draw box in javascript - javascript

I am trying to animate the drawing of a box that will then fill in when it is complete. I am taking a class in JS so the code has to be JS. The problem is that the right side of the box will not animate correctly. If I put in one set of coordinates for it it animates from the bottom to the top instead of from the corner where the top line started. When I reverse the coordinates it does animate from the proper corner but instead of drawing the line it starts with a solid line and takes away from it, like a disappearing line. Also both the left and right side lines seem to go off the area assigned. For example my area is 600 x 400 and the lines go off the bottom of the page. If I change the dimensions to 600 x 600 the lines still go off the page. The point of this whole project is that we have coded houses using the SVG library and I want to create an animation to make it look as though the house is being drawn before it fills in the colors. This is more for my own knowledge as it is no longer an assignment. There are 2 links to my jsfiddle, the first one is going to be the problem code of drawing the box. The second is what the house that I would like to animate is to look like.
drawing box
"use strict"
var draw = SVG('drawing').size(600, 400);
function makeBox()
{
var line1 = draw.line(25,175,26,175);
line1.stroke({width:1});
line1.animate(4000).size(550);
var line2 = draw.line(575,175,575,176);
line2.stroke({width:1});
line2.animate({duration:4000,delay:4000}).size(200).move(575,375);
var line3 = draw.line(575,375,574,375);
line3.stroke({width:1});
line3.animate({duration:4000,delay:8000}).move(25,375).size(550);
var line4 = draw.line(25,375,25,374);
line4.stroke({width:1});
line4.animate({duration:4000,delay:12000}).size(200).move(25,175);
}
makeBox();
function makeBaseb1(bx,by,c,s)
{
var Baseb1 = draw.rect(550,200).opacity(0).fill(c).stroke();
Baseb1.animate({delay:'16s'}).opacity(1).fill({color:c});
Baseb1.stroke({width:s,color:'black'});
Baseb1.move(bx,by);
}
makeBaseb1(25,175,'#FF9900',1);
house

There are 2 issues with the makeBox function:
The .size method taks 2 arguments instead of 1 (x and y dimension).
For the line drawing in the reverse direction wrt the coordinate system,
both, starting coordinates and line length, need to be animated.
The updated function:
function makeBox() {
var line1 = draw.line(25,175,26,175);
line1.stroke({width:1});
line1.animate(4000).size(550,0);
var line2 = draw.line(575,175,575,176);
line2.stroke({width:1});
line2.animate({duration:4000,delay:4000}).size(0,200);
var line3 = draw.line(574,375,575,375);
line3.stroke({width:1});
line3
.animate({duration:4000,delay:8000})
.during(
function (pos, morph, eased, situation) {
line3.x(morph(574,25));
line3.size(morph(1,550),morph(0,0));
}
)
;
var line4 = draw.line(25,374,25,375);
line4.stroke({width:1});
line4
.animate({duration:4000,delay:12000})
.during(
function (pos, morph, eased, situation) {
line4.y(morph(374,175));
line4.size(morph(0,0),morph(1,200));
}
)
;
}
The use of the .during method is documented here.

Related

Extendscript - Adobe Illustrator - Ellipse not in right location

I'm trying to do something that seems simple, but not sure how it's not working. I have a map layer and I'm trying to draw circles via Extendscript. I'm trying to test just by trying to draw a simple circle at point 100,100 (I assume top left of map is 0,0), but when I execute it, the circle appears way further down than it should be (seems close to 200,700). Below is my code I'm using...
var dotRadius = 8.136 / 2;
var testDOT = mapLayer.pathItems.ellipse(100, 100, dotRadius*2, dotRadius*2, false, false);
testDOT.strokeWidth = 0.25;
testDOT.strokeColor = getColor("MAROON"); // defined above
testDOT.fillColor = getColor("MAROON");
the getColor just creates a CYMK Color object. Can anyone give me a clue on why the 100,100 point is not where I expect it to be?
TIA!
Just in case, it looks like your script used the 'relative' coordinate system (relative to zero point of current artboard).
To made it to use 'absolute' coordinates (relative to the top-left corner of the first artboard for a new document) you can add this line at the start of your script:
app.coordinateSystem = CoordinateSystem.DOCUMENTCOORDINATESYSTEM;
Or you can use the 'relative' coordinate system:
app.coordinateSystem = CoordinateSystem.ARTBOARDCOORDINATESYSTEM;
In this case you can move zero point of any artboard with this commands:
var doc = app.activeDocument;
doc.artboards[0].rulerOrigin = [0,0];
doc.artboards[1].rulerOrigin = [200,700];
// etc

How do I rotate around a point towards the mouse in PaperJS?

I'm creating a simple game using PaperJS and I'm currently stuck on a small part of it.
In the game, there is a player (just a circle) who has two hands (two smaller circles)
I want the hands to always point towards the mouse position, but I can't figure out the equation needed to do so.
Here's some of the code I have so far, I just need help filling in the blank...
view.onMouseMove = function(event) {
var mouseX = event.point.x;
var mouseY = event.point.y;
var rotation = ???
playerHands.rotate(rotation, view.center)
}
Here is a diagram of what I'm trying to accomplish:
is really simple:
function onMouseMove(event) {
let delta = (event.point - player.position);
player.rotation = delta.angle+90;
}
the idea here is you can use two Points to do Vector-Geometry.
more in depth descriptions are in the Vector-Geometry Tutorial
there is a +90 offset needed to align mouse with top of player as paperjs sees the x axis as 0° for rotation.
i have created a working example in sketch.paperjs.org
the above player.rotation is only working if the Player Group has its .applyMatrix set to false.
additionally i set the Player-Group pivot point to the big circle center at creation:
let player = new Group(circle, handleleft, handleright);
player.applyMatrix = false;
player.pivot = circle.bounds.center;
player.position = position;

How to place one element inside another in raphael js?

Im trying to create an interactive seating layout like this Seats.io. However I dont need the exact features but just few things such as:
Plotting seats anywhere on the screen
Plotting list of seats from one point to another
Seats hover as circle when plotting from one mouse click point to another
After much research in Jquery and simultaneously on raphaeljs, I have decided to start working with raphaeljs. Im totally new to the vector graphics. So obviously there might be something that I may be missing. I have followed this fiddle to draw a straight line. I have also created another script to plot circles anywhere on the window(the circles will mean seats) following is the script
window.onload = function () {
var height = $(document).outerHeight(true);
var width = $(document).width();
var radius = 10;
var paper = Raphael(0, 0, width, height);
var i = 0;
$(document).click(function (e) {
i = i + 1;
var x = e.pageX;
var y = e.pageY;
var seat = paper.circle(x, y, radius)
.attr({stroke: "none", fill: "#f00", opacity: .4})
.data("i", i);
seat.mouseover(function () {
this.attr("opacity", 1);
});
seat.mouseout(function () {
this.attr("opacity", .4);
});
});
}
using the above script I'm able to plot circles(seats) on my screen. Now based on the fiddle example lines are drawn using 'path', so is it possible to load circles on every path and draw them as sequential line of circles one after the other, or do I have to take any different approach.
Also on a side note is there any opensource project or code for the Seats.io
Any help would be really appreciated
Ben from seats.io here.
http://raphaeljs.com/reference.html#Element.getPointAtLength is indeed what we use. You'll basically need to
calculate a helper path between start and end point. You already have that.
calculate the distance between seats (based on seat size): helperPath.getTotalLength() / (numberOfSeats - 1);
for each seat, call getPointAtLength and draw a circle around that
point: helperPath.getPointAtLength(distanceBetweenSeatsOnHelperPath * i++)
Obviously, it gets more interesting if you want to snap to a grid to align rows, curve rows, etc, but you should be able to get started with the above.

How to Draw line in 3D rectangle based on x,y and z?

I would like draw 3D points represented in image to 3D rectangle. Any idea how could I represent these in x,y and z axis
Here projection type is orthographic.
Thanks
Okay. Let's look at a simple example of what you are trying to accomplish it, and why this is such a complicated problem.
First, lets look a some projection functions. You need a way to mathematically describe how to transform a 3D (or higher dimensional) point into a 2D space (your monitor), or a projection.
The simpiest to understand is a very simple dimetric projection. Something like:
x' = x + z/2;
y' = y + z/4;
What does this mean? Well, x' is you x coordinate 2D projection: for every unit you move backwards in space, the projection will move that point half that many units to the right. And y' represents that same projection for your y coordinate: for every unit you move backwards in space, the projection will move that point a quarter unit up.
So a point at [0,0,0] will get projected to a 2d point of [0,0]. A point at [0,0,4] will get projected to a 2d point of [2,1].
Implemented in JavaScript, it would look something like this:
// Dimetric projection functions
var dimetricTx = function(x,y,z) { return x + z/2; };
var dimetricTy = function(x,y,z) { return y + z/4; };
Once you have these projection functions -- or ways to translate from 3D space into 2D space -- you can use them to start draw your image. A simple example of that using js canvas. First, some context stuff:
var c = document.getElementById("cnvs");
var ctx = c.getContext("2d");
Now, lets make a little helper to draw a 3D point:
var drawPoint = (function(ctx,tx,ty, size) {
return function(p) {
size = size || 3;
// Draw "point"
ctx.save();
ctx.fillStyle="#f00";
ctx.translate(tx.apply(undefined, p), ty.apply(undefined,p));
ctx.beginPath();
ctx.arc(0,0,size,0,Math.PI*2);
ctx.fill();
ctx.restore();
};
})(ctx,dimetricTx,dimetricTy);
This is pretty simple function, we are injecting the canvas context as ctx, as well as our tx and ty functions, which in this case our the dimetric functions we saw earlier.
And now a polygon drawer:
var drawPoly = (function(ctx,tx,ty) {
return function() {
var args = Array.prototype.slice.call(arguments, 0);
// Begin the path
ctx.beginPath();
// Move to the first point
var p = args.pop();
if(p) {
ctx.moveTo(tx.apply(undefined, p), ty.apply(undefined, p));
}
// Draw to the next point
while((p = args.pop()) !== undefined) {
ctx.lineTo(tx.apply(undefined, p), ty.apply(undefined, p));
}
ctx.closePath();
ctx.stroke();
};
})(ctx, dimetricTx, dimetricTy);
With those two functions, you could effectively draw the kind of graph you are looking for. For example:
// The array of points
var points = [
// [x,y,z]
[20,30,40],
[100,70,110],
[30,30,75]
];
(function(width, height, depth, points) {
var c = document.getElementById("cnvs");
var ctx = c.getContext("2d");
// Set some context
ctx.save();
ctx.scale(1,-1);
ctx.translate(0,-c.height);
ctx.save();
// Move our graph
ctx.translate(100,20);
// Draw the "container"
ctx.strokeStyle="#999";
drawPoly([0,0,depth],[0,height,depth],[width,height,depth],[width,0,depth]);
drawPoly([0,0,0],[0,0,depth],[0,height,depth],[0,height,0]);
drawPoly([width,0,0],[width,0,depth],[width,height,depth],[width,height,0]);
drawPoly([0,0,0],[0,height,0],[width,height,0],[width,0,0]);
ctx.stroke();
// Draw the points
for(var i=0;i<points.length;i++) {
drawPoint(points[i]);
}
})(150,100,150,points);
However, you should now be able to start to see some of the complexity of your actual question emerge. Namely, you asked about rotation, in this example we are using an extremely simple projection (our dimetric projection) which doesn't take much other than an oversimplified relationship between depth and its influences on x,y position. As the projections become more complex, you need to know more about your relationship/orientation in 3D space in order to create a reasonable 2D projection.
A working example of the above code can be found here. The example also includes isometric projection functions that can be swapped out for the dimetric ones to see how that changes the way the graph looks. It also does some different visualization stuff that I didn't include here, like drawing "shadows" to help "visualize" the actual orientation -- the limitations of 3D to 2D projections.
It's complicated, and even a superficial discussion is kind of beyond the scope of this stackoverflow. I recommend you read more into the mathematics behind 3D, there are plenty of resources, both online and in print form. Once you have a more solid understanding of the basics of how the math works then return here if you have a specific implementation question about it.
What you want to do is impossible to do using the method you've stated - this is because a box - when rotated in 3 dimensions won't look anything like that diagram of yours. It will also vary based on the type of projection you need. You can, however get started using three.js which is a 3D drawing library for Javascript.
Hope this helps.
How to Draw 3D Rectangle?
posted in: Parallelogram | updated on: 14 Sep, 2012
To sketch 3 - Dimensional Rectangle means we are dealing with the figures which are different from 2 – D figures, which would need 3 axes to represent them. So, how to draw 3D rectangle?
To start with, first make two lines, one vertical and another horizontal in the middle of the paper such that they represent a “t” letter of English. This is what we need to draw for temporary use and will be removed later after the construction of the 3 – D rectangle is complete. Next we draw a Square whose measure of each side is 1 inch. Square must be perfect in Geometry so that 90 degree angles that are formed at respective corners are exact in measure. Now starting from upper right corner of the square we draw a line segment that will be stretched to a measure of 2 inches in the direction at an angle of 45 degrees. Similarly, we repeat the procedure by drawing another Line Segment from the upper left corner of the square and stretching it to 2 inches length in the direction at an angle of 45 degrees. These 2 line segments are considered to be the diagonals with respect to the horizontal line that we drew temporarily in starting. Also these lines will be parallel to each other. Next we draw a line that joins the end Point of these two diagonals.
Next starting from the very right of the 2 inch diagonal end point, draw a line of measure 1 inch that is supposed to be perpendicular to the temporary horizontal line. Next we need to join the lower left corner of the square with end point of the last 1’’ line we drew in 4th step and finally we get our 3 - D rectangular. Now we can erase our initial “t”. This 3- D rectangle resembles a Cuboid.

Why is my canvas fill pattern repeating/overlapping itself?

I've drawn a grid of rounded rectangles, and I need to fill them with an image background. Eventually I'll have many image backgrounds, but for now, I'm trying to get it to work with one. I'm close, my rectangles draw but the fill does something a little whacky - it overlaps itself and kills my pattern (except on the edges) basically filling the whole canvas with the image. I've tried to 'clip' my path but that just causes only one rectangle to fill. I'm not sure what I'm doing wrong, and I'm hoping a canvas expert can spot it?
/* build rounded rectangle */
var roundedRect=function(ctx,x,y,width,height,radius,fill,stroke)
{
ctx.save(); // save the context so we don't mess up others ctx.beginPath();
// draw top and top right corner ctx.moveTo(x+radius,y);
ctx.arcTo(x+width,y,x+width,y+radius,radius);
// draw right side and bottom right corner
ctx.arcTo(x+width,y+height,x+width-radius,y+height,radius);
// draw bottom and bottom left corner
ctx.arcTo(x,y+height,x,y+height-radius,radius);
// draw left and top left corner
ctx.arcTo(x,y,x+radius,y,radius);
ctx.clip();
if(fill){ ctx.fill(); }
if(stroke){ ctx.stroke(); }
ctx.restore(); // restore context to what it was on entry
}
/* onload, fill canvas with pattern of rounded rectangles separated by 2px */
window.onload = function() {
var canvas = document.getElementById("canvas");
/* rounded filled rectangle pattern */
var canvasWidth=530;
var canvasHeight=530;
var recWidth=42;
var recHeight=42;
var grout=2;
var radius=2;
var cols=canvasWidth/(recWidth+grout);
var rows=canvasWidth/(recHeight+grout);
/* loop through each row/column to build pattern */
alert("rows" + rows + " & cols " + cols);
for (i=1; i<rows; i++){
for (j=1; j<cols; j++){
var ctx = canvas.getContext("2d");
/* fill pattern */
var img=document.getElementById("poppy");
var pat=ctx.createPattern(img,"repeat");
ctx.fillStyle=pat;
roundedRect(ctx,(j*grout + (j-1)*recWidth),(i*grout + (i-1)*recHeight),recWidth,recHeight,radius,true,false);
}
}
};
Let's assume that your problem is reproduced in this JSFiddle: http://jsfiddle.net/hBEwr/. (If this is not the case, the rest of this answer is ~bunk; please edit to match your exact problem.)
If we remove the pattern from the equation altogether, we can see that it is not directly to blame.
http://jsfiddle.net/hBEwr/1/
Instead, the rounded rects are not leaving the grout necessary between them.
Since everything is running over each other, we then change the fill color to a low-opacity blue. Interesting!
http://jsfiddle.net/hBEwr/2/
We see that many of the paths are getting drawn again and again. This insight leads us to look at the implementation of roundedRect() more closely and notice that we never call beginPath(). Indeed, in your code from the question above it seems to have gotten eaten by a comment. Without this call, each invocation of roundedRect() adds additional rectangles to an ever-growing path, instead of starting over.
Adding the call to beginPath() back in, we see that we are on the path to success:
http://jsfiddle.net/hBEwr/3/
Now we can add back in the pattern (with some slight changes) and achieve glorious victory:
http://jsfiddle.net/hBEwr/4/
Some notes on other small tweaks I made:
Make sure you always var your local variables:
for (i=0; i<10; i++) // Oops! i is a global variable
for (var i=0; i<10; i++) // Much better
It's inefficient to re-get the ctx, img, and create the pattern for each tile. In the final code above I've moved these outside the loops for simplicity and speed.
Using console.log instead of alert for debugging is often far easier. (Open the developer console to see the output.)
I added the final outer row/col of grout the the column calculations to ensure that there is space for it to be included. Use or not as you like.

Categories