Draw Rectangles in Area on Google Maps - javascript

I'm drawing an area on Google Maps using the Geometry API. I want to know if it is possible to draw a repeating element onto an area that is dynamic in size?
For example, if I draw my area to look like this:
Then I want to be able to hit 'Next Step' and see something like this, with the rectangles drawn in the area, but only if they will fit. i.e., they have to be 'full' rectangles, not part rectangles:
The only problem is, I'm not entirely sure how to go about this. I would use HTML5 <canvas> but unfortunately, this needs to be as browser-friendly as possible, but if it has to be <canvas> then so be it!

Although I didn't use canvas, how about this code?
function onPolygonComplete(polygon) {
var bounds, paths, sw, ne, ystep, xstep,
boxH, boxW, posArry, flag, pos,
x, y, i, box, maxBoxCnt;
//Delete old boxes.
boxes.forEach(function(box, i) {
box.setMap(null);
delete box;
});
//Calculate the bounds that contains entire polygon.
bounds = new google.maps.LatLngBounds();
paths = polygon.getPath();
paths.forEach(function(latlng, i){
bounds.extend(latlng);
});
//Calculate the small box size.
maxBoxCnt = 8;
sw = bounds.getSouthWest();
ne = bounds.getNorthEast();
ystep = Math.abs(sw.lat() - ne.lat()) / maxBoxCnt;
boxH = Math.abs(sw.lat() - ne.lat()) / (maxBoxCnt + 1);
xstep = Math.abs(sw.lng() - ne.lng()) / maxBoxCnt;
boxW = Math.abs(sw.lng() - ne.lng()) / (maxBoxCnt + 1);
for (y = 0; y < maxBoxCnt; y++) {
for (x = 0; x < maxBoxCnt; x++) {
//Detect that polygon is able to contain a small box.
bounds = new google.maps.LatLngBounds();
posArry = [];
posArry.push(new google.maps.LatLng(sw.lat() + ystep * y, sw.lng() + xstep * x));
posArry.push(new google.maps.LatLng(sw.lat() + ystep * y, sw.lng() + xstep * x + boxW));
posArry.push(new google.maps.LatLng(sw.lat() + ystep * y + boxH, sw.lng() + xstep * x));
posArry.push(new google.maps.LatLng(sw.lat() + ystep * y + boxH, sw.lng() + xstep * x + boxW));
flag = true;
for (i = 0; i < posArry.length; i++) {
pos = posArry[i];
if (flag) {
flag = google.maps.geometry.poly.containsLocation(pos, polygon);
bounds.extend(pos);
}
}
//Draw a small box.
if (flag) {
box = new google.maps.Rectangle({
bounds : bounds,
map : mapCanvas,
strokeColor: '#00ffff',
strokeOpacity: 0.5,
strokeWeight: 1,
fillColor: '#00ffff',
fillOpacity : 0.5,
clickable: false
});
boxes.push(box);
}
}
}
}
This code works like this image.
I wrote a page that explains the code.
http://googlemaps.googlermania.com/google_maps_api_v3/en/poly_containsLocation.html

#Joshua M
Sorry for keeping you wait.
Ok, the new code is below.
You can specify the small box size at var boxSize = new google.maps.Size(10, 20);
<!DOCTYPE html>
<html>
<head>
<script src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=geometry"></script>
<script type='text/javascript'>
var mapCanvas, boxes = new google.maps.MVCArray();
function initialize() {
var mapDiv = document.getElementById("map_canvas");
mapCanvas = new google.maps.Map(mapDiv, {
center : new google.maps.LatLng(37.422191,-122.084585),
mapTypeId : google.maps.MapTypeId.SATELLITE,
zoom : 19,
tilt : 0
});
//Encoded path
var encodedPath = "eblcFnuchVv#D#q#P?a#eD]AC~#b#DCz#a#A";
var points = google.maps.geometry.encoding.decodePath(encodedPath);
//Draw a polygon
var polygonOpts = {
paths : points,
strokeWeight : 6,
strokeColor : "#FF0000",
strokeOpacity : 1,
//fillColor : "blue",
fillOpacity : 0,
map : mapCanvas,
editable : true
};
var poly = new google.maps.Polygon(polygonOpts);
var proc = function() {
onPolygonComplete(poly);
};
google.maps.event.addListener(mapCanvas, "projection_changed", proc);
google.maps.event.addListener(poly.getPath(), 'insert_at', proc);
google.maps.event.addListener(poly.getPath(), 'remove_at', proc);
google.maps.event.addListener(poly.getPath(), 'set_at', proc);
}
function onDrawMgr_complete(polygon) {
var path = polygon.getPath();
console.log(google.maps.geometry.encoding.encodePath(path));
}
function onPolygonComplete(polygon) {
var bounds, paths, sw, ne, ystep, xstep, boxH, boxW, posArry, flag, pos, x, y, i, box;
//Delete old boxes.
boxes.forEach(function(box, i) {
box.setMap(null);
delete box;
});
//Calculate the bounds that contains entire polygon.
bounds = new google.maps.LatLngBounds();
paths = polygon.getPath();
paths.forEach(function(latlng, i) {
bounds.extend(latlng);
});
var projection = mapCanvas.getProjection();
var zoom = mapCanvas.getZoom();
var powBase = Math.pow(2, zoom);
//Calculate the small box size.
sw = bounds.getSouthWest();
ne = bounds.getNorthEast();
var swPoint = projection.fromLatLngToPoint(sw);
var nePoint = projection.fromLatLngToPoint(ne);
var boxSize = new google.maps.Size(10, 20); //in pixels.
boxSize.width /= powBase;
boxSize.height /= powBase;
var maxX = Math.floor(Math.abs((swPoint.x - nePoint.x)) / boxSize.width);
var maxY = Math.floor(Math.abs((swPoint.y - nePoint.y)) / boxSize.height);
for ( y = 0; y < maxY; y++) {
for (x = 0; x < maxX; x++) {
//Detect that polygon is able to contain a small box.
bounds = new google.maps.LatLngBounds();
posArry = [];
posArry.push(new google.maps.Point(swPoint.x + boxSize.width * x, swPoint.y - boxSize.height * y));
posArry.push(new google.maps.Point(swPoint.x + boxSize.width * x, swPoint.y - boxSize.height * (y + 1)));
posArry.push(new google.maps.Point(swPoint.x + boxSize.width * (x + 1), swPoint.y - boxSize.height * y));
posArry.push(new google.maps.Point(swPoint.x + boxSize.width * (x + 1), swPoint.y - boxSize.height * (y + 1)));
var flag = true;
for (var i = 0; i < posArry.length; i++) {
pos = projection.fromPointToLatLng(posArry[i]);
if (flag) {
flag = google.maps.geometry.poly.containsLocation(pos, polygon);
bounds.extend(pos);
}
}
if (flag) {
box = new google.maps.Rectangle({
bounds : bounds,
map : mapCanvas,
strokeColor : 'green',
strokeOpacity : 1,
strokeWeight : 1,
fillColor : 'yellow',
fillOpacity : 0.5,
clickable : false
});
boxes.push(box);
}
}
}
}
google.maps.event.addDomListener(window, "load", initialize);
</script>
<style type="text/css">
window,html,#map_canvas{
width : 700px;
height : 500px;
}
</style>
</head>
<body>
<div id="map_canvas"/>
</body>
</html>

Related

Ol-ext: rotation changes image size

I am using ol.interaction.Transform to rotate one image on the map after selecting it. The final goal is to have the possibility to scale, stretch, rotate and translate (drag&drop) the image.
My problems are that:
when I rotate the image, it does not keep the aspect ratio (the size of the image change furthermore it stretches)
the red dotted line that appears along the image perimeter when the image is selected does not follow the movement of the rotation, e.g this is how it looks before I start the rotation:
and this is how it looks meanwhile I am doing the rotation:
I would aspect indeed something like this (black dotted line):
How can I fix it?
This is my code:
var styleCache = {};
function getStyle(img, scaleX, scaleY) {
var view = map.getView();
var resolutionAtEquator = view.getResolution();
var y = Math.round(img.height * scaleY);
var x = Math.round(img.width * scaleX);
var key = img.src + ',' + x + ',' + y;
var style = styleCache[key];
if (!style) {
var canvas = document.createElement('canvas');
canvas.width = x;
canvas.height = y;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, x, y);
var resizeImageUrl = canvas.toDataURL();
canvas.remove();
var keys = Object.keys(styleCache);
if (keys.length >= 100) {
// delete an old entry to limit the cache size
delete styleCache[keys[0]];
}
var style = new ol.style.Style({
image: new ol.style.Icon({
src: resizeImageUrl,
opacity: imageOpacity,
})
});
styleCache[key] = style;
}
return style;
}
styles = [
new ol.style.Style({
fill: new ol.style.Fill({
color: transparent
})
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: transparent,
width: width + 2
})
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: transparent,
width: width
})
}),
new ol.style.Style({
image: new ol.style.Circle({
radius: width * 2,
fill: new ol.style.Fill({
color: blue
}),
stroke: new ol.style.Stroke({
color: transparent,
width: width / 2
})
}),
zIndex: Infinity
})
];
var florplanStyle = new ol.style.Style({
image: new ol.style.Icon({
src: img.src,
opacity: imageOpacity,
})
});
styleFunction = function(feature, resolution) {
var rayDrawValueX = img.width/2;
var resAdjustX = rayDrawValueX * resolution;
var rayDrawValueY = img.height/2;
var resAdjustY = rayDrawValueY * resolution;
var rotation = feature.get('rotation');
if (rotation !== undefined) {
var extent = feature.getGeometry().getExtent();
var coordinates = feature.getGeometry().getCoordinates()[0];
var getBottomLeft = ol.extent.getBottomLeft(extent);
var getBottomRight = ol.extent.getBottomRight(extent);
var getTopLeft = ol.extent.getTopLeft(extent);
var getTopRight = ol.extent.getTopRight(extent);
var center = ol.extent.getCenter(extent);
var dx = center[0] - getBottomLeft[0];
var dy = 0;
var scaleX = Math.sqrt(dx * dx + dy * dy)/resAdjustX;
var dx = 0;
var dy = getTopRight[1] - center[1];
var scaleY = Math.sqrt(dx * dx + dy * dy)/resAdjustY;
var florplanStyle2 = getStyle(img, scaleX, scaleY);
florplanStyle2.setGeometry(new ol.geom.Point(center));
florplanStyle2.getImage().setRotation(rotation);
return debug ? styles.concat([florplanStyle2]) : florplanStyle2;
} else if (feature.getGeometry().getCenter) {
//scrolling map case
florplanStyle.setGeometry(new ol.geom.Point(feature.getGeometry().getCenter()));
// get rotation from drawn feature or geometry
florplanStyle.getImage().setRotation(feature.getGeometry().get('rotation'));
florplanStyle.getImage().setScale(feature.getGeometry().getRadius()/resAdjustX);
return florplanStyle;
} else {
return styles;
}
};
if ( this.nord && this.sud && this.est && this.ovest && this.floorplanImage && this.opacity) {
var extent = ol.proj.transformExtent([this.ovest, this.sud, this.est, this.nord], 'EPSG:4326', 'EPSG:3857');
var center = ol.extent.getCenter(extent);
var size = ol.extent.getSize(extent);
var view = map.getView();
var resolutionAtEquator = view.getResolution();
var width = ol.extent.getWidth(extent);
var height = ol.extent.getHeight(extent);
var radius = width/2;
var rotation = 0;
var circle = circle || new ol.geom.Circle(center, radius);
var circleFeature = new ol.Feature(circle);
circleFeature.set('rotation', rotation);
var geom = ol.geom.Polygon.fromExtent(extent);
circleFeature.setGeometry(geom);
this.features.push(circleFeature);
this.mapView.fit(geom, {minResolution: 0.05});
} else {
this.controller.fireEvent('mapstaterequest');
}
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var source = new ol.source.Vector({
wrapX: false,
features: this.features
});
var vector = new ol.layer.Vector({
source: source,
style: styleFunction
});
vector.setMap(map);
var draw = new ol.interaction.Draw({
source: source,
type: 'Circle',
geometryFunction: function(coordinates, geometry) {
var center = coordinates[0];
var last = coordinates[1];
var dx = center[0] - last[0];
var dy = center[1] - last[1];
var radius = dx;
var rotation = Math.PI - Math.atan2(dy, dx);
geometry = geometry || new ol.geom.Circle(center, radius);
geometry.setCenterAndRadius(center, radius);
geometry.set('rotation', rotation);
return geometry;
},
style: styleFunction,
handler: 'onSaveClick'
});
draw.on('drawstart', function () {
source.clear();
});
draw.on('drawend', function (evt) {
// move rotation from geometry to drawn feature
var rotation = evt.feature.getGeometry().get('rotation');
evt.feature.set('rotation', rotation);
var extent = evt.feature.getGeometry().getExtent();
var geom = ol.geom.Polygon.fromExtent(extent);
if(img.width!==img.height){
scaleY = img.height/img.width
geom.scale(1,scaleY);
}
evt.feature.setGeometry(geom);
});
this.map.addInteraction(draw);
var isCorner = true; // use opposite corner to scale/stretch, (false = use center);
var transform = new ol.interaction.Transform({
features: this.features,
translateFeature: false,
// flip wouldn't be compatible with rotation
noFlip: true,
rotate: true,
modifyCenter: function(){ return isCorner; }
});
var startangle = 0;
transform.on('select', function(e) {
draw.setActive(e.features.length == 0 );
});
transform.on('rotatestart', function(e) {
startangle = e.feature.get('rotation') || 0;
});
transform.on('rotating', function (e) {
// Set angle attribute to be used on style !
e.feature.set('rotation', startangle - e.angle);
});
this.map.addInteraction(transform);
This is the part of the code where I have the feeling I am doing something wrong, but I don't understand what:
if (rotation !== undefined) {
var extent = feature.getGeometry().getExtent();
var coordinates = feature.getGeometry().getCoordinates()[0];
var getBottomLeft = ol.extent.getBottomLeft(extent);
var getBottomRight = ol.extent.getBottomRight(extent);
var getTopLeft = ol.extent.getTopLeft(extent);
var getTopRight = ol.extent.getTopRight(extent);
var center = ol.extent.getCenter(extent);
var dx = center[0] - getBottomLeft[0];
var dy = 0;
var scaleX = Math.sqrt(dx * dx + dy * dy)/resAdjustX;
var dx = 0;
var dy = getTopRight[1] - center[1];
var scaleY = Math.sqrt(dx * dx + dy * dy)/resAdjustY;
var florplanStyle2 = getStyle(img, scaleX, scaleY);
florplanStyle2.setGeometry(new ol.geom.Point(center));
florplanStyle2.getImage().setRotation(rotation);
return debug ? styles.concat([florplanStyle2]) : florplanStyle2;
}
I found a solution for my 2 problems. I felt right about the part of the code I mentioned at the bottom of my question. I was calculating scaleX and scaleY in the wrong way.
This is the correct code that fixed my first problem
when I rotate the image, it does not keep the aspect ratio
if (rotation !== undefined) {
//style during rotation
var extent = feature.getGeometry().getExtent();
var coordinates = feature.getGeometry().getCoordinates()[0];
var getTopLeft = coordinates[0];
var getBottomLeft = coordinates[1];
var getBottomRight = coordinates[2];
var getTopRight = coordinates[3];
var center = ol.extent.getCenter(extent);
var top = new ol.geom.LineString([getTopLeft, getTopRight]).getClosestPoint(center);
var left = new ol.geom.LineString([getTopLeft, getBottomLeft]).getClosestPoint(center);
var dx = center[0] - left[0];
var dy = center[1] - left[1];
var scaleX = Math.sqrt(dx * dx + dy * dy) / resAdjustX;
var dx = top[0] - center[0];
var dy = top[1] - center[1];
var scaleY = Math.sqrt(dx * dx + dy * dy) / resAdjustY;
var floorplanStyle2 = getStyle(img, scaleX, scaleY);
floorplanStyle2.setGeometry(new ol.geom.Point(center));
floorplanStyle2.getImage().setRotation(rotation);
return debug ? styles.concat([floorplanStyle2]) : floorplanStyle2;
}
About my second problem
the red dotted line that appears along the image perimeter when the
image is selected does not follow the movement of the rotation
In order to have this feature, I had to add keepRectangle: true to my ol.interaction.Transform variable. This feature was not initially working on my app because I was using ol-ext v3.1.2, so I had to change it first to the ol-ext v3.2.24 in order to use it.
This is my complete code:
var iconURL = '/media/floorplans/' + uploadedImage;
var transparent = [255, 255, 255, 0];
var blue = [0, 153, 255, 1];
var width = 3;
img.crossOrigin = 'anonymous';
img.src = iconURL;
this.features = new ol.Collection();
var styleCache = {};
function getStyle(img, scaleX, scaleY) {
var view = map.getView();
var resolutionAtEquator = view.getResolution();
var y = Math.round(img.height * scaleY);
var x = Math.round(img.width * scaleX);
var key = img.src + ',' + x + ',' + y;
var style = styleCache[key];
if (!style) {
var canvas = document.createElement('canvas');
canvas.width = x;
canvas.height = y;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, x, y);
var resizeImageUrl = canvas.toDataURL();
canvas.remove();
var keys = Object.keys(styleCache);
if (keys.length >= 100) {
// delete an old entry to limit the cache size
delete styleCache[keys[0]];
}
var style = new ol.style.Style({
image: new ol.style.Icon({
src: resizeImageUrl,
opacity: imageOpacity,
})
});
styleCache[key] = style;
}
return style;
}
// Patch because ol-ext is changing extent of circle during rotation
ol.geom.Circle.prototype.rotate = function(angle, anchor) {
var point = new ol.geom.Point(this.getCenter());
point.rotate(angle, anchor);
this.setCenter(point.getCoordinates());
};
styles = [
new ol.style.Style({
stroke: new ol.style.Stroke({
color: transparent,
width: width
})
}),
//pointer used to draw the image
new ol.style.Style({
image: new ol.style.Circle({
radius: width * 2,
fill: new ol.style.Fill({
color: blue
}),
}),
zIndex: Infinity
})
];
var floorplanStyle = new ol.style.Style({
image: new ol.style.Icon({
src: img.src,
opacity: imageOpacity,
})
});
styleFunction = function(feature, resolution) {
var rayDrawValueX = img.width / 2;
var resAdjustX = rayDrawValueX * resolution;
var rayDrawValueY = img.height / 2;
var resAdjustY = rayDrawValueY * resolution;
var rotation = feature.get('rotation');
if (rotation !== undefined) {
//style during rotation
var extent = feature.getGeometry().getExtent();
var coordinates = feature.getGeometry().getCoordinates()[0];
var getTopLeft = coordinates[0];
var getBottomLeft = coordinates[1];
var getBottomRight = coordinates[2];
var getTopRight = coordinates[3];
var center = ol.extent.getCenter(extent);
var top = new ol.geom.LineString([getTopLeft, getTopRight]).getClosestPoint(center);
var left = new ol.geom.LineString([getTopLeft, getBottomLeft]).getClosestPoint(center);
var dx = center[0] - left[0];
var dy = center[1] - left[1];
var scaleX = Math.sqrt(dx * dx + dy * dy) / resAdjustX;
var dx = top[0] - center[0];
var dy = top[1] - center[1];
var scaleY = Math.sqrt(dx * dx + dy * dy) / resAdjustY;
var floorplanStyle2 = getStyle(img, scaleX, scaleY);
floorplanStyle2.setGeometry(new ol.geom.Point(center));
floorplanStyle2.getImage().setRotation(rotation);
return debug ? styles.concat([floorplanStyle2]) : floorplanStyle2;
} else if (feature.getGeometry().getCenter) {
//style meanwhile drawing
floorplanStyle.setGeometry(new ol.geom.Point(feature.getGeometry().getCenter()));
// get rotation from drawn feature or geometry
floorplanStyle.getImage().setRotation(feature.getGeometry().get('rotation'));
floorplanStyle.getImage().setScale(feature.getGeometry().getRadius() / resAdjustX);
return floorplanStyle;
} else {
return styles;
}
};
if (this.nord && this.sud && this.est && this.ovest && this.floorplanImage && this.opacity) {
//floorplan when floorplan position map is opened
var extent = ol.proj.transformExtent([this.ovest, this.sud, this.est, this.nord], 'EPSG:4326', 'EPSG:3857');
var center = ol.extent.getCenter(extent);
var size = ol.extent.getSize(extent);
var view = map.getView();
var resolutionAtEquator = view.getResolution();
var width = ol.extent.getWidth(extent);
var height = ol.extent.getHeight(extent);
var radius = width / 2;
var rotation = this.rotation;
var rotationInRadian = rotation * Math.PI / 180;
var circle = circle || new ol.geom.Circle(center, radius);
var circleFeature = new ol.Feature(circle);
circleFeature.set('rotation', rotationInRadian);
var geom = ol.geom.Polygon.fromExtent(extent);
geom.rotate(-rotationInRadian, ol.extent.getCenter(geom.getExtent()));
circleFeature.setGeometry(geom);
this.features.push(circleFeature);
this.mapView.fit(geom, {
minResolution: 0.05
});
} else {
this.controller.fireEvent('mapstaterequest');
}
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var source = new ol.source.Vector({
features: this.features
});
var vector = new ol.layer.Vector({
source: source,
style: styleFunction,
updateWhileAnimating: true,
});
vector.setMap(map);
var draw = new ol.interaction.Draw({
source: source,
type: 'Circle',
geometryFunction: function(coordinates, geometry) {
var center = coordinates[0];
var last = coordinates[1];
var dx = center[0] - last[0];
var dy = center[1] - last[1];
var radius = dx;
var rotation = Math.PI - Math.atan2(dy, dx);
geometry = geometry || new ol.geom.Circle(center, radius);
geometry.setCenterAndRadius(center, radius);
geometry.set('rotation', rotation);
return geometry;
},
style: styleFunction,
});
draw.on('drawstart', function() {
source.clear();
});
draw.on('drawend', function(evt) {
var rotation = evt.feature.getGeometry().get('rotation');
evt.feature.set('rotation', rotation);
var extent = evt.feature.getGeometry().getExtent();
var geom = ol.geom.Polygon.fromExtent(extent);
if (img.width !== img.height) {
scaleY = img.height / img.width;
geom.scale(1, scaleY);
}
geom.rotate(-rotation, ol.extent.getCenter(geom.getExtent()));
evt.feature.setGeometry(geom);
});
this.map.addInteraction(draw);
var isCorner = true; // use opposite corner to scale/stretch, (false = use center);
var transform = new ol.interaction.Transform({
features: this.features,
keepRectangle: true,
// flip wouldn't be compatible with rotation
noFlip: true,
translateFeature: false,
rotate: true,
handler: 'onSaveClick',
modifyCenter: function() {
return isCorner;
}
});
var startangle;
transform.on('select', function(e) {
if (e.feature != undefined) {
draw.setActive(e.feature.length == 0);
} else {
draw.setActive(true);
}
});
transform.on(['rotatestart', 'scalestart'], function(e) {
startangle = e.feature.get('rotation') || 0;
});
transform.on('rotating', function(e) {
// Set angle attribute to be used on style !
e.feature.set('rotation', startangle - e.angle);
});
this.map.addInteraction(transform);

Adjusting lines positions on polygon

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)

Snap circle to a polyline in Leaflet

I have a polyline in leaflet on which I want to snap center a circle with which I want to move among the polyline so the circle is always at the center of the polyline.
Is there a way how to snap center of circle into center so when I move the circle it always centers on the polyline?
I've made a fiddle, where the circle is moved just on mousemove event: http://jsfiddle.net/v0bseuqz/32/
The main idea is to create a line (when mouse is moved) that strokes cursor coordinates from the top of the map to the bottom, and check if it intersects the polyline to which the circle should be snapped. It they intersect, their intersection should be new centre of the circle.
document.onload = loadMap();
function loadMap() {
var map = L.map('map').setView([0, 0], 12);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpandmbXliNDBjZWd2M2x6bDk3c2ZtOTkifQ._QA7i5Mpkd_m30IGElHziw', {
maxZoom: 18,
id: 'mapbox.streets',
accessToken: 'pk.eyJ1IjoiZW======V6ZTdlb2V5cyJ9.3HqHQ4BMRvSPaYe8ToA7YQ'
}).addTo(map);
L.polyline([
[-50, 1000],
[0, 0]
], {
color: 'red',
weight: 1
}).addTo(map);
var circle = L.circle([0, 0], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(map);
$( "#map" ).mousemove(function( event ) {
var cursorPoint = new L.Point(event.clientX, event.clientY);
var cursorLatLng = map.containerPointToLatLng(cursorPoint);
var intersection = (checkLineIntersection(0, 0, 1000, -50, cursorLatLng.lng, 1, cursorLatLng.lng, -1));
if (intersection.onLine1 && intersection.onLine2) {
circle.setLatLng(new L.LatLng(intersection.y, intersection.x));
}
});
}
function checkLineIntersection(line1StartX, line1StartY, line1EndX, line1EndY, line2StartX, line2StartY, line2EndX, line2EndY) {
// if the lines intersect, the result contains the x and y of the intersection (treating the lines as infinite) and booleans for whether line segment 1 or line segment 2 contain the point
var denominator, a, b, numerator1, numerator2, result = {
x: null,
y: null,
onLine1: false,
onLine2: false
};
denominator = ((line2EndY - line2StartY) * (line1EndX - line1StartX)) - ((line2EndX - line2StartX) * (line1EndY - line1StartY));
if (denominator == 0) {
return result;
}
a = line1StartY - line2StartY;
b = line1StartX - line2StartX;
numerator1 = ((line2EndX - line2StartX) * a) - ((line2EndY - line2StartY) * b);
numerator2 = ((line1EndX - line1StartX) * a) - ((line1EndY - line1StartY) * b);
a = numerator1 / denominator;
b = numerator2 / denominator;
// if we cast these lines infinitely in both directions, they intersect here:
result.x = line1StartX + (a * (line1EndX - line1StartX));
result.y = line1StartY + (a * (line1EndY - line1StartY));
/*
// it is worth noting that this should be the same as:
x = line2StartX + (b * (line2EndX - line2StartX));
y = line2StartX + (b * (line2EndY - line2StartY));
*/
// if line1 is a segment and line2 is infinite, they intersect if:
if (a > 0 && a < 1) {
result.onLine1 = true;
}
// if line2 is a segment and line1 is infinite, they intersect if:
if (b > 0 && b < 1) {
result.onLine2 = true;
}
// if line1 and line2 are segments, they intersect if both of the above are true
return result;
};
UPDATE
If you have a polyline that is defined by more than two points, you should check intersection of it's every segment with the perpendicular line. Jut do it in a loop. Here is the fiddle: http://jsfiddle.net/v0bseuqz/39/
var coords = [
[0.003, 0.080],
[-0.008, 0.041],
[0, 0]
];
L.polyline(coords, {
color: 'red',
weight: 1
}).addTo(map);
var circle = L.circle([0, 0], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(map);
var startY, startX, endY, endX, cursorPoint, cursorLatLng, intersection;
$( "#map" ).mousemove(function( event ) {
for(i = coords.length, i >0; i--;) {
if (i - 1 >= 0) {
startY = coords[i][0];
startX = coords[i][1];
endY = coords[i - 1][0];
endX = coords[i - 1][1];
cursorPoint = new L.Point(event.clientX, event.clientY);
cursorLatLng = map.containerPointToLatLng(cursorPoint);
intersection = (checkLineIntersection(startX, startY, endX, endY, cursorLatLng.lng, 1, cursorLatLng.lng, -1));
if (intersection.onLine1 && intersection.onLine2) {
circle.setLatLng(new L.LatLng(intersection.y, intersection.x));
}
}
}
});
I've taken the algorithm of detecting the intersection of two lines here.

Binning data into a hexagonal grid in Google Maps

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.

google maps circle to polyline coordinate array

how to get array of polyline coordinates from google.maps.Circle's object
there is no api doc entry about that
A google.maps.Circle doesn't contain an array of coordinates. If you want a google.maps.Polygon that is shaped like a circle, you need to make one.
function drawCircle(point, radius, dir) {
var d2r = Math.PI / 180; // degrees to radians
var r2d = 180 / Math.PI; // radians to degrees
var earthsradius = 3963; // 3963 is the radius of the earth in miles
var points = 32;
// find the raidus in lat/lon
var rlat = (radius / earthsradius) * r2d;
var rlng = rlat / Math.cos(point.lat() * d2r);
var extp = new Array();
if (dir==1) {
var start=0;
var end=points+1; // one extra here makes sure we connect the path
} else {
var start=points+1;
var end=0;
}
for (var i=start; (dir==1 ? i < end : i > end); i=i+dir)
{
var theta = Math.PI * (i / (points/2));
ey = point.lng() + (rlng * Math.cos(theta)); // center a + radius x * cos(theta)
ex = point.lat() + (rlat * Math.sin(theta)); // center b + radius y * sin(theta)
extp.push(new google.maps.LatLng(ex, ey));
}
return extp;
}
var circle = new google.maps.Polygon({
map: map,
paths: [drawCircle(new google.maps.LatLng(-33.9,151.2), 100, 1)],
strokeColor: "#0000FF",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35
});
Example
code snippet:
function drawCircle(point, radius, dir) {
var d2r = Math.PI / 180; // degrees to radians
var r2d = 180 / Math.PI; // radians to degrees
var earthsradius = 3963; // 3963 is the radius of the earth in miles
var points = 32;
// find the raidus in lat/lon
var rlat = (radius / earthsradius) * r2d;
var rlng = rlat / Math.cos(point.lat() * d2r);
var extp = new Array();
if (dir == 1) {
var start = 0;
var end = points + 1
} // one extra here makes sure we connect the
else {
var start = points + 1;
var end = 0
}
for (var i = start;
(dir == 1 ? i < end : i > end); i = i + dir) {
var theta = Math.PI * (i / (points / 2));
ey = point.lng() + (rlng * Math.cos(theta)); // center a + radius x * cos(theta)
ex = point.lat() + (rlat * Math.sin(theta)); // center b + radius y * sin(theta)
extp.push(new google.maps.LatLng(ex, ey));
bounds.extend(extp[extp.length - 1]);
}
// alert(extp.length);
return extp;
}
var map = null;
var bounds = null;
function initialize() {
var myOptions = {
zoom: 10,
center: new google.maps.LatLng(-33.9, 151.2),
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
},
navigationControl: true,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"),
myOptions);
bounds = new google.maps.LatLngBounds();
var donut = new google.maps.Polygon({
paths: [drawCircle(new google.maps.LatLng(-33.9, 151.2), 100, 1),
drawCircle(new google.maps.LatLng(-33.9, 151.2), 50, -1)
],
strokeColor: "#0000FF",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35
});
donut.setMap(map);
map.fitBounds(bounds);
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map_canvas {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
}
<script src="https://maps.google.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div id="map_canvas"></div>
I implement this inside autocomplete, but, can't understand this: var points = 32; how calculate this variable?
createAutocomplete() {
var drawer = this.drawCircle;
var MAPS = window.Heatmap.Maps;
const center = MAPS.map.center;
const defaultBounds = {
north: center.lat + 0.1,
south: center.lat - 0.1,
east: center.lng + 0.1,
west: center.lng - 0.1,
};
let input = document.getElementById("search");
const options = {
bounds: defaultBounds,
componentRestrictions: {country: "us"},
fields: ["address_components", "geometry", "icon", "name"],
origin: MAPS.map.center,
strictBounds: false,
types: ['(cities)'],
};
MAPS.autocomplete = new google.maps.places.Autocomplete(input, options);
google.maps.event.addListener(MAPS.autocomplete, 'place_changed', function () {
const selectedIndex = document.getElementById("distance").selectedIndex;
let distance = document.getElementsByTagName("option")[selectedIndex].value;
if (MAPS.circle.instance) {
MAPS.circle.instance.setMap(null);
MAPS.marker.collection['searchMarker'].setMap(null);
}
let place = MAPS.autocomplete.getPlace();
var center = {lat: place.geometry.location.lat(), lng: place.geometry.location.lng()};
MAPS.map.instance.panTo(center);
MAPS.map.instance.setZoom(7);
MAPS.marker.collection['searchMarker'] = new google.maps.Marker({
position: center,
map: MAPS.map.instance,
icon: {
url: "http://maps.google.com/mapfiles/ms/icons/yellow-dot.png"
}
});
MAPS.circle.instance = new google.maps.Polygon({
map: MAPS.map.instance,
paths: [drawer(center, distance, 1)],
strokeColor: "#0000FF",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35
});
console.log(MAPS.circle.instance.getPath())
});
}
drawCircle(point, radius, dir) {
var d2r = Math.PI / 180;
var r2d = 180 / Math.PI;
var earthsradius = 3963;
var points = 32;
var rlat = (radius / earthsradius) * r2d;
var rlng = rlat / Math.cos(point.lat * d2r);
var extp = [];
var start = null;
var end = null;
if (dir === 1) {
start = 0;
end = points + 1;
} else {
start = points + 1;
end = 0;
}
for (var i = start; (dir === 1 ? i < end : i > end); i = i + dir) {
var theta = Math.PI * (i / (points / 2));
var ey = point.lng + (rlng * Math.cos(theta));
var ex = point.lat + (rlat * Math.sin(theta));
extp.push(new google.maps.LatLng(ex, ey));
}
return extp;
}

Categories