Mae
Mae

Reputation: 1

clip on intersection with KineticJS Wedges

I'm a KineticJS beginner, and I'd like to make two draggable wedges that change to a specific color at their intersection. I've seen the shape clipping tutorial and the shape intersection questions on this forum. I understand that the general tactic is to catch the drag event, then redraw the KineticJS shape, and within that shape's drawFunc to use the context.rect/context.arc to duplicate the shape and clip on that.

My problem is that there is no convenient context.wedge to simulate a KineticJS wedge. So either I stop using wedges, or I perform complicated calculations to simulate wedges with context.arc and lines, or I figure out a better way. Does anyone know the better way?

Thanks,
Mae

Code on JSFiddle: http://jsfiddle.net/kdRjP/5/ (Doesn't work, just makes duplicate wedges all over the place, and not even clipped ones.)

Code:

<!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>

Upvotes: 0

Views: 789

Answers (1)

markE
markE

Reputation: 105045

Here is a solution:

Assuming you have your canvas#1 with two KineticJs wedges (red and cyan).

When the user has completed their dragging:

  1. Create a new canvas#2 (same size as canvas#1) with the just red wedge in its current position/rotation. Don't show canvas#2 (visibility:hidden).

  2. Create a new canvas#3 (same size as canvas#1) with the just cyan wedge in its current position/rotation. Don't show canvas#3 (visibility:hidden).

  3. Starting with the top-left pixel in both canvas#2 and canvas#3, iterate through every corresponding pixel on canvas#2 and canvas#3.

  4. If any corresponding pixel on #2 and #3 are both "colored", then the wedges are intersecting at that pixel.

  5. For any "hits" in step4, draw whatever you want on canvas#1 at the intersecting pixel (like changing that pixel to your specified color)

To improve performance, you can calculate the bounding boxes for the two wedges and see if they intersect at all.

If the wedges don't intersect at all, don't bother with the pixel-hit-testing.

If they do intersect, just pixel-hit-test the bounding box of the combined wedges.

Upvotes: 0

Related Questions