如何对齐fabric.Image对象水平?

时间:2016-02-22 16:06:43

标签: html5-canvas fabricjs

我只是想加载三个矩形图像,并希望它们彼此水平对齐。我认为在fabric.Image.fromURL方法中设置left属性可以完成此操作,但树图像会堆叠在一起。即使我包括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>

1 个答案:

答案 0 :(得分:1)

fabric.Image.fromURL回调与执行for循环之间存在竞争条件,导致图像无法显示。

如果您在回调中打印ioffset[i]

fabric.Image.fromURL(tiles[i], function (img) {
    console.log(i, offset[i]);
    ...                
});

您会注意到所有关闭回调中i3offset[i]undefined

这是因为每个回调都保留对i变量的同一实例的引用,并在执行时使用其最新值。 for循环遍历其循环,每次递增i,在任何回调执行之前,i的最终值为3。当您的回调执行时,他们会尝试将left:值设置为offset[3],这是未定义的,并且结构会回退到0

<强>解决方案

ES6之前的变量javascript(与大多数语言不同)仅限于声明它们的函数,代码块不会影响范围。

将图像构建逻辑放入其自己的函数中,在每个循环周期中将当前值i作为参数传递。这会将值放入新范围,并保留该值。

另外,请不要忘记var前面的i关键字。否则,您将影响全局命名空间,您需要不惜一切代价避免它。

以下是您的代码应该是什么样的:

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);
    });
}

最后,您可能需要考虑设置图片的originXoriginY属性,如下所示:

originX: 'left',
originY: 'top'

默认情况下,在放置图像时,结构将使用图像的中心作为原点,并且图像不会完全显示在画布上。

<强>更新

这是fully working example。它取决于结构,需要放在你的js /文件夹中。