簡體   English   中英

使用一條線將畫布分為兩個新畫布

[英]Using a line to divide a canvas into two new canvases

我希望允許用戶以他們想要的任何方向將現有的畫布分割成兩個畫布。

我知道如何允許用戶畫一條線,我也知道如何將一個畫布的圖像數據復制到兩個新畫布上,但是如何將用戶畫線的任何一側的相關顏色數據僅復制到畫布上各自的帆布?

例如,在下面的演示中,我希望“剪切”畫布,其中白線是:

 const canvas = document.querySelector("canvas"), ctx = canvas.getContext("2d"); const red = "rgb(104, 0, 0)", lb = "rgb(126, 139, 185)", db = "rgb(20, 64, 87)"; var width, height, centerX, centerY, smallerDimen; var canvasData, inCoords; function sizeCanvas() { width = canvas.width = window.innerWidth; height = canvas.height = window.innerHeight; centerX = width / 2; centerY = height / 2; smallerDimen = Math.min(width, height); } function drawNormalState() { // Color the bg ctx.fillStyle = db; ctx.fillRect(0, 0, width, height); // Color the circle ctx.arc(centerX, centerY, smallerDimen / 4, 0, Math.PI * 2, true); ctx.fillStyle = red; ctx.fill(); ctx.lineWidth = 3; ctx.strokeStyle = lb; ctx.stroke(); // Color the triangle ctx.beginPath(); ctx.moveTo(centerX + smallerDimen / 17, centerY - smallerDimen / 10); ctx.lineTo(centerX + smallerDimen / 17, centerY + smallerDimen / 10); ctx.lineTo(centerX - smallerDimen / 9, centerY); ctx.fillStyle = lb; ctx.fill(); ctx.closePath(); screenshot(); ctx.beginPath(); ctx.strokeStyle = "rgb(255, 255, 255)"; ctx.moveTo(width - 20, 0); ctx.lineTo(20, height); ctx.stroke(); ctx.closePath(); } function screenshot() { canvasData = ctx.getImageData(0, 0, width, height).data; } function init() { sizeCanvas(); drawNormalState(); } init(); 
 body { margin: 0; } 
 <canvas></canvas> 

TL; DR 演示


我發現最好的方法是:1)計算畫布邊界(或外部)邊緣的線的“端點”,2)使用在生成的線的端點創建兩個*多邊形步驟1和畫布的四個角,以及3)根據我們創建的多邊形將原始畫布的圖像數據划分為兩個新的畫布。

*我們實際上創建了一個,但是“第二個”是原始畫布的剩余部分。


1)計算終點

給定起始坐標,x和y的差(即斜率)以及畫布的邊界,您可以使用一種非常便宜的算法來計算一些端點。 我使用了以下內容:

function getEndPoints(startX, startY, xDiff, yDiff, maxX, maxY) {
    let currX = startX, 
        currY = startY;
    while(currX > 0 && currY > 0 && currX < maxX && currY < maxY) {
        currX += xDiff;
        currY += yDiff;
    }
    let points = {
        firstPoint: [currX, currY]
    };

    currX = startX;
    currY = startY;
    while(currX > 0 && currY > 0 && currX < maxX && currY < maxY) {
        currX -= xDiff;
        currY -= yDiff;
    }
    points.secondPoint = [currX, currY];

    return points;
}

哪里

let xDiff = firstPoint.x - secondPoint.x,
    yDiff = firstPoint.y - secondPoint.y;

2)創建兩個多邊形

為了創建多邊形,我使用了Paul Bourke的 Javascript線交叉點

function intersect(point1, point2, point3, point4) {
    let x1 = point1[0], 
        y1 = point1[1], 
        x2 = point2[0], 
        y2 = point2[1], 
        x3 = point3[0], 
        y3 = point3[1], 
        x4 = point4[0], 
        y4 = point4[1];

    // Check if none of the lines are of length 0
    if((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) {
        return false;
    }

    let denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1));

    // Lines are parallel
    if(denominator === 0) {
        return false;;
    }

    let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator;
    let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator;

    // is the intersection along the segments
    if(ua < 0 || ua > 1 || ub < 0 || ub > 1) {
        return false;
    }

    // Return a object with the x and y coordinates of the intersection
    let x = x1 + ua * (x2 - x1);
    let y = y1 + ua * (y2 - y1);

    return [x, y];
}

加上我自己的一些邏輯:

let origin = [0, 0],
    xBound = [width, 0],
    xyBound = [width, height],
    yBound = [0, height];

let polygon = [origin];

// Work clockwise from 0,0, adding points to our polygon as appropriate

// Check intersect with top bound
let topIntersect = intersect(origin, xBound, points.firstPoint, points.secondPoint);
if(topIntersect) {
    polygon.push(topIntersect);
}
if(!topIntersect) {
    polygon.push(xBound);
}

// Check intersect with right
let rightIntersect = intersect(xBound, xyBound, points.firstPoint, points.secondPoint);
if(rightIntersect) {
    polygon.push(rightIntersect);
}
if((!topIntersect && !rightIntersect)
|| (topIntersect && rightIntersect)) {
    polygon.push(xyBound);
}


// Check intersect with bottom
let bottomIntersect = intersect(xyBound, yBound, points.firstPoint, points.secondPoint);
if(bottomIntersect) {
    polygon.push(bottomIntersect);
}
if((topIntersect && bottomIntersect)
|| (topIntersect && rightIntersect)) {
    polygon.push(yBound);
}

// Check intersect with left
let leftIntersect = intersect(yBound, origin, points.firstPoint, points.secondPoint);
if(leftIntersect) {
    polygon.push(leftIntersect);
}

3)划分原始畫布的圖像數據

現在我們有了多邊形,剩下的就是將這些數據放到新的畫布中。 最簡單的方法是使用canvas的ctx.drawImagectx.globalCompositeOperation

// Use or create 2 new canvases with the split original canvas
let newCanvas1 = document.querySelector("#newCanvas1");
if(newCanvas1 == null) {
    newCanvas1 = document.createElement("canvas");
    newCanvas1.id = "newCanvas1";
    newCanvas1.width = width;
    newCanvas1.height = height;
    document.body.appendChild(newCanvas1);
}
let newCtx1 = newCanvas1.getContext("2d");
newCtx1.globalCompositeOperation = 'source-over';
newCtx1.drawImage(canvas, 0, 0);
newCtx1.globalCompositeOperation = 'destination-in';
newCtx1.beginPath();
newCtx1.moveTo(polygon[0][0], polygon[0][1]);
for(let item = 1; item < polygon.length; item++) {
    newCtx1.lineTo(polygon[item][0], polygon[item][1]);
}
newCtx1.closePath();
newCtx1.fill();

let newCanvas2 = document.querySelector("#newCanvas2");
if(newCanvas2 == null) {
    newCanvas2 = document.createElement("canvas");
    newCanvas2.id = "newCanvas2";
    newCanvas2.width = width;
    newCanvas2.height = height;
    document.body.appendChild(newCanvas2);
}
let newCtx2 = newCanvas2.getContext("2d");
newCtx2.globalCompositeOperation = 'source-over';
newCtx2.drawImage(canvas, 0, 0);
newCtx2.globalCompositeOperation = 'destination-out';
newCtx2.beginPath();
newCtx2.moveTo(polygon[0][0], polygon[0][1]);
for(let item = 1; item < polygon.length; item++) {
    newCtx2.lineTo(polygon[item][0], polygon[item][1]);
}
newCtx2.closePath();
newCtx2.fill();

所有這些都給了我們這個演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM