How to place one element inside another in raphael js? - javascript

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.

Related

How to draw rectangles inside a polygon using p5.js

I am working on a project for a solar panel installation calculator on roofs. The solar panels are rectangular and have fixed widths and heights. But the roofs are dynamic in shape, i.e. a polygon with multiple sides. See the attached image for reference.
I am trying to find out the maximum number of panels that can be installed on the roofs. I need to place the rectangles (panels) inside the polygon (roof), which you can not overlap and can not touch the boundary.
I was trying to achieve this using p5.js.
Here are the basic codes.
function setup() {
createCanvas(800, 500);
background(220);
noLoop();
}
function draw() {
fill(237, 34, 93);
beginShape();
vertex(50, 50);
vertex(750, 50);
vertex(750, 450);
vertex(500, 450);
vertex(500, 200);
vertex(350, 200);
vertex(350, 450);
vertex(50, 450);
endShape(CLOSE);
var solarPanel = {
width: 40,
height: 40
};
//Algorithm to add the solar panels.
}
Link to p5.js editor - https://editor.p5js.org/abhishekdas/sketches/cVoxihH0n
I am new to p5.js. Can anyone please help me to find the correct Algorithm?
One simple option is to lay the panels in a grid. Your typical nested for loop should do the trick: remember to add the spacing required between panels when computing the position of each one (this should take care of overlaps).
Regarding panels laying inside the polygon of the shape you can get started with this point in polygon p5.js example. If you can test one point, you can check 4 points. If you can check 4 points (1 panel), you can check all panels) then simply remove the ones that aren't inside the roof polygon from the grid.
For reference here's function:
function pointInPoly(verts, pt) {
let c = false;
for (let i = 0, j = verts.length - 1; i < verts.length; j = i++) {
if (((verts[i].y > pt.y) != (verts[j].y > pt.y)) && (pt.x < (verts[j].x - verts[i].x) * (pt.y - verts[i].y) / (verts[j].y - verts[i].y) + verts[i].x)) c = !c;
}
return c;
}
...where verts is an array of p5.Vector objects and pt is also a p5.Vector (though a basic object .x, .y properties will also work)
That should be a simple straight forward approach.
If you need more complex options you can look into square/rectangle packing algorithms / simulations and optimisations etc. though given the point is to set up solar panels, the real world probably the simpler setup to install and maintain on the long run will outweight potentially space saving layouts that are odd shaped.

draw box in 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.

Javascript sprites moving between two points

I'm wanting to get some sprites moving between two points in my (very basic) javascript game. Each sprite is randomly placed in the level, so I want them to move back and forth between their base position. I have the code below
function Taniwha(pos) {
this.basePos = this.pos;
this.size = new Vector(0.6, 1);
this.move = basePos + moveDist(5,0));
}
Taniwha.prototype.type = "taniwha"
var moveSpeed = 4;
Taniwha.prototype.act = function(step) {
this.move = ???
and this is where I get stuck. I'm not sure how to tell it to go left, back to base pos, right then back to base pos again (I plan to loop this). Does anyone have any advice? (also using Eloquen Javascript's example game as an outline/guide for this, if how I'm doing things seems odd!)
For horizontal movement, change x coordinate of the position.
var pos = { x: 1, y: 2 };
pos.x++ ; // This will move right
pos.x-- ; // This will move left
Likewise for vertical movement. You also need to update the coordinates after change for the object which you are drawing.
In truth ,there are lots of library to develop a game.
Use those, control a sprite is very easy.
Like:
Pixijs
CreateJS
Both of them are opensource project, you can watch and learn the source.
And have lots of examples and document.

Draw polygons on existing SVG to capture coordinate data

We have a web application that displays a SVG map of an office. The map has small icons that represent users walking around with RF tags. This allows administrators of the system to see what rooms users are in. We are using Snap.SVG to load the office SVG file and manipulate it to display the user icons. The challenge is that the map scales to the size of the browser. Using JavaScript to determine the coordinates is not always accurate because the position of the SVG changes based on the browser size.
Here is an example of the map with the icons:
The icons are placed on the map based on X Y coordinates coming from our database. The values for the X Y coordinates are set for each location and were determined using Adobe Illustrator. Currently, we can only place one icon in a room at a time. Because we only have 1 set coordinates the icons overlap if more than one person is in a room at one time.
The second phase of this project is to allow users to draw on of the map to specify locations. Essentially, the user will set points and create a polygon to represent each location on the map. We would use the coordinates of the polygon along with the total area of the polygon to know where on the map we can place icons. This would allow users to define areas without a developer getting involved.
Here is an example of what we want to achieve .
I have been researching how to do this, but have not found anything outside of using something like the Google Maps API to draws polygons on a map. I did find this article that outlines how to dynamically pull points. We thought about using a grid system that is an overlay on the map and the user defines what grid elements are in what locations. So something like [A1,A2,B1,B2]. I persoanlly like the polygon approach as it is more visually appealing and is easier for a user to adopt.
We need some advice on where to start with this and if something like snap.svg is all we need or if we have to rely on other libraries in conjunction with snap.
Update:
With Ian's advice I found a fiddle that describes what he was talking about.
var S;
var pt;
var svg
var box;
window.onload = function(){
svg = $('#mysvg')[0];
S = Snap(svg);
console.log( S );
pt = pt = svg.createSVGPoint(); // create the point
// add the rectangle
box = S.rect(12,12, 12, 12);
box.attr({ fill : 'red', stroke : 'none' });
S.drag(
function(dx, dy, posX, posY, e){
//onmove
pt.x = posX - S.node.offsetLeft;
pt.y = posY - S.node.offsetTop;
console.log(pt.x + "," + pt.y);
// convert the mouse X and Y
//so that it's relative to the svg element
var transformed = pt.matrixTransform(svg.getCTM().inverse());
box.attr({ x : transformed.x, y : transformed.y });
},
function(){
//onstart
},
function(){
//onend
}
);
}
The Fiddle

How can I make Raphael.js elements "wiggle" on the canvas?

I'm working on a project that uses SVG with Raphael.js. One component is a group of circles, each of which "wiggles" around randomly - that is, slowly moves along the x and y axes a small amount, and in random directions. Think of it like putting a marble on your palm and shaking your palm around slowly.
Is anyone aware of a Raphael.js plugin or code example that already accomplishes something like this? I'm not terribly particular about the effect - it just needs to be subtle/smooth and continuous.
If I need to create something on my own, do you have any suggestions for how I might go about it? My initial idea is along these lines:
Draw a circle on the canvas.
Start a loop that:
Randomly finds x and y coordinates within some circular boundary anchored on the circle's center point.
Animates the circle from its current location to those coordinates over a random time interval, using in/out easing to smooth the effect.
My concern is that this might look too mechanical - i.e., I assume it will look more like the circle is tracing a star pattern, or having a a seizure, or something like that. Ideally it would curve smoothly through the random points that it generates, but that seems far more complex.
If you can recommend any other code (preferably JavaScript) that I could adapt, that would be great too - e.g., a jQuery plugin or the like. I found one named jquery-wiggle, but that seems to only work along one axis.
Thanks in advance for any advice!
Something like the following could do it:
var paper = Raphael('canvas', 300, 300);
var circle_count = 40;
var wbound = 10; // how far an element can wiggle.
var circleholder = paper.set();
function rdm(from, to){
return Math.floor(Math.random() * (to - from + 1) + from);
}
// add a wiggle method to elements
Raphael.el.wiggle = function() {
var newcx = this.attrs.origCx + rdm(-wbound, wbound);
var newcy = this.attrs.origCy + rdm(-wbound, wbound);
this.animate({cx: newcx, cy: newcy}, 500, '<');
}
// draw our circles
// hackish: setting circle.attrs.origCx
for (var i=0;i<circle_count;i++) {
var cx = rdm(0, 280);
var cy = rdm(0, 280);
var rad = rdm(0, 15);
var circle = paper.circle(cx, cy, rad);
circle.attrs.origCx = cx;
circle.attrs.origCy = cy;
circleholder.push(circle);
}
// loop over all circles and wiggle
function wiggleall() {
for (var i=0;i<circleholder.length;i++) {
circleholder[i].wiggle();
}
}
// call wiggleAll every second
setInterval(function() {wiggleall()}, 1000);
http://jsfiddle.net/UDWW6/1/
Changing the easing, and delays between certain things happening should at least help in making things look a little more natural. Hope that helps.
You can accomplish a similar effect by extending Raphael's default easing formulas:
Raphael.easing_formulas["wiggle"] = function(n) { return Math.random() * 5 };
[shape].animate({transform:"T1,1"}, 500, "wiggle", function(e) {
this.transform("T0,0");
});
Easing functions take a ratio of time elapsed to total time and manipulate it. The returned value is applied to the properties being animated.
This easing function ignores n and returns a random value. You can create any wiggle you like by playing with the return formula.
A callback function is necessary if you want the shape to end up back where it began, since applying a transformation that does not move the shape does not produce an animation. You'll probably have to alter the transformation values.
Hope this is useful!
There is a very good set of easing effects available in Raphael.
Here's a random set of circles that are "given" bounce easing.
Dynamically add animation to objects
The full range of easing effects can be found here. You can play around with them and reference the latest documentation at the same time.
Putting calls in a loop is not the thing to do, though. Use callbacks, which are readily available.

Categories