# visualize **Repository Path**: yindj/visualize ## Basic Information - **Project Name**: visualize - **Description**: 数据可视化 - **Primary Language**: JavaScript - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-11-16 - **Last Updated**: 2021-11-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 数据可视化 ![avatar](/canvans/static/images/intro.png) # canvas ## canvans实现直线图 ### ![avatar](/canvans/static/images/line.png) ## canvas绘制高清图 ### 01. 放大canvas ### 02. 在css中将宽高设置为原来的大小 ### 03. 考虑到内容的缩放,因此也需要将ctx 缩放 ## canvans 绘制坐标系 ### ![avatar](/canvans/static/images/axis.png) ```js const drawAxis = options => { const { ht, wd, pad, bottomPad, step, ctx } = options // 绘制坐标轴 ctx.beginPath() ctx.lineWith = 2 ctx.strokeStyle = 'lightblue' ctx.moveTo(pad, pad) ctx.lineTo(pad, ht * ratio - bottomPad) ctx.lineTo(wd * ratio - pad, ht * ratio - bottomPad) ctx.stroke() ctx.closePath() // 绘制X轴的刻度 ctx.beginPath() ctx.lineWidth = 1 ctx.strokeStyle = '#666' for (let i = 1; i < Math.floor(wd * ratio / step); i++) { ctx.moveTo(pad + i * step, ht * ratio - bottomPad) ctx.lineTo(pad + i * step, ht * ratio - bottomPad - 10) } ctx.stroke() ctx.closePath() // 绘制y轴的刻度 ctx.beginPath() ctx.lineWidth = 1 ctx.strokeStyle = '#666' for (let i = 1; i < Math.floor(ht * ratio / step); i++) { ctx.moveTo(pad, (ht * ratio - bottomPad) - (i * step)) ctx.lineTo(pad + 10, (ht * ratio - bottomPad) - (i * step)) } ctx.stroke() ctx.closePath() } ``` ## canvans 绘制矩形 ### ![avatar](/canvans/static/images/rect.png) ```js // 绘制矩形 // 填充+描边 ctx.beginPath() ctx.lineWidth = 5 ctx.strokeStyle = 'orange' ctx.fillStyle = 'hotpink' ctx.rect(100, 100, 100, 100) ctx.fill() ctx.stroke() ctx.closePath() // 描边 ctx.beginPath() ctx.lineWidth = 4 ctx.strokeStyle = 'seagreen' ctx.strokeRect(100, 210, 100, 100) ctx.closePath() // 填充 ctx.beginPath() ctx.fillStyle = 'skyblue' ctx.fillRect(210, 210, 100, 100) ctx.closePath() ``` ## canvans 动态绘制直方图 ### ![avatar](/canvans/static/images/dayrect.png) ```js ctx.beginPath() setInterval(() => { ctx.clearRect(0, 0, wd, ht) // 清空画布 for (let i = 1; i < Math.floor(wd * ratio / step); i++) { const height = Math.random() * 300 + 50; ctx.fillStyle = `#${parseInt(Math.random() * 0xFFFFFF).toString(16)}` ctx.fillRect((i * step), ht * ratio - bottomPad - height, 40, height) } }, 100) ctx.closePath() ``` ## 绘制圆 ### ![avatar](/canvans/static/images/circle.png) ```js // 绘制圆环 ctx.beginPath() ctx.lineWidth = 2 ctx.strokeStyle = 'orange' ctx.arc(200, 200, 100, 0, Math.PI / 4) ctx.stroke() ctx.closePath() // 绘制圆形 ctx.beginPath() ctx.fillStyle = 'skyblue' ctx.moveTo(200, 200) ctx.arc(200, 200, 50, 0, -Math.PI / 2) ctx.fill() ctx.closePath() ctx.beginPath() ctx.fillStyle = 'skyblue' moveTo(300,300) ctx.arc(300, 300, 50, 0, -Math.PI / 2, true) ctx.fill() ctx.closePath() ``` ## 绘制饼图 ### ![avatar](/canvans/static/images/pipe.png) ```js // 绘制饼图 ctx.beginPath() ctx.shadowOffsetX = 0 ctx.shadowOffsetY = 0 ctx.shadowBlur = 4 ctx.shadowColor = '#333' ctx.fillStyle = '#5c1918' ctx.moveTo(200, 200) ctx.arc(200, 200, 100, -Math.PI / 2, -Math.PI / 4) ctx.fill() ctx.closePath() ctx.beginPath() ctx.shadowOffsetX = 0 ctx.shadowOffsetY = 0 ctx.shadowBlur = 4 ctx.shadowColor = '#5c1918' ctx.fillStyle = '#A32D29' ctx.moveTo(200, 200) ctx.arc(200, 200, 110, -Math.PI / 4, Math.PI / 4) ctx.fill() ctx.closePath() ctx.beginPath() ctx.shadowOffsetX = 0 ctx.shadowOffsetY = 0 ctx.shadowBlur = 4 ctx.shadowColor = '#A32D29' ctx.fillStyle = '#B9332E' ctx.moveTo(200, 200) ctx.arc(200, 200, 120, Math.PI / 4, Math.PI * 5 / 8) ctx.fill() ctx.closePath() ctx.beginPath() ctx.shadowOffsetX = 0 ctx.shadowOffsetY = 0 ctx.shadowBlur = 4 ctx.shadowColor = '#B9332E' ctx.fillStyle = '#842320' ctx.moveTo(200, 200) ctx.arc(200, 200, 130, Math.PI * 5 / 8, Math.PI) ctx.fill() ctx.closePath() ctx.beginPath() ctx.shadowOffsetX = 0 ctx.shadowOffsetY = 0 ctx.shadowBlur = 4 ctx.shadowColor = '#842320' ctx.fillStyle = '#D76662' ctx.moveTo(200, 200) ctx.arc(200, 200, 140, Math.PI, -Math.PI / 2) ctx.fill() ctx.closePath() ``` ## 绘制文字 ### ![avatar](/canvans/static/images/text.png) ```js // 绘制居中线条 ctx.beginPath() ctx.lineWidth = 1 ctx.strokeStyle = '#ccc' ctx.moveTo(300,0) ctx.lineTo(300,500) ctx.stroke() ctx.closePath() ctx.beginPath() ctx.lineWidth = 1 ctx.strokeStyle = '#ccc' ctx.moveTo(0,250) ctx.lineTo(600,250) ctx.stroke() ctx.closePath() // 实心文字 描边文字 ctx.fillStyle = 'orange' ctx.strokeStyle = 'hotpink' ctx.font = 'bold 60px 微软雅黑' ctx.fillText('敲出真谛',100,125,100) ctx.strokeText('大前端',400,125) ctx.strokeText('可视化',100,375,100) ctx.fillText('全栈',400,375) // 设置水平和竖直对齐方式 ctx.textAlign = 'center' // left right start end center ctx.textBaseline = 'middle' // top bottom middle ctx.fillText('因为有你心存感激',300,250) ``` ## 绘制运动的小球 ### ![avatar](/canvans/static/images/oneBall.png) ```js const drawCircle = (x, y, r) => { ctx.beginPath() ctx.fillStyle = 'orange' ctx.arc(x, y, r, 0, Math.PI * 2) ctx.fill() ctx.closePath() } // 配置属性 const wd = canvans.clientWidth * ratio const ht = canvans.clientHeight * ratio let x = y = 100 const r = 20 let xSpeed = 6 let ySpeed = 4 drawCircle(x, y, r) // 动起来 setInterval(() => { ctx.clearRect(0, 0, wd, ht) // 清空画布 if (x - r <= 0 || x + r >= wd) { xSpeed = -xSpeed } if (y - r <= 0 || y + r >= ht) { ySpeed = -ySpeed } x += xSpeed y += ySpeed drawCircle(x, y, r) }, 20) ``` ## 绘制运动的多个小球 ### ![avatar](/canvans/static/images/Ball.png) ```js class Ball { constructor(canvans) { this.canvans = canvans this.ctx = this.canvans.getContext('2d') this.wd = this.canvans.clientWidth * ratio this.ht = this.canvans.clientHeight * ratio this.r = Math.random() * 40 + 10 this.x = Math.random() * (this.wd - (this.r * 2)) + this.r this.y = Math.random() * (this.ht - (this.r * 2)) + this.r this.color = '#' + parseInt(Math.random() * 0xFFFFFF).toString(16) this.xSpeed = Math.random() * 4 + 6 this.ySpeed = Math.random() * 6 + 4 this.init() } init() { this.run() this.draw() } draw() { this.ctx.beginPath() this.ctx.fillStyle = this.color this.ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI) this.ctx.fill() this.ctx.closePath() } run() { if (this.x - this.r <= 0 || this.x + this.r >= this.wd) { this.xSpeed = -this.xSpeed } if (this.y - this.r <= 0 || this.y + this.r >= this.ht) { this.ySpeed = -this.ySpeed } this.x += this.xSpeed this.y += this.ySpeed } } let ballArr = [] for (let i = 0; i < 100; i++) { let ball = new Ball(canvas) ballArr.push(ball) } // 动画 setInterval(() => { ctx.clearRect(0, 0, canvas.clientWidth * 1.5, canvas.clientHeight * 1.5) for (let i = 0; i < ballArr.length; i++) { let ball = ballArr[i] ball.init() } }, 30) ``` ## 绘制关系图 ### ![avatar](/canvans/static/images/diagram.png) ```js const canvans = document.getElementById('canvas') const ctx = canvans.getContext('2d') const getPixelRatio = context => { return window.devicePixelRatio || 1 } /** * 01. 放大canvas * 02. 在css中将宽高设置为原来的大小 * 03. 考虑到内容的缩放,因此也需要将ctx 缩放 * */ const ratio = getPixelRatio() const oldWith = document.documentElement.clientWidth - 10 const oldHeight = document.documentElement.clientHeight - 20 // 放大canvas canvans.width = document.documentElement.clientWidth * ratio canvans.height = document.documentElement.clientHeight * ratio // css中设置为原来的大小 canvans.style.width = oldWith + 'px' canvans.style.height = oldHeight + 'px' // 缩放ctx ctx.scale(ratio, ratio) class Ball { constructor(options) { this.canvans = options.canvans this.text = options.title this.ctx = this.canvans.getContext('2d') this.wd = this.canvans.clientWidth * ratio this.ht = this.canvans.clientHeight * ratio this.r = Math.random() * 40 + 10 this.x = Math.random() * (this.wd - (this.r * 2)) + this.r this.y = Math.random() * (this.ht - (this.r * 2)) + this.r this.color = '#' + parseInt(Math.random() * 0xFFFFFF).toString(16) this.xSpeed = Math.random() * 4 + 6 // [6,10) this.ySpeed = Math.random() * 6 + 4 // [4,10) this.init() } init() { this.run() this.draw() } // 绘制 draw() { this.drawCircle() this.drawText(this.text, this.x, this.y + this.r + 10) } // 绘制小球 drawCircle() { this.ctx.beginPath() this.ctx.fillStyle = this.color this.ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI) this.ctx.fill() this.ctx.closePath() } // 绘制文字 drawText(text, x, y) { this.ctx.font = 'normal 20px 微软雅黑' this.ctx.textAlign = 'center' this.ctx.textBaseline = 'middle' this.ctx.fillText(text, x, y) } // 绘制线条 drawLine(x1, y1, x2, y2, color) { this.ctx.beginPath() this.ctx.lineWidth = 1 this.ctx.strokeStyle = color || '#666' this.ctx.moveTo(x1, y1) this.ctx.lineTo(x2, y2) this.ctx.stroke() this.ctx.closePath() } /** * 小球运动边界处理 * */ run() { if (this.x - this.r <= 0 || this.x + this.r >= this.wd) { this.xSpeed = -this.xSpeed } if (this.y - this.r <= 0 || this.y + this.r >= this.ht) { this.ySpeed = -this.ySpeed } this.x += this.xSpeed this.y += this.ySpeed } } let ballArr = [] const titleArr = ['Vue', 'React', 'Node', 'Angular', 'Webpack', 'Vite', 'eCharts', 'Next', 'Git', 'uniApp'] for (let i = 0; i < 8; i++) { let ball = new Ball({ canvans, title: titleArr[i] }) ballArr.push(ball) // 连线 for (let j = 0; j < i; j++) { const preBall = ballArr[j] ball.drawLine(ball.x, ball.y, preBall.x, preBall.y) } } // 动画 setInterval(() => { ctx.clearRect(0, 0, canvas.clientWidth * 1.5, canvas.clientHeight * 1.5) for (let i = 0; i < ballArr.length; i++) { let ball = ballArr[i] // 连线 for (let j = 0; j < i; j++) { const preBall = ballArr[j] ball.drawLine(ball.x, ball.y, preBall.x, preBall.y) } } for (let i = 0; i < ballArr.length; i++) { let ball = ballArr[i] ball.init() } }, 30) ```