Add ID to each rendered element inside canvas - javascript

I need little help.
How can I add a text inside each rendered element inside canvas ?
here is a fiddle representing my idea:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x_width = canvas.width;
var y_height = canvas.height;
var dx = 2;
var dy = -2;
var ballRadius = 10;
var data = [
[1,0.506,0.648],
[2,0.253,0.433],
[5,0.339,0.445],
[7,0.396,0.569],
[8,0.271,0.583],
[9,0.307,0.187],
[10,0.431,0.213],
[12,0.71,1.045],
[13,0.2,0.259],
[14,0.272,0.259],
[15,0.477,0.379]
];
for (var i = 0; i<=data.length-1; i++) {
var x = x_width*data[i][1];
var y = y_height*data[i][2];
var id = data[i][0];
drawPlayer (id, x,y);
}
function drawPlayer(id, x, y) {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.fillText(id, 0, 0);
ctx.closePath();
}
drawPlayer();
//setInterval(draw , 100);
#myCanvas {
border: 1px solid red;
}
<canvas id="myCanvas" width="480" height="320"></canvas>
<div class="play-btn-hld">
<button class="play">Graj</button>
</div>
Can I somehow add a text inside each element ? Idealy the text should be the data[i][0] number. Is it possible ? I can not wrap my head around it.
Or Should I use classic html and css to create similar effect ?
Cheers

you need to set the x and y position of the text to be the same as the circle's position.
plus measuring the text in order to have it aligned nicely.
here you go:
function drawPlayer(id, x, y) {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
const textWidth = ctx.measureText(id);
const textHeight = 12 * 0.5;
ctx.font = "12px Arial"
ctx.fillStyle = "#fff";
ctx.fillText(id, x-textWidth.width/2, y+textHeight/2);
}

Related

Aligning text inside rectangle of html5 canvas

I have resizable rectangle, and I wish to have right-aligned text (day numbers) next to it.
what I have now:
(also when resizing the text does not really align vertically)
what I wish to have:
Is there a way to fill the text and align it inside a drawn rectangle? Other suggestions are welcome too.
js.do code
function dayRect(day) {
const days = ["I","II","III","IV","V","VI","VII"];
context.beginPath();
//maybe align the text inside this rect somehow
context.rect(0, day*h/7, 3*w/27, h/7);
context.stroke();
context.font = "0.5rem Arial";
context.fillStyle = "#fff";
context.fillText(days[day], 0, (day+1)*h/7);
}
I've changed a few things in your code since I wasn't able to see anything. You need to use context.textAlign="right" for your text and move it to a different position. I hope it helps.
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
var canvas = document.getElementById("posHourCanvas");
var context = canvas.getContext('2d');
canvas.width=600,canvas.height=300;
var boxes = [];
function init() {
context.clearRect(0, 0, canvas.width, canvas.height);
boxes.length = 0;
const strokeWidth = 0.6;
//canvas.width = $('#two')[0].clientWidth;
var cellSize = canvas.width/27;
canvas.height = 7/27 * canvas.width;
var x = y = 0;
draw(x,y,canvas.width,canvas.height,cellSize,strokeWidth);
}
function Box(x, y, day, hour) {
this.x = x;
this.y = y;
this.day = day;
this.hour = hour;
}
function draw(x, y, w, h, cellSize, strokeWidth) {
let onePixel = cellSize * strokeWidth;
cellSize = cellSize * (1 - strokeWidth);
context.beginPath();
context.lineWidth = 1;
context.strokeStyle = 'rgba(0, 0, 0, 1)';
const rectCoordinates = {
x: x+3*w/27,
y: y,
w: w-3*w/27,
h: h
}
context.rect(rectCoordinates.x, y, rectCoordinates.w, h);
context.fillStyle = 'white';
context.fill();
context.stroke();
let offX = rectCoordinates.w/24 + rectCoordinates.x;
let offY = h/7;
for (let i = 0; i < 7; i++) {
dayRect(i);
context.beginPath();
context.moveTo(0, offY);
context.lineTo(w, offY);
context.strokeStyle = "black";
context.stroke();
offY+=h/7;
}
for (let i = 0; i < 24; i++) {
context.beginPath();
context.moveTo(offX, 0);
context.lineTo(offX, h);
context.stroke();
offX+=rectCoordinates.w/24;
}
function dayRect(day) {
const days = ["I","II","III","IV","V","VI","VII"];
context.beginPath();
context.rect(0, day*h/7, 3*w/27, h/7);
context.stroke();
context.font = "0.5rem Arial";
context.fillStyle = "#fff";
context.textAlign="right";
context.fillText(days[day], 60, (day+1)*h/7);
}
}
init();
body {
margin: auto;
color: white;
background-color: black;
min-height: 100vh;
}
<div id="parent">
<div>text above</div>
<div id="two">
<canvas id="posHourCanvas" width="600" height="300"></canvas>
</div>
<div>text under</div>
</div>

populating more type of similar objects in canvas

I have a canvas,I am using it to draw balls.However I want to populate balls from 1 to say 10 balls at random space within the canvas.Should i use 10 seperate functions(drawBall1(),drawBall2,....,drawBall10)?
OR
Are there any other methods?
var canvas = document.getElementById("myCanvas");
var ballRadius = 10;
var ctx = canvas.getContext("2d");
function draw() {
drawBall();
}
function drawBall() {
ctx.beginPath();
ctx.arc(Math.random() * canvas.width, Math.random() * canvas.height, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = "green";
ctx.fill();
}
draw();
canvas {
background: #eee;
display: block;
margin: 0 auto;
}
<canvas id="myCanvas"></canvas>
You can just call that one function ten times instead of creating ten functions which do the same thing or you could introduce a loop inside which loops 10 times for you, depedning on what suits you better.
I hope I understood your question correctly.
function drawBall(x, y, radius, color, ctx)
{
ctx.beginPath()
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
}
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
var x, y, color,
colors = ['#ffc0cb', '#008080', '#b0e0e6', '#003366', '#666666', '#faebd7'],
radius = 10,
ballCount = 10;
for (var i = 0; i < ballCount; i++)
{
x = Math.floor(Math.random() * (canvas.width + 1));
y = Math.floor(Math.random() * (canvas.height + 1));
color = colors[Math.floor(Math.random() * colors.length)];
drawBall(x, y, radius, color, ctx);
}
<canvas width="200px" height="200px" id="canvas" style="border: 1px solid black"></canvas>
You can create object that describe the ball and has functions that can draw or other behaviours
var ctx = canvas.getContext("2d");
function createBall(x,y,radius,color){
return { // return a new ball
x,y,radius,color, // set the balls properties
draw(ctx){ // add a draw function
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fill();
return this; // to allow chaining
},
}
}
const colors = "#C30A4C,#CCAB7C,#CC984B,#DE880C,#546D84,#7F858A,#697785,#375E85,#125290,#94B870";
const ballRadius = 20;
const rand = (size)=>{return Math.floor(Math.random() * size)}; // rand util
const balls = []; // an array to hold the balls
balls.push( // add some balls to the ball array
...colors
.split(",")
.map(color=>createBall(
rand(ctx.canvas.width),
rand(ctx.canvas.height),
ballRadius,
color
))
)
balls.forEach(ball=>ball.draw(ctx)); // draw them.
<canvas id="canvas" width=512 height=200></canvas>

HTML 5 Canvas, rotate everything

I made a cylinder gauge, very similar to this one:
It is drawn using about 7 or so functions... mine is a little different. It is very fleixble in that I can set the colors, transparency, height, width, whether there is % text shown and a host of other options. But now I have a need for the same thing, but all rotated 90 deg so that I can set the height long and the width low to generate something more like this:
I found ctx.rotate, but no mater where it goes all the shapes fall apart.. ctx.save/restore appears to do nothing, I tried putting that in each shape drawing function. I tried modifying, for example, the drawOval function so that it would first rotate the canvas if horizontal was set to one; but it appeared to rotate it every single iteration, even with save/restore... so the top cylinder would rotate and the bottom would rotate twice or something. Very tough to tell what is really happening. What am I doing wrong? I don't want to duplicate all this code and spend hours customizing it, just to produce something I already have but turned horizontal. Erg! Help.
Option 1
To rotate everything just apply a transform to the element itself:
canvas.style.transform = "rotate(90deg)"; // or -90 depending on need
canvas.style.webkitTransform = "rotate(90deg)";
Option 2
Rotate context before drawing anything and before using any save(). Unlike the CSS version you will first need to translate to center, then rotate, and finally translate back.
You will need to make sure width and height of canvas is swapped before this is performed.
ctx.translate(ctx.canvas.width * 0.5, ctx.canvas.height * 0.5); // center
ctx.rotate(Math.PI * 0.5); // 90°
ctx.translate(-ctx.canvas.width * 0.5, -ctx.canvas.height * 0.5);
And of course, as an option 3, you can recalculate all your values to go along the other axis.
Look at the rotate function in this example. You want to do a translation to the point you want to rotate around.
example1();
example2();
function rotate(ctx, degrees, x, y, fn) {
ctx.save();
ctx.translate(x, y);
ctx.rotate(degrees * (Math.PI / 180));
fn();
ctx.restore();
}
function rad(deg) {
return deg * (Math.PI / 180);
}
function example2() {
var can = document.getElementById("can2");
var ctx = can.getContext('2d');
var w = can.width;
var h = can.height;
function drawBattery() {
var percent = 60;
ctx.beginPath();
ctx.arc(35,50, 25,0,rad(360));
ctx.moveTo(35+percent+25,50);
ctx.arc(35+percent,50,25,0,rad(360));
ctx.stroke();
ctx.beginPath();
ctx.fillStyle = "rgba(0,255,0,.5)";
ctx.arc(35,50,25,0,rad(360));
ctx.arc(35+percent,50,25,0,rad(360));
ctx.rect(35,25,percent,50);
ctx.fill();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle = "#666666";
ctx.moveTo(135,25);
ctx.arc(135,50,25, rad(270), rad(269.9999));
//ctx.moveTo(35,75);
ctx.arc(35,50,25,rad(270),rad(90), true);
ctx.lineTo(135,75);
ctx.stroke();
}
drawBattery();
can = document.getElementById("can3");
ctx = can.getContext('2d');
w = can.width;
h = can.height;
rotate(ctx, -90, 0, h, drawBattery);
}
function example1() {
var can = document.getElementById('can');
var ctx = can.getContext('2d');
var color1 = "#FFFFFF";
var color2 = "#FFFF00";
var color3 = "rgba(0,155,255,.5)"
var text = 0;
function fillBox() {
ctx.save();
ctx.fillStyle = color3;
ctx.fillRect(0, 0, can.width / 2, can.height);
ctx.restore();
}
function drawBox() {
ctx.save();
ctx.beginPath();
ctx.strokeStyle = ctx.fillStyle = color1;
ctx.rect(10, 10, 50, 180);
ctx.font = "30px Arial";
ctx.fillText(text, 25, 45);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = color2;
ctx.lineWidth = 10;
ctx.moveTo(10, 10);
ctx.lineTo(60, 10);
ctx.stroke();
ctx.restore();
}
fillBox();
rotate(ctx, 90, can.width, 0, fillBox);
text = "A";
drawBox();
color1 = "#00FFFF";
color2 = "#FF00FF";
text = "B";
rotate(ctx, 90, can.width, 0, drawBox);
centerRotatedBox()
function centerRotatedBox() {
ctx.translate(can.width / 2, can.height / 2);
for (var i = 0; i <= 90; i += 10) {
var radians = i * (Math.PI / 180);
ctx.save();
ctx.rotate(radians);
ctx.beginPath();
ctx.strokeStyle = "#333333";
ctx.rect(0, 0, 50, 50)
ctx.stroke();
ctx.restore();
}
}
}
#can,
#can2,
#can3 {
border: 1px solid #333333
}
<canvas id="can" width="200" height="200"></canvas>
<canvas id="can2" width="200" height="100"></canvas>
<canvas id="can3" width="100" height="200"></canvas>

Trying to make 2 happy/sad faces with canvas

I'm currently trying to make 1 happy face and 1 sad face with canvas but the problem is I can't get 2 faces to appear, only one.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>My Site's Title</title>
</head>
<body>
<canvas id="myDrawing" width="800" height="200" style="border:1px solid #EEE">
</canvas>
<script>
var canvas = document.getElementById("myDrawing");
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = 0;
var endAngle = 2 * Math.PI;
function drawFace() {
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.stroke();
ctx.fillStyle = "yellow";
ctx.fill();
}
function drawSmile(){
var x = canvas.width / 2;
var y = 150
var radius = 40;
var startAngle = 1.1 * Math.PI;
var endAngle = 1.9 * Math.PI;
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.lineWidth = 7;
// line color
ctx.strokeStyle = 'black';
ctx.stroke();
}
function drawEyes(){
var centerX = 40;
var centerY = 0;
var radius = 10;
// save state
ctx.save();
// translate context so height is 1/3'rd from top of enclosing circle
ctx.translate(canvas.width / 2, canvas.height / 3);
// scale context horizontally by 50%
ctx.scale(.5, 1);
// draw circle which will be stretched into an oval
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// restore to original state
ctx.restore();
// apply styling
ctx.fillStyle = 'black';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
//left eye
var centerX = -40;
var centerY = 0;
var radius = 10;
// save state
ctx.save();
// translate context so height is 1/3'rd from top of enclosing circle
ctx.translate(canvas.width / 2, canvas.height / 3);
// scale context horizontally by 50%
ctx.scale(.5, 1);
// draw circle which will be stretched into an oval
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// restore to original state
ctx.restore();
// apply styling
ctx.fillStyle = 'black';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
}
drawFace()
function drawHappyFace(){
drawFace();
drawEyes();
drawSmile();
}
drawHappyFace();
// SECOND FACE - HAPPY FACE
<canvas id="canvas" width="200" height="200" style="border:1px solid #EEE">
</canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = 0;
var endAngle = 2 * Math.PI;
function drawFace() {
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.stroke();
ctx.fillStyle = "yellow";
ctx.fill();
}
function drawSmile(){
var x = canvas.width / 2;
var y = 150
var radius = 40;
var startAngle = 1.9 * Math.PI;
var endAngle = 1.1 * Math.PI;
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.lineWidth = 7;
// line color
ctx.strokeStyle = 'black';
ctx.stroke();
}
function drawEyes(){
var centerX = 40;
var centerY = 0;
var radius = 10;
// save state
ctx.save();
// translate context so height is 1/3'rd from top of enclosing circle
ctx.translate(canvas.width / 2, canvas.height / 3);
// scale context horizontally by 50%
ctx.scale(.5, 1);
// draw circle which will be stretched into an oval
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// restore to original state
ctx.restore();
// apply styling
ctx.fillStyle = 'black';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
//left eye
var centerX = -40;
var centerY = 0;
var radius = 10;
// save state
ctx.save();
// translate context so height is 1/3'rd from top of enclosing circle
ctx.translate(canvas.width / 2, canvas.height / 3);
// scale context horizontally by 50%
ctx.scale(.5, 1);
// draw circle which will be stretched into an oval
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// restore to original state
ctx.restore();
// apply styling
ctx.fillStyle = 'black';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
}
drawFace()
function drawHappyFace(){
drawFace();
drawEyes();
drawSmile();
}
drawHappyFace();
</script>
</body>
</html>
</body>
</html>
I cna only get one of the faces to appear at once, for some reason, but I want both at the same time!
you can't have multiple functions with the same name because the second one overrides (hides) the first one; doesn't matter if they are in the same <script> tag or not (they can even be in different files)
change the name of the functions for the second face if you are such a beginner, but you should provide arguments to the function which will let you choose between multiple canvases and shapes using single function
it can look like this:
http://jsfiddle.net/Y5rUH/2/

Adding alert to canvas faces

I'm currently trying to make so that when you click on one of the happy face you get an alert box which says "thanks for the feed back", but I'm currently not sure to to incoperate that in tho my code! Thanks! Here is the fiddle http://jsfiddle.net/bsjs9/
<html lang="en">
<head>
<meta charset="utf-8" />
<title>SmileMore</title>
</head>
<body>
<h1>
Bring your Charts to life with HTML5 Canvas</h1>
</hgroup>
<p>
Rendering Dynamic charts in JS
</p>
<div class="smile">
<canvas id="myDrawing" width="200" height="200" style="border:1px solid #EEE"></canvas>
<canvas id="canvas" width="200" height="200" style="border:1px solid #EEE"></canvas>
</div>
<script>
var FacePainter = function(canvasName)
{
var canvas = document.getElementById(canvasName);
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = 0;
var endAngle = 2 * Math.PI;
function drawFace() {
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.stroke();
ctx.fillStyle = "yellow";
ctx.fill();
}
function drawSmile(startAngle, endAngle)
{
var x = canvas.width / 2;
var y = 150;
var radius = 40;
ctx.beginPath();
ctx.arc(x, y, radius, startAngle * Math.PI, endAngle * Math.PI);
ctx.lineWidth = 7;
// line color
ctx.strokeStyle = 'black';
ctx.stroke();
}
function drawEyes() {
var centerX = 40;
var centerY = 0;
var radius = 10;
// save state
ctx.save();
// translate context so height is 1/3'rd from top of enclosing circle
ctx.translate(canvas.width / 2, canvas.height / 3);
// scale context horizontally by 50%
ctx.scale(.5, 1);
// draw circle which will be stretched into an oval
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// restore to original state
ctx.restore();
// apply styling
ctx.fillStyle = 'black';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
//left eye
var centerX = -40;
var centerY = 0;
var radius = 10;
// save state
ctx.save();
// translate context so height is 1/3'rd from top of enclosing circle
ctx.translate(canvas.width / 2, canvas.height / 3);
// scale context horizontally by 50%
ctx.scale(.5, 1);
// draw circle which will be stretched into an oval
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// restore to original state
ctx.restore();
// apply styling
ctx.fillStyle = 'black';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
}
this.drawHappyFace = function() {
drawFace();
drawEyes();
drawSmile(1.1, 1.9);
}
this.drawSadFace = function() {
drawFace();
drawEyes();
drawSmile(1.9, 1.1);
;
}
}
new FacePainter('canvas').drawHappyFace();
new FacePainter('myDrawing').drawSadFace();
</script>
</body>
</html>
</body>
</html>
As an extra assignment I would like to know if anyone knows how to fix the "happy" smile, its kinda way off! Thanks all!
Since you draw the happy face on its own canvas, you can simple put an onclick handler on the canvas.
<canvas id="myDrawing" width="200" height="200" style="border:1px solid #EEE" onclick="alert('thanks');"></canvas>
Regarding the smiles, I added a new ofsy parameter to drawSmile, which offsets the arc origin vertically.
Here is the updated fiddle.
If you only want to show the alert, when the user clicks inside the face, you need to get the click coordinates and hittest it against the circle. You can see this in this fiddle.

Categories

Resources