当前位置: 首页 > news >正文

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>

相关文章:

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

需求: 1、 根据后端返回的数据&#xff0c;动态绘制出信令图 2、根据 dataStatus 返回值&#xff1a; 0 和 1&#xff0c; 判断 文字内容的颜色&#xff0c;0&#xff1a;#000&#xff0c;1&#xff1a;red 3.、根据 lineType 返回值&#xff1a; 0 和 1&#xff0c; 判断 箭…...

无影云电脑不能连接到本机的调试串口的解决方案

目录 概述 解决方案 云端电脑中的操作 本地USBDK驱动程序的更新 概述 我从1月份开始使用阿里的无影云电脑进行嵌入式开发板的测试&#xff0c;主要的原因有两个&#xff1a;一是平时使用的笔记本资源过于紧张&#xff0c;二是方便移动办公&#xff0c;这样我只要平时拿着开…...

gpt科普1 GPT与搜索引擎的对比

GPT&#xff08;Generative Pre-trained Transformer&#xff09;是一种基于Transformer架构的自然语言处理模型。它通过大规模的无监督学习来预训练模型&#xff0c;在完成这个阶段后&#xff0c;可以用于各种NLP任务&#xff0c;如文本生成、机器翻译、文本分类等。 以下是关…...

Element-plus使用中遇到的问题

el-input 设置typenumber&#xff0c;会出现上下箭头&#xff0c;在全局配置css样式即可解决&#xff0c;在app.vue中的css中加入&#xff1a;.table-clear-row {input::-webkit-outer-spin-button,input::-webkit-inner-spin-button {-webkit-appearance: none;}input[type&q…...

如何使用Arduino IDE对STM32F103C8T6进行编程

使用Arduino IDE对STM32F103C8T6进行编程调试&#xff0c;你需要进行一些准备工作和设置。以下是详细的操作步骤&#xff1a; 准备工作&#xff1a; 安装Arduino IDE&#xff1a;确保你已经安装了最新版本的Arduino IDE。可以从官方网站 https://www.arduino.cc/en/software 下…...

【迅为iMX6Q】开发板 Linux version 6.6.3 SD卡 启动

开发环境 win10 64位 VMware Workstation Pro 16 ubuntu 20.04 【迅为imx6q】开发板&#xff0c; 2G DDR RAM linux-imx 下载 使用 NXP 官方提供的 linux-imx&#xff0c;代码地址为&#xff1a; https://github.com/nxp-imx/linux-imx 使用 git 下载 linux-imx&#xff…...

C语言每日一题(66)三数之和

题目链接 力扣15.三数之和 题目描述 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答…...

vue3-element-admin实现同一个菜单多标签

原框架代码: 赵志江/huzhushan-vue3-element-admin 目录 TagsBar实现 实现同一个菜单多标签 device/detail/:id&#xff0c;不同参数时页面缓存删不掉的问题 TagsBar实现 在src/layout/components/下新建目录Tagsbar&#xff0c;新建index.vue <template><div c…...

第三十六节 Java 网络编程

网络编程是指编写运行在多个设备&#xff08;计算机&#xff09;的程序&#xff0c;这些设备都通过网络连接起来。 java.net包中J2SE的API包含有类和接口&#xff0c;它们提供低层次的通信细节。你可以直接使用这些类和接口&#xff0c;来专注于解决问题&#xff0c;而不用关注…...

DRF的认证、权限、限流、序列化、反序列化

DRF的认证、权限、限流、序列化、反序列化 一、认证1、直接用&#xff0c;用户授权2、认证组件源码 二、权限1. 直接使用&#xff0c;用户权限2.权限组件源码 三、序列化1. 序列化1.1 自定义Serailizer类序列化1.2 在视图APIView中使用1.3 自定义ModelSerializer类序列化1.4 不…...

解决:Cannot read properties of undefined (reading ‘validate‘)问题

问题&#xff1a;Element UI使用表单校验功能控制台出现Cannot read properties of undefined (reading validate)报错 解决&#xff1a;在 <el-form :model"form" :rules"rules">添加 ref"form"&#xff0c;form为自定义的表单名称 <…...

关于IP地址发展历程的详细探讨

IP地址的发展历程是一段不断演进、适应网络技术发展的历史。自互联网诞生以来&#xff0c;IP地址作为网络设备的唯一标识&#xff0c;扮演了至关重要的角色。以下是对IP地址发展历程的详细探讨。 在互联网的初期&#xff0c;主机数量相对较少&#xff0c;IP地址主要用于区分不…...

【LeetCode热题100】【二叉树】将有序数组转换为二叉搜索树

题目链接&#xff1a;108. 将有序数组转换为二叉搜索树 - 力扣&#xff08;LeetCode&#xff09; 取中间的数作为根节点&#xff0c;左边的数递归转换&#xff0c;右边的数递归转换 class Solution { public:TreeNode *sortedArrayToBST(vector<int> &nums) {retur…...

文心一言和GPT-4全面比较

自大型语言模型出现以来&#xff0c;人工智能在自然语言处理方面取得了显著进步。文心一言和GPT-4是当前最先进的两款语言模型&#xff0c;在业内广受关注。两者都具有强大的能力&#xff0c;但各有特点和优势。本文将从多个方面对这两个模型进行全面比较&#xff0c;以帮助读者…...

Mac的终端配置

Mac的终端配置 参考教程包管理工具 - Homebrew出现的问题用虚拟环境解决方案&#xff1a;直接将解释器的路径放过去错误方法&#xff1a;用find查找到虚拟环境安装的路径&#xff0c;其链接的是brew安装的python路径 编辑器没有报错&#xff0c;但是运行过程中仍然找不到pandas…...

制作一个RISC-V的操作系统十-Trap和Exception(流 mtvec mepc mcause mtval mstatus trap完整流程)

文章目录 流mtvecmepcmcausemtvalmstatustrap 初始化trap的top half&#xff08;硬件完成&#xff09;trap的bottom half&#xff08;软件完成&#xff09;从trap返回代码实现 流 控制流&#xff1a;程序控制的执行流 trap分为中断和异常 mtvec base&#xff1a;存储trap入…...

【爬虫开发】爬虫从0到1全知识md笔记第4篇:Selenium课程概要,selenium的介绍【附代码文档】

爬虫开发从0到1全知识教程完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;爬虫课程概要&#xff0c;爬虫基础爬虫概述,,http协议复习。requests模块&#xff0c;requests模块1. requests模块介绍,2. response响应对象,3. requests模块发送请求,4. request…...

对一个时间序列中的每个元素按照指定精度向上取整

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 对一个时间序列中的每个元素 按照指定精度向上取整 例如&#xff1a;对小时处理&#xff0c; 则9:01处理为10:00 Series.dt.ceil() 选择题 以下代码的输出结果中正确的是? import pandas as…...

51单片机+TN901非接触式红外测温设计论文与源码PCB等资料

1、摘要 温度测量技术应用十分广泛&#xff0c;而且在现代设备故障检测领域中也是一项非常重要的技术。但在某些应用领域中&#xff0c;要求测量温度用的传感器不能与被测物体相接触&#xff0c;这就需要一种非接触的测温方式来满足上述测温需求。本论文正是应上述实际需求而设…...

AI创业项目:AI旅游规划定制师

在当前的旅游市场中&#xff0c;个性化旅游规划成为越来越多旅行者的需求。然而&#xff0c;现行的定制旅行服务主要依赖于人工定制师&#xff0c;这一模式面临着信息不透明、价格弹性大等挑战。定制师在客户与服务供应商之间掌握着信息差&#xff0c;依靠这一优势获得收益&…...

win 安装 Stable Diffusion

注&#xff1a;本人使用的是 RTX2060 - 6G版 特别提醒&#xff1a;安装一定要 CUDA 和 PyTorch 版本能配套用&#xff0c;不然会有生成保存问题(我是这样的)&#xff0c;装完用 python -m xformers.info 这个看对应的版本 建议&#xff1a;有些命令安装在venv 虚拟机中做&…...

STM32F407+FreeRTOS+LWIP UDP组播

开发环境介绍&#xff1a; MCU&#xff1a;STM32F407ZET6 网卡&#xff1a;LAN8720A LWIP版本&#xff1a;V1.1.0 FreeRTOS 版本&#xff1a;V10.2.1 LAN8720A硬件原理图&#xff1a; 硬件连接说明&#xff1a; MII_RX_CLK/RMII_REF_CLK ------>PA1 …...

(源码+部署+讲解)基于Spring Boot + Vue的车位租赁系统设计与实现

前言 &#x1f497;博主介绍&#xff1a;✌专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅&#x1f447;&#x1f3fb; 2024年Java精品实战案例《100套》 &#x1f345;文末获取源码联系&#x1f345; &#x1f31f;…...

Lecture 2~4 About Filter

文章目录 空间域上的滤波器- 线性滤波器盒状滤波器Box Filter锐化Sharpening相关运算 vs. 卷积运算 Correlation vs. Convolution - 非线性滤波器高斯滤波器Gaussian filter - 实际问题- 纹理texture 频域上的滤波器 滤波的应用- 模板匹配- 图像金字塔 空间域上的滤波器 图像…...

【LINUX】Linux 命令大全:系统管理与网络操作指南

开始之前 Linux命令行&#xff0c;也称为终端&#xff0c;是Linux最强大的特性之一。通过命令行&#xff0c;用户可以执行几乎所有的任务&#xff0c;比如文件操作、程序安装、系统监控和网络配置等。了解这些基本命令&#xff0c;将帮助你更好地掌握Linux系统。 文件和目录操…...

Day50 动态规划 part11

Day50 动态规划 part11 123.买卖股票的最佳时机III 我的思路&#xff1a; 这道题考虑了交易次数 j&#xff08;最大次数为2&#xff09;&#xff0c;以及某天 i 应该买or卖股票&#xff08;两种状态&#xff09; 用三维数组表示 dp[i][j][0] – 第i天结束时&#xff0c;交易j…...

Docker 搭建私有镜像仓库

一、镜像仓库简介 Docker的镜像仓库是一个用于存储和管理Docker镜像的中央位置。镜像仓库的主要作用是提供一个集中的地方&#xff0c;让用户可以上传、下载、删除和共享Docker镜像。镜像仓库又可以分为公共镜像仓库和私有仓库镜像仓库&#xff1a; 公共镜像仓库 Docker Hub 是…...

Nginx反向代理与Tomcat实现ssm项目前后端分离部署

Nginx nginx是一款http和支持反向代理的web服务器&#xff0c;以其优越的性能被广泛使用。以下是百度百科的介绍。 Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器&#xff0c;同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔赛索耶夫为俄罗斯访问量第二的Rambler.…...

element UI 日期选择器 当前年份之前不可选

<el-date-pickertype"year"format"YYYY"value-format"YYYY"v-model"declareYear"placeholder"请选择年份":disabled-date"disabledDateFun"/>function disabledDateFun(time) {if (time.getFullYear() <…...

windows wireshark抓包rtmp推流出现TCP Retransmission

解决办法&#xff1a;tcp.port1935 && !(tcp.analysis.retransmission)...