Alright, I have a HTML canvas with a bunch of circles on it. I want mouseclick events on circles to trigger some Javascript function. I already have the basics, but the coordinates are obviously so precise that it takes me like 30 times to hit the exact coordinates of a certain circle.
Is there a way I could implement an "about equal to"; in other words, I would like the x and y of the mouseclick to trigger a function when it's pretty close to (let's say 10px) the coordinates of something on canvas?
Thanks
Alex
You can use something like this to test if one point is within a certain radius of another point:
function withinRadius (x1, y1, x2, y2, radius) {
var dX = x1 - x2, dY = y1 - y2;
return ((dX*dX) + (dY*dY) < radius*radius);
}
First thoughts:
if ((mouselocx >= (corodinatex - 10)) && (mouselocx <= (corodinatex + 10)) {
if ((mouselocy >= (corodinatey - 10)) && (mouselocy <= (corodinatey + 10)) {
Do something...
}
}
General case, you want to check if you have clicked within a polygon created by expanding your curve outward in both left and right directions. Calculation of this polygon in the case of bezier curves, general conic sections, etc. is tricky. Most graphic libraries allow you to set a stroke-width parameter and do it for you. Draw a wide curve in background color below your 1px curve and check for hits on the wide one. Just make sure you draw all the background color ones before any of the foreground color ones.
In your specific case of circles, if you don't have such a graphic library, it will suffice to see if you have clicked within your tolerance of a distance from the circle center. If you have a very small number of circles you can go through the whole list. If you have more than a half dozen (gut feel for when to cut over to better algorithm) divide the screen up into quarters with a list of which circles a hit in one of the rectangles might have hit, then divide into quarters within that rectangle and check with circles it might be until you have just a half dozen or so possibilities. Then go down the list of possibilities checking if you are within your delta for any of the circles.
Related
I'm currently working on a mini map for a game in which keeps track of different items of importance on and off the screen. When I first created the mini map through a secondary camera rendered onto a texture and displayed on screen in a miniature display, it was rectangle shape. I was able to ensure when the item of importance left the view of the map, an arrow pointing to the target showed up and remained on the edge of the map. It was basically clamping the x & y positions of the arrow to half the camera view's width and length (with some suitable margin space).
Anyway. Now I am trying to make the mini map circular and while I have the proper render mask on to guarantee that shape of the mini map, I am having difficulties in clamping the arrows to the shape of the new mini-map. In the rectangular mini map, the arrows stayed in the corners while clamped, but obviously, circles don't have corners.
I am thinking clamping the arrow's x & y positions have to do with the radius of the circle (half of the height of the screen/minimap), but because I'm a little weak on the math side, I am kindly requesting some help. How would I clamp the arrows to the edge of a new circle shape?
The code I have now is as follows:
let {width: canvasWidth, height: canvasHeight} = cc.Canvas.instance.node, // 960, 640
targetScreenPoint = cc.Camera.main.getWorldToScreenPoint(this.targetNode.position)
// other code for rotation of arrow, etc...
// FIXME: clamp the the edge of the minimap mask which is circular
// This is the old clamping code for a rectangle shape.
let arrowPoint = targetScreenPoint;
arrowPoint.x = utils.clamp(arrowPoint.x, (-canvasWidth / 2) + this.arrowMargin,
(canvasWidth / 2) - this.arrowMargin);
arrowPoint.y = utils.clamp(arrowPoint.y, (-canvasHeight / 2) + this.arrowMargin,
(canvasHeight /2) - this.arrowMargin);
this.node.position = cc.v2(arrowPoint.x, arrowPoint.y);
I should probably also note that all mini-map symbols and arrows technically are on screen but only are displayed in on the secondary camera through a culling mask... you know, just in case it helps.
Just for anyone else looking to do the same, I basically normalized the direction from the target node that the arrow points at and multiplied it by the radius of the image mask (with appropriate margin space).
Since the player node and the centre of the mask is at origin, I just got the difference from the player. The (640/2) is the diameter, which of course, shouldn't be hardcoded, but meh for now. Thanks to those who commented and got me thinking in the right direction.
let direction = this.targetNode.position.sub(this.playerNode.position).normalize();
let arrowPos = direction.mul((640/2) - this.arrowMargin);
this.node.position = arrowPos;
I'm making a diagramming library in Blazor which uses HTML nodes and SVG links. I am wondering how can I draw links between two nodes when they aren't always rectangular.
All the solutions I find are based on nodes that are rectangles/squares, where it's easy to draw a link on the borders (or even the center, but only works for direct links).
But what about nodes that have custom stuff in them that makes them non rectangular, for example a div with border-radius: 50%?
One possible solution is to draw the lines from/to the center of the elements, but that would only work with simple lines, curved lines would look weird.
In this example:
How does arrow position get calculated?
You need to have an container, width and height of the container, then inside the container find the x / y point of the element that you want to connect and draw a line to the next elements x / y point, the x/y points can be calculated using x,y,w,h of the element, for an example x:100 y:100 w:100 h:100 the center point sits at x:150, y:150 x = x + ( w / 2 ), y = y + ( h / 2 ).. using math just calculate the point of connection of the elements, the complexity of math for calculating the connection point is in the shape of the element, for each different shape you need a different calculation metod if not in center
I'm trying to use brownian motion to create a group of random moving particles.
http://jsfiddle.net/J75Em/16/
So far I've got the particles moving randomly but I'm not sure how to set the forward direction to make it look more natural.
I've tried to use the change in x and y axis to calculate rotation using atan, you can see this by uncommenting rotate but this doesn't seem to perform well.
Is this the right approach for this type of movement? thanks;
This is pretty neat!
You are sort of going about it the right way but you should actually use the atan2 function. This removes the need for any 0 checks.
The atan2 function gives you an angle which is anticlockwise from the positive x vector
(1, 0) --->
The bees are 90 degrees off from this starting angle so you must subtract 90 degrees from the direction. (depending on which way round you do the dy and dx calculation, you might need to add)
You could find that the direction changes rapidly, so you could consider limiting the next change to a set of changes that cause an angle change below some threshold. This will make the movement a little smoother.
I would actually go about it by generating an angle between say -pi/8 and pi/8 radians, and a random length. Essentially using polar coordinates. Then add this new random polar offset to the x and y position like
newX = currentX + (randomLength * cos(randomAngle + currentAngle)) and
newY = currentY + (randomLength * sin(randomAngle + currentAngle))
If you work with angles you can also get more natural effects like if you want the bees to stay within a certain area, you can force a bias towards the center of the area as they get closer and closer to the edge.
Update:
So I've taken a closer look. The trouble is that you expect .rotate to set the rotation when it actually adds to the rotation
There are 2 options for fixing this.
Rotate by the difference between the previous and the current angle
Set the rotation using the .transform method
You can see solution 2 in action here http://jsfiddle.net/c5A2A/
Manipulating the slider until the end, the circle that represents the star disappears or does a different motion. See: jsfiddle.net/NxNXJ/13 Unlike this: astro.unl.edu/naap/hr/animations/hrExplorer.html
Can you help me?? Thanks
When you supply a big luminosity, You're rendering a circle which is millions of pixels tall. The broswer might not render it because it's so big.
However, you are really only interested in a small slice of that big circle - namely, the bit that fits in your tiny window.
At some point, it doesn't make sense to increase the size of the circle, since you can't observe a change in the curvature of the circle - it just looks like a straight vertical line.
This apparent verticality occurs around when x^2 + y^2 = R^2, where R is the radius of the star, Y is half the height of your window, and x is R-1. Solve for R in terms of Y, and you get
function maximumNecessaryRadius(windowHeight){
y = windowHeight / 2;
maxRadius = (y*y - 1)/2;
return Math.round(maxRadius);
}
When resizing the star, check to make sure that its radius doesn't exceed the maximum necessary radius. Rendering it any larger than that is overkill.
Example Implementation
For example it may be used in the application of manually adjusting the hands of the clock. I guess it probably involves translating the needle (to make the end point of the needle the centre of rotation) then rotating it, then translating the needle again.
But since the needle listens to the mouse event all the time, the 1st mouse event will be captured. The result is that the needle ends up being translated and not rotated at all. Mouse event is impossible to debug too...
Any idea or code snippets that I can refer to? Using Javascript or CSS to rotate both fine.
In your example, you will want to calculate the angle between the centre of the clock face (black dot), and the current mouse position (red dot), relative to the Y axis (cardinal north if you imagine a compass).
If I remember my trig correctly, you can calculate this by using the following:
var angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
// alter the angle to be relative to Y axis instead of X
angle += 90;
if(angle < 0) { angle = 360 + angle; }
In the formula, x and y are the coordinates of the two points, one of which you will know (it is the centre of the clock face), and the other you can get from the mouse move event.
Once you have the angle, you can simply translate to the the centre of the circle, rotate the canvas by the calculated amount, and draw the hand.
Update: I created a jsfiddle to illustrate the angle calculation:
http://jsfiddle.net/DAEpy/1/