# src/chart/canvas.js

    function BBOX(opts) {
        let _opts = opts || {};
        this.minX = _opts.minX;
        this.minY = _opts.minY;
        this.maxX = _opts.maxX;
        this.maxY = _opts.maxY;
    }

    // Some Static Function bind with one Canvas context
    export default class Canvas {
        // Bound with a canvas element.
        static init(ele) {
            if (ele instanceof HTMLCanvasElement) {
                Canvas.canv = ele;
                Canvas.height = ele.height;
                Canvas.width = ele.width;
                // let the canvas's width/height cohere width DOM width/height.
                Canvas.ctx = ele.getContext("2d");
                Canvas.ctx.strokeStyle = "rgba(0,0,0,0.9)";
                Canvas.ctx.fillStyle = "rgba(10,200,240,0.4)";
                Canvas.ctx.strokeWidth = 1;
                Canvas.animate = false;
                Canvas.img = new Image();
            } else {
                console.error("ele is not instanceof CANVAS");
            }
        }

        /**
         * set ctx.strokeStyle with rgba() @string
         */
        static setStroke(colorStr) {
            if (Canvas.ctx) Canvas.ctx.strokeStyle = colorStr;
        }

        /**
         * set ctx.fillStyle with rgba(). @string
         */
        static setFill(colorStr) {
            if (Canvas.ctx) Canvas.ctx.fillStyle = colorStr;
        }

        /**
         * set ctx.strokeWidth and lineWidth. @number
         */
        static setWidth(pixel) {
            if (Canvas.ctx)
            {
                Canvas.ctx.lineWidth = pixel;
                Canvas.ctx.strokeWidth = pixel;
            }
        }

        /**
         * draw Circle with given x, y.
         * radius: radius of Circle @number
         * fill @bool
         */
        static drawPoint(coords, radius, fill, image, rotate, text){
            let imgWidth, imgHeight;
            Canvas.setFill("#EEE");
            Canvas.setStroke("#EE1");
            if (coords instanceof Array && coords.length == 2){
                Canvas.ctx.beginPath();
                if (image) {
                    Canvas.img.src = image;
                    if (radius) {
                        imgWidth = radius;
                        imgHeight = radius;
                    } else {
                        imgWidth = Canvas.img.width;
                        imgHeight = Canvas.img.height;
                    }
                    // drawImage(img, x2left, y2up, imgWidth, imgHeight)
                    // console.log("rendering drone..with width:" + imgWidth + " height:" + imgHeight);
                    let y = Canvas.height - coords[1];
                    if(rotate) Canvas.rotateCtx(coords, rotate);
                    Canvas.ctx.drawImage(Canvas.img, parseInt(coords[0]), parseInt(y),imgWidth,imgHeight);
                    if(rotate) Canvas.restore(coords);
                    return;
                }
                let y = Canvas.height - coords[1];
                Canvas.ctx.arc(parseInt(coords[0]), parseInt(y), radius, 0, Math.PI*2);

                if (typeof rotate == 'number') {
                    let tmp = rotate%(Math.PI*2) - Math.PI/2;
                    Canvas.ctx.arc(parseInt(coords[0]), parseInt(y), radius + 2, tmp-Math.PI/4, tmp+Math.PI/4);
                    // console.log("rendering drone..with rotate:" + tmp);
                }

                if (text) Canvas.ctx.fillText(text, coords[0], parseInt(y)-4);

                if (fill) {
                    Canvas.ctx.fill();
                } else {
                    Canvas.ctx.stroke();
                }
            }
            else return;
        }

        static restore(coords) {
            let y = Canvas.height - coords[1];
            Canvas.ctx.translate(parseInt(-coords[0]), parseInt(-y));
            Canvas.ctx.restore();
        }

        /**
         * rotate by the obj!
         * first save ctx and translate to the obj center..
         * draw obj after ctx rotate !!
         * then translate back and retore
         */
        static rotateCtx(coords, rotate) {
            Canvas.ctx.save();
            let y = Canvas.height - coords[1];
            Canvas.ctx.translate(parseInt(coords[0]), parseInt(y));
            Canvas.ctx.rotate(rotate);
        }

        /**
         * drawBar with given Value..
         * x: where to draw in X axis..
         * width: bar width,
         * value: bar y value.
         * fill: fill or stroke. default false.
         */
        static drawBar(x, width, value, fill) {
            let barY = Canvas.height - value;
            if (fill) {
                // fillRect(leftUP.X, Y, RectWidth, RectHeight)
                Canvas.ctx.fillRect(x, barY, width, value);
            } else {
                Canvas.ctx.strokeRect(x, barY, width, value);
            }
        }

        /**
         * drawRect with given BBox{minX, minY, maxX, maxY}
         */
        static drawRect(bbox, fill=false) {
            let _bbox = new BBOX(bbox),
                rectWidth = _bbox.maxX - _bbox.minX,
                rectHeight = _bbox.maxY - _bbox.minY;
            if (fill) {
                Canvas.ctx.fillRect(_bbox.minX, _bbox.minY, rectWidth, rectHeight);
            } else {
                Canvas.ctx.strokeRect(_bbox.minX, _bbox.minY, rectWidth, rectHeight);
            }
        }

        /**
         * drawLine with given Value..@Array
         * lwidth : lineWidth @number
         * dash: default false @bool
         * fill: closeLine to a polygon
         */
        static drawLine(data, lwidth, dash, fill) {
            if (data instanceof Array && data.length > 0) {
                Canvas.ctx.strokeStyle = "#FF0000";
                Canvas.ctx.lineWidth = lwidth? lwidth: 2;
                Canvas.ctx.beginPath();
                // for drawing area close with xaxis.. render first point.
                if (fill) {
                    Canvas.ctx.moveTo(-100, Canvas.height);
                }
                for (let i = 0; i < data.length; i++) {
                    // each point of line contains x, y.
                    if (data[i] instanceof Array && data[i].length == 2) {
                        let pointy = Canvas.height - data[i][1];
                        Canvas.ctx.lineTo(data[i][0], pointy);
                    }
                }
                if (fill) {
                    // close with beginPath point
                    Canvas.ctx.lineTo(data[data.length-1][0], Canvas.height);
                    Canvas.ctx.closePath();
                    // Canvas.ctx.stroke();
                    Canvas.ctx.fill();
                } else {
                    Canvas.ctx.stroke();
                }

            }
        }

        /**
         * draw Math.sin with canvas.
         */
        // static drawDemoline() {
        //     let base = 50;

        // }

        /**
         * drawBars with given data..
         * width: bar width,
         * data: Array of values..
         * fill: fill or stroke. default false.
         */
        static drawBars(data, fill) {
            Canvas.clearCanv();
            Canvas.ctx.strokeStyle = "#000";
            Canvas.setWidth(2);
            let barY, barX = 10;
            if (data instanceof Array) {
                let segWidth = (Canvas.width-20)/data.length;
                let barWidth = segWidth * 0.7;
                for (let i = 0; i < data.length; i ++) {
                    Canvas.drawBar(barX, barWidth, data[i]);
                    barX += segWidth;
                }
            } else {
                console.error('pls Input Array Data');
            }
            console.warn("Bars rendered complete..");
        }

        static clearCanv() {
            Canvas.ctx.clearRect(0,0,Canvas.width,Canvas.height);
            // Canvas.setFill("#000");
            // Canvas.ctx.fillRect(0,0,Canvas.width,Canvas.height);
        }

    }