I think an older version of canvas had a canvas.PenPos property that let you see where the current pen location is. I'm mostly going to use this for debugging purposes and to draw relatively (e.g. a line 50px long to the right of the current position). Is there any way to do this currently? If not, why did they remove it...?
The pen position I'm referring to is the virtual "pen" that a drawing context (that you would get for example by calling var ctx = canvas.getContext('2d')) uses, rather than a physical pen or mouse.
I am not trying to draw with a mouse. Again, this is not a physical pen I'm looking for, it's the virtual pen that is moved with ctx.moveTo(x,y)
According to w3.org, there isn't a method that returns the pen position.
Because the .getContext("2d") method returns an object, you can store the pen position as properties and call them as needed:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
//Start position
ctx.x = 100;
ctx.y = 100;
ctx.moveTo(ctx.x, ctx.y);
ctx.x = ctx.x + 100;
ctx.y = ctx.y + 300;
ctx.lineTo(ctx.x, ctx.y);
ctx.stroke();
When creating an arc though, you would need to calculate the pen's new position afterward.
Related
I've drawn a simple half circle shape using a closed arc, the arc is created using a start point (x,y), end point (x,y) and a through point (x,y)
var from = new Point(20, 20);
var through = new Point(60, 20);
var to = new Point(80, 80);
var path = new Path.Arc(from, through, to);
path.closed = true;
its width and length are NOT the same, when i rotate it at any degree, its dimensions start morphing.. why is that happening and how can i fix it?
note that this only happens when i set the length and width of the shape to be different using the path.size property.
path.size = [calcWidth, calcHeight];
the problem is as you see in the images below.
What are you trying to do when setting the path.size property (which is not documented http://paperjs.org/reference/path/) ?
I guess that you should instead use the path.scale() function.
solved..i was using both size property and scale function on my shape. what was causing the problem is i would rotate the shape and THEN call the scale function.
instead i set the size, then scale the shape and after that call the rotate function. this will allow the shape to maintain its dimensions without any changes
I'm new to HTML5 Canvas and Javascript. I'm currently working on a HTML5 Canvas project (I wrote a separate question about it here and here).
The logic of the game is pretty simple: track the mouse position and if the mouse position exits the blue region, the game resets. The user starts on level 1 (function firstLevel). If their mouse position enters the red box region, they advance onto the next level (return secondLevel()). I did this previously by a hefty list of if statements that compared the mouse's x and y coordinates.
I've corrected the code to create a global constructor function I can reference in each of the level functions:
function Path(array, color) {
let path = new Path2D();
path.moveTo(array[0][0], array[0][1]);
for (i = 1; i < array.length; i++) {
path.lineTo(array[i][0], array[i][1]);
}
path.lineTo(array[0][0], array[0][1]);
return path;
}
And its referenced in the level functions as such:
// In the individual levels, put code that describes the shapes locally
var big = [[350,200], [900,200], [900,250], [700,250], [600,250], [600,650], [350,650]];
var blue = Path(big);
var small = [[900,200], [900,250], [850,250], [850, 200], [900, 200]];
var red = Path(small);
// 2. create cursor
c.beginPath();
c.rect(mouseX, mouseY, mouseWidth, mouseHeight);
c.fillStyle = "#928C6F";
c.fill();
// Local code that draws shapes:
c.beginPath()
c.fillStyle = '#C1EEFF';
c.fill(blue);
c.beginPath()
c.fillStyle = "#FF4000";
c.fill(red);
I want to know how can I check for the mouse position so it can run those conditional statements using the isPointInPath method? I now have a reference (refs. blue and red) for the Canvas shape, so I'm hoping there's a way I can check if the mouse's x and y position is a point that is inside the shape/path.
Link to my project: https://github.uconn.edu/pages/ssw19002/dmd-3475/final-project/maze-page-1.html
Source code: https://github.uconn.edu/ssw19002/dmd-3475/tree/master/final-project
You could use the MouseEvent.offsetX and MouseEvent.offsetY properties of a mouse event such as mousemove. (You would need to add an event listener for mouse events to the canvas element of course.)
Then use the x and y offset values obtained to call isPointInPath like
ctx.isPointInPath(path, x, y)
where path is a return value from function Path.
While MDN lists the offset properties as "experimental" they seem to have been around since IE9 at least.
I am making a document that will build a tree type graph through user input. I am trying to connect styled divs to the relative div they branched from with canvas lines.
I have been using .getBoundingClientRect() to get the positions, but the divs are static with inline-block, so every time a new one is added, the whole structure changes.
So, here is my attempt at a 'for loop' that is called every time a new branch is made, to re-draw all of the canvas lines.
var lines = function(){
var blocks=document.getElementsByClassName('block');
for (i=1;i<blocks.length-1;i++){
var blockDiv = blocks[i]
var offset = blockDiv.getBoundingClientRect();
var xa = offset.left+40;
var ya = offset.top+40;
var blockFrom = blockDiv.parentNode.parentNode.previousSibling;
var offsets = blockFrom.getBoundingClientRect();
var yb = offsets.top+40;
var xb = offsets.left+40;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.moveTo(xa,ya);
ctx.lineTo(xb,yb);
ctx.stroke();
}
}
Here is a jsfiddle so you can see the general structure of the divs.
When the function is called, I get no canvas lines and a console error of
166 Uncaught TypeError: blockDiv.parentNode.parentNode.previousSibling.getBoundingClientRect is not a function
I am stumped on this one and would really appreciate the help.
I am new to canvas, javascript, and coding in general so any other constructive criticism would also be greatly appreciated. :)
Vanilla js only please!
The problem is this:
Gecko-based browsers insert text nodes into a document to represent
whitespace in the source markup. Therefore a node obtained, for
example, using Node.firstChild or Node.previousSibling may refer to a
whitespace text node rather than the actual element the author
intended to get.
https://developer.mozilla.org/en-US/docs/Web/API/Node/previousSibling
Therefore, change this line:
var blockFrom = blockDiv.parentNode.parentNode.previousSibling;
to this:
var blockFrom = blockDiv.parentNode.parentNode.previousSibling.previousSibling;
I have two canvases that are different sizes. My goal is copy the user's drawing from the main canvas to a second canvas as a scaled down version. So far the drawImage() and scale appear to be working, but the second canvas keeps the old version of the main drawing along with the new copy. I tried clearing it each time before calling drawImage(), but that doesn't appear to do anything. How can I copy just the current image to my secondary canvas each time the function runs?
$('#hand').dblclick(function(){
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
//var imageData = context.getImageData(0, 0, 100, 100);
var newCanvas = document.getElementById('scaledCanvas');
var destCtx = newCanvas.getContext('2d');
destCtx.clearRect(0, 0, newCanvas.width, newCanvas.height);
destCtx.scale(.5,.5);
destCtx.drawImage(canvas, 0, 0);
});
I can include more code if necessary. I also just realized that scale keeps getting called; this explains why the new copied image would get smaller each time as well, so that might be another problem.
It's quite simple actually, you're using what's called a transform (translate, rotate, or scale).
In order to use them "freshly" each time you must save and restore the canvas state each time.
$('#hand').dblclick(function(){
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
//var imageData = context.getImageData(0, 0, 100, 100);
var newCanvas = document.getElementById('scaledCanvas');
var destCtx = newCanvas.getContext('2d');
destCtx.clearRect(0, 0, newCanvas.width, newCanvas.height);
//save the current state of this canvas' drawing mode
destCtx.save();
destCtx.scale(.5,.5);
destCtx.drawImage(canvas, 0, 0);
//restore destCtx to a 1,1 scale (and also 0,0 origin and 0 rotation)
destCtx.restore();
});
It's also important to note you can push several times before calling restore, in order to perform many cool geometric tricks using recursive functions etc...
Take a look at this explanation of states and transformations:
https://developer.mozilla.org/en-US/docs/HTML/Canvas/Tutorial/Transformations
Hope this helps you understand canvas transforms a bit better.
I want to take an irregularly shaped section from an existing image and render it as a new image in Javascript using HTML5 canvases. So, only the data inside the polygon boundary will be copied. The approach I came up with involved:
Draw the polygon in a new canvas.
Create a mask using clip
Copy the data from the original canvas using getImageData (a rectangle)
Apply the data to the new canvas using putImageData
It didn't work, the entire rectangle (e.g. the stuff from the source outside the boundary) is still appearing. This question explains why:
"The spec says that putImageData will not be affected by clipping regions." Dang!
I also tried drawing the shape, setting context.globalCompositeOperation = "source-in", and then using putImageData. Same result: no mask applied. I suspect for a similar reason.
Any suggestions on how to accomplish this goal? Here's basic code for my work in progress, in case it's not clear what I'm trying to do. (Don't try too hard to debug this, it's cleaned up/extracted from code that uses a lot of functions that aren't here, just trying to show the logic).
// coords is the polygon data for the area I want
context = $('canvas')[0].getContext("2d");
context.save();
context.beginPath();
context.moveTo(coords[0], coords[1]);
for (i = 2; i < coords.length; i += 2) {
context.lineTo(coords[i], coords[i + 1]);
}
//context.closePath();
context.clip();
$img = $('#main_image');
copy_canvas = new_canvas($img); // just creates a new canvas matching dimensions of image
copy_ctx = copy.getContext("2d");
tempImage = new Image();
tempImage.src = $img.attr("src");
copy_ctx.drawImage(tempImage,0,0,tempImage.width,tempImage.height);
// returns array x,y,x,y with t/l and b/r corners for a polygon
corners = get_corners(coords)
var data = copy_ctx.getImageData(corners[0],corners[1],corners[2],corners[3]);
//context.globalCompositeOperation = "source-in";
context.putImageData(data,0,0);
context.restore();
dont use putImageData,
just make an extra in memory canvas with document.createElement to create the mask and apply that with a drawImage() and the globalCompositeOperation function (depending on the order you need to pick the right mode;
I do something similar here the code is here (mind the CasparKleijne.Canvas.GFX.Composite function)