我有一个背景和无限数量的图像或动画,我想将部分图像或动画遮罩或剪辑到背景。我希望用户使用或移动多边形来确定他们希望发生这种情况的位置。请参阅JSFiddle
我已经尝试了一些方法,但我似乎必须多次重新添加背景图像才能获得我正在寻找的效果,但即使如此,它也不仅仅是填充多边形。我希望用户能够移动多边形并调整形状或动画的大小,并且蒙版或剪辑效果仍然有效。
如有任何帮助,我们将不胜感激!
var canvas = new fabric.Canvas('c');
var points = [{
x: 3,
y: 4,
},
{
x: 16,
y: 3,
},
{
x: 30,
y: 5,
},
{
x: 25,
y: 55,
},
];
// define a function that can locate the controls.
// this function will be used both for drawing and for interaction.
function polygonPositionHandler(dim, finalMatrix, fabricObject) {
var x =
fabricObject.points[this.pointIndex].x - fabricObject.pathOffset.x,
y = fabricObject.points[this.pointIndex].y - fabricObject.pathOffset.y;
return fabric.util.transformPoint({
x: x,
y: y
},
fabric.util.multiplyTransformMatrices(
fabricObject.canvas.viewportTransform,
fabricObject.calcTransformMatrix()
)
);
}
function getObjectSizeWithStroke(object) {
var stroke = new fabric.Point(
object.strokeUniform ? 1 / object.scaleX : 1,
object.strokeUniform ? 1 / object.scaleY : 1
).multiply(object.strokeWidth);
return new fabric.Point(
object.width + stroke.x,
object.height + stroke.y
);
}
// define a function that will define what the control does
// this function will be called on every mouse move after a control has been
// clicked and is being dragged.
// The function receive as argument the mouse event, the current trasnform object
// and the current position in canvas coordinate
// transform.target is a reference to the current object being transformed,
function actionHandler(eventData, transform, x, y) {
var polygon = transform.target,
currentControl = polygon.controls[polygon.__corner],
mouseLocalPosition = polygon.toLocalPoint(
new fabric.Point(x, y),
"center",
"center"
),
polygonBaseSize = getObjectSizeWithStroke(polygon),
size = polygon._getTransformedDimensions(0, 0),
finalPointPosition = {
x: (mouseLocalPosition.x * polygonBaseSize.x) / size.x +
polygon.pathOffset.x,
y: (mouseLocalPosition.y * polygonBaseSize.y) / size.y +
polygon.pathOffset.y,
};
polygon.points[currentControl.pointIndex] = finalPointPosition;
return true;
}
// define a function that can keep the polygon in the same position when we change its
// width/height/top/left.
function anchorWrapper(anchorIndex, fn) {
return function(eventData, transform, x, y) {
var fabricObject = transform.target,
absolutePoint = fabric.util.transformPoint({
x: fabricObject.points[anchorIndex].x - fabricObject.pathOffset.x,
y: fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y,
},
fabricObject.calcTransformMatrix()
),
actionPerformed = fn(eventData, transform, x, y),
newDim = fabricObject._setPositionDimensions({}),
polygonBaseSize = getObjectSizeWithStroke(fabricObject),
newX =
(fabricObject.points[anchorIndex].x - fabricObject.pathOffset.x) /
polygonBaseSize.x,
newY =
(fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y) /
polygonBaseSize.y;
fabricObject.setPositionByOrigin(absolutePoint, newX + 0.5, newY + 0.5);
return actionPerformed;
};
}
var polygon = new fabric.Polygon(points, {
left: 150,
top: 100,
fill: "transparent",
strokeWidth: 2,
stroke: "green",
scaleX: 2,
scaleY: 2,
objectCaching: false,
transparentCorners: false,
cornerColor: "blue",
absolutePositioned: true,
});
fabric.Image.fromURL("https://s3.amazonaws.com/static-mywoodhome/wp-content/uploads/sites/4/2014/11/Screen-Shot-2016-10-18-at-4.39.30-PM.png", (img) => {
canvas.add(img);
img.sendToBack();
});
fabric.Image.fromURL("https://s3.amazonaws.com/static-mywoodhome/wp-content/uploads/sites/4/2014/11/Screen-Shot-2016-10-18-at-4.39.30-PM.png", (house) => {
fabric.Image.fromURL("https://www.onlygfx.com/wp-content/uploads/2017/06/man-silhouette-1-79x300.png", (person) => {
person.set("left", 100);
canvas.add(person, polygon);
house.set({
left: 10,
top: 10,
clipPath: polygon,
});
});
});
var poly = polygon;
var lastControl = poly.points.length - 1;
poly.cornerStyle = "circle";
poly.cornerColor = "rgba(0,0,255,0.5)";
poly.controls = poly.points.reduce(function(acc, point, index) {
acc["p" + index] = new fabric.Control({
positionHandler: polygonPositionHandler,
actionHandler: anchorWrapper(
index > 0 ? index - 1 : lastControl,
actionHandler
),
actionName: "modifyPolygon",
pointIndex: index,
});
return acc;
}, {});
给出的示例,我想要这样的输出:
我用圆形、三角形、静态 html、js 做了一个简单的例子。通过(圆形,三角形)的并集来掩盖背景。只需将并集部分更改为交集部分即可
是的,下面的代码有一些问题
那么我为什么要中途发布这个答案呢?
new fabric.Intersection()
可以接收结构点,为了让事情变得简单,它有intersectLineLine intersectLinePolygon intersectPolygonPolygon intersectPolygonRectangle
但是您无法获取轮廓图像对象和库中的多边形交集(您可以检查它们是否相交,但无法从中制作遮罩) 至于你的问题,由于你无法获得对象的交集,你可以将其用作掩模,除非你脱离织物的 object-svg 框架进入光栅图形。或者使用其他支持两个对象交集的库(对象上的布尔运算)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fabric.js Example</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.5.0/fabric.min.js"></script>
<style>
canvas {
border: 1px solid #ccc;
}
</style>
</head>
<body>
<canvas id="canvas" width="800" height="600"></canvas>
<script>
// Create a Fabric.js canvas
const canvas = new fabric.Canvas('canvas');
canvas.backgroundColor = '#45eeee';
canvas.renderAll()// Create a circle and a triangle
const circle = new fabric.Circle({
radius: 100,
top: 0,
left: 0,
originX: 'center',
originY: 'center'
});
const triangle = new fabric.Triangle({
width: 150,
height: 150,
top: 50,
left: 0,
originX: 'center',
originY: 'center'
}); canvas.add(circle); canvas.add(triangle);
// Load an image onto the canvas
fabric.Image.fromURL('https://picsum.photos/seed/picsum/1600/1200', function (img) {
img.originX = 'center';
img.originY = 'center';
// Resize the image if necessary
img.scaleToWidth(1600);
img.scaleToHeight(1200);
img.selectable = false;
img.hasControls = false;
// Group the circle and triangle
function update() {
maskGroup = new fabric.Group([circle,
triangle], {
originX: 'center',
originY: 'center',
});
// Apply the mask as a clipPath to the image
img.set({
clipPath: maskGroup
});
// Add the image to the canvas
canvas.add(img);
canvas.renderAll()
}
update();
circle.on('moving', update);
circle.on('modified', update);
triangle.on('moving', update);
triangle.on('modified', update);
});
</script>
</body>
</html>