How to add an image to canvas, and put a rotated text on top of it? - html5-canvas

Im trying to get canvas to work, what i'm trying to do is make an image(from an existing image) and place a text on it. I want the text to be rotated on the left side of the image. The moment i try to rotate the text, i can't see it anymore in the canvas. Im using the following solution:
var ctx = canvas.getContext("2d");
ctx.drawImage(img,0,0);
ctx.save();
ctx.rotate(-0.5*Math.PI);
ctx.font = "12px Arial";
ctx.fillStyle = 'white';
ctx.textBaseline = 'top';
ctx.fillText("copyright", 0, 0);
ctx.restore();
var image = canvas.toDataURL("image/jpeg");
With this solution i cannot see the text anymore. When i delete the rotation and make the code into the following, everything works fine the image is rendered and the text is rendered on the image.
var ctx = canvas.getContext("2d");
ctx.drawImage(img,0,0);
ctx.rotate(-0.5*Math.PI);
ctx.font = "12px Arial";
ctx.fillStyle = 'white';
ctx.textBaseline = 'top';
ctx.fillText("copyright", 0, 0);
var image = canvas.toDataURL("image/jpeg");
Can anyone see the mistake im making, or does someone have a solution to this problem of mine?
[edit]
I've made a jsfiddle showing the problem http://jsfiddle.net/7kzuN/4/

Before rotating you should always set the rotation point.
Think of the rotation point as a pencil-tip pressed on on a piece of paper.
When you rotate, the paper will rotate around the point of the pencil-tip.
You set the rotation point using context.translate(x,y).
To rotate on the left side of the image, you would translate something like this:
// set the rotation point
ctx.translate(6,img.height/2);
This sets your rotation point 6 pixels off the left side and at the vertical-center of the image.
Here's example code and a demo: http://jsfiddle.net/m1erickson/ANpPm/
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var img=new Image();
img.crossOrigin="anonymous";
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/houseIcon.png";
function start(){
canvas.width=img.width;
canvas.height=img.height;
// draw the image
ctx.drawImage(img,0,0);
// save the unrotated context
ctx.save();
// set the rotation point with translate
ctx.translate(6,img.height/2);
// rotate by -90 degrees
ctx.rotate(-0.5*Math.PI);
// draw the copyright bar
ctx.fillStyle="black";
ctx.fillRect(-img.height/2,-6,img.height,14);
ctx.font = "12px Arial";
ctx.fillStyle = 'white';
ctx.textBaseline = 'top';
ctx.fillText("copyright", -img.height/2+5,-6);
// restore the context to its unrotated state
ctx.restore();
// save the image+text to a dataURL
var image = canvas.toDataURL("image/jpeg");
}

Related

Three js - the best way to draw text and line

after gone through three.js docs, I found it is quite hard to draw line with stroke width, and text.
For the line with stroke width I have to draw an rectange and adjust it to look likes a thick line
For the text, there only two option, one is using font loader, which I found it very hard to handle the promise of font loader, and it become slower if I have so many text.
But if I use canvas to draw the text then use sprite to add that canvas, then I got my texts keep rotates whenever I rotate my camera
so it is 2018, is there any way to make life more easier with three js.
Thanks all
my code to create a thick curve line
function curveLine(start, mid, end, width) {
var curveLine = new THREE.Shape();
curveLine.moveTo(start.x, start.y + width);
curveLine.quadraticCurveTo(mid.x, mid.y + width, end.x, end.y + width);
curveLine.lineTo(end.x, end.y);
curveLine.quadraticCurveTo(mid.x, mid.y, start.x, start.y);
curveLine.lineTo(start.x, start.y);
return curveLine;
}
var line = curveLine({x:0,y:0}, {x:120,y:80}, {x:240,y:0}, 20);
var lineGeo = new THREE.ExtrudeGeometry(line, extrudeSettings);
var lineMesh = new THREE.Mesh(lineGeo, new THREE.MeshBasicMaterial({color: 'red'}));
scene.add(lineMesh);
And this my code to draw text, current using canvas to draws
function text2D(text, params) {
var canvas = document.createElement('canvas');
canvas.width = params.radius * 4;
canvas.height = params.radius * 2;
var context = canvas.getContext('2d');
context.font = '20px Verdana';
var metrics = context.measureText(text);
var textWidth = metrics.width;
context.fillStyle = params.color;
context.fillText(text, (canvas.width - textWidth) / 2, params.radius);
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial({map: texture});
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(canvas.width, canvas.height, 1);
return sprite;
}
and then whenever i rotate the camera, the text keep face the camera. is there any way to prevent that
Cheers all

crop an image multipile times using drawImage() canvas?

I have this code and successfully croped the left corner , but I need to crop all 4 corners of this image ,can it be done with the same object?
I have this code and successfully croped the left corner , but I need to crop all 4 corners of this image ,can it be done with the same object?
the croped image
//Global variables
var myImage = new Image(); // Create a new blank image.
// Load the image and display it.
function displayImage() {
// Get the canvas element.
canvas = document.getElementById("myCanvas");
// Make sure you got it.
if (canvas.getContext) {
// Specify 2d canvas type.
ctx = canvas.getContext("2d");
// When the image is loaded, draw it.
myImage.onload = function() {
// Load the image into the context.
ctx.drawImage(myImage, 0, 0);
// Get and modify the image data.
changeImage();
}
// Define the source of the image.
myImage.src = "ice.jpg";
}
}
function changeImage() {
ctx.strokeStyle = "white";
ctx.lineWidth = "70";
ctx.beginPath();
ctx.arc(0,0,10,0*Math.PI,0.5*Math.PI);
ctx.closePath();
ctx.stroke();
}
</script>
</head>
<body onload="displayImage()">
<canvas id="myCanvas" width="200" height="200">
</canvas>
</body>
</html>
Kind of what #AndreaBogazzi says, but kind of not...
Yes, you can draw all 4 of the corner cutouts using a single path.
This is done by drawing a cutout circle and then picking up the "brush" and moving it to the center of the next cutout.
You must pick up the brush or otherwise you will get a line drawn that connects the centerpoints of each cutout circle.
Begin a single path: ctx.beginPath()
Draw an arc: ctx.arc(0,0,cutRadius,0,Math.PI*2)
Pick up the "brush" and move it to the center of the next arc: ctx.moveTo(w,0)
Draw an arc: ctx.arc(w,0,cutRadius,0,Math.PI*2)
Pick up the "brush" and move it to the center of the next arc: ctx.moveTo(w,h)
Draw an arc: ctx.arc(w,h,cutRadius,0,Math.PI*2)
Pick up the "brush" and move it to the center of the next arc: ctx.moveTo(0,h)
Draw an arc: ctx.arc(0,h,cutRadius,0,Math.PI*2)
Fill all 4 cutout circles: ctx.fill()
Note: since the "brush" begins at [0,0] you don't have to moveTo(0,0) after step#1.
Example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var cutRadius=10;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/reef.jpg";
function start(){
cw=canvas.width=img.width;
ch=canvas.height=img.height
ctx.drawImage(img,0,0);
changeImage();
}
function changeImage() {
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(0,0,cutRadius,0,Math.PI*2);
ctx.moveTo(cw,0);
ctx.arc(cw,0,cutRadius,0,Math.PI*2);
ctx.moveTo(cw,ch);
ctx.arc(cw,ch,cutRadius,0,Math.PI*2);
ctx.moveTo(0,ch);
ctx.arc(0,ch,cutRadius,0,Math.PI*2);
ctx.fill();
}
<canvas id="canvas" width=300 height=300></canvas>
You have to manually draw the four quarter circle:
//Global variables
var myImage = new Image(); // Create a new blank image.
// Load the image and display it.
function displayImage() {
// Get the canvas element.
canvas = document.getElementById("myCanvas");
// Make sure you got it.
if (canvas.getContext) {
// Specify 2d canvas type.
ctx = canvas.getContext("2d");
// When the image is loaded, draw it.
myImage.onload = function() {
canvas.width = myImage.width;
canvas.height = myImage.height;
// Load the image into the context.
ctx.drawImage(myImage, 0, 0);
// Get and modify the image data.
changeImage(myImage.width, myImage.height);
}
// Define the source of the image.
myImage.src = "http://www.keenthemes.com/preview/metronic/theme/assets/global/plugins/jcrop/demos/demo_files/image1.jpg";
}
}
function changeImage(w,h) {
var r = 70;
ctx.fillStyle = "white";
ctx.beginPath();
ctx.moveTo(0,0);
ctx.arc(0,0,r,0*Math.PI,0.5*Math.PI);
ctx.moveTo(0,r);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.arc(w,0,r, -0.5*Math.PI,-1*Math.PI);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(0,h);
ctx.arc(0,h,r, -0.5*Math.PI,0*Math.PI);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(w,h);
ctx.arc(w,h,r, -1*Math.PI,-0.5*Math.PI);
ctx.closePath();
ctx.fill();
}
displayImage();
<canvas id="myCanvas" width="200" height="200">
</canvas>

Three.js - Why is my sprite drawing somewhere other than its position?

I'm using Three.js r69.
I'm drawing several sprites, each with a canvas texture so that I can draw text onto it. I'm following the suggestions found in this question, with a few simple modifications to make it work in r69. When I set the position of the sprite, it doesn't draw it at its position. Here's a screenshot of what's happening:
I'll also include the code I'm using to generate the sprite:
this.text = _text;
this.textColor = new THREE.Color();
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
//...set the font
//...measure the text width
//...get the aspect ratio of width to height of the text
//...set the background color
//...set the border color
var borderThickness = 2;
ctx.lineWidth = borderThickness;
roundRect(ctx,
borderThickness * 0.5, // x
borderThickness * 0.5, // y
this.textWidth + borderThickness, // width
fontsize * 1.4 + borderThickness, // height
6 // corner radius
);
//...set font color
ctx.fillText(this.text, borderThickness, fontsize + borderThickness);
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial(
{map: texture}
);
this.object = new THREE.Sprite(spriteMaterial);
this.object.scale.set(2, 2/this.aspect, 1.0);
Am I doing something wrong when I'm generating the canvas and SpriteMaterial? Or is it something else? I'd like the sprite to pivot around its center, not some point that's completely outside the canvas.
Looks like I wasn't explicitly setting the size of the canvas, so it was defaulting to 300 x 150.
I set the canvas size to that of just the text label, and it positions it correctly.

Get the color of a pixel by its xyz coordinates

I need to get the color of an image texture on a mesh at a given xyz point (mouse click + ray cast). How can I achieve it in THREE.js?
I know I could use gl.readPixels from plain webgl, but it's not a valid option for me.
Thanks!
So I ended using a separate canvas, in which I load the image texture, translate the three.js coordinates into canvas one and read the pixel. Something like this:
// point is a THREE.Vector3
var getColor = function(point, callback) {
var img = new Image();
img.src = 'assets/img/myImage.png';
img.onload = function() {
// get the xy coords from the point
var xyCoords = convertVector3ToXY(point);
// create a canvas to manipulate the image
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
// get the pixel data and callback
var pixelData = canvas.getContext('2d').getImageData(x, y, 1, 1).data;
callback(pixelData);
}
};
Thanks

Positioning an HTML5 Canvas Element

I am completely new to HTML5 and have been reading about it for the past few days mainly because I wanted to create a rotating image to put in a <div>. I found a code that does exactly what I want, but it throws the canvas on to the bottom left corner of my page (I'm not sure why, but I think it has something to do with the very first line of the code below). I'm not sure how to adapt the code to a element so that I can put it where I want. From looking at other people's scripts and trying to emulate them, I know you're supposed to do this sort of thing to hold the canvas "<canvas width="100" height="100" id="pageCanvas"></canvas>," but I don't know how to name the below code in order to do that. I greatly appreciate any help anyone can offer me - thank you so much for reading! :)
<script>
window.addEventListener("load", init);
var counter = 0,
logoImage = new Image(),
TO_RADIANS = Math.PI/180;
logoImage.src = 'IMG URL';
var canvas = document.createElement('canvas');
canvas.width = 100;
canvas.height = 100;
var context = canvas.getContext('2d');
document.body.appendChild(canvas);
function init(){
setInterval(loop, 1000/30);
}
function loop() {
context.clearRect(0,0,canvas.width, canvas.height);
drawRotatedImage(logoImage,100,100,counter);
drawRotatedImage(logoImage,300,100,counter+90);
drawRotatedImage(logoImage,500,100,counter+180);
counter+=2;
}
function drawRotatedImage(image, x, y, angle) {
// save the current co-ordinate system
// before we screw with it
context.save();
// move to the middle of where we want to draw our image
context.translate(x, y);
// rotate around that point, converting our
// angle from degrees to radians
context.rotate(angle * TO_RADIANS);
// draw it up and to the left by half the width
// and height of the image
context.drawImage(image, -(image.width/2), -(image.height/2));
// and restore the co-ords to how they were when we began
context.restore();
}
</script>
Create a canvas element in your HTML code so you can place it exactly where you want (with html + css) :
<canvas id='canvas' height='100' width='100'> Your browser does not support HTML5 canvas </canvas>
And replace this javascript code :
var canvas = document.createElement('canvas');
canvas.width = 100;
canvas.height = 100;
var context = canvas.getContext('2d');
document.body.appendChild(canvas);
by this one :
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

Resources