I'm using http://raphaeljs.com/ to try and draw multiple small circles. The problem I'm having is that the canvas has a fixed width, and if I want to draw, say, 1000 circles, they don't wrap onto a 'new line' (because you have to specify the xy position of each circle).
E.g.
I want this:
..................................................
to look like this:
............................
......................
At the moment I'm doing this:
for ( var i = 0; i < 1000; i++ ) {
var multiplier = i*3;
if ( i <= 50 ) {
paper.circle((2*multiplier),2,2);
} else if ( i >= 51 && i <= 101 ) {
paper.circle((2*multiplier) - 304,8,2);
} else if ( i >= 152 && i <= 202 ) {
paper.circle((2*multiplier) - 910,14,2);
}
}
For reference: circle(x co-ord, y co-ord, radius)
This is messy. I have to add an if statement for every new line I want. Must be a better way of doing it..?
You want modulo.
I'm not sure exactly what your bounding box is, but something like:
var width = 300;
for (var i = 0; i < 1000; i++) {
var multiplier = i*3;
var x = 2 * multiplier * i % width;
var y = 2 + 6 * (i + 50) / 100;
}
Related
I have an object that sits at point 0,0. This object cannot share space with any other object of its type that may appear on top of it, next to it, above it, etc.. There may be more than a few of these objects present overlapping each other and i have no knowledge of where the other ones are placed until i try the collision detection method.
My thinking is that i'll use a collision detection along side a grid search. Along the lines of the photo below.
The object will first try its default best case location. If that doesn't work then it tries to the left, left-above, left-below, etc, until it has searched all the #1 positions. Then it moves onto the #2 positions and so on until it finds a place to drop the element where it won't be overlapping another.
this is the code i'm playing around with right now but it is choosing some very, very random locations for things. I'm pretty sure it isn't following the algorithm i described above.
for (let i = 0; i < 5 && this._hasCollisions(this._tagWrapper); i++) {
/**
* This algorithm explores positions inside nested boxes.
* The move algorithm behaves the following way. It goes,
* down, up, left, down, up, right * 2, repeat.
*
* For example this is how it works given the height of 5 and a width of 7
* numbers are expressed in the offset generated
* 1: 5,0 4: 5,-7 7: 5,7 10: 10,-14
* 2: -5,0 5: -5,-7 8: -5,7 11: -10,-14
* 3: 0,-7 6: 0,7 9: 0,-14
*/
// Calculate which box the collision detector is working in
// This happens every 9 iterations
let multiplier = (i / 9) + 1;
/**
* Get the x offset
*/
if (i % 3 === 0) {
// Clear the height offset on multiples of 3
xOffset = 0;
} else {
// Set the height to the multiplier
xOffset = this._tagWrapper.offsetWidth * multiplier;
}
if (i % 3 === 2) {
// Get the sequence 2, 5, 8, 11, 14, etc..
xOffset *= -1;
}
/**
* Get the y offset
*/
if (i > 2) {
// Set the width to a multiple of the multiplier and assign the existing negativeness
yOffset = this._tagWrapper.offsetHeight * multiplier * (yOffset > 0 ? 1 : -1);
}
if (i % 3 === 0) {
// Flip the sign every 3 numbers
yOffset *= -1;
}
console.log('iteration', i);
this._tagWrapper.style.top = (basePosition.y + yOffset) + 'px';
this._tagWrapper.style.left = (basePosition.x + xOffset) + 'px';
}
What is the best way to go about performing this search? I already hav
Something like this work? (most of the code is just for the visualization)
// just draw a table to visualize
var SIZE = 15;
for (var i = 0; i < SIZE; i++) {
$("#a").append("<tr>");
for (var j = 0; j < SIZE; j++) {
$("#a > tr").last().append("<td>.</td>");
}
}
// where to start searching from
var startX = 8;
var startY = 8;
function loop() {
// tell the world which grid we are on
$("#a > tr:nth-child(" + y + ") > td:nth-child(" + x + ")").css("backgroundColor", "red");
// check if done here!!! - x and y are our positions in the grid
// also do bounds checking here
if (isX) {
x = x + xDirection;
i--;
if (!i) {
// switch dimension
isX = !isX;
i = moveFor;
// switch direction
xDirection *= -1;
}
} else {
y = y + yDirection;
i--;
if (!i) {
// switch dimension
isX = !isX;
// increase the width / height we are spanning
moveFor += 1;
i = moveFor;
// switch direction
yDirection *= -1;
}
}
// jsut so that we have a nice animation
if (x > 0 && y > 0 && x <= SIZE && y <= SIZE) {
setTimeout(loop, 10)
}
}
var x = startX;
var y = startY;
var moveFor = 1;
// our step (down) counter
var i = moveFor;
var xDirection = -1;
var yDirection = -1;
// are we moving along x or y
var isX = true;
loop();
body {
font-family: monospace;
}
td {
height: 20px;
width: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tbody id="a"></tbody>
</table>
I would suggest using distance solution
point1 has x1 and y1
point2 has x2 and y2
var d = Math.sqrt( (x2-=x1)*x2 + (y2-=y1)*y2 );
link here: Get distance between two points in canvas
Here is an implementation of scanning points in a ring around a center point. You define the center point and the distance you want to sample and it returns the list of points in clock-wise order. It is in Python not JavaScript but it is simple enough that you can translate if needed.
jsfiddle here: http://jsfiddle.net/yw0w18m3/2/
I'm using paper.js to make a background image that looks somthing like this:
Basically, I'm creating a couple thousand triangles over a loop and rotating them on every other iteration.
function Tri(x, y, rotate) {
var tri = new Path([
new Point((x - 42), (y - 48)),
new Point((x - 42), y),
new Point(x, (y - 24)),
new Point((x - 42), (y - 48))
]);
tri.fillColor = {
hue: Math.random() * 360,
saturation: 0,
brightness: ( (( Math.random() ) * .95) + .3 )
};
if(rotate) { tri.rotate(180); }
}
for (var i = 0; i < 2000; i++) {
rotate = false;
if( i % 2 ) {
rotate = true;
}
new Tri(x, y, rotate);
x = x + 42;
if( x > (winWidth + 42) ) {
x = 0 ;
y = y + 24;
}
}
There seems to be a brief 1-2 second pause/freeze though while the shapes are being drawn. Is there a more efficient way to draw all the shapes first (or push to an array) then add that to the canvas all at once?
I based my code off of the example here: http://paperjs.org/examples/candy-crash/ (click "source" in the upper right corner).
Any help is much appreciated.
Thanks!
I would end up creating two triangles, one rotated, so they don't have to be built from new points each time. Then choose the correct triangle based on the rotation variable and clone it, as opposed to create points and a triangle from scratch each time. Finally, just change the position of the cloned triangle.
Last, I would correct the maxTri so it doesn't do more than it needs to. The paren should follow the 48, not the 24. You're doing an order of magnitude more triangles than needed.
Here's a link to the sketch.paperjs.org solution I created based on your code. I find sketch easier to use than jsfiddle for paper examples.
proto1 = new Path([
new Point(0, -24),
new Point(0, 24),
new Point(42, 0)
]);
proto1.closed = true;
proto2 = proto1.clone();
proto2.rotate(180);
function putTriangle(pos, rotate) {
var tri = (rotate ? proto2 : proto1).clone();
tri.position = pos;
tri.position = tri.position.subtract([21, 0])
tri.fillColor = {
hue: Math.random() * 360,
saturation: 0,
brightness: Math.random() * 0.5 + 0.5
}
}
var tris = [],
x = 42,
y = 24,
rotate,
winWidth = paper.view.size.width,
winHeight = paper.view.size.height,
rows = (winHeight + 48) / 24,
cols = (winWidth + 42) / 42,
numTri = rows * cols,
numTriOrig = (winWidth + 42) / 42 * (winHeight + 48 / 24);
//console.log(numTri, numTriOrig);
x = 0;
y = 0;
for (var row = 0; row < rows; row++) {
rowrotate = row % 2;
for (var col = 0; col <= cols; col++) {
rotate = rowrotate ^ col % 2;
putTriangle([x,y], rotate);
x += 42;
}
x = 0;
y = y + 24;
}
Two thoughts:
I see you use rotate to transform you triangles into place. This is an expensive operation. You could replace the rotate with a less geometric & more arithmetic calculation of the triangles orientation.
Also, I see is that the fill color is being changed with each triangle and state changes (like fill) are modestly expensive. You could group all the similarly colored triangles and draw them in a single batch.
I am creating a Tangram puzzle game using Javascript. And I need to detect when a user has drawn a circle (or circle like shape) with their finger. I have been able to gather hundreds (if not thousands) of x and y points with:
var touchX = event.targetTouches[0].pageX - canvas.offsetLeft;
var touchY = event.targetTouches[0].pageY - canvas.offsetTop;
I then push each x and y coordinate into an array:
touchMoveX.push(touchX);
touchMoveY.push(touchY);
I then loop through each array and create two points:
for(var i = 0; i < touchMoveX.length; i++)
{
for(var l=0; l < touchMoveY.length; l++)
{
var xPosition = touchMoveX[i];
var yPosition = touchMoveY[l];
var v1x = touchMoveX[i];
var v2x = touchMoveX[i + 1];
var v1y = touchMoveY[l];
var v2y = touchMoveY[l + 1];
Then using those two points, I use the following formula to figure out the angle between these two points in degrees:
var v1 = {x: v1x, y: v1y}, v2 = {x: v2x, y: v2y},
angleRad = Math.acos( (v1.x * v2.x + v1.y * v2.y) /
(Math.sqrt(v1.x*v1.x + v1.y*v1.y) * Math.sqrt(v2.x*v2.x + v2.y*v2.y) ) ),
angleDeg = angleRad * 180 / Math.PI;
I then sum up all of the angles and see if they are around 360 degrees.
But the above code I have described isn't working very well. Does someone out there have a better way to do this? Thank you very much.
yeah compute the average of all points (giving you a cheaply approximated center) then check if more than a certain percent of points are within a certain threshold. You can tune those values to adjust the precision until it feels right.
edit: Didn't consider that the circle could have multiple sizes, but you could just add another step computing the average of all distances. Adjusted the example for that.
var totalAmount = touchMoveX.length;
// sum up all coordinates and divide them by total length
// the average is a cheap approximation of the center.
var averageX = touchMoveX.reduce( function ( previous, current) {
return previous + current;
} ) / totalAmount ;
var averageY = touchMoveY.reduce( function ( previous, current) {
return previous + current;
} ) / totalAmount ;
// compute distance to approximated center from each point
var distances = touchMoveX.map ( function ( x, index ) {
var y = touchMoveY[index];
return Math.sqrt( Math.pow(x - averageX, 2) + Math.pow(y - averageY, 2) );
} );
// average of those distance is
var averageDistance = distances.reduce ( function ( previous, current ) {
return previous + current;
} ) / distances.length;
var min = averageDistance * 0.8;
var max = averageDistance * 1.2;
// filter out the ones not inside the min and max boundaries
var inRange = distances.filter ( function ( d ) {
return d > min && d < max;
} ).length;
var minPercentInRange = 80;
var percentInRange = inRange.length / totalAmount * 100;
// by the % of points within those boundaries we can guess if it's circle
if( percentInRange > minPercentInRange ) {
//it's probably a circle
}
Below is some code I found for moving a marker but I want to move a marker on straight path between two coordinates can any one help these are the coordinates
[90.40237426757811,23.75015391301012],[88.34930419921875,22.573438264572406]
I need the coordinates between these two points for a line. The code is:
var marker = L.marker([0, 0], {
icon: L.mapbox.marker.icon({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [-77, 37.9]
},
properties: { }
})
});
var t = 0;
window.setInterval(function() {
// making a lissajous curve here just for fun. this isn't necessary
// Reassign the features
marker.setLatLng(L.latLng(
Math.cos(t * 0.5) * 50,
Math.sin(t) * 50));
t += 0.1;
}, 50);
marker.addTo(map);
How accurate do you need the lines to be? Try something like this to begin with:
var start = {lat:90.40237426757811, lng:23.75015391301012}
var end = {lat:88.34930419921875, lng:22.573438264572406}
var n = 100; // the number of coordinates you want
coordinates = []
for(var i = n - 1; i > 0; i--){
coordinates.push( {lat: start.lat*i/n + end.lat*(n-i)/n,
lng: start.lng*i/n + end.lng*(n-i)/n});
}
This isn't accurate because the world isn't flat and over long distances it will begin to look wrong.
The full maths of plotting straight lines on projected globes is more difficult but there's a great explanation here:
http://www.movable-type.co.uk/scripts/latlong.html
Not far down the page there's a formula to calculate the midpoint of two given points.
Use that formula, then use the midpoint you've found with each end point to find two more points then use those points and so on until you have enough for a smooth line.
This might help. It draws a line between two points on a 2d plane.
fromXy and toXy are arrays containing the coordinates.
pref.canvas.size is and array containing the width and height of the canvas.
pref.color is the color of the pixel you want to print.
setPx() sets a pixel given x and y coordinates and color.
function line(toXy,fromXy) {
var y;
var m = (toXy[1] - fromXy[1]) / (fromXy[0] - toXy[0]);
var b = (m * toXy[0]) + toXy[1];
if (Math.abs(fromXy[0] - toXy[0]) >= Math.abs(fromXy[1] - toXy[1])) {
if (fromXy[0] < toXy[0]) {
for (var x = fromXy[0]; x <= toXy[0]; x++) {
y = m * x - b;
setPx(x,Math.abs(Math.round(y)),pref.color,);
}
} else {
for (var x = fromXy[0]; x >= toXy[0]; x--) {
y = m * x - b;
setPx(x,Math.abs(Math.round(y)),pref.color)
}
}
} else {
if (fromXy[1] <= toXy[1]) {
for (y = fromXy[1]; y <= toXy[1]; y++) {
x = (y / -(m)) + Math.abs(b / -(m));
if (x.toString() == 'Infinity' || x.toString() == 'NaN') {
x = fromXy[0];
}
if (x > pref.canvas.size[0] - 1) {
continue;
}
setPx(Math.abs(Math.round(x)),y,pref.color);
}
} else {
for (y = fromXy[1]; y >= toXy[1]; y--) {
x = (y / -(m)) + Math.abs(b / -(m));
if (x.toString() == 'Infinity' || x.toString() == 'NaN') {
x = fromXy[0];
}
if (x > pref.canvas.size[0] - 1) {
continue;
}
setPx(Math.abs(Math.round(x)),y,pref.color);
}
}
}
}
The code basically builds a linear equation out of the two coordinates then graphs that linear equation.
You should be able to edit the code so that it fits your needs pretty easily.
Thank you all for your useful answers :)
I used the below code for my use case, its not fully correct and with lot of hard-coding too but it worked fr me
here is the link of mock-up app which i developed using this
http://nandinibhotika.com/compass/discover.htm
here is the project description http://nandinibhotika.com/portfolio/compass-exploring-stories/
var geojson = {
type: 'LineString',
coordinates: []
},
start = [90.4010009765625, 23.74763991365265];
geojson.coordinates.push(start.slice());
momentum = [.025, .01429];
for (var i = 0; i < 557; i++) {
if (start[0] > 88.36878921508789 && start[1] > 22.571377617836507) {
start[0] -= momentum[0];
start[1] -= momentum[1];
} else {
momentum = [.00899, .0231];
start[0] += momentum[0];
start[1] -= momentum[1];
}
geojson.coordinates.push(start.slice());
}
I have the following simple blur algorithm:
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
total = 0
for (ky = -radius; ky <= radius; ++ky)
for (kx = -radius; kx <= radius; ++kx)
total += source(x + kx, y + ky)
dest(x, y) = total / (radius * 2 + 1) ^ 2
}
}
And I need to make this work with an array, generated by canvas with getImageData(). The problem is that the array from canvas is one dimentional, and the algorithm needs a two dimentional one, because "kx" and "ky" are distances from the current pixel, and in a two dimentional array you just change one of the indexes in order to move left or right on the grid, but in a one dimentional array (which is trying to represent a two-dim. one) you can't do that.
What do you think, how should I approach this problem? In my opinion, the entire problem is here:
total += source(x + kx, y + ky)
This line needs to get the correct pixels from the one-dimentional array and it should work fine.
P.S. I forgot to say that I'm trying to blur the image one channel at a time, like this:
for (var i=0; i<imgData.data.length; i+=4) {
red[index] = imgData.data[i];
green[index] = imgData.data[i+1];
blue[index] = imgData.data[i+2];
index++;
}
and I'm passing each array (red, green and blue) individually to the algorithm.
In order access a single dimensional array with two dimensional coordinates, you have the following formula:
var pixel = pixels[ ( ( y * width ) + x ) * 4 ];
The * 4 was added to account for the r,g,b,a values.
xResolution is the width if the image.
So source() would be:
function source( imageArray, x, y, imageWidth )
{
var pos = ( ( y * imageWidth ) + x ) * 4;
var val =
{
r : imageArray[ pos ],
g : imageArray[ pos + 1 ],
b : imageArray[ pos + 2 ],
a : imageArray[ pos + 3 ]
};
return val;
}