如何水平对齐 fabric.Image 个对象?
How to align fabric.Image objects horizontally?
我只是想加载三个矩形图像并希望它们彼此水平对齐。我认为在 fabric.Image.fromURL
方法中设置左 属性 可以实现此目的,但加载的树图像彼此堆叠。此外,即使我包含 selectable:true,图像也无法选择。我使用 fabric.Image.fromURL
不正确吗?
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<!-- Get version 1.1.0 of Fabric.js from CDN -->
<script src="js/fabric.js"></script>
<!-- Get the highest 1.X version of jQuery from CDN. Required for ready() function. -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(function () {
var canvas = new fabric.Canvas('canvas', {
backgroundColor: 'black',
selectionColor: 'blue',
selectionLineWidth: 0
// ...
});
debugger;
var tiles = [
"images/Green.png",
"images/Red.png",
"images/Yellow.png"
];
var offset = [
"0",
"200",
"400"
];
debugger;
for (i = 0; i < tiles.length; i++) {
fabric.Image.fromURL(tiles[i], function (img) {
img.scale(1.0).set({
left: offset[i],
top: 0,
selectable:true,
});
canvas.add(img).setActiveObject(img);
});
}
function handleDragStart(e) {
[].forEach.call(images, function (img) {
img.classList.remove('img_dragging');
});
this.classList.add('img_dragging');
}
function handleDragOver(e) {
if (e.preventDefault) {
e.preventDefault(); // Necessary. Allows us to drop.
}
e.dataTransfer.dropEffect = 'copy'; // See the section on the DataTransfer object.
// NOTE: comment above refers to the article (see top) -natchiketa
return false;
}
function handleDragEnter(e) {
// this / e.target is the current hover target.
this.classList.add('over');
}
function handleDragLeave(e) {
this.classList.remove('over'); // this / e.target is previous target element.
}
function handleDrop(e) {
// this / e.target is current target element.
if (e.stopPropagation) {
e.stopPropagation(); // stops the browser from redirecting.
}
var img = document.querySelector('#images img.img_dragging');
console.log('event: ', e);
var newImage = new fabric.Image(img, {
width: img.width,
height: img.height,
// Set the center of the new object based on the event coordinates relative
// to the canvas container.
left: e.layerX,
top: e.layerY
});
canvas.add(newImage);
return false;
}
function handleDragEnd(e) {
// this/e.target is the source node.
[].forEach.call(images, function (img) {
img.classList.remove('img_dragging');
});
}
// Bind the event listeners for the image elements
var images = document.querySelectorAll('#images img');
[].forEach.call(images, function (img) {
img.addEventListener('dragstart', handleDragStart, false);
img.addEventListener('dragend', handleDragEnd, false);
});
// Bind the event listeners for the canvas
var canvasContainer = document.getElementById('canvas-container');
canvasContainer.addEventListener('dragenter', handleDragEnter, false);
canvasContainer.addEventListener('dragover', handleDragOver, false);
canvasContainer.addEventListener('dragleave', handleDragLeave, false);
canvasContainer.addEventListener('drop', handleDrop, false);
});
</script>
</head>
<body>
<div id="canvas-container">
<canvas id="canvas" width="600" height="200"></canvas>
</div>
<div id="images">
<img draggable="true" src="images/Red.png" width="50" height="50"></img>
<img draggable="true" src="images/Yellow.png" width="50" height="50"></img>
<img draggable="true" src="images/Green.png" width="50" height="50"></img>
</div>
</body>
</html>
您的 fabric.Image.fromURL
回调与 for
循环的执行之间存在竞争条件,这会阻止图像显示。
如果您在回调中打印 i
和 offset[i]
:
fabric.Image.fromURL(tiles[i], function (img) {
console.log(i, offset[i]);
...
});
您会注意到 i
是 3
而 offset[i]
是 undefined
在所有回调中。
发生这种情况是因为每个回调都保留对 i
变量的同一实例的引用,并在它们执行时使用其最新值。 for 循环在其循环中循环,每次递增 i
,然后再执行任何回调,使 i
的最终值为 3
。当您的回调执行时,它们会尝试将 left:
值设置为 offset[3]
,这是未定义的,并且 fabric 回退到 0
.
解决方案
ES6 之前的变量 javascript(与大多数语言不同)仅作用于声明它们的函数,代码块不影响作用域。
将您的图像构建逻辑放入它自己的函数中,将 i
的当前值作为每个循环周期中的参数传递。这会将值放入新范围,并保留该值。
此外,不要忘记 i
前面的 var
关键字。否则你会影响全局命名空间,你想不惜一切代价避免它。
您的代码应如下所示:
for (var i = 0; i < tiles.length; i++) {
buildImage(i);
}
// creates a new scope for the passed in value of i when called:
function buildImage(i) {
fabric.Image.fromURL(tiles[i], function (img) {
img.scale(1.0).set({
left: offset[i],
top: 0,
selectable: true,
});
canvas.add(img).setActiveObject(img);
});
}
最后,您可能需要考虑设置图像的 originX
and originY
属性,如下所示:
originX: 'left',
originY: 'top'
默认情况下,fabric 在放置它们时会以图像的中心作为原点,并且您的图像不会在 canvas.
的全视图中
更新
这里是fully working example。依赖fabric,需要放在你的js/文件夹下。
我只是想加载三个矩形图像并希望它们彼此水平对齐。我认为在 fabric.Image.fromURL
方法中设置左 属性 可以实现此目的,但加载的树图像彼此堆叠。此外,即使我包含 selectable:true,图像也无法选择。我使用 fabric.Image.fromURL
不正确吗?
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<!-- Get version 1.1.0 of Fabric.js from CDN -->
<script src="js/fabric.js"></script>
<!-- Get the highest 1.X version of jQuery from CDN. Required for ready() function. -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(function () {
var canvas = new fabric.Canvas('canvas', {
backgroundColor: 'black',
selectionColor: 'blue',
selectionLineWidth: 0
// ...
});
debugger;
var tiles = [
"images/Green.png",
"images/Red.png",
"images/Yellow.png"
];
var offset = [
"0",
"200",
"400"
];
debugger;
for (i = 0; i < tiles.length; i++) {
fabric.Image.fromURL(tiles[i], function (img) {
img.scale(1.0).set({
left: offset[i],
top: 0,
selectable:true,
});
canvas.add(img).setActiveObject(img);
});
}
function handleDragStart(e) {
[].forEach.call(images, function (img) {
img.classList.remove('img_dragging');
});
this.classList.add('img_dragging');
}
function handleDragOver(e) {
if (e.preventDefault) {
e.preventDefault(); // Necessary. Allows us to drop.
}
e.dataTransfer.dropEffect = 'copy'; // See the section on the DataTransfer object.
// NOTE: comment above refers to the article (see top) -natchiketa
return false;
}
function handleDragEnter(e) {
// this / e.target is the current hover target.
this.classList.add('over');
}
function handleDragLeave(e) {
this.classList.remove('over'); // this / e.target is previous target element.
}
function handleDrop(e) {
// this / e.target is current target element.
if (e.stopPropagation) {
e.stopPropagation(); // stops the browser from redirecting.
}
var img = document.querySelector('#images img.img_dragging');
console.log('event: ', e);
var newImage = new fabric.Image(img, {
width: img.width,
height: img.height,
// Set the center of the new object based on the event coordinates relative
// to the canvas container.
left: e.layerX,
top: e.layerY
});
canvas.add(newImage);
return false;
}
function handleDragEnd(e) {
// this/e.target is the source node.
[].forEach.call(images, function (img) {
img.classList.remove('img_dragging');
});
}
// Bind the event listeners for the image elements
var images = document.querySelectorAll('#images img');
[].forEach.call(images, function (img) {
img.addEventListener('dragstart', handleDragStart, false);
img.addEventListener('dragend', handleDragEnd, false);
});
// Bind the event listeners for the canvas
var canvasContainer = document.getElementById('canvas-container');
canvasContainer.addEventListener('dragenter', handleDragEnter, false);
canvasContainer.addEventListener('dragover', handleDragOver, false);
canvasContainer.addEventListener('dragleave', handleDragLeave, false);
canvasContainer.addEventListener('drop', handleDrop, false);
});
</script>
</head>
<body>
<div id="canvas-container">
<canvas id="canvas" width="600" height="200"></canvas>
</div>
<div id="images">
<img draggable="true" src="images/Red.png" width="50" height="50"></img>
<img draggable="true" src="images/Yellow.png" width="50" height="50"></img>
<img draggable="true" src="images/Green.png" width="50" height="50"></img>
</div>
</body>
</html>
您的 fabric.Image.fromURL
回调与 for
循环的执行之间存在竞争条件,这会阻止图像显示。
如果您在回调中打印 i
和 offset[i]
:
fabric.Image.fromURL(tiles[i], function (img) {
console.log(i, offset[i]);
...
});
您会注意到 i
是 3
而 offset[i]
是 undefined
在所有回调中。
发生这种情况是因为每个回调都保留对 i
变量的同一实例的引用,并在它们执行时使用其最新值。 for 循环在其循环中循环,每次递增 i
,然后再执行任何回调,使 i
的最终值为 3
。当您的回调执行时,它们会尝试将 left:
值设置为 offset[3]
,这是未定义的,并且 fabric 回退到 0
.
解决方案
ES6 之前的变量 javascript(与大多数语言不同)仅作用于声明它们的函数,代码块不影响作用域。
将您的图像构建逻辑放入它自己的函数中,将 i
的当前值作为每个循环周期中的参数传递。这会将值放入新范围,并保留该值。
此外,不要忘记 i
前面的 var
关键字。否则你会影响全局命名空间,你想不惜一切代价避免它。
您的代码应如下所示:
for (var i = 0; i < tiles.length; i++) {
buildImage(i);
}
// creates a new scope for the passed in value of i when called:
function buildImage(i) {
fabric.Image.fromURL(tiles[i], function (img) {
img.scale(1.0).set({
left: offset[i],
top: 0,
selectable: true,
});
canvas.add(img).setActiveObject(img);
});
}
最后,您可能需要考虑设置图像的 originX
and originY
属性,如下所示:
originX: 'left',
originY: 'top'
默认情况下,fabric 在放置它们时会以图像的中心作为原点,并且您的图像不会在 canvas.
的全视图中更新
这里是fully working example。依赖fabric,需要放在你的js/文件夹下。