打造自己的图表控件1
首先从最简单的折线图开始
一个最简单的折线图有如下部分(这是从Excel截取的)
X,Y坐标轴和折线图,所以可以把图表分成3个部分,左边,下边和中间。
这里,构造两个对象,来组织这些部分。
Chart 表示图表控件。
ChartElement 表示控件中的内容。
class Chart { constructor() { this.elements = [] } add(element) { element.attach(this) this.elements.push(element) } remove(element) { element.detach(this) this.elements.remove(element) } } class ChartElement { constructor() { this.chart = null } attach(chart) { this.chart = chart } detach(chart) { this.chart = null } }
但是有了这两个类,并不能画出来东西。所以还要构造出绘图的类CanvasDrawing和CanvasDrawingElement
class CanvasDrawing { constructor(width, height) { var canvas = this.canvas = document.createElement("canvas") canvas.width = width canvas.height = height this.width = width this.height = height this.context = canvas.getContext("2d") } init(dom) { dom.appendChild(this.canvas); } renderChart(chart) { for (var element of chart.elements) { if (element instanceof CanvasDrawingElement) { element.render(this.context, this.width, this.height) } } } } class CanvasDrawingElement extends ChartElement { constructor() { super() } render(context, width, height) { } }
到这里,已经获取基本满足画东西的需求了。
开始关键部分,画折线图。创建一个类,用来处理折线图
class SampleLineDrawing extends CanvasDrawingElement { constructor() { super() this.data = null //[ x1,y1,x2,y2 ] } render(context, width, height) { super.render(context, width, height) if (this.data != null) { context.save() context.strokeStyle = "#FF0000" context.beginPath() context.moveTo(this.data[0], this.data[1]); let length = this.data.length / 2 for (let i = 1; i < length; i++) { let x = this.data[2 * i] let y = this.data[2 * i + 1] context.lineTo(x, y) console.log(x, y) } context.stroke(); context.restore() } } }
最后调用一下
var width = 800 var height = 600 var chart = new Chart() var lineDrawing = new SampleLineDrawing() chart.add(lineDrawing) var chartDrawing = new CanvasDrawing(width, height) chartDrawing.init(document.body) function run() { requestAnimationFrame(run) lineDrawing.data = [] for (var i = 0; i < width; i++) { lineDrawing.data.push(i) lineDrawing.data.push(Math.random() * (500 - 200) + 200) } chartDrawing.renderChart(chart) } run()
本期到此结束,下期实现坐标系映射和视点设置。