I'm working on a project where I load an SVG onto the Fabric.js canvas and programmatically add a watermark image inside the SVG. My goal is to embed the watermark only within the main SVG path or content area—not outside or covering the entire bounding box.
Current Behavior:
The watermark is added, but I want to make sure it stays within the main SVG content area and does not cover large portions of the bounding box or render outside the SVG entirely.
Expected Behavior:
The watermark should be placed only within the visible content of the SVG (e.g., inside paths or shapes) and not in empty or padding areas around the 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 Load SVG with Black Paths</title>
<script src="/[email protected]/dist/index.min.js"></script>
<style>
body {
background-color: #f0f0f0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
#canvas {
border: 1px solid #ccc;
}
button {
position: absolute;
top: 20px;
left: 20px;
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
}
</style>
</head>
<body>
<canvas id="canvas" width="600" height="600"></canvas>
<script>
const canvas = new fabric.Canvas('canvas');
const svgUrl = '.svg?v=1738307566215'; // Sample SVG URL
fabric.loadSVGFromURL(svgUrl).then(({
objects,
options
}) => {
const svgGroup = fabric.util.groupSVGElements(objects, options);
svgGroup.scaleToWidth(canvas.width * 0.8);
svgGroup.scaleToHeight(canvas.height * 0.8);
svgGroup.set({
angle: 0,
padding: 0,
borderColor: '#0069FF',
peloas: 12,
cornerSize: 15,
cornerColor: '#0069FF',
cornerStyle: 'circle',
borderScaleFactor: 1.5,
centeredScaling: false,
centeredRotation: true,
transparentCorners: false,
isLocked: false,
visible: true,
clipTo: null,
lockScalingFlip: true,
excludeFromExport: false,
_controlsVisibility: {
tl: true,
tr: true,
br: true,
bl: true,
ml: true,
mt: true,
mr: true,
mb: true,
mtr: true
},
element_type: 'SVGShape',
isSVGElement: true,
objectCaching: true,
left: (canvas.width - svgGroup.getScaledWidth()) / 2,
top: (canvas.height - svgGroup.getScaledHeight()) / 2
});
console.log('svgGroup: ', svgGroup);
canvas.add(svgGroup);
canvas.renderAll();
addWatermarkToSvg(svgGroup, '//3c0a13c09cf845ba/proElementWatermark.png?Expires=1832916413&Key-Pair-Id=K2ZIVPTIP2VGHC&Signature=T~Nbyb9Z3gkMBLqhpObfK~bG6kxFgOsSjMqi4GwDQvFrR2EOdBn-NWZgku1qNVX~lDfjblhaz9gjHBPkUlFanw4BNpiRC8XFExmk13jugwEuIGluM3AJEU6U3JqpQDEsQg6wBM1SvUv5Katdfz9YQj-SEhBHnomEbA4UNKpUzPZ5SYVUX22kLiGPxM3TdJS~DpOyYA7SSkNimjFNS~2IINuugRofSSHWKLMxCGTK8aoBSGs2tqwNe5h06cvwgmUpRD8vE4wJc~lyBqU8-5P1DaGvuTSkybHm9jT9NgiJu-gF-PnOBZ~qRopiBhML-JDdPq6KqG3FhV8z14GuIPQ5Aw__').then(() => {
canvas.renderAll(); // Ensure everything is properly rendered
}).catch(err => console.error('Error adding watermark:', err));
});
function addWatermarkToSvg(svgObject, watermarkUrl) {
return new Promise((resolve, reject) => {
fabric.Image.fromURL(watermarkUrl, {
crossOrigin: 'anonymous'
}).then((watermark) => {
svgObject.scaleToHeight(svgObject.height * svgObject.scaleY);
svgObject.scaleToWidth(svgObject.width * svgObject.scaleX);
canvas.renderAll();
const svgBoundingBox = svgObject.getBoundingRect(true);
// Scale and position the watermark to fit inside the SVG bounding box
watermark.set({
left: svgBoundingBox.left,
top: svgBoundingBox.top + svgBoundingBox.height - watermark.getScaledHeight(),
opacity: 1,
selectable: false,
evented: false,
height: svgBoundingBox.height,
width: svgBoundingBox.width,
});
// Add the watermark to the canvas
svgObject.add(watermark);
resolve(svgObject);
}).catch((error) => {
reject(error);
});
});
}
</script>
</body>
</html>