I am using FabricJS to generate a polygon with 6 points
var polygon = new fabric.Polygon([
new fabric.Point(150, 50),
new fabric.Point(250, 50),
new fabric.Point(250, 150),
new fabric.Point(150, 150),
new fabric.Point(50, 250),
]);
On each point I need to have a line, so I am iterating through points and adding lines successfully:
return new fabric.Line([p.x, p.y, fromX, fromY], {
stroke: colors[i],
strokeWidth: 10,
hasBorders: true,
strokeDashArray: [20, 5]
});
this code generates polygon successfully with my desired coloured line:
The issue is now I want to adjust lines positions, for example the red line I need to be sticky on top of the polygon, the green one I need it half inside of polygon, blue 5% distant from polygon, etc.
While searching I found, Check if Point Is Inside A Polygon and tried those functions, which gives different results, so I have two functions, isinPolygonFirst and isinPolygonSecond, which basically are checking if my point is inside polygon. I thought If I could know that if my points are inside polygon I can add some value, for example if point was [20,20 and if it is inside polygon I can increase to [21,21] and recheck if it is. I am posting debugging info(in snippet below needs to move polygon box to see debug messages):
// function to check if line exists in polygon
function isinPolygonFirst(points, longitude_x, latitude_y) {
vertices_y = new Array();
vertices_x = new Array();
var r = 0;
var i = 0;
var j = 0;
var c = 0;
var point = 0;
for (r = 0; r < points.length; r++) {
vertices_y.push(points[r].y);
vertices_x.push(points[r].x);
}
points_polygon = vertices_x.length;
for (i = 0, j = points_polygon; i < points_polygon; j = i++) {
point = i;
if (point == points_polygon)
point = 0;
if (((vertices_y[point] > latitude_y != (vertices_y[j] > latitude_y)) && (longitude_x < (vertices_x[j] - vertices_x[point]) * (latitude_y - vertices_y[point]) / (vertices_y[j] - vertices_y[point]) + vertices_x[point])))
c = !c;
}
return c;
}
// other function to check if line exist in polygon
function isinPolygonSecond(points, x, y) {
cornersX = new Array();
cornersY = new Array();
for (r = 0; r < points.length; r++) {
cornersX.push(points[r].x);
cornersY.push(points[r].y);
}
var i, j = cornersX.length - 1;
var odd = false;
var pX = cornersX;
var pY = cornersY;
for (i = 0; i < cornersX.length; i++) {
if ((pY[i] < y && pY[j] >= y || pY[j] < y && pY[i] >= y) &&
(pX[i] <= x || pX[j] <= x)) {
odd ^= (pX[i] + (y - pY[i]) * (pX[j] - pX[i]) / (pY[j] - pY[i])) < x;
}
j = i;
}
return odd;
}
var canvas = new fabric.Canvas("c", {
selection: false
});
var points = [];
var polygon = new fabric.Polygon([
new fabric.Point(150, 50),
new fabric.Point(250, 50),
new fabric.Point(250, 150),
new fabric.Point(150, 150),
new fabric.Point(50, 250),
]);
polygon.on("modified", function() {
//document.getElementById("p").innerHTML = JSON.stringify(this)+ "<br>";
var matrix = this.calcTransformMatrix();
var transformedPoints = this.get("points")
.map(function(p) {
return new fabric.Point(
p.x - polygon.pathOffset.x,
p.y - polygon.pathOffset.y);
})
.map(function(p) {
return fabric.util.transformPoint(p, matrix);
});
var circles = transformedPoints.map(function(p) {
return new fabric.Circle({
left: p.x,
top: p.y,
radius: 3,
fill: "red",
originX: "center",
originY: "center",
hasControls: false,
hasBorders: false,
selectable: false
});
});
//Lines Colors
var colors = ['red', 'green', 'blue', 'violet', 'teal', 'brown'];
//I need these distances from the polygon, where is negative value it should go inside polygon
var LinesDistances = [10, -5, -20, 0, 20, 40];
var lines = transformedPoints.map(function(p, i) {
var po = (i < polygon.points.length) ? i + 1 : 0;
if (typeof transformedPoints[po] === 'undefined')
po = 0;
var fromX = transformedPoints[po].x;
var fromY = transformedPoints[po].y;
var isinPolygon = isinPolygonFirst(transformedPoints, fromX, fromY);
var isinPolygon2 = isinPolygonSecond(transformedPoints, fromX, fromY);
var debug = '';
debug += 'fromX:' + fromX;
debug += ' ,fromY :' + fromY;
debug += ' ,isinPolygon:' + isinPolygon;
debug += ' ,isinPolygonSecond:' + isinPolygon2;
document.getElementById("p").innerHTML += '<p style="color:#fff;background:' + colors[i] + '"> ' + debug + "</p>";
return new fabric.Line([p.x, p.y, fromX, fromY], {
stroke: colors[i],
strokeWidth: 10,
hasBorders: true,
strokeDashArray: [20, 5]
});
});
this.canvas.clear().add(this).add.apply(this.canvas, lines).add.apply(this.canvas, circles).setActiveObject(this).renderAll();
polygon.set({
opacity: 0.5
});
polygon.sendToBack();
});
canvas.add(polygon).renderAll();
canvas {
border: 1px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.2/fabric.min.js"></script>
<div id="p"></div>
<canvas id="c" width="600" height="400"></canvas>
I am not certain if it's the right approach I am moving to, I wants to dynamically distance lines around the polygon as it will be required.
I need these distances from the polygon, where is negative value it should go inside polygon
var LinesDistances = [10, -5, -20, 0, 20, 40];
Here is fiddle and code. at https://jsfiddle.net/DivMaster/0e34Lnyx/211/
Any help? Thanks <3
I was able to solve it by using Intersects library available at https://github.com/davidfig/intersects
I calculated the midpoint of line and performed plus/minus operations on x/y points to see if points reside in polygon
pointPolygon(x1, y1, points)
I am attempting to build something like this but instead of it being a line, I want it to be circles. That way I can add a different fill. So far, I am able to have it move on mouse over with this code but only for the first circle. How can I get them to follow in a line?
// The amount of points in the path:
var points = 30;
// The distance between the points:
var length = 10;
var path = new paper.Path({
strokeColor: "white",
strokeWidth: 50,
strokeCap: "round"
});
var start = view.center / [10, 1];
// Circle
var circlePath = new Path.Circle({
center: [80, 50],
fillColor: "transparent",
radius: 50
});
var thirdLayer = new Group();
for (var i = 0; i < points; i++) path.add(start + new Point(i * length, 0));
console.log(path);
// // for (var i = 0; i < points; i++) path.add(end + new Point(i * length, 0));
// // path.addSegments([[657.55, 455], [657.55, 500.5]]);
// path.closed = true;
function onMouseMove(event) {
path.firstSegment.point = event.point;
for (var i = 0; i < points - 1; i++) {
var segment = path.segments[i];
var nextSegment = segment.next;
var vector = segment.point - nextSegment.point;
vector.length = length;
nextSegment.point = segment.point - vector;
}
// rect.subtract(nextSegment.point);
path.smooth({ type: "continuous" });
var rect = new paper.Path.Rectangle({
point: [0, 0],
size: [view.size.width],
fillColor: "#E50069",
strokeWidth: 1
});
// path.offset(10);
var drilled = rect.subtract(path);
secondLayer.removeChildren();
secondLayer.addChild(drilled);
rect.remove();
secondLayer.addChild();
}
function onMouseDown(event) {
console.log(event);
path.fullySelected = true;
path.strokeColor = "#e08285";
}
function onMouseUp(event) {
path.fullySelected = false;
path.strokeColor = "#fff";
path.opacity = 1;
}
// function onFrame(event) {
// rect.unite(path);
// }
Any insight on what way to move forward would be appreciated.
Based on your reference, here is a sketch demonstrating a possible solution.
var points = 25;
var length = 35;
var path = new Path();
var start = view.center / [10, 1];
for (var i = 0; i < points; i++) {
path.add(start + new Point(i * length, 0));
}
// Create a circle for each segment of the path.
var circles = [];
for (var i = 0; i < path.segments.length; i++) {
var circle = new Path.Circle({
center: path.segments[i].point,
radius: 10,
strokeColor: 'red'
});
circles.push(circle);
}
function onMouseMove(event) {
path.firstSegment.point = event.point;
for (var i = 0; i < points - 1; i++) {
var segment = path.segments[i];
var nextSegment = segment.next;
var vector = segment.point - nextSegment.point;
vector.length = length;
nextSegment.point = segment.point - vector;
}
// Each time the path is updated, update circles position.
updateCirclesPosition();
}
function updateCirclesPosition() {
for (var i = 0; i < path.segments.length; i++) {
circles[i].position = path.segments[i].point;
}
}
Edit
Based on your comment below, here is a sketch demonstrating how to use the same logic to produce a "reveal image" effect.
The tricks relies on using blend mode to compose layers rather than having to use boolean operations (I originally posted it here).
// First draw an image as background.
var background = new Raster({
source: 'http://assets.paperjs.org/images/marilyn.jpg',
onLoad: function() {
// Make it fill all the screen.
this.fitBounds(view.bounds, true);
}
});
// Draw a rectangle to hide the background.
var maskBase = new Path.Rectangle({
rectangle: view.bounds,
fillColor: 'white'
});
// Prepare a group to store the circles that will make the background appear.
var circles = new Group({
blendMode: 'destination-out'
});
// Assemble both previous element in a group in order to make it display as we
// need.
var mask = new Group({
children: [maskBase, circles],
blendMode: 'source-over'
});
// Then prepare the path.
var points = 25;
var length = 35;
var path = new Path();
var start = view.center / [10, 1];
for (var i = 0; i < points; i++) {
path.add(start + new Point(i * length, 0));
}
// Create a circle for each segment of the path.
for (var i = 0; i < path.segments.length; i++) {
var circle = new Path.Circle({
center: path.segments[i].point,
radius: 10,
fillColor: 'red'
});
circles.addChild(circle);
}
// Update the path when the mouse moves.
function onMouseMove(event) {
path.firstSegment.point = event.point;
for (var i = 0; i < points - 1; i++) {
var segment = path.segments[i];
var nextSegment = segment.next;
var vector = segment.point - nextSegment.point;
vector.length = length;
nextSegment.point = segment.point - vector;
}
// Each time the path is updated, update circles position.
updateCirclesPosition();
}
function updateCirclesPosition() {
for (var i = 0; i < path.segments.length; i++) {
circles.children[i].position = path.segments[i].point;
}
}
For general lines with two or three vertices, I got help from #Wilt at the question: Can I merge geometry in every frame in rendering process using three.js?
So that I can generate a large number of lines with one single bufferGeometry.
using the code like:
var geometry = new THREE.BufferGeometry();
positions = new Float32Array(total * pointsNum * 3);
geometry.addAttribute(
'position', new THREE.BufferAttribute(positions, 3)
);
var material = new THREE.LineBasicMaterial({
transparent: true,
color: 0x0000ff,
opacity: 1
});
var line = new THREE.Line(bufferGeometry, material);
var all_vertices = [new THREE.Vector3(-1, 0, 0), new THREE.Vector3(0, 1, 0), new THREE.Vector3(1, 0, 0)];
for(var i = 0; i< all_vertices.length; i++){
positions[i] = all_vertices[i].x;
positions[i+1] = all_vertices[i].y;
positions[i+2] = all_vertices[i].z;
}
var start = all_vertices.length;
var end = start + all_vertices.length;
bufferGeometry.addGroup(start, end);
line.geometry.attributes.position.needsUpdate = true
What I was thinking is apparently too naive that I could get a CatmullRomCurve3 line by easily adding more vertices in var all_vertices. The fact is it is not that easy. For example, I got a few vertices like:
var maxX = Math.random() * 0.7 + 0.7;
var maxY = Math.random() * (maxX / 2) + 0.01;
var maxZ = Math.random() * (maxX - maxY) + maxY;
console.log(maxX + ' ' + maxY + ' ' + maxZ);
//32, 45, 38, 36, 35, 39, 41, 42
var degs = [32, 45, 38, 36, 35, 39, 41, 42];
var alpha = 32;
var tgAlpha = Math.tan(alpha);
var xpow = maxX * maxX;
var zpow = maxZ * maxZ;
orig[0] = new THREE.Vector3(-maxX, 0, 0);
var x1 = -Math.sqrt(xpow * zpow / (zpow + tgAlpha * xpow));
var z1 = x1 * tgAlpha;
orig[1] = new THREE.Vector3(x1, maxY, z1);
orig[2] = new THREE.Vector3(-x1, -maxY, z1);
orig[3] = new THREE.Vector3(maxX, 0, 0);
orig[4] = new THREE.Vector3(-x1, maxY, -z1);
orig[5] = new THREE.Vector3(x1, -maxY, -z1);
And apply them to var curve = new THREE.CatmullRomCurve3(orig); curve.closed = true;, As a result, I can get one closed line like a infinity sign in the 3D space.
So how can I use these vertices to create the CatmullRomCurve3 from bufferGeometry? Can I scale it to some other size?
The Jsfiddle is https://jsfiddle.net/do7ur33u/2/
Thanks for any help.
I'm trying to display geospatial data in a hexagonal grid on a Google Map.
In order to do so, given a hexagon tile grid size X I need to be able to convert ({lat, lng}) coordinates into the ({lat, lng}) centers of the hexagon grid tiles that contain them.
In the end, I would like to be able to display data on a Google Map like this:
Does anybody have any insight into how this is done?
I've tried porting this Python hexagon binning script, binner.py to Javascript but it doesn't seem to be working properly- the output values are all the same as the input ones.
For the sake of this example, I don't care if there are multiple polygons in a single location, I just need to figure out how to bin them into the correct coordinates.
Code below, (Plunker here!)
var map;
var pointCount = 0;
var locations = [];
var gridWidth = 200000; // hex tile size in meters
var bounds;
var places = [
[44.13, -69.51],
[45.23, -67.42],
[46.33, -66.53],
[44.43, -65.24],
[46.53, -64.15],
[44.63, -63.06],
[44.73, -62.17],
[43.83, -63.28],
[44.93, -64.39],
[44.13, -65.41],
[41.23, -66.52],
[44.33, -67.63],
[42.43, -68.74],
[44.53, -69.65],
[40.63, -70.97],
]
var SQRT3 = 1.73205080756887729352744634150587236;
$(document).ready(function(){
bounds = new google.maps.LatLngBounds();
map = new google.maps.Map(document.getElementById("map_canvas"), {center: {lat: 0, lng: 0}, zoom: 2});
// Adding a marker just so we can visualize where the actual data points are.
// In the end, we want to see the hex tile that contain them
places.forEach(function(place, p){
latlng = new google.maps.LatLng({lat: place[0], lng: place[1]});
marker = new google.maps.Marker({position: latlng, map: map})
// Fitting to bounds so the map is zoomed to the right place
bounds.extend(latlng);
});
map.fitBounds(bounds);
// Now, we draw our hexagons! (or try to)
locations = makeBins(places);
locations.forEach(function(place, p){
drawHorizontalHexagon(map, place, gridWidth);
})
});
function drawHorizontalHexagon(map,position,radius){
var coordinates = [];
for(var angle= 0;angle < 360; angle+=60) {
coordinates.push(google.maps.geometry.spherical.computeOffset(position, radius, angle));
}
// Construct the polygon.
var polygon = new google.maps.Polygon({
paths: coordinates,
position: position,
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35,
geodesic: true
});
polygon.setMap(map);
}
// Below is my attempt at porting binner.py to Javascript.
// Source: https://github.com/coryfoo/hexbins/blob/master/hexbin/binner.py
function distance(x1, y1, x2, y2){
console.log(x1, y1, x2, y2);
result = Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
console.log("Distance: ", result);
return result;
}
function nearestCenterPoint(value, scale){
div = (value / (scale / 2));
mod = value % (scale / 2);
if(div % 2 == 1){
increment = 1;
} else {
increment = 0;
}
rounded = (scale / 2) * (div + increment);
if(div % 2 === 0){
increment = 1;
} else {
increment = 0;
}
rounded_scaled = (scale / 2) * (div + increment)
result = [rounded, rounded_scaled];
return result;
}
function makeBins(data){
bins = [];
data.forEach(function(place, p){
x = place[0];
y = place[1];
console.log("Original location:", x, y);
px_nearest = nearestCenterPoint(x, gridWidth);
py_nearest = nearestCenterPoint(y, gridWidth * SQRT3);
z1 = distance(x, y, px_nearest[0], py_nearest[0]);
z2 = distance(x, y, px_nearest[1], py_nearest[1]);
console.log(z1, z2);
if(z1 > z2){
bin = new google.maps.LatLng({lat: px_nearest[0], lng: py_nearest[0]});
console.log("Final location:", px_nearest[0], py_nearest[0]);
} else {
bin = new google.maps.LatLng({lat: px_nearest[1], lng: py_nearest[1]});
console.log("Final location:", px_nearest[1], py_nearest[1]);
}
bins.push(bin);
})
return bins;
}
Use google.maps.geometry.poly.containsLocation.
for (var i = 0; i < hexgrid.length; i++) {
if (google.maps.geometry.poly.containsLocation(place, hexgrid[i])) {
if (!hexgrid[i].contains) {
hexgrid[i].contains = 0;
}
hexgrid[i].contains++
}
}
Example based off this related question: How can I make a Google Maps API v3 hexagon tiled map, preferably coordinate-based?. The number in the white box in the center of each hexagon is the number of markers contained by it.
proof of concept fiddle
code snippet:
var map = null;
var hexgrid = [];
function initMap() {
var myOptions = {
zoom: 8,
center: new google.maps.LatLng(43, -79.5),
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
},
navigationControl: true,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map"),
myOptions);
createHexGrid();
var bounds = new google.maps.LatLngBounds();
// Seed our dataset with random locations
for (var i = 0; i < hexgrid.length; i++) {
var hexbounds = new google.maps.LatLngBounds();
for (var j = 0; j < hexgrid[i].getPath().getLength(); j++) {
bounds.extend(hexgrid[i].getPath().getAt(j));
hexbounds.extend(hexgrid[i].getPath().getAt(j));
}
hexgrid[i].bounds = hexbounds;
}
var span = bounds.toSpan();
var locations = [];
for (pointCount = 0; pointCount < 50; pointCount++) {
place = new google.maps.LatLng(Math.random() * span.lat() + bounds.getSouthWest().lat(), Math.random() * span.lng() + bounds.getSouthWest().lng());
bounds.extend(place);
locations.push(place);
var mark = new google.maps.Marker({
map: map,
position: place
});
// bin points in hexgrid
for (var i = 0; i < hexgrid.length; i++) {
if (google.maps.geometry.poly.containsLocation(place, hexgrid[i])) {
if (!hexgrid[i].contains) {
hexgrid[i].contains = 0;
}
hexgrid[i].contains++
}
}
}
// add labels
for (var i = 0; i < hexgrid.length; i++) {
if (typeof hexgrid[i].contains == 'undefined') {
hexgrid[i].contains = 0;
}
var labelText = "<div style='background-color:white'>" + hexgrid[i].contains + "</div>";
var myOptions = {
content: labelText,
boxStyle: {
border: "1px solid black",
textAlign: "center",
fontSize: "8pt",
width: "20px"
},
disableAutoPan: true,
pixelOffset: new google.maps.Size(-10, 0),
position: hexgrid[i].bounds.getCenter(),
closeBoxURL: "",
isHidden: false,
pane: "floatPane",
enableEventPropagation: true
};
var ibLabel = new InfoBox(myOptions);
ibLabel.open(map);
}
}
function createHexGrid() {
// === Hexagonal grid ===
var point = new google.maps.LatLng(42, -78.8);
map.setCenter(point);
var hex1 = google.maps.Polygon.RegularPoly(point, 25000, 6, 90, "#000000", 1, 1, "#00ff00", 0.5);
hex1.setMap(map);
var d = 2 * 25000 * Math.cos(Math.PI / 6);
hexgrid.push(hex1);
var hex30 = google.maps.Polygon.RegularPoly(EOffsetBearing(point, d, 30), 25000, 6, 90, "#000000", 1, 1, "#00ffff", 0.5);
hex30.setMap(map);
hexgrid.push(hex30);
var hex90 = google.maps.Polygon.RegularPoly(EOffsetBearing(point, d, 90), 25000, 6, 90, "#000000", 1, 1, "#ffff00", 0.5);
hex90.setMap(map);
hexgrid.push(hex90);
var hex150 = google.maps.Polygon.RegularPoly(EOffsetBearing(point, d, 150), 25000, 6, 90, "#000000", 1, 1, "#00ffff", 0.5);
hex150.setMap(map);
hexgrid.push(hex150);
var hex210 = google.maps.Polygon.RegularPoly(EOffsetBearing(point, d, 210), 25000, 6, 90, "#000000", 1, 1, "#ffff00", 0.5);
hex210.setMap(map);
hexgrid.push(hex210);
hex270 = google.maps.Polygon.RegularPoly(EOffsetBearing(point, d, 270), 25000, 6, 90, "#000000", 1, 1, "#ffff00", 0.5);
hex270.setMap(map);
hexgrid.push(hex270);
var hex330 = google.maps.Polygon.RegularPoly(EOffsetBearing(point, d, 330), 25000, 6, 90, "#000000", 1, 1, "#ffff00", 0.5);
hex330.setMap(map);
hexgrid.push(hex330);
var hex30_2 = google.maps.Polygon.RegularPoly(EOffsetBearing(EOffsetBearing(point, d, 30), d, 90), 25000, 6, 90, "#000000", 1, 1, "#ff0000", 0.5);
hex30_2.setMap(map);
hexgrid.push(hex30_2);
var hex150_2 = google.maps.Polygon.RegularPoly(EOffsetBearing(EOffsetBearing(point, d, 150), d, 90), 25000, 6, 90, "#000000", 1, 1, "#0000ff", 0.5);
hex150_2.setMap(map);
hexgrid.push(hex150_2);
var hex90_2 = google.maps.Polygon.RegularPoly(EOffsetBearing(EOffsetBearing(point, d, 90), d, 90), 25000, 6, 90, "#000000", 1, 1, "#00ff00", 0.5);
hex90_2.setMap(map);
hexgrid.push(hex90_2);
// This Javascript is based on code provided by the
// Community Church Javascript Team
// http://www.bisphamchurch.org.uk/
// http://econym.org.uk/gmap/
//]]>
}
google.maps.event.addDomListener(window, 'load', initMap);
// EShapes.js
//
// Based on an idea, and some lines of code, by "thetoy"
//
// This Javascript is provided by Mike Williams
// Community Church Javascript Team
// http://www.bisphamchurch.org.uk/
// http://econym.org.uk/gmap/
//
// This work is licenced under a Creative Commons Licence
// http://creativecommons.org/licenses/by/2.0/uk/
//
// Version 0.0 04/Apr/2008 Not quite finished yet
// Version 1.0 10/Apr/2008 Initial release
// Version 3.0 12/Oct/2011 Ported to v3 by Lawrence Ross
google.maps.Polygon.Shape = function(point, r1, r2, r3, r4, rotation, vertexCount, strokeColour, strokeWeight, Strokepacity, fillColour, fillOpacity, opts, tilt) {
var rot = -rotation * Math.PI / 180;
var points = [];
var latConv = google.maps.geometry.spherical.computeDistanceBetween(point, new google.maps.LatLng(point.lat() + 0.1, point.lng())) * 10;
var lngConv = google.maps.geometry.spherical.computeDistanceBetween(point, new google.maps.LatLng(point.lat(), point.lng() + 0.1)) * 10;
var step = (360 / vertexCount) || 10;
var flop = -1;
if (tilt) {
var I1 = 180 / vertexCount;
} else {
var I1 = 0;
}
for (var i = I1; i <= 360.001 + I1; i += step) {
var r1a = flop ? r1 : r3;
var r2a = flop ? r2 : r4;
flop = -1 - flop;
var y = r1a * Math.cos(i * Math.PI / 180);
var x = r2a * Math.sin(i * Math.PI / 180);
var lng = (x * Math.cos(rot) - y * Math.sin(rot)) / lngConv;
var lat = (y * Math.cos(rot) + x * Math.sin(rot)) / latConv;
points.push(new google.maps.LatLng(point.lat() + lat, point.lng() + lng));
}
return (new google.maps.Polygon({
paths: points,
strokeColor: strokeColour,
strokeWeight: strokeWeight,
strokeOpacity: Strokepacity,
fillColor: fillColour,
fillOpacity: fillOpacity
}))
}
google.maps.Polygon.RegularPoly = function(point, radius, vertexCount, rotation, strokeColour, strokeWeight, Strokepacity, fillColour, fillOpacity, opts) {
rotation = rotation || 0;
var tilt = !(vertexCount & 1);
return google.maps.Polygon.Shape(point, radius, radius, radius, radius, rotation, vertexCount, strokeColour, strokeWeight, Strokepacity, fillColour, fillOpacity, opts, tilt)
}
function EOffsetBearing(point, dist, bearing) {
var latConv = google.maps.geometry.spherical.computeDistanceBetween(point, new google.maps.LatLng(point.lat() + 0.1, point.lng())) * 10;
var lngConv = google.maps.geometry.spherical.computeDistanceBetween(point, new google.maps.LatLng(point.lat(), point.lng() + 0.1)) * 10;
var lat = dist * Math.cos(bearing * Math.PI / 180) / latConv;
var lng = dist * Math.sin(bearing * Math.PI / 180) / lngConv;
return new google.maps.LatLng(point.lat() + lat, point.lng() + lng)
}
html,
body,
#map {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<script src="https://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/src/infobox.js"></script>
<div id="map"></div>
Take a look at deck.gl and its hexagon layer
https://deck.gl/docs/api-reference/geo-layers/h3-hexagon-layer
With the getHexagon function, you can retrieve the H3 hexagon index of each object.
Then, you can use H3's cellToLatLng function to retrieve the hexagon cell's center coordinates.
But actually, you won't need this step if you just want to create a hexagonal data grid like the one you have shown in the image. You can simply feed the data into the deck.gl hexagon layer and the framework will do the rest to produce the output you want.