I'm using Patrick Wied's OpenLayers Heatmap layer, but only for locations in the UK.
How can I preset the initial map display area to show just the UK?
Here's the code I've used in an ASPX page
var map, layer, heatmap;
function init() {
var testData = <asp:literal id="cLtMapData" runat="server" />
var transformedTestData = { max: testData.max, data: [] },
data = testData.data,
datalen = data.length,
nudata = [];
// in order to use the OpenLayers Heatmap Layer we have to transform our data into
// { max: <max>, data: [{lonlat: <OpenLayers.LonLat>, count: <count>},...]}
while (datalen--) {
nudata.push({
lonlat: new OpenLayers.LonLat(data[datalen].lon, data[datalen].lat),
count: data[datalen].count
});
}
transformedTestData.data = nudata;
map = new OpenLayers.Map('heatmapArea');
layer = new OpenLayers.Layer.OSM();
// create our heatmap layer
heatmap = new OpenLayers.Layer.Heatmap("Heatmap Layer", map, layer, { visible: true, radius: 10 }, { isBaseLayer: false, opacity: 0.3, projection: new OpenLayers.Projection("EPSG:4326") });
map.addLayers([layer, heatmap]);
map.zoomToMaxExtent();
//maxExtent: new OpenLayers.Bounds(-1*b, -1*b, b, b);
map.zoomIn();
heatmap.setDataSet(transformedTestData);
}
It's almost exactly like Patrick's demo pages, but with one difference - var testData = (an asp literal) - so that I can use dynamic data selected bu the user, and retrieved from an SQL Database via a stored procedure that translates UK postcodes into latitude and longitude.
I would do it in the map initialization. Something like this:
map = new OpenLayers.Map({
projection: new OpenLayers.Projection("EPSG:900913"),
units: "m",
numZoomLevels: 18,
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(
-20037508.34, -20037508.34, 20037508.34, 20037508.34
),
layers: [
new OpenLayers.Layer.OSM("OpenStreetMap", null, {
transitionEffect: 'resize'
})
],
center: new OpenLayers.LonLat(-10309900, 4215100),
zoom: 4
});
var lat = -3.841867446899414;
var lon = 43.466002139041116;
var zoom = 0;
var fromProjection = new OpenLayers.Projection("EPSG:28992"); // EPSG:4326Transform from WGS 1984
var toProjection = new OpenLayers.Projection("EPSG:900913"); // to Spherical Mercator Projection
var position = new OpenLayers.LonLat(lon, lat).transform(fromProjection, toProjection);
var options = {
controls: [
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.MousePosition(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.Permalink()
]
};
map = new OpenLayers.Map("basicMap", options);
var mapnik = new OpenLayers.Layer.OSM();
map.addLayer(mapnik);
map.setCenter(position, zoom);
Related
I have to store the created polygon in ArcGIS. Once the polygon is stored in ArcGIS, it returns an ID (Object ID). With the object ID, the administrator can access the polygon in ArcGIS. I found a piece of code in one of our old systems the code is written in version 3xx.
function SendFeaturesToParent()
{
editingEnabled = false;
editToolbar.deactivate();
lyrMeters.clearSelection();
polygon = currentEVT.graphic.geometry;
var query = new Query();
query.geometry = polygon;
lyrAreas.applyEdits(null, [currentEVT.graphic], null);
var attributes = [];
var featureValues = [];
for (var x = 0; x < selectedfeatures.length; x++) {
featureValues.push("METER_ID: " + selectedfeatures[x].attributes["METER_ID"] + ", Type: " + selectedfeatures[x].attributes["Type"]);
attributes.push(selectedfeatures[x].attributes);
}
console.log("attributes"+ attributes);
//Send the array of meter values back to the parent page.
var objectId = lyrAreas._defnExpr;
objectId = objectId.split('=');
window.parent.postMessage(
{
event_id: 'my_cors_message',
data: attributes,
objectId: objectId[1]
},
"*" //or "www.parentpage.com"
);
$('#modelConfirm').modal('hide');
}
I need to implement in latest version of arcGIS API 4.23. What are the applyEdits do?
/**** modified code in 4.23 */
var token = '';
const PermitAreaURL = "url_1";
const locatorUrl = "url_2";
const streetmapURL = "url_3";
const streetmapLebelsURL = "url_4";
const MetersURL = "url_5";
const MetersWholeURL = "url_6";
require(["esri/config",
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/layers/TileLayer",
"esri/layers/VectorTileLayer",
"esri/layers/GraphicsLayer",
"esri/widgets/Search",
"esri/widgets/Sketch/SketchViewModel",
"esri/geometry/geometryEngineAsync",
],
function (esriConfig, Map, MapView, FeatureLayer, TileLayer, VectorTileLayer, GraphicsLayer, Search, SketchViewModel, geometryEngineAsync) {
esriConfig.apiKey = "AAPK3f43082c24ae493196786c8b424e9f43HJcMvP1NYaqIN4p63qJnCswIPsyHq8TQHlNtMRLWokqJIWYIJjga9wIEzpy49c9v";
const graphicsLayer = new GraphicsLayer();
const streetmapTMLayer = new TileLayer({
url: streetmapURL
});
const streetmapLTMLayer = new VectorTileLayer({
url: streetmapLebelsURL
});
const lyrwholeMeters = new FeatureLayer({
url: MetersWholeURL,
outFields: ["*"],
});
const lyrMeters = new FeatureLayer({
url: MetersURL,
outFields: ["*"],
});
// const permitAreaUrl = new FeatureLayer({
// url: PermitAreaURL,
// outFields: ["*"],
// });
// console.log(lyrMeters);
const map = new Map({
basemap: "arcgis-topographic", // Basemap layer service
layers: [streetmapTMLayer, streetmapLTMLayer, lyrMeters, lyrwholeMeters, graphicsLayer]
});
const view = new MapView({
map: map,
center: [-95.9406, 41.26],
zoom: 16,
maxZoom: 21,
minZoom: 13,
container: "viewDiv" // Div element
});
view.when(() => {
const polygonSymbol = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [207, 34, 171, 0.5],
outline: {
// autocasts as new SimpleLineSymbol()
color: [247, 34, 101, 0.9],
}
};
const sketchViewModel = new SketchViewModel({
view: view,
layer: graphicsLayer,
polygonSymbol: polygonSymbol,
});
sketchViewModel.create("polygon", { mode: "hybrid" });
// Once user is done drawing a rectangle on the map
// use the rectangle to select features on the map and table
sketchViewModel.on("create", async (event) => {
if (event.state === "complete") {
// this polygon will be used to query features that intersect it
const geometries = graphicsLayer.graphics.map(function (graphic) {
return graphic.geometry
});
const queryGeometry = await geometryEngineAsync.union(geometries.toArray());
selectFeatures(queryGeometry);
}
});
});
// This function is called when user completes drawing a rectangle
// on the map. Use the rectangle to select features in the layer and table
function selectFeatures(geometry) {
console.log(geometry.rings);
// create a query and set its geometry parameter to the
// rectangle that was drawn on the view
const query = {
geometry: geometry,
outFields: ["*"]
};
lyrwholeMeters.queryFeatures(query).then(function (results) {
var lyr = results.features;
console.log(lyr);
// save the polygon
lyr.applyEdits({
addFeatures: [geometry] /*updates*/
});
lyr.forEach(element => {
console.log(`MeterID-${element.attributes.METER_ID}, OBJECTID-${element.attributes.OBJECTID}, Passport_ID-${element.attributes.Passport_ID}`);
});
});
}
// search widget
const searchWidget = new Search({
view: view,
});
view.ui.add(searchWidget, {
position: "top-left",
index: 2
});
});
applyEdits method is the way you to add/update/delete features in a feature layer. Both version of the library have the method although in version 4 takes an object that contain the edits instead of the separated parameters. In your code, version 3, it is,
lyrAreas.applyEdits(null, [currentEVT.graphic], null);
first parameter is for new features, second for updates on features and third for features to delete.
While in version 4 it should be,
lyrAreas.applyEdits({
updateFeatures: [currentEVT.graphic] /*updates*/
});
the object goes all the informations about the edits, in this case you only have updates.
I am not completely sure about this line,
var objectId = lyrAreas._defnExpr;
objectId = objectId.split('=');
I am guessing is the definition expression of the feature layer, a sql expression, that is why in the next line it is split, to use later the value. Version 3 library did not expose the property but gives set and get methods.
Version 4 have the property and works in similar way. In this case for latest version it should be,
var objectId = lyrAreas.definitionExpression;
objectId = objectId.split('=');
So I do not think you will have
ArcGIS API v3 - FeatureLayer
ArcGIS API v4 - FeatureLayer
I have a page setup that requires multiple instances of Google Maps via the API to be initialized. All works fine when one map is initialized the first time. When you re click on the button to do so, the map does not fully show.
var locations = [
['test1', 45.440188, -75.676309, 1, 'transportation.png'],
['test2', 45.439463, -75.675751, 1, 'medical.png'],
['test3', 45.439792, -75.683544, 1, 'schools.png'],
['test4', 45.439652, -75.676929, 1, 'shopping.png']
];
function initialize_1() {
var mapOptions = {
center: new google.maps.LatLng(45.438612, -75.677561),
zoom: 16,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas_1"), mapOptions);
marker = new google.maps.Marker({
position: new google.maps.LatLng(45.438612, -75.677561),
map: map
});
var marker, i;
var iconBase = 'http://www.elkproperty.com/new/images/icons/';
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map
,icon: iconBase + locations[i][4]
});
}
}
I think the issue is that you are initialising map to a hidden layer. Try to move call to initialize_1() after show():
onclick="$('#units_1').hide(); $('#unitArrow_1').hide(); $('#amenity_1').show(); $('#amenityArrow_1').show(); initialize_1();"
Other option is to force resize event after divs are visible. For this to work you would probably have to make map variable global.
google.maps.event.trigger(map, 'resize');
Maybe unrelated to your question but do you have to initialise the map layer each time you show div with map? Maybe you could test whether it is initialised or not, for example:
var isInit_1 = false;
function initialize_1() {
if (isInit_1) { return; }
isInit_1 = true;
var mapOptions = {
...
I believe I need to make follow up calls to get the results I am looking for. However, I cannot get the phone number and www url for any of the results I pull up.
I am a novice and need some help explaining where in this code I can get the correct results pulled. Please see the demo site here:
http://news.yeselectric.com/gmaps-excel-master/
Here is my JS code:
var store = (function () {
var searchBox,
infowindow,
markers = [],
myLatlng = new google.maps.LatLng(50.0019, 10.1419),
myOptions = { zoom: 6, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP, mapTypeControl: false, streetViewControl:false },
customIcons = { iconblue: './icons/blue.png' };
var init = function() {
map = new google.maps.Map(document.getElementById("map-canvas"), myOptions);
input = (document.getElementById('pac-input'));
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
searchBox = new google.maps.places.SearchBox((input));
store.listener();
},
listener = function() {
google.maps.event.addListener(searchBox, 'places_changed', function() {
//search for places
var places = searchBox.getPlaces();
for (var i = 0, marker; marker = markers[i]; i++) {
marker.setMap(null);
}
//set markers zero
markers = [];
$('.addaddress').empty();
//get new bounds
var bounds = new google.maps.LatLngBounds();
for (var i = 0, place; place = places[i]; i++) {
store.create_marker(place);
//append to the table
$('.addaddress').append('<tr><td>'+ place.name +'</td><td>'+ place.formatted_address +'</td><td>'+ place.formatted_phone_number +'</td><td>'+ place.website +'</td></tr>');
bounds.extend(place.geometry.location);
}
//set the map
map.fitBounds(bounds);
});
},
create_marker = function(info) {
//create a marker for each place
var marker = new google.maps.Marker({ map: map, icon: customIcons.iconblue, title: info.name, position: info.geometry.location });
//infowindow setup
google.maps.event.addListener(marker, "click", function() {
if (infowindow) {
infowindow.close();
}
infowindow = new google.maps.InfoWindow({content: info.name});
infowindow.open(map, marker);
});
//push the marker
markers.push(marker);
}
return {
init: init,
listener: listener,
create_marker: create_marker
};
})();
google.maps.event.addDomListener(window, 'load', store.init);
Google's API returns different place metadata, depending on which call you're using. To get more place details, you'll need to get the place's placeId and use that to make a call to place.getDetails()
Here's a more thorough answer: https://stackoverflow.com/a/9523345/2141296
We are trying to find suggestions, or implementation options on how to hide a marker once a new point on the map has been clicked.
In our application, once the user clicks on a particular pin on the map, we display a new pin (in a different lat/long location) that is associated with the click event. I.e. a point should be in oklahoma, but the map is displaying texas, so once the marker texas is clicked, a new marker in oklahoma is shown. Our issue is that whenever a user selects a new point, we are not able to "hide" the marker for the previous selection, which then clutters our screen.
Any suggestions on how we could handle this issue?
Code is below:
require(["esri/map", "esri/geometry/Point", "esri/symbols/SimpleMarkerSymbol", "esri/graphic", "dojo/_base/array", "dojo/dom-style", "dojox/widget/ColorPicker", "esri/InfoTemplate", "esri/Color", "dojo/dom", "dojo/domReady!", "esri/geometry/Polyline", "esri/geometry/geodesicUtils", "esri/units","esri/symbols/SimpleLineSymbol"],
function( Map, Point,SimpleMarkerSymbol, Graphic, arrayUtils, domStyle, ColorPicker, InfoTemplate, Color, dom, Polyline, geodesicUtils, Units,SimpleLineSymbol) {
map = new Map("mapDiv", {
center : [-98.35, 35.50],
zoom : 5,
basemap : "topo"
//basemap types: "streets", "satellite", "hybrid", "topo", "gray", "oceans", "osm", "national-geographic"
} );
map.on("load", pinMap);
var arr = [];
var initColor, iconPath;
function pinMap( ) {
map.graphics.clear();
iconPath = "M16,3.5c-4.142,0-7.5,3.358-7.5,7.5c0,4.143,7.5,18.121,7.5,18.121S23.5,15.143,23.5,11C23.5,6.858,20.143,3.5,16,3.5z M16,14.584c-1.979,0-3.584-1.604-3.584-3.584S14.021,7.416,16,7.416S19.584,9.021,19.584,11S17.979,14.584,16,14.584z";
var infoContent = "<b>Id</b>: ${Id} ";
var infoTemplate = new InfoTemplate(" Details",infoContent);
$.post( '{{ path( 'points' ) }}', {}, function( r ) {
arrayUtils.forEach( r.points, function( point ) {
if (point.test==1) {
initColor = "#CF3A3A";
}
else {
initColor = "#FF9900";
}
arr.push(point.id,point.pinLon1,point.pinLat1,point.pinLon2,point.pinLat2);
var attributes = {"Site URL":point.url,"Activity Id":point.id,"Updated By":point.updated,"Customer":point.customer};
var graphic = new Graphic(new Point(point.pinLon1,point.pinLat1),createSymbol(iconPath,initColor),attributes,infoTemplate);
map.graphics.add( graphic );
map.graphics.on("click",function(evt){
var Content = evt.graphic.getContent();
var storeId = getStoreId(Content);
sitePins(storeId);
});
} );
}, 'json' );
}
function getStoreId( content ){
var init = content.split(":");
var fin= init[2].split("<");
return fin[0].trim();
}
function sitePins( siteId ) {
iconPathSite = "M15.834,29.084 15.834,16.166 2.917,16.166 29.083,2.917z";
initColorSite = "#005CE6";
var infoContent = "<b>Distance</b>: ${Distance} Miles";
var infoTemplate = new InfoTemplate(" Distance to Location",infoContent);
var indexValue=0;
for (var index = 0; index < arr.length; index++){
if (arr[index]==storeId){
indexValue =index;
}
}
pinLon1 = arr[indexValue+1];
pinLat1 = arr[indexValue+2];
pinLon2 = arr[indexValue+3];
pinLat2 = arr[indexValue+4];
var line = {"paths":[[[pinLon1, pinLat1], [pinLon2, pinLat2]]]};
line = new esri.geometry.Polyline(line);
var lengths = Number(esri.geometry.geodesicLengths([line], esri.Units.MILES)).toFixed(2);
var attributes = {"Distance":lengths};
var graphicSite = new Graphic(new Point (pinLon1,pinLat1), createSymbol(iconPathSite, initColorSite),attributes,infoTemplate);
var pathLine = new esri.Graphic(line, new esri.symbol.SimpleLineSymbol());
map.graphics.add( pathLine );
map.graphics.add( graphicSite );
}
function createSymbol( path, color ) {
var markerSymbol = new esri.symbol.SimpleMarkerSymbol( );
markerSymbol.setPath(path);
markerSymbol.setSize(18);
markerSymbol.setColor(new dojo.Color(color));
markerSymbol.setOutline(null);
return markerSymbol;
}
} );
</script>
As far as I get the code, it shows the distance between the marker and the point then clicked.You are creating point and polyline on each click event on map. Following can help:
1) Please provide id say 'abc' to polyline, graphic site.
2) Then on every click event remove the graphic and polyline with id 'abc'.
dojo.forEach(this.map.graphics.graphics, function(g) {
if( g && g.id === "abc" ) {
//remove graphic with specific id
this.map.graphics.remove(g);
}
}, this);
3) Then you can create the new polyline and point as you are already doing it.
I have two points having lolLat as 0,10 and 30,0
Now to draw a marker at this point i use this transform while generating marker for it
lonLat.transform(
new OpenLayers.Projection("EPSG:4326"), // transform from WGS 1984
map.getProjectionObject() // to Spherical Mercator Projection
)
How can i draw line between them is there any way to do that in openlayers,i have tried doing it with linestring in vector layer but it doesn't seems to be working for me.
In OpenLayers version 3.3, you can do this as
var points = [ [-89.8802, 32.5804], [-95.04286, 46.9235] ];
for (var i = 0; i < points.length; i++) {
points[i] = ol.proj.transform(points[i], 'EPSG:4326', 'EPSG:3857');
}
var featureLine = new ol.Feature({
geometry: new ol.geom.LineString(points)
});
var vectorLine = new ol.source.Vector({});
vectorLine.addFeature(featureLine);
var vectorLineLayer = new ol.layer.Vector({
source: vectorLine,
style: new ol.style.Style({
fill: new ol.style.Fill({ color: '#00FF00', weight: 4 }),
stroke: new ol.style.Stroke({ color: '#00FF00', width: 2 })
})
});
Then add layer to map
map.addLayer(vectorLineLayer);
For example:
map = new OpenLayers.Map();
var start_point = new OpenLayers.Geometry.Point(0,10);
var end_point = new OpenLayers.Geometry.Point(30,0);
var vector = new OpenLayers.Layer.Vector();
vector.addFeatures([new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([start_point, end_point]))]);
map.addLayers([vector]);
Live demo
I am aware that this is an old question, but no up-to-date answer exists.
Here is a runnable code as an answer, using current version of Openlayers (August 2022).
const Feature = ol.Feature;
const VectorSource = ol.source.Vector;
const VectorLayer = ol.layer.Vector;
const LineString = ol.geom.LineString;
//const Point = ol.geom.Point;
const Style = ol.style.Style;
const Stroke = ol.style.Stroke;
const fromLonLat = ol.proj.fromLonLat;
const Overlay = ol.Overlay;
// Two locations with long/lat values in degrees
const lonlat0 = [100.538142, 13.765230];
const lonlat1 = [100.529321, 13.793656];
/* BEGIN: Code for the line joining the 2 points */
var points = [fromLonLat(lonlat0), fromLonLat(lonlat1)];
var line_feat1 = new Feature({
geometry: new LineString(points),
name: "My_Simple_LineString"
});
var line_vsrc = new VectorSource({
features: [line_feat1],
wrapX: false
});
var lineStyle = new Style({
stroke: new Stroke({
color: "red",
width: 5,
//lineDash: [4, 4, 4],
lineCap: "butt"
/* https://openlayers.org/en/latest/apidoc/module-ol_style_Stroke.html */
})
});
var veclay_line = new VectorLayer({
source: line_vsrc,
style: lineStyle
});
// `veclay_line` is the outcome of this complicate code
/* END: Code for the line joining the 2 points */
// Create map
// Note: `veclay_line`, containing the LineString is used within `layers`
var map = new ol.Map({
target: "map",
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
veclay_line
],
view: new ol.View({
center: ol.proj.fromLonLat(lonlat0),
zoom: 13
})
});
.map {
height: 400px;
width: 100%;
}
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.15.1/css/ol.css" type="text/css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.15.1/build/ol.js"></script>
<title>OpenLayers 6</title>
</head>
<body>
<div id="map" class="map"></div>
</body>
As this question comes up on top in search results, I figured giving the current v6 answer would be beneficial.
It's a bit more complicated now, need to create a bunch of intermediary objects (at least as far as I understood):
const raster = new ol.layer.Tile({
source: new ol.source.OSM(),
});
const source = new ol.source.Vector();
const p1 = [-12500000, 6500000];
const p2 = [-10000000, 4000000];
const line = new ol.geom.LineString([p1, p2]);
const feature = new ol.Feature({
geometry: line,
name: "Line"
});
source.addFeature(feature);
const vector = new ol.layer.Vector({
source: source,
});
const map = new ol.Map({
layers: [raster, vector],
target: 'mapdiv',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 4,
}),
});
You can then also modify the geometry on the fly with e.g.
line.appendCoodrinate([long,lat]);
and the map will be updated extending the line.
Here's a working demo for v6: Live demo
I don't get why the coord format is this way (10000ths of a degree), the docs on Coordinates, for example, show "normal" values, but code examples use that.