I'm trying to change background RGB according to mouse position. Here you can see the example http://rockit.folio.su/gexans/
There are no problems with first two numbers, they are horizontal and vertical axes. But there is a problem with 3rd number which must be relative to the diagonal of the document. And I figured out that it's because i receive the number according to X and Y mouse position, but I need it according to how close the mouse is to the diagonal of the document and not a mouse-made rectangle.
Here is the code
function mousePage(e){
var x = 0, y = 0, z =0;
if (!e) e = window.event;
x = e.pageX;
y = e.pageY;
z = Math.sqrt(Math.pow(x,2) + Math.pow(y,2));
return {"x":x, "y":y, "z":z};
}
$(window).load(function(){
$(document).mousemove(function(e) {
var widthStep = $(document).width() / 256;
var heightStep = $(document).height() / 256;
var diagonalStep = Math.sqrt(Math.pow($(document).width(),2) + Math.pow($(document).height(),2)) / 256;
var mCur = mousePage(e);
var colorX = Math.floor( Number(mCur.x) / Number(widthStep) );
var colorY = Math.floor( Number(mCur.y) / Number(heightStep) );
var colorZ = Math.floor( Number(mCur.z) / Number(diagonalStep));
var hue = 'rgb(' + colorX + ',' + colorY + ',' + colorZ + ')';
$("body").css({backgroundColor: hue});
});
});
Ok, so now I have a formula for the distance from cursor to the line like this
var numerator = Math.abs( ( A * m ) + ( B * n ) + C );
var denominator = Math.sqrt( Math.pow( A, 2 ) + Math.pow( B, 2 ) );
var d = numerator / denominator;
And I suppose that now I need to calculate the distance to top right, divide it by 256 = dStep, then distance to top right - var d and divide it by dStep = mColorZ and after that colorZ - mColorZ = the value that I need for my third colour?
And what is even more important, I have no idea what are the values for A, B, and C.
z=x*y/oldz; //the distance close from mouse to the diagonal, is this u want?
I'm not sure if this is what I want. What does this formula do?)
Update
Right now I'm having this but it gives me Zero on the diagonal.
var width = $(document).width();
var height = $(document).height();
var widthStep = $(document).width()/256;
var heightStep = $(document).height()/256;
var diagonalStep = Math.sqrt(Math.pow(width,2)+Math.pow(height,2))/256;
var mCur = mousePage(e);
var numerator = Math.abs((height*Number(mCur.x))+(width*Number(mCur.y))+0);
var denominator = Math.sqrt(Math.pow(height,2)+Math.pow(width,2));
var d = numerator/denominator;
var vp_numerator = Math.abs((height*width)+(width*height)+0);
var vp_denominator = Math.sqrt(Math.pow(height,2)+Math.pow(width,2));
var vp_d = vp_numerator/vp_denominator;
var vp_dStep = vp_d/256;
var m_colorZ = Math.floor(Number(d)/Number(vp_dStep));
var colorX = Math.floor(Number(mCur.x)/Number(widthStep));
var colorY = Math.floor(Number(mCur.y)/Number(heightStep));
var colorZ = Math.floor(Number(mCur.z)/Number(diagonalStep)) - m_colorZ;
var hue = 'rgb(' + colorX + ',' + colorY + ',' + colorZ + ')';
$("body").css({backgroundColor: hue});
Update
Ok, it's great that I have now the distance of cursor from the diagonal line. But now I need to have position of cursor ON the diagonal, if it's top-right part of the screen it's vertical line from cursor crossing the diagonal reltive to X, lower-left - horizontal relative to Y.
And after that position on the line - distance from the line = color.
Update #2
I decided to finish it, but I got not the cool version but just a simple one. The third value always depends on hypotenuse. Very simple. Here's the code.
function rgbchange(target, source){
var widthStep = source.width() / 256,
heightStep = source.height() / 256,
diagonal = Math.sqrt( Math.pow( source.width(), 2 ) + Math.pow( source.height(), 2 ) ),
diagonalStep = diagonal / 256,
colorX,
colorY,
colorZ,
newDiagonal,
hue;
source.on('mousemove', function( event ){
colorX = Math.floor( event.pageX / widthStep ),
colorY = Math.floor( event.pageY / heightStep );
newDiagonal = Math.sqrt( Math.pow( event.pageY, 2 )+ Math.pow( event.pageX, 2 ) );
colorZ = 255 - Math.floor( ( diagonal - newDiagonal ) / diagonalStep );
hue = 'rgb(' + colorX + ',' + colorY + ',' + colorZ + ')';
target.css({'background-color': hue});
});
}
The example
z = Math.sqrt(Math.pow(x,2) + Math.pow(y,2));
This is saying that the value z is the length of the line between the mouse and the upper-left-hand corner. I'm not sure what you mean by "distance from the diagonal of the document", but if you really want the closest distance to the line which looks like this:
____
|\ .| <-- hypothetical point (.)
| \/ | <-- perpendicular line
| \ |
| \|
Then you can use the formula for the closest line to a plane (google for formula for distance of point from line).
var oldz=Math.sqrt(Math.pow(x,2) + Math.pow(y,2));
z=x*y/oldz; //the distance close from mouse to the diagonal, is this u want?
Related
I have a for loop that returns a decimal between 0 and 1. I'd like to make a curve that appears more like a rounded corner than it is now. I'd also like to have it start ramping up only after 0.25. I can't quite figure out how to do it with the math I have now. I'm using Math.log and a linear conversion function, but maybe I need something more related to a parabolic curve.
for (i = 1; i < 101; ++i) {
var dec = i / 100
if (dec >= 0.25) {
console.log("dec = " + dec);
var large = i * 100
var log = Math.log(large);
console.log("log = " + log);
var linCon = applyLinearConversion(log, 2.8, 9.2104, -2.7, 1)
console.log("linCon " + i + " = " + linCon);
document.getElementById("graph").innerHTML += "<div style='background-color:#000000; width:" + (linCon * 1000) + "px; height:5px;'></div>";
}
}
function applyLinearConversion(OldValue, OldMin, OldMax, NewMin, NewMax) {
OldRange = (OldMax - OldMin)
if (OldRange == 0)
NewValue = NewMin
else {
NewRange = (NewMax - NewMin)
NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
}
return NewValue
}
<div id="graph"></div>
I have it populating a div with more styled divs.
Mine is like this:
I want mine more like this:
You can use the formula of the half circle graph which is:
It results in the following graph:
Since you are using horizontal divs that are stacked vertically to draw the graph, the x and y coordinates will be reversed and the left quarter of the circle will be used from the above graph.
var width = 200; // the width of the graph
var height = 200; // the height of the graph
var xOffset = 0.25 * width; // the x offset at which the graph will start ramping up (this offset is added to the graph width)
var html = ""; // to accumulate the generated html before assigning it to innerHTML (it's not a good idea to constantly update innerHTML)
for (i = 1; i < 101; ++i) {
var x = 1 - i / 100; // the x coordinate, we are using the left side of the graph so x should be negative going from -1 to 0
var y = Math.sqrt(1 - x * x); // the y coordinate as per the formula (this will be used for the width)
html += "<div style='background-color:#000000; width:" + (xOffset + y * width) + "px; height:" + (height / 100) + "px;'></div>";
}
document.getElementById("graph").innerHTML = html;
<div id="graph"></div>
I'm using Highmaps to create a flight path chart, using their demo Simple flight routes (jsfiddle) as a starting point. When I update the code to use a world map the line paths between locations/markers become distorted with an exaggerated curve.
See my jsfiddle where I have only modified from the demo to the following:
HTML
<!-- line 5 -->
<script src="https://code.highcharts.com/mapdata/custom/world.js"></script>
JavaScript
// line 39
mapData: Highcharts.maps['custom/world'],
// line 47
data: Highcharts.geojson(Highcharts.maps['custom/world'], 'mapline'),
See the difference between both where before is the Highcharts demo and after is my few changes as noted above:
The paths are calculated through function pointsToPath which uses quadratic Bézier curve Q in SVG to curve the line drawn between markers.
// Function to return an SVG path between two points, with an arc
function pointsToPath(from, to, invertArc) {
var arcPointX = (from.x + to.x) / (invertArc ? 2.4 : 1.6),
arcPointY = (from.y + to.y) / (invertArc ? 2.4 : 1.6);
return 'M' + from.x + ',' + from.y + 'Q' + arcPointX + ' ' + arcPointY +
',' + to.x + ' ' + to.y;
}
If I modify the function to always divide by 2 for arc points x and y then I get a straight line between markers:
var arcPointX = (from.x + to.x) / 2,
arcPointY = (from.y + to.y) / 2;
I'm not sure of the math to get a smaller, less exaggerated curve.
Ideally I would like for the line to be symmetrical as per an example from MDN - Paths:
<svg width="190" height="160" xmlns="http://www.w3.org/2000/svg">
<path d="M 10 80 Q 95 10 180 80" stroke="black" fill="transparent"/>
</svg>
Using world map data, how do I calculate line paths between markers to appear with a smaller or symmetrical curve?
You just need to get your denominator closer to 2.0 as when it is 2.0 is a perfectly straight line: https://jsfiddle.net/my7bx50p/1/
So I chose 2.03 and 1.97 and that gives you much "softer" curves. Hope that helps.
function pointsToPath(from, to, invertArc) {
var arcPointX = (from.x + to.x) / (invertArc ? 2.03 : 1.97),
arcPointY = (from.y + to.y) / (invertArc ? 2.03 : 1.97);
return 'M' + from.x + ' ' + from.y + 'Q' + arcPointX + ' ' + arcPointY + ' ' + to.x + ' ' + to.y;
}
UPDATE:
I tried to focus in only on the math: https://jsfiddle.net/9gkvhfuL/1/
I think the math is now correct:
Which back to the real example: https://jsfiddle.net/my7bx50p/6/
Gives, I believe, the desired outcome :):
From the code (https://jsfiddle.net/my7bx50p/6/):
function pointsToPath(from, to, invertArc) {
var centerPoint = [ (from.x + to.x) / 2, (from.y + to.y) / 2];
var slope = (to.x - from.x) / (to.y - from.y);
var invSlope = -1 / slope;
var distance = Math.sqrt( Math.pow((to.x - from.x), 2) + Math.pow((to.y - from.y), 2) );
if (Math.abs(slope) > Math.abs(invSlope) ){
//then we should offset in the y direction
var offset = (invertArc ? -1 : 1) * 2 * Math.sqrt(distance);
var min_slope = Math.min( Math.abs(slope), Math.abs(invSlope) );
var final_slope = Math.max(min_slope, 1);
var offsetCenter = [centerPoint[0] + (offset * (1/slope)), centerPoint[1] + offset];
//console.log(centerPoint, slope, invSlope, distance);
var arcPointX = offsetCenter[0], //(from.x + to.x) / (invertArc ? 2.03 : 1.97),
arcPointY = offsetCenter[1] //(from.y + to.y) / (invertArc ? 2.03 : 1.97);
} else{ //invSlope <= slope
//then we should offset in the x direction
var offset = (invertArc ? -1 : 1) * 2 * Math.sqrt(distance);
var min_slope = Math.min( Math.abs(slope), Math.abs(invSlope) );
var final_slope = Math.max(min_slope, 1);
var offsetCenter = [centerPoint[0] + offset, centerPoint[1] + (offset * (1/invSlope))];
//console.log(centerPoint, slope, invSlope, distance);
var arcPointX = offsetCenter[0], //(from.x + to.x) / (invertArc ? 2.03 : 1.97),
arcPointY = offsetCenter[1] //(from.y + to.y) / (invertArc ? 2.03 : 1.97);
}
return 'M' + from.x + ' ' + from.y + 'Q' + arcPointX + ' ' + arcPointY +
' ' + to.x + ' ' + to.y;
}
UPDATE 2: (to try to explain the math and clean up the code)
Check out the Math Fiddle: https://jsfiddle.net/alexander_L/dcormfxy/53/
The solid black line between the two points is the straight line between them and it also has the corresponding slope (used in the code later). I also drew a centre point on each line. Then I drew the inverse slope as a dotted line (also used in the code) The inverse slope is by definition perpendicular to the slope and is related by invSlope = -1/slope. From this, we are now set up to find the perpendicular points to the left or right of the centre point, that will become the centre of our symmetrical arcs. We do this by first figuring out if the slope is greater than the inverse slope or if the inverse slope is greater than the slope (absolute values). This is only necessary because when we have a perfectly horizontal or perfectly vertical line then the slope is zero and undefined respectively and then our math doesn't work. (remember slope = (y2 - y1)/(x2 - x1) so when the line is vertical y-changes but x-doesn't so x2 = x1 and then the denominator is zero and gives us undefined slope)
Let's think about line C from : {x: 40, y: 40}, to : {x: 220, y: 40}
slope = (y2 - y1)/(x2 - x1)
slope = (40 - 40)/(220 - 40)
slope = 0 / 180
slope = 0
invSlope = -1/slope
invSlope = undefined
This is why we need to have the two cases (the if else) in the code as whenever we get slope or invSlope as undefined the math is not going to work. So now, although slope is zero, it is greater than invSlope (undefined). (note SVGs are upside down compared to normal charts and how we think about them so it requires your brain to keep that in mind, otherwise, it's easy to get lost)
So now we can offset the centre point in the y-direction and then figure out how much we have to offset in the x-direction. If you had a line with slope 1, then you would offset the same in the x and the y-directions because the slope of the line is 1 (line makes a 45-degree angle with the x-axis) and so moving perpendicularly away from that line is achieved just by moving for example 5 in the x-direction and -5 in the y-direction.
Luckily, with this edge case (slope = 0), then we just move in the y-direction and the x-direction offset = 0. Look at line C in the math example and you can see what I mean, to move perpendicularly, we just move either positive or negative y-direction from the centre point. From the code:
offsetCenter = [centerPoint[0] + (offset * (1/slope)), centerPoint[1] + offset];
So as I said, we offset in the y-direction from the centerPoint and the term + (offset * (1/slope)) will be zero here because 1/slope is undefined. We can chose to offset "left" or "right" by the function's argument invertArc which is used in this line: var offset = (invertArc ? -1 : 1) * 2 * Math.sqrt(distance); which basically means move postive or negative direction away from the centerPoint in a magnitude equal to two times the square root of the distance between the points. I settled on two times the square root of the distance between the points because this gives us an offsetCenter of our arc that gives similarly soft curves for all lines both short and long.
Now, let's think about line A from : {x: 40, y: 40}, to : {x: 320, y: 360}
slope = (y2 - y1)/(x2 - x1)
slope = (360 - 40)/(320 - 40)
slope = 320 / 280
slope = 1.143
invSlope = -1/slope
invSlope = -0.875
Final cleaned up code and real example here https://jsfiddle.net/alexander_L/o43ka9u5/4/:
function pointsToPath(from, to, invertArc) {
var centerPoint = [ (from.x + to.x) / 2, (from.y + to.y) / 2];
var slope = (to.x - from.x) / (to.y - from.y);
var invSlope = -1 / slope;
var distance = Math.sqrt( Math.pow((to.x - from.x), 2) + Math.pow((to.y - from.y), 2) );
var arcPointX = 0;
var arcPointY = 0;
var offset = 0;
var offsetCenter = 0;
if (Math.abs(slope) > Math.abs(invSlope) ){
//then we should offset in the y direction (then calc. x-offset)
offset = (invertArc ? -1 : 1) * 2 * Math.sqrt(distance);
offsetCenter = [centerPoint[0] + (offset * (1/slope)), centerPoint[1] + offset];
arcPointX = offsetCenter[0]
arcPointY = offsetCenter[1]
} else{ //invSlope >= slope
//then we should offset in the x direction (then calc. y-offset)
offset = (invertArc ? -1 : 1) * 2 * Math.sqrt(distance);
offsetCenter = [centerPoint[0] + offset, centerPoint[1] + (offset * (1/invSlope))];
arcPointX = offsetCenter[0]
arcPointY = offsetCenter[1]
}
return 'M' + from.x + ' ' + from.y + 'Q' + arcPointX + ' ' + arcPointY +
' ' + to.x + ' ' + to.y;
}
UPDATE 3:
I figured out how to remove the need for the if else control flow / switch statement by using trigonometry instead. I hope my sketch helps explain the logic, you might also want to read some stuff (https://study.com/academy/lesson/sohcahtoa-definition-example-problems-quiz.html) etc. as I would struggle to explain briefly here (and I am already writing an essay here :) so will not explain SOH CAH TOA etc.)
This makes the core function code like this (Math only - https://jsfiddle.net/alexander_L/dcormfxy/107/) (full example - https://jsfiddle.net/alexander_L/o43ka9u5/6/):
function pointsToPath(from, to, invertArc) {
const centerPoint = [ (from.x + to.x) / 2, (from.y + to.y) / 2];
const slope = (to.y - from.y) / (to.x - from.x);
const invSlope = -1 / slope;
const distance = Math.sqrt( Math.pow((to.x - from.x), 2) + Math.pow((to.y - from.y), 2) );
const offset = (invertArc ? -1 : 1) * 2 * Math.sqrt(distance);
const angle = Math.atan(slope);
//Math.cos(angle) = offsetY/offset;
//Math.sin(angle) = offsetX/offset;
const offsetY = Math.cos(angle)*offset;
const offsetX = Math.sin(angle)*offset;
//if slope = 0 then effectively only offset y-direction
const offsetCenter = [centerPoint[0] - offsetX, centerPoint[1] + offsetY];
const arcPointX = offsetCenter[0]
const arcPointY = offsetCenter[1]
return 'M' + from.x + ' ' + from.y + 'Q' + arcPointX + ' ' + arcPointY +
' ' + to.x + ' ' + to.y;
}
I believe this code is more elegant, cleaner and more robust and mathematically valid :) Thanks also Ash for the tips on Const & Let use versus var.
This also gives the final result:
I have a page that shows a grid of job positions and I am showing the progression from one to another by using SVG + paths to draw the connection between boxes.
My code is working just fine when I am connecting an element at the top to one at the bottom. It is finding the XY of the top box and the XY of the bottom box and connects the two.
My issue is I want to flip this code and go from the bottom up. This means I need the top XY of the bottom element and the bottom XY of the top element and draw the path.
I have been trying to flip offsets around and basically do the opposite of what is working but I think my math is wrong somewhere.
Here is what the top down approach looks like. Works just fine.
The bottom up approach however is not correct. Theres some math errors somewhere and the calculations are causing the SVG to be cut off.
I believe the answer lies within the connectElements() function as that is where the coordinates are determined.
Any thoughts on how I can get these calculations corrected?
Fiddle: http://jsfiddle.net/Ly59a2hf/2/
JS Code:
function getOffset(el) {
var rect = el.getBoundingClientRect();
return {
left: rect.left + window.pageXOffset,
top: rect.top + window.pageYOffset,
width: rect.width || el.offsetWidth,
height: rect.height || el.offsetHeight
};
}
function drawPath(svg, path, startX, startY, endX, endY) {
// get the path's stroke width (if one wanted to be really precize, one could use half the stroke size)
var style = getComputedStyle(path)
var stroke = parseFloat(style.strokeWidth);
// check if the svg is big enough to draw the path, if not, set heigh/width
if (svg.getAttribute("height") < endY) svg.setAttribute("height", endY);
if (svg.getAttribute("width") < (startX + stroke)) svg.setAttribute("width", (startX + stroke));
if (svg.getAttribute("width") < (endX + stroke * 3)) svg.setAttribute("width", (endX + stroke * 3));
var deltaX = (endX - startX) * 0.15;
var deltaY = (endY - startY) * 0.15;
// for further calculations which ever is the shortest distance
var delta = deltaY < absolute(deltaX) ? deltaY : absolute(deltaX);
// set sweep-flag (counter/clock-wise)
// if start element is closer to the left edge,
// draw the first arc counter-clockwise, and the second one clock-wise
var arc1 = 0;
var arc2 = 1;
if (startX > endX) {
arc1 = 1;
arc2 = 0;
}
// draw tha pipe-like path
// 1. move a bit down, 2. arch, 3. move a bit to the right, 4.arch, 5. move down to the end
path.setAttribute("d", "M" + startX + " " + startY +
" V" + (startY + delta) +
" A" + delta + " " + delta + " 0 0 " + arc1 + " " + (startX + delta * signum(deltaX)) + " " + (startY + 2 * delta) +
" H" + (endX - delta * signum(deltaX)) +
" A" + delta + " " + delta + " 0 0 " + arc2 + " " + endX + " " + (startY + 3 * delta) +
" V" + (endY - 30));
}
function connectElements(svg, path, startElem, endElem, type, direction) {
// Define our container
var svgContainer = document.getElementById('svgContainer'),
svgTop = getOffset(svgContainer).top,
svgLeft = getOffset(svgContainer).left,
startX,
startY,
endX,
endY,
startCoord = startElem,
endCoord = endElem;
console.log(svg, path, startElem, endElem, type, direction)
/**
* bottomUp - This means we need the top XY of the starting box and the bottom XY of the destination box
* topDown - This means we need the bottom XY of the starting box and the top XY of the destination box
*/
switch (direction) {
case 'bottomUp': // Not Working
// Calculate path's start (x,y) coords
// We want the x coordinate to visually result in the element's mid point
startX = getOffset(startCoord).left + 0.5 * getOffset(startElem).width - svgLeft; // x = left offset + 0.5*width - svg's left offset
startY = getOffset(startCoord).top + getOffset(startElem).height - svgTop; // y = top offset + height - svg's top offset
// Calculate path's end (x,y) coords
endX = endCoord.getBoundingClientRect().left + 0.5 * endElem.offsetWidth - svgLeft;
endY = endCoord.getBoundingClientRect().top - svgTop;
break;
case 'topDown': // Working
// If first element is lower than the second, swap!
if (startElem.offsetTop > endElem.offsetTop) {
var temp = startElem;
startElem = endElem;
endElem = temp;
}
// Calculate path's start (x,y) coords
// We want the x coordinate to visually result in the element's mid point
startX = getOffset(startCoord).left + 0.5 * getOffset(startElem).width - svgLeft; // x = left offset + 0.5*width - svg's left offset
startY = getOffset(startCoord).top + getOffset(startElem).height - svgTop; // y = top offset + height - svg's top offset
// Calculate path's end (x,y) coords
endX = endCoord.getBoundingClientRect().left + 0.5 * endElem.offsetWidth - svgLeft;
endY = endCoord.getBoundingClientRect().top - svgTop;
break;
}
// Call function for drawing the path
drawPath(svg, path, startX, startY, endX, endY, type);
}
function connectAll(direction) {
var svg = document.getElementById('svg1'),
path = document.getElementById('path1');
// This is just to help with example.
if (direction == 'topDown') {
var div1 = document.getElementById('box_1'),
div2 = document.getElementById('box_20');
} else {
var div1 = document.getElementById('box_20'),
div2 = document.getElementById('box_1');
}
// connect all the paths you want!
connectElements(svg, path, div1, div2, 'line', direction);
}
//connectAll('topDown'); // Works fine. Path goes from the bottom of box_1 to the top of box_20
connectAll('bottomUp'); // Doesn't work. I expect path to go from top of box_20 to the bottom of box_1
IMO, you can simplify things by making the SVG the exact right size. Ie. fit it between the two elements vertically, and have it start at the leftmost X coord.
If you do that, the path starts and ends at either:
X: 0 or svgWidth
Y: 0 or svgHeight.
Then as far as drawing the path goes, it's just a matter of using the relative directions (startX -> endX and startY -> endY) in your calculations. I've called these variables xSign and ySign. If you are consistent with those, everything works out correctly.
The last remaining complication is working out which direction the arcs for the rounded corners have to go - clockwise or anticlockwise. You just have to work out the first one, and the other one is the opposite.
function getOffset(el) {
var rect = el.getBoundingClientRect();
return {
left: rect.left + window.pageXOffset,
top: rect.top + window.pageYOffset,
width: rect.width || el.offsetWidth,
height: rect.height || el.offsetHeight
};
}
function drawPath(svg, path, start, end) {
// get the path's stroke width (if one wanted to be really precise, one could use half the stroke size)
var style = getComputedStyle(path)
var stroke = parseFloat(style.strokeWidth);
var arrowHeadLength = stroke * 3;
var deltaX = (end.x - start.x) * 0.15;
var deltaY = (end.y - start.y) * 0.15;
// for further calculations which ever is the shortest distance
var delta = Math.min(Math.abs(deltaX), Math.abs(deltaY));
var xSign = Math.sign(deltaX);
var ySign = Math.sign(deltaY);
// set sweep-flag (counter/clock-wise)
// If xSign and ySign are opposite, then the first turn is clockwise
var arc1 = (xSign !== ySign) ? 1 : 0;
var arc2 = 1 - arc1;
// draw tha pipe-like path
// 1. move a bit vertically, 2. arc, 3. move a bit to the horizontally, 4.arc, 5. move vertically to the end
path.setAttribute("d", ["M", start.x, start.y,
"V", start.y + delta * ySign,
"A", delta, delta, 0, 0, arc1, start.x + delta * xSign, start.y + 2 * delta * ySign,
"H", end.x - delta * xSign,
"A", delta, delta, 0, 0, arc2, end.x, start.y + 3 * delta * ySign,
"V", end.y - arrowHeadLength * ySign].join(" "));
}
function connectElements(svg, path, startElem, endElem, type, direction) {
// Define our container
var svgContainer = document.getElementById('svgContainer');
// Calculate SVG size and position
// SVG is sized to fit between the elements vertically, start at the left edge of the leftmost
// element and end at the right edge of the rightmost element
var startRect = getOffset(startElem),
endRect = getOffset(endElem),
pathStartX = startRect.left + startRect.width / 2,
pathEndX = endRect.left + endRect.width / 2,
startElemBottom = startRect.top + startRect.height,
svgTop = Math.min(startElemBottom, endRect.top + endRect.height),
svgBottom = Math.max(startRect.top, endRect.top),
svgLeft = Math.min(pathStartX, pathEndX),
svgHeight = svgBottom - svgTop;
// Position the SVG
svg.style.left = svgLeft + 'px';
svg.style.top = svgTop + 'px';
svg.style.width = Math.abs(pathEndX - pathStartX) + 'px';
svg.style.height = svgHeight + 'px';
// Call function for drawing the path
var pathStart = {x: pathStartX - svgLeft, y: (svgTop === startElemBottom) ? 0 : svgHeight};
var pathEnd = {x: pathEndX - svgLeft, y: (svgTop === startElemBottom) ? svgHeight : 0};
drawPath(svg, path, pathStart, pathEnd);
}
function connectAll(direction) {
var svg = document.getElementById('svg1'),
path = document.getElementById('path1');
// This is just to help with example.
if (direction == 'topDown') {
var div1 = document.getElementById('box_1'),
div2 = document.getElementById('box_20');
} else {
var div1 = document.getElementById('box_20'),
div2 = document.getElementById('box_1');
}
// connect all the paths you want!
connectElements(svg, path, div1, div2, 'line');
}
//connectAll('topDown');
connectAll('bottomUp');
http://jsfiddle.net/93Le85tk/3/
Ok, I have two positions in 3d space:
var fromX = 1,
fromY = 2,
fromZ = 3,
toX = 15,
toY = 16,
toZ = 17;
Then I need to calculate the current position, when someone/something is moving in a straight line from the from-coordinates, to the to-coordinates. I know the distance left is 2, what would be the formula for calculating the current position?
I guess this is more of a math question than a javascript question, but it is for a javascript application, so I'm hoping that is not a problem.
Given two points, fromPt and toPt, the distance between two points can easily be calculated:
distanceX = Math.pow(fromPt.x - toPt.x, 2)
distanceY = Math.pow(fromPt.y - toPt.y, 2)
distanceZ = Math.pow(fromPt.z - toPt.z, 2)
total_distance = Math.sqrt(distanceX + distanceY + distanceZ)
and now finding the correct point along the line is just a case of correct interpolation :)
newPt = {}
newPt.x = fromPt.x + ((toPt.x - fromPt.x) * (wantedDistance / total_distance))
newPt.y = fromPt.y + ((toPt.y - fromPt.y) * (wantedDistance / total_distance))
newPt.z = fromPt.z + ((toPt.z - fromPt.z) * (wantedDistance / total_distance))
There are already 2 answers with the correct algorithm, this one's no different, just a bit neater.
// Distance between two points is the square root of the sum
// of the squares of the differences
function get3dDistance(startCoords, endCoords) {
var dx = Math.pow((startCoords[0] - endCoords[0]), 2);
var dy = Math.pow((startCoords[1] - endCoords[1]), 2);
var dz = Math.pow((startCoords[2] - endCoords[2]), 2);
return Math.sqrt(dx + dy + dz);
}
// The coordinates of a point some distance from the end is
// proportional to the distance left and total distance.
function getCoordsFromDistanceLeft(startCoords, endCoords, distanceLeft) {
var distance = get3dDistance(startCoords, endCoords);
var f = (distance - distanceLeft)/distance;
return [startCoords[0] + f*(endCoords[0] - startCoords[0]),
startCoords[1] + f*(endCoords[1] - startCoords[1]),
startCoords[2] + f*(endCoords[2] - startCoords[2])];
}
// Test case
var start = [1,2,3];
var end = [15,16,17];
var distanceLeft = 2;
// Distance between the two points
var dist = get3dDistance(start, end)
document.write('distance: ' + dist + '<br>');
// distance: 24.24871130596428
// Get the coords
var x = getCoordsFromDistanceLeft(start, end, distanceLeft);
document.write('x: ' + x + ' is ' + distanceLeft + ' to end<br>');
// x: 13.845299461620748,14.845299461620748,15.845299461620748 is 2 to end
document.write('From x to end: ' + get3dDistance(x, end) + '<br>');
// From x to end: 2.0000000000000013
Salix alba has introduced Math.hypot, which is interesting but since it's a new feature in ECMAScript 2015 it would be wise to include a polyfill.
You need to use 3D Pythagoras to find the distance between two points. If x1,y1,z1 and x2,y2,z2 are your points then the distance is sqrt((x1-x2)^2+(y1-y2)^2+(z1-z2)^2). There are several ways of finding the desired point. We can find the distance from the starting point to the ending point and then calculate the proportion of that distance which will give 2 as a result using linear interpolation.
var fromX = 1,
fromY = 2,
fromZ = 3,
toX = 15,
toY = 16,
toZ = 17;
// find the difference
var dx = toX-fromX, dy = toY-fromY, dz=toZ-fromZ;
// find the total length
var dist = Math.hypot(dx,dy,dz);
// find the proportion of this length
var lambda = (dist-2.0) / dist;
// do the linear interpolation
var x = fromX + lambda * dx,
y = fromY + lambda * dy,
z = fromZ + lambda * dz;
console.log(x,y,z);
// Just to check
var dx2 = toX-x, dy2 = toY-y, dz2=toZ-z;
var dist2 = Math.hypot(dx2,dy2,dz2);
console.log(dist2);
We get the result 13.845299461620748 14.845299461620748 15.845299461620748 and the final distance is 2.0000000000000013.
Note I've uses Math.hypot this is a new feature which works in Chrome/firefox/opera but not in IE. There is a work-around to enable it in other browsers if needed. You just use Math.sqrt(dx*dx+dy*dy+dz*dz) instead.
I am trying to plot coordinates around a square programatically here it is hard coded to show what i am after.
http://jsfiddle.net/zwkny/
// amount of chairs
var aoc = 4;
// table width
var tw = 200;
// table height
var th = 200;
// chair width height
var cwh = 60 / 2;
var space = tw * 4 / aoc;
var left = [-30,100,-30,-160];
var top = [-160,-30,100,-30];
// straing point
var sp = 12;
for(var i=0; i<aoc; i++){
var x = cwh + space * i / aoc;
console.log(x);
//var y = space / 2 - cwh * i;
$("#center").append("<div class='chair' style='left:"+left[i]+"px;top:"+top[i]+"px;'>"+i+"</div>");
}
Maths is definately not my strong point just thought i would post up here see if anyone can help point me in the right direction i keep going and update if i get it???
I need it this way to represent people the small circles standing around the large square but there will be random amounts of people and they all need to be at equal distances.
I posted the same post about a circle object yesterday and now i am on squares i just cant get my head around the maths, any help.
Sore that this has been voted down just thought i would update with a post putting all these together
http://devsforrest.com/116/plot-positions-around-shapes-with-javascript
Hope it helps someone else
var x,y;
// amount of chairs
var totalChairs = 12;
// square size
var squareSize = 200;
var chairSize = 20;
for(var i=0; i<totalChairs; i++){
var angle = 2*Math.PI * i/totalChairs;
if (angle > Math.PI/4 && angle <= Math.PI* 3/4){
x = (squareSize/2) / Math.tan(angle);
y = -squareSize/2;
} else if (angle > Math.PI* 3/4 && angle <= Math.PI* 5/4){
x = -squareSize/2;
y = (squareSize/2) * Math.tan(angle);
} else if (angle > Math.PI* 5/4 && angle <= Math.PI* 7/4){
x = -(squareSize/2) / Math.tan(angle);
y = -squareSize/2 + squareSize;
} else {
x = -squareSize/2 + squareSize;
y = -(squareSize/2) * Math.tan(angle);
}
x -= chairSize/2;
y -= chairSize/2;
$("#center").append("<div class='chair' style='left:"+x+"px;top:"+y+"px;'></div>");
}
Demo