I try to create a countdown clock using canvas and useEffect. It work fine until I test it in iPhone's browser (all device >= iPhone 8). When my clock running on iPhone 8, sometimes it has issue look like in picture.
This issue don't happend in other device (android, laptop, iphone <= 6)
Please help me!
[![`
useEffect(() => {
console.log('percent canvas = ', percent);
// var canvas = document.getElementById("clockCanvas");
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, width, width);
ctx.lineWidth = strokeWidth;
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, 2 * Math.PI);
ctx.fillStyle = backgroundClock;
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, 2 * Math.PI);
ctx.strokeStyle = colorStroke;
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.arc(cx, cy, radius, -0.5 * Math.PI + (2 * (percent / 100) * Math.PI), - 0.5 * Math.PI, true);
ctx.strokeStyle = strokeColor;
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = textStrokeWidth;
ctx.strokeStyle = textStrokeColor;
ctx.font = `${textSize}px Roboto`;
ctx.textAlign = "center";
ctx.textBaseline = 'middle';
ctx.strokeText(text, width / 2, width / 2, width - 2 * strokeWidth);
ctx.closePath();
},
[
cx,
cy,
radius,
width,
percent,
strokeColor,
strokeWidth,
text,
textSize,
textStrokeColor,
textStrokeWidth
]);
return (
<canvas id="clockCanvas" width={width} height={width} ref={canvasRef}>
</canvas>
);
};
export default Clock;
`]2]2
Hey there Do Anh Bon!
I know this question is 8 months old, so I'm assuming that you found a solution, but in case you did not...
I am working on a web development project and encountered a similar error. I spent quite some time doing research on the topic and I believed that I had tried nearly everything (changing image rendering settings in CSS, messing with device pixel ratio in various ways, etc.). None of the suggestions even came close to fixing the problem. Some of them actually made the code more verbose and the resulting image less appealing on top of that.
What I finally found to be the solution was to simply use the close path function INSTEAD of drawing the last iteration (meaning the last line) of my drawing. What this does is simply connect the line to the starting position.
function drawShape(x, y, radius, inset, n) {
ctx.fillStyle = "hsl(" + hue + ",100%,50%)";
ctx.beginPath();
ctx.save();
ctx.translate(x, y)
ctx.moveTo(0, -radius);
for (let i = 0; i < n; i++) {
ctx.rotate(Math.PI / n);
ctx.lineTo(0, -radius * inset);
ctx.rotate(Math.PI / n);
if (i === n - 1) {
break;
} else {
ctx.lineTo(0, -radius);
}
}
ctx.restore();
ctx.closePath();
ctx.stroke();
ctx.fill();
}
Keep in mind that since you are attempting to draw a curved line, this solution may not work for you (I have not tried it out with your code).
If this solution does not work, then another thing you might want to try to to omit the use of close path and see what results you get then.
I really hope this helps!
-Keith
Before
After
Related
What I want to do is
1) I want to draw a length on image and want to add handle to edit it.
2) When I want to zoom the image the drawn length should match the zoom level.
ctx.beginPath();
ctx.moveTo(linearr[i].x1, linearr[i].y1);
ctx.lineTo(linearr[i].x2, linearr[i].y2);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.arc(linearr[i].x1, linearr[i].y1, 2, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = 'green';
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.arc(linearr[i].x2, linearr[i].y2, 2, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = 'green';
ctx.fill();
ctx.stroke();
where linearr is an array
Papaya already supports a ruler tool, if that's what you're looking for.
Otherwise, see the function papaya.viewer.Viewer.prototype.drawRuler() for an example of how to use the screen transform to draw lines, which includes the zoom transform. Another function that might be helpful to you is this.selectedSlice.findProximalRulerHandle().
Inspiring myself from this answer, I want to make several progress circle in my page (about 30). It works perfectly for one but I don't get the circle for the values. I however get the percentage displayed correctly.
I've tried various thing, adding [count] to most of the options but still the circle is not drawn for each cell.
I added my code in this Fiddle.
Can you see what's wrong?
Your drawCircle function needs a bit more information (ctx and radius)
var drawCircle = function(ctx, radius, 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();
};
and you need to pass it that info when using it:
drawCircle(ctx[count], radius[count], '#efefef', options[count].lineWidth, 100 / 100);
drawCircle(ctx[count], radius[count], color[count], options[count].lineWidth, options[count].percent / 100);
like here: https://fiddle.jshell.net/6ooL53pp/3/
I’ve got drawings of planets that revolve around the sun. They rotate fine, but they need to be positioned accurately. They move at the same speed so it doesn’t look realistic.
I would like to know how to make some planets swing a lot faster than others but they’re all in the same animation function and trying to make several animation functions just causes errors.
Here's my relevant code:
function rotate_point(pointX, pointY, originX, originY, ang) {
ang = Math.PI / 180.0;
return {
x: Math.cos(ang) * (pointX-originX) - Math.sin(ang) * (pointY-originY) + originX ,
y: Math.sin(ang) * (pointX-originX) + Math.cos(ang) * (pointY-originY) + originY
};
}
, Venus: {
render: function(){
ctx.beginPath();
gravityVenus = rotate_point(gravityVenus.x, gravityVenus.y, dynamicSunX, dynamicSunY, angleOfSun); //the positions are dynamic based on what the canvas height and width are
ctx.arc(gravityVenus.x,gravityVenus.y ,7, 0, 2*Math.PI);
ctx.fillStyle = "rgba(255,165,0,1)";
ctx.closePath();
ctx.fill();
}
}
, Mercury: {
render: function(){
ctx.beginPath();
gravityMercury = rotate_point(gravityMercury.x, gravityMercury.y, dynamicSunX, dynamicSunY - 2, angleOfSun);
ctx.arc(gravityMercury.x,gravityMercury.y ,5, 0, 2*Math.PI);
ctx.fillStyle = "rgba(119,136,153,1)";
ctx.closePath();
ctx.fill();
ctx.stroke();
}
function animate(){
background.render();
Solarsystem.Neptune.render();
Solarsystem.Uranus.render();
Solarsystem.Saturn.render();
Solarsystem.Jupiter.render();
Solarsystem.Mars.render();
Solarsystem.Earth.render();
Solarsystem.Venus.render();
Solarsystem.Mercury.render();
Solarsystem.Sun.render();
}
var animateInterval = setInterval(animate, 1000/60); //this sets the speed for everything in the Solarsystem array.
I’ve found a snippet from somewhere that might help you but didn’t help me adjust , I tried to play with it but I couldn’t get it working. Here it is.
var time = new Date();
ctx.arc( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() );
enter code here
Could someone help me out? Thanks!
I have this animation, but i cant get over the logic. I hope someone can help me here.
Basicly i need this: http://jsfiddle.net/PDE85/9/ but without the arrow doing such crazy moves. It should be attached to the front of the open circle to simulate an expanding arrow.
I got the triangle to turn right here but it doesnt work when i mix it with position logic as seen in the first example.
Here is the code for reference
(function() {
var size = ($(window).height()/5)*4;
$("#intro-container").css('width',size);
$("#intro-canvas").css('width',size);
$("#intro-canvas").css('height',size);
var interval = window.setInterval(draw, 30);
var degrees = 0.0;
var offset = 20;
var rotate = 0;
var canvas = document.getElementById('intro-canvas');
var ctx = canvas.getContext('2d');
canvas.width = size;
canvas.height = size;
draw();
function draw() {
if (canvas.getContext) {
ctx.fillStyle="white";
ctx.strokeStyle="white";
ctx.clearRect(0, 0, size, size);
ctx.save();
ctx.translate(size/2, size/2);
ctx.rotate(-90 * Math.PI / 180);
ctx.beginPath();
ctx.lineWidth = size/8;
ctx.arc(0, 0, size/3, 0, rotate * Math.PI / 180);
//ctx.shadowBlur=1;
//ctx.shadowColor="black";
ctx.stroke();
ctx.restore();
ctx.beginPath();
ctx.save();
// moving logic
ctx.translate(size/2, size/2);
ctx.rotate(-Math.PI / 180 * -rotate+1);
ctx.translate(-size/3, -size/3);
// rotating logic
ctx.translate(size/2, size/2);
ctx.rotate((rotate * Math.PI + 420) / 180);
ctx.moveTo(0,0);
ctx.lineTo(size/6,0);
ctx.lineTo(0,size/6);
ctx.lineTo(0,0);
ctx.fill();
ctx.restore();
rotate += 1;
if(rotate > 360){
window.clearInterval(interval)
}
}
}
})();
I believe you are looking for this : http://jsfiddle.net/PDE85/12/
The rotation comes from, the rotate call which is unnecessary.
Plus you need an inverted triangle, hence the coordinates needed an update:
...
// ctx.rotate((rotate * Math.PI + 420) / 180);
ctx.moveTo(0,0);
ctx.lineTo(-size/6,0);
ctx.lineTo(0,-size/6);
...
I have just started using canvas to get this kind of effect:
"James Bond Gunbarrel View Start"
http://www.youtube.com/watch?v=sfXazFp68cE
I managed to get almost there:
http://jsbin.com/uyaker/8/edit
Now as you can see I clip my canvas with two circles (At least I try to) ... but the problem is the region that overlaps is not clipped anymore ...
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(canvas.width, 0);
ctx.lineTo(canvas.width, canvas.height);
ctx.lineTo(0, canvas.height);
ctx.closePath();
ctx.moveTo(cx + r, cy);
ctx.arc(cx, cy, r, 0, Math.PI*2, true);
// check if to draw a fixed circle, every 200 pixels for 100 pixels
if(goingright && cx % 200 < 100) {
ctx.moveTo(cx - cx % 200 + r, cy);
ctx.arc(cx - cx % 200, cy, r, 0, Math.PI*2, true);
}
ctx.closePath();
ctx.clip();
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
Maybe this effect is possible without using clipping but give the canvas a css background-image and draw everything but the circles ... but I don't really know how to do that :/.
Maybe this effect is possible without using clipping ... but I don't really know how to do that
Yes it is possible, you need to create a path that will do all the work:
context.beginPath();
context.moveTo(x, y);
// Draw your big shape, in your case is a rectangle (4 point)
context.lineTo(xn, yn);
context.closePath();
// Now the context knows that every path that will be added without .beginPath(), will clip the current path
context.arc(cx, cy, r, 0, Math.PI * 2, true);
context.closePath();
context.fill(); // Fill with color all the area except the arc
Example: http://jsfiddle.net/drhWb/
Saving, restoring and clipping the context are very expensive operations so you should use this approach is the right way you need to go.