(function (global) { 'use strict'; /** * Lightweight Canvas2D ring-buffer line chart with marker lines. * @constructor * @param {HTMLCanvasElement} canvas */ function RingChart(canvas) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.color = '#3794ff'; this.fill = 'rgba(55,148,255,0.15)'; this.min = null; this.max = null; } /** * Draw series and markers. * @param {number[]} values * @param {{t:number,label:string}[]} markers * @param {number[]} times */ RingChart.prototype.draw = function (values, markers, times) { var ctx = this.ctx; var canvas = this.canvas; var dpr = window.devicePixelRatio || 1; var cssW = canvas.clientWidth || 220; var cssH = canvas.clientHeight || 72; if (canvas.width !== Math.floor(cssW * dpr) || canvas.height !== Math.floor(cssH * dpr)) { canvas.width = Math.floor(cssW * dpr); canvas.height = Math.floor(cssH * dpr); } ctx.setTransform(dpr, 0, 0, dpr, 0, 0); ctx.clearRect(0, 0, cssW, cssH); ctx.fillStyle = '#111'; ctx.fillRect(0, 0, cssW, cssH); if (!values || values.length < 2) { ctx.fillStyle = '#666'; ctx.fillText('暂无数据', 8, 20); return; } var min = this.min; var max = this.max; if (min == null || max == null) { min = values[0]; max = values[0]; for (var i = 1; i < values.length; i++) { if (values[i] < min) min = values[i]; if (values[i] > max) max = values[i]; } if (min === max) { min -= 1; max += 1; } } var pad = 2; var t0 = times && times.length ? times[0] : 0; var t1 = times && times.length ? times[times.length - 1] : values.length - 1; var span = Math.max(1, t1 - t0); if (markers && markers.length && times && times.length) { ctx.strokeStyle = 'rgba(241,76,76,0.7)'; ctx.lineWidth = 1; for (var m = 0; m < markers.length; m++) { var mt = markers[m].t; if (mt < t0 || mt > t1) continue; var mx = pad + ((mt - t0) / span) * (cssW - pad * 2); ctx.beginPath(); ctx.moveTo(mx, 0); ctx.lineTo(mx, cssH); ctx.stroke(); } } ctx.beginPath(); for (var j = 0; j < values.length; j++) { var x = pad + (j / (values.length - 1)) * (cssW - pad * 2); var y = cssH - pad - ((values[j] - min) / (max - min)) * (cssH - pad * 2); if (j === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); } ctx.strokeStyle = this.color; ctx.lineWidth = 1.5; ctx.stroke(); ctx.lineTo(pad + (cssW - pad * 2), cssH - pad); ctx.lineTo(pad, cssH - pad); ctx.closePath(); ctx.fillStyle = this.fill; ctx.fill(); ctx.fillStyle = '#aaa'; ctx.font = '10px Consolas, monospace'; var last = values[values.length - 1]; ctx.fillText(String(Math.round(last * 100) / 100), 4, 12); }; global.PWRingChart = RingChart; })(window);