Search code examples
createjseaseljs

EaselJs shape hitTest unable to set alpha or visiblity


From the sample I created I am unable to set the circle's alpha / visiblity when mousedown draw line. But I am able to console log it when its detect hitTest.. Is there advise in this?

Below is the block of codes:

var canvas, stage;
    var drawingCanvas;
    var oldPt;
    var oldMidPt;
    var title;
    var color;
    var stroke;
    var colors;
    var index;
    var rect, circle1;
    var currMidPt;

    $(document).ready(function() {
        init();

    });

    function init() {
        canvas = document.getElementById("canvas");
        index = 0;
        colors = ["#828b20", "#b0ac31", "#cbc53d", "#fad779", "#f9e4ad", "#faf2db", "#563512", "#9b4a0b", "#d36600", "#fe8a00", "#f9a71f"];

        //check to see if we are running in a browser with touch support
        stage = new createjs.Stage(canvas);
        stage.autoClear = false;
        stage.enableDOMEvents(true);

        createjs.Touch.enable(stage);
        createjs.Ticker.setFPS(24);
        createjs.Ticker.on("tick", tick);

        drawingCanvas = new createjs.Shape();

        stage.addEventListener("stagemousedown", handleMouseDown);
        stage.addEventListener("stagemouseup", handleMouseUp);

        title = new createjs.Text("Click and Drag to draw", "36px Arial", "#777777");
        title.x = 300;
        title.y = 200;

    rect = new createjs.Shape();
    rect.graphics.beginFill("#000").drawRect(0, 0, stage.canvas.width, stage.canvas.height);
    var container = new createjs.Container();
    container.x = 0;
    container.y = 0;

        stage.addChild(container, title);

        stage.addChild(drawingCanvas);




    circle1 = new createjs.Shape();
    circle1.graphics.beginFill("#990000").drawCircle(120,120,40);

    container.addChild(circle1);

        stage.update();
    }

    function handleMouseDown(event) {
        if (!event.primary) { return; }
        if (stage.contains(title)) {
            stage.clear();
            stage.removeChild(title);
        }
        color = colors[(index++) % colors.length];
        stroke = Math.random() * 30 + 10 | 0;
        oldPt = new createjs.Point(stage.mouseX, stage.mouseY);
        oldMidPt = oldPt.clone();
        stage.addEventListener("stagemousemove", handleMouseMove);
    }

    function handleMouseMove(event) {
        if (!event.primary) { return; }
        var midPt = new createjs.Point(oldPt.x + stage.mouseX >> 1, oldPt.y + stage.mouseY >> 1);

        drawingCanvas.graphics.clear().setStrokeStyle(stroke, 'round', 'round').beginStroke(color).moveTo(midPt.x, midPt.y).curveTo(oldPt.x, oldPt.y, oldMidPt.x, oldMidPt.y);

        oldPt.x = stage.mouseX;
        oldPt.y = stage.mouseY;

        oldMidPt.x = midPt.x;
        oldMidPt.y = midPt.y;

        currMidPt = midPt;
        if(circle1.hitTest(currMidPt.x, currMidPt.y)) {
                console.log('test');
                circle1.alpha = 0.6;
          circle1.visible = false;
            } 
        stage.update();
    }

    function tick(event) {


    // console.log(ndgmr.checkPixelCollision(drawingCanvas,circle1,0,false));

        stage.update(event);
    }

    function handleMouseUp(event) {
        if (!event.primary) { return; }
        stage.removeEventListener("stagemousemove", handleMouseMove);
    }

Solution

  • The main reason this doesn't work is because you are using a stage that never clears itself. This gives you the benefit of a "paint brush", since it just adds new curves as you draw, but the circle can never be removed, since it is painted on to the canvas. If you change the alpha, it just draws on top of the current circle. This is also why your circle gets all aliased, as it constantly draws on top of itself, multiplying the alpha.

    Here is a quick edit that shows the circle moving its x position instead of adjusting the alpha. Any time you roll over the original position it will move 10 pixels to the right.

    http://codepen.io/lannymcnie/pen/redrgo?editors=0010

    The hitTest code you have used is not correct though, since it always checks the x/y position of the pen against the local coordinates of the circle -- this means the position of the circle doesn't matter. To fix this, you need to find the local coordinates instead:

    currMidPt = circle1.globalToLocal(midPt.x, midPt.y);
    

    Here is an updated fiddle showing that behaviour: http://codepen.io/lannymcnie/pen/grejVg?editors=0010


    However, to get the effect you are probably looking for, you have to take a different approach. Instead of using the stage auto-clear, use a cached Shape, and update the cache when you draw. This will provide the paint effect, but let the rest of the stage get updated as usual.

    // Remove this!
    stage.autoClear = false;
    
    // Cache the drawingCanvas once after creating it
    drawingCanvas = new createjs.Shape();
    drawingCanvas.cache(0,0,canvas.width,canvas.height);
    
    // After drawing, update the cache. This is at the end of the mousemove function.
    // Use "source-over" to apply the new contents on top, instead of clearing the cache.
    drawingCanvas.updateCache("source-over");
    stage.update();
    

    I also made a few other changes:

    • Removed the Ticker listener that updates the stage. Your mousemove already updates the stage when the contents change. If you want to reintroduce the ticker update for other content, then remove the stage.update() calls everywhere else, as they are redundant.
    • Moved the drawingCanvas below the circle/container. This just makes sure the circle is always visible for the demo

    Here is a final demo with these changes: http://codepen.io/lannymcnie/pen/NNYLPX?editors=0010

    Hope that helps!