how to manage zoom and length handle in papaya - javascript

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().

Related

ReactJS: HTML5 Canvas render error in iOS device (>= iPhone 8)

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

Overlapping clipping issue

I have an issue where I am grabbing a users displayAvatar() and then I use an arc to make the image round. This works fine, however, I need to place a circle on top of that image, but it is getting cut in half because of the previous clip()
Without clip() : https://i.gyazo.com/b474c656f33a1f004f5e3becffcef527.png
With clip() : https://i.gyazo.com/da13377cd3f6dc7516c2b8fd1f0f8ac9.png
I know that in the 'With clip()' image, it appears as if the arc border is showing outside of the clip, but that is hardcoded into the image, I put it as a guide with an image editor.
I tried moving around the code, I removed the line ctx.clip() and saw that my circle displays fine on top of the image.
// circle around avatar
ctx.beginPath();
ctx.arc(122.5, 141.8, 81, 0, Math.PI * 2, true);
ctx.closePath();
ctx.clip();
const avatar = await Canvas.loadImage(
message.author.displayAvatarURL({ format: 'png' })
);
ctx.strokeStyle = '#ffffff';
ctx.strokeRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(avatar, 41.5, 60.5, 162, 162);
// presence circle
ctx.beginPath();
ctx.arc(184.5, 193.5, 19, 0, Math.PI * 2, true);
ctx.strokeStyle = '#000000';
ctx.lineWidth = 8;
ctx.stroke();
ctx.fillStyle = userStatusColor;
ctx.fill();
Take a look at the canvas clip() definition:
https://www.w3schools.com/tags/canvas_clip.asp
Tip: Once a region is clipped, all future drawing will be limited to the clipped region (no access to other regions on the canvas). You can however save the current canvas region using the save() method before using the clip() method, and restore it (with the restore() method) any time in the future.
Below is an example using the save and restore
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(90, 90, 81, 0, Math.PI * 2, true);
ctx.stroke();
ctx.save();
ctx.clip();
ctx.beginPath();
ctx.arc(150, 50, 19, 0, Math.PI * 2, true);
ctx.fillStyle = '#0000ff';
ctx.lineWidth = 8;
ctx.stroke();
ctx.fill();
ctx.restore();
ctx.beginPath();
ctx.arc(170, 99, 19, 0, Math.PI * 2, true);
ctx.fillStyle = '#ff0000';
ctx.lineWidth = 8;
ctx.stroke();
ctx.fill();
<canvas id="canvas"></canvas>

Canvas shadow properties affect all subsequent paths

Canvas shadow properties seem to affect all paths that follow it, even when closing the path that contains those properties. I tried changing the order of things. Ok, placing a path that doesnt require a shadow before the one that does works, but that isnt very reliable work-around. Is there any way to fix this?
Here a simple Jsfiddle demonstrating the problem: http://jsfiddle.net/zrt61283/1/
var c=document.getElementById("canvas");
var ctx=c.getContext("2d");
// Left
ctx.beginPath();
ctx.arc(100, 75, 20, 0, 2 * Math.PI);
ctx.shadowColor = 'blue';
ctx.shadowBlur = 30;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.stroke();
ctx.fill();
ctx.closePath();
// Right
ctx.beginPath();
ctx.arc(200, 75, 20, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
ctx.closePath();
you can reset the shadowBlur property with ctx.shadowBlur = 0; or ctx.shadowBlur = null;
for more info take a look at specs shadowBlur (canvas2dAPI).
here's an alternative way using save() and restore();
fiddle
As others have said doing a reset will work - also you can do .save() which will save the canvas state, you will need to restore as well...
var c=document.getElementById("canvas");
var ctx=c.getContext("2d");
// Left
ctx.save();
ctx.beginPath();
ctx.arc(100, 75, 20, 0, 2 * Math.PI);
ctx.shadowColor = 'blue';
ctx.shadowBlur = 30;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.stroke();
ctx.fill();
ctx.closePath();
ctx.restore();
// Right
ctx.save();
ctx.beginPath();
ctx.arc(200, 75, 20, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
ctx.closePath();
ctx.restore();
This will basically save the state of the canvas and allow you to take actions within it, then add new things to the canvas and keep them as different pieces.
here is a quick fiddle of this being used - https://jsfiddle.net/e0qm94dn/

How can we take advantage of moveTo( ) HTML5 method?

please I am a little confused so I need your help .
My question is how can we take advantage of moveTo() html5 method ?
for example I found this example on stackOverflow
function drawSmile(ctx, x, y, faceRadius, eyeRadius) {
ctx.save(); // save
ctx.fillStyle = '#FF6'; // face style : fill color is yellow
ctx.translate(x, y); // now (x,y) is the (0,0) of the canvas.
ctx.beginPath(); // path for the face
ctx.arc(0, 0, faceRadius, 0, 6.28);
ctx.fill();
ctx.fillStyle = '#000'; // eye style : fill color is black
ctx.beginPath(); // path for the two eyes
ctx.arc(faceRadius / 2, - faceRadius /3, eyeRadius, 0, 6.28);
ctx.moveTo(-faceRadius / 2, - faceRadius / 3); // sub path for second eye
ctx.arc(-faceRadius / 2, - faceRadius / 3, eyeRadius, 0, 6.28);
ctx.fill();
ctx.restore(); // context is just like before entering drawSmile now.
}
drawSmile(c, 200,200, 60, 12);
but when I removed the line number 11 in the code which uses the moveTo method no thing changed!!!!.
The moveTo() HTML5 method lets you to move your (0,0) origin to another point in the space.
Here you have and example. To draw some kind of triangle:
// first part of the path
ctx.moveTo(20,20);
ctx.lineTo(100, 100);
ctx.lineTo(100,0);
// second part of the path
ctx.moveTo(120,20);
ctx.lineTo(200, 100);
ctx.lineTo(200,0);
// indicate stroke color + draw the path
ctx.strokeStyle = "#0000FF";
ctx.stroke();
In this example we simply called moveTo(x, y) after drawing the first part of the path (the shape on the left). Then, we only called stroke() once to draw the whole path.

html5 canvas - merge two clipping regions - James Bond Gunbarrel

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.

Categories