Dectect click in irregular shapes inside HTML5 canvas - javascript

I am new using canvas and I created a simple script to draw irregular polygons in a canvas knowing the coord. Now I need to detect if an user clicks on one of those shapes and wich one (each object has an ID). You can see my script working here.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
var objetos = [];
// First Shape
objetos.push( {
id:'First',
coordinates: {
p1: {
x: 30,
y: 10
},
p2: {
x: 50,
y: 50
},
p3: {
x: 90,
y: 90
},
p4: {
x: 50,
y: 90
},
}
});
// Second Shape
objetos.push( {
id:'Two',
coordinates: {
p1: {
x: 150,
y: 20
},
p2: {
x: 90,
y: 50
},
p3: {
x: 90,
y: 30
},
}
});
// 3th Shape
objetos.push( {
id:'Shape',
coordinates: {
p1: {
x: 150,
y: 120
},
p2: {
x: 160,
y: 120
},
p3: {
x: 160,
y: 50
},
p4: {
x: 150,
y: 50
},
}
});
// Read each object
for (var i in objetos){
// Draw rhe shapes
ctx.beginPath();
var num = 0;
for (var j in objetos[i].coordinates){
if(num==0){
ctx.moveTo(objetos[i].coordinates[j]['x'], objetos[i].coordinates[j]['y']);
}else{
ctx.lineTo(objetos[i].coordinates[j]['x'], objetos[i].coordinates[j]['y']);
}
num++;
}
ctx.closePath();
ctx.lineWidth = 2;
ctx.fillStyle = '#8ED6FF';
ctx.fill();
ctx.strokeStyle = 'blue';
ctx.stroke();
}
NOTE: A cursor pointer on hover would be appreciated. =)
EDIT: Note I am using irregular shapes with no predefined number of points. Some scripts (like those on pages linked as "Possible duplication") using circles or regular polygons (certain number of sides with the same lengh do not solve my issue).

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.

Change Scatter Chart Size and shape dynamically - LightningChart JS

How do we change scatter chart size and shape dynamically while adding data to series
const pointz = chart.addPointSeries({ pointShape: PointShape.Circle })
.setName('Kuopio')
.setPointFillStyle(fillStyles[0])
.setPointSize(pointSize)
.setMaxPointCount(10000);
I know that we can change color dynamically by
const fillStyle = new IndividualPointFill({ color: ColorHSV(0) })
Is there any way to change size dynamically like elipse series ?
Lightning Chart JS v2.0.0 or greater
Point size and rotation can be set individually for each point. To enable support for individual size or rotation call series.setIndividualPointSizeEnabled(true) and/or series.setIndividualPointRotationEnabled(true)
const series = chart.addPointSeries({ pointShape: PointShape.Triangle })
.setIndividualPointSizeEnabled(true)
When the individual point size is enabled, the point size can be set by providing a value to a size field for each point.
series.add([
{ x: 0, y: 0, size: 1 },
{ x: 1, y: 0, size: 5 },
{ x: 2, y: 0, size: 10 },
{ x: 3, y: 0, size: 15 },
{ x: 4, y: 0, size: 20 },
{ x: 5, y: 0, size: 25 },
])
Rotation works in a similar way, the point rotation can be set by providing a value to a rotation field for each point. The rotation is defined in radians.
const series = chart.addPointSeries({ pointShape: PointShape.Triangle })
.setIndividualPointSizeEnabled(true)
series.add([
{ x: 0, y: 3, rotation: 0 },
{ x: 1, y: 3, rotation: Math.PI / 4 },
{ x: 2, y: 3, rotation: Math.PI / 2 },
{ x: 3, y: 3, rotation: Math.PI },
{ x: 4, y: 3, rotation: Math.PI * 3/2 },
{ x: 5, y: 3, rotation: Math.PI * 2 },
])
Individual point size and rotation can be also used at the same time.
const series = chart.addPointSeries({ pointShape: PointShape.Triangle })
.setIndividualPointSizeEnabled(true)
.setIndividualPointRotationEnabled(true)
series4.add([
{ x: 0, y: 3, size: 1, rotation: 0 },
{ x: 1, y: 3, size: 5, rotation: Math.PI / 4 },
{ x: 2, y: 3, size: 10, rotation: Math.PI / 2 },
{ x: 3, y: 3, size: 15, rotation: Math.PI },
{ x: 4, y: 3, size: 20, rotation: Math.PI * 3/2 },
{ x: 5, y: 3, size: 25, rotation: Math.PI * 2 },
])
Point shape can't yet be changed individually.
Lightning Chart JS v1.x:
LightningChart JS currently doesn't support changing the point shape or size individually. This is a feature that we would like to develop but haven't yet decided on when or if it will be done.
As a workaround you could use multiple point series for different shapes. So you could have one series for each point shape (square, triangle, circle) and then add the points to the different series based on the factors you want to use to determine the shape. I know that this isn't an optimal solution but it's the only solution that I can think of right now.

Finding closest x,y coordinates

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.

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

What javascript array, nested array, object is most suitable for searching

I'm trying to build a colors structure that has 3 data per item. For example, red has x and y, blue has x and y, etc. So the 3 pieces of data are color, x, y
What structure do I need to make it easy to read the x and y based on the color. I usually do push(color, x, y) but that wouldn't work here, because I need to search quickly by the color without needing to loop. What structure do I need here, and how do I set it and get it.
What about a simple object (hash) ?
// Initial creation
var colors = {
blue: { x: 897, y: 98 },
red: { x: 43, y: 1334 },
yellow: { y: 12 }
}
// Adding new element to existing object
colors['green'] = { x: 19 };
// Accessing them
console.log(colors.blue.x);
console.log(colors.yellow.y);
// Accessing them with name in var
var needed = 'green';
console.log(colors[needed].x);
console.log(colors[needed]['x']);
Or did I understand you wrong?
Are you looking for something like a dictionary?!?
var colorArray = {};
colorArray["red"] = {
x: 100,
y: 200
};
colorArray["blue"] = {
x: 222,
y: 200
};
alert(colorArray["red"].x);​
var colors = {
red : { x : 42, y : 7 },
blue : { x : .., y : .. },
...
};
alert(colors.red.x);
Or if you need the color also in the array
var colors = {
blue: { color:"blue", x: 100, y: 200 },
red: { color:"red", x: 50, y: 300 },
yellow: { color:"yellow", x: 30 y: 700 }
}
You also could use string "constants":
var RED = "red";
var colors = {};
colors[RED] = { color: RED, x: 100, y: 200 };
...
var colors = [
{color: 'blue', x: 897, y: 98 },
{color: 'red', x: 25, y: 1334 },
{color: 'yellow', x: 50, y: 12 }
]
for(var i in colors) {
console.log(colors[i].color);
console.log(colors[i].x);
console.log(colors[i].y);
}
// To insert into colors
colors.push({color: 'pink', x: 150, y: 200});
or if you have structure like this
var colors = [
['red', 837, 98],
['blue', 25, 144],
['yellow', 50, 12]
];
then
for(var i in colors) {
console.log(colors[i][0]); // output: red, yellow ...
console.log(colors[i][1]); // output: 837, 25 ..
console.log(colors[i][2]); // output: 98, 144 ..
}
and to insert into colors for this structure
colors.push(['pink', 150, 200])
or
var colors = {
blue: { x: 58, y: 100 },
red: { x: 43, y: 1334 },
yellow: {x: 254, y: 12 }
}
then
for(var i in colors) {
console.log(colors[i].blue.x);
console.log(colors[i].blue.y);
// or
console.log(colors[i]['blue'].x);
// or like
console.log(colors[i]['blue']['x']);
}
// and to insert for this sturcture
colors.pink= {x: 150, y: 200};

Categories

Resources