canvas标注 js-查看文章

canvas标注 js

发表于:2020-10-24 12:51:14 分类:开发杂记 阅读:621次

image
function MarkImage(div, image, markData, styleConfig) {
    var POSITION_ABSOLUTE = 'absolute';
    var config = {
        markColor: "#fff2aa",
        markFillColor: "rgba(0, 0, 0, 0.3)",
        textSize: 16,
        textColor: "#3482ff",
        selectedColor: "#FF0000",
        intoBorderColor: "rgba(200, 100, 100, 0.8)"
    };
    var temCanvas = null;
    var tempContent = null;
    var tempPoints = [];
    var drawState = false;
    //当前选中的标签
    this.selected = null;
    //当前移入的标签
    this.moveInto = null;
    //画布宽度
    this.width = 0;
    //画面高度
    this.height = 0;
    //画面所在dom元素
    this.element = div;
    //需要标注的底图
    this.image = image;
    //实时标签数据
    this.markArray = [];
    var scaling = 1;
    var idSequence = {
        startTime: new Date().getTime()
    };
    var pushDownPoint = null;
    var pushDown = false;
    var pushUpPoint = null;
    function initCanvas(markImage) {
        if (!div || !image) {
            return false;
        }
        if (styleConfig) {
            if (styleConfig.markColor) {
                config.markColor = styleConfig.markColor;
            }
            if (styleConfig.textSize) {
                config.textSize = styleConfig.textSize;
            }
            if (styleConfig.textColor) {
                config.textColor = styleConfig.textColor;
            }
        }
        removeAllChild(div);
        const wh = Number(image.width) / Number(image.height);
        if (wh > 1) {
            scaling = div.offsetWidth / image.width;
        } else {
            scaling = div.offsetHeight / image.height;
        }
        markImage.width = image.width * scaling;
        markImage.height = image.height * scaling;
        var imageCanvas = document.createElement('canvas');
        div.appendChild(imageCanvas);
        imageCanvas.id = 'MARK_IMAGE';
        imageCanvas.width = markImage.width;
        imageCanvas.height = markImage.height;
        imageCanvas.style.position = POSITION_ABSOLUTE;
        var imageCanvasCtx = imageCanvas.getContext("2d");
        imageCanvasCtx.drawImage(image, 0, 0, imageCanvas.width, imageCanvas.height);
        drawMarks(markImage);
        temCanvas = document.createElement('canvas');
        div.appendChild(temCanvas);
        temCanvas.id = 'MARK_IMAGE_TEMP';
        temCanvas.width = markImage.width;
        temCanvas.height = markImage.height;
        temCanvas.style.position = POSITION_ABSOLUTE;
        tempContent = temCanvas.getContext("2d");
        bindEvent(markImage);
        return true;
    }
    function drawMarks(markImage) {
        if (markData) {
            for (var i = 0; i < markData.length; i++) {
                var data = markData[i];
                var mark = new Object();
                mark.markType = data.markType;
                mark.realName = data.realName;
                mark.name = data.name;
                mark.points = JSON.parse(data.markJson);
                markImage.drawMark(mark);
            }
        }
    }
    function bindEvent(markImage) {
        markImage.element.onclick = function (event) {
            if (event.layerX <= markImage.width && event.layerY <= markImage.height) {
                if (drawState) {
                    if (pushDownPoint && pushUpPoint && (Math.abs(pushUpPoint.x - pushDownPoint.x) < 10 || Math.abs(pushUpPoint.y - pushDownPoint.y) < 10)) {
                        tempPoints.push({ x: event.layerX, y: event.layerY });
                        drawTempMark(markImage);
                    }
                } else {
                    if (markImage.moveInto) {
                        if (markImage.selected) {
                            if (markImage.selected.id !== markImage.moveInto.id) {
                                flashSelected(markImage, markImage.selected, false);
                                markImage.selected = markImage.moveInto;
                                flashSelected(markImage, markImage.selected, true);
                            }
                        } else {
                            markImage.selected = markImage.moveInto;
                            flashSelected(markImage, markImage.selected, true);
                        }
                    } else {
                        if (markImage.selected) {
                            flashSelected(markImage, markImage.selected, false);
                            markImage.selected = null;
                        }
                    }
                }
            }
        }
        markImage.element.onmousemove = function (event) {
            markImage.element.style.cursor = 'default';
            if (event.layerX <= markImage.width && event.layerY <= markImage.height) {
                if (!drawState) {
                    var point = { x: event.layerX / scaling, y: event.layerY / scaling };
                    var mark = intoMark(markImage, point);
                    if (mark) {
                        markImage.element.style.cursor = 'pointer';
                    } else {
                        if (markImage.moveInto) {
                            markImage.moveInto = null;
                        }
                    }
                } else {
                    if (pushDown) {
                        drawTempRectangle({ x: event.layerX, y: event.layerY });
                    }
                }
            }
        }
        markImage.element.oncontextmenu = function (event) {
            if (event.button === 2) {
                event.preventDefault();
                draw(markImage);
            }
        }
        markImage.element.onmousedown = function (event) {
            if (event.layerX <= markImage.width && event.layerY <= markImage.height) {
                if (drawState) {
                    pushDownPoint = { x: event.layerX, y: event.layerY };
                    pushDown = true;
                }
            }
        }
        markImage.element.onmouseup = function (event) {
            if (event.layerX <= markImage.width && event.layerY <= markImage.height) {
                if (drawState) {
                    pushUpPoint = { x: event.layerX, y: event.layerY };
                    pushDown = false;
                    if (pushDownPoint && pushUpPoint && (Math.abs(pushUpPoint.x - pushDownPoint.x) >= 10 || Math.abs(pushUpPoint.y - pushDownPoint.y) >= 10)) {
                        drawRectangle(markImage);
                    }
                }
            }
        }
    }
    function draw(markImage) {
        if (tempPoints && tempPoints.length > 3) {
            var newMark = {};
            newMark.realName = '请选择标注标签';
            newMark.markType = '0';
            newMark.points = [];
            for (var i = 0; i < tempPoints.length; i++) {
                newMark.points.push({ x: tempPoints[i].x / scaling, y: tempPoints[i].y / scaling });
            }
            tempPoints = [];
            temCanvas.width = markImage.width;
            markImage.selectedMark(markImage.drawMark(newMark));
        }
    }
    function drawRectangle(markImage) {
        tempPoints = [];
        tempPoints.push(pushDownPoint);
        tempPoints.push({ x: pushDownPoint.x, y: pushUpPoint.y });
        tempPoints.push(pushUpPoint);
        tempPoints.push({ x: pushUpPoint.x, y: pushDownPoint.y });
        temCanvas.width = markImage.width;
        draw(markImage);
    }
    function drawTempRectangle(point) {
        if (pushDownPoint) {
            if (point.x - pushDownPoint.x !== 0 && point.y - pushDownPoint.y !== 0) {
                temCanvas.width = temCanvas.width;
                tempContent.setLineDash([20, 5]);  // [实线长度, 间隙长度]
                tempContent.lineDashOffset = -0;
                tempContent.strokeStyle = config.intoBorderColor;
                tempContent.strokeRect(pushDownPoint.x, pushDownPoint.y,
                    (point.x - pushDownPoint.x), (point.y - pushDownPoint.y));
            }
        }
    }
    function drawTempMark(markImage) {
        if (tempPoints && tempPoints.length > 0) {
            pushUpPoint = null;
            pushDownPoint = null;
            var p = tempPoints[tempPoints.length - 1];
            if (tempPoints.length === 1) {
                tempContent.arc(p.x, p.y, 2, 0, 2 * Math.PI, false);
                tempContent.stroke();
            } else {
                tempContent.moveTo(tempPoints[tempPoints.length - 2].x, tempPoints[tempPoints.length - 2].y);       //设置起点状态
                tempContent.lineTo(p.x, p.y);       //设置末端状态
                tempContent.stroke();
                tempContent.arc(p.x, p.y, 2, 0, 2 * Math.PI, false);
                tempContent.stroke();
            }
        }
    }
    function flashSelected(markImage, mark, selected) {
        mark.dataCanvas.width = markImage.width;
        mark.nameCanvas.width = markImage.width;
        var dataCanvasCtx = mark.dataCanvas.getContext("2d");
        var nameCanvasCtx = mark.nameCanvas.getContext("2d");
        nameCanvasCtx.font = config.textSize + "px 黑体";
        if (selected) {
            dataCanvasCtx.strokeStyle = config.selectedColor;
            nameCanvasCtx.fillStyle = config.selectedColor;
        } else {
            dataCanvasCtx.strokeStyle = config.markColor;
            nameCanvasCtx.fillStyle = config.textColor;
        }
        if (mark.textPoint.y === mark.border[0].y) {
            nameCanvasCtx.fillText("名称:" + mark.realName, mark.textPoint.x * scaling, mark.textPoint.y * scaling + config.textSize);
        } else {
            nameCanvasCtx.fillText("名称:" + mark.realName, mark.textPoint.x * scaling, mark.textPoint.y * scaling);
        }

        if (mark.points) {
            for (var i = 0; i < mark.points.length; i++) {
                const point = mark.points[i];
                if (i === 0) {
                    dataCanvasCtx.beginPath();
                    dataCanvasCtx.moveTo(point.x * scaling, point.y * scaling);
                } else {
                    dataCanvasCtx.lineTo(point.x * scaling, point.y * scaling);
                    if (i === mark.points.length - 1) {
                        dataCanvasCtx.closePath();
                        dataCanvasCtx.fillStyle = config.markFillColor;
                        dataCanvasCtx.fill();
                        dataCanvasCtx.stroke();
                    }
                }
            }
        }
    }
    function intoMark(markImage, point) {
        for (var i = 0; i < markImage.markArray.length; i++) {
            var mark = markImage.markArray[i];
            if (mark.border[0].x < point.x && point.x < mark.border[1].x && mark.border[0].y < point.y && point.y < mark.border[1].y) {
                if (!markImage.moveInto || markImage.moveInto.id !== mark.id) {
                    markImage.moveInto = mark;
                    drawBorder(mark);
                }
                return mark;
            }
        }
        clearBorder(markImage);
        return null;
    }
    function drawBorder(mark) {
        temCanvas.width = temCanvas.width;
        tempContent.setLineDash([20, 5]);  // [实线长度, 间隙长度]
        tempContent.lineDashOffset = -0;
        tempContent.strokeStyle = config.intoBorderColor;
        tempContent.strokeRect(mark.border[0].x * scaling, mark.border[0].y * scaling, (mark.border[1].x - mark.border[0].x) * scaling, (mark.border[1].y - mark.border[0].y) * scaling);
    }
    function clearBorder(markImage) {
        if (markImage.moveInto) {
            temCanvas.width = temCanvas.width;
        }
    }
    //添加一个标注
    this.drawMark = function (mark) {
        mark.id = genId();
        this.markArray.push(mark);
        mark.dataCanvas = drawPoints(mark, this);
        if (mark.textPoint.y === mark.border[0].y) {
            mark.nameCanvas = drawText('MARK_NAME_' + mark.id, mark.realName, mark.textPoint.x * scaling, mark.textPoint.y * scaling + config.textSize, this);
        } else {
            mark.nameCanvas = drawText('MARK_NAME_' + mark.id, mark.realName, mark.textPoint.x * scaling, mark.textPoint.y * scaling, this);
        }
        return mark.id;
    }
    function drawPoints(mark, markImage) {
        var minX = -1, minY = -1, maxX = -1, maxY = -1;
        var dataCanvas = document.createElement('canvas');
        div.appendChild(dataCanvas);
        dataCanvas.id = 'MARK_DATA_' + mark.id;
        dataCanvas.style.position = POSITION_ABSOLUTE;
        dataCanvas.width = markImage.width;
        dataCanvas.height = markImage.height;
        var dataCanvasCtx = dataCanvas.getContext("2d");
        dataCanvasCtx.strokeStyle = config.markColor;
        if (mark.points) {
         var xArr = [],yArr = [];
            for (var i = 0; i < mark.points.length; i++) {
                const point = mark.points[i];
                if(!xArr.includes(point.x)){
                    xArr.push(point.x);
                }
                if(!yArr.includes(point.y)){
                    yArr.push(point.y);
                }
                if (i === 0) {
                    minX = point.x;
                    maxX = point.x;
                    minY = point.y;
                    maxY = point.y;
                    mark.textPoint = point;
                    dataCanvasCtx.beginPath();
                    dataCanvasCtx.moveTo(point.x * scaling, point.y * scaling);
                } else {
                    if (point.x < minX) {
                        minX = point.x;
                        mark.textPoint = point;
                    }
                    minY = point.y < minY ? point.y : minY;
                    maxX = point.x > maxX ? point.x : maxX;
                    maxY = point.y > maxY ? point.y : maxY;
                    dataCanvasCtx.lineTo(point.x * scaling, point.y * scaling);
                    if (i === mark.points.length - 1) {
                        dataCanvasCtx.closePath();
                        dataCanvasCtx.fillStyle = config.markFillColor;
                        dataCanvasCtx.fill();
                        dataCanvasCtx.stroke();
                    }
                }
            }
            if(mark.points.length===4&&xArr.length<=2&&yArr.length<=2){
                mark.markType = "0";
            }else{
                mark.markType = "1";
            }
            mark.border = [{ x: minX, y: minY }, { x: maxX, y: maxY }];
        }
        return dataCanvas;
    }
    //设置绘制状态 true 画图状态 false 选择状态
    this.setDrawState = function (state) {
        drawState = state;
        if (state) {
            tempPoints = [];
            temCanvas.width = this.width;
            if (this.selected) {
                flashSelected(this, this.selected, false);
                this.selected = null;
            }
        }
    }
    this.getDrawState = function () {
        return drawState;
    }
    //获取所有数据,返回格式同传入格式
    this.getMarkerData = function () {
        var data = [];
        for (var i = 0; i < this.markArray.length; i++) {
            var mark = {};
            mark.id = this.markArray[i].id;
         if(this.markArray[i].name){
            mark.name = this.markArray[i].name;
         }
            mark.realName = this.markArray[i].realName;
            mark.markType = this.markArray[i].markType;
            mark.markJson = JSON.stringify(this.markArray[i].points);
            data.push(mark);
        }
        return data;
    }
    function drawText(id, name, x, y, markImage) {
        var nameCanvas = document.createElement('canvas');
        div.appendChild(nameCanvas);
        nameCanvas.id = id;
        nameCanvas.style.position = POSITION_ABSOLUTE;
        nameCanvas.width = markImage.width;
        nameCanvas.height = markImage.height;
        var nameCanvasCtx = nameCanvas.getContext("2d");
        nameCanvasCtx.font = config.textSize + "px 黑体";
        nameCanvasCtx.fillStyle = config.textColor;
        nameCanvasCtx.fillText("名称:" + name, x, y);
        return nameCanvas;
    }
    //编辑指定标签
    this.editMark = function (mark) {
        var findMark = this.findMark(mark.id);
        if (!findMark) {
            return false;
        }
        this.element.removeChild(findMark.nameCanvas);
        this.element.removeChild(findMark.dataCanvas);
        findMark.dataCanvas = drawPoints(mark, this);
        if (mark.textPoint.y === mark.border[0].y) {
            mark.nameCanvas = drawText('MARK_NAME_' + mark.id, mark.realName, mark.textPoint.x * scaling, mark.textPoint.y * scaling + config.textSize, this);
        } else {
            mark.nameCanvas = drawText('MARK_NAME_' + mark.id, mark.realName, mark.textPoint.x * scaling, mark.textPoint.y * scaling, this);
        }
        return true;
    }
    //移除所有
    this.removeAll = function () {
        for (var i = 0; i < this.markArray.length; i++) {
            this.element.removeChild(this.markArray[i].nameCanvas);
            this.element.removeChild(this.markArray[i].dataCanvas);
        }
        this.markArray = [];
    }
    //根据ID移除标签
    this.removeMark = function (target) {
        var id = null;
        if(typeof (target) === "string"){
            id = target;
        }else{
            if(target.id){
                id = target.id;
            }
        }
        if(!id){
            return null;
        }
        var findMark = null;
        for (var i = 0; i < this.markArray.length; i++) {
            if (this.markArray[i].id === id) {
                findMark = this.markArray[i];
                this.markArray.splice(i, 1);
                break;
            }
        }
        if (findMark) {
            this.element.removeChild(findMark.nameCanvas);
            this.element.removeChild(findMark.dataCanvas);
        }
        return findMark;
    }
    //根据ID查找标签
    this.findMark = function (id) {
        for (var i = 0; i < this.markArray.length; i++) {
            if (this.markArray[i].id === id) {
                return this.markArray[i];
            }
        }
        return null;
    }
    //根据ID选中标签
    this.selectedMark = function (id) {
        var findMark = this.findMark(id);
        if (findMark) {
            if (this.selected) {
                flashSelected(this, this.selected, false);
            }
            this.selected = findMark;
            flashSelected(this, this.selected, true);
        }
    }
    function genId() {
        var now = new Date().getTime();
        var timeDifference = now - idSequence.startTime;
        if (idSequence.time && idSequence.time === timeDifference) {
            idSequence.sequence = idSequence.sequence + 1;
        } else {
            idSequence.time = timeDifference;
            idSequence.sequence = 0;
        }
        return genIdString(idSequence.time + "", idSequence.sequence + "")
    }
    function genIdString(a, b) {
        var post = b.padStart(3, "0");
        return a + post;
    }
    function removeAllChild(div) {
        while (div.hasChildNodes()) {
            div.removeChild(div.firstChild);
        }
    }
    initCanvas(this);
}


关键词:js,canvas,图片标注


验证码: