Finding closest x,y coordinates - javascript

I have coordinates (x, y) of place where I am currently and array of objects with coordinates of destinations.
Coordinates x and y are just representing of fields in map like this:
and it is up to 100x100.
myPosition is array: [ 13, 11 ] where 13 is x and 11 is y (demonstratively marked it as red in above jpg).
destinations is array of object:
[ { x: 22, y: 13 },
{ x: 16, y: 25 },
{ x: 20, y: 11 },
{ x: 76, y: 49 },
{ x: 65, y: 47 },
{ x: 82, y: 33 },
{ x: 86, y: 35 },
{ x: 61, y: 59 },
{ x: 62, y: 52 },
{ x: 18, y: 52 },
{ x: 24, y: 49 },
{ x: 52, y: 55 },
{ x: 20, y: 57 },
{ x: 80, y: 11 },
{ x: 55, y: 61 },
{ x: 46, y: 59 },
{ x: 77, y: 19 },
{ x: 2, y: 22 },
{ x: 78, y: 23 },
{ x: 86, y: 51 },
{ x: 75, y: 46 },
{ x: 6, y: 8 },
{ x: 25, y: 12 },
{ x: 81, y: 21 },
{ x: 53, y: 58 } ]
I need some tips or algorithm which will sort destination array of object in order from closest to my position.

What you got is called the nearest neighbor problem.
Two solutions, depening on where you need to take your problem:
You could simply do a brute force distance search with the usual optimization of skipping the square-root:
Some code:
function DistSquared(pt1, pt2) {
var diffX = pt1.x - pt2.x;
var diffY = pt1.y - pt2.y;
return (diffX*diffX+diffY*diffY);
}
closest = destinations[0];
shortestDistance = DistSquared(myPosition, destinations[0]);
for (i = 0; i < destinations.length; i++) {
var d = DistSquared(myPosition, destinations[i]);
if (d < shortestDistance) {
closest = destinations[i];
shortestDistance = d;
}
}
If you are going to make repeated nearest neighbor queries on the same destinations array, you can use an algorithm known as a k-d tree. This where you build a binary tree representation of your grid of points by partitioning it in half many times along a different axis.

Related

How to check if the the difference of and number and a value from my object in my array is smaller than 100?

I need to access an object and it's property and check if the the value of the property smaller than 100 is.
My code would look like following:
let myArr = [{
id: 1,
x: 120,
y: 150,
}, {
id: 2,
x: 170,
y: 420,
}, {
id: 3,
x: 160,
y: 220,
}, {
id: 4,
x: 140,
y: 170,
}];
if(nearestEnemy.x - /*go throught all of my "x"-properties*/ && nearestEnemy.y - /*go throught all of my "y"-properties*/ < 100){
}
You don't need to matter about the other code, just look at my comments.
I want to check if the x axis and the y axis is almost the same as of one of my properties from my object in my array.
I guess you'd need something like a loop for this but I can't think of anything!
I don't know if you can understand me because I cant really explain what I mean.
Thanks for you help anyway.
You can achieve this by filtering out the objects by using Array.filter() method.
let myArr = [{
id: 1,
x: 120,
y: 150
}, {
id: 2,
x: 170,
y: 420
}, {
id: 3,
x: 160,
y: 220
}, {
id: 4,
x: 140,
y: 170
}];
function difference(a, b) {
return Math.abs(a - b);
}
const filtered = myArr.filter(({x, y}) => difference(x, y) < 100);
console.log(filtered);
It sounds to me like you have an array of points and want to find an element which is the nearest to the given point. If this is the case, you can proceed like this:
write a function that computes distance (https://en.wikipedia.org/wiki/Euclidean_distance) between two points
write a loop that minimizes distance
Example:
let myArr = [
{
id: 1,
x: 120,
y: 150,
}, {
id: 2,
x: 170,
y: 420,
}, {
id: 3,
x: 160,
y: 220,
}, {
id: 4,
x: 140,
y: 170,
}];
function distance(p1, p2) {
return Math.sqrt(
(p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2,
)
}
function nearestPoint(points, somePoint) {
let min = +Infinity,
minPt = null;
for (let p of points) {
let d = distance(p, somePoint);
if (d < min) {
min = d;
minPt = p;
}
}
return minPt;
}
console.log(nearestPoint(myArr, {x: 190, y: 130}))
This is not very efficient, but should be fine for < 10,000 points. If you have more, you'll need some kind of spatial indexing.

sort 2 array's with objects of coordinates to get a list of which are closest to each-other

I have 2 array's with objects of coordinates. For example:
const coordinates = [
{ x: 2, y: 6 },
{ x: 14, y: 10 },
{ x: 7, y: 10 },
{ x: 11, y: 6 },
];
const coordinates2 = [
{ x: 8, y: 9 },
{ x: 25, y: 11 },
{ x: 2, y: 11 },
{ x: 7, y: 8 },
];
I want to make an sort function which will return which are closest to each other.
I tried multiple things but can not figure it out.
Any solution is accepted. Maybe sort 1 to the other or sort both at the same time.
This is wat I want to achive:
result array 1[
{ x: 2, y: 6 },
{ x: 14, y: 10 },
{ x: 7, y: 10 },
{ x: 11, y: 6 },
];
result array 2 = [
{ x: 2, y: 11 }, // beceause it is closest to {x: 2,y: 6}
{ x: 25, y: 11 }, // beceayse it is closest to {x: 14,y: 10},
{ x: 7, y: 8 }, // beceause it is closest to { x: 7, y: 10 }
{ x: 8, y: 9 }, // beceause it is closest to {x: 11,y: 6} after x: 7, y:10 but x:7, y:8 is even closer
];
^ the result can be different. But I want the most efficient distance between them.
The formula to see the distance of coordination a and coordination b is the following:
distance=√((x1-x2)²+(y1-y2)²).
If anyone has an idea or an tip please let me know !
You could map the first array by getting the closest coordinate from the second array.
const
getClosest = ({ x, y }, data) => data.reduce((a, b) => Math.hypot(x - a.x, y - a.y) < Math.hypot(x - b.x, y - b.y) ? a : b),
coordinates = [{ x: 2, y: 6 }, { x: 14, y: 10 }, { x: 7, y: 10 }, { x: 11, y: 6 }, { x: 6, y: 2 }],
coordinates2 = [{ x: 8, y: 9 }, { x: 25, y: 11 }, { x: 2, y: 11 }, { x: 18, y: 21 }, { x: 7, y: 8 }],
pairs = coordinates.map(o => [o, getClosest(o, coordinates2)]);
console.log(pairs);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to show custom label in line chart or scatter chart

I am adding data to charts like this
const data = [
["2020-05-22 14:20:22", "173.9"],
["2020-05-22 14:20:40", "175.3"],
["2020-05-22 14:20:58", "172.4"]
]
function stringToDate(s) {
s = s.split(/[-: ]/);
return new Date(s[0], s[1]-1, s[2], s[3], s[4], s[5]);
}
for(var key in data)
{
var xTime = stringToDate(data[key][0]);
var yVal = parseFloat(data[key][1]);
series.add({ x: xTime.getTime() - dateOrigin.getTime(), y: yVal})
}
How do I show custom label to it, For example I want to show full date for above line series and also for other scatter charts , I want to show custom label like below.
series.add({ x: xTime.getTime() - dateOrigin.getTime(), y: yVal , label : "my own text" })
To show a full date for a series using a DateTime axis you can take a look at my previously posted answer: https://stackoverflow.com/a/59839354/6198227 The sort version of it is to define a format options based on Intl.DateTimeFormat when defining the axis tick strategy for a axis.
Custom labels can be done by creating custom ticks. The text inside the tick can be defined with a text formatter set by Axis.setTextFormatter. The formatter function gets the position and the tick itself as parameters so those can be used to define the text inside the tick if that's needed.
const tick = lineSeries.axisX.addCustomTick()
.setGridStrokeLength(0)
.setTextFormatter(()=>'My Text')
.setValue(dataFrequency * 50)
See below snippet for a implementation of both custom DateTime formatting and the use of custom ticks. The snippet is based on DateTime Axis example from the LightningChart JS Interactive Examples.
LightningChart JS v1.3.1 example:
// Extract required parts from LightningChartJS.
const {
lightningChart,
AxisTickStrategies,
DataPatterns,
emptyFill,
emptyLine
} = lcjs
// Create a XY Chart.
const dateOrigin = new Date(2008, 0, 1)
const chart = lightningChart().ChartXY({
defaultAxisXTickStrategy: AxisTickStrategies.DateTime(
dateOrigin,
undefined,
{
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}
)
})
.setTitle('Customer Satisfaction')
chart.setPadding({ right: '5' })
// Add a progressive line series.
// Using the DataPatterns object to select the horizontalProgressive pattern for the line series.
const lineSeries = chart.addLineSeries({ dataPattern: DataPatterns.horizontalProgressive })
.setName('Customer Satisfaction')
// Generate some points using for each month
const dataFrequency = 30 * 24 * 60 * 60 * 1000
// Setup view nicely.
chart.getDefaultAxisY()
.setScrollStrategy(undefined)
.setInterval(0, 100)
.setTitle('Satisfaction %')
// Data for the plotting
const satisfactionData = [
{ x: 0, y: 0 },
{ x: 1, y: 8 },
{ x: 2, y: 12 },
{ x: 3, y: 18 },
{ x: 4, y: 22 },
{ x: 5, y: 32 },
{ x: 6, y: 40 },
{ x: 7, y: 48 },
{ x: 8, y: 50 },
{ x: 9, y: 54 },
{ x: 10, y: 59 },
{ x: 11, y: 65 },
{ x: 12, y: 70 },
{ x: 13, y: 68 },
{ x: 14, y: 70 },
{ x: 15, y: 69 },
{ x: 16, y: 66 },
{ x: 17, y: 65.4 },
{ x: 18, y: 64 },
{ x: 19, y: 65 },
{ x: 20, y: 63.5 },
{ x: 21, y: 62 },
{ x: 22, y: 61.2 },
{ x: 23, y: 63 },
{ x: 24, y: 61 },
{ x: 25, y: 62 },
{ x: 26, y: 62 },
{ x: 27, y: 60 },
{ x: 28, y: 57.8 },
{ x: 29, y: 58 },
{ x: 30, y: 61 },
{ x: 31, y: 59 },
{ x: 32, y: 63 },
{ x: 33, y: 61 },
{ x: 34, y: 61.8 },
{ x: 35, y: 62 },
{ x: 36, y: 59.9 },
{ x: 37, y: 58 },
{ x: 38, y: 60 },
{ x: 39, y: 63 },
{ x: 40, y: 59.5 },
{ x: 41, y: 62.5 },
{ x: 42, y: 59.7 },
{ x: 43, y: 57 },
{ x: 44, y: 61 },
{ x: 45, y: 59 },
{ x: 46, y: 61 },
{ x: 47, y: 65 },
{ x: 48, y: 62 },
{ x: 49, y: 60 },
{ x: 50, y: 58 },
{ x: 51, y: 59 },
{ x: 52, y: 61 },
{ x: 53, y: 64 },
{ x: 54, y: 65.5 },
{ x: 55, y: 67 },
{ x: 56, y: 68 },
{ x: 57, y: 69 },
{ x: 58, y: 68 },
{ x: 59, y: 69.5 },
{ x: 60, y: 69.9 },
{ x: 61, y: 68.5 },
{ x: 62, y: 67 },
{ x: 63, y: 65 },
{ x: 64, y: 63 },
{ x: 65, y: 60 },
{ x: 66, y: 61.6 },
{ x: 67, y: 62 },
{ x: 68, y: 61 },
{ x: 69, y: 60 },
{ x: 70, y: 63.3 },
{ x: 71, y: 62.7 },
{ x: 72, y: 64.3 },
{ x: 73, y: 63 },
{ x: 74, y: 61.2 },
{ x: 75, y: 60 },
{ x: 76, y: 61 },
{ x: 77, y: 64 },
{ x: 78, y: 61.9 },
{ x: 79, y: 61 },
{ x: 80, y: 58 },
{ x: 81, y: 59 },
{ x: 82, y: 60.5 },
{ x: 83, y: 61 },
{ x: 84, y: 63 },
{ x: 85, y: 64.5 },
{ x: 86, y: 65 },
{ x: 87, y: 66.2 },
{ x: 88, y: 64.9 },
{ x: 89, y: 63 },
{ x: 90, y: 62 },
{ x: 91, y: 63 },
{ x: 92, y: 61.8 },
{ x: 93, y: 62 },
{ x: 94, y: 63 },
{ x: 95, y: 64.2 },
{ x: 96, y: 63 },
{ x: 97, y: 61 },
{ x: 98, y: 59.7 },
{ x: 99, y: 61 },
{ x: 100, y: 58 },
{ x: 101, y: 59 },
{ x: 102, y: 58 },
{ x: 103, y: 58 },
{ x: 104, y: 57.5 },
{ x: 105, y: 59.2 },
{ x: 106, y: 60 },
{ x: 107, y: 61.9 },
{ x: 108, y: 63 },
{ x: 109, y: 64.1 },
{ x: 110, y: 65.9 },
{ x: 111, y: 64 },
{ x: 112, y: 65 },
{ x: 113, y: 62 },
{ x: 114, y: 60 },
{ x: 115, y: 58 },
{ x: 116, y: 57 },
{ x: 117, y: 58.2 },
{ x: 118, y: 58.6 },
{ x: 119, y: 59.3 },
{ x: 120, y: 61 }
]
// Adding points to the series
lineSeries.add(satisfactionData.map((point) => ({ x: point.x * dataFrequency, y: point.y })))
// Show the customized result table for each point
lineSeries.setResultTableFormatter((builder, series, xValue, yValue) => {
return builder
.addRow('Customer Satisfaction')
.addRow(series.axisX.formatValue(xValue))
.addRow(yValue.toFixed(2) + "%")
})
const tick = lineSeries.axisX.addCustomTick()
.setGridStrokeLength(0)
.setTextFormatter(()=>'My Text')
.setValue(dataFrequency * 50)
<script src="https://unpkg.com/#arction/lcjs#2.2.1/dist/lcjs.iife.js"></script>
Update for LightningChart JS v3.4.0
DateTime axis formatting options have changed a little bit, there are more options to format based on the zoom level. And setResultTableFormatter has been renamed to setCursorResultTableFormatter.
const formatting = {year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric'}
chart.getDefaultAxisX().setTickStrategy(AxisTickStrategies.DateTime, (styler)=>
styler.setDateOrigin(dateOrigin)
.setFormattingDay(formatting, formatting, formatting)
.setFormattingDecade(formatting, formatting, formatting)
.setFormattingHour(formatting, formatting, formatting)
.setFormattingMilliSecond(formatting, formatting, formatting)
.setFormattingMinute(formatting, formatting, formatting)
.setFormattingMonth(formatting, formatting, formatting)
.setFormattingSecond(formatting, formatting, formatting)
.setFormattingWeek(formatting, formatting, formatting)
.setFormattingYear(formatting, formatting, formatting)
)
LightningChart JS v3.4.0 example:
// Import LightningChartJS
const {
lightningChart,
AxisTickStrategies,
DataPatterns,
emptyFill,
emptyLine
} = lcjs
// Create a XY Chart.
const dateOrigin = new Date(2008, 0, 1)
const chart = lightningChart().ChartXY()
.setTitle('Customer Satisfaction')
const formatting = {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}
chart.getDefaultAxisX().setTickStrategy(AxisTickStrategies.DateTime, (styler) =>
styler.setDateOrigin(dateOrigin)
.setFormattingDay(formatting, formatting, formatting)
.setFormattingDecade(formatting, formatting, formatting)
.setFormattingHour(formatting, formatting, formatting)
.setFormattingMilliSecond(formatting, formatting, formatting)
.setFormattingMinute(formatting, formatting, formatting)
.setFormattingMonth(formatting, formatting, formatting)
.setFormattingSecond(formatting, formatting, formatting)
.setFormattingWeek(formatting, formatting, formatting)
.setFormattingYear(formatting, formatting, formatting)
)
chart.setPadding({
right: '5'
})
// Add a progressive line series.
// Using the DataPatterns object to select the horizontalProgressive pattern for the line series.
const lineSeries = chart.addLineSeries({
dataPattern: DataPatterns.horizontalProgressive
})
.setName('Customer Satisfaction')
// Generate some points using for each month
const dataFrequency = 30 * 24 * 60 * 60 * 1000
// Setup view nicely.
chart.getDefaultAxisY()
.setScrollStrategy(undefined)
.setInterval(0, 100)
.setTitle('Satisfaction %')
// Data for the plotting
const satisfactionData = [
{ x: 0, y: 0 },
{ x: 1, y: 8 },
{ x: 2, y: 12 },
{ x: 3, y: 18 },
{ x: 4, y: 22 },
{ x: 5, y: 32 },
{ x: 6, y: 40 },
{ x: 7, y: 48 },
{ x: 8, y: 50 },
{ x: 9, y: 54 },
{ x: 10, y: 59 },
{ x: 11, y: 65 },
{ x: 12, y: 70 },
{ x: 13, y: 68 },
{ x: 14, y: 70 },
{ x: 15, y: 69 },
{ x: 16, y: 66 },
{ x: 17, y: 65.4 },
{ x: 18, y: 64 },
{ x: 19, y: 65 },
{ x: 20, y: 63.5 },
{ x: 21, y: 62 },
{ x: 22, y: 61.2 },
{ x: 23, y: 63 },
{ x: 24, y: 61 },
{ x: 25, y: 62 },
{ x: 26, y: 62 },
{ x: 27, y: 60 },
{ x: 28, y: 57.8 },
{ x: 29, y: 58 },
{ x: 30, y: 61 },
{ x: 31, y: 59 },
{ x: 32, y: 63 },
{ x: 33, y: 61 },
{ x: 34, y: 61.8 },
{ x: 35, y: 62 },
{ x: 36, y: 59.9 },
{ x: 37, y: 58 },
{ x: 38, y: 60 },
{ x: 39, y: 63 },
{ x: 40, y: 59.5 },
{ x: 41, y: 62.5 },
{ x: 42, y: 59.7 },
{ x: 43, y: 57 },
{ x: 44, y: 61 },
{ x: 45, y: 59 },
{ x: 46, y: 61 },
{ x: 47, y: 65 },
{ x: 48, y: 62 },
{ x: 49, y: 60 },
{ x: 50, y: 58 },
{ x: 51, y: 59 },
{ x: 52, y: 61 },
{ x: 53, y: 64 },
{ x: 54, y: 65.5 },
{ x: 55, y: 67 },
{ x: 56, y: 68 },
{ x: 57, y: 69 },
{ x: 58, y: 68 },
{ x: 59, y: 69.5 },
{ x: 60, y: 69.9 },
{ x: 61, y: 68.5 },
{ x: 62, y: 67 },
{ x: 63, y: 65 },
{ x: 64, y: 63 },
{ x: 65, y: 60 },
{ x: 66, y: 61.6 },
{ x: 67, y: 62 },
{ x: 68, y: 61 },
{ x: 69, y: 60 },
{ x: 70, y: 63.3 },
{ x: 71, y: 62.7 },
{ x: 72, y: 64.3 },
{ x: 73, y: 63 },
{ x: 74, y: 61.2 },
{ x: 75, y: 60 },
{ x: 76, y: 61 },
{ x: 77, y: 64 },
{ x: 78, y: 61.9 },
{ x: 79, y: 61 },
{ x: 80, y: 58 },
{ x: 81, y: 59 },
{ x: 82, y: 60.5 },
{ x: 83, y: 61 },
{ x: 84, y: 63 },
{ x: 85, y: 64.5 },
{ x: 86, y: 65 },
{ x: 87, y: 66.2 },
{ x: 88, y: 64.9 },
{ x: 89, y: 63 },
{ x: 90, y: 62 },
{ x: 91, y: 63 },
{ x: 92, y: 61.8 },
{ x: 93, y: 62 },
{ x: 94, y: 63 },
{ x: 95, y: 64.2 },
{ x: 96, y: 63 },
{ x: 97, y: 61 },
{ x: 98, y: 59.7 },
{ x: 99, y: 61 },
{ x: 100, y: 58 },
{ x: 101, y: 59 },
{ x: 102, y: 58 },
{ x: 103, y: 58 },
{ x: 104, y: 57.5 },
{ x: 105, y: 59.2 },
{ x: 106, y: 60 },
{ x: 107, y: 61.9 },
{ x: 108, y: 63 },
{ x: 109, y: 64.1 },
{ x: 110, y: 65.9 },
{ x: 111, y: 64 },
{ x: 112, y: 65 },
{ x: 113, y: 62 },
{ x: 114, y: 60 },
{ x: 115, y: 58 },
{ x: 116, y: 57 },
{ x: 117, y: 58.2 },
{ x: 118, y: 58.6 },
{ x: 119, y: 59.3 },
{ x: 120, y: 61 }
]
// Adding points to the series
lineSeries.add(satisfactionData.map((point) => ({
x: point.x * dataFrequency,
y: point.y
})))
// Show the customized result table for each point
lineSeries.setCursorResultTableFormatter((builder, series, xValue, yValue) => {
return builder
.addRow('Customer Satisfaction')
.addRow(series.axisX.formatValue(xValue))
.addRow(yValue.toFixed(2) + "%")
})
const tick = lineSeries.axisX.addCustomTick()
.setGridStrokeLength(0)
.setTextFormatter(() => 'My Text')
.setValue(dataFrequency * 50)
<script src="https://unpkg.com/#arction/lcjs#3.4.0/dist/lcjs.iife.js"></script>

How to add more than one array to kendo chart

I have more than one array, I want to add them to Kendo chart, I did the search could not get the solution, it will be helpful if you help me.
see the example here
Suppose I want to add one more array like this
[{
x: 33, y: 50,
}, {
x: 15, y: 26
} ]
to the xyData object, How can I do? I have applied directly like
var xyData = [[{
x: 10, y: 20,
}, {
x: 100, y: 200
} ], [{
x: 33, y: 50,
}, {
x: 15, y: 26
} ]];
this but it did not work, How to do? please help me.
You can use Array.concat() to create one new array:
var xyData = [{
x: 10, y: 20,
}, {
x: 100, y: 200
} ];
var xyData2 = [{
x: 33, y: 50,
}, {
x: 15, y: 26
} ];
var xyTotal = xyData.concat(xyData2);
DEMO

How to create a datapoint object with a loop in JS?

I would like to create this output in a JS while loop:
dataPoints: [
{ x: 10, y: 10 },
{ x: 20, y: 11 },
{ x: 30, y: 14 },
{ x: 40, y: 16 },
{ x: 50, y: 19 },
{ x: 60, y: 15 },
{ x: 70, y: 12 },
{ x: 80, y: 10 }
]
When I put this
sdata[i] = accumulated;
Into my loop, it adds the entries like that:
Object {
1: 1500,
2: 3005,
3: 4515.016666666666,
4: 6030.066722222222,
5: 7550.166944629629
}
What do I have to put into the loop to create the output like at the beginning?
Thanks for your help!
You're probably trying to push (x, y) points in an array. This is is how it should be done.
var sdata = []; // an array;
assuming that accumulated is a point it should have a structure like below
accumulated = { x: 10, y: 20};
Next is just create the points and push it to the array.
while(/*loop-condition-*/) {
var accumulated = {
x: xCurrent,
y: yCurrent
};
sdata.push(accmulated);
}
//that's it.
sdata now has the output as desired

Categories

Resources