Мне нужно запустить FabricJS / canvas на довольно оптимальном уровне для работы в моем случае использования в браузере.
У меня есть случаи, когда у меня есть фоновое изображение, и мне нужно нарисовать более 20000 полигонов в теме. Это невозможно, поэтому я в данный момент: 1) Сгенерирую статичное * PNG-изображение на стороне сервера полигонов, затем отправлю его в браузер и наложу его на фоновое изображение. 2) Затем, когда пользовательская мышь перемещается по соответствующие области, я загружаю интерактивные аннотации Fabri c в эти области.
Когда пользователь выбирает интерактивный многоугольник, перемещает его и опускает, мне нужно заново сгенерировать слой изображения stati c polygon с обновленными позициями этого многоугольника. Требуется слишком много памяти для воссоздания полного многоугольного изображения stati c с помощью toDataUrl, браузер падает.
Скажите, что я могу затем создать небольшое изображение stati c, используя дополнительный меньший холст. Затем мне нужно объединить его с большим многогранным изображением stati c. Я видел fabri c .clipTo, но использование его много раз (например, до 20 000 раз), в то время как fabri c сохраняет ссылку на него, наверняка замедлит работу браузера?
Есть ли способ в fabri cjs сделать эквивалент ctx.drawImage (img, sx, sy, swidth, sheight, x, y, width, height); таким образом, чтобы объединить его в изображение на холсте без создания дополнительных объектов?
Вот игровая площадка, которую я построил, чтобы попытаться найти способ объединить изменения в изображение многоугольника stati c ниже :
const SPACING = 15;
const RECTANGLE_SIDE = 40;
const TOTAL_RECT_SPACE = RECTANGLE_SIDE + SPACING;
const CANVAS_WIDTH = 300;
const CANVAS_HEIGHT = 300;
const CANVAS_RECT = document.getElementById('c').getBoundingClientRect();
const app = async () => {
const canvas = new fabric.Canvas('c');
const rectangles = generateRectangles();
await createStaticImage(canvas, rectangles);
showAnnotationsOnHover(canvas, rectangles);
};
const generateRectangles = () => {
let rectangles = [];
for (let i = 0; (i + 1) * TOTAL_RECT_SPACE < CANVAS_WIDTH; i++) {
for (let j = 0; (j+ 1) * TOTAL_RECT_SPACE < CANVAS_HEIGHT; j++) {
let rectangle = new fabric.Rect({
left: i * TOTAL_RECT_SPACE,
top: j * TOTAL_RECT_SPACE,
fill: 'rgba(0, 0, 0, 0)',
stroke: 'red',
strokeWidth: 1,
width: RECTANGLE_SIDE,
height: RECTANGLE_SIDE
});
rectangles.push(rectangle);
}
};
return rectangles;
}
const createStaticImage = (canvas, rectangles) => {
return new Promise(resolve => {
rectangles.forEach(rect => {
rect.set({ stroke: 'blue' });
canvas.add(rect);
});
const dataUrl = canvas.toDataURL();
fabric.Image.fromURL(dataUrl, image => {
image.set({
selectable: false
});
canvas.add(image);
resolve();
});
rectangles.forEach(rect => {
rect.set({ stroke: 'red' });
canvas.remove(rect);
});
});
}
const showAnnotationsOnHover = (canvas, rectangles) => {
let showAnnotations = false;
canvas.on('mouse:over', () => {
if (!showAnnotations) {
showAnnotations = true;
rectangles.forEach(rect => {
canvas.add(rect);
})
}
});
canvas.on('mouse:out', () => {
if (showAnnotations) {
showAnnotations = false;
rectangles.forEach(rect => {
canvas.remove(rect);
});
}
});
}
app();
<html>
<body>
<div style="display: inline-block; height: 300px; width: 300px; background-color: lightblue; padding: 20px; box-sizing: border-box; ; vertical-align: top">
<p> Hovering on the canvas shows Fabric Annotations. Otherwise it's a static image </p>
<p> When a rectangle is moved, that change should be flattened down to the static image of the rectangles below. </p>
</div>
<div style="display: inline-block; height: 300px; width: 300px; vertical-align: top">
<canvas id="c" width=300 height=300></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.0/fabric.min.js"></script>
<script src="index.js"></script>
</body>
</html>