我发现最好的方法是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's
Javascript line intersection
以下内容:
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.drawImage
和
ctx.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();
所有这些加在一起给了我们
this demo
啊!