Possible to use a Bitmap Font to create text in KineticJs?

183 views Asked by At

I like the "Text"-class of KineticJS but its not enough for what I have in mind. Thats why I want to create a bitmap font (having all characters inside one image and using parts of the image to create the text).

  • Is there a best approach to do this in KineticJS?
  • Is there a way to copy a part of an image and draw it on a layer?
2

There are 2 answers

0
markE On BEST ANSWER

If you use Kinetic.Shape, you're given a canvas context to work with.

(It's actually wrapper around the actual context--but it's almost fully functional).

Then use context.drawImage with the clipping parameters to clip letters from your "font spritesheet".

Also keep in mind that there's nothing prohibiting you from creating an offscreen html canvas for tasks like yours.

Clip the letters from your spritesheet onto the offscreen canvas and then use offscreen.toDataURL() to create an image object that you can use in Kinetic.Image--best of both worlds!

Cheers!

0
Christian Strang On

This answer is based on the information markE gave me in his answer.

I implemented the suggestions markE gave me and wanted to share the code with you (complete working example at the end).

Explanation

I load the spritesheet at the top of the script. In the function "drawGame()" I create a new image will use the return value of the "create_math_task_image()"-function. Inside this function I draw the numbers I need on the offscreen canvas (in this example, these are just random numbers). Once I have finished drawing, I grab the image data with c.toDataURL("image/png"); and return it.

working example, just copy and paste into an empty html-file

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />   <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Canvas-Spritesheet Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link href="/favicon.ico" type="image/x-icon" rel="icon" /><link href="/favicon.ico" type="image/x-icon" rel="shortcut icon" /><meta name="description" />
<link rel="stylesheet" type="text/css" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.css" />

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
  <script src="//raw.github.com/twbs/bootstrap/v3.0.0/assets/js/html5shiv.js"></script>
  <script src="//raw.github.com/twbs/bootstrap/v3.0.0/assets/js/respond.min.js"></script>
<![endif]-->

<script src="http://cdnjs.cloudflare.com/ajax/libs/kineticjs/4.7.2/kinetic.min.js"></script>

<style type="text/css">
    #container {border: 1px solid black;}
    #offscreen-canvas   {border: 1px solid red;}
</style>  

</head>
<body>
<div id="container"></div>
<canvas id="offscreen-canvas" style="display:block;"></canvas>

<script type="text/javascript">
var stage;
var game_width = 600;
var game_height = 800;

var layer_math_task = new Kinetic.Layer();

var images = new Array();
images['spritesheet'] = new Image(); 
images['spritesheet'].src = 'http://tuuduu.de/html-templates/ultimath-images/big_numbers.png';

$(function() {
    initGame();

    setTimeout(function() {
        drawGame();
    }, 1000);
});

function initGame() {
    stage = new Kinetic.Stage({
        container: 'container',
        width: game_width,
        height: game_height
    });
}

function drawGame() {
    stage.add(layer_math_task);

    var myMathTaskImgObj = new Image(); 
    myMathTaskImgObj.src = create_math_task_image();

    var image_math_task = new Kinetic.Image({ x: 0, y: 0, image: myMathTaskImgObj});
    layer_math_task.add(image_math_task);
    layer_math_task.draw();     
}


function create_math_task_image() {
    var c=document.getElementById("offscreen-canvas");
    var ctx=c.getContext("2d");
    ctx.canvas.width = game_width;
    ctx.canvas.height = game_height;
    ctx.clearRect(0, 0, game_width, game_height);

    var xpos_pointer = 0;
    var ypos_pointer = 0;

    for(var i=0; i<5; i++)
    {
        var math_task_number = Math.floor(Math.random()*4);
        switch(math_task_number)
        {
            case 0:
                ctx.drawImage(images['spritesheet'], 0, 0, 83, 110, xpos_pointer, 0, 83, 110);
                xpos_pointer += 83;     
                break;
            case 1:
                ctx.drawImage(images['spritesheet'], 84, 0, 45, 110, xpos_pointer, 0, 45, 110);
                xpos_pointer += 45;
                break;
            case 2:
                ctx.drawImage(images['spritesheet'], 131, 0, 86, 110, xpos_pointer, 0, 86, 110);
                xpos_pointer += 86;
                break;
            case 3:
                ctx.drawImage(images['spritesheet'], 218, 0, 75, 110, xpos_pointer, 0, 75, 110);
                xpos_pointer += 75;
                break; 
        }
    }

    return c.toDataURL("image/png");
}
</script>   
</body>
</html>

Additional Information:

  • I load the spritesheet at the top. I use settimeout so the image will be loaded once I need it in the canvas
  • I just mapped the numbers 0-3 from the spritesheet
  • the offscreen-canvas is still visible, for testing purposes. Just style it with "display:none" to hide it