#javascript #html #fabricjs
#javascript #HTML #fabricjs
Вопрос:
У меня возникла проблема с динамическим созданием и настройкой фонов холста. Я хочу, чтобы пользователь мог комментировать изображения текстом и фигурами, вот почему я делаю это таким образом.
Я хотел бы знать, почему этот код выдает такой результат
Идея
- Отправьте запрос get на конечную точку, которая возвращает данные json, содержащие URL-адреса изображений.
- Преобразуйте эти данные в массив javascript.
- Динамически создавайте холсты fabric js на основе длины вышеуказанного массива.
- Установите фоны холста для изображений, используя их URL-адреса. (т.е. У каждого холста будет другой фон, взятый из URL-адреса)
Проблема
Фоновое изображение есть только у последнего холста.
код
<!DOCTYPE html>
<html>
<head>
<style>
body {
}
</style>
<script
src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
crossorigin="anonymous"
></script>
</head>
<body>
<script src="fabric.js"></script>
<!--new start-->
<script>
//procedurally load images from a given source
//endpoint with image links
var end_point = "http://localhost:8080/endpoint.php";
var settings = {
url: "http://localhost:8080/endpoint.php",
method: "GET",
};
//get the images array from end point
$.ajax(settings).done(function (images_json) {
var images = JSON.parse(images_json);
//procedurally create farbric.js canvas for each image element in the html document and set their background as the corresponding image.
//for each item in the images array, create a fabric.js canvas with its background set as the image itself
var canvas_array = [];
for (var i = 0, len = images.length; i < len; i ) {
//console.log(images[i]);
//create canvas and then make it a fabric canvas
document.body.innerHTML = `<canvas
id=${[i]}
width="1000"
height="200"
style="border-style: solid;">
</canvas>`;
//canvases stored in canvas_array
canvas_array[i] = new fabric.Canvas(`${[i]}`);
console.log(canvas_array[i]);
//set canvas background as the image
canvas_array[i].setBackgroundImage(
`${images[i]}`,
canvas_array[i].renderAll.bind(canvas_array[i]),
{
backgroundImageOpacity: 1,
backgroundImageStretch: false,
}
);
}
});
</script>
<!--new end-->
</body>
</html>
Результат
обратите внимание, что код генерирует правильное количество холстов. Однако фоновое изображение, похоже, не работает
Желаемый результат будет иметь 10 холстов с разным фоном, соответствующим URL-адресам изображений.
Я новичок в fabric.js , это может быть глупой ошибкой.
Ответ №1:
Использование удаленного источника было строгим требованием. Я попробовал несколько вещей, и это, наконец, сработало.
код
//c global variable
var n_can_arr = [];
var f_can_arr = [];
var img_arr = [];
//c procedurally load images from a given source
$.ajax({
url: "http://localhost:8080/endpoint.php",
type: "GET",
dataType: "json", //c added data type
success: function (res) {
for (var index = 0; index < res.length; index ) {
//c create canvas
var setHtml = `<canvas
id=${index}
width="1000"
height="800"
style="border-style: solid;">
</canvas>`;
document.body.innerHTML = setHtml;
//c update canvas and image arrays
n_can_arr.push(index);
img_arr.push(res[index]);
}
//c call image set after the loop is over
$(document).trigger("images_set");
},
});
//c on image_set called
$(document).bind("images_set", () => {
//c for each element of normal canvas array, create a fabric js canvas and set its background
for (var i = 0; i < n_can_arr.length; i ) {
create_canvas(i);
}
//c for each element of fabric canvas array, apply the extend canvas function
extend_canvas();
});
function create_canvas(i) {
//c create fabric js canvases with normal canvas id from canvas arrray
var canvas = new fabric.Canvas(`${i}`);
f_can_arr.push(canvas);
//c set canvas background using image array
canvas.setBackgroundImage(img_arr[i], canvas.renderAll.bind(canvas), {
backgroundImageOpacity: 1,
backgroundImageStretch: false,
});
}
function extend_canvas() {
f_can_arr.forEach((canvas) => {
var origX, origY, isDown, mode_rect, mode_uline, mode_free, pointer;
//c setting keypress listener
$(window).on("keypress", (e) => {
console.log(e.key);
//c drawing rectangles
if (e.key == 1) {
var rect;
console.log("Box");
isDown = true;
mode_free = false;
mode_uline = false;
mode_rect = true;
//c canvas event listners
canvas.on("mouse:down", function (o) {
isDown = true;
if (mode_rect) {
pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
console.log(origX "," origY);
rect = new fabric.Rect({
left: origX,
top: origY,
originX: "left",
originY: "top",
width: pointer.x - origX,
height: pointer.y - origY,
fill: "red",
angle: 0,
fill: "rgba(255,0,0,0.0)",
stroke: "black",
strokeWidth: 1,
});
canvas.add(rect);
}
});
canvas.on("mouse:move", function (o) {
if (mode_rect) {
if (isDown) {
var pointer = canvas.getPointer(o.e);
if (origX > pointer.x) {
rect.set({ left: Math.abs(pointer.x) });
}
if (origY > pointer.y) {
rect.set({ top: Math.abs(pointer.y) });
}
rect.set({ width: Math.abs(origX - pointer.x) });
rect.set({ height: Math.abs(origY - pointer.y) });
canvas.renderAll();
}
}
});
}
//c freehand drawing/Highlighter
if (e.key == 2) {
console.log("freehand");
isDown = true;
mode_free = true;
mode_uline = false;
mode_rect = false;
canvas.isDrawingMode = 1;
canvas.freeDrawingBrush.color = "rgba(255,0,0,0.2)";
canvas.freeDrawingBrush.width = 20;
//c canvas event listners
canvas.on("mouse:down", function (o) {
isDown = true;
if (mode_free) {
canvas.renderAll();
}
});
}
//c line mode
if (e.key == 3) {
var line;
console.log("line");
isDown = true;
mode_free = false;
mode_uline = true;
mode_rect = false;
//c canvas event listners
canvas.on("mouse:down", function (o) {
isDown = true;
var pointer = canvas.getPointer(o.e);
var points = [pointer.x, pointer.y, pointer.x, pointer.y];
if (mode_uline) {
line = new fabric.Line(points, {
strokeWidth: 3,
fill: "red",
stroke: "red",
originX: "center",
originY: "center",
targetFindTolerance: true,
});
canvas.add(line);
}
});
canvas.on("mouse:move", function (o) {
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if (mode_uline) {
line.set({ x2: pointer.x, y2: pointer.y });
canvas.renderAll();
}
});
}
//c deleting a selected shape
if (e.key == 4) {
var activeObject = canvas.getActiveObject();
if (activeObject) {
canvas.remove(activeObject);
}
}
//c cancling freehand drawing mode
if (e.key == "x") {
console.log("freehand mode cancled");
canvas.isDrawingMode = 0;
}
});
//c removing previous event listeners and resetting some global variables
canvas.on("mouse:up", function (o) {
isDown = false;
mode_free = false;
mode_uline = false;
mode_rect = false;
canvas.off("mouse:down");
canvas.off("mouse:move");
});
});
}
function save_canvas() {}
function load_canvas() {}
решение
Я настраиваю пользовательское событие запуска после выполнения вызова ajax. Только после запуска триггерного события я создаю холсты fabricjs. (по-видимому, даже с обещаниями код структуры выполнялся не в правильном порядке. Что, вероятно, было связано с плохим синтаксисом. Пользовательские триггеры решают эту проблему.)
-Каждое изображение отображается отдельно в своем собственном fabric.js холст в качестве фона. -Каждый холст независим.
Ответ №2:
Создайте для вас просто скопируйте код, а затем используйте свои собственные изображения в local, чтобы получить фактический полный результат в выходном div (изображения будут сгенерированы).
let CANVAS_LIST = [];
let imageList = [
'https://homepages.cae.wisc.edu/~ece533/images/airplane.png',
'https://homepages.cae.wisc.edu/~ece533/images/arctichare.png',
'https://homepages.cae.wisc.edu/~ece533/images/baboon.png',
]
imageList.forEach(element => {
let canvasElement = document.createElement("canvas");
canvasElement.width = '300';
canvasElement.height = '300';
$("#canvas_container").append(canvasElement);
let canvas = new fabric.Canvas(canvasElement);
// Adding Example Text here.
canvas.add(new fabric.Text('This text is added', {
fontFamily: 'Delicious_500',
color: 'red',
left: 10,
top: 100
}));
// Setting up Background to dynamic generated Canvas
canvas.setBackgroundImage(
`${element}`,
canvas.renderAll.bind(canvas),
{
backgroundImageOpacity: 1,
backgroundImageStretch: false,
}
);
CANVAS_LIST.push(canvas);
});
setTimeout(() => {
generateOutput();
}, 3000);
function generateOutput() {
$("#output").empty();
CANVAS_LIST.forEach(canvas => {
let image = $("<img>").attr({
width: 200,
height: 200,
src: canvas.toDataURL()
});
image.css({ marginLeft: '20px' });
$("#output").append(image);
})
}
<!DOCTYPE html>
<html>
<head>
<style>
body {}
</style>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.1.0/fabric.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<div id="canvas_container">
</div>
<button onclick="generateOutput()"> Show output</button>
<div id="output">
</div>
</div>
</body>
</html>
Спасибо
Комментарии:
1. привет, я получаю сообщение «Испорченные холсты не могут быть экспортированы» при вызове toDataURL. Также мне бы очень хотелось знать, почему мой код не работает в первую очередь. обновленный пост.
2. Не используйте удаленные изображения при работе с локальными, в приведенном выше примере есть удаленные URL-адреса, просто загрузите их в папку, а затем поместите в одну папку и запустите ее на сервере localhost. это будет работать.
3. это вам помогает?