boolean rectangles to polygon(s) - javascript

I am building something where I need to draw multiple rectangles, either adding them or subtracting them, and from that produce one or more polygons that represent the overall area enclosed. This would work like the thing you see in paint programs, etc, where you can create a selection by drawing rectangles and clicking the + or - button to determine whether to add or subtract from the current selected area.
I can do all the drawing code, but need to know how to convert an ordered series of rectangles, each with a mode of "add" or "subtract", into one or more polygons. Here is how I envision it being used:
var rectList = [
{x: 50, y: 40, w: 20, h: 30, mode: "+"},
{x: 24, y: 12, w: 14, h: 62, mode: "+"},
{x: 12, y: 30, w: 34, h: 14, mode: "-"},
{x: 22, y: 21, w: 45, h: 19, mode: "+"},
{x: 17, y: 20, w: 10, h: 21, mode: "+"}
];
var polygonList = getPolygonsFromRectangleList (rectList);
The polygonList might look like this (an array of arrays of points). (The numbers below are just made up and have nothing to do with the input above)
[
[
{x: 23, y: 12},
{x: 14, y: 12},
{x: 14, y: 36},
{x: 24, y: 36},
....
],
[
{x: 32, y: 45},
{x: 32, y: 22},
{x: 14, y: 22},
...
]
I imagine this must be a pretty standard graphics gem sort of thing.

Related

Convert hard-coded data into automated data in Javascript Chart.js

I have a data variable that needs to be represented on a line chart in Chart.js in React app. I am showing train and test data on the same line chart.
The values for the train dataset and test dataset are as follows:
train(y-axis): [369, 438, 329, 435, 359, 345, 406, 469, 457, 499, 352, 336, 480, 499, 354]
test(y-axis): [354, 354, 354, 354, 354]
The values for the train dataset indices and test dataset indices are as follows:
train_idx(x-axis): [0, 1, 2, 3, 4, 5,6,7 ,8 9, 10, 11, 12, 13, 14]
test_idx(x-axis): [14, 15, 16, 17, 18] /
I have hard-coded the values for now and the code looks as follows:
const [data, setData] = useState({
labels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
datasets: [{
label: 'Train Dataset',
data: [{x: 0, y: 369},
{x: 1, y: 438},
{x: 2, y: 329},
{x: 3, y: 435},
{x: 4, y: 359},
{x: 5, y: 345},
{x: 6, y: 406},
{x: 7, y: 469},
{x: 8, y: 457},
{x: 9, y: 499},
{x: 10, y: 352},
{x: 11, y: 336},
{x: 12, y: 480},
{x: 13, y: 499},
{x: 14, y: 354}],
//data: [369, 438, 329, 435, 359, 345, 406, 469, 457, 499, 352, 336, 480, 499, 354],
borderColor: 'blue',
}, {
label: 'Test Dataset',
data: [{x: 14, y: 354},
{x: 15, y: 354},
{x: 16, y: 354},
{x: 17, y: 354},
{x: 18, y: 354}],
//data: [354, 354, 354, 354, 354],
type: 'line',
borderColor: 'purple',
}],
})
From the above data, I get a graph that looks like this:
Now, I need the same graph but without hard-coding the values like above.
Please help me. The resulting graph without hard-coding the values needs to look like the picture.

How to predict the y based on past data

I have a data array like this
{x: 0, y: 7.9}
{x: 1, y: 7.5}
{x: 2, y: 7.0}
{x: 3, y: 7.4}
{x: 4, y: 7.3}
{x: 5, y: 7.2}
{x: 6, y: 7.5}
{x: 7, y: 7.6}
{x: 8, y: 7.7}
{x: 9, y: 7.2}
Based on this data, how can I find out the following y?
For example, I used a library to find out this data but how could I predict based on this data
the following data
eg for the next 30 indexes
now I have this
const cleanData = helpers.cleanData(this.data.datasets[0].data);
const ordersRegression = regression.linear(cleanData);
const regressionPoints = ordersRegression.points.map(([x, y]) => {
return {x, y};
});
this.data.datasets[1].data = regressionPoints;
But now I would like to do something with the data that I have to predict the following
It's possible ?
Is there a genuine formula?

Most time efficient route

I am looking for an algorithm to make a pathfinding tool. I believe, it is not exact salesman problem due to different nature of desired result.
Main goal is to build route through multiple points to visit more points in less time. It does not require to include all points into route, just opposite: if visiting a point or a group of points makes big detour, it is not worth including into route, as point/distance ratio would drop significantly.
Conditions:
there will always be starting point A (chosen by user), but finish can be back in point A, can be in point B or can be undefined to end route when visiting any more points would decrease efficiency
total pool of points (chosen by user) ranges from tens to thousands depending on filter
points can have weights to define how much visiting them contributes
app has to be more or less real time: user needs to get result within few minutes from entering starting conditions
To decrease waiting times I can make two optimizations: merge nearby points by distance into one point with increased weight and limit visitable points by certain radius from A or AB vector.
Bruteforce method does not work with big numbers, and popular pathfinding algorithm A* does not seem to be applicable here as well from what I understood. I thought about using ant algorithm or looking into other genetic algorithms, but is there any existing algorithm/method specifically made for such task? Also what (if any) further optimizations could be made to the pool of points for better results?
My approach so far (JavaScript). Scenarios 2 and 3 include distance to finish point as well.
let maxRatio = 0
let bestRoute = []
for (let path of allPaths) {
let distance = 0
let weight = 0
let currentPosition = {x: 0, y: 0}
for (let point of path) {
distance += getDistance(currentPosition, point)
weight += point.weight
currentPosition.x = point.x
currentPosition.y = point.y
}
if (weight / distance > maxRatio) {
maxRatio = weight / distance
bestRoute = path
}
}
With 2 sets of starting conditions (difference only in last point)
// input 1
[
{x: 10, y: 12, weight: 1.2},
{x: 15, y: 14, weight: 1},
{x: 6, y: 8, weight: 1},
{x: 30, y: 30, weight: 2},
]
// input 2
[
{x: 10, y: 12, weight: 1.2},
{x: 15, y: 14, weight: 1},
{x: 6, y: 8, weight: 1},
{x: 30, y: 30, weight: 4},
]
Scenario 1, from point A (0:0) to the end of route:
// output 1.1
Best weight/distance ratio: 0.15207666105559417
at visiting order [
{ x: 0, y: 0 },
{ x: 6, y: 8, weight: 1 },
{ x: 10, y: 12, weight: 1.2 },
{ x: 15, y: 14, weight: 1 }
]
Here we can see that one point, 30:30 with weight 2, is not included into the best route because it is simply too far away.
// output 1.2
Best weight/distance ratio: 0.16754421339617698
at visiting order [
{ x: 0, y: 0 },
{ x: 6, y: 8, weight: 1 },
{ x: 10, y: 12, weight: 1.2 },
{ x: 15, y: 14, weight: 1 },
{ x: 30, y: 30, weight: 4 }
]
Here we can see that point, 30:30 with weight 4 now, being included into the best route because visiting it benefits us.
Scenario 2, from point A (0:0) back to point A (0:0):
// output 2.1
Best weight/distance ratio: 0.07699655016791247
at visiting order [
{ x: 0, y: 0 },
{ x: 15, y: 14, weight: 1 },
{ x: 10, y: 12, weight: 1.2 },
{ x: 6, y: 8, weight: 1 },
{ x: 0, y: 0 }
]
Different order or points this time, but still furthest point not included
// output 2.2
Best weight/distance ratio: 0.08469183439702697
at visiting order [
{ x: 0, y: 0 },
{ x: 15, y: 14, weight: 1 },
{ x: 30, y: 30, weight: 4 },
{ x: 10, y: 12, weight: 1.2 },
{ x: 6, y: 8, weight: 1 },
{ x: 0, y: 0 }
]
And here, with weight 4, we include it.
Scenario 3, from point A (0:0) to point B (10:10):
// output 3.1
Best weight/distance ratio: 0.12459750581354255
at visiting order [
{ x: 0, y: 0 },
{ x: 6, y: 8, weight: 1 },
{ x: 10, y: 12, weight: 1.2 },
{ x: 10, y: 10 }
]
Here optimal route became shorter
// output 3.2
Best weight/distance ratio: 0.12459750581354255
at visiting order [
{ x: 0, y: 0 },
{ x: 6, y: 8, weight: 1 },
{ x: 10, y: 12, weight: 1.2 },
{ x: 10, y: 10 }
]
But even with weight 4 on (30:30) point we do not include it.

Add multi color gradient for different points in d3.js

I have to add gradient inside a foot shape according to the value of a point inside the foot. I have X and Y coordinates of a point and a value is attached to it. According to the value I have to assign color gradient like in the picture below. Higher the value of a point, darker the area is
So far, I have created the foot and added 2 color gradient to the whole foot, but I am unable to add gradient like this in the picture. Below is what I have achieved. Please if anyone could help me to find any solution to this
Here is the Stackblitz Link
Sample data :
[
{sensor: 0, value: 7.4, x: 108, y: 406}
{sensor: 1, value: 8.1, x: 68, y: 412}
{sensor: 2, value: 3.6, x: 108, y: 346}
{sensor: 3, value: 4.5, x: 61, y: 350}
{sensor: 4, value: 0.5, x: 108, y: 280}
{sensor: 5, value: 1, x: 49, y: 288}
{sensor: 6, value: 1, x: 122, y: 200}
{sensor: 7, value: 0.5, x: 30, y: 218}
{sensor: 8, value: 3.3, x: 140, y: 109}
{sensor: 9, value: 3.4, x: 105, y: 114}
{sensor: 10, value: 2.7, x: 78, y: 119}
{sensor: 11, value: 2.3, x: 51, y: 124}
{sensor: 12, value: 1.6, x: 22, y: 136}
{sensor: 13, value: 3.5, x: 121, y: 41}
{sensor: 14, value: 1.2, x: 85, y: 45}
{sensor: 15, value: 1, x: 50, y: 59}
]
Here is a hit map with 'populated' data (based on average value of closest points):
Just add the mask of the foot contour...
const data = [
{sensor: 0, value: 7.4, x: 108, y: 406},
{sensor: 1, value: 8.1, x: 68, y: 412},
{sensor: 2, value: 3.6, x: 108, y: 346},
{sensor: 3, value: 4.5, x: 61, y: 350},
{sensor: 4, value: 0.5, x: 108, y: 280},
{sensor: 5, value: 1, x: 49, y: 288},
{sensor: 6, value: 1, x: 122, y: 200},
{sensor: 7, value: 0.5, x: 30, y: 218},
{sensor: 8, value: 3.3, x: 140, y: 109},
{sensor: 9, value: 3.4, x: 105, y: 114},
{sensor: 10, value: 2.7, x: 78, y: 119},
{sensor: 11, value: 2.3, x: 51, y: 124},
{sensor: 12, value: 1.6, x: 22, y: 136},
{sensor: 13, value: 3.5, x: 121, y: 41},
{sensor: 14, value: 1.2, x: 85, y: 45},
{sensor: 15, value: 1, x: 50, y: 59},
];
const populateData = (points, width, height, step) => {
const populated = [];
for (let x = 0; x < width; x += step)
for (let y = 0; y < height; y += step) {
const distances = points.map(p =>
({...p, distance: Math.hypot(p.x - x, p.y - y)})).filter(d => d.distance < 100);
const sum = distances.reduce((s, d) => s + 1 / d.distance, 0);
const value = distances.reduce((a, d) => a + 1 / sum / d.distance * d.value, 0);
populated.push({x, y, value});
}
return populated;
};
const pd = populateData(data, 300, 500, 10);
const RECT_SIZE = 20;
const getColor = v => `rgb(255,${255 - v * 25},0)`
const svg = d3.select('svg');
pd.forEach(d => {
svg.append('rect')
.attr('x', d.x - RECT_SIZE / 2)
.attr('y', d.y - RECT_SIZE / 2)
.attr('width', RECT_SIZE / 2)
.attr('height', RECT_SIZE / 2)
.style('fill', getColor(d.value));
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="300" height="500" />
Here is a simple plot with the data you provided:
If you have more points, it can be a more precise picture
const data = [
{sensor: 0, value: 7.4, x: 108, y: 406},
{sensor: 1, value: 8.1, x: 68, y: 412},
{sensor: 2, value: 3.6, x: 108, y: 346},
{sensor: 3, value: 4.5, x: 61, y: 350},
{sensor: 4, value: 0.5, x: 108, y: 280},
{sensor: 5, value: 1, x: 49, y: 288},
{sensor: 6, value: 1, x: 122, y: 200},
{sensor: 7, value: 0.5, x: 30, y: 218},
{sensor: 8, value: 3.3, x: 140, y: 109},
{sensor: 9, value: 3.4, x: 105, y: 114},
{sensor: 10, value: 2.7, x: 78, y: 119},
{sensor: 11, value: 2.3, x: 51, y: 124},
{sensor: 12, value: 1.6, x: 22, y: 136},
{sensor: 13, value: 3.5, x: 121, y: 41},
{sensor: 14, value: 1.2, x: 85, y: 45},
{sensor: 15, value: 1, x: 50, y: 59},
];
const RECT_SIZE = 20;
const getColor = v => `rgb(255,${255 - v * 25},0)`
const svg = d3.select('svg');
data.forEach(d => {
svg.append('rect')
.attr('x', d.x - RECT_SIZE / 2)
.attr('y', d.y - RECT_SIZE / 2)
.attr('width', RECT_SIZE / 2)
.attr('height', RECT_SIZE / 2)
.style('fill', getColor(d.value));
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="300" height="500" />

In my vis.js stacked bar chart, how do I move my labels to the correct location?

Here's the code for my stacked bar chart:
var barGraphDiv = document.createElement('div');
barGraphCombinedDiv.appendChild(barGraphDiv);
var groups = new vis.DataSet();
groups.add({id: 0, content: "group0",})
groups.add({id: 1, content: "group1",})
groups.add({id: 2, content: "group2",})
var items = [
{x: '2014-06-11', y: 10, group:0, label: {content: 10, xOffset: -25}},
{x: '2014-06-12', y: 25, group:0, label: {content: 25, xOffset: -25}},
{x: '2014-06-13', y: 30, group:0, label: {content: 30, xOffset: -25}},
{x: '2014-06-14', y: 10, group:0, label: {content: 10, xOffset: -25}},
{x: '2014-06-15', y: 15, group:0, label: {content: 15, xOffset: -25}},
{x: '2014-06-16', y: 30, group:0, label: {content: 30, xOffset: -25}},
{x: '2014-06-11', y: 12, group:1, label: {content: 12, xOffset: -25}},
{x: '2014-06-12', y: 15, group:1, label: {content: 15, xOffset: -25}},
{x: '2014-06-13', y: 34, group:1, label: {content: 34, xOffset: -25}},
{x: '2014-06-14', y: 24, group:1, label: {content: 24, xOffset: -25}},
{x: '2014-06-15', y: 5, group:1, label: {content: 5, xOffset: -25}},
{x: '2014-06-16', y: 12, group:1, label: {content: 12, xOffset: -25}},
{x: '2014-06-11', y: 22, group:2, label: {content: 22, xOffset: -25}},
{x: '2014-06-12', y: 14, group:2},
{x: '2014-06-13', y: 24, group:2, label: {content: 24, xOffset: -25}},
{x: '2014-06-14', y: 21, group:2, label: {content: 21, xOffset: -25}},
{x: '2014-06-15', y: 30, group:2},
{x: '2014-06-16', y: 18, group:2}
];
var dataset = new vis.DataSet(items);
var options = {
style:'bar',
stack:true,
barChart: {width:50, align:'center', sideBySide:true},
drawPoints: {
size: 0,
},
dataAxis: {
icons:true
},
orientation:'top',
start: '2014-06-10',
end: '2014-06-18',
};
var graph2d = new vis.Graph2d(barGraphDiv, items, groups, options);
This produces a bar chart that looks like this:
How would I get the labels to line up with the groups? Basically the labels need to be shifted up like the groups.
The bottom label is in the correct location. The others are not. When I do an inspect element, the first bar looks like this:
<rect class="vis-graph-group0 vis-bar" height="33.33333333333337" width="50" y="300" x="1956.375">
</rect>
<rect class="vis-graph-group0 vis-point" height="0" width="0" y="300" x="1981.375">
</rect>
<text y="300" x="1956.375">10</text>
<rect class="vis-graph-group1 vis-bar" height="40.33333333333337" width="50" y="259.66666666666663" x="1956.375">
</rect>
<rect class="vis-graph-group1 vis-point" height="0" width="0" y="293" x="1981.375">
</rect>
<text y="293" x="1956.375">12</text>
<rect class="vis-graph-group2 vis-bar" height="73.33333333333337" width="50" y="186.33333333333326" x="1956.375">
</rect>
<rect class="vis-graph-group2 vis-point" height="0" width="0" y="260" x="1981.375">
</rect>
<text y="260" x="1956.375">22</text>
What I have noticed is that the y value for the text elements needs to be modified. The bottom most text element has the correct y value. The next to bottom one needs the y value changed to the previous text element's y value - the height of the bar.
For example, the bottom most text element has a y value of 300. The next text element has a y value of 293 while the bar associated with that text value has a height of 40.33333. This y value actually needs to be set to 300 - 40.33333 = 259.66667. Then the next text element's y value needs to be set to 259.66667 - 73.33333 = 186.33334.
How would I go about accomplishing this? Is there an easier to shift the labels?
I'm one of the developers of visjs. It seems like this is a bug. I'm not sure when this will be fixed as it's very busy currently. As for an easier way, I don't think so. If everything worked the way it should you shouldn't have to do anything for this.
We plan on a huge refactor of the graph2d but as it stands we do not have the manpower available to undertake this in the near future.

Categories