I want to create a graph with nodes and lines that connect node around the circumference only
I tried this; it didn't work
for (int i = 0; i < nodeX.length; i++) {
fill(0);
ellipse(nodeX[i], nodeY[i], 10, 10);
}
or a pass mark, there must be a display window of size (600, 360) containing a grid with the same number of columns and rows (10 in the video). Your program should work correctly with a different size and/or number of partitions.
You set a constant globally at the VERY TOP, as:
final int N_PARTITIONS = 10;
and use it (N_PARTITIONS) throughout the program. your program should work even if the marker changes the value of N_PARTITIONS to 5 or 8 or 15 or ... (obviously, when N_PARTITIONS changes to 15, there should be 15 rows and 15 columns)
When you click anywhere on the display window, circle of diameter 10 (henceforth called a node) should be displayed at that point. Nodes from previous clicks should stay on the screen and there should be lines that join each node with the next one (and the last is joined to the first node). There should be no other lines besides these lines (and the grid lines of course).
There should be nodes drawn at the three points and lines from (200, 400) to (300, 300); (300, 300) to (60, 100); and (60, 100) to (200, 400).
From how you desribed the expected output, it seems as if the grid lines and the nodes connected by lines are unrelated. Therefore, you have two tasks to accomplish:
Drawing a grid with N_PARTITIONS rows and column lines, and
Drawing and connecting circles of diameter 10 through a mouse-click.
The former is relatively easy. Given
final int N_PARTITIONS = 10;
we need 10 lines across the screen and 10 lines down the screen.
Within void setup(), use size(600, 360); to set the size of the canvas to 600x360 pixels.
Let's handle drawing lines across the screen first. We will use a for loop to accomplish this.
void draw() {
int distVertLine = width / N_PARTITIONS; // This variable defines the distance between each subsequent vertical line.
for(int i = distVertLine / 2; i < width; i += distVertLine) {
line(i, 0, i, height); // Draw a line at x=i starting at the top of the canvas (y=0) and going to the bottom (y=height)
}
}
Above, we initialize a distVertLine variable to define the horizontal distance between each vertical line. Its value is width / N_PARTITIONS because we are splitting up the width of the canvas into a given amount of partitions.
In the for loop, i is initialized as distVertLine / 2 so that the grid lines are in the center.
Similarly, we can do this with the horizontal lines:
int distHorizLine = height / N_PARTITIONS; // This variable defines the distance between each subsequent vertical line.
for(int i = distHorizLine / 2; i < width; i += distHorizLine) {
line(0, i, width, i); // Draw a line at y=i starting at the left of the canvas (x=0) and going to the right (x=width)
}
Now for the nodes and lines. A circle in Processing is given by circle(x, y, extent) (check out the docs here).
When the mouse is pressed, the method void mousePressed() is called. Upon each press, we wish to record the x and y values in an array:
ArrayList nodeX = new ArrayList(); // ArrayLists are nice to use because they're expandable, unlike a Processing array.
ArrayList nodeY = new ArrayList(); // ArrayLists are nice to use because they're expandable, unlike a Processing array.
void mouseClicked() {
nodeX.add(mouseX); // Adds the x-position of the mouse pointer to the nodeX list.
nodeY.add(mouseY); // Adds the y-position of the mouse pointer to the nodeY list.
}
In void draw(), set up a for loop that draws circles at the coordinates in both lists:
stroke(0); // Set the circle's outline as black.
for(int i = 0; i < nodeX.size(); i++) {
float xPos = (int)nodeX.get(i); // Grab the ith x-position from the list.
float yPos = (int)nodeY.get(i); // Grab the ith y-position from the list.
circle(xPos, yPos, 10); // Draw a circle of diameter 10 at (xPos, yPos).
}
(Note, within the first line of void draw() I added
background(255); // Set the background color to white
stroke(125); // Set the stroke color as gray.
to make it easier to see the circles).
Last, we need to connect each circle with a line.
stroke(0, 0, 255); // Make the connecting lines blue.
for(int i = 0; i < nodeX.size() - 1; i++) {
float xPosA = (int)nodeX.get(i); // Grab the ith x-position from the list.
float yPosA = (int)nodeY.get(i); // Grab the ith y-position from the list.
float xPosB = (int)nodeX.get(i+1); // Grab the next x-position from the list.
float yPosB = (int)nodeY.get(i+1); // Grab the next y-position from the list.
line(xPosA, yPosA, xPosB, yPosB);
}
// And draw the connecting line.
if(nodeX.size() > 0) { // The code in this block will crash unless this condition is added to handle an empty list.
int size = nodeX.size() - 1; // Get the index of the last item in nodeX/nodeY.
float xPosA = (int)nodeX.get(0); // Grab the first x-position from the list.
float yPosA = (int)nodeY.get(0); // Grab the first y-position from the list.
float xPosB = (int)nodeX.get(size); // Grab the last x-position from the list.
float yPosB = (int)nodeY.get(size); // Grab the last y-position from the list.
line(xPosA, yPosA, xPosB, yPosB);
}
Related
I have a polar graph (see image) with 120 different points. I want to make it so if the user clicks or hovers on one of the points, the coordinate of that point is displayed. I have an array called pointCoordinates that stores each canvas coordinate of each points like this:
[[x1, y1], [x2, y2] ... [x120, y120]]
This is how I am capturing mouse coordinates (which I might later change to click):
document.onmousemove = function(e) {
var x = e.clientX;
var y = e.clientY;
}
I was originally planning to use a formula to check if the mouse is in a certain region (using the distance formula) or simplifying it all into a circle. Either way, this will require me to have 120 different if statements to check for this. I feel like this is inefficient and probably slow. Are there other methods for doing this?
Edit:
To provide more information, these points will NOT be draggable. I am planning to display something like a tooltip near the point that was clicked where the polar coordinates of the point will be shown.
Edit 2:
After using the code posted below and drawing a rectangle in the "clickable" spot on the map, I get this image. I do not want the click detection to be perfect, but this is pretty far off after pi/3. Any ideas how to fix this? I used this code to generate the black spots:
for(var x = 0; x < WIDTH*2/3; x++){
for(var y = 0; y < HEIGHT; y++){
var mp = realToPolar(x, y);//converts canvas x and y into polar
if(checkRadialDistance(mp[0], mp[1])){ //returns true if in bounds
ctx.fillRect(x, y, 1, 1);
}
}
}
Playing around with the constants still generates the same pattern, just of different thicknesses. checkRadialDistance is just the renamed checkr function that inside calls checkrt.
JSBIN Keep in mind, width of screen has to be greater than height for this to work properly.
The image generated by mt-rt. I later made a minor edit, so that whole circle is covered when theta = 0.
EDIT: My (accepted) answer was bad. This corrects it:
This assumes r to be 1 to 5. Convert mouse cartesian mx,my to polar mr,mt. First check if mr is close to 1 of the 5 radii. Function checkr does that. If it is close, then check if mt is close to 1 of the 24 thetas. Function checkt does that. A complication is that the atan2 function is not continuous at pi radians which is where points are at, so make the discontinuity at -pi/24 radians where there are no points.
A "close" value is pi/24 since the arc distance between two adjacent points at r=1 will be pi/12.
var del = 1*Math.PI/24*.7; // for example
function xy2rt(xy) { // to polar cordinates
var rt = [];
rt.push(Math.sqrt(xy[0]*xy[0]+xy[1]*xy[1])); // r
var zatan = Math.atan2(xy[1], xy[0]);
// make the discontinuity at -pi/24
if (zatan < -Math.PI/24) zatan += 2*Math.PI;
rt.push(zatan); // theta
return rt;
}
function checkr() { // check radial distance
for (var pr=1; pr<=5; pr+=1) { // 5 radii
if (Math.abs(mr-pr) < del) { checkt(pr); break; }
}
}
function checkt(pr) { // check theta
var pt;
for (var ipt=0; ipt<24; ipt+=1) { // 24 thetas
pt = ipt / 24 * 2 * Math.PI;
if (Math.abs(mt-pt) < del/pr) {
// is close -- do whatever
break;
}
}
}
My problem was when checking the arc distance, I was using mr and pr whereas only pr should be used. The OP found my error by processing every pixel on the canvas and found there was a problem. I also processed every pixel and this image shows the routines to be correct now. The black is where the routines determine that the pixel is close to one of the 120 points.
EDIT: Faster processing
There are a lot of Math.* functions being executed. Although I haven't timed anything, I think this has to be much faster.
1) The x,y coordintates of the 120 points are stored in arrays.
2) Instead of getting polar mr, mt, pr, and pt, use vector processing.
Here is the derivation of arcd, the arc distance using vectors.
sint = sin(theta) = (M cross P)/mr/pr (cross product Mouse X Point)
cost = cos(theta) = (M dot P)/mr/pr (dot product Mouse . Point)
sint will be used to get arc distance, but sint goes to zero at theta=+-pi as well as theta=0, so:
mdotp will be used to determine if theta is near zero and not +-pi
arcd = pr*theta
arcd = pr*sin(theta) (good approximation for small theta)
arcd = pr*abs(M cross P)/mr/mp (from above)
if ardd < del, check if mdotp > 0.
Here are the load-xy-arrays and the new checkr and checkt routines.
apx=[], apy=[]; // the saved x,y of the 120 points
function loadapxapy() { // load arrays of px, py
var itheta, theta
for (var pr=1; pr<=5; pr+=1) { // 2-dimension arrays
apx[pr] = []; apy[pr] = []; // 5 arrays, 1 for each pr
for (itheta=0; itheta<24; itheta+=1) { // 24 x's and y's
theta = Math.PI*itheta/12;
apx[pr][itheta] = pr*Math.cos(theta);
apy[pr][itheta] = pr*Math.sin(theta);
}
}
}
function checkr() { // check radial distance
var mr = Math.sqrt(mx*mx+my*my); // mouse r
for (var pr=1; pr<=5; pr+=1) { // check 1 to 5
if (Math.abs(mr-pr) < del) { // mouser - pointr
checkt(mr, pr); // if close, check thetas
}
}
}
function checkt(mr, pr) { // check thetas
var px, py, sint, mdotp, arcd;
for (var itheta=0; itheta<24; itheta+=1) { // check 24
px = apx[pr][itheta]; // get saved x
py = apy[pr][itheta]; // and y
// This arcd is derived from vector processing
// At least this doesn't use the accursed "atan"!
sint = Math.abs(mx*py-my*px)/mr/pr; // sine
arcd = pr*sint; // arc distance
if (arcd<del) { // arc distance check
mdotp = (mx*px+my*py); // final check
if (mdotp > 0) { // to see if theta is near zero and not +-pi
setpixelxy([mx, my]); // or whatever..
}
}
}
}
I'm trying to create a chess board, and place it in the middle of the screen, so far i cannot get it to be directly in the center. i don't want to hard code the position to the screen because i'm going to be dealing with different screen sizes.
var winsize = cc.director.getWinSize();
var centerpos = cc.p(winsize.width / 2, winsize.height / 2);
for (i=0; i<64; i++){
var tile = cc.Sprite.create(res.tile_png);
this.addChild(tile,0);
tile.setPosition(winsize.width+i%8*50/-10, winsize.height-Math.floor(i/8)*50);
}
But the tiles and positioning is completely off
#jumpman8947, if you're using Cocos2d js perhaps you have a similar line: cc.view.setDesignResolutionSize(480, 320, cc.ResolutionPolicy.SHOW_ALL);
In this particular case the game will scale to any sceeen, but still run in 480x320 resolution, so no matter what screen resoultion you use, the center in the cocos world would always be cc.p(240, 160) so no matter what's the window size or the screen resolution, the resolution of the game stays the same
You can read more about resolution policies here (and in official js-doc):
http://www.cocos2d-x.org/wiki/Multiple_Resolution_Policy_for_Cocos2d-JS
Also please be aware, that the Sprite position in Cocos is the position of the centre of the sprite, not bottom left corner
In your question it's not completely clear exactly what you want. However, I made some assumptions. The explanation for my solution is embedded in the comments in the code below.
// var winsize = cc.director.getWinSize();
// Here is some example hard-coded return values:
var winsize = {width: 600, height: 400};
// You can change these numbers to see how they influence
// the outcome.
// var centerpos = cc.p(winsize.width / 2, winsize.height / 2);
// This line doesn't seem relevant for the question you asked.
// Or, rather, the following calculations will result in the tiles
// being centred on the screen anyway, so this calculation here
// is unnecessary.
// Being a chess board, I assume that you want the tiles to be square,
// i.e. to have the same width and height.
// If so, first find out which is the minimum dimension
// and calculate the tile size as being 1/8 of that.
var minDimn = Math.min(winsize.width, winsize.height);
var tileSize = minDimn / 8;
// Find out how far in from the left and how far down from the top
// you need the upper left corner of the upper left tile to start.
// This assumes that you don't need any "margin" around the board.
// (If you do need such a "margin", basically subtract it twice
// from each of winsize.width and winsize.height above.)
// Start with default values of 0 for each, but then add in the
// excess for the longer dimension, but divide it by two
// because that excess will be split between either
// the top and bottom or the left and right.
var xStart = 0, yStart = 0;
if (winsize.width > winsize.height) {
xStart = (winsize.width - winsize.height) / 2;
} else if (winsize.height > winsize.width) {
yStart = (winsize.height - winsize.width) / 2;
}
// Instead of looping through all 64 positions in one loop,
// loop through all the horizontal positions in an outer loop
// and all the vertical positions in an inner loop.
for (i = 0; i < 8; i++) {
// For the horizontal dimension, calculate x for each tile
// as the starting position of the left-most tile plus
// the width of the tile multiplied by the number of tiles (0-based)
var x = xStart + i * tileSize;
// Now the inner loop
for (j = 0; j < 8; j++) {
// Same type of calculation for the y value.
var y = yStart + j * tileSize;
// You can see the values in this demo here.
document.write("<pre>(" + x + ", " + y + ")</pre>");
// The following two lines don't seem to be relevant to the question.
// var tile = cc.Sprite.create(res.tile_png);
// this.addChild(tile,0);
// Use your calculated values in your function call.
// tile.setPosition(x, y);
}
}
I have problems animating part of the character 'W' that is converted to svg. This character is styled out a bit, it has like small flag at the left side (the part that I want to animate).
Right now when the animation is going, that flag is stretched vertically at the top of page. It should stay at the same position where it was, also the top and bottom line of the flag should be in parallel( like in image sample below).
Code sample:
var pathData = "M253.477,175...";
var path = new paper.Path(pathData);
var flags = {
collection:[]
}
var Flag = function(){
var model = {
startIndex:0, // start point in path.segments array
middleIndex:0,// middle point in path.segments array
endIndex:0, // end point in path.segments array
height:20, // the wave animation height
segments:[] // only flag segments
}
return model;
};
var initializeFlag = function(){
var segments = path.segments;
//...
for(var i = flag.startIndex; i <= flag.endIndex; i++ ){
flag.segments.push(segments[i]);
}
flags.collection.push(flag); //adds to flags collection
};
var doWaveAnimation = function(segment, counter, height, top, e){
var sinus = Math.sin(e.time * 3 + counter);
segment.point.y = sinus * height + top;
};
var animateFlags = function(e){
var collection = flags.collection;
for(var i = 0; i < collection.length; i++){
var flag = collection[i];
for(var s = flag.startIndex, n = flag.endIndex -1;
s < flag.middleIndex && n > flag.middleIndex -2;
s++, n--){
//top line
doWaveAnimation(flag.segments[n], n, flag.height, 180, e);
//bottom line
doWaveAnimation(flag.segments[s], s, flag.height, 200, e);
}
}
};
//...
Full code sample -> flag animation
To get greater understanding what kind of "wave" animation I want, here is also one example(at the bottom of page) -> http://paperjs.org/
EDIT
Looks like the main reason why this animation is not working properly is that both lines are not positioned horizontally but diagonally..
There's a few things you can do to make this easier:
Make the 'flag' segments linear instead curved
Create your flags so that they are N segments long and are at the end of a path. Then you can refer to them by segment index instead of matching coordinates
Store each moving segment's initial coordinates in a property
Move each segment by a ratio of it's distance from the letter form over the entire length of the flag.
Here's an example sketch
Try moving the X-coordinate of each segment with a different phase to create a more complex motion.
Well obviously a sine wave is centred on zero. So you are going to have to keep a record of all your flag Y coordinates when you loop through finding your start and end indices. Then add those Ys back in when you are doing your animation.
I have to generate random point/marker in the map which should not outside of specific country.
For canvas, I found following example
http://jsfiddle.net/6cFfU/3/
var markerPositions = [[225,175], [75,275], [150,225], [400,125], [300,300]];
var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS = "http://www.w3.org/1999/xlink";
for (var i=0; i<markerPositions.length; i++) {
// Create an SVG <use> element
var use = document.createElementNS(svgNS, "use");
// Point it at our pin marker (the circle)
use.setAttributeNS(xlinkNS, "href", "#pin");
// Set it's x and y
use.setAttribute("x", markerPositions[i][0]);
use.setAttribute("y", markerPositions[i][1]);
// Add it to the "markers" group
document.getElementById("markers").appendChild(use);
}
It adds marker but I have to generate random marker and check it should not be outside of the shape/region.
Is there any way to detect whether the random point is outside? As the above sample has simple shapes but map will have different corners/polygons?
First, you calculate the bounding box rectangle.
Then you generate random points within that rectangle.
x ==> rand(x_min,x_max)
y ==> rand (y_min, y_max)
Then you check if the point is in the polygon, and if yes add.
While not numMatchingPoints < numPointsMustHave ==> repeat
You can check if a point is in a non-overlapping n-Vertex-Polygon like this (C-Code):
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
This is called a ray-casting algorithm.
This algorithm ray-casts to the right.
In each iteration, it tests the test point against one of the polygon's edges.
The first if-statement succeeds if the point's y-coord is within the edge's scope.
The second condition checks whether the test point is to the left of the line
If both are true, then the line drawn rightwards from the test point crosses that edge.
By repeatedly inverting the value of c, the algorithm counts how many times the rightward line crosses the polygon. If it crosses an odd number of times, then the point is inside the polygon;
if it crosses an even number of times, the point is outside the polygon.
See also:
http://en.wikipedia.org/wiki/Point_in_polygon
I'm trying to make big circle and move divs along the circle's circumference.
Each div must change the content inside the big circle.
The number of div(s) must be dependent on how many are fetched from database (from table category).
I tried to do this and modified the code by putting .eq() but the problem with .eq is that next circle will appear after that circle, all put in the same place. I want them all to appear at the same time like this without repeating functions
Updated your fiddle:
http://jsfiddle.net/wyW2D/1/
Used:
var t = -1.6;
var t2 = -1.6;
var x = 0;
var t = [-1.6, -1.6, -1.6], // starting angle in radians for each circle
delta = [0.05, 0.03, 0.02], // change in radians for each circle
// e.g the first moves fastest, the last
// slowest. if this gets too big, the
// movement won't look circular, since the
// animation is really a bunch of straight lines
finish = [1.4, 1.0, 0.6]; // the stopping point in radians for each
// circle. if the circle size changes, this
// may need to change
function moveit(i) {
t[i] += delta[i]; // move the angle forward by delta
var r = 300; // radius (the .inner div is 600 x 600)
var xcenter = -30; // center X position: this reproduces the .inner horizontal
// center but from the body element
var ycenter = 420; // center Y position: same here but vertical
// Basic trig, these use sin/cos to find the vert and horiz offset for a given
// angle from the center (t[i]) and a given radius (r)
var newLeft = Math.floor(xcenter + (r * Math.cos(t[i])));
var newTop = Math.floor(ycenter + (r * Math.sin(t[i])));
// Now animate to the new top and left, over 1ms, and when complete call
// the move function again if t[i] hasn't reached the finish.
$('div.circle'+(i+1)).animate({
top: newTop,
left: newLeft,
},1, function() {
if (t[i] < finish[i]) moveit(i);
});
// You can slow down the animation by increasing the 1, but that will eventually
// make it choppy. This plays opposite the delta.
}
// Start the ball rolling
$("document").ready(function(e) {
moveit(0);
moveit(1);
moveit(2);
});
This was a quick change to reduce the code to one function that used arrays (t, delta, finish) to keep track of the three circles. It could be improved to accept arbitrary circles, of any size, at any starting / ending angle.
Also, this kind of animation is much easier with CSS. It is simple to specify and has much better performance.