Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I add a selectable text in HTML 5 Canvas? [duplicate]

I need to place a text label on top of a canvas. Is it possible? How can I do that? I know there's fillText but fillText is not giving me smooth output text. I also want the text on the label to be copyable by the users, which is not possible if I use fillText.

like image 294
Sachin Joseph Avatar asked Jul 29 '13 10:07

Sachin Joseph


3 Answers

Assuming, you simply want to place some text on top of the canvas in an html page :

HTML:

<label>Yahoo, I'm on top of canvas??</label>
<canvas width="500" height="500" ></canvas>

CSS:

canvas {
    border:1px solid gray;
}

label {
    position:absolute;
    top:20px;
    left:20px;
}

Working demo


EDIT:

As per the edit, if you are looking for a solution to select text inside canvas, it would be a bit more pain full.

I would suggest using CreateJS. It would make your life whole lot easier while working with canvas.

Although the library does not provide you with a selectable text, but it is easier to implement.

Here is a DEMO of how you could create a selectable text.

// Text Selector Class
function Selector(stage, text) {
    var select = new createjs.Shape();

    function selector(x, y, width, height) {
        select.graphics.clear().beginFill("#ace")
            .drawRect(x || 0, y || 0, width || 0, height || 0);
    }
    var tuw = text.getMeasuredWidth();
    var tuh = text.getMeasuredHeight();
    text.addEventListener("mousedown", function (e) {
        var startX = e.rawX;
        var onMove = function (e) {
            if (e.rawX >= text.x && e.rawX <= text.x + tuw) selector(startX, text.y, e.rawX - startX, tuh);
        };
        var onUp = function () {
            stage.removeEventListener("stagemousemove", onMove);
            selector();
        };
        stage.addEventListener("stagemousemove", onMove);
        stage.addEventListener("stagemouseup", onUp);
    });
    return select;
}


var stage = new createjs.Stage("shape");

// Text Node
var text = new createjs.Text("Hello World");
text.x = 100;
text.font = "20px Arial";
text.color = "#ff7700";
text.cursor = "text";
stage.addChild(text);

// Attach Selector 
stage.addChildAt(new Selector(stage, text), 0);

// Important
stage.enableMouseOver();
setInterval(function () {
    stage.update();
}, 100);
like image 84
loxxy Avatar answered Oct 17 '22 14:10

loxxy


It is possible. Here's an example using an svg with a foreignObject straight from the Mozilla Developer Network.

<!DOCTYPE html>
<html>
<body>
<p><canvas id="canvas" style="border:2px solid black;" width="200" height="200"></canvas>
<script>
  var canvas = document.getElementById("canvas");
  var ctx = canvas.getContext("2d");
  var data = "<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'>" +
         "<foreignObject width='100%' height='100%'>" +
           "<div xmlns='http://www.w3.org/1999/xhtml' style='font-size:40px'>" +
             "<em>I</em> like <span style='color:white; text-shadow:0 0 2px blue;'>cheese</span>" +
           "</div>" +
         "</foreignObject>" +
       "</svg>";
  var DOMURL = self.URL || self.webkitURL || self;
  var img = new Image();
  var svg = new Blob([data], {type: "image/svg+xml;charset=utf-8"});
  var url = DOMURL.createObjectURL(svg);
  img.onload = function() {
      ctx.drawImage(img, 0, 0);
      DOMURL.revokeObjectURL(url);
  };
  img.src = url;
</script>
</body>
</html>
like image 31
Richard Ambler Avatar answered Oct 17 '22 13:10

Richard Ambler


In one of my canvas projects I needed to create highlight-able, editable, and copy-able text area generated on click and removed when the text area loses focus. Below is the structure of how I did it

Javascript:

var mousePos;
var textarea = null;  
var x;
var y;
var textValue;
function getMousePos(canvas, evt) 
{
  var rect = canvas.getBoundingClientRect();
  return {
    x: evt.clientX - rect.left,
    y: evt.clientY - rect.top
  };
}
canvas.addEventListener('mousedown', function(evt) 
 {
   mousePos = getMousePos(canvas, evt);
   mouseDown = true;
   setTimeout(function() { check(mousePos.x, mousePos.y) }, 50);  
 }, false);
canvas.addEventListener('mouseup', function(evt) 
 {
   evt.preventDefault();
   mouseDown = false;
 }, false);

function check(xPos, yPos)
{
  if(xPos > /*lower bounding x position*/ && xPos < /*upper bounding x position*/ && yPos < /*upper bounding y position*/ && yPos > /*lower bounding y position*/)
  {
    if(!textarea) {
      textarea = document.createElement('textarea');
      textarea.className = 'textArea';
      textarea.onkeypress = function (e) {
        if (e.which === 13) { // Allows pressing 'Enter' to change the focus of the text area
          textarea.blur();
        }
      }
      textarea.onblur = function () {
        /*do something with value*/
        textValue = textarea.value;
        document.body.removeChild(textarea);
        textarea = null;
      } 
      document.body.appendChild(textarea);
    }
    textarea.blur();
    textarea.value = /*put default value*/;
    textarea.style.left = /*put left position of object*/;
    textarea.style.top = /*put top position of object*/;        
  }
}

CSS

.textArea {
  /* The only necessary CSS is a height, a width, and position:absolute */
  position: absolute;
  background:grey;
  height:20px;
  border:0;
  outline:0;
  line-height:10px;
  width:100px;
  resize: none;
  overflow:hidden;
  font-size:10px;
}

This allows only one text area to be created and is created on click and removed when it loses focus. Not sure if you want this functionality, but it's easy to remove if not

Demo here (WiP) when you click on the value to the right of one of the bars

like image 36
Zach Saucier Avatar answered Oct 17 '22 13:10

Zach Saucier