夹在与 KineticJS 楔子的交点上

Posted

技术标签:

【中文标题】夹在与 KineticJS 楔子的交点上【英文标题】:clip on intersection with KineticJS Wedges 【发布时间】:2013-02-10 05:52:17 【问题描述】:

我是 KineticJS 初学者,我想制作两个可拖动的楔子,在它们的交点处更改为特定颜色。我在这个论坛上看到了形状剪裁教程和形状相交问题。我知道一般策略是捕获拖动事件,然后重绘 KineticJS 形状,并在该形状的 drawFunc 中使用 context.rect/context.arc 复制形状并对其进行剪辑。

我的问题是没有方便的 context.wedge 来模拟 KineticJS 楔形。所以要么我停止使用楔形,要么我执行复杂的计算来模拟带有 context.arc 和线条的楔形,或者我想出一个更好的方法。有谁知道更好的方法吗?

谢谢, 梅

JSFiddle 上的代码:http://jsfiddle.net/kdRjP/5/ (不起作用,只是在整个地方制作重复的楔子,甚至没有剪掉的楔子。)

代码:

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript" charset="utf-8" src="js/kinetic-v4.3.1.min.js"></script>
</head>



<body>
    <div id="container"></div>

    <script type="text/javascript">

        drawWedges();


        function drawWedges() 
            var stage = new Kinetic.Stage(
                container: "container",
                width: 400,
                height: 400
            );
            window.console.log("Wedges: 1");

            var wedgeLayer = new Kinetic.Layer();


            var wedgeGroup = new Kinetic.Group(
                x: stage.getWidth() / 2,
                y: stage.getWidth() / 2
            );


            var wedge_1 = new Kinetic.Wedge(
                x: -100,
                y: 0,
                radius: 80,
                angleDeg: 40,
                opacity: 0.7,
                fill: 'red',
                stroke: 'black',
                strokeWidth: 2,
                draggable: true,
                rotationDeg: 0
            );


            var wedge_2 = new Kinetic.Wedge(
                x: 100,
                y: 0,
                radius: 80,
                angleDeg: 40,
                opacity: 0.7,
                fill: 'cyan',
                stroke: 'black',
                strokeWidth: 2,
                draggable: true,
                rotationDeg: 0
            );             



            function makeShapeClip(clipShape, compositeShape) 
                clipShape.attrs.drawFunc_bak = clipShape.attrs.drawFunc;
                clipShape.attrs.drawFunc = function() 
                    var context = this.getContext();
                    context.save();
                    context.beginPath();
                    this.attrs.drawFunc_bak.call(this, context);
                    context.clip();
                    context.beginPath();
                    compositeShape.attrs.drawFunc.call(this, context);
                    context.fill();
                    context.closePath();
                    context.restore();
                ;

                return compositeShape;
            ;   


            wedge_1.on("dragend", function(evt) 
                var mousePos = stage.getMousePosition();

                var stageIntersections = stage.getIntersections("x": mousePos.x, "y": mousePos.y);
                if (stageIntersections.length > 0) 
                    // Want to draw a piece of wedge_1 clipped around wedge_2.
                    // Since can't turn wedge_2 into a clip path after it's been drawn, 
                    // draw a duplicate of wedge_2 superimposed on top of wedge_2, 
                    // turn that duplicate into a clip path, 
                    // and then try to draw a duplicate of wedge_1 into it.


                    // Start by creating the wedge_1 duplicate in proper "intersection area color"
                    var wedgeComposite = new Kinetic.Wedge(
                        x: wedge_1.getX(),
                        y: wedge_1.getY(),
                        radius: wedge_1.getRadius(),
                        angleDeg: wedge_1.getAngleDeg(),
                        opacity: 0.5,
                        fill: 'yellow',
                        stroke: 'blue',
                        strokeWidth: 2,
                        draggable: true,
                        rotationDeg: wedge_1.getRotationDeg()
                    );


                    // Now pass that wedge_1 duplicate into a special function that 
                    // creates wedge_2 duplicate and makes it into a clip path.
                    var wedgeClip = makeShapeClip(new Kinetic.Wedge(
                        x: stageIntersections[0].getX(),
                        y: stageIntersections[0].getY(),
                        radius: stageIntersections[0].getRadius(),
                        angleDeg: stageIntersections[0].getAngleDeg(),
                        opacity: 0.5,
                        fill: '#999999',
                        stroke: 'red',
                        strokeWidth: 2,
                        draggable: true,
                        rotationDeg: stageIntersections[0].getRotationDeg()
                    ), wedgeComposite);


                    wedgeGroup.add(wedgeClip);
                

                wedgeLayer.draw();
            );




            wedgeGroup.add(wedge_1);
            wedgeGroup.add(wedge_2);
            wedgeLayer.add(wedgeGroup);
            stage.add(wedgeLayer);
           
    </script>


</body>
</html>

【问题讨论】:

顺便说一句,KineticJS 计划在下个月左右提供裁剪支持。敬请期待。 真的吗?那太棒了!现在......关于文档......重言式的单行词不适合我。当我弄清楚它们时,我愿意为我自己弄清楚的位编写方法标头。我将如何做出贡献?更好的是,我不想写文本块,如果我不知道它们会在未来的开发过程中被更新。他们会虔诚地更新,对吧? :) 是的,我意识到 KineticJS 文档现在非常稀少。它会变得更好:) 谢谢埃里克。随时需要帮助。 【参考方案1】:

这里有一个解决方案:

假设您的 canvas#1 带有两个 KineticJs 楔形物(红色和青色)。

当用户完成拖动时:

    创建一个新的画布#2(与画布#1 的大小相同),其当前位置/旋转中只有红色楔形。不显示 canvas#2(可见性:隐藏)。

    创建一个新的画布#3(与画布#1 相同的大小),在其当前位置/旋转中只有青色楔形。不显示 canvas#3(可见性:隐藏)。

    从 canvas#2 和 canvas#3 的左上角像素开始,遍历 canvas#2 和 canvas#3 上的每个对应像素。

    如果 #2 和 #3 上的任何对应像素都“着色”,则楔形在该像素处相交。

    对于步骤 4 中的任何“命中”,在 canvas#1 上的相交像素处绘制您想要的任何内容(例如将该像素更改为您指定的颜色)

为了提高性能,您可以计算两个楔形的边界框,看看它们是否完全相交。

如果楔子根本不相交,请不要​​进行像素命中测试。

如果它们确实相交,只需对组合楔块的边界框进行像素命中测试。

【讨论】:

谢谢马克E。您的解决方案是可靠的,并且会起作用。我还提出了我自己的有效解决方案 (jsfiddle.net/4fT3p)。我不喜欢这两种解决方案,因为两者都打破了“让我们使用 KineticJS 来管理形状”模型并回到使用直立画布。如果要做有趣的事情必须停止使用 KineticJS,那么 KineticJS 有很多成熟的工作要做。 Otoh,我可能会遗漏一些东西。

以上是关于夹在与 KineticJS 楔子的交点上的主要内容,如果未能解决你的问题,请参考以下文章

KineticJS - 图像上的图案和填充

KineticJs - 将图像合并到另一个图像上

在 KineticJS 中检测舞台上的点击而不是形状上的点击

KineticJS教程(1-2)

如何在kineticjs中通过json在舞台上绘制图层

Kineticjs如何在舞台上居中图像并根据浏览器调整大小