【问题标题】:Moving element in canvas copies it multiple times until developer's console is opened在画布中移动元素会多次复制它,直到打开开发人员的控制台
【发布时间】:2020-04-15 17:11:52
【问题描述】:

我想要实现的是为画布加载背景图像,然后创建和移动形状。由于我想稍后扩展这个功能,所以我使用的是 paper.js (0.12.4),它带有很多示例和方便的工具。

总而言之,我能够做到这一点,但我需要通过打开浏览器控制台或放大和缩小(Firefox 74;Chrome 80.0.3987.149)。就在那时,一切都按计划进行。请看下面的 GIF。

这是上面演示的代码:

<!DOCTYPE html>
<html lang="en">
    <head >
        <title></title>

        <!-- Load Bootstrap and JQuery -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>

    <body>
        <div id="main">
            <div>
                <canvas id="myCanvas" resize></canvas>
            </div>
        </div>

        <script type="text/paperscript" canvas="myCanvas">

            var hitOptions = {
                segments: true,
                stroke: true,
                fill: true,
                tolerance: 5
            };

            var segment, path;
            var movePath = false;
            function onMouseDown(event) {
                segment = path = null;
                var hitResult = project.hitTest(event.point, hitOptions);
                if (!hitResult)
                    return;

                if (event.modifiers.shift) {
                    if (hitResult.type == 'segment') {
                        hitResult.segment.remove();
                    };
                    return;
                }

                if (hitResult) {
                    path = hitResult.item;
                    if (hitResult.type == 'segment') {
                        segment = hitResult.segment;
                    } else if (hitResult.type == 'stroke') {
                        var location = hitResult.location;
                        segment = path.insert(location.index + 1, event.point);
                    }
                }
                movePath = hitResult.type == 'fill';
                if (movePath)
                    project.activeLayer.addChild(hitResult.item);
            }

            function onMouseDrag(event) {
                if (segment) {
                    segment.point += event.delta;
                } else if (path) {
                    path.position += event.delta;
                }
                logCanvasData();
            }

            function logCanvasData() {
                var c = document.getElementById('myCanvas');
                var ctx = c.getContext('2d');
                var imgData = ctx.getImageData(0, 0, c.width, c.height);

                for (var i = 0; i < 120; i += 4) {
                    if (imgData.data[i] == 255) {
                        console.log("We have a color with red inside.");

                    } else if (imgData.data[i] == 0 && imgData.data[i+1] == 0 && imgData.data[i+2] == 0 && imgData.data[i+3] != 0){
                        console.log("We have a black value!");
                    }
                }
            }

            function onResize(event) {
                // Whenever the window is resized, recenter the path:
                path.position = view.center;
            }
        </script>

        <script>
            window.onload = function() {
                // Loads the canvas element with a background image
                // and an example polygon.
                loadCanvas();
            }
        </script>
        <script>
            function loadCanvas(imageUrl, canvasId) {

                if (typeof imageUrl == "undefined") {
                    imageUrl = "teddy_bear.jpg";
                }

                if (typeof canvasId == "undefined") {
                    canvasId = "myCanvas";
                }

                canvasImageWidth = 0;
                canvasImageHeight = 0;
                var canvasImage = new Image();
                canvasImage.onload = function() {
                    // Determine the image size which will be the background of the canvas.
                    canvasImageWidth = this.width;
                    canvasImageHeight = this.height;

                    // Adjust the canvas size and set the background image.
                    var canvasElement = document.getElementById(canvasId);
                    canvasElement.width = canvasImageWidth;
                    canvasElement.height = canvasImageHeight;
                    canvasElement.style.background = "url(" + canvasImage.src + ")";

                    myPath = new paper.Path();
                    myPath.closed = true;

                    myPath.strokeColor = 'black';
                    myPath.fillColor = {hue:180, saturation:30, lightness:100}
                    myPath.add(new paper.Point(0, 0));
                    myPath.add(new paper.Point(100, 50));
                    myPath.add(new paper.Point(50, 150));
                    myPath.opacity = 0.3;

                };

                canvasImage.src = imageUrl;
            }
        </script>

        <!-- Load script to draw polygons -->
        <script src="paperjs-v0.12.4/dist/paper-full.js"></script>
    </body>
</html> 

我相信有办法解决这个问题。任何建议表示赞赏。


可能的解决方案:

  1. 如 sasensi 在他的回复下方的评论中所示:sfiddle.net/xidi2xidi/v67odmjy

  2. 另一种可行的方式,但在某种程度上取决于您如何加载网站和图像,如下所示。在我的例子中,图像信息由 python Flask 后端传递,因此我可以将它们添加为画布的样式参数。

<style>
  canvas[resize] {
    width: {{ imageWidth }}px;
    height: {{ imageHeight }}px;
    background-image: url("{{ imagePath }}");
  }
</style>

【问题讨论】:

    标签: javascript paperjs


    【解决方案1】:

    依赖 Paper.js 是个好主意,因为它会为您完成很多工作。
    其实你也应该用它来画你的背景,一切都会简单很多。

    这是一个sketch 演示解决方案。

    // Draw an image as background.
    const raster = new Raster({
        source: 'http://assets.paperjs.org/images/marilyn.jpg',
        // Lower down the opacity so we can see the rest better.
        opacity: 0.4,
        // When image is loaded...
        onLoad: () => {
            // ...make sure that it fills the entire canvas.
            raster.fitBounds(view.bounds, true);
        }
    });
    
    // Draw a circle on top of the image.
    const circle = new Path.Circle({
        center: view.center,
        radius: 50,
        fillColor: 'orange',
        // On circle drag...
        onMouseDrag: event => {
            // ...move it.
            circle.position += event.delta;
        }
    });
    
    // Draw intsructions.
    new PointText({
        content: 'Drag and drop the circle over the image',
        point: view.center + [0, -80],
        justification: 'center',
        fontSize: 24
    });
    
    

    【讨论】:

    • 感谢您的回复@sasensi。您在此处共享的代码仍然存在一个问题:画布大小需要预先设置,并且不会根据加载的图像动态调整。我没有明确提到它,但提供的代码包括根据提供的图像 URL 确定画布大小的步骤。
    • 在这种情况下,我认为您应该先加载图像并相应地设置画布大小,然后再进行绘制。这是一个演示可能实现的小提琴:jsfiddle.net/xidi2xidi/v67odmjy
    猜你喜欢
    • 2015-09-22
    • 1970-01-01
    • 2019-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-21
    • 2021-12-12
    相关资源
    最近更新 更多