预览地址 http://132.232.99.217:8090/#/

上期我们说了如何创建项目并把各个项目的文件结构创建好后这期我们来说如何画出图中代写线段

首先我们在src/components/Render.vue中添加一下引用

import zrender from 'zrender'
import {chartData,configData} from '@/mock/index' 这是mock数据
import { createLine,createCircle,addHover,createPolygon,hoverLine } from '../js/utli' 这是负责创建线段 阴影图等 公共方法 该文件在文章底部
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex' 这是vuex负责存储数据

然后我们在data里写入以下属性

//线段开始横坐标lineStartX:0,//线段开始纵坐标lineStartY:0,//线段结束横坐标lineEndX:0,//线段结束纵坐标LineEndY:0,//多少个y轴坐标xLineLen:{//天数 7天 day:0,//一天多少分段time:6},canavsWidth:0, //画板宽度canavsHeight:0, //画板高度zr:"", //画板属性yLineLen:{XRegion:13, //X轴坐标分几个大块XShare:5, //每块份几个小块XLineArr:[3], //需要特殊处理的横线 冲上往下算},YLineReset:[], //Y轴每一小格份几份width:0,YCellHeight:0, //y轴大格子高度lastData:0,  //上一个数据CircleSize:8, //画板上圆点的直径hoverCircleSize:10,//画板上圆点移入变化的直径fontSize:15, //画板上圆圈里的字体大小

这些属性都是以数据的形式来创建画板的横坐标 竖坐标 横线 竖线 基础属性创建好后我们在methods里先创建一个init方法 该方法负责初始化创建一个cavans画板 以及获取一些页面基础属性

init(){this.zr = zrender.init(document.getElementById("main"))var div = document.createElement("div")div.classList.add("tips")document.getElementById("main").append(div)this.canavsWidth = this.zr.getWidth()this.canavsHeight = this.zr.getHeight()if (this.httpType == 'http') {this.$axios({method:'post',url:`${this.configUrl}/api/PatrolInfo/ChartData`,data:{"PatientCode":this.urlData['cstId'],"beginDate":this.urlData['begin'],"endDate":this.urlData['end'],"PatroInfoType":this.urlData['PatroInfoType']},}).then(res => {res = res.data.Datathis.xLineLen.time = this.TimeArr.lengththis.YLineReset = this.resetY(this.TimeArr)this.filterData(res)this.yLine() //生成Y轴坐标this.xLine() //生成X轴坐标this.getCellHeight()})}else{this.xLineLen.time = this.TimeArr.lengththis.xLineLen.day = 7this.YLineReset = this.resetY(this.TimeArr)this.filterData(chartData)this.yLine() //生成Y轴坐标this.xLine() //生成X轴坐标this.getCellHeight()}// this.hoverLine()},

这里使用了一个判断 来判断当前是本地版本还是线上版本

这里的httpType通过src/store/http.js来配置是本地还是线上 没有文件请先创建

http.js httpType是mock就是本地 http就是线上

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'Vue.use(Vuex)const store = new Vuex.Store({state:{configUrl:'', //先自己的请求地址httpType:"mock",data:JSON.parse(localStorage.getItem('patientData')), //此方法可用可不用  用于基础普通html项目是使用},mutations:{},actions:{getUrlData(context){context.commit('setUrlData',data)}}
})export default store

init方法创建好后里面有4个方法分别是

this.filterData(res) 过滤数据
this.yLine() //生成Y轴坐标
this.xLine() //生成X轴坐标
this.getCellHeight() 获取格子的总高度

yLine() {//横坐标 最底部横坐标let Xline = new zrender.Line({shape:{x1:0,y1:this.canavsHeight,x2:this.canavsWidth,y2:this.canavsHeight}})this.zr.add(Xline)const yWidth = this.canavsWidth/this.xLineLen.day//循环显示竖线格子 红色竖线for (let i = 0; i < this.xLineLen.day; i++) {//纵坐标let Yline = new zrender.Line({shape:{x1:yWidth*i,y1:0,x2:yWidth*i,y2:this.canavsHeight},style:{opacity:1,lineWidth:1,stroke:"#ff0000"}})this.zr.add(Yline)}let yLinAll = this.xLineLen.day*this.xLineLen.timefor (let i = 0; i < yLinAll; i++) {let Yline = new zrender.Line({shape:{x1:yWidth/this.xLineLen.time*i,y1:0,x2:yWidth/this.xLineLen.time*i,y2:this.canavsHeight},style:{opacity:1,lineWidth:0.5,stroke:"#000"}})this.zr.add(Yline)}},xLine(){let xHeight = this.canavsHeight/this.yLineLen.XRegionlet XShareAll = this.yLineLen.XRegion*this.yLineLen.XSharefor (let i = 0; i < this.yLineLen.XRegion; i++) {let color = "#000"this.yLineLen.XLineArr.forEach(el => {if (el == i) {color = "#ff0000"}});//横坐标 加粗let Xline = new zrender.Line({shape:{x1:0,y1:xHeight*i,x2:this.canavsWidth,y2:xHeight*i},style:{opacity:1,lineWidth:2,stroke:color}})this.zr.add(Xline)for (let a = 0; a < XShareAll; a++) {//横坐标let Xline = new zrender.Line({shape:{x1:0,y1:xHeight/this.yLineLen.XShare*a,x2:this.canavsWidth,y2:xHeight/this.yLineLen.XShare*a},style:{opacity:1,lineWidth:0.4,stroke:"#000"}})this.zr.add(Xline)}}},filterData(data){//重置信息 避免重复出现的bugthis.lastData = 0data.forEach((el,i) => {switch (el.type) {case "text":this.zrText(el)break;case "line":this.zrLine(el)break;case "area":this.zrPolyline(el)break;case "tag":this.zrTag(el)break;default:break;}});},

横纵坐标创建好后我们就开始创建折线 阴影等图

//绘制文本内容zrText(data){if (this.xLineLen.day*24 >= data.time) {//最小值const cellMin = data.cellMin//坐标轴每格代表值const cellSplit = data.cellSplitvar textWidthHeight = 15 //一个字的原始宽度高度var textHeight = 0 //字体总高度var textWidth = textWidthHeight //字体总宽度var moveRange = textWidthHeight/2 //需要移动的距离 用于移动字体下面的矩形背景框//计算文本高度if (data.text) {let dataLen = data.text.split("\n").length//需要换行的字体 移动距离是字体的一半 每个字宽度,高度为12if (dataLen > 1) {textHeight = dataLen * textWidthHeighttextWidth = textWidthHeight} else {let textLen = data.text.lengthtextHeight = textWidthHeighttextWidth = textWidthHeight * textLenmoveRange = textWidthHeight}}let xWidth = this.XShareOne(data.time)//如果和上一个时间相同就往后移动if ( this.lastData != 0 || data.time <= 1 ) {if (this.lastData == data.time) {xWidth = xWidth + textWidth + 5}}this.lastData = data.time  //存入当前时间 用于重合区分let YHeight = this.YShareOne().heightlet y = this.transformY(data.position,cellSplit,cellMin)let state = new zrender.Group();state.add(new zrender.Rect({shape:{x:xWidth-(textWidth/2),y:y,width:textWidth,height:textHeight},style:{fill:"#FFF"},zlevel:4}))state.add(new zrender.Text({style:{text:data.text,textShadowColor:"#fff",textStroke:"#fff",textFill:data.color,textAlign:"center",fontSize:13},position:[xWidth,y],zlevel:4}));this.zr.add(state)}},
zrLine(data){var style = {}//最小值const cellMin = data.cellMin//坐标轴每格代表值const cellSplit = data.cellSplitdata.array.forEach((el,i) =>{//过滤shape 个别需特殊处理 后期需优化switch (el.shape) {case "x-circle":style = {stroke:data.color,fill:"#fff",text:"x",fontSize:this.fontSize}break;case "empty-circle":style = {stroke:data.color,fill:"#fff",text:"",}break;case 'x':style = {stroke:data.color,fill:"#fff",text:"x",fontSize:this.fontSize}break;case 'o-circle':style = {stroke:data.color,fill:"#fff",text:"●",fontSize:this.fontSize}break;case '':style = {stroke:data.color,fill:data.color,text:"",}break;default:break;}//疼痛单独处理if (el.type == "pain") {style = {stroke:data.color,fill:"#fff",text:"",}}if (i > 0) {let firstX = this.getX(data.array[i-1].time)  let firstY = this.transformY(data.array[i-1].value,cellSplit,cellMin)let x = this.getX(data.array[i].time)let y = this.transformY(data.array[i].value,cellSplit,cellMin)if (data.array[i-1].Break == "false") {let line = createLine(firstX,firstY,x,y,{stroke:data.color,lineWidth:2,})this.zr.add(line)}}if (el.extraArr && el.extraArr.length > 0) {el.extraArr.forEach((item,a) => {console.log(item);let x = this.getX(el.time)let y = this.transformY(el.value,cellSplit,cellMin)let lastY =  this.transformY(item.extra,cellSplit,cellMin)let dottedLine = createLine(x,y,x,lastY,{stroke:data.color,lineWidth:3,lineDash:[2,2]})this.zr.add(dottedLine)el.extraArr.forEach((item,a) => {let getY = this.transformY(item.extra,cellSplit,cellMin)let Circle = createCircle(x,getY,this.CircleSize,{stroke:item.extraColor,fill:"#fff",})this.zr.add(Circle)addHover(Circle,{tips:item.extraTips,},x,getY,{r:this.hoverCircleSize,},{r:this.CircleSize,})})})}let getX = this.getX(el.time)let getY = this.transformY(el.value,cellSplit,cellMin)let Circle = createCircle(getX,getY,this.CircleSize,style)this.zr.add(Circle)addHover(Circle,el,getX,getY,{r:this.hoverCircleSize,},{r:this.CircleSize,})})},//多边形zrPolyline(data){console.log(data);//最小值const cellMin = data.cellMin//坐标轴每格代表值const cellSplit = data.cellSplitvar points = []data.array.forEach((el,i) => {//生成圆点let cx = this.getX(el.time)let cy1 = this.transformY(el.v1,cellSplit,cellMin)let Circle1 = createCircle(cx,cy1,this.CircleSize,{stroke:data.color,fill:"#fff",text:"",})this.zr.add(Circle1)addHover(Circle1,{tips:el.v1Tips},cx,cy1,{r:this.hoverCircleSize,},{r:this.CircleSize,})let cy2 = this.transformY(el.v2,cellSplit,cellMin)let Circle2 = createCircle(cx,cy2,this.CircleSize,{stroke:data.color,fill:data.color,text:"",})this.zr.add(Circle2)addHover(Circle2,{tips:el.v2Tips},cx,cy2,{r:this.hoverCircleSize,},{r:this.CircleSize,})if (i > 0) {if (data.array[i-1].Break == "false") {points = []let pox1 = this.getX(data.array[i-1].time)let poy1 = this.transformY(data.array[i-1].v1,cellSplit,cellMin)let poy2 = this.transformY(data.array[i-1].v2,cellSplit,cellMin)let pox3 = this.getX(el.time)let poy3 = this.transformY(el.v1,cellSplit,cellMin)let poy4 = this.transformY(el.v2,cellSplit,cellMin)points.push([pox1,poy1],[pox1,poy2],[pox3,poy4],[pox3,poy3],[pox1,poy1])let area = createPolygon(points,{fill:data.bgColor,opacity:0.8,stroke:data.color})this.zr.add(area)}}})},zrTag(data){//最小值const cellMin = data.cellMin//坐标轴每格代表值const cellSplit = data.cellSplitif (data.text == "R") {data.array.forEach((el,i) => {let x = this.getX(el.time)let y = this.transformY(el.value,cellSplit,cellMin)let Circle = createCircle(x,y,this.CircleSize,{text:data.text,fill:"#fff",stroke:data.color,textVerticalAlign:"middle",textAlign:"center",})this.zr.add(Circle)addHover(Circle,{tips:""},0,0,{r:this.hoverCircleSize,},{r:this.CircleSize,})})}if(data.text == "H"){data.array.forEach((el,i) => {let x = this.getX(el.time)let y = this.transformY(el.y,cellSplit,cellMin)let Circle = createCircle(x,y,this.CircleSize,{text:data.text,fill:"#fff",stroke:data.color,textVerticalAlign:"middle",textAlign:"center"})this.zr.add(Circle)addHover(Circle,{tips:""},0,0,{r:this.hoverCircleSize,},{r:this.CircleSize,})})}},

创建图形是还需要写几个方法
用于获取x轴小格子的宽度
y轴小格子宽度
以及每日时间变化后每个坐标点的定位

//每个x轴小格子宽度是多少XShareOne(data){let widthArr = [] //每格宽度 全部存入数组var width = 0let YLineResetAll = []  //7天所有份数for (let i = 0; i < 7; i++) {YLineResetAll.push(...this.YLineReset)}for (let i = 0; i < parseInt(data); i++) {width = YLineResetAll[i].width + width}return width},//每个Y轴小格子宽度是多少YShareOne(){//计算大格子里的每格小格子高度let childerHeight = this.canavsHeight/this.yLineLen.XRegion/this.yLineLen.XShare//计算大格高度let height = this.canavsHeight/this.yLineLen.XRegionreturn {height:height,childerHeight:childerHeight}},//转换y轴坐标点为正确坐标点 因为y轴坐标是顶点为0递增的 所有用总高度减去原来坐标的高度剩下的高度就是正确坐标点//i代表一个格子代表几个高度transformY(data,i,cellMin){let YHeight = this.YShareOne().heightlet YHeightChilder = this.YShareOne().childerHeightlet xAll = this.yLineLen.XRegion  //一共多少个横坐标 大的let surplusHeightvar cellAll = this.yLineLen.XRegion*this.yLineLen.XShare //一共多少个横坐标let index = cellMinvar aIndex = 0let lastNumber = 0//总共占几格for (let a = 0; a < cellAll; a++) {//每格代表的值小于0的时候 需要特殊处理if (parseInt(i) == 0) {let floatNumber = this.getFloat(index,1)if (floatNumber <= this.getFloat(data,1)) {lastNumber = floatNumberaIndex = asurplusHeight = this.canavsHeight -this.getFloat(YHeightChilder,1)*a}}else{if (index <= data) {lastNumber = indexaIndex = asurplusHeight = this.canavsHeight - YHeightChilder*a}}index = index+i}if (lastNumber-data < 0) {surplusHeight = surplusHeight -YHeightChilder/2}return surplusHeight},

transformY(data,i,cellMin)这个方法里的逻辑比较复杂 后面我们在单独讲
下面是几个基础方法
resetY方法也是一个重点后面再讲

//获取X坐标 data当前时间点getX(data){let XShareOne = this.XShareOne(data)return XShareOne},//重置y轴坐标间隔条数 传入日期数组 格式["1","3","4","5","6","18","21","24"]resetY(data){let oneYLinWidth = this.canavsWidth/this.xLineLen.day/this.xLineLen.time //每个时间点格子宽度let resetArr = [] //得到的新数组data.forEach((item,i) => {if (i == 0) {for (let index = 0; index < item; index++) {resetArr.push({width:oneYLinWidth/2/item})}}else{let indexItem = item - data[i-1]for (let index = 0; index < indexItem; index++) {resetArr.push({width:oneYLinWidth/indexItem})}if (i+1 == data.length) {let indexItem = 24 - itemfor (let index = 0; index < indexItem; index++) {resetArr.push({width:oneYLinWidth/2/indexItem})}}}})return resetArr},getFloat(num,n){n = n ? parseInt(n) : 0;if(n <= 0) {return Math.round(num);}num = Math.round(num * Math.pow(10, n)) / Math.pow(10, n); //四舍五入num = Number(num).toFixed(n); //补足位数return num;},getCellHeight(){//yHeight Y轴每个小格子高度 xHeight X轴每个小格子宽度let xWidth = this.canavsWidth / this.xLineLen.day / this.xLineLen.timethis.$emit('yHeight',this.YShareOne().height)this.$emit('xHeight',xWidth)},hoverLine(){var timer = null;let line = new zrender.Line({shape:{x1:0,y1:0,x2:0,y2:this.canavsHeight},})this.zr.add(line)hoverLine(this.zr,line,this.canavsHeight)}
<template><div id="main"></div>
</template>

这是创建初始cavans需要用的

<style scoped>#main{height: 1250px;width: 100%;position: relative;}html,body{height: 100%;width: 100%;margin: 0;padding: 0;}canvas{width: 100%;height: 700px;}
</style>

然后是src/js/utli.js里的各个方法

import zrender from "zrender"
import moment from 'moment';//线段
export const createLine = (x1,y1,x2,y2,style)=>{return new zrender.Line({shape:{x1:x1,y1:y1,x2:x2,y2:y2},style:style,});
};
// cx 横坐标 cy纵坐标 r半径 空心圆
export const createCircle = (cx,cy,r,style)=>{return new zrender.Circle({shape:{cx:cx,cy:cy,r:r},style:style,zlevel:4})
}
//添加horver事件 el 元素对象 config 一些配置项 x x轴坐标 y y轴坐标 shapeOn鼠标移入一些属性配置 shapeOn鼠标移出一些属性配置 shape配置项看官网
export const addHover = (el,config,x,y,shapeOn,shapeOut) => {const domTips = document.getElementsByClassName("tips")el.on('mouseover',function(){domTips[0].innerHTML = config.tipslet textWidth = config.tips.length*15domTips[0].setAttribute("style",`position:absolute;top:${y-30}px;left:${x-textWidth/2}px;display:block;font-size:10px;background-color:rgba(0,0,0,.7);padding:3px 2px;border-radius:2px;color:#fff;width:${textWidth}px;text-align:center`)el.animateTo({shape:shapeOn},100,0)}).on('mouseout',function () {domTips[0].setAttribute("style",`display:none`)el.animateTo({shape:shapeOut},100,0)})
}
//多边形
export const createPolygon = (points,style) => {return new zrender.Polyline({shape:{points:points,},style:style})
}export const hoverLine = (el,line,y2) => {window.onmousemove = function (e) {line.animateTo({shape:{x1:e.offsetX,y1:0,x2:e.offsetX,y2:y2}},50,0)}
}
//时间格式化
export const getFullTime = (i) => {return moment(i).format("YYYY-MM-DD HH:mm:ss");
}
//贝塞尔曲线
export const BezierCurve = (x1,y1,x2,y2,cpx1,cpy1,style) => {return new zrender.BezierCurve({shape:{x1:x1,y1:y1,x2:x2,y2:y2,cpx1:cpx1,cpy1:cpy1},style:style,});
}

这里创建完成后画板区域基本完成加上数据就能看见效果了

关注公众号回复 体温单 获取源代码

源码下载地址https://download.csdn.net/download/qq_37347787/37274072

使用vue+zrender绘制体温单 三测单(2)相关推荐

  1. 医疗系统--体温单(三测单)系统(体温单控件)

    不同区域的体温单格式不尽相同,本文以江苏某地体温单为范例,介绍完整的体温单系统开发. 1.名词解释 体温单:又叫三测单,是护理病历的一部分.体温单主要用于记录患者的生命体征及有关情况,内容包括患者姓名 ...

  2. 使用vue+zrender绘制体温单 三测单(1)

    先上预览地址 http://132.232.99.217:8090/#/ 1.创建项目 使用vue init webpack temperaure 创建一个vue项目 然后安装axios zrende ...

  3. 关于java的提问单_使用vue+zrender绘制体温单 三测单(1)

    1.创建项目 使用vue init webpack  temperaure 创建一个vue项目 然后安装axios zrender 命令分别是 npm install axios -S npm ins ...

  4. react svg 实现体温单 三测单

    技术栈:react svg 效果图: 开发电子病历可以用此控件

  5. 体温单源码 delphi体温单源码 又叫三测单

    体温单:又叫三测单,是护理病历的一部分.体温单主要用于记录患者的生命体征及有关情况,内容包括患者姓名.年龄.性别.科别.床号.入院日期.住院号(或病案号).日期.住院天数.手术后天数.脉搏.呼吸.体温 ...

  6. 最新医疗系统三测单控件(体温单控件)

    最新实现的医疗系统中的三测单控件,很早之前(好像2年前),实现了一个体温单控件,那个时候,由于刚刚做Delphi没多久,所以,做的不是很灵活,很多东西都写死了,最终还是依靠东拼西凑的,凑了一个控件出来 ...

  7. html 体温单源码,体温单 三色单

    [实例简介] 根据护理记录数据绘出体温单,三色单,附带源码 [实例截图] [核心代码] 体温单控件源码 └── 体温单控件源码 ├── TemperatureChart.dll ├── 体温单源码+数 ...

  8. vue 绘制体温单与三测单组件 实现前端js打印

    更新: 代码开源 https://github.com/mydaoyuan/my-development 有帮助请帮忙点个 start .企鹅:1534815114 如何使用chatGPT辅助开发复杂 ...

  9. html 绘制体温单,使用zrender.js绘制体温单效果

    今天我们来画折线图 效果图 以下为模拟数据 [{"time":19,"text":"入\n院\n19\n时\n11\n分","po ...

最新文章

  1. 使用Redis 管理事务(Java)
  2. dz linux wind 数据库,Discuz!数据转换/Discuz!数据转换phpwind教程
  3. 天兔(Lepus)监控邮件推送安装配置
  4. android 颜色填充工具栏,Android工具栏颜色未由colorPrimary设置
  5. 在监控网络项目中该如何选择光纤交换机?
  6. InnoDB还是MyISAM?
  7. 290种零食大统计,谁能唤起80、90后的童年回忆?|数据会说话
  8. MYSQL基础(事务,触发器,函数,过程指令操作)
  9. python 调用mysql存储过程返回结果集
  10. 科学技术的不完备性及其实践意义
  11. 一句话告诉你为什么有些jQuery插件会有特殊字符(加号、减号、感叹号等)
  12. mumu模拟器cpu设置_网易MuMu模拟器CPU虚拟化怎么设置?
  13. ARM汇编之TCP Bind Shell
  14. 大周末的不休息,继续学习pandas吧,pandas你该这么学,No.7
  15. 网络工程师提高篇 | 路由重发布你了解多少?从原理到配置,瑞哥带你学习一波!
  16. 将一个数组中重复的元素去除,并且返回一个新数组
  17. 京东主图视频上传,如何关联商品投放?
  18. 数据分析模型:OGSM模型
  19. 【51单片机实验】4-单片机定时/计数器的应用(附Proteus电路)
  20. 不要再这样做shopee虾皮跨境电商,不然有苦说不出

热门文章

  1. [RISC-V MCU 应用开发]基于CH32V307和TtencentOS Tiny的物联网心率监测
  2. android模拟器不能运行 控制台显示 VCPU shutdown request
  3. 550w计算机电源,GTX 1080显卡配550W电源够用不?老司机来告诉你如何DIY电脑主机...
  4. Matlab绘制二维(三维)图形时设置对数坐标轴
  5. 峭度度量非高斯分布的理论知识
  6. 抓取WIFI空中包工具--OmniPeek
  7. 数字信号处理|Matlab设计巴特沃斯低通滤波器(冲激响应不变法和双线性变换法)
  8. Python之数据处理与可视化
  9. 【手把手指导】给开源项目贡献代码
  10. VB程序逆向反汇编常见的函数