Search code examples
phphtmlcanvaskineticjs

Using stage.toDataUrl ,Shape drawFunc content will not captured


I recently found using stage.toDataURL for saving stage content as a image.(KineticJS version 5.0.1)

Custom Shape drawFunc content with core HTML5 canvas object will not applied in image after saving an image.

###################### Images

Please see attached image to get better clarity.

1)Original canvas(stage).

https://f.cloud.github.com/assets/1320926/2300781/c8167c30-a107-11e3-9b61-acf94005c252.png

2)Image after saving stage content test1

https://f.cloud.github.com/assets/1320926/2300784/fc5343b6-a107-11e3-8c69-07cccc4d7ac4.png

We see that the vertical string "Sample Text" will not saved or it's invisible whatever it is.

###################### Code

1)Here is my code of shape object where line was printed vertically "Sample Text"

var sampleText = new Kinetic.Shape({
    drawFunc: function(context) {
        var ctx=this.getContext()._context;
        ctx.beginPath();

        var maxWidth = 2;
        var lineHeight = 25;
        var x = 415;
        var y = 700;
        var text = 'Sample Text';
        ctx.font = '15pt Calibri';
        ctx.fillStyle = 'green';
        //Function for vetical text display
        wrapText(ctx, text, x, y, maxWidth, lineHeight);
        ctx.closePath();
        ctx.fill();
        ctx.restore();

   },
});

//wrapText function if needed

function wrapText(context, text, x, y, maxWidth, lineHeight) {
    var words = text.split('');
    var line = '';
    //alert(context);
    for(var n = 0; n < words.length; n++) {
        var testLine = line + words[n] + ' ';
        var metrics = context.measureText(testLine);
        var testWidth = 20;
        if (testWidth > maxWidth && n > 0) {
            context.fillText(line, x, y);
            line = words[n] + ' ';
            y += lineHeight;
        }
        else {
            line = testLine;
        }
   }
   context.fillText(line, x, y);
}

2)Stage code for saving an image

stage.toDataURL({
    callback: function(dataUrl) {
    /*
    * here you can do anything you like with the data url.
    * In this tutorial we'll just open the url with the browser
    * so that you can see the result as an image
    */
        $('#theimage').attr('src',dataUrl);
        $.ajax({
            type: "POST",
            url: "save.php",
            data: { imageData: dataUrl },
        });
    }
});

Please advise.

Thanks in advance for your time and consideration.

-Naitik.


Solution

  • You chould not use this.getContext()._context because _context is "private" property (starts with undescore). It is not KinetiJS way. Use context as in an example: http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-shape-tutorial/

    Your solution:

    var sampleText = new Kinetic.Shape({
        drawFunc: function(ctx) {
            ctx.beginPath();
    
            var maxWidth = 2;
            var lineHeight = 25;
            var x = 0;
            var y = 0;
            var text = 'Sample Text';
            ctx.setAttr("font", '15pt Calibri');
            ctx.setAttr('fillStyle','green');
            //Function for vetical text display
            wrapText(ctx, text, x, y, maxWidth, lineHeight);
            ctx.closePath();
            // KineticJS specific context method
            ctx.fillStrokeShape(this);
    
       }
    });
    function wrapText(context, text, x, y, maxWidth, lineHeight) {
        var words = text.split('');
        var line = '';
        //alert(context);
        for(var n = 0; n < words.length; n++) {
            var testLine = line + words[n] + ' ';
            var metrics = context._context.measureText(testLine);
            var testWidth = 20;
            if (testWidth > maxWidth && n > 0) {
                context.fillText(line, x, y);
                line = words[n] + ' ';
                y += lineHeight;
            }
            else {
                line = testLine;
            }
       }
       context.fillText(line, x, y);
    }
    

    Demo: http://jsbin.com/xolen/1/edit

    Note: KineticJS's context has not measureText method, so you have to use _context property. I think measureText method will be added soon.