For some strange and sudden reason, my canvas seems to make lines thicker and darker on the right ~1/4-ish. I have tried multiple browsers and different computers and they all have the same rendering issue EXCEPT for Chrome for Android. Here is a screenshot of the test lines that I drew:
And here is the code in case anyone was wondering:
var canvas = document.getElementById("foreground");
var context = canvas.getContext("2d");
var height = 450;
var width = 600;
canvas.width = width;
canvas.height = height;
function draw() {
context.clearRect(0, 0, canvas.height, canvas.width);
for (var i = 1; i < (800 - (0 * 2)) / 35; i++) {
context.beginPath();
context.moveTo(200 + (i * 35) + 0 | 0, 50 + 0 | 0);
context.lineWidth = 1;
context.lineTo(200 + (i * 35) + 0 | 0, 50 + 800 - 0 | 0);
context.strokeStyle = "black";
context.stroke();
context.closePath();
}
for (var i = 1; i < (800 - (0 * 2)) / 35; i++) {
context.beginPath();
context.moveTo(200 + 0 | 0, 50 + (i * 35) + 0 | 0);
context.lineWidth = 0.5;
context.lineTo(200 + 800 - 0 | 0, 50 + (i * 35) + 0 | 0);
context.strokeStyle = "black";
context.stroke();
context.closePath();
}
requestAnimationFrame(draw);
}
draw();
<div id="container">
<canvas id="foreground"></canvas>
</div>
You're not clearing the canvas properly: you swapped width and height. The requestAnimationFrame then draws everything again, and since only part of the image is cleared, the part that's not, gets 'thicker'.
The fix:
context.clearRect(0, 0, canvas.width, canvas.height);
var canvas = document.getElementById("foreground");
var context = canvas.getContext("2d");
var height = 450;
var width = 600;
canvas.width = width;
canvas.height = height;
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 1; i < (800 - (0 * 2)) / 35; i++) {
context.beginPath();
context.moveTo(200 + (i * 35) + 0 | 0, 50 + 0 | 0);
context.lineWidth = 1;
context.lineTo(200 + (i * 35) + 0 | 0, 50 + 800 - 0 | 0);
context.strokeStyle = "black";
context.stroke();
context.closePath();
}
for (var i = 1; i < (800 - (0 * 2)) / 35; i++) {
context.beginPath();
context.moveTo(200 + 0 | 0, 50 + (i * 35) + 0 | 0);
context.lineWidth = 0.5;
context.lineTo(200 + 800 - 0 | 0, 50 + (i * 35) + 0 | 0);
context.strokeStyle = "black";
context.stroke();
context.closePath();
}
requestAnimationFrame(draw);
}
draw();
<div id="container">
<canvas id="foreground"></canvas>
</div>
Simply remove draw from requestAnimationFrame.
var canvas = document.getElementById("foreground");
var context = canvas.getContext("2d");
var height = 450;
var width = 600;
canvas.width = width;
canvas.height = height;
function draw() {
context.clearRect(0, 0, canvas.height, canvas.width);
for (var i = 1; i < (800 - (0 * 2)) / 35; i++) {
context.beginPath();
context.moveTo(200 + (i * 35) + 0 | 0, 50 + 0 | 0);
context.lineWidth = 1;
context.lineTo(200 + (i * 35) + 0 | 0, 50 + 800 - 0 | 0);
context.strokeStyle = "black";
context.stroke();
context.closePath();
}
for (var i = 1; i < (800 - (0 * 2)) / 35; i++) {
context.beginPath();
context.lineTo(200 + 0 | 0, 50 + (i * 35) + 0 | 0);
context.lineWidth = 0.5;
context.lineTo(200 + 800 - 0 | 0, 50 + (i * 35) + 0 | 0);
context.strokeStyle = "black";
context.stroke();
context.closePath();
}
requestAnimationFrame();
}
draw();
<div id="container">
<canvas id="foreground"></canvas>
</div>
Related
i'm working on a spinner i am stuck on how to set specific percentage to the spinner.
Here is my demo => https://jsfiddle.net/fmvucqno/
inside options variable i have 10% and 90% i want to achieve 10% fill and 90% fill on the usernames.
<input type="button" value="spin" style="float:left;" id='spin'/>
<canvas id="canvas" width="500" height="500"></canvas>
<body style="background-color: white">
<script>
var options = [
[
'#david',
'10%',
],
[
'#burn',
'90%'
]
];
var startAngle = 0;
var arc = Math.PI / (options.length / 2);
var spinTimeout = null;
var spinArcStart = 10;
var spinTime = 0;
var spinTimeTotal = 0;
var ctx;
document.getElementById("spin").addEventListener("click", spin);
function byte2Hex(n)
{
var nybHexString = "0123456789ABCDEF";
return String(nybHexString.substr((n >> 4) & 0x0F, 1)) + nybHexString.substr(n & 0x0F, 1);
}
function RGB2Color(r, g, b)
{
return '#' + byte2Hex(r) + byte2Hex(g) + byte2Hex(b);
}
function getColor(item, maxitem)
{
var phase = 0;
var center = 128;
var width = 127;
var frequency = Math.PI * 2 / maxitem;
red = Math.sin(frequency * item + 2 + phase) * width + center;
green = Math.sin(frequency * item + 0 + phase) * width + center;
blue = Math.sin(frequency * item + 4 + phase) * width + center;
return RGB2Color(red, green, blue);
}
function drawRouletteWheel()
{
var canvas = document.getElementById("canvas");
if (canvas.getContext)
{
var outsideRadius = 200;
var textRadius = 160;
var insideRadius = 125;
ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, 500, 500);
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.font = 'bold 12px Helvetica, Arial';
for (var i = 0; i < options.length; i++)
{
var angle = startAngle + i * arc;
ctx.fillStyle = getColor(i, options.length);
ctx.beginPath();
ctx.arc(250, 250, outsideRadius, angle, angle + arc, false);
ctx.arc(250, 250, insideRadius, angle + arc, angle, true);
ctx.stroke();
ctx.fill();
ctx.save();
ctx.shadowOffsetX = -1;
ctx.shadowOffsetY = -1;
ctx.shadowBlur = 0;
ctx.shadowColor = "rgb(220,220,220)";
ctx.fillStyle = "black";
ctx.translate(250 + Math.cos(angle + arc / 2) * textRadius,
250 + Math.sin(angle + arc / 2) * textRadius);
ctx.rotate(angle + arc / 2 + Math.PI / 2);
var text = options[i];
ctx.fillText(text, -ctx.measureText(text).width / 2, 0);
ctx.restore();
}
//Arrow
ctx.fillStyle = "black";
ctx.beginPath();
ctx.moveTo(250 - 4, 250 - (outsideRadius + 5));
ctx.lineTo(250 + 4, 250 - (outsideRadius + 5));
ctx.lineTo(250 + 4, 250 - (outsideRadius - 5));
ctx.lineTo(250 + 9, 250 - (outsideRadius - 5));
ctx.lineTo(250 + 0, 250 - (outsideRadius - 13));
ctx.lineTo(250 - 9, 250 - (outsideRadius - 5));
ctx.lineTo(250 - 4, 250 - (outsideRadius - 5));
ctx.lineTo(250 - 4, 250 - (outsideRadius + 5));
ctx.fill();
}
}
function spin()
{
spinAngleStart = Math.random() * 10 + 10;
spinTime = 0;
spinTimeTotal = Math.random() * 3 + 4 * 1000;
rotateWheel();
}
function rotateWheel()
{
spinTime += 30;
if (spinTime >= spinTimeTotal)
{
stopRotateWheel();
return;
}
var spinAngle = spinAngleStart - easeOut(spinTime, 0, spinAngleStart, spinTimeTotal);
startAngle += (spinAngle * Math.PI / 180);
drawRouletteWheel();
spinTimeout = setTimeout('rotateWheel()', 30);
}
function stopRotateWheel()
{
clearTimeout(spinTimeout);
var degrees = startAngle * 180 / Math.PI + 90;
var arcd = arc * 180 / Math.PI;
var index = Math.floor((360 - degrees % 360) / arcd);
ctx.save();
ctx.font = 'bold 30px Helvetica, Arial';
var text = options[index]
ctx.fillText(text, 250 - ctx.measureText(text).width / 2, 250 + 10);
ctx.restore();
}
function easeOut(t, b, c, d)
{
var ts = (t /= d) * t;
var tc = ts * t;
return b + c * (tc + -3 * ts + 3 * t);
}
drawRouletteWheel();
</script>
Although some options are set up for the different people, which include the percentage they should occupy, these are not actually used.
The arc is calculated to be equal for all users - Math.PI / (options.length / 2)
Instead we need to use the value given in the option for that user, and we have to gradually add to the start angle to know where to start the next arc.
Here's the snippet with the changes:
var options = [
[
'#david',
'10%',
],
[
'#burn',
'90%'
]
];
var startAngle = 0;
var arc = Math.PI / (options.length / 2);
var spinTimeout = null;
var spinArcStart = 10;
var spinTime = 0;
var spinTimeTotal = 0;
var ctx;
document.getElementById("spin").addEventListener("click", spin);
function byte2Hex(n)
{
var nybHexString = "0123456789ABCDEF";
return String(nybHexString.substr((n >> 4) & 0x0F, 1)) + nybHexString.substr(n & 0x0F, 1);
}
function RGB2Color(r, g, b)
{
return '#' + byte2Hex(r) + byte2Hex(g) + byte2Hex(b);
}
function getColor(item, maxitem)
{
var phase = 0;
var center = 128;
var width = 127;
var frequency = Math.PI * 2 / maxitem;
red = Math.sin(frequency * item + 2 + phase) * width + center;
green = Math.sin(frequency * item + 0 + phase) * width + center;
blue = Math.sin(frequency * item + 4 + phase) * width + center;
return RGB2Color(red, green, blue);
}
function drawRouletteWheel()
{
var canvas = document.getElementById("canvas");
if (canvas.getContext)
{
var outsideRadius = 200;
var textRadius = 160;
var insideRadius = 125;
ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, 500, 500);
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.font = 'bold 12px Helvetica, Arial';
var angle = startAngle;
for (var i = 0; i < options.length; i++)
{ arc = Math.PI * Number(options[i][1].replace('%','')) / 50;
ctx.fillStyle = getColor(i, options.length);
ctx.beginPath();
ctx.arc(250, 250, outsideRadius, angle, angle + arc, false);
ctx.arc(250, 250, insideRadius, angle + arc, angle, true);
ctx.stroke();
ctx.fill();
ctx.save();
ctx.shadowOffsetX = -1;
ctx.shadowOffsetY = -1;
ctx.shadowBlur = 0;
ctx.shadowColor = "rgb(220,220,220)";
ctx.fillStyle = "black";
ctx.translate(250 + Math.cos(angle + arc / 2) * textRadius,
250 + Math.sin(angle + arc / 2) * textRadius);
ctx.rotate(angle + arc / 2 + Math.PI / 2);
var text = options[i];
ctx.fillText(text, -ctx.measureText(text).width / 2, 0);
ctx.restore();
angle += (i+1) * arc;
}
//Arrow
ctx.fillStyle = "black";
ctx.beginPath();
ctx.moveTo(250 - 4, 250 - (outsideRadius + 5));
ctx.lineTo(250 + 4, 250 - (outsideRadius + 5));
ctx.lineTo(250 + 4, 250 - (outsideRadius - 5));
ctx.lineTo(250 + 9, 250 - (outsideRadius - 5));
ctx.lineTo(250 + 0, 250 - (outsideRadius - 13));
ctx.lineTo(250 - 9, 250 - (outsideRadius - 5));
ctx.lineTo(250 - 4, 250 - (outsideRadius - 5));
ctx.lineTo(250 - 4, 250 - (outsideRadius + 5));
ctx.fill();
}
}
function spin()
{
spinAngleStart = Math.random() * 10 + 10;
spinTime = 0;
spinTimeTotal = Math.random() * 3 + 4 * 1000;
rotateWheel();
}
function rotateWheel()
{
spinTime += 30;
if (spinTime >= spinTimeTotal)
{
stopRotateWheel();
return;
}
var spinAngle = spinAngleStart - easeOut(spinTime, 0, spinAngleStart, spinTimeTotal);
startAngle += (spinAngle * Math.PI / 180);
drawRouletteWheel();
spinTimeout = setTimeout('rotateWheel()', 30);
}
function stopRotateWheel()
{
clearTimeout(spinTimeout);
var degrees = startAngle * 180 / Math.PI + 90;
var arcd = arc * 180 / Math.PI;
var index = Math.floor((360 - degrees % 360) / arcd);
ctx.save();
ctx.font = 'bold 30px Helvetica, Arial';
var text = options[index]
ctx.fillText(text, 250 - ctx.measureText(text).width / 2, 250 + 10);
ctx.restore();
}
function easeOut(t, b, c, d)
{
var ts = (t /= d) * t;
var tc = ts * t;
return b + c * (tc + -3 * ts + 3 * t);
}
drawRouletteWheel();
<input type="button" value="spin" style="float:left;" id='spin'/>
<canvas id="canvas" width="500" height="500"></canvas>
I try to draw the three dots then connect only two of them by line.
My attempts looks like this.
Why I get wrong circles in x0, x1, x2 coordinates?
for (let x = 0; x < width; x += offsetX) {
ctx.arc(x0, y0, 1, 0, 2 * Math.PI, false);
ctx.arc(x1, y1, 1, 0, 2 * Math.PI, false);
ctx.arc(x2, y2, 1, 0, 2 * Math.PI, false);
ctx.fill();
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x2, y2);
ctx.moveTo(x2, y2);
ctx.lineTo(x1, y1);
ctx.stroke();
x0 += offsetX;
x1 += offsetX;
x2 += offsetX;
}
You should have each circle in own path:
ctx.beginPath();
ctx.arc(x0, y0, 4, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.arc(x1, y1, 4, 0, 2 * Math.PI);
ctx.fill();
Here is a simplified version of your code:
let canvas = document.createElement("canvas");
canvas.width = canvas.height = 200;
ctx = canvas.getContext("2d");
ctx.translate(5, 5);
let triangleWidth = 20;
let offset = 50;
let y0 = 1;
let y1 = triangleWidth;
let y2 = triangleWidth / 2;
function draw() {
for (let y = 0; y < canvas.height; y++) {
x0 = triangleWidth;
x1 = triangleWidth;
x2 = 0;
for (let x = 0; x < canvas.width; x += offset) {
ctx.beginPath();
ctx.arc(x0, y0, 4, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.arc(x1, y1, 4, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.arc(x2, y2, 4, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x2, y2);
ctx.moveTo(x2, y2);
ctx.lineTo(x1, y1);
ctx.stroke();
x0 += offset;
x1 += offset;
x2 += offset;
}
y0 += offset;
y1 += offset;
y2 += offset;
}
}
draw();
document.body.appendChild(canvas);
I am working on the canvas showing levels according to users below is my code the issue is after clip the image on the first level the next drawing and animations stops working.
The canvas holds a json array which is used to draw the levels Class levels
holds the method to deay static shapes and functions starting with animate uses animation frames to animate line or circles.
HTML:
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
</head>
<body>
<canvas id="levelchart" data-levels="[{"text":"Mark","dotcolor":"#28912e","linecolor":"#28912e","current":"0","completed":"1","image":"http:\/\/nessgoods.com\/timthumb.php?src=http:\/\/www.nessgoods.com\/upload\/users\/3\/pills_311869.jpg&q=100"},{"text":5,"dotcolor":"#28912e","linecolor":"#28912e","current":"0","pending":"0","completed":"1"},{"text":25,"dotcolor":"#28912e","linecolor":"#28912e","current":"0","pending":"0","completed":"1"},{"text":125,"dotcolor":"#28912e","linecolor":"#28912e","current":"0","pending":"0","completed":"1"},{"text":625,"dotcolor":"#28912e","linecolor":"#28912e","current":"0","pending":"0","completed":"1"},{"text":3125,"dotcolor":"#28912e","linecolor":"#28912e","current":"0","pending":"0","completed":"1"},{"text":15625,"dotcolor":"#3498db","linecolor":"#3498db","current":"1","completed":"1","pending":"3125"},{"text":78125,"dotcolor":"#3498db","linecolor":"#3498db","current":0,"pending":"0","completed":0},{"text":390625,"dotcolor":"#3498db","linecolor":"#3498db","current":0,"pending":"0","completed":0}]" width="1360" height="380"></canvas>
</body>
JS:
<script
src="https://code.jquery.com/jquery-2.2.4.min.js"
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
crossorigin="anonymous"></script>
<script type="text/javascript">
class levels{
constructor(){
var x = 0;
var y = 0;
var height = 0;
var width = 0;
var canvas = 0;
var fill = 0;
var start = 0;
var end = 0;
var lineWidth = 0;
var color = 0;
var gradient = 0;
var lineCap = "square";
var to = 0;
var data = 0;
var counter = 0;
var circleanimate = 0;
var percent=0;
var completed = 0;
var imagee = "";
}
config(){
}
line(){
// console.log(this.end);
this.canvas.beginPath();
this.canvas.moveTo(this.start, this.y);
this.canvas.lineTo(this.end, this.y);
this.canvas.lineWidth = this.lineWidth;
this.canvas.strokeStyle = this.color;
this.canvas.lineCap = this.lineCap
this.canvas.stroke();
};
circle(){
this.canvas.beginPath();
this.canvas.moveTo(this.end, this.y);
this.canvas.arc(this.end, this.y, this.radius, 0, 2 * Math.PI);
this.canvas.fillStyle = this.color;
this.canvas.fill();
this.canvas.closePath();
}
baloon(){
var bheight = (10 - lv.counter + lv.counter * 8 / 100 * canvas.height);
var totheight = canvas.height - (60 + bheight);
var height = totheight + 80 / 100 * bheight;
this.canvas.beginPath();
//console.log("check "+bheight+" "+totheight+" "+height);
var last = (lv.end-30) + (15 / 100 * bheight);
var y = lv.y-50;
this.canvas.moveTo(last + (12 / 100 * bheight), height - (13 / 100 * bheight));
this.canvas.bezierCurveTo(last - (16 / 100 * bheight), y, last - (16 / 100 * bheight), y, last - (16 / 100 * bheight), y);
this.canvas.bezierCurveTo(last - (36 / 100 * bheight), height, last - (36 / 100 * bheight), height, last - (36 / 100 * bheight), height);
this.canvas.arc(last - (18 / 100 * bheight), totheight + (38 / 100 * bheight), (last + (14 / 100 * bheight)) - (last - (28 / 100 * bheight)), 0.75 * Math.PI, 0.25 * Math.PI);
this.canvas.strokeStyle = lv.color;
this.canvas.lineWidth=3;
this.canvas.stroke();
// count++;
console.log(lv.imagee+" as");
if (this.imagee != "") {
var img = new Image();
img.src = this.imagee;
var newcanvas = this.canvas;
img.onload = function (e)
{
newcanvas.beginPath();
newcanvas.moveTo(last - (18 / 100 * bheight), totheight + (38 / 100 * bheight));
newcanvas.arc(last - (18 / 100 * bheight), totheight + (38 / 100 * bheight), (last + (14 / 100 * bheight)) - (last - (28 / 100 * bheight)) - 1, 0, 2 * Math.PI);
newcanvas.strokeStyle = "#fff";
newcanvas.stroke();
newcanvas.clip();
newcanvas.drawImage(img,last - (18 / 100 * bheight)-(1.5/100*canvas.width),totheight + (38 / 100 * bheight)-(1.5/100*canvas.width));
lv.canvas.beginPath();
// lv.image="";
}
}
}
}
function animateCircle() {
if(lv.circleanimate<2.1){
requestAnimationFrame(animateCircle);
lv.canvas.beginPath();
lv.canvas.moveTo(lv.end, lv.y);
lv.canvas.arc(lv.end, lv.y, lv.radius, (lv.circleanimate-0.1) * Math.PI, lv.circleanimate * Math.PI);
lv.canvas.fillStyle = lv.color;
lv.strokeStyle = "none";
lv.canvas.fill();
lv.canvas.closePath();
lv.circleanimate=lv.circleanimate+0.1;
}else{
lv.circleanimate=0;
if (lv.end == 0) {
lv.start = 0;
lv.end = 0;
lv.to = 30;
lv.color = lv.data[0].linecolor;
lv.style = "normal";
if(lv.data[0].hasOwnProperty("image")){
lv.imagee = lv.data[0].image;
}
} else {
lv.style = "bold";
lv.start = lv.end + 10;
var index = lv.counter-1;
if(lv.counter>=8){
index = 8;
}
console.log(index+" c ");
lv.imagee = "";
if(lv.data[index].hasOwnProperty("image")){
var w = 3/100*canvas.width;
lv.imagee = lv.data[index].image+"&w="+w+"&h="+w;
}
lv.color = lv.data[index].linecolor;
lv.percent = (Number(lv.data[index].pending) / Number(lv.data[index].text) * 100);
lv.completed = lv.data[index].completed;
lv.end = lv.start;
var p = (lv.counter * 2)+2;
lv.to = lv.to + ((p / 100) * workarea);
}
animateElipse();
animateLineFill();
}
}
function animateElipse(){
if(lv.circleanimate<2.1){
requestAnimationFrame(animateElipse);
var bheight = (10 - lv.counter + lv.counter * 8 / 100 * canvas.height);
var totheight = canvas.height - (60 + bheight);
var height = totheight + 80 / 100 * bheight;
var last = lv.end-25;
var y = lv.y-48;
lv.canvas.beginPath();
lv.canvas.moveTo(last, y);
lv.canvas.ellipse(last, y, 8, 2, 0,0, lv.circleanimate * Math.PI);
lv.canvas.fillStyle = "#e4e5e7";
lv.canvas.fill();
lv.circleanimate=lv.circleanimate+0.1;
}else{
lv.baloon();
}
}
function animateLineFill(){
if(lv.end<lv.to){
requestAnimationFrame(animateLineFill);
}else if(lv.counter<lv.count){
lv.circleanimate=0;
if (lv.end == 0) {
lv.start = 0;
lv.end = 0;
lv.to = 30;
lv.color = lv.data[0].linecolor;
lv.style = "normal";
} else {
lv.style = "bold";
lv.start = lv.end + 8;
var index = lv.counter;
if(lv.counter>=8){
index = 8;
}
lv.imagee = "";
if(lv.data[index].hasOwnProperty("image")){
var w = 3/100*canvas.width;
lv.imagee = lv.data[index].image+"&w="+w+"&h="+w;
}
lv.color = lv.data[index].linecolor;
lv.end = lv.start;
// var p = (lv.counter+1.9 * 5);
// lv.to = lv.to + ((p / 100) * workarea);
}
animateCircle();
lv.counter++;
}
lv.line();
lv.end++;
}
var lv = new levels();
var canvas = document.querySelector("canvas#levelchart");
/*canvas.width = (98 / 100) * $("div.team_link").width();
canvas.height = (28 / 100) * canvas.width;*/
canvas.width = (98 / 100) * $(window).width();
canvas.height = (28 / 100) * canvas.width;
var c = canvas.getContext('2d');
var workarea = (canvas.width);
var points = workarea / 10;
var start = canvas.width - 10;
var last = 0;
var y = canvas.height - 10;
var cheight = canvas.height;
var data = document.getElementById("levelchart").getAttribute("data-levels");
data = JSON.parse(data);
var i = 0;
var style = "normal";
lv.start = start;
lv.end = last;
lv.canvas = c;
lv.color="#000000";
lv.y = y;
lv.start = 50;
lv.end = workarea-50;
lv.lineWidth = 4;
lv.color = "#eee";
lv.lineCap = "round";
lv.line();
lv.end = 0;
lv.radius = 5;
lv.count = data.length;
lv.data = data;
lv.counter = 0;
if (lv.end == 0) {
lv.start = 0;
lv.end = 0;
lv.to = 30;
lv.color = lv.data[0].linecolor;
lv.style = "normal";
}
animateLineFill();
</script>
In image.load function we have to call .save() on canvas and after clip() we have call the .restore() function as defined in below code.
img.onload = function (e)
{
newcanvas.save();
newcanvas.beginPath();
newcanvas.moveTo(last - (18 / 100 * bheight), totheight + (38 / 100 * bheight));
newcanvas.arc(last - (18 / 100 * bheight), totheight + (38 / 100 * bheight), (last + (14 / 100 * bheight)) - (last - (28 / 100 * bheight)) - 1, 0, 2 * Math.PI);
newcanvas.strokeStyle = "#fff";
newcanvas.stroke();
newcanvas.clip();
newcanvas.drawImage(img,last - (18 / 100 * bheight)-(1.5/100*canvas.width),totheight + (38 / 100 * bheight)-(1.5/100*canvas.width));
newcanvas.restore();
// lv.image="";
}
Sometimes the y-coordinates is greater than height of imagedata. can anybody help me to find my mistake!
Width is 320 px, height is 240px.
Here is my code:
function countPixels(context) {
var nAlive = 0,
all = [];
var w = canvas.width;
var p = context.getImageData(0, 0, canvas.width, canvas.height).data;
for (var y = 0, i = 0; y < canvas.height; y++)
for (var x = 0; x < canvas.width; x++, i += 4) {
if (p[i] == 255 || p[i + 1] == 255 || p[i + 2] == 255) //Not black
{
nAlive++;
var xc = i % w;
var yc = parseInt(i / w, 10);
var pos = {};
pos.x = xc;
pos.y = yc;
all.push(pos);
}
}
var percent = ((canvas.width * canvas.height) / 100) * nAlive;
console.log("Count: " + nAlive + ",percent: " + percent + ",all: " + JSON.stringify(all));
// $("#notifies").append("Count: "+nAlive+",percent: "+ percent+",all: "+JSON.stringify(all));
return {
percentage: parseFloat(percent),
positions: all
};
}
Here is the function call:
var tmp = countPixels(ctx2);
ctx2.strokeStyle = "blue";
$.each(tmp.positions, function(i, value) {
// if (ctx2.isPointInPath(value.x, value.y))
$('div').eq(0).append("i: " + i + " " + value.x + ", " + +value.y + '</br>');
ctx2.rect(value.x, value.y, 5, 5);
});
ctx2.stroke();
I have spheres bouncing off each other and the canvas walls, however im struggling on the speed. How would I control the speed? so maybe connected to the beginpath function? so they kind of explode and then bounce everywhere
<script type="text/javascript">
$(function () {
var canvas = $("#target");
var context = canvas.get(0).getContext("2d");
var canvasWidth = canvas.width();
var canvasHeight = canvas.height();
$(window).resize(resizeCanvas);
function resizeCanvas() {
canvas.attr("width", $(window).get(0).innerWidth);
canvas.attr("height", $(window).get(0).innerHeight);
canvasWidth = canvas.width();
canvasHeight = canvas.height();
};
var Sphere = function (x, y, radius, mass, vX, vY) {
this.x = x;
this.y = y;
this.radius = radius;
this.mass = mass;
this.vX = vX;
this.vY = vY;
this.updatePosition = function () {
this.x += this.vX;
this.y += this.vY;
};
this.checkBoundaryCollision = function () {
if (this.x - this.radius < 0) {
this.x = this.radius;
this.vX *= -1;
} else if (this.x + this.radius > canvasWidth) {
this.x = canvasWidth - this.radius;
this.vX *= -1;
}
if (this.y - this.radius < 0) {
this.y = this.radius;
this.vY *= -1;
} else if (this.y + this.radius > canvasHeight) {
this.y = canvasHeight - this.radius;
this.vY *= -1;
}
}
}
resizeCanvas();
var spheresLength = 20;
var spheres = new Array();
function loadContent() {
for (var i = 0; i < spheresLength; i++) {
var x = 20 + (Math.random() * (canvasWidth - 40));
var y = 20 + (Math.random() * (canvasHeight - 40));
var radius = 5 + Math.random() * 10;
var mass = radius / 2;
var vX = Math.random() * 4 - 2;
var vY = Math.random() * 4 - 2;
spheres.push(new Sphere(x, y, radius, mass, vX, vY));
};
animate();
}
loadContent();
function animate() {
update();
draw();
setTimeout(animate, 33);
}
function update() {
for (var i = 0; i < spheresLength; i++) {
var sphere1 = spheres[i];
for (var j = i + 1; j < spheresLength; j++) {
var sphere2 = spheres[j];
var dX = sphere2.x - sphere1.x;
var dY = sphere2.y - sphere1.y;
var distance = Math.sqrt((dX * dX) + (dY * dY));
if (distance < sphere1.radius + sphere2.radius) {
var angle = Math.atan2(dY, dX);
var sine = Math.sin(angle);
var cosine = Math.cos(angle);
var x = 0;
var y = 0;
var xB = dX * cosine + dY * sine;
var yB = dY * cosine - dX * sine;
var vX = sphere1.vX * cosine + sphere1.vY * sine;
var vY = sphere1.vY * cosine - sphere1.vX * sine;
var vXb = sphere2.vX * cosine + sphere2.vY * sine;
var vYb = sphere2.vY * cosine - sphere2.vX * sine;
var vTotal = vX - vXb;
vX = (
(sphere1.mass - sphere2.mass) * vX + 2 * sphere2.mass * vXb
)
/ (sphere1.mass + sphere2.mass);
vXb = vTotal + vX;
xB = x + (sphere1.radius + sphere2.radius);
sphere1.x = sphere1.x + (x * cosine - y * sine);
sphere1.y = sphere1.y + (y * cosine + x * sine);
sphere2.x = sphere1.x + (xB * cosine - yB * sine);
sphere2.y = sphere1.y + (yB * cosine + xB * sine);
sphere1.vX = vX * cosine - vY * sine;
sphere1.vY = vY * cosine + vX * sine;
sphere2.vX = vXb * cosine - vYb * sine;
sphere2.vY = vYb * cosine + vXb * sine;
}
}
sphere1.updatePosition();
sphere1.checkBoundaryCollision();
}
}
function draw() {
context.clearRect(0, 0, canvasWidth, canvasHeight);
context.fillStyle = "rgb(255, 255, 255)";
for (var i = 0; i < spheresLength; i++) {
var sphere = spheres[i];
context.beginPath();
context.arc(sphere.x, sphere.y, sphere.radius, 0, Math.PI * 2);
context.closePath();
context.fill();
}
}
});
</script>
The "speed" of the balls is a function of the distance they travel per frame. This code runs about 3 frames per second, and it looks like the distance is a function of the "mass." You can increase the speed by increasing the factor that determines the distance traveled in each frame (in the update() function.)
Incidentally, I wasn't able to get this code to work. In future, try prototyping on jsFiddle.net or Codepen.io.
UPDATE:
Here's the line that controls the velocity of the balls:
vX = ((sphere1.mass - sphere2.mass) * vX + 2 * sphere2.mass * vXb)
/ (sphere1.mass + sphere2.mass);
That value, 2, is the overall velocity modifier. Small increases to that value correlate to large increases in velocity. Kick it up to 2.25 and watch them fly.