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、 根据后端返回的数据,动态绘制出信令图 2、根据 dataStatus 返回值: 0 和 1, 判断 文字内容的颜色,0:#000,1:red 3.、根据 lineType 返回值: 0 和 1, 判断 箭…...
无影云电脑不能连接到本机的调试串口的解决方案
目录 概述 解决方案 云端电脑中的操作 本地USBDK驱动程序的更新 概述 我从1月份开始使用阿里的无影云电脑进行嵌入式开发板的测试,主要的原因有两个:一是平时使用的笔记本资源过于紧张,二是方便移动办公,这样我只要平时拿着开…...
gpt科普1 GPT与搜索引擎的对比
GPT(Generative Pre-trained Transformer)是一种基于Transformer架构的自然语言处理模型。它通过大规模的无监督学习来预训练模型,在完成这个阶段后,可以用于各种NLP任务,如文本生成、机器翻译、文本分类等。 以下是关…...
Element-plus使用中遇到的问题
el-input 设置typenumber,会出现上下箭头,在全局配置css样式即可解决,在app.vue中的css中加入:.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进行编程调试,你需要进行一些准备工作和设置。以下是详细的操作步骤: 准备工作: 安装Arduino IDE:确保你已经安装了最新版本的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】开发板, 2G DDR RAM linux-imx 下载 使用 NXP 官方提供的 linux-imx,代码地址为: https://github.com/nxp-imx/linux-imx 使用 git 下载 linux-imxÿ…...
C语言每日一题(66)三数之和
题目链接 力扣15.三数之和 题目描述 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意:答…...
vue3-element-admin实现同一个菜单多标签
原框架代码: 赵志江/huzhushan-vue3-element-admin 目录 TagsBar实现 实现同一个菜单多标签 device/detail/:id,不同参数时页面缓存删不掉的问题 TagsBar实现 在src/layout/components/下新建目录Tagsbar,新建index.vue <template><div c…...
第三十六节 Java 网络编程
网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。 java.net包中J2SE的API包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注…...
DRF的认证、权限、限流、序列化、反序列化
DRF的认证、权限、限流、序列化、反序列化 一、认证1、直接用,用户授权2、认证组件源码 二、权限1. 直接使用,用户权限2.权限组件源码 三、序列化1. 序列化1.1 自定义Serailizer类序列化1.2 在视图APIView中使用1.3 自定义ModelSerializer类序列化1.4 不…...
解决:Cannot read properties of undefined (reading ‘validate‘)问题
问题:Element UI使用表单校验功能控制台出现Cannot read properties of undefined (reading validate)报错 解决:在 <el-form :model"form" :rules"rules">添加 ref"form",form为自定义的表单名称 <…...
关于IP地址发展历程的详细探讨
IP地址的发展历程是一段不断演进、适应网络技术发展的历史。自互联网诞生以来,IP地址作为网络设备的唯一标识,扮演了至关重要的角色。以下是对IP地址发展历程的详细探讨。 在互联网的初期,主机数量相对较少,IP地址主要用于区分不…...
【LeetCode热题100】【二叉树】将有序数组转换为二叉搜索树
题目链接:108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode) 取中间的数作为根节点,左边的数递归转换,右边的数递归转换 class Solution { public:TreeNode *sortedArrayToBST(vector<int> &nums) {retur…...
文心一言和GPT-4全面比较
自大型语言模型出现以来,人工智能在自然语言处理方面取得了显著进步。文心一言和GPT-4是当前最先进的两款语言模型,在业内广受关注。两者都具有强大的能力,但各有特点和优势。本文将从多个方面对这两个模型进行全面比较,以帮助读者…...
Mac的终端配置
Mac的终端配置 参考教程包管理工具 - Homebrew出现的问题用虚拟环境解决方案:直接将解释器的路径放过去错误方法:用find查找到虚拟环境安装的路径,其链接的是brew安装的python路径 编辑器没有报错,但是运行过程中仍然找不到pandas…...
制作一个RISC-V的操作系统十-Trap和Exception(流 mtvec mepc mcause mtval mstatus trap完整流程)
文章目录 流mtvecmepcmcausemtvalmstatustrap 初始化trap的top half(硬件完成)trap的bottom half(软件完成)从trap返回代码实现 流 控制流:程序控制的执行流 trap分为中断和异常 mtvec base:存储trap入…...
【爬虫开发】爬虫从0到1全知识md笔记第4篇:Selenium课程概要,selenium的介绍【附代码文档】
爬虫开发从0到1全知识教程完整教程(附代码资料)主要内容讲述:爬虫课程概要,爬虫基础爬虫概述,,http协议复习。requests模块,requests模块1. requests模块介绍,2. response响应对象,3. requests模块发送请求,4. request…...
对一个时间序列中的每个元素按照指定精度向上取整
【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 对一个时间序列中的每个元素 按照指定精度向上取整 例如:对小时处理, 则9:01处理为10:00 Series.dt.ceil() 选择题 以下代码的输出结果中正确的是? import pandas as…...
51单片机+TN901非接触式红外测温设计论文与源码PCB等资料
1、摘要 温度测量技术应用十分广泛,而且在现代设备故障检测领域中也是一项非常重要的技术。但在某些应用领域中,要求测量温度用的传感器不能与被测物体相接触,这就需要一种非接触的测温方式来满足上述测温需求。本论文正是应上述实际需求而设…...
AI创业项目:AI旅游规划定制师
在当前的旅游市场中,个性化旅游规划成为越来越多旅行者的需求。然而,现行的定制旅行服务主要依赖于人工定制师,这一模式面临着信息不透明、价格弹性大等挑战。定制师在客户与服务供应商之间掌握着信息差,依靠这一优势获得收益&…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...
Visual Studio Code 扩展
Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后,命令 changeCase.commands 可预览转换效果 EmmyLua…...
Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践
前言:本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中,跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南,你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案,并结合内网…...
