Skip to content

palette

js
class Palette {
    constructor(canvas, {drawType = 'line', drawColor = 'rgba(19, 206, 102, 1)', lineWidth = 5, sides = 3, allowCallback, moveCallback}) {
        this.canvas = canvas;
        this.width = canvas.width; // 宽
        this.height = canvas.height; // 高
        this.paint = canvas.getContext('2d');
        this.isClickCanvas = false; // 是否点击canvas内部
        this.isMoveCanvas = false; // 鼠标是否有移动
        this.imgData = []; // 存储上一次的图像,用于撤回
        this.index = 0; // 记录当前显示的是第几帧
        this.x = 0; // 鼠标按下时的 x 坐标
        this.y = 0; // 鼠标按下时的 y 坐标
        this.last = [this.x, this.y]; // 鼠标按下及每次移动后的坐标
        this.drawType = drawType; // 绘制形状
        this.drawColor = drawColor; // 绘制颜色
        this.lineWidth = lineWidth; // 线条宽度
        this.sides = sides; // 多边形边数
        this.allowCallback = allowCallback || function () {}; // 允许操作的回调
        this.moveCallback = moveCallback || function () {}; // 鼠标移动的回调
        this.bindMousemove = function () {}; // 解决 eventlistener 不能bind
        this.bindMousedown = function () {}; // 解决 eventlistener 不能bind
        this.bindMouseup = function () {}; // 解决 eventlistener 不能bind
        this.bindTouchstart = function () {}; 
        this.bindTouchmove = function () {}; 
        this.bindTouchend = function () {}; 
        this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
        this.init();
        this.isCando = false;
        console.log(this.isMobile)
    }
    init() {
        this.paint.fillStyle = '#fff';
        this.paint.fillRect(0, 0, this.width, this.height);
        this.gatherImage();
        this.bindMousemove = this.onmousemove.bind(this); // 解决 eventlistener 不能bind
        this.bindMousedown = this.onmousedown.bind(this);
        this.bindMouseup = this.onmouseup.bind(this);
        this.bindTouchstart = this.touchstart.bind(this); // 解决 eventlistener 不能bind
        this.bindTouchmove = this.touchmove.bind(this);
        this.bindTouchend = this.touchend.bind(this);
        if(!this.isMobile){
            this.canvas.addEventListener('mousedown', this.bindMousedown);
            document.addEventListener('mouseup', this.bindMouseup);
        } else {
            this.canvas.addEventListener('touchstart', this.bindTouchstart);
            document.addEventListener('touchend', this.bindTouchend);
        }
        
    }
    onmousedown(e) { // 鼠标按下
        if(!this.isCando) return
        this.isClickCanvas = true;
        this.x = e.offsetX;
        this.y = e.offsetY;
        this.last = [this.x, this.y];
        this.canvas.addEventListener('mousemove', this.bindMousemove);
    }
    gatherImage() { // 采集图像
        this.imgData = this.imgData.slice(0, this.index + 1); // 每次鼠标抬起时,将储存的imgdata截取至index处
        let imgData = this.paint.getImageData(0, 0, this.width, this.height);
        this.imgData.push(imgData);
        this.index = this.imgData.length - 1; // 储存完后将 index 重置为 imgData 最后一位
        this.allowCallback(this.index > 0, this.index < this.imgData.length - 1);
    }
    reSetImage() { // 重置为上一帧
        this.paint.clearRect(0, 0, this.width, this.height);
        if(this.imgData.length >= 1){
            this.paint.putImageData(this.imgData[this.index], 0, 0);
        }
    }
    touchstart(e) {
        e.preventDefault();
        if(!this.isCando) return
        this.isClickCanvas = true;
        this.x = e.touches[0].clientX;
        this.y = e.touches[0].clientY;
        this.last = [this.x, this.y];
        this.canvas.addEventListener('touchmove', this.bindTouchmove);
    }
    touchmove(e) {
        e.preventDefault();
        this.isMoveCanvas = true;
        let endx = e.touches[0].clientX;
        let endy = e.touches[0].clientY;
        let width = endx - this.x;
        let height = endy - this.y;
        let now = [endx, endy]; // 当前移动到的位置
        this.switchTypeDraw(now, width, height)
    }
    touchend() {
        if (this.isClickCanvas) {
            this.isClickCanvas = false;
            this.canvas.removeEventListener('touchmove', this.bindTouchmove);
            if (this.isMoveCanvas) { // 鼠标没有移动不保存
                this.isMoveCanvas = false;
                this.moveCallback('gatherImage');
                this.gatherImage();
            }
        }
    }
    switchTypeDraw(now, width, height){
        switch (this.drawType) {
            case 'line' : {
                let params = [this.last, now, this.lineWidth, this.drawColor];
                this.moveCallback('line', ...params);
                this.line(...params);
            }
                break;
            case 'rect' : {
                let params = [this.x, this.y, width, height, this.lineWidth, this.drawColor];
                this.moveCallback('rect', ...params);
                this.rect(...params);
            }
                break;
            case 'polygon' : {
                let params = [this.x, this.y, this.sides, width, height, this.lineWidth, this.drawColor];
                this.moveCallback('polygon', ...params);
                this.polygon(...params);
            }
                break;
            case 'arc' : {
                let params = [this.x, this.y, width, height, this.lineWidth, this.drawColor];
                this.moveCallback('arc', ...params);
                this.arc(...params);
            }
                break;
            case 'eraser' : {
                let params = [endx, endy, this.width, this.height, this.lineWidth];
                this.moveCallback('eraser', ...params);
                this.eraser(...params);
            }
                break;
        }
    }
    onmousemove(e) { // 鼠标移动
        this.isMoveCanvas = true;
        let endx = e.offsetX;
        let endy = e.offsetY;
        let width = endx - this.x;
        let height = endy - this.y;
        let now = [endx, endy]; // 当前移动到的位置
        this.switchTypeDraw(now, width, height)
    }
    onmouseup() { // 鼠标抬起
        if (this.isClickCanvas) {
            this.isClickCanvas = false;
            this.canvas.removeEventListener('mousemove', this.bindMousemove);
            if (this.isMoveCanvas) { // 鼠标没有移动不保存
                this.isMoveCanvas = false;
                this.moveCallback('gatherImage');
                this.gatherImage();
            }
        }
    }
    line(last, now, lineWidth, drawColor) { // 绘制线性
        this.paint.beginPath();
        this.paint.lineCap = "round"; // 设定线条与线条间接合处的样式
        this.paint.lineJoin = "round";
        this.paint.lineWidth = lineWidth;
        this.paint.strokeStyle = drawColor;
        this.paint.moveTo(last[0], last[1]);
        this.paint.lineTo(now[0], now[1]);
        this.paint.closePath();
        this.paint.stroke(); // 进行绘制
        this.last = now;
    }
    rect(x, y, width, height, lineWidth, drawColor) { // 绘制矩形
        this.reSetImage();
        this.paint.lineWidth = lineWidth;
        this.paint.strokeStyle = drawColor;
        this.paint.strokeRect(x, y, width, height);
    }
    polygon(x, y, sides, width, height, lineWidth, drawColor) { // 绘制多边形
        this.reSetImage();
        let n = sides;
        let ran = 360 / n;
        let rn = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
        this.paint.beginPath();
        this.paint.strokeStyle = drawColor;
        this.paint.lineWidth = lineWidth;
        for(let i=0; i < n; i++){
            this.paint.lineTo(x + Math.sin((i * ran + 45) * Math.PI / 180) * rn, y + Math.cos((i * ran + 45) * Math.PI / 180) * rn);
        }
        this.paint.closePath();
        this.paint.stroke();
    }
    arc(x, y, width, height, lineWidth, drawColor) { // 绘制圆形
        this.reSetImage();
        this.paint.beginPath();
        this.paint.lineWidth = lineWidth;
        let r = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
        this.paint.arc(x, y, r, 0, Math.PI*2, false);
        this.paint.strokeStyle = drawColor;
        this.paint.closePath();
        this.paint.stroke();
    }
    eraser(endx, endy, width, height, lineWidth) { // 橡皮擦
        this.paint.save();
        this.paint.beginPath();
        this.paint.arc(endx, endy, lineWidth / 2, 0, 2 * Math.PI);
        this.paint.closePath();
        this.paint.clip();
        this.paint.clearRect(0, 0, width, height);
        this.paint.fillStyle = '#fff';
        this.paint.fillRect(0, 0, width, height);
        this.paint.restore();
    }
    cancel() { // 撤回
        if (--this.index <0) {
            this.index = 0;
            return;
        }
        this.allowCallback(this.index > 0, this.index < this.imgData.length - 1);
        this.paint.putImageData(this.imgData[this.index], 0, 0);
    }
    go () { // 前进
        if (++this.index > this.imgData.length -1) {
            this.index = this.imgData.length -1;
            return;
        }
        this.allowCallback(this.index > 0, this.index < this.imgData.length - 1);
        this.paint.putImageData(this.imgData[this.index], 0, 0);
    }
    clear() { // 清屏
        this.imgData = [];
        this.paint.clearRect(0, 0, this.width, this.height);
        this.paint.fillStyle = '#fff';
        this.paint.fillRect(0, 0, this.width, this.height);
        this.gatherImage();
    }
    changeWay({type, color, lineWidth, sides}) { // 绘制条件
        this.drawType = type !== 'color' && type || this.drawType; // 绘制形状
        this.drawColor = color || this.drawColor; // 绘制颜色
        this.lineWidth = lineWidth || this.lineWidth; // 线宽
        this.sides = sides || this.sides; // 边数
    }
    destroy() {
        this.clear();
        this.canvas.removeEventListener('mousedown', this.bindMousedown);
        document.removeEventListener('mouseup', this.bindMouseup);
        this.canvas = null;
        this.paint = null;
    }
}
class Palette {
    constructor(canvas, {drawType = 'line', drawColor = 'rgba(19, 206, 102, 1)', lineWidth = 5, sides = 3, allowCallback, moveCallback}) {
        this.canvas = canvas;
        this.width = canvas.width; // 宽
        this.height = canvas.height; // 高
        this.paint = canvas.getContext('2d');
        this.isClickCanvas = false; // 是否点击canvas内部
        this.isMoveCanvas = false; // 鼠标是否有移动
        this.imgData = []; // 存储上一次的图像,用于撤回
        this.index = 0; // 记录当前显示的是第几帧
        this.x = 0; // 鼠标按下时的 x 坐标
        this.y = 0; // 鼠标按下时的 y 坐标
        this.last = [this.x, this.y]; // 鼠标按下及每次移动后的坐标
        this.drawType = drawType; // 绘制形状
        this.drawColor = drawColor; // 绘制颜色
        this.lineWidth = lineWidth; // 线条宽度
        this.sides = sides; // 多边形边数
        this.allowCallback = allowCallback || function () {}; // 允许操作的回调
        this.moveCallback = moveCallback || function () {}; // 鼠标移动的回调
        this.bindMousemove = function () {}; // 解决 eventlistener 不能bind
        this.bindMousedown = function () {}; // 解决 eventlistener 不能bind
        this.bindMouseup = function () {}; // 解决 eventlistener 不能bind
        this.bindTouchstart = function () {}; 
        this.bindTouchmove = function () {}; 
        this.bindTouchend = function () {}; 
        this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
        this.init();
        this.isCando = false;
        console.log(this.isMobile)
    }
    init() {
        this.paint.fillStyle = '#fff';
        this.paint.fillRect(0, 0, this.width, this.height);
        this.gatherImage();
        this.bindMousemove = this.onmousemove.bind(this); // 解决 eventlistener 不能bind
        this.bindMousedown = this.onmousedown.bind(this);
        this.bindMouseup = this.onmouseup.bind(this);
        this.bindTouchstart = this.touchstart.bind(this); // 解决 eventlistener 不能bind
        this.bindTouchmove = this.touchmove.bind(this);
        this.bindTouchend = this.touchend.bind(this);
        if(!this.isMobile){
            this.canvas.addEventListener('mousedown', this.bindMousedown);
            document.addEventListener('mouseup', this.bindMouseup);
        } else {
            this.canvas.addEventListener('touchstart', this.bindTouchstart);
            document.addEventListener('touchend', this.bindTouchend);
        }
        
    }
    onmousedown(e) { // 鼠标按下
        if(!this.isCando) return
        this.isClickCanvas = true;
        this.x = e.offsetX;
        this.y = e.offsetY;
        this.last = [this.x, this.y];
        this.canvas.addEventListener('mousemove', this.bindMousemove);
    }
    gatherImage() { // 采集图像
        this.imgData = this.imgData.slice(0, this.index + 1); // 每次鼠标抬起时,将储存的imgdata截取至index处
        let imgData = this.paint.getImageData(0, 0, this.width, this.height);
        this.imgData.push(imgData);
        this.index = this.imgData.length - 1; // 储存完后将 index 重置为 imgData 最后一位
        this.allowCallback(this.index > 0, this.index < this.imgData.length - 1);
    }
    reSetImage() { // 重置为上一帧
        this.paint.clearRect(0, 0, this.width, this.height);
        if(this.imgData.length >= 1){
            this.paint.putImageData(this.imgData[this.index], 0, 0);
        }
    }
    touchstart(e) {
        e.preventDefault();
        if(!this.isCando) return
        this.isClickCanvas = true;
        this.x = e.touches[0].clientX;
        this.y = e.touches[0].clientY;
        this.last = [this.x, this.y];
        this.canvas.addEventListener('touchmove', this.bindTouchmove);
    }
    touchmove(e) {
        e.preventDefault();
        this.isMoveCanvas = true;
        let endx = e.touches[0].clientX;
        let endy = e.touches[0].clientY;
        let width = endx - this.x;
        let height = endy - this.y;
        let now = [endx, endy]; // 当前移动到的位置
        this.switchTypeDraw(now, width, height)
    }
    touchend() {
        if (this.isClickCanvas) {
            this.isClickCanvas = false;
            this.canvas.removeEventListener('touchmove', this.bindTouchmove);
            if (this.isMoveCanvas) { // 鼠标没有移动不保存
                this.isMoveCanvas = false;
                this.moveCallback('gatherImage');
                this.gatherImage();
            }
        }
    }
    switchTypeDraw(now, width, height){
        switch (this.drawType) {
            case 'line' : {
                let params = [this.last, now, this.lineWidth, this.drawColor];
                this.moveCallback('line', ...params);
                this.line(...params);
            }
                break;
            case 'rect' : {
                let params = [this.x, this.y, width, height, this.lineWidth, this.drawColor];
                this.moveCallback('rect', ...params);
                this.rect(...params);
            }
                break;
            case 'polygon' : {
                let params = [this.x, this.y, this.sides, width, height, this.lineWidth, this.drawColor];
                this.moveCallback('polygon', ...params);
                this.polygon(...params);
            }
                break;
            case 'arc' : {
                let params = [this.x, this.y, width, height, this.lineWidth, this.drawColor];
                this.moveCallback('arc', ...params);
                this.arc(...params);
            }
                break;
            case 'eraser' : {
                let params = [endx, endy, this.width, this.height, this.lineWidth];
                this.moveCallback('eraser', ...params);
                this.eraser(...params);
            }
                break;
        }
    }
    onmousemove(e) { // 鼠标移动
        this.isMoveCanvas = true;
        let endx = e.offsetX;
        let endy = e.offsetY;
        let width = endx - this.x;
        let height = endy - this.y;
        let now = [endx, endy]; // 当前移动到的位置
        this.switchTypeDraw(now, width, height)
    }
    onmouseup() { // 鼠标抬起
        if (this.isClickCanvas) {
            this.isClickCanvas = false;
            this.canvas.removeEventListener('mousemove', this.bindMousemove);
            if (this.isMoveCanvas) { // 鼠标没有移动不保存
                this.isMoveCanvas = false;
                this.moveCallback('gatherImage');
                this.gatherImage();
            }
        }
    }
    line(last, now, lineWidth, drawColor) { // 绘制线性
        this.paint.beginPath();
        this.paint.lineCap = "round"; // 设定线条与线条间接合处的样式
        this.paint.lineJoin = "round";
        this.paint.lineWidth = lineWidth;
        this.paint.strokeStyle = drawColor;
        this.paint.moveTo(last[0], last[1]);
        this.paint.lineTo(now[0], now[1]);
        this.paint.closePath();
        this.paint.stroke(); // 进行绘制
        this.last = now;
    }
    rect(x, y, width, height, lineWidth, drawColor) { // 绘制矩形
        this.reSetImage();
        this.paint.lineWidth = lineWidth;
        this.paint.strokeStyle = drawColor;
        this.paint.strokeRect(x, y, width, height);
    }
    polygon(x, y, sides, width, height, lineWidth, drawColor) { // 绘制多边形
        this.reSetImage();
        let n = sides;
        let ran = 360 / n;
        let rn = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
        this.paint.beginPath();
        this.paint.strokeStyle = drawColor;
        this.paint.lineWidth = lineWidth;
        for(let i=0; i < n; i++){
            this.paint.lineTo(x + Math.sin((i * ran + 45) * Math.PI / 180) * rn, y + Math.cos((i * ran + 45) * Math.PI / 180) * rn);
        }
        this.paint.closePath();
        this.paint.stroke();
    }
    arc(x, y, width, height, lineWidth, drawColor) { // 绘制圆形
        this.reSetImage();
        this.paint.beginPath();
        this.paint.lineWidth = lineWidth;
        let r = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
        this.paint.arc(x, y, r, 0, Math.PI*2, false);
        this.paint.strokeStyle = drawColor;
        this.paint.closePath();
        this.paint.stroke();
    }
    eraser(endx, endy, width, height, lineWidth) { // 橡皮擦
        this.paint.save();
        this.paint.beginPath();
        this.paint.arc(endx, endy, lineWidth / 2, 0, 2 * Math.PI);
        this.paint.closePath();
        this.paint.clip();
        this.paint.clearRect(0, 0, width, height);
        this.paint.fillStyle = '#fff';
        this.paint.fillRect(0, 0, width, height);
        this.paint.restore();
    }
    cancel() { // 撤回
        if (--this.index <0) {
            this.index = 0;
            return;
        }
        this.allowCallback(this.index > 0, this.index < this.imgData.length - 1);
        this.paint.putImageData(this.imgData[this.index], 0, 0);
    }
    go () { // 前进
        if (++this.index > this.imgData.length -1) {
            this.index = this.imgData.length -1;
            return;
        }
        this.allowCallback(this.index > 0, this.index < this.imgData.length - 1);
        this.paint.putImageData(this.imgData[this.index], 0, 0);
    }
    clear() { // 清屏
        this.imgData = [];
        this.paint.clearRect(0, 0, this.width, this.height);
        this.paint.fillStyle = '#fff';
        this.paint.fillRect(0, 0, this.width, this.height);
        this.gatherImage();
    }
    changeWay({type, color, lineWidth, sides}) { // 绘制条件
        this.drawType = type !== 'color' && type || this.drawType; // 绘制形状
        this.drawColor = color || this.drawColor; // 绘制颜色
        this.lineWidth = lineWidth || this.lineWidth; // 线宽
        this.sides = sides || this.sides; // 边数
    }
    destroy() {
        this.clear();
        this.canvas.removeEventListener('mousedown', this.bindMousedown);
        document.removeEventListener('mouseup', this.bindMouseup);
        this.canvas = null;
        this.paint = null;
    }
}