打造自己的图表控件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()

本期到此结束,下期实现坐标系映射和视点设置。

 

posted @ 2017-10-13 16:04  长蘑菇星人  阅读(199)  评论(0编辑  收藏  举报