Fabricjs - 在一个文档中渲染多个画布
Posted
技术标签:
【中文标题】Fabricjs - 在一个文档中渲染多个画布【英文标题】:Fabricjs - Rendering multiple canvases in one document 【发布时间】:2021-01-17 05:29:45 【问题描述】:我在动态创建和设置画布背景时遇到问题。 我希望用户能够用文本和形状注释图像,这就是我这样做的原因。
我想知道为什么这段代码会产生这样的输出
想法
-
向端点发送获取请求,该端点返回包含的 json 数据
图片网址。
将该数据转换为 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]
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>
结果
result
注意 该代码正在生成正确数量的画布。但是背景图像似乎不起作用
期望的结果将有 10 个不同背景的画布,对应于图像 url。
我是 fabric.js 的新手,这可能是一个愚蠢的错误。
【问题讨论】:
【参考方案1】:为您创建只需复制代码,然后在本地使用您自己的图像以获得输出 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>
谢谢
【讨论】:
嗨,我在调用 toDataUrl 时收到“可能无法导出受污染的画布”。另外,我真的很想知道为什么我的代码一开始就不起作用。更新帖子。 在本地工作时不要使用远程图像,在上面的示例中有远程 URL,只需将它们下载到文件夹中,然后放入单个文件夹并在 localhost 服务器中运行。它会起作用的。 这对你有帮助吗?【参考方案2】:使用远程源是一项严格的要求。我尝试了几种方法,终于成功了。
代码
//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
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 画布。 (显然即使有承诺,结构代码也没有按正确的顺序运行。这可能是由于语法错误。自定义触发器解决了这个问题。)
results
-每个图像作为背景单独出现在其自己的 fabric.js 画布中。 - 每个画布都是独立的。
【讨论】:
以上是关于Fabricjs - 在一个文档中渲染多个画布的主要内容,如果未能解决你的问题,请参考以下文章