How to drawing a geoshapes (polygon) in HERE Maps javascript 3.0 with mouse event click? and save the coordinates in database..
I search the guides at developer.here.com but no one script guides showing how to draw in here map javascript 3.0 API. (https://developer.here.com/api-explorer/maps-js/geoshapes/polygon-on-the-map)
Beside that in javascript 2.5 API show the guides, but it will be expired and deleted soon.
here a script to draw in javascript 2.5 (http://developer.here.com/apiexplorer/index.html#js/pub/shapes/map-with-polyline-on-click/):
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=7; IE=EmulateIE9; IE=10" />
<base href="./../../../..//examples/public/api-for-js/shapes/map-with-polyline-on-click.html" />
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>HERE Maps API for JavaScript Example: Click to create a polyline on map</title>
<meta name="description" content="Creating a polyline wih markers by clicking on the map"/>
<meta name="keywords" content="drawpolyline, map objects, shape, shapes, triangle, rectangle, circle, polyline, polygon"/>
<meta name=viewport content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<link rel="stylesheet" type="text/css" href="./../../../..//examples/templates/js/exampleHelpers.css"/>
<script type="text/javascript" charset="UTF-8" src="http://js.cit.api.here.com/se/2.5.4/jsl.js?with=all"></script>
<script type="text/javascript" charset="UTF-8" src="./../../../..//examples/templates/js/exampleHelpers.js"></script>
<style type="text/css">
html {
overflow:hidden;
}
body {
margin: 0;
padding: 0;
overflow: hidden;
width: 100%;
height: 100%;
position: absolute;
}
#mapContainer {
width: 100%;
height: 100%;
left: 0;
top: 0;
position: absolute;
}
</style>
</head>
<body>
<div id="mapContainer"></div>
<div id="uiContainer"></div>
<script type="text/javascript" id="exampleJsSource">
nokia.Settings.set("app_id", "DemoAppId01082013GAL");
nokia.Settings.set("app_code", "AJKnXv84fjrb0KIHawS0Tg");
// Use staging environment (remove the line for production environment)
nokia.Settings.set("serviceMode", "cit");
// Get the DOM node to which we will append the map
var mapContainer = document.getElementById("mapContainer");
// Create a map inside the map container DOM node
var map = new nokia.maps.map.Display(mapContainer, {
// Initial center and zoom level of the map
center: [52.51, 13.4],
zoomLevel: 10,
components: [
// ZoomBar provides a UI to zoom the map in & out
new nokia.maps.map.component.ZoomBar(),
// we add the behavior component to allow panning / zooming of the map
new nokia.maps.map.component.Behavior(),
// creates UI to easily switch between street map satellite and terrain mapview modes
new nokia.maps.map.component.TypeSelector()
]
});
var noteContainer = new NoteContainer({
id: "drawPolylineUi",
parent: document.getElementById("uiContainer"),
title: "Drawing a polyline",
content:
'<p>Click or touch anywhere on the map to add a new point to the existing polyline.</p>' +
'<input id="resetPolyline" role="button" type="button" value="Reset Polyline"/>'
});
// We bind DOM element to variable so we use it later to install event handler.
var resetPolylineUiElt = document.getElementById("resetPolyline");
// Javascript inheritance helper function
function extend(B, A) {
function I() {}
I.prototype = A.prototype;
B.prototype = new I();
B.prototype.constructor = B;
}
var MarkerPolyline = function (coords, props) {
// Call the "super" constructor to initialize properties inherited from Container
nokia.maps.map.Container.call(this);
// Calling MarkerPolyline constructor
this.init(coords, props);
};
extend(MarkerPolyline, nokia.maps.map.Container);
// MarkerPolyline constructor function
MarkerPolyline.prototype.init = function (coords, props) {
var i,
coord,
marker,
lineProps = props.polyline || {},
markerProps = (this.markerProps = props.marker || {});
this.coords = {};
// Create a polyline
this.polyline = new nokia.maps.map.Polyline(coords, lineProps);
// Add the polyline to the container
this.objects.add(this.polyline);
/* We loop through the point to create markers
* for each of the points and we store them
*/
for (i = 0; coord = coords[i]; i++) {
marker = new nokia.maps.map.StandardMarker(coord, markerProps);
this.coords[coord.latitude + "_" + coord.longitude] = { idx: i + 1, marker: marker };
this.objects.add(marker);
}
};
// The add function allows you to add a new point to a MarkerPolyline
MarkerPolyline.prototype.add = function (coord) {
// Create a new standard marker
var markerProps = this.markerProps,
marker,
key = coord.latitude + "_" + coord.longitude;
if (!this.coords[key]) {
marker = new nokia.maps.map.StandardMarker(coord, markerProps);
this.coords[key] = { idx: this.objects.getLength(), marker: marker };
/* Add the marker to the object's collections
* so the marker will be rendered onto the map
*/
this.objects.add(marker);
this.polyline.path.add(coord);
}
};
// The remove function allows you to remove a point from MarkerPolyline
MarkerPolyline.prototype.remove = function (coord) {
var coords = this.polyline.path.internalArray,
i = this.polyline.path.getLength(),
marker,
key = coord.latitude + "_" + coord.longitude,
idx;
if (!this.coords[key])
return;
while (i--) {
if (coords[i * 3 ] === coord.latitude && coords[i * 3 + 1] === coord.longitude) {
idx = i;
}
}
// Index of coordinate found, now we remove coordinate from polyline
this.polyline.path.remove(idx);
// Remove the marker
marker = this.coords[key].marker;
this.objects.remove(marker);
marker.destroy();
delete this.coords[key];
};
// Set of initial geo coordinates to create the polyline
var coords = [
new nokia.maps.geo.Coordinate(52.5032, 13.2790),
new nokia.maps.geo.Coordinate(52.5102, 13.2818),
new nokia.maps.geo.Coordinate(52.5121, 13.3224),
new nokia.maps.geo.Coordinate(52.5145, 13.3487),
new nokia.maps.geo.Coordinate(52.5139, 13.3501),
new nokia.maps.geo.Coordinate(52.5146, 13.3515),
new nokia.maps.geo.Coordinate(52.5161, 13.3769)
];
// Create a new polyline with markers
var markerPolyline = new MarkerPolyline(
coords,
{
polyline: { pen: { strokeColor: "#00F8", lineWidth: 4 } },
marker: { brush: { color: "#1080dd" } }
}
);
/* Add the markerPolyline to the map's object collection so
* all of its containing shapes will be rendered onto the map.
*/
map.objects.add(markerPolyline);
/* We would like to add event listener on mouse click or finger tap so we check
* nokia.maps.dom.Page.browser.touch which indicates whether the used browser has a touch interface.
*/
var TOUCH = nokia.maps.dom.Page.browser.touch,
CLICK = TOUCH ? "tap" : "click",
addedCoords = [];
// Attach an event listeners on mouse click / touch to add points to
map.addListener(CLICK, function (evt) {
// We translate a screen pixel into geo coordinate (latitude, longitude)
var coord = map.pixelToGeo(evt.displayX, evt.displayY);
// Next we add the geoCoordinate to the markerPolyline
markerPolyline.add(coord);
// We store added coordinates so we can remove them later on
addedCoords.push(coord);
});
// Reset markerPolyline to its original shape on click of reset button
resetPolylineUiElt.onclick = function () {
var i = addedCoords.length;
while (i--) {
markerPolyline.remove(addedCoords[i]);
}
addedCoords = [];
};
// Zoom the map to encapsulate the initial polyline, once the map is initialized and ready
map.addListener("displayready", function () {
map.zoomTo(markerPolyline.getBoundingBox());
});
</script>
</body>
</html>
You must update the strip of the GeoShape:
get the strip via getStrip()
push a geo.Point to the strip via pushPoint()
apply the updated strip via setStrip()
// enable the event system
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map)),
//create the line
line=new H.map.Polyline(new H.geo.Strip([ 52.5032, 13.2790,0,
52.5102, 13.2818,0,
52.5121, 13.3224,0,
52.5145, 13.3487,0,
52.5139, 13.3501,0,
52.5146, 13.3515,0,
52.5161, 13.3769,0])
);
//draw the line
map.addObject(line);
//add tap-listener
map.addEventListener('tap', function(e){
var pointer = e.currentPointer,
//create geo.Point
latLng = map.screenToGeo(pointer.viewportX, pointer.viewportY),
//get current strip
strip=line.getStrip();
//push point to strip
strip.pushPoint(latLng);
//set updated strip
line.setStrip(strip);
});
Related
I have a logic problem I am stuck on and could use some help. I think this would be normally easy for me, but I am a little brain fried after hurricane Ian here in FL.
I am plotting a gradient line on an Azure map. My GPS service returns a large array of coordinates (latitude/longitude) and related data for those points along the route.
I am finding that for longer routes, Azure maps will only accept up to 10 coordinates for the lineLayer method.
My issue is more with logic. I have an array of coordinates with maybe 4000+ items. Sometimes more, sometimes less depending on the length of the chosen route.
I need to break that 4000+ items into 10 chunks, from there, I will take the first item in each of the 10 and use that to plot my data point.
So for 4000 items, my chunked array size would be 400. 2000 items would be 200, 100, would be 10, 50 would be 5, etc. If there is overflow in the last chunk, that is fine.
//This is the top temperature
this.finalTemp = 75
//I need to break points into 10 chunks so the Azure maps lineLayer expression can handle it.
for (var i = 0; i < points.length; i++) {
let temperatureAtPoint = points[i].temperature //22.0 - this will usually increase as we iterate through.
let progressValue: number = pointTemp / this.finalTemp;
//this progressValue will be used to generate a color that is plotted on the map (I have that working)
}
For the life of me, I can't get this figured out and thought I would hop on here to see if someone can get me straight. I just need a typescript or Javascript example.
Thank you!
Azure Maps line layer has no limit on the number of coordinates in the line. That said, if you try and create a gradient based on thousands of stops/colors, then that would likely be slow.
A few of approaches to show your data as a gradient:
Show the individual points using the bubble layer and color each bubble based the temperature in that point. As a bonus, if you have additional metadata in your point, you can easily retrieve that and show it in a popup when the user interacts with it. Here is an example:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<style>
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#myMap {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body onload="GetMap()">
<div id="myMap"></div>
<!-- Add references to the Azure Maps Map control JavaScript and CSS files. -->
<link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css" rel="stylesheet" />
<script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>
<script>
var map, datasource;
//From: https://samples.azuremaps.com/data/geojson/GpsTrace.json
var gpsTrace = 'GpsTrace.json';
//The property name to base the gradient on.
var metric = 'ele';
function GetMap() {
map = new atlas.Map('myMap', {
center: [12.858333, 43.247383],
zoom: 12,
style: 'grayscale_dark',
authOptions: {
authType: 'subscriptionKey',
subscriptionKey: '<Your Azure Maps Key>'
}
});
map.events.add('ready', function () {
datasource = new atlas.source.DataSource();
map.sources.add(datasource);
datasource.importDataFromUrl(gpsTrace);
map.layers.add(new atlas.layer.BubbleLayer(datasource, null, {
strokeWidth: 0,
color: [
'interpolate',
['linear'],
['get', metric],
300, "blue",
400, "royalblue",
500, "cyan",
600, "lime",
700, "yellow",
800, "red"
]
}));
});
}
</script>
</body>
</html>
Break your lines up into line segments (2-point lines) and capture the temperature as a property of each segment, then use a data driven style expression to color the line segments.
Similar to #2 but calculate the mid-points between points since that is more representative of when the metric is valid.
Similar to #2 and 3 but combine the points where the temperature is the same. This will be more optimized as the render will be able to reduce the resolution of these multi-point lines when zoomed out. Here is an example:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<style>
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#myMap {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body onload="GetMap()">
<div id="myMap"></div>
<!-- Add references to the Azure Maps Map control JavaScript and CSS files. -->
<link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css" rel="stylesheet" />
<script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>
<script>
var map, datasource;
//From: https://samples.azuremaps.com/data/geojson/GpsTrace.json
var gpsTrace = 'GpsTrace.json';
//The property name to base the gradient on.
var metric = 'ele';
function GetMap() {
map = new atlas.Map('myMap', {
center: [12.858333, 43.247383],
zoom: 12,
style: 'grayscale_dark',
authOptions: {
authType: 'subscriptionKey',
subscriptionKey: '<Your Azure Maps Key>'
}
});
map.events.add('ready', function () {
datasource = new atlas.source.DataSource();
map.sources.add(datasource);
datasource.importDataFromUrl(gpsTrace).then(chunkPoints);
map.layers.add(new atlas.layer.LineLayer(datasource, null, {
strokeWidth: 6,
strokeColor: [
'interpolate',
['linear'],
['get', metric],
300, "blue",
400, "royalblue",
500, "cyan",
600, "lime",
700, "yellow",
800, "red"
]
}));
});
}
function chunkPoints() {
var points = datasource.toJson().features;
//Convery GPS points into line segments.
var lines = [];
var currentMetric = null;
var coords = null;
for (var i = 0; i < points.length; i++) {
var p = points[i];
//If the metric value has changed, need to create a line with current data and collect data for the next line.
if (p.properties[metric] !== currentMetric) {
var midPoint;
//If there is no existing coords, must be starting out.
if (coords !== null) {
//Calculate the mid-point between current and last point.
midPoint = atlas.math.interpolate(coords[coords.length - 1], p, 0.5);
coords.push(midPoint);
//Create a line for the current metric and coords.
var props = {};
props[metric] = currentMetric;
lines.push(new atlas.data.Feature(new atlas.data.LineString(coords), props));
}
currentMetric = p.properties[metric];
coords = [];
//Start the new line
if (midPoint) {
coords.push(midPoint);
}
}
//Capture the point coordinates.
coords.push(p.geometry.coordinates);
}
//Add the remaining current line.
if (currentMetric != null && coords !== null) {
var props = {};
props[metric] = currentMetric;
lines.push(new atlas.data.Feature(new atlas.data.LineString(coords), props));
}
//Add the lines to the data source.
datasource.setShapes(lines);
}
</script>
</body>
</html>
If you still find that your data is too big, you then may need to consider reducing the resolution of your data, or serving it in a more efficient format, such as vector tiles.
The following should suffice
function sliceIntoChunks(arr, chunkSize) {
const res = [];
for (let i = 0; i < arr.length; i += chunkSize) {
const chunk = arr.slice(i, i + chunkSize);
res.push(chunk);
}
return res;
}
// the remainder is important because if not divisible then it would be a float number, we can safely omit it
let chunkSize = (points.length + (points.length % 10)) / 10
const chunkedArray = sliceIntoChunks(points, chunkSize)
This article sums it up pretty well.
I need to display different polylines from A to B. So, these lines should be distinguishable from each other. I haved tried to set polylines using pushpoint function with altitude parameter. However it is still on the ground level. And the last polyline I inserted overwrites the previous one.
Altitude value works on markers but I want to apply it on polyline.
I changed the sample code here markers with altitude as below. You can see the orange line is just on top of the gray line when you change the code with the below one. I would like both lines to be displayed like the markers you see above them.
/**
* Calculate the bicycle route.
* #param {H.service.Platform} platform A stub class to access HERE services
*/
function calculateRouteFromAtoB (platform) {
var router = platform.getRoutingService(),
routeRequestParams = {
mode: 'fastest;bicycle',
representation: 'display',
routeattributes : 'shape',
waypoint0: '-16.1647142,-67.7229166',
waypoint1: '-16.3705847,-68.0452683',
// explicitly request altitude values
returnElevation: true
};
router.calculateRoute(
routeRequestParams,
onSuccess,
onError
);
}
/**
* Process the routing response and visualise the descent with the help of the
* H.map.Marker
*/
function onSuccess(result) {
var lineString = new H.geo.LineString(),
lineString2 = new H.geo.LineString(),
routeShape = result.response.route[0].shape,
group = new H.map.Group(),
dict = {},
polyline,
polyline2;
routeShape.forEach(function(point) {
var parts = point.split(',');
var pp= new H.geo.Point(parts[0],parts[1],4000,"SL");
console.log(parts[2]);
lineString.pushLatLngAlt(parts[0], parts[1]);
lineString2.pushPoint(pp);
// normalize the altitude values for the color range
var p = (parts[2] - 1000) / (4700 - 1000);
var r = Math.round(255 * p);
var b = Math.round(255 - 255 * p);
// create or re-use icon
var icon;
if (dict[r + '_' + b]) {
icon = dict[r + '_' + b];
} else {
var canvas = document.createElement('canvas');
canvas.width = 4;
canvas.height = 4;
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(' + r + ', 0, ' + b + ')';
ctx.fillRect(0, 0, 4, 4);
icon = new H.map.Icon(canvas);
// cache the icon for the future reuse
dict[r + '_' + b] = icon;
}
// the marker is placed at the provided altitude
var marker = new H.map.Marker({
lat: parts[0], lng: parts[1], alt: parts[2]
}, {icon: icon});
var marker2 = new H.map.Marker({
lat: parts[0], lng: parts[1], alt: parts[2]-800
}, {icon: icon});
group.addObject(marker);
group.addObject(marker2);
});
polyline = new H.map.Polyline(lineString, {
style: {
lineWidth: 6,
strokeColor: '#555555'
}
});
polyline2 = new H.map.Polyline(lineString2, {
style: {
lineWidth: 3,
strokeColor: '#FF5733'
}
});
// Add the polyline to the map
map.addObject(polyline);
map.addObject(polyline2);
// Add markers to the map
map.addObject(group);
// Zoom to its bounding rectangle
map.getViewModel().setLookAtData({
bounds: polyline.getBoundingBox(),
tilt: 60
});
}
/**
* This function will be called if a communication error occurs during the JSON-P request
* #param {Object} error The error message received.
*/
function onError(error) {
alert('Can\'t reach the remote server');
}
/**
* Boilerplate map initialization code starts below:
*/
// set up containers for the map + panel
var mapContainer = document.getElementById('map'),
routeInstructionsContainer = document.getElementById('panel');
//Step 1: initialize communication with the platform
// In your own code, replace variable window.apikey with your own apikey
var platform = new H.service.Platform({
apikey: window.apikey
});
var defaultLayers = platform.createDefaultLayers();
//Step 2: initialize a map - this map is centered over Berlin
var map = new H.Map(mapContainer,
defaultLayers.vector.normal.map,{
center: {lat:52.5160, lng:13.3779},
zoom: 13,
pixelRatio: window.devicePixelRatio || 1
});
// add a resize listener to make sure that the map occupies the whole container
window.addEventListener('resize', () => map.getViewPort().resize());
//Step 3: make the map interactive
// MapEvents enables the event system
// Behavior implements default interactions for pan/zoom (also on mobile touch environments)
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// Create the default UI components
var ui = H.ui.UI.createDefault(map, defaultLayers);
// Now use the map as required...
calculateRouteFromAtoB (platform);
Unfortunately, for now only markers support altitudes.
Polylines should follow in near future.
I want to make a circle on map using jQuery. In this given code circles are made randomly. But I want to make only one circle on click. Openlayer.js can be found on Openlayer website.
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<script type='text/javascript' src='OpenLayers.js'></script>
<script type='text/javascript'>
var map;
var vector_layer;
function init() {
//Create a map with an empty array of controls
map = new OpenLayers.Map('map_element');
//Create a base layer
var wms_layer = new OpenLayers.Layer.WMS(
'OpenLayers WMS',
'http://vmap0.tiles.osgeo.org/wms/vmap0',
{layers: 'basic'},
{}
);
map.addLayer(wms_layer);
//Add vector layer
vector_layer = new OpenLayers.Layer.Vector('Settlement Vector Layer');
map.addLayer(vector_layer);
var settlement_values = {
4: 'circle'
}
//Create some points
for(var i=0; i<20; i++){
vector_layer.addFeatures([new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(
(Math.floor(Math.random() * 360) - 180),
(Math.floor(Math.random() * 180) - 90)
),
{
'settlement_type': settlement_values[(Math.floor(Math.random() * 5))]
}
)]);
}
//Create a style map object
var vector_style_map = new OpenLayers.StyleMap({});
//ADD RULES
//We need to create a 'lookup table' that contains the desired values
// and corresponding symbolizer
var symbolizers_lookup = {
'circle': {
'fillColor': '#336699','fillOpacity':.8, 'pointRadius':50, 'strokeColor': '#003366', 'strokeWidth':2
}
}
//Now, call addUniqueValueRules and pass in the symbolizer lookups
vector_style_map.addUniqueValueRules('default', 'settlement_type', symbolizers_lookup);
//Add the style map to the vector layer
vector_layer.styleMap = vector_style_map;
if(!map.getCenter()){
map.zoomToMaxExtent();
}
}
</script>
</head>
<body onload='init();'>
<div id='map_element' style='width: 600px; height: 600px;'></div>
</body>
</html>
I strongly recommend you to study this: http://openlayers.org/en/latest/examples/draw-features.html
Here is a minimalist edition of the example:
var draw; // global so we can remove it later
function addInteraction() {
var value = "circle"
draw = new ol.interaction.Draw({
source: source,
type: /** #type {ol.geom.GeometryType} */ (typeSelect.value)
});
map.addInteraction(draw);
}
addInteraction();
Although it does not create shapes by jquery, it allows to draw circles on the map.
Hope it helps, happy coding :)
Yes If you are talking in Openlayer2 the this will help you cheers.further I have attached code in jsfiddle
`
var point1 = new OpenLayers.Geometry.Point(0, 0);
var point2 = new OpenLayers.Geometry.Point(5000000, 1000000);
var point3 = new OpenLayers.Geometry.Point(2000000, 2000000);
var radius = $("#amount").val();
var mycircle = OpenLayers.Geometry.Polygon.createRegularPolygon(point2, radius, 20, 0);
var featurecircle = new OpenLayers.Feature.Vector(mycircle);
marker1 = new OpenLayers.Feature.Vector(point1, null, {
externalGraphic: "marker.png",
graphicWidth: 32,
graphicHeight: 32,
fillOpacity: 1
});
marker1.style = {
display: 'none'
};
http://jsfiddle.net/zLjae81b/18/`
I am trying to apply a simple clustering stategy to my OpenLayers v2.13 map, but it is not working.
Here is my code so far, it all loads correctly but the random points on the map do not cluster, they just overlap horribly...
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<title>OpenLayers 2.13.x Clustered Markers</title>
<script src="../OpenLayers.js"></script>
</head>
<body onload="run()" style="position: absolute; top: 0; bottom: 0; left: 0; right: 0;">
<div id='map' style="width: 100%; height: 100%">
</div>
<script>
function run(){
// create the map
var map = new OpenLayers.Map("map");
// add a google maps layer to the map
var layer = new OpenLayers.Layer.WMS("OpenLayers WMS", "http://vmap0.tiles.osgeo.org/wms/vmap0", {
layers: "basic"
});
map.addLayers([layer]);
// set up cluster strategy and vector layer
var strategy = new OpenLayers.Strategy.Cluster({
distance: 15,
clustering: true
});
var markersLayer = new OpenLayers.Layer.Vector("Clustered markers", {strategies: [strategy]});
// create and add all markers randomly
var markers = [];
for (var i = 0; i < 700; i++) {
var r1 = Math.random();
var r2 = Math.random();
var r3 = Math.random();
var r4 = Math.random();
var px = r1 * 180 * ((r2 < 0.5) ? -1 : 1);
var py = r3 * 90 * ((r4 < 0.5) ? -1 : 1);
var p = new OpenLayers.Geometry.Point(px, py);
var clazz = (i % 10 === 0) ? 4 : Math.ceil(r4 * 3);
var f = new OpenLayers.Feature.Vector(p, {clazz: clazz});
markers.push(f);
}
markersLayer.addFeatures(markers);
// add markers layer to the map
map.addLayer(markersLayer);
map.zoomToMaxExtent();
}
</script>
</body>
</html>
Note: OpenLayers is locally on my machine and is version 2.13.1
I have looked at several examples, none have helped me solve this issue. I have looked at several stack overflow answers, the best of them was about marker clustering, but also didn't help.
I must be missing something obvious but I cant see what?
[UPDATE]
Taking advice from the answers below, here is the code snippet (from above) edited to run correctly, adding the markers after the layer has been added to the map and not including the clustering flag...
// set up cluster strategy and vector layer
var strategy = new OpenLayers.Strategy.Cluster({
distance: 15 // <-- removed clustering flag
});
var markersLayer = new OpenLayers.Layer.Vector("Clustered markers", {strategies: [strategy]});
// add markers layer to the map
map.addLayer(markersLayer); // <-- adding layer before adding features
// create and add all markers randomly
var markers = [];
for (var i = 0; i < 700; i++) {
var r1 = Math.random();
var r2 = Math.random();
var r3 = Math.random();
var r4 = Math.random();
var px = r1 * 180 * ((r2 < 0.5) ? -1 : 1);
var py = r3 * 90 * ((r4 < 0.5) ? -1 : 1);
var p = new OpenLayers.Geometry.Point(px, py);
var clazz = (i % 10 === 0) ? 4 : Math.ceil(r4 * 3);
var f = new OpenLayers.Feature.Vector(p, {clazz: clazz});
markers.push(f);
}
markersLayer.addFeatures(markers); // <-- now can add features
// zoom to extent
map.zoomToMaxExtent();
It looks like maybe a good practice to follow is to make sure that you add a layer to the map before adding/removing features to it.
I removed "clustering" from the cluster strategy options
// set up cluster strategy and vector layer
var strategy = new OpenLayers.Strategy.Cluster({
distance: 15
});
and then added the markers after I'd added the layer to the map
// add markers layer to the map
map.addLayer(markersLayer);
markersLayer.addFeatures(markers);
map.zoomToMaxExtent();
then all seemed to work.
Mailed similar to Angela to you internally.
Not sure why removing clustering has any affect, I think its true by default anyway.
As for the order of adding the points, I seem to remember reading something about the fact your points are replaced by the clusters so adding the layer to map after adding points to layer may mean that process doesn't happen. Or something. ;)
Cheers
Ian
I am using Multimarker to add markers with labels to a custom google map. The div containing the label calls a function with onclick. But if I add a polyline to the map, the onclick stops working. I can not figure out why...
This is the code for adding a marker:
var fastMarkers = [];
var myLatlng = new google.maps.LatLng(70,-101);
var marker = new com.redfin.FastMarker(/*id*/1, myLatlng, ["<div onclick='test()'><span>mylabel</span></div>"], null);
fastMarkers.push(marker);
new com.redfin.FastMarkerOverlay(map, fastMarkers);
This is the polyline:
var linepathcoords = [
new google.maps.LatLng(71, -103),
new google.maps.LatLng(73, -107),
];
var linepath=new google.maps.Polyline({
path:linepathcoords,
strokeColor:"#ff0000",
strokeOpacity:0.9,
strokeWeight:2
});
//This next line is what's causing the onclick in the marker to stop working. Why?
linepath.setMap(map);
};
And this is the code for Multimarker:
/*
Copyright 2010 Redfin Corporation
Licensed under the Apache License, Version 2.0:
http://www.apache.org/licenses/LICENSE-2.0
*/
com = {redfin: {}};
/* Construct a new FastMarkerOverlay layer for a V2 map
* #constructor
* #param {google.maps.Map} map the map to which we'll add markers
* #param {Array.<com.redfin.FastMarker>} markers the array of markers to display on the map
*/
com.redfin.FastMarkerOverlay = function(map, markers) {
this.setMap(map);
this._markers = markers;
}
com.redfin.FastMarkerOverlay.prototype = new google.maps.OverlayView();
com.redfin.FastMarkerOverlay.prototype.onAdd = function() {
this._div = document.createElement("div");
var panes = this.getPanes();
panes.overlayLayer.appendChild(this._div);
}
/* Copy our data to a new FastMarkerOverlay
* #param {google.maps.Map} map the map to which the copy will add markers
* #return {FastMarkerOverlay} Copy of FastMarkerOverlay
*/
com.redfin.FastMarkerOverlay.prototype.copy = function(map) {
var markers = this._markers;
var i = markers.length;
var markersCopy = new Array(i);
while (i--) {
markersCopy[i] = markers[i].copy();
}
return new com.redfin.FastMarkerOverlay(map, markers);
};
/* Draw the FastMarkerOverlay based on the current projection and zoom level; called by Gmaps */
com.redfin.FastMarkerOverlay.prototype.draw = function() {
// if already removed, never draw
if (!this._div) return;
// Size and position the overlay. We use a southwest and northeast
// position of the overlay to peg it to the correct position and size.
// We need to retrieve the projection from this overlay to do this.
var overlayProjection = this.getProjection();
// DGF use fastloop http://ajaxian.com/archives/fast-loops-in-js
// JD Create string with all the markers
var i = this._markers.length;
var textArray = [];
while (i--) {
var marker = this._markers[i];
var divPixel = overlayProjection.fromLatLngToDivPixel(marker._latLng);
textArray.push("<div style='position:absolute; left:");
textArray.push(divPixel.x + marker._leftOffset);
textArray.push("px; top:");
textArray.push(divPixel.y + marker._topOffset);
textArray.push("px;")
if (marker._zIndex) {
textArray.push(" z-index:");
textArray.push(marker._zIndex);
textArray.push(";");
}
textArray.push("'");
if (marker._divClassName) {
textArray.push(" class='");
textArray.push(marker._divClassName);
textArray.push("'");
}
textArray.push(" id='");
textArray.push(marker._id);
textArray.push("' >");
var markerHtmlArray = marker._htmlTextArray;
var j = markerHtmlArray.length;
var currentSize = textArray.length;
while (j--) {
textArray[j + currentSize] = markerHtmlArray[j];
}
textArray.push("</div>");
}
//Insert the HTML into the overlay
this._div.innerHTML = textArray.join('');
}
/** Hide all of the markers */
com.redfin.FastMarkerOverlay.prototype.hide = function() {
if (!this._div) return;
this._div.style.display = "none";
}
/** Show all of the markers after hiding them */
com.redfin.FastMarkerOverlay.prototype.unhide = function() {
if (!this._div) return;
this._div.style.display = "block";
}
/** Remove the overlay from the map; never use the overlay again after calling this function */
com.redfin.FastMarkerOverlay.prototype.onRemove = function() {
this._div.parentNode.removeChild(this._div);
this._div = null;
}
/** Create a single marker for use in FastMarkerOverlay
* #constructor
* #param {string} id DOM node ID of the div that will contain the marker
* #param {google.maps.LatLng} latLng geographical location of the marker
* #param {Array.<string>} htmlTextArray an array of strings which we'll join together to form the HTML of your marker
* #param {string=} divClassName the CSS class of the div that will contain the marker. (optional)
* #param {string=} zIndex zIndex of the div that will contain the marker. (optional, 'auto' by default)
* #param {number=} leftOffset the offset in pixels by which we'll horizontally adjust the marker position (optional)
* #param {number=} topOffset the offset in pixels by which we'll vertically adjust the marker position (optional)
*/
com.redfin.FastMarker = function(id, latLng, htmlTextArray, divClassName, zIndex, leftOffset, topOffset) {
this._id = id;
this._latLng = latLng;
this._htmlTextArray = htmlTextArray;
this._divClassName = divClassName;
this._zIndex = zIndex;
this._leftOffset = leftOffset || 0;
this._topOffset = topOffset || 0;
}
/** Copy the FastMarker
* #return {com.redfin.FastMarker} duplicate of this marker
*/
com.redfin.FastMarker.prototype.copy = function() {
var htmlArray = this._htmlTextArray;
var i = htmlArray.length;
var htmlArrayCopy = new Array(i);
while (i--) {
htmlArrayCopy[i] = htmlArray[i];
}
return new com.redfin.FastMarker(this._id, latLng, htmlArrayCopy, this._divClassName, this._zIndex, this._leftOffset, this._topOffset);
}
Additional info: Before adding the polyline I can use the "inspect" tool in Firefox and select the div and span containing the label. But after adding the polyline the div is gone (the label is still visible on the map, but I can not click it, and I can not select it with the inspect-tool. Also, after adding the polyline I see in the Firefox "inspect"-list that a lot of divs suddenly have "overflow:hidden" on them, and I don't think they had it before. Is this a clue? Also it does not help if I remove the polyline. The onclick function of the labels still don't work. Like, I can add polyline, remove it, add labels, and the labels' onclick is not working. Or I can add labels, add ployline, labels' onclick stops working, remove polyline, labels' onclick still not working.)
There are differences between the Multimarker js-script contained in the zip-file offered for download (2013-03-22) (
http://code.google.com/p/multimarker/) and the js-script accessed through http://multimarker.googlecode.com/svn/trunk/fast-marker-overlay/maps-v3/src/FastMarkerOverlay.js.
The script accessed through http:// says:
line 24:
panes.floatPane.appendChild(this._div);
instead of
panes.overlayLayer.appendChild(this._div);
and line 140:
this.latLng
instead of
latLng
I changed these things in the downloaded script and now it works! Thank you so much geocodezip for helping me solve this! If there is any way I can give you cred for this please tell me. I'm new to the site and I'm not sure of how it works...