Progress bar view without rotating around does not work - javascript

The following code is generating a circle bar by using canvas. Everything works fine.
But when I tried to change the code so that the percent circle and value view
dont rotate/circulate around until they reach the real position/value I run into
problems. The graph should only view the percentage position within the circle
and the value in the mittle of the circle without rotating/couting up to the real end value.
I know I have to change/delete some things in the JS arcMove() function like
deegres += 1 which is responsible for the rotation steps and so on, but if I tried it didnt work like it should.
window.onload = function() {
var can = document.getElementById('canvas'),
spanProcent = document.getElementById('procent'),
c = can.getContext('2d');
var posX = can.width / 2,
posY = can.height / 2,
fps = 1000 / 200,
procent = 0,
oneProcent = 360 / 100,
result = oneProcent * 64;
c.lineCap = 'round';
arcMove();
function arcMove(){
var deegres = 0;
var acrInterval = setInterval (function() {
deegres += 1;
c.clearRect( 0, 0, can.width, can.height );
procent = deegres / oneProcent;
spanProcent.innerHTML = procent.toFixed();
c.beginPath();
c.arc( posX, posY, 70, (Math.PI/180) * 270, (Math.PI/180) * (270 + 360) );
c.strokeStyle = '#b1b1b1';
c.lineWidth = '10';
c.stroke();
c.beginPath();
c.strokeStyle = '#3949AB';
c.lineWidth = '10';
c.arc( posX, posY, 70, (Math.PI/180) * 270, (Math.PI/180) * (270 + deegres) );
c.stroke();
if( deegres >= result ) clearInterval(acrInterval);
}, fps);
}
}
:root {
background: #fff;
}
span#procent {
display: block;
position: absolute;
left: 50%;
top: 50%;
font-size: 50px;
transform: translate(-50%, -50%);
color: #3949AB;
}
span#procent::after {
content: '%';
}
.canvas-wrap {
position: relative;
width: 300px;
height: 300px;
}
<div class="canvas-wrap">
<canvas id="canvas" width="300" height="300"></canvas>
<span id="procent"></span>
</div>

In the arcMove function you have to set degree to result so the interval is done on first call. But if you do not want an animation than you should use a pure css way of displaying it. Checkout the following answer: https://stackoverflow.com/a/41147560/8820118
window.onload = function() {
var can = document.getElementById('canvas'),
spanProcent = document.getElementById('procent'),
c = can.getContext('2d');
var posX = can.width / 2,
posY = can.height / 2,
fps = 1000 / 200,
procent = 0,
oneProcent = 360 / 100,
result = oneProcent * 64;
c.lineCap = 'round';
arcMove();
function arcMove(){
var deegres = result; // change degrees to result, than you won't have the animation.
var acrInterval = setInterval (function() {
deegres += 1;
c.clearRect( 0, 0, can.width, can.height );
procent = deegres / oneProcent;
spanProcent.innerHTML = procent.toFixed();
c.beginPath();
c.arc( posX, posY, 70, (Math.PI/180) * 270, (Math.PI/180) * (270 + 360) );
c.strokeStyle = '#b1b1b1';
c.lineWidth = '10';
c.stroke();
c.beginPath();
c.strokeStyle = '#3949AB';
c.lineWidth = '10';
c.arc( posX, posY, 70, (Math.PI/180) * 270, (Math.PI/180) * (270 + deegres) );
c.stroke();
if( deegres >= result ) clearInterval(acrInterval);
}, fps);
}
}
:root {
background: #fff;
}
span#procent {
display: block;
position: absolute;
left: 50%;
top: 50%;
font-size: 50px;
transform: translate(-50%, -50%);
color: #3949AB;
}
span#procent::after {
content: '%';
}
.canvas-wrap {
position: relative;
width: 300px;
height: 300px;
}
<div class="canvas-wrap">
<canvas id="canvas" width="300" height="300"></canvas>
<span id="procent"></span>
</div>

Related

js canvas object movement animation using pythagorean theorem

I am trying to make an object move to click position, like in rpgs like diablo or modern moba games, i needed to find a way to animate to click coordinates and i have found a method that uses pythagorean theorem, i understood and custimized the code to a certain degree, but there is a bug where the ball keeps bouncing in the very end of animation. I know this happens because of the "moves" variable and the loop, but can't understand exactly why.
here's the function that draws the object
function drawPlayer() {
//
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(player.x, player.y, 12, 0, Math.PI*2);
ctx.fillStyle = 'white';
ctx.fill();
ctx.closePath();
//Calculate variables
let dx = player.newx - player.x;
let dy = player.newy - player.y;
let distance = Math.sqrt(dx*dx + dy*dy);
let moves = distance/player.speed;
let xunits = (player.newx - player.x)/moves;
let yunits = (player.newy - player.y)/moves;
if (moves > 0 ) {
moves--;
player.x += xunits;
player.y += yunits;
console.log(moves);
}
}
const canvas = document.getElementById('canvas1');
const ctx = canvas.getContext('2d');
canvas.addEventListener('click', e => {
setClickCoords(e);
drawPlayer();
})
canvas.width = 300;
canvas.height = 300;
const player = {
x: 0,
y: 0,
newx: 0,
newy: 0,
speed: 1,
radius: 15,
}
function drawPlayer() {
//Draw
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(player.x, player.y, 12, 0, Math.PI * 2);
ctx.fillStyle = 'white';
ctx.fill();
ctx.closePath();
//Calculate variables
let dx = player.newx - player.x;
let dy = player.newy - player.y;
let distance = Math.sqrt(dx * dx + dy * dy);
let moves = distance / player.speed;
let xunits = (player.newx - player.x) / moves;
let yunits = (player.newy - player.y) / moves;
console.log(moves);
if (moves > 0) {
moves--;
player.x += xunits;
player.y += yunits;
console.log(moves);
}
}
function setClickCoords(e) {
player.newx = e.offsetX;
player.newy = e.offsetY;
document.getElementById('oldcoords').innerHTML = "old Coords " + player.x + " " + player.y;
document.getElementById('newcoords').innerHTML = "new Coords " + player.newx + " " + player.newy;
}
function gameLoop() {
window.setTimeout(gameLoop, 24);
drawPlayer()
}
gameLoop();
body {
background: black;
display: flex;
flex-direction: column;
}
#canvas1 {
border: 3px solid white;
top: 50%;
left: 50%;
position: absolute;
width: 300px;
height: 300px;
transform: translate(-50%, -50%);
}
#oldcoords,
#newcoords {
color: white;
font-size: 18px;
}
<span id="oldcoords"></span>
<span id="newcoords"></span>
<canvas id="canvas1"> </canvas>
Check if moves is between 0 and 1. If it's between, move the ball to the desired position. Currently, the ball goes too far in the direction and has to return in the next animation.
const canvas = document.getElementById('canvas1');
const ctx = canvas.getContext('2d');
canvas.addEventListener('click', e => {
setClickCoords(e);
drawPlayer();
})
canvas.width = 300;
canvas.height = 300;
const player = {
x: 0,
y: 0,
newx: 0,
newy: 0,
speed: 1,
radius: 15,
}
function drawPlayer() {
//Draw
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(player.x, player.y, 12, 0, Math.PI * 2);
ctx.fillStyle = 'white';
ctx.fill();
ctx.closePath();
//Calculate variables
let dx = player.newx - player.x;
let dy = player.newy - player.y;
let distance = Math.sqrt(dx * dx + dy * dy);
let moves = distance / player.speed;
console.log(moves);
if (moves > 1) {
let xunits = (player.newx - player.x) / moves;
let yunits = (player.newy - player.y) / moves;
moves--;
player.x += xunits;
player.y += yunits;
console.log(moves);
} else if (moves > 0) {
moves = 0;
player.x = player.newx;
player.y = player.newy;
console.log(moves);
}
}
function setClickCoords(e) {
player.newx = e.offsetX;
player.newy = e.offsetY;
document.getElementById('oldcoords').innerHTML = "old Coords " + player.x + " " + player.y;
document.getElementById('newcoords').innerHTML = "new Coords " + player.newx + " " + player.newy;
}
function gameLoop() {
window.setTimeout(gameLoop, 24);
drawPlayer()
}
gameLoop();
body {
background: black;
display: flex;
flex-direction: column;
}
#canvas1 {
border: 3px solid white;
top: 50%;
left: 50%;
position: absolute;
width: 300px;
height: 300px;
transform: translate(-50%, -50%);
}
#oldcoords,
#newcoords {
color: white;
font-size: 18px;
}
<span id="oldcoords"></span>
<span id="newcoords"></span>
<canvas id="canvas1"> </canvas>

clickable object or shape inside a canvas viewbox window

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<style>
body {
font-family: "Lato", sans-serif;
}
.sidenav {
height: 100%;
width: 0;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: #111;
overflow-x: hidden;
transition: 0.5s;
padding-top: 60px;
}
.sidenav a {
padding: 8px 8px 8px 32px;
text-decoration: none;
font-size: 25px;
color: #818181;
display: block;
transition: 0.3s;
}
.sidenav a:hover {
color: #f1f1f1;
}
.sidenav .closebtn {
position: absolute;
top: 0;
right: 25px;
font-size: 36px;
margin-left: 50px;
}
#main {
transition: margin-left .5s;
padding: 16px;
}
#media screen and (max-height: 450px) {
.sidenav {padding-top: 15px;}
.sidenav a {font-size: 18px;}
}
</style>
</head>
<body>
<div id="mySidenav" class="sidenav">
×
About
Services
Clients
Contact
</div>
<div id="main">
<span style="font-size:30px;cursor:pointer" onclick="openNav()">☰ Menu</span>
<canvas id="canvas" width="600" height="350" style="border:2px solid #d3d3d3;">></canvas>
</div>
<script>
var zoomIntensity = 0.1;
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var width = 90;
var height = 50;
var scale = 1;
var originx = 0;
var originy = 0;
var visibleWidth = width;
var visibleHeight = height;
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
function draw(){
context.fillStyle = "white";
context.fillRect(originx,originy,1000/scale,800/scale);
context.fillStyle = "blue";
context.fillRect(170,50,50,50);
context.fillStyle = "white";
context.fillText('click here',175,70);
}
setInterval(draw, 1000/60);
canvas.onwheel = function (event){
event.preventDefault();
var mousex = event.clientX - canvas.offsetLeft;
var mousey = event.clientY - canvas.offsetTop;
var wheel = event.deltaY < 0 ? 1 : -1;
var zoom = Math.exp(wheel*zoomIntensity);
context.translate(originx, originy);
originx -= mousex/(scale*zoom) - mousex/scale;
originy -= mousey/(scale*zoom) - mousey/scale;
context.scale(zoom, zoom);
context.translate(-originx, -originy);
scale *= zoom;
visibleWidth = width / scale;
visibleHeight = height / scale;
}
function openNav() {
document.getElementById("mySidenav").style.width = "200px";
document.getElementById("main").style.marginLeft = "200px";
}
function closeNav() {
document.getElementById("mySidenav").style.width = "0";
document.getElementById("main").style.marginLeft= "0";
}
</script>
</body>
</html>
is there away to make a shape or object clickable on canvas frame or viewbox, even when i zoom in or out, cause all the examples i saw was just a fixed clickable location. for instance google map locations when i zoom in i can click more objects.
is there away to make a shape or object clickable on canvas frame or viewbox, even when i zoom in or out, cause all the examples i saw was just a fixed clickable location. for instance google map locations when i zoom in i can click more objects.
There are two spaces you have to account for, the actual canvas space and the translated space. This means you need to translate the mouse coordinates in order to know where in the space the object is actually located and map it back to the canvas coordinates so you can know if you are clicking on it. This is achieved by keeping track of the offset value you provided in the var originx, but the problem is that there is no way based on my trails at least for you to translate the mouse click location if you use the context.translate(originx, originy) if you both scale and pan the object space.
I have rewritten the code without the use of the translate function by making my own translate function that enables you to translate between the canvas space and object space in order to register a click event on the object regardless of the panned or zoomed in location.
This function also has a click to pan feature so you can click and drag the object screen to where ever you want to object to be positioned.
/*jshint esversion: 8 */
(function() {
const canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");
let canvasWidth = 600;
let canvasHeight = 600;
let offset = {
x: 0,
y: 0
};
let pan = {
x: 0,
y: 0
};
var zoomIntensity = 0.1;
let scale = 1;
let mouse = {
x: 0,
y: 0
};
let dragging = false;
let square;
let shapes = [{
x: 170,
y: 50,
w: 50,
h: 50,
color: "blue"
},
{
x: 85,
y: 25,
w: 50,
h: 50,
color: "red"
},
{
x: 50,
y: 100,
w: 50,
h: 50,
color: "green"
},
];
function init() {
canvas.width = canvasWidth;
canvas.height = canvasHeight;
renderCanvas();
}
function drawSquare(x, y, width, height, color) {
context.fillStyle = color;
context.fillRect(x, y, width, height);
}
function objectsToCanvasScreen(x, y) {
const canvasScreenX = Math.floor((x - offset.x) * scale);
const canvasScreenY = Math.floor((y - offset.y) * scale);
return {
x: canvasScreenX,
y: canvasScreenY
};
}
function canvasToObjectsScreen(x, y) {
return {
x: x / scale + offset.x,
y: y / scale + offset.y
};
}
function renderCanvas() {
context.clearRect(0, 0, canvas.width, canvas.height);
shapes.forEach(({
x,
y,
w,
h,
color
}, index) => {
const {
x: csx,
y: csy
} = objectsToCanvasScreen(x, y);
shapes[index]._x = csx;
shapes[index]._y = csy;
shapes[index]._w = w * scale;
shapes[index]._h = h * scale;
drawSquare(csx, csy, w * scale, h * scale, color);
});
}
canvas.onwheel = function(e) {
const zoom = Math.exp((e.deltaY < 0 ? 1 : -1) * zoomIntensity);
const beforeZoom = canvasToObjectsScreen(mouse.x, mouse.y);
scale *= zoom;
const afterZoom = canvasToObjectsScreen(mouse.x, mouse.y);
offset.x += beforeZoom.x - afterZoom.x;
offset.y += beforeZoom.y - afterZoom.y;
renderCanvas();
};
canvas.onmousedown = function(e) {
if (e.button === 0) {
pan.x = mouse.x;
pan.y = mouse.y;
dragging = true;
}
};
canvas.onmouseup = (e) => (dragging = false);
canvas.onmousemove = function(e) {
mouse.x = e.offsetX;
mouse.y = e.offsetY;
if (dragging) {
offset.x -= (mouse.x - pan.x) / scale;
offset.y -= (mouse.y - pan.y) / scale;
pan.x = mouse.x;
pan.y = mouse.y;
renderCanvas();
}
};
canvas.onclick = function(e) {
shapes.forEach(({
_x,
_y,
_w,
_h,
color
}) => {
const {
x: mousex,
y: mousey
} = canvasToObjectsScreen(mouse.x, mouse.y);
const {
x: squarex,
y: squarey
} = canvasToObjectsScreen(_x, _y);
if (
mousex >= squarex &&
mousex <= _w / scale + squarex &&
mousey >= squarey &&
mousey <= _h / scale + squarey
) {
alert(`${color} clicked!`);
}
});
};
init();
})();
body {
font-family: "Lato", sans-serif;
}
#canvas {
background: #E1BC8B;
}
<body>
<div id="main">
<canvas id="canvas" width="300" height="350"></canvas>
</div>
</body>

Aim triangle point towards center of circle while moving

I want the triangle to aim towards the center at all time while it is spinning as it is right now
var element = document.getElementById('background');
var ctx = element.getContext("2d");
var camera = {};
camera.x = 0;
camera.y = 0;
var scale = 1.0;
var obj = [];
var t = {};
t.angle = Math.random() * Math.PI * 2; //start angle
t.radius = 200;
t.x = Math.cos(t.angle) * t.radius; // start position x
t.y = Math.sin(t.angle) * t.radius; //start position y
t.duration = 10000; //10 seconds per rotation
t.rotSpeed = 2 * Math.PI / t.duration; // Rotational speed (in radian/ms)
t.start = Date.now();
obj.push(t);
function update() {
for (var i = 0; i < obj.length; i++) {
var delta = Date.now() - obj[i].start;
obj.start = Date.now();
var angle = obj[i].rotSpeed * delta;
// The angle is now already in radian, no longer need to convert from degree to radian.
obj[i].x = obj[i].radius * Math.cos(angle);
obj[i].y = obj[i].radius * Math.sin(angle);
}
}
function draw() {
update();
ctx.clearRect(0, 0, element.width, element.height);
ctx.save();
ctx.translate(0 - (camera.x - element.width / 2), 0 - (camera.y - element.height / 2));
ctx.scale(scale, scale);
ctx.fillStyle = 'blue';
for (var i = 0; i < obj.length; i++) {
/*Style circle*/
ctx.beginPath();
ctx.arc(0, 0, obj[i].radius, 0, Math.PI * 2);
ctx.lineWidth = 60;
ctx.strokeStyle = "black";
ctx.stroke();
//Dot style
ctx.beginPath();
ctx.arc(obj[i].x,obj[i].y,10,0,Math.PI*2);
ctx.moveTo(0 + obj[i].x, 0 + obj[i].y);
ctx.lineTo(75 + obj[i].x, 25 + obj[i].y);
ctx.lineTo(75 + obj[i].x, -25 + + obj[i].y);
ctx.lineWidth = 1.5;
ctx.strokeStyle = "red";
ctx.stroke();
ctx.fillStyle = "red";
ctx.fill();
}
ctx.restore();
requestAnimationFrame(draw);
}
draw();
<canvas id="background" width="500" height="500"></canvas>
Here is a quick fiddle that has all the code already in it just for convenience :)
https://jsfiddle.net/4xwmo5tj/5/
I have already made it spin (the dot is there for now but will be removed later so that can be ignored) the only thing that I still need to do is aim it towards the center at all time. I think I have to use css transform translate for it. but I don't know how to
Use CSS animations.
.outer-circle {
height: 200px;
width: 200px;
background-color: black;
padding: 25px;
position: relative;
border-radius: 50%;
-webkit-animation:spin 4s linear infinite;
-moz-animation:spin 4s linear infinite;
animation:spin 4s linear infinite;
}
.inner-cricle {
width: 150px;
height: 150px;
background: white;
margin: auto;
margin-top: 25px;
border-radius: 50%;
}
.triangle {
width: 0;
height: 0;
border-left: 20px solid transparent;
border-right: 20px solid transparent;
border-top: 20px solid #f00;
position: absolute;
left: 40%;
top: 6%;
}
#-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
#-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
#keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
<div class="outer-circle">
<div class="triangle"></div><div class="inner-cricle"></div>
</div>
The triangle is not spinning at all. There is just a red dot circle in circumference and triangle inside black circle which is still. So what do you want to do?
The block of the code responsible for the triangle is under // Dot Style. The lines ctx.lineTo plot two dots at (x,y) coordinates. I fiddle around with the two coordinates until the triangle was facing down. Below is the end result:
var element = document.getElementById('background');
var ctx = element.getContext("2d");
var camera = {};
camera.x = 0;
camera.y = 0;
var scale = 1.0;
var obj = [];
var t = {};
t.angle = Math.random() * Math.PI * 2; //start angle
t.radius = 200;
t.x = Math.cos(t.angle) * t.radius; // start position x
t.y = Math.sin(t.angle) * t.radius; //start position y
t.duration = 10000; //10 seconds per rotation
t.rotSpeed = 2 * Math.PI / t.duration; // Rotational speed (in radian/ms)
t.start = Date.now();
obj.push(t);
function update() {
for (var i = 0; i < obj.length; i++) {
var delta = Date.now() - obj[i].start;
obj.start = Date.now();
var angle = obj[i].rotSpeed * delta;
// The angle is now already in radian, no longer need to convert from degree to radian.
obj[i].x = obj[i].radius * Math.cos(angle);
obj[i].y = obj[i].radius * Math.sin(angle);
}
}
function draw() {
update();
ctx.clearRect(0, 0, element.width, element.height);
ctx.save();
ctx.translate(0 - (camera.x - element.width / 2), 0 - (camera.y - element.height / 2));
ctx.scale(scale, scale);
ctx.fillStyle = 'blue';
for (var i = 0; i < obj.length; i++) {
/*Style circle*/
ctx.beginPath();
ctx.arc(0, 0, obj[i].radius, 0, Math.PI * 2);
ctx.lineWidth = 60;
ctx.strokeStyle = "white";
ctx.stroke();
//Dot style
ctx.beginPath();
ctx.arc(obj[i].x, obj[i].y, 10, 0, Math.PI * 2);
ctx.moveTo(0 + obj[i].x, 0 + obj[i].y);
ctx.lineTo(25 + obj[i].x, -75 + obj[i].y);
ctx.lineTo(-25 + obj[i].x, -75 + obj[i].y);
ctx.lineWidth = 1.5;
ctx.strokeStyle = "red";
ctx.stroke();
ctx.fillStyle = "red";
ctx.fill();
}
ctx.restore();
requestAnimationFrame(draw);
}
draw();
#background {
background: #000000;
border: 1px solid black;
}
<canvas id="background" width="500" height="500"></canvas>
Sorry, I can't provide any more specific details. The Cavas API and drawing are not my turfs.

How to create more than one circular progress bar?

I find this code for progress bar circle, But this code just creates one progress bar circle.
I need to create more one progress bar.
This code:
http://jsfiddle.net/Aapn8/3410/
<div class="chart" id="graph" data-percent="88"></div>
JS
var el = document.getElementById('graph'); // get canvas
var options = {
percent: el.getAttribute('data-percent') || 25,
size: el.getAttribute('data-size') || 220,
lineWidth: el.getAttribute('data-line') || 15,
rotate: el.getAttribute('data-rotate') || 0
}
var canvas = document.createElement('canvas');
var span = document.createElement('span');
span.textContent = options.percent + '%';
if (typeof(G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
el.appendChild(span);
el.appendChild(canvas);
ctx.translate(options.size / 2, options.size / 2); // change center
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); // rotate -90 deg
//imd = ctx.getImageData(0, 0, 240, 240);
var radius = (options.size - options.lineWidth) / 2;
var drawCircle = function(color, lineWidth, percent) {
percent = Math.min(Math.max(0, percent || 1), 1);
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, false);
ctx.strokeStyle = color;
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = lineWidth
ctx.stroke();
};
drawCircle('#efefef', options.lineWidth, 100 / 100);
drawCircle('#555555', options.lineWidth, options.percent / 100);
Thank you.
You have already done the hard-work. wrap your code in a function which accepts a DOM element and create circle based on it.
var elems = document.querySelectorAll('.chart'); // get canvas
elems.forEach(function(el) {
createCircle(el);
})
function createCircle(el) {
//Logic to create circle
}
var elems = document.querySelectorAll('.chart'); // get canvas
elems.forEach(function(el) {
createCircle(el);
})
function createCircle(el) {
var options = {
percent: el.getAttribute('data-percent') || 25,
size: el.getAttribute('data-size') || 220,
lineWidth: el.getAttribute('data-line') || 15,
rotate: el.getAttribute('data-rotate') || 0
}
var canvas = document.createElement('canvas');
var span = document.createElement('span');
span.textContent = options.percent + '%';
if (typeof(G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
el.appendChild(span);
el.appendChild(canvas);
ctx.translate(options.size / 2, options.size / 2); // change center
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); // rotate -90 deg
//imd = ctx.getImageData(0, 0, 240, 240);
var radius = (options.size - options.lineWidth) / 2;
var drawCircle = function(color, lineWidth, percent) {
percent = Math.min(Math.max(0, percent || 1), 1);
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, false);
ctx.strokeStyle = color;
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = lineWidth
ctx.stroke();
};
drawCircle('#efefef', options.lineWidth, 100 / 100);
drawCircle('#555555', options.lineWidth, options.percent / 100);
}
div {
position: relative;
margin: 80px;
width: 220px;
height: 220px;
}
canvas {
display: block;
position: absolute;
top: 0;
left: 0;
}
span {
color: #555;
display: block;
line-height: 220px;
text-align: center;
width: 220px;
font-family: sans-serif;
font-size: 40px;
font-weight: 100;
margin-left: 5px;
}
input {
width: 200px;
}
span {}
<div class="chart" data-percent="88"></div>
<div class="chart" data-percent="32"></div>
Update Fiddle

How to use the same JS for same HTML multiple times

I used this from another stackoverflow question: http://jsfiddle.net/Aapn8/3410/ to create circle progress bars.
Except when I'm trying to create more then 1, nothing happens how can you clean fix this without copying the JavaScript and change just 1 var.
This is my code:
.circleWrapper {
width: 250px;
float: left;
}
.circleText {} .circleTextSmall {} #graph div {
position: relative;
margin: 80px;
width: 220px;
height: 220px;
}
#graph canvas {
display: block;
top: 0;
left: 0;
}
#graph span {
color: #555;
display: block;
line-height: 220px;
text-align: center;
width: 220px;
font-family: sans-serif;
font-size: 40px;
font-weight: 100;
margin-left: 5px;
}
#graph input {
width: 200px;
}
<div class="circleWrapper">
<div class="chart" id="graph" data-percent="50"></div>
<div class="circleText">HTML/CSS</div>
<div class="circleTextSmall">Small text</div>
</div>
<div class="circleWrapper">
<div class="chart" id="graph" data-percent="45"></div>
<div class="circleText">PHP</div>
<div class="circleTextSmall">Small text</div>
</div>
var els = document.getElementsByClassName("chart");
for(var i=0; i < els.length; i++){
var el = els[i];
var options = {
percent: el.getAttribute('data-percent') || 25,
size: el.getAttribute('data-size') || 220,
lineWidth: el.getAttribute('data-line') || 15,
rotate: el.getAttribute('data-rotate') || 0
}
var canvas = document.createElement('canvas');
var span = document.createElement('span');
span.textContent = options.percent + '%';
if (typeof(G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
el.appendChild(span);
el.appendChild(canvas);
ctx.translate(options.size / 2, options.size / 2); // change center
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); // rotate -90 deg
//imd = ctx.getImageData(0, 0, 240, 240);
var radius = (options.size - options.lineWidth) / 2;
var drawCircle = function(color, lineWidth, percent) {
percent = Math.min(Math.max(0, percent || 1), 1);
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, false);
ctx.strokeStyle = color;
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = lineWidth
ctx.stroke();
};
drawCircle('#efefef', options.lineWidth, 100 / 100);
drawCircle('#555555', options.lineWidth, options.percent / 100);
}
div {
position:relative;
margin:80px;
width:220px; height:220px;
}
canvas {
display: block;
position:absolute;
top:0;
left:0;
}
span {
color:#555;
display:block;
line-height:220px;
text-align:center;
width:220px;
font-family:sans-serif;
font-size:40px;
font-weight:100;
margin-left:5px;
}
input {
width: 200px;
}
span {
}
<div class="chart" data-percent="88"></div>
<div class="chart" data-percent="78"></div>
Use functions
Put your code inside a function which accepts some way of identifying a particular element, then call that function multiple times. Here's a fork of that fiddle as a working example:
function startGraph(el) { // turn it into a function which accepts an element
// (Nothing else has changed)
var options = {
percent: el.getAttribute('data-percent') || 25,
size: el.getAttribute('data-size') || 220,
lineWidth: el.getAttribute('data-line') || 15,
rotate: el.getAttribute('data-rotate') || 0
}
var canvas = document.createElement('canvas');
var span = document.createElement('span');
span.textContent = options.percent + '%';
if (typeof(G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
el.appendChild(span);
el.appendChild(canvas);
ctx.translate(options.size / 2, options.size / 2); // change center
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); // rotate -90 deg
//imd = ctx.getImageData(0, 0, 240, 240);
var radius = (options.size - options.lineWidth) / 2;
var drawCircle = function(color, lineWidth, percent) {
percent = Math.min(Math.max(0, percent || 1), 1);
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, false);
ctx.strokeStyle = color;
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = lineWidth
ctx.stroke();
};
drawCircle('#efefef', options.lineWidth, 100 / 100);
drawCircle('#555555', options.lineWidth, options.percent / 100);
}
Assuming each element has class="chart" then you can get all the elements and call the function with each one:
// Get all charts:
var myCharts=document.getElementsByClassName("chart");
// For each one..
for (var i in myCharts) {
// Start it:
startGraph(myCharts[i]);
}
You have used the graph ID twice.
You can only use an ID once per document.
The id attribute specifies a unique id for an HTML element (the value must be unique within the HTML document).
More information on this can be found here.
Change the ID to something else and change the JS to interact with both elements.
This can for example be done with getElementsByClassName(). This function returns an array of elements instead of a single element.
I think it is best if you wrap all your functionality in a function with the following signature:
function startGraph(el) {
...
}
and then call the function from this for-loop:
var elements = document.getElementsByClassName("chart");
var i;
for (i = 0; i < x.length; i++) {
startGraph(elements[i]);
}
More information on that can be found here.
All you need to do is to define unique ids in your HTML, and define an array of all your graph elements and loop through the logic, see this as an example:
var elements = [{
'id': 'graph1'
}, {
'id': 'graph2'
}];
for (var i = 0; i < elements.length; i++) {
var el = document.getElementById(elements[i]['id']);
var options = {
percent: el.getAttribute('data-percent') || 25,
size: el.getAttribute('data-size') || 220,
lineWidth: el.getAttribute('data-line') || 15,
rotate: el.getAttribute('data-rotate') || 0
}
var canvas = document.createElement('canvas');
var span = document.createElement('span');
span.textContent = options.percent + '%';
if (typeof(G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
el.appendChild(span);
el.appendChild(canvas);
ctx.translate(options.size / 2, options.size / 2); // change center
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); // rotate -90 deg
//imd = ctx.getImageData(0, 0, 240, 240);
var radius = (options.size - options.lineWidth) / 2;
var drawCircle = function(color, lineWidth, percent) {
percent = Math.min(Math.max(0, percent || 1), 1);
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, false);
ctx.strokeStyle = color;
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = lineWidth
ctx.stroke();
};
drawCircle('#efefef', options.lineWidth, 100 / 100);
drawCircle('#555555', options.lineWidth, options.percent / 100);
}
div {
position: relative;
margin: 80px;
width: 220px;
height: 220px;
}
canvas {
display: block;
position: absolute;
top: 0;
left: 0;
}
span {
color: #555;
display: block;
line-height: 220px;
text-align: center;
width: 220px;
font-family: sans-serif;
font-size: 40px;
font-weight: 100;
margin-left: 5px;
}
input {
width: 200px;
}
span {}
<div class="chart" id="graph1" data-percent="88"></div>
<div class="chart" id="graph2" data-percent="25"></div>

Categories