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

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...

YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...