Write text inside rectangle - html

I am trying to find how to filltext inside a rectangle. Unfortunately i can only find C# projects/tutorials.
Is it possible to add text inside a rectangle in HTML5 in a canvas?
I want each rectangle (node) to have a different text on it for example 1 is called cow and the other tiger and so on. Is this possible? i have tried everything!
var x = 150;
var y = 100;
var canvas = $('#NodeList').get(0);
var ctx = canvas.getContext('2d');
ctx.font = "30px Arial";
canvas.height = 0;
var rects = [
[20, 20, x, y],
[20, 220, x, y],
[20, 420, x, y],
[20, 620, x, y],
[20, 820, x, y],
[20, 1020, x, y],
[20, 1220, x, y],
[20, 1420, x, y],
[20, 1620, x, y]
];
for (var i = 0; i < rects.length; i++) {
canvas.height = canvas.height + 200;
ctx.clearRect(0, 0, canvas.width, canvas.height);
//rectangles opnieuw tekenen
for (var j = 0; j < i; j++) {
ctx.fillRect(rects[j][0],
rects[j][1],
rects[j][2],
rects[j][3]);
}
ctx.fillRect(rects[i][0],
rects[i][1],
rects[i][2],
rects[i][3]);
}
$('#NodeList').click(function (e) {
var x = e.offsetX,
y = e.offsetY;
for (var i = 0; i < rects.length; i++) {
if (x > rects[i][0] && x < rects[i][0] + rects[i][2] && y > rects[i][1] && y < rects[i][1] + rects[i][3]) {
alert('Vierkant ' + i + ' clicked');
}
}
});
enter code here

I know its really old question. But I ran into a similar so I decided to post the answer.
Note: You have to treat canvas differently that html tags like div. You get one ctx for canvas and you paint on it like a stream. Just change the position of your next elements and it would as expected.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath();
context.rect(188, 50, 200, 100);
context.fillStyle = 'red';
context.shadowColor = '#999';
context.shadowBlur = 20;
context.shadowOffsetX = 15;
context.shadowOffsetY = 15;
context.fill();
context.fillStyle = 'black';
context.font = '20px Courier';
context.shadowColor = 'transparent';
context.shadowBlur = 0;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.fillText(`List item`, 200, 80);
context.lineWidth = 7;
<canvas id="myCanvas" width="578" height="200"></canvas>

Related

Draw Line Arrowhead Without Rotating in Canvas

Most code to drawing arrowheads in html canvas involves rotating the canvas context and drawing the lines.
My use case is to draw them using trigonometry without rotating the canvas. or is that vector algorithm you call it? Help is appreciated.
This is what I have (forgot where I got most of the code). Draws 2 arrowheads on start and end based on the last 2 parameters arrowStart and arrowEnd which are boolean.
drawLineArrowhead: function(context, arrowStart, arrowEnd) {
// Place start end points here.
var x1 = 0;
var y1 = 0;
var x2 = 0;
var y2 = 0;
var distanceFromLine = 6;
var arrowLength = 9;
var dx = x2 - x1;
var dy = y2 - y1;
var angle = Math.atan2(dy, dx);
var length = Math.sqrt(dx * dx + dy * dy);
context.translate(x1, y1);
context.rotate(angle);
context.beginPath();
context.moveTo(0, 0);
context.lineTo(length, 0);
if (arrowStart) {
context.moveTo(arrowLength, -distanceFromLine);
context.lineTo(0, 0);
context.lineTo(arrowLength, distanceFromLine);
}
if (arrowEnd) {
context.moveTo(length - arrowLength, -distanceFromLine);
context.lineTo(length, 0);
context.lineTo(length - arrowLength, distanceFromLine);
}
context.stroke();
context.setTransform(1, 0, 0, 1, 0, 0);
},
See the code below, just a bit of trigonometry.
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
ctx.lineCap = "round";
ctx.lineWidth = 5;
function drawLineArrowhead(p1, p2, startSize, endSize) {
ctx.beginPath()
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
if (startSize > 0) {
lineAngle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
delta = Math.PI/6
for (i=0; i<2; i++) {
ctx.moveTo(p1.x, p1.y);
x = p1.x + startSize * Math.cos(lineAngle + delta)
y = p1.y + startSize * Math.sin(lineAngle + delta)
ctx.lineTo(x, y);
delta *= -1
}
}
if (endSize > 0) {
lineAngle = Math.atan2(p1.y - p2.y, p1.x - p2.x);
delta = Math.PI/6
for (i=0; i<2; i++) {
ctx.moveTo(p2.x, p2.y);
x = p2.x + endSize * Math.cos(lineAngle + delta)
y = p2.y + endSize * Math.sin(lineAngle + delta)
ctx.lineTo(x, y);
delta *= -1
}
}
ctx.stroke();
}
drawLineArrowhead({x:10, y:10}, {x:100, y:20}, 0, 30)
drawLineArrowhead({x:20, y:25}, {x:140, y:120}, 20, 20)
drawLineArrowhead({x:140, y:20}, {x:80, y:50} , 20, 0)
drawLineArrowhead({x:150, y:20}, {x:150, y:90}, 20, 5)
drawLineArrowhead({x:180, y:90}, {x:180, y:20}, 20, 5)
drawLineArrowhead({x:200, y:10}, {x:200, y:140}, 10, 10)
drawLineArrowhead({x:220, y:140}, {x:220, y:10}, 10, 20)
<canvas id="canvas">
If you run it you should see a few samples.
The drawLineArrowhead has 4 parameters (p1, p2, startSize, endSize)
the first two are the starting-point and end-point of the line, the last two are arrow size, just to give some control to the final user over how big are those arrows at the end, if we want to remove them we set to 0.

HTML5 Canvas - cant apply source-atop on mask

Sorry I am new to Canvas and dont know how to google this out. Problem is that I cant draw on mask if previous layer (night sky) is present.
Here are the two snippets:
const canvas = document.querySelector('#board canvas');
const ctx = canvas.getContext('2d');
const { width: w, height: h } = canvas;
// first layer
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, w, h);
ctx.fillStyle = '#555';
let x, y, radius;
for (let i = 0; i < 550; i++) {
x = Math.random() * w;
y = Math.random() * h;
radius = Math.random() * 3;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
ctx.fill();
}
// destination
ctx.font = 'bold 70pt monospace';
ctx.fillStyle = 'black';
ctx.fillText('FOO', 10, 60);
ctx.fillText('BAR', 10, 118);
ctx.fill();
// source
ctx.globalCompositeOperation = 'source-atop';
for (let i = 0; i < 6; i++) {
ctx.fillStyle = `hsl(${i * (250 / 6)}, 90%, 55%)`;
ctx.fillRect(0, i * 20, 200, 20);
}
<div id="board">
<canvas width="640" height="480"></canvas>
</div>
EXPECTED RESULT (but with the first layer - night sky):
const canvas = document.querySelector('#board canvas');
const ctx = canvas.getContext('2d');
const { width: w, height: h } = canvas;
// destination
ctx.font = 'bold 70pt monospace';
ctx.fillStyle = 'black';
ctx.fillText('FOO', 10, 60);
ctx.fillText('BAR', 10, 118);
ctx.fill();
// source
ctx.globalCompositeOperation = 'source-atop';
for (let i = 0; i < 6; i++) {
ctx.fillStyle = `hsl(${i * (250 / 6)}, 90%, 55%)`;
ctx.fillRect(0, i * 20, 200, 20);
}
<div id="board">
<canvas width="640" height="480"></canvas>
</div>
Compositing will affect the whole context.
source-atop mode will draw only where there were existing pixels (i.e only where alpha > 0).
When you draw your background, all the pixels of your context have alpha values set to 1.
This means that source-atop will not produce anything on your fully opaque image.
Once you understand these points, it's clear that you need to make your compositing alone.
It could be e.g on a different off-screen canvas that you would then draw back on the main canvas with ctx.drawImage(canvas, x, y).
const canvas = document.querySelector('#board canvas');
const ctx = canvas.getContext('2d');
const {
width: w,
height: h
} = canvas;
// background
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, w, h);
ctx.fillStyle = '#555';
let x, y, radius;
for (let i = 0; i < 550; i++) {
x = Math.random() * w;
y = Math.random() * h;
radius = Math.random() * 3;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
ctx.fill();
}
// text compositing on an off-screen context
const ctx2 = Object.assign(document.createElement('canvas'), {
width: 200,
height: 120
}).getContext('2d');
// text
ctx2.font = 'bold 70pt monospace';
ctx2.fillStyle = 'black';
ctx2.fillText('FOO', 10, 60);
ctx2.fillText('BAR', 10, 118);
ctx2.globalCompositeOperation = 'source-atop';
// rainbow
for (let i = 0; i < 6; i++) {
ctx2.fillStyle = `hsl(${i * (250 / 6)}, 90%, 55%)`;
ctx2.fillRect(0, i * 20, 200, 20);
}
// now draw our off-screen canvas on the main one
ctx.drawImage(ctx2.canvas, 0, 0);
<div id="board">
<canvas width="640" height="480"></canvas>
</div>
Or, since this is the only compositing in your composition, you can also do it all on the same, but use an other compositing mode: destination-over.
This mode will draw behind the existing content, this means that you will have to actually draw your background after you made the compositing.
const canvas = document.querySelector('#board canvas');
const ctx = canvas.getContext('2d');
const {
width: w,
height: h
} = canvas;
//
// text compositing on a clear context
drawText();
// will draw only where the text has been drawn
ctx.globalCompositeOperation = 'source-atop';
drawRainbow();
// from here we will draw behind
ctx.globalCompositeOperation = 'destination-over';
// so we need to first draw the stars, otherwise they'll be behind
drawStars();
//And finally the sky black background
drawSky();
//... reset
ctx.globalCompositeOperation = 'source-over';
function drawSky() {
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, w, h);
}
function drawStars() {
ctx.fillStyle = '#555';
let x, y, radius;
for (let i = 0; i < 550; i++) {
x = Math.random() * w;
y = Math.random() * h;
radius = Math.random() * 3;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
ctx.fill();
}
}
function drawText()  {
ctx.font = 'bold 70pt monospace';
ctx.fillStyle = 'black';
ctx.fillText('FOO', 10, 60);
ctx.fillText('BAR', 10, 118);
}
function drawRainbow() {
for (let i = 0; i < 6; i++) {
ctx.fillStyle = `hsl(${i * (250 / 6)}, 90%, 55%)`;
ctx.fillRect(0, i * 20, 200, 20);
}
}
<div id="board">
<canvas width="640" height="480"></canvas>
</div>

Properties lost when copying HTML canvas or converting toDataURL

I'm using a native HTML 5 canvas to create a text effect then attempting to create an image from the canvas or copy the canvas to a fabric.js object, but the output doesn't reflect the changes done to the text.
Fiddle: https://jsfiddle.net/rf8kdxq1/2/
Something simple I hope?
var ctx = demo.getContext('2d'),
font = '64px impact',
w = demo.width,
h = demo.height,
curve,
offsetY,
bottom,
textHeight,
isTri = false,
dltY,
angleSteps = 180 / w,
i = w,
y,
os = document.createElement('canvas'),
octx = os.getContext('2d');
os.width = w;
os.height = h;
octx.font = font;
octx.textBaseline = 'top';
octx.textAlign = 'center';
curve = parseInt(110, 10);
offsetY = parseInt(4, 10);
textHeight = parseInt(64, 10);
bottom = parseInt(200, 10);
octx.fillText('BRIDGE', w * 0.5, 0);
/// slide and dice
i = w;
dltY = curve / textHeight;
y = 0;
while (i--) {
y = bottom - curve * Math.sin(i * angleSteps * Math.PI / 180);
ctx.drawImage(os, i, 0, 1, textHeight,
i, h * 0.5 - offsetY / textHeight * y, 1, y);
}
// ctx.drawImage(os, i, 0);
dataURL = os.toDataURL();
img = new Image();
img.src = dataURL;
img.onload = function() {
console.log(img);
};
var newCanv = new fabric.Canvas('canvasd');
function xfer() {
var image = new fabric.Image(os);
setTimeout(function() {
newCanv.add(image);
},500);
}
xfer();

HTML5 canvas background image repeat

I have a html5 canvas that draws a sound wave. I have set the background as an background image, however, I want this background image to repeat. Can anyone tell me how I would do this and what I need to add into my code:
var backgroundImage = new Image();
backgroundImage.src = 'http://www.samskirrow.com/client-kyra/images/main-bg.jpg';
var canvas;
var context;
function init(c) {
canvas = document.getElementById(c);
context = canvas.getContext("2d");
soundManager.onready(function() {
initSound(clientID, playlistUrl);
});
aniloop();
}
function aniloop() {
requestAnimFrame(aniloop);
drawWave();
}
function drawWave() {
var step = 10;
var scale = 60;
// clear
context.drawImage(backgroundImage, 0, 0);
// left wave
context.beginPath();
context.moveTo(0, 256);
for ( var i = 0; i < 256; i++) {
context.lineTo(6 * i, 257 + waveLeft[i] * 80.);
}
context.lineWidth = 1;
context.strokeStyle = "#000";
context.stroke();
// right wave
context.beginPath();
context.moveTo(0, 256);
for ( var i = 0; i < 256; i++) {
context.lineTo(6 * i, 256 + waveRight[i] * 80.);
}
context.lineWidth = 1;
context.strokeStyle = "#000";
context.stroke();
}
function updateWave(sound) {
waveLeft = sound.waveformData.left;
}
return {
init : init
};
})();
You can see this code in action here:
http://www.samskirrow.com/client-kyra
Use the canvas' createPattern function
const canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
img = new Image();
img.src = 'https://www.google.nl/images/srpr/logo3w.png';
img.addEventListener('load', () => {
const ptrn = context.createPattern(img, 'repeat'); // Create a pattern with this image, and set it to "repeat".
context.fillStyle = ptrn;
context.fillRect(0, 0, canvas.width, canvas.height); // context.fillRect(x, y, width, height);
})
<canvas id="canvas" width="600px" height="600px"></canvas>
(This is the fastest of the 2 samples).
Or, try a manual implementation:
const canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
img = new Image();
img.src = 'https://www.google.nl/images/srpr/logo3w.png';
img.addEventListener('load', () => {
for (let w = 0; w < canvas.width; w += img.width) {
for (let h = 0; h < canvas.height; h += img.height) {
context.drawImage(img, w, h);
}
}
})
<canvas id="canvas" width="600px" height="600px"></canvas>

Draw a series of rotated lines with HTML canvas

I want to draw a polyline like this
from an array consisting of sets of angles and lengths (50 and 100, 90 and 20, 90 and 30 etc..)
Any ideas?
that was a hard one ...
e.g array of objects of angle & lengths:
var arr = [
{ angle: 0, h: 50 },
{ angle: 90, h: 60 },
{ angle: 180, h: 70 },
{ angle: 270, h: 80 },
{ angle: 180, h: 90 }
];
the following draw method will draw the lines from the previous array,
function getAngle(ctx, x, y, angle, h) {
var radians = angle * (Math.PI / 180);
return { x: x + h * Math.cos(radians), y: y + h * Math.sin(radians) };
}
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.beginPath();
var pos = { x: 400, y: 400 };
for (var i = 0; i < arr.length; i++) {
ctx.moveTo(pos.x, pos.y);
pos = getAngle(ctx, pos.x, pos.y, arr[i].angle, arr[i].h);
ctx.lineTo(pos.x, pos.y);
}
ctx.stroke();
}
}
you can call the draw after the canvas element
<div style="width:800px;height:800px;border:solid 1px red;">
<canvas id="canvas" width="800" height="800"></canvas>
</div>
<script type="text/javascript">
draw();
</script>
EDIT:
try changing draw function to this,
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.beginPath();
var pos = { x: 400, y: 400 },
angle = 0;
for (var i = 0; i < arr.length; i++) {
angle += arr[i].angle;
angle = (arr[i].angle + angle) % 360;
ctx.moveTo(pos.x, pos.y);
pos = getAngle(ctx, pos.x, pos.y, arr[i].angle + angle, arr[i].h);
ctx.lineTo(pos.x, pos.y);
}
ctx.stroke();
}
}
I had a similar problem as Morten J and tried Shlomi Komemi's second draw function and it works fine ... but only for the Array he gave with only multiples of 90°.
However, if you try 30° you will notice that something is wrong because a right angle is drawn.
I figured out that the reason for this is that angle and arr[i].angle are summed up 3 times.
Here is the corrected version of the function:
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.beginPath();
var pos = { x: 400, y: 400 },
angle = 0;
for (var i = 0; i < arr.length; i++) {
angle = (arr[i].angle + angle) % 360;
ctx.moveTo(pos.x, pos.y);
pos = getAngle(ctx, pos.x, pos.y, angle, arr[i].h);
ctx.lineTo(pos.x, pos.y);
}
ctx.stroke();
}
}
That should work (but I guess the Morten does not care after 3 years...).