Search code examples
jqueryhtml5-canvaseaseljscreatejs

Referencing canvas graphics as DOM elements with jQuery


Is it possible to reference graphics drawn on an HTML5 canvas element with jQuery? Here's a function I wrote for EaselJS that iterates through an object containing arrays of vector coordinates:

function newShape(obj,shape,coords){
    obj.graphics.beginFill('green');
    obj.alpha = 0.05;
    for (var i=0; i<coords[shape].length; i+=2) {
        var arr = coords[shape].slice(i,i+2);
        obj.graphics.lineTo(arr[0],arr[1]);
    }
    obj.graphics.closePath();
    obj.graphics.endFill();
    stage.addChild(obj);
}

The coords object looks something like this with 100s of points:

var coords = {};

coords['0']  = [214,266,214,291,194,291];
coords['1']  = [243,1,254,2,278,9,290,14];
coords['2']  = [109,112,116,114,129,117];

And the stage:

canvas = document.getElementById("canvas");
stage = new createjs.Stage(canvas);

shape1 = new createjs.Shape();
shape2 = new createjs.Shape();
shape3 = new createjs.Shape();

newShape(shape1,'shape1',coords);
newShape(shape2,'shape2',coords);
newShape(shape3,'shape3',coords);

I can add listeners to the rendered shape for click/touch events, however I'd like to have the ability to reference each graphic as a DOM element for use with plugins like Bootstrap Popover and niceScroll eg.. $(shape1).popover('show');. I've been actively working on a solution with no success, any help would be much appreciated!


Solution

  • Option 1 :

    From Shmiddty's post, a programmatic approach to referencing with 2d context:

    function Shape(can) {
        this.x = 0;
        this.y = 0;
        this.width = 0;
        this.height = 0;
        this.fill = "rgba(0,0,0,0)";
        this.parent = can;
    
        this.draw = function(ctx) {
            if (!$(me.parent).is(':visible')) return;
    
            var parts = me.fill.split(',');
            parts[3] = $(me.parent).css("opacity") + ')';
            me.fill = parts.join(',');
    
            ctx.fillStyle = me.fill;
            ctx.fillRect(me.x, me.y, me.width, me.height);
        };
    
        var me = this;
    }
    
    (function() {
        var can = $("#sandbox")[0],
            ctx = can.getContext('2d'),
            wid = can.width,
            hei = can.height,
            sha = new Shape($('<div id="box"/>').appendTo('body'));
    
        sha.x = 0;
        sha.y = 0;
        sha.width = 50;    
        sha.height = 50;
        sha.offsetWidth = 50;
        sha.offsetHeight = 50;
        sha.fill = "rgba(000,111,222,1)";
    
        (function draw(){
            ctx.clearRect(0,0,wid,hei);
            sha.draw(ctx);
            webkitRequestAnimationFrame(draw);
        })();
    
    
        $(can).click(function(){
            $(sha.parent).fadeToggle();
        });
        $('#box').click(function(){
            $(this).fadeToggle();
        });
    })();​  
    

    Option 2 :

    I was able to track x,y coords from click and touch events by applying CSS to a hidden DOM element.

    Calling a bootstrap popover :

    $("#canvas").click(function(e) {
        var x = e.pageX;
        var y = e.pageY;
    
        if ($.inArray(x, coords['shape1']) !== -1 || $.inArray(y, coords['shape1']) !== -1){
            $("#myObj").css({'position':'absolute','top':y,'left':x}).popover({
                trigger: 'click',
                placement:'top',
            }).popover('show');
        }
    });
    stage.update();
    

    HTML:

    <canvas id="canvas" width="375" height="322"></canvas>
    <span class="myObj" data-content="lorem ipsum content" data-original-title="pop-title"></span>