vue canvas绘制信令图,动态显示标题、宽度、高度

需求:

1、 根据后端返回的数据,动态绘制出信令图
2、根据 dataStatus 返回值: 0 和 1, 判断 文字内容的颜色,0:#000,1:red
3.、根据 lineType 返回值: 0 和 1,  判断 箭头线的显示 是实线、虚线
4、根据返回的文字内容的换行符:“\r\n” 自动换行 (这步比较难,得计算高度)
最后的效果图大概是这样的:

 一、标题的动态获取


1-1、如果后端给你返回的标题是随机顺序的,这里需要根据全部标题数组做一下排序。
// 全部标题数组:
titletypeArr: ['ATP', 'MT', 'BTS', 'BSC', 'MSC', 'RBC'],// 后端返回的随机标题数组: 
resultTitle: ['MT', 'ATP' ]// 处理方法
this.typeArr = this.titletypeArr.filter(item => this.resultTitle.indexOf(item) !== -1)

 二、canvas绘制初始化

    // 初始化加载initData() {var mycanvas = document.getElementById("myCanvas");this.canvas = mycanvas;var context = mycanvas.getContext("2d");// 动态设置宽高一定要在 myCanvas 节点添加之后document.getElementById("myCanvas").width = this.typeArr.length * 320 - 120;document.getElementById("myCanvas").style.background = "#fff";const minHeight = window.innerHeight - 180;if (this.xlArr.length > 0) {document.getElementById("myCanvas").height =30 * this.xlArr.length + 80 < minHeight? minHeight: 30 * this.xlArr.length + 80;} else {document.getElementById("myCanvas").height = minHeight;}var height = this.paddingTop + 62; // 初始值this.xlArr.map((v, i) => {const k = this.typeArr.indexOf(v.startDataDir);const j = this.typeArr.indexOf(v.endDataDir);context.font = '13px "微软雅黑"'; // 设置字体// 时间文字context.fillStyle = '#000' // 时间颜色context.fillText(v.recTime.split(' ')[1], 40, height);// 箭头this.paintArr(v,[this.gapX * k + this.paddingLeft, height],[this.gapX * j + this.paddingLeft, height],k < j ? "right" : "left",context);var maxWidth = 260; // 最大宽度,超过这个宽度会自动换行var words = v.showInfo.split("\r\n");// 文字自动换行this.wrapText(v,context,words,this.gapX * (k < j ? k : j) + this.paddingLeft,height - 10,maxWidth,this.lineHeight);if (i < this.xlArr.length - 1) {let nextWords = this.xlArr[i + 1].showInfo.split("\r\n");height += (this.lineHeight * (words.length + nextWords.length)) / 2 + 30;} else {height += this.lineHeight * words.length + 30;}// console.log(height, "height")})// 画虚线以及标题this.typeArr.map((v, i) => {this.paintText(context, v, i);setTimeout(() => {this.drawDashed(context, i);}, 300)})// document.getElementById('container').onscroll = (e) => {//   // console.log('e:', e.target)//   this.left = e.target.scrollLeft// }// 屏蔽所有页面 右键菜单// document.oncontextmenu = (event) => {//   event.returnValue = false// }// 屏蔽当前页面 右键菜单// document.getElementById('container').oncontextmenu = (event) => {//   event.returnValue = false// }}

三、绘制箭头

    // 箭头paintArr(item, s, t, direction, ctx) {ctx.beginPath()ctx.lineWidth = 1if (item.dataStatus == 1) {ctx.strokeStyle = 'red'} else {ctx.strokeStyle = '#000' // 箭头线的颜色}if (item.lineType === 1) {ctx.setLineDash([5, 2]); // 虚线}ctx.moveTo(s[0], s[1])ctx.lineTo(t[0], t[1])ctx.stroke()ctx.closePath()ctx.beginPath()if (direction === 'right') {ctx.moveTo(t[0] - 10, t[1] + 3)ctx.lineTo(t[0], t[1])ctx.lineTo(t[0] - 10, t[1] - 3)} else {ctx.moveTo(t[0] + 10, t[1] - 3)ctx.lineTo(t[0], t[1])ctx.lineTo(t[0] + 10, t[1] + 3)}// ctx.closePath()ctx.stroke()// ctx.fill()},

四、绘制 标题列的虚线

    // 标题列的虚线drawDashed(ctx, i) {ctx.beginPath()ctx.lineWidth = 1ctx.strokeStyle = '#696969' // '#FF8080'//虚线的颜色ctx.setLineDash([5, 2])ctx.moveTo(320 * i + this.paddingLeft, this.paddingTop + 40);ctx.lineTo(320 * i + this.paddingLeft, 400 * this.typeArr.length);ctx.fill()ctx.stroke()ctx.closePath()},

五、文字自动换行 遇到换行符换行

    // 文字自动换行 遇到换行符换行,并且超出最大宽度换行,只计算了最多显示7行的情况,超出7行得再计算wrapText(item, context, words, x, y, maxWidth, lineHeight) {// console.log(words, "words")let originY = y;let len = words.length;let rectWidth = 0;for (var n = 0; n < len; n++) {// 不超出一行var testWidth = context.measureText(words[n]).width;if (testWidth < maxWidth) {if (rectWidth < testWidth) {rectWidth = testWidth;}}}// 在上面循环计算出文字实际最宽的位置,画出背景色遮挡箭头// 画背景色遮盖箭头, 背景色自己调,跟画布统一就行context.fillStyle = "#fff"; // 背景颜色context.fillRect(x + this.gapX / 2 - rectWidth / 2 - 4,originY,rectWidth + 6,lineHeight); // 填充黄色背景for (var n = 0; n < len; n++) {// 不超出一行var testWidth = context.measureText(words[n]).width;if (testWidth < maxWidth) {// console.log(words[n], 1);let currentY = y;if (len === 1) {currentY = y + 14;} else if (len === 2) {currentY = y + 2;} else if (len === 3) {currentY = y - 6;} else if (len === 4) {currentY = y - 18;} else if (len === 5) {currentY = y - 28;} else if (len === 6) {currentY = y - 38;} else if (len === 7) {currentY = y - 48;}if (item.dataStatus == 1) {context.fillStyle = 'red'} else {context.fillStyle = '#000' // 字体颜色}// context.fillStyle = "#000"; // 字体颜色context.fillText(words[n], x + this.gapX / 2 - testWidth / 2, currentY);if (len > 1) {y += lineHeight;}} else {console.log(words[n], 2);// 文字超出一行,需要换行展示// 实际大于页面width font-size: 12, 计算出显示多少行let singleWordwith = 13;// 计算一行显示的最大字数,以及显示多少行let len = Math.floor(maxWidth / singleWordwith);let lineCount = Math.ceil(words[n].length / len);for (let j = 0; j <= lineCount; j++) {// 截取出每行显示的字let word = words[n].substr(j * len, len);let wordWidth = context.measureText(word).width;// 写入画布// 画背景色遮盖箭头, 背景色自己调,跟画布统一就行context.fillStyle = "#fff";context.fillRect(x + this.gapX / 2 - wordWidth / 2,y - 4,wordWidth,lineHeight); // 填充黄色背景let currentY = y;if (lineCount === 2) {currentY = y + 2;} else if (lineCount === 3) {currentY = y - 6;} else if (lineCount === 4) {currentY = y - 18;} else if (lineCount === 5) {currentY = y - 28;} else if (lineCount === 6) {currentY = y - 38;} else if (lineCount === 7) {currentY = y - 48;}if (item.dataStatus == 1) {context.fillStyle = 'red'} else {context.fillStyle = '#000' // 字体颜色}// context.fillStyle = "#000";context.fillText(word, x + this.gapX / 2 - wordWidth / 2, currentY);y += lineHeight; // 换行}}}},

六、模拟后端返回的数据

// signalTimeData: [//   {//     startDataDir: "ATP",//     endDataDir: "MT",//     recTime: '2023-09-10 09:12:48',//     showInfo: "M136\r\nT_Train=9340940ms\r\nDT:16",//     dataDir: 0,//     dataDirStr: "上行",//     lineType: 0,//     dataStatus: 0//   },//   {//     startDataDir: "MT",//     endDataDir: "ATP",//     recTime: '2023-09-10 09:12:49',//     showInfo: "M24\r\nT_Train=9341070ms",//     dataDir: 1,//     dataDirStr: "下行",//     lineType: 0,//     dataStatus: 0//   },//   {//     startDataDir: "ATP",//     endDataDir: "MT",//     recTime: '2023-09-10 09:13:06',//     showInfo: "M136\r\nT_Train=9358940ms\r\nDT:19\r\n此时,M24之后ATP发送3条APDU",//     dataDir: 0,//     dataDirStr: "上行",//     lineType: 0,//     dataStatus: 1//   },//   {//     startDataDir: "MT",//     endDataDir: "ATP",//     recTime: '2023-09-10 09:13:07',//     showInfo: "AK:20\r\n此时,M24之后RBC发送3条AK,无APDU",//     dataDir: 1,//     dataDirStr: "下行",//     lineType: 0,//     dataStatus: 1//   },//   {//     startDataDir: "ATP",//     endDataDir: "MT",//     recTime: '2023-09-10 09:13:08',//     showInfo: "TPDU_DR/SaPDU_D",//     dataDir: 0,//     dataDirStr: "上行",//     lineType: 0,//     dataStatus: 1//   },//   {//     startDataDir: "MT",//     endDataDir: "ATP",//     recTime: '2023-09-10 09:13:09',//     showInfo: "TPDU_DC",//     dataDir: 1,//     dataDirStr: "下行",//     lineType: 0,//     dataStatus: 0//   },//   {//     startDataDir: "ATP",//     endDataDir: "MT",//     recTime: "2023-09-10 09:13:09",//     showInfo: "DISC",//     dataDir: 0,//     dataDirStr: "上行",//     lineType: 0,//     dataStatus: 0//   },//   {//     startDataDir: "MT",//     endDataDir: "ATP",//     recTime: "2023-09-10 09:13:09",//     showInfo: "NO CARRIER",//     dataDir: 1,//     dataDirStr: "下行",//     lineType: 0,//     dataStatus: 0//   }// ],

 全部代码如下:

<template><!-- :width="dialogWidth" --><vxe-modal v-model="sigModal" :title="titles" width="1200" min-width="550" :height="dialogHeight" :position="{ top: '3vh' }" @close="closeEvent" resize destroy-on-close><div class="con"><el-row style="margin-bottom:10px"><el-button type="primary" icon="el-icon-upload" @click="screenShot()">上传</el-button></el-row><div ref="screen" :style="{width: canvasWidth, height: canvasHeight}"><canvas id="myCanvas" :width="canvasWidth" :height="canvasHeight">你的浏览器还不支持canvas</canvas></div></div></vxe-modal>
</template><script>
import html2canvas from 'html2canvas'
import { DownLoadFromTime } from '@/utils/times.js'
import { get_signallInfo } from '@/api/c3/offlineImportant.js'
import axios from 'axios'
export default {data() {return {uploadId: '',			titles: '信令图',dialogWidth: '90%',dialogHeight: '92%',sigModal: false,// 'ATP'-----'MT'------------ 'BTS'-------'BSC'----'MSC'------ 'RBC'//   Igsmr-R   Um_AMS/Um_BMS      Abis           A      PRIresultTitle: ['ATP', 'MT'], // 后台返回的随机顺序titletypeArr: ['ATP', 'MT', 'BTS', 'BSC', 'MSC', 'RBC'],typeArr: [],canvasWidth: '1080px',canvasHeight: (window.innerHeight) - 170 + 'px',minHeight: (window.innerHeight) - 170,// signalTimeData: [//   {//     startDataDir: "ATP",//     endDataDir: "MT",//     recTime: '2023-09-10 09:12:48',//     showInfo: "M136\r\nT_Train=9340940ms\r\nDT:16",//     dataDir: 0,//     dataDirStr: "上行",//     lineType: 0,//     dataStatus: 0//   },//   {//     startDataDir: "MT",//     endDataDir: "ATP",//     recTime: '2023-09-10 09:12:49',//     showInfo: "M24\r\nT_Train=9341070ms",//     dataDir: 1,//     dataDirStr: "下行",//     lineType: 0,//     dataStatus: 0//   },//   {//     startDataDir: "ATP",//     endDataDir: "MT",//     recTime: '2023-09-10 09:13:06',//     showInfo: "M136\r\nT_Train=9358940ms\r\nDT:19\r\n此时,M24之后ATP发送3条APDU",//     dataDir: 0,//     dataDirStr: "上行",//     lineType: 0,//     dataStatus: 1//   },//   {//     startDataDir: "MT",//     endDataDir: "ATP",//     recTime: '2023-09-10 09:13:07',//     showInfo: "AK:20\r\n此时,M24之后RBC发送3条AK,无APDU",//     dataDir: 1,//     dataDirStr: "下行",//     lineType: 0,//     dataStatus: 1//   },//   {//     startDataDir: "ATP",//     endDataDir: "MT",//     recTime: '2023-09-10 09:13:08',//     showInfo: "TPDU_DR/SaPDU_D",//     dataDir: 0,//     dataDirStr: "上行",//     lineType: 0,//     dataStatus: 1//   },//   {//     startDataDir: "MT",//     endDataDir: "ATP",//     recTime: '2023-09-10 09:13:09',//     showInfo: "TPDU_DC",//     dataDir: 1,//     dataDirStr: "下行",//     lineType: 0,//     dataStatus: 0//   },//   {//     startDataDir: "ATP",//     endDataDir: "MT",//     recTime: "2023-09-10 09:13:09",//     showInfo: "DISC",//     dataDir: 0,//     dataDirStr: "上行",//     lineType: 0,//     dataStatus: 0//   },//   {//     startDataDir: "MT",//     endDataDir: "ATP",//     recTime: "2023-09-10 09:13:09",//     showInfo: "NO CARRIER",//     dataDir: 1,//     dataDirStr: "下行",//     lineType: 0,//     dataStatus: 0//   }// ],xlArr: [],canvas: null,left: 0,paddingLeft: 120,paddingTop: 20,gapX: 320, // x轴间隔gapY: 90, // y轴间隔lineHeight: 20 // 行高}},created() {// this.typeArr = this.titletypeArr.filter(item => this.resultTitle.indexOf(item) !== -1)// this.xlArr = this.signalTimeData// this.canvasWidth = (this.typeArr.length * 320) - 120 + 'px'this.fnHight()window.addEventListener('resize', this.fnHight, true)},mounted() {},destroyed() {this.$destroy()window.removeEventListener('resize', this.fnHight, true)},methods: {// 获取信令图数据getSignallList(accidentId) {let parmsData = {accidentId: accidentId}get_signallInfo(parmsData).then(res => {if (res.status === 200) {if (res.data.code === 0) {if (res.data.data) {this.resultTitle = res.data.data.interfaceTypesthis.typeArr = this.titletypeArr.filter(item => this.resultTitle.indexOf(item) !== -1)this.xlArr = res.data.data.mtDiagramInfoVoListthis.canvasWidth = (this.typeArr.length * 320) - 120 + 'px'} else {this.$XModal.message({ content: '未查询到信令图数据.', status: 'warning' })}} else {this.$XModal.message({ content: res.message, status: 'error' })}}})},// 截屏screenShot() {html2canvas(this.$refs.screen, {backgroundColor: '#FFFFFF',useCORS: true}).then((canvas) => {// 获取到canvascanvas.toBlob(blob => {// 将二进制对象的内容 转成fileconst file = new File([blob], Date.now() + '.png', { type: 'image/png' })const formData = new FormData()formData.append('file', file)formData.append('uploadId', this.uploadId)// 发起请求axios({headers: {'Authorization': this.$store.state.user.token,'showInfo-Type': 'multipart/form-data'},method: 'post',url: '/api/offline/analysisContent/uploadReportPdf',data: formData,}).then((res) => {// 上传成功if (res.status === 200) {this.$XModal.message({ content: '上传成功', status: 'success'})this.$emit('sumitSuccess', 'ok')}}).catch((error) => {// 上传失败 执行对应操作this.$XModal.message({ content: '上传失败', status: 'error' })})}, 'image/png')if (navigator.msSaveBlob) { // IE10+ let blob = canvas.msToBlob(); return navigator.msSaveBlob(blob, name);} else {let imageurl = canvas.toDataURL('image/png')const newTime = DownLoadFromTime(new Date())//这里需要自己选择命名规则let imagename = '信令图_' + 'G1884' + '_' + newTimethis.fileDownload(imageurl, imagename)}  })},// 下载截屏图片fileDownload(downloadUrl, downloadName) {let aLink = document.createElement("a")aLink.style.display = "none"aLink.href = downloadUrlaLink.download = `${downloadName}.png`// 触发点击-然后移除document.body.appendChild(aLink)aLink.click()document.body.removeChild(aLink)},closeEvent() {this.sigModal = false},fnHight() {setTimeout(() => {this.minHeight = (window.innerHeight) - 170}, 300)},// 标题的边框paintText(ctx, text, i) {// ctx.fillStyle = '#FEFECE'ctx.fillStyle = '#FFF'ctx.fillRect(320 * i + this.paddingLeft - 30, this.paddingTop, 60, 30); // 填充黄色背景// ctx.strokeStyle = 'red'ctx.strokeStyle = '#000' // '#A80036' // 标题的边框颜色ctx.strokeRect(320 * i + this.paddingLeft - 30, this.paddingTop, 60, 30); // 设置边框ctx.font = '12px "微软雅黑"' // 设置字体ctx.textBaseline = 'bottom' // 设置字体底线对齐绘制基线ctx.textAlign = 'left' // 设置字体对齐的方式ctx.fillStyle = 'Black'ctx.fillText(text, 320 * i + this.paddingLeft - 10, this.paddingTop + 22); // 填充文字标题// ctx.closePath()},// 箭头paintArr(item, s, t, direction, ctx) {ctx.beginPath()ctx.lineWidth = 1if (item.dataStatus == 1) {ctx.strokeStyle = 'red'} else {ctx.strokeStyle = '#000' // 箭头线的颜色}if (item.lineType === 1) {ctx.setLineDash([5, 2]); // 虚线}ctx.moveTo(s[0], s[1])ctx.lineTo(t[0], t[1])ctx.stroke()ctx.closePath()ctx.beginPath()if (direction === 'right') {ctx.moveTo(t[0] - 10, t[1] + 3)ctx.lineTo(t[0], t[1])ctx.lineTo(t[0] - 10, t[1] - 3)} else {ctx.moveTo(t[0] + 10, t[1] - 3)ctx.lineTo(t[0], t[1])ctx.lineTo(t[0] + 10, t[1] + 3)}// ctx.closePath()ctx.stroke()// ctx.fill()},// 标题列的虚线drawDashed(ctx, i) {ctx.beginPath()ctx.lineWidth = 1ctx.strokeStyle = '#696969' // '#FF8080'//虚线的颜色ctx.setLineDash([5, 2])ctx.moveTo(320 * i + this.paddingLeft, this.paddingTop + 40);ctx.lineTo(320 * i + this.paddingLeft, 400 * this.typeArr.length);ctx.fill()ctx.stroke()ctx.closePath()},// 文字自动换行 遇到换行符换行,并且超出最大宽度换行,只计算了最多显示7行的情况,超出7行得再计算wrapText(item, context, words, x, y, maxWidth, lineHeight) {// console.log(words, "words")let originY = y;let len = words.length;let rectWidth = 0;for (var n = 0; n < len; n++) {// 不超出一行var testWidth = context.measureText(words[n]).width;if (testWidth < maxWidth) {if (rectWidth < testWidth) {rectWidth = testWidth;}}}// 在上面循环计算出文字实际最宽的位置,画出背景色遮挡箭头// 画背景色遮盖箭头, 背景色自己调,跟画布统一就行context.fillStyle = "#fff"; // 背景颜色context.fillRect(x + this.gapX / 2 - rectWidth / 2 - 4,originY,rectWidth + 6,lineHeight); // 填充黄色背景for (var n = 0; n < len; n++) {// 不超出一行var testWidth = context.measureText(words[n]).width;if (testWidth < maxWidth) {// console.log(words[n], 1);let currentY = y;if (len === 1) {currentY = y + 14;} else if (len === 2) {currentY = y + 2;} else if (len === 3) {currentY = y - 6;} else if (len === 4) {currentY = y - 18;} else if (len === 5) {currentY = y - 28;} else if (len === 6) {currentY = y - 38;} else if (len === 7) {currentY = y - 48;}if (item.dataStatus == 1) {context.fillStyle = 'red'} else {context.fillStyle = '#000' // 字体颜色}// context.fillStyle = "#000"; // 字体颜色context.fillText(words[n], x + this.gapX / 2 - testWidth / 2, currentY);if (len > 1) {y += lineHeight;}} else {console.log(words[n], 2);// 文字超出一行,需要换行展示// 实际大于页面width font-size: 12, 计算出显示多少行let singleWordwith = 13;// 计算一行显示的最大字数,以及显示多少行let len = Math.floor(maxWidth / singleWordwith);let lineCount = Math.ceil(words[n].length / len);for (let j = 0; j <= lineCount; j++) {// 截取出每行显示的字let word = words[n].substr(j * len, len);let wordWidth = context.measureText(word).width;// 写入画布// 画背景色遮盖箭头, 背景色自己调,跟画布统一就行context.fillStyle = "#fff";context.fillRect(x + this.gapX / 2 - wordWidth / 2,y - 4,wordWidth,lineHeight); // 填充黄色背景let currentY = y;if (lineCount === 2) {currentY = y + 2;} else if (lineCount === 3) {currentY = y - 6;} else if (lineCount === 4) {currentY = y - 18;} else if (lineCount === 5) {currentY = y - 28;} else if (lineCount === 6) {currentY = y - 38;} else if (lineCount === 7) {currentY = y - 48;}if (item.dataStatus == 1) {context.fillStyle = 'red'} else {context.fillStyle = '#000' // 字体颜色}// context.fillStyle = "#000";context.fillText(word, x + this.gapX / 2 - wordWidth / 2, currentY);y += lineHeight; // 换行}}}},// 初始化加载initData() {var mycanvas = document.getElementById("myCanvas");this.canvas = mycanvas;var context = mycanvas.getContext("2d");// 动态设置宽高一定要在 myCanvas 节点添加之后document.getElementById("myCanvas").width = this.typeArr.length * 320 - 120;document.getElementById("myCanvas").style.background = "#fff";const minHeight = window.innerHeight - 180;if (this.xlArr.length > 0) {document.getElementById("myCanvas").height =30 * this.xlArr.length + 80 < minHeight? minHeight: 30 * this.xlArr.length + 80;} else {document.getElementById("myCanvas").height = minHeight;}var height = this.paddingTop + 62; // 初始值this.xlArr.map((v, i) => {const k = this.typeArr.indexOf(v.startDataDir);const j = this.typeArr.indexOf(v.endDataDir);context.font = '13px "微软雅黑"'; // 设置字体// 时间文字context.fillStyle = '#000' // 时间颜色context.fillText(v.recTime.split(' ')[1], 40, height);// 箭头this.paintArr(v,[this.gapX * k + this.paddingLeft, height],[this.gapX * j + this.paddingLeft, height],k < j ? "right" : "left",context);var maxWidth = 260; // 最大宽度,超过这个宽度会自动换行var words = v.showInfo.split("\r\n");// 文字自动换行this.wrapText(v,context,words,this.gapX * (k < j ? k : j) + this.paddingLeft,height - 10,maxWidth,this.lineHeight);if (i < this.xlArr.length - 1) {let nextWords = this.xlArr[i + 1].showInfo.split("\r\n");height += (this.lineHeight * (words.length + nextWords.length)) / 2 + 30;} else {height += this.lineHeight * words.length + 30;}// console.log(height, "height")})// 画虚线以及标题this.typeArr.map((v, i) => {this.paintText(context, v, i);setTimeout(() => {this.drawDashed(context, i);}, 300)})// document.getElementById('container').onscroll = (e) => {//   // console.log('e:', e.target)//   this.left = e.target.scrollLeft// }// 屏蔽所有页面 右键菜单// document.oncontextmenu = (event) => {//   event.returnValue = false// }// 屏蔽当前页面 右键菜单// document.getElementById('container').oncontextmenu = (event) => {//   event.returnValue = false// }}}
}
</script><style lang="scss" scoped>.con {position: relative;}.topTitle{position: absolute;background: #fff;top: 38px;padding-left: 15px;// width: 2580px;display: flex;li {display: inline-block;width: 320px;margin: 3px 0;}li:nth-last-child(1) {width: 100px;}span {// border: 1px solid #A80036;border: 1px solid #000;padding: 5px 10px;// background-color: #FEFECE;background-color: #fff;display: inline-block;}}#container {// overflow-x: scroll;// overflow-y: scroll;overflow: hidden;}#canvas {display: block;background-color: #fff;}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/303162.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FPGA:图像数字细节增强算法(工程+仿真+实物,可用毕设)

目录 日常唠嗑一、视频效果二、硬件及功能1、硬件选择2、功能3、特点 未完、待续……四、工程设计五、板级验证六、工程获取 日常唠嗑 有2个多月没写文章了&#xff0c;又是老借口&#xff1a;“最近实在是很忙”&#x1f923;&#xff0c;不过说真&#xff0c;确实是比较忙&am…

vue点击上传图片并实现图片预览功能,并实现多张图片放到一个数组中进行后端请求(使用原生input)

一、将 File 对象转成 BASE64 字符串 &#xff08;FileReader&#xff09; <template><div><!-- 用来显示封面的图片 --><!-- <img src"/assets/images/cover.jpg" alt"" class"cover-img" ref"imgRef" />…

最短编辑距离(线性dp)-java

最短编辑问题也是一种非常经典的二维线性dp问题。 文章目录 前言 一、最短编辑距离问题 二、算法思路 1.dp[i][j]的情况 2.边界问题初始化 3.状态转移方程 三、代码如下 1.代码如下 2.读入数据 3.代码运行结果 总结 前言 最短编辑问题也是一种非常经典的二维线性dp问题。 提示&…

C++学习进阶:unordered_set和ma的实现

目录 前言 1.哈希表的结构 1.1.哈希节点 1.2.迭代器的结构 1.2.1.普通迭代器 1.2.2.const迭代器的实现 1.3.哈希表的实现 2.如何封装哈希表实现个性化的容器 2.1.unordered_set的封装 2.2.unordered_map的封装 3.以上内容的代码实现 3.1.HashTable.h 3.2.unorde…

51单片机之LED点阵屏

目录 1.LED点阵屏简介 2.配置LED点阵屏代码 1.LED点阵屏简介 LED点阵屏真的是遍布我们我们生活的每个角落&#xff0c;从街边的流动显示字的招牌到你的液晶显示屏&#xff0c;都是基于点阵屏的原理研究出来的。还有那个世界上最大的球状建筑物&#xff1a;MSG Sphere&#xff…

低代码ARM计算机在IIoT中的采集控制生产面板

工业4.0的大潮下工业物联网&#xff08;IIoT&#xff09;已成为推动制造业转型升级的重要动力。其中&#xff0c;低代码ARM嵌入式计算机凭借其出色的性能、灵活的配置以及高度集成化的特点&#xff0c;在工业设备远程监控、维护与诊断方面发挥着关键作用。 一、远程监控与维护 …

python爬虫———post请求方式(第十四天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

Maven与Jave web结构

Maven 简介 https://www.liaoxuefeng.com/wiki/1252599548343744/1255945359327200 java web module web目录 –src 应用程序源代码和测试程序代码的根目录 –main –java  应用程序源代码目录     --package1     --class1     --class2 –resources  应用…

Docker内更新Jenkins详细讲解

很多小伙伴在Docker中使用Jenkins时更新遇到困难&#xff0c;本次结合自己的实际经验&#xff0c;详细讲解。根据官网Jenkins了解以下内容&#xff1a; 一、Jenkins 是什么? Jenkins是一款开源 CI&CD 软件&#xff0c;用于自动化各种任务&#xff0c;包括构建、测…

Mysql-数据库集群的搭建以及数据库的维护

一、数据库的维护 1.数据库的备份与恢复 1&#xff09;备份指定数据库 #mysqldump -u root -p zx > ./zx.dump 2&#xff09;备份所有库 #mysqldump -u root -p --all-databases > ./all.dump 3)恢复所有库 #mysql -u root -p < ./all.dump 4)恢复指定数据库 #mysq…

网络基础三——IP协议补充和Mac帧协议

全球网络及网段划分的理解 ​ 根据国家组织地区人口综合评估进行IP地址范围的划分&#xff1b; ​ 假设前8位用来区分不同的国家&#xff0c;国际路由器负责全球数据传输&#xff0c;子网掩码为IP/8&#xff1b;次6位区分不同的省份&#xff0c;国内路由器负责全国数据的传输…

再见 MybatisPlus,阿里推出新 ORM 框架更牛X

最近看到一个 ORM 框架 Fluent Mybatis 挺有意思的&#xff0c;整个设计理念非常符合工程师思维。 我对官方文档的部分内容进行了简单整理&#xff0c;通过这篇文章带你看看这个新晋 ORM 框架。 官方文档&#xff1a;https://gitee.com/fluent-mybatis/fluent-mybatis/wikis 提…

Golang | Leetcode Golang题解之第19题删除链表的倒数第N个结点

题目&#xff1a; 题解&#xff1a; func removeNthFromEnd(head *ListNode, n int) *ListNode {dummy : &ListNode{0, head}first, second : head, dummyfor i : 0; i < n; i {first first.Next}for ; first ! nil; first first.Next {second second.Next}second.N…

Redis缓存设计

文章目录 1 缓存的收益与成本分析1.1 收益1.2 成本 2 缓存更新策略的选择和使用场景2.1 LRU/LFU/FIFO算法剔除2.2 超时剔除2.3 主动更新2.4 缓存更新策略对比 2.5 最佳实践 3 缓存粒度控制方法3.1 缓存全部数据3.2 缓存部分数据3.3 缓存粒度控制方法对比 4 缓存穿透问题优化4.1…

(2022级)成都工业学院软件构造实验三:面向数据的软件构造

写在前面 1、基于2022级软件工程实验指导书 2、代码仅提供参考 3、如果代码不满足你的要求&#xff0c;请寻求其他的途径 运行环境 window11家庭版 IntelliJ IDEA 2023.2.2 jdk17.0.6 实验要求 任务&#xff1a; ‍一、构造任务4&#xff1a;批量产生习题并用文件存储…

IntelliJ IDEA 2024.1安装与激活[破解]

一&#xff1a;IDEA官方下载 ①如题&#xff0c;先到IDEA官方下载&#xff0c;简简单单 ②IDEA官方&#xff1a;IntelliJ IDEA – the Leading Java and Kotlin IDE 二&#xff1a;获取脚本 &#x1f31f;网盘下载&#xff1a;jetbra (密码&#xff1a;lzh7) &#x1f31f;获取…

STC89C52学习笔记(七)

STC89C52学习笔记&#xff08;七&#xff09; 综述&#xff1a;本文介绍了串口以及讲述了串口相关寄存器如何配置并给予相关代码。 一、修改代码注意事项 在修改代码时不要一次性加入一堆代码&#xff0c;不利于定位错误。可以先注释一些代码&#xff0c;待解决完毕问题后再…

物联网农业四情在线监测系统

TH-Q2随着科技的飞速发展和信息化时代的来临&#xff0c;物联网技术在各个领域都取得了显著的应用成果。其中&#xff0c;物联网农业四情在线监测系统作为农业现代化的重要组成部分&#xff0c;正在为农业生产带来革命性的变革。 一、物联网农业四情在线监测系统的概念 物联网…

大模型笔记:Prompt tuning

1 NLP模型的几个阶段 1.1 第一阶段&#xff08;在深度学习出现之前&#xff09; 通常聚焦于特征工程&#xff08;feature engineering&#xff09;利用领域知识从数据中提取好的特征 1.2 第二阶段&#xff08;在深度学习出现之后&#xff09; 特征可以从数据中习得——>…

使用 kaggle api 实现 kaggle 数据快速下载

在下载kaggle数据集时&#xff0c;以猫狗数据集举例子&#xff0c;有两种方法&#xff1a; Dogs vs. Cats | Kaggle 1&#xff1a;直接浏览器下载&#xff0c;较慢&#xff0c;不推荐。 2&#xff1a;使用kaggle API下载&#xff0c;很快。本文重点介绍。详情可以&#xff1…