<html>
<head>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.5.0/css/ol.css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.5.0/build/ol.js"></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.70/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
<script src="https://cesium.com/downloads/cesiumjs/releases/1.70/Build/CesiumUnminified/Cesium.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol-cesium#2.11.3/css/olcs.css">
<script src="https://cdn.jsdelivr.net/npm/ol-cesium#2.11.3/dist/olcesium.min.js"></script>
<style>
html,
body,
#olCesMap {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
#btnSwitchMap {
position: absolute;
top: 10px;
right: 50px;
z-index: 2;
padding: 4px;
}
</style>
</head>
<body>
<div id="olCesMap">
<button id="btnSwitchMap" onclick="cesViewer.setEnabled(!cesViewer.getEnabled());">Switch 2D/3D</button>
</div>
<script defer>
var controls = ol.control.defaults({
rotate: true,
rotateOptions: {
tipLabel: "Reset rotation. \nUse Alt+Shift+Drag to rotate the map."
}
});
var interactions = ol.interaction.defaults({ altShiftDragRotate: true, pinchRotate: true });
// Declaring Zoom level to further view
var zoom = 3;
// Declaring Map center
var center = ol.proj.fromLonLat([-96.41778916767144, 39.90201978025539]);
var worldImagery = new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
maxZoom: 19
})
});
worldImagery.set('name', 'tileLayer');
//Map Creation
var map = new ol.Map({
controls: controls,
//interactions: interactions,
target: 'olCesMap',
layers: [worldImagery, new ol.layer.Image({
extent: [-13884991, 2870341, -7455066, 6338219],
})],
view: new ol.View({
center: center,
zoom: zoom
})
});
//Cesium Viewer constructed based on Ol.Map
var cesViewer = new olcs.OLCesium({
map: map,
sceneOptions: {
mapProjection: new Cesium.WebMercatorProjection()
}
});
//Cesium Viewer scene
var scene = cesViewer.getCesiumScene();
//Cesium Viewer enable
cesViewer.setEnabled(false);
//Cesium Viewer depthtest
scene.globe.depthTestAgainstTerrain = true;
</script>
</body>
</html>
I want to animate arrow image every 3 seconds on the route like as when animation is start then arrow animate every 3 second.
move arrow image on route every 3 seconds from one location to second location.
see image what I want.
click here for image
import Feature from 'ol/Feature';
import LineString from 'ol/geom/LineString';
import Map from 'ol/Map';
import Point from 'ol/geom/Point';
import Polyline from 'ol/format/Polyline';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import OSM from 'ol/source/OSM';
import {Icon, Stroke, Style} from 'ol/style';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import {getVectorContext} from 'ol/render';
const center = [-5639523.95, -3501274.52];
const map = new Map({
target: document.getElementById('map'),
view: new View({
center: center,
zoom: 10,
minZoom: 2,
maxZoom: 19,
}),
layers: [
new TileLayer({
source: new OSM(),
}),
],
});
// The polyline string is read from a JSON similiar to those returned
// by directions APIs such as Openrouteservice and Mapbox.
fetch('data/polyline/route.json').then(function (response) {
response.json().then(function (result) {
const polyline = result.routes[0].geometry;
const route = new Polyline({
factor: 1e6,
}).readGeometry(polyline, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857',
});
const routeFeature = new Feature({
type: 'route',
geometry: route,
});
const startMarker = new Feature({
type: 'icon',
geometry: new Point(route.getFirstCoordinate()),
});
const endMarker = new Feature({
type: 'icon',
geometry: new Point(route.getLastCoordinate()),
});
const position = startMarker.getGeometry().clone();
const geoMarker = new Feature({
type: 'geoMarker',
geometry: position,
});
const styles = {
route: new Style({
stroke: new Stroke({
width: 6,
color: [237, 212, 0, 0.8],
}),
}),
icon: new Style({
image: new Icon({
anchor: [0.5, 1],
src: 'data/icon.png',
}),
}),
geoMarker: new Style({
image: new Icon({
src:
'https://cdn1.iconfinder.com/data/icons/basic-ui-elements-color-round/3/19-32.png',
rotation: getAngleAt(route, 0) + Math.PI / 2,
}),
}),
};
const vectorLayer = new VectorLayer({
source: new VectorSource({
features: [routeFeature, geoMarker, startMarker, endMarker],
}),
style: function (feature) {
return styles[feature.get('type')];
},
});
map.addLayer(vectorLayer);
const speedInput = document.getElementById('speed');
const startButton = document.getElementById('start-animation');
let animating = false;
function getAngleAt(lineString, distance) {
const length = lineString.getLength();
const coordinates = lineString.getCoordinates();
for (let i = 1, len = coordinates.length; i <= len; ++i) {
if (
new LineString(coordinates.slice(0, i + 1)).getLength() >=
length * distance
) {
return -Math.atan2(
coordinates[i][1] - coordinates[i - 1][1],
coordinates[i][0] - coordinates[i - 1][0]
);
}
}
}
const lastTimes = [];
function moveFeature(event) {
const speed = Number(speedInput.value);
const time = event.frameState.time;
for (let i = 0, ii = lastTimes.length; i < ii; ++i) {
let {lastTime, distance} = lastTimes[i];
const elapsedTime = time - lastTime;
distance = (distance + (speed * elapsedTime) / 1e6) % 2;
lastTime = time;
lastTimes[i] = {lastTime, distance};
const lineDistance = distance > 1 ? 2 - distance : distance;
const direction = distance > 1 ? -Math.PI / 2 : Math.PI / 2;
const currentCoordinate = route.getCoordinateAt(lineDistance);
const angle = getAngleAt(route, lineDistance) + direction;
styles.geoMarker.getImage().setRotation(angle);
position.setCoordinates(currentCoordinate);
const vectorContext = getVectorContext(event);
vectorContext.setStyle(styles.geoMarker);
vectorContext.drawGeometry(position);
}
// tell OpenLayers to continue the postrender animation
map.render();
}
function startAnimation() {
lastTimes.push({lastTime: Date.now(), distance: 0});
if (!animating) {
animating = true;
//startButton.textContent = 'Stop Animation';
vectorLayer.on('postrender', moveFeature);
// hide geoMarker and trigger map render through change event
geoMarker.setGeometry(null);
}
}
startButton.addEventListener('click', startAnimation);
});
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Marker Animation</title>
<link rel="stylesheet" href="node_modules/ol/ol.css">
<style>
.map {
width: 100%;
height: 400px;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<label for="speed">
speed:
<input id="speed" type="range" min="10" max="999" step="10" value="60">
</label>
<button id="start-animation">Start Animation</button>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://unpkg.com/elm-pep#1.0.6/dist/elm-pep.js"></script>
<script type="module" src="main.js"></script>
</body>
</html>
{
"name": "feature-move-animation",
"dependencies": {
"ol": "7.1.0"
},
"devDependencies": {
"vite": "^3.0.3",
"#babel/core": "latest"
},
"scripts": {
"start": "vite",
"build": "vite build"
}
}
I am trying this code but not getting idea how we can move every 3 seconds.
Related
I am trying to use WMTS layers in opnelayers project. This is my firt time when I try to use WMTS instead of WMS. Unfortunatelly I am stuck. I have no idea how to set up.
PLease help me to set up correct settings:
WMTS url GetCapabilities
my code (I used template from example on opnelayers.org):
import Map from 'ol/Map.js';
import OSM from 'ol/source/OSM.js';
import TileLayer from 'ol/layer/Tile.js';
import View from 'ol/View.js';
import WMTS from 'ol/source/WMTS.js';
import WMTSTileGrid from 'ol/tilegrid/WMTS.js';
import {get as getProjection} from 'ol/proj.js';
import {getTopLeft, getWidth} from 'ol/extent.js';
const projection = getProjection('EPSG:4326');
const projectionExtent = projection.getExtent();
const size = getWidth(projectionExtent) / 256;
const resolutions = new Array(19);
const matrixIds = new Array(19);
for (let z = 0; z < 19; ++z) {
// generate resolutions and matrixIds arrays for this WMTS
resolutions[z] = size / Math.pow(2, z);
matrixIds[z] = z;
}
const map = new Map({
layers: [
new TileLayer({
source: new OSM(),
}),
new TileLayer({
opacity: 0.7,
source: new WMTS({
url: 'https://mapy.geoportal.gov.pl/wss/service/PZGIK/ORTO/WMTS/HighResolution?SERVICE=WMTS&REQUEST=GetCapabilities',
layer: 'ORTOFOTOMAPA',
matrixSet: 'EPSG:2180',
format: 'image/png',
projection: projection,
tileGrid: new WMTSTileGrid({
origin: getTopLeft(projectionExtent),
resolutions: resolutions,
matrixIds: matrixIds,
}),
// style: 'default',
wrapX: true,
}),
}),
],
target: 'map',
view: new View({
center: [2008582, 6753697],
zoom: 7,
}),
});
Thanks!
If you have a custom projection there will also be a custom tile grid, so it is easier to parse the capabilities and let OpenLayers obtain the options. You will also need to define and register the EPSG:2180 projection (including the N-E axis order) using proj4.
import Map from 'ol/Map.js';
import OSM from 'ol/source/OSM.js';
import TileLayer from 'ol/layer/Tile.js';
import View, {createRotationConstraint} from 'ol/View.js';
import WMTS, {optionsFromCapabilities} from 'ol/source/WMTS.js';
import WMTSCapabilities from 'ol/format/WMTSCapabilities.js';
import proj4 from 'proj4';
import {register} from 'ol/proj/proj4';
proj4.defs(
'EPSG:2180',
'+proj=tmerc +lat_0=0 +lon_0=19 +k=0.9993 +x_0=500000 +y_0=-5300000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs +axis=neu'
);
register(proj4);
const wmtsLayer = new TileLayer({
opacity: 0.7,
});
const map = new Map({
layers: [
new TileLayer({
source: new OSM(),
}),
wmtsLayer,
],
target: 'map',
view: new View({
center: [2008582, 6753697],
zoom: 7,
}),
});
const parser = new WMTSCapabilities();
fetch(
'https://mapy.geoportal.gov.pl/wss/service/PZGIK/ORTO/WMTS/HighResolution?SERVICE=WMTS&REQUEST=GetCapabilities'
)
.then(function (response) {
return response.text();
})
.then(function (text) {
const result = parser.read(text);
const options = optionsFromCapabilities(result, {
layer: 'ORTOFOTOMAPA',
matrixSet: 'EPSG:2180',
});
wmtsLayer.setSource(new WMTS(options));
});
https://codesandbox.io/s/wmts-layer-from-capabilities-forked-6gu26y?file=/main.js
I am a relative beginner to using OpenLayers so I was playing around with some of the examples given on the OpenLayers website. When trying the image-vector-layer example, I had a problem where it would work fine with a json online, but when using a local geojson file the response under the networks section for the geojson file would be an html instead, giving the error "Unexpected token < in JSON at position 0". Attached is my javascript below, the error is occurring at the "url: data/countries.geojson". Is there any way I can use a local file instead of an online link? Thank you!
import 'ol/ol.css';
import GeoJSON from 'ol/format/GeoJSON';
import Map from 'ol/Map';
import VectorImageLayer from 'ol/layer/VectorImage';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import {Fill, Stroke, Style} from 'ol/style';
const style = new Style({
fill: new Fill({
color: '#eeeeee',
}),
});
const vectorLayer = new VectorImageLayer({
background: 'lightblue',
imageRatio: 2,
source: new VectorSource({
url: 'data/countries.geojson',
format: new GeoJSON(),
}),
style: function (feature) {
const color = feature.get('COLOR') || '#eeeeee';
style.getFill().setColor(color);
return style;
},
});
const map = new Map({
layers: [vectorLayer],
target: 'map',
view: new View({
center: [0, 0],
zoom: 1,
}),
});
const featureOverlay = new VectorLayer({
source: new VectorSource(),
map: map,
style: new Style({
stroke: new Stroke({
color: 'rgba(255, 255, 255, 0.7)',
width: 2,
}),
}),
});
let highlight;
const displayFeatureInfo = function (pixel) {
const feature = map.forEachFeatureAtPixel(pixel, function (feature) {
return feature;
});
const info = document.getElementById('info');
if (feature) {
info.innerHTML = feature.get('ECO_NAME') || ' ';
} else {
info.innerHTML = ' ';
}
if (feature !== highlight) {
if (highlight) {
featureOverlay.getSource().removeFeature(highlight);
}
if (feature) {
featureOverlay.getSource().addFeature(feature);
}
highlight = feature;
}
};
map.on('pointermove', function (evt) {
if (evt.dragging) {
return;
}
const pixel = map.getEventPixel(evt.originalEvent);
displayFeatureInfo(pixel);
});
map.on('click', function (evt) {
displayFeatureInfo(evt.pixel);
});
I have a WebView vehicle tracking application. I completed everything, but I could not manage to draw the path. What is the problem here?
var vectorSource = new ol.source.Vector(),
url_osrm_nearest = '//router.project-osrm.org/nearest/v1/driving/',
url_osrm_route = '//router.project-osrm.org/route/v1/driving/',
icon_url = '//cdn.rawgit.com/openlayers/ol3/master/examples/data/icon.png',
vectorLayer = new ol.layer.Vector({
source: vectorSource
}),
styles = {
route: new ol.style.Style({
stroke: new ol.style.Stroke({
width: 6, color: [40, 40, 40, 0.8]
})
}),
icon: new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: icon_url
})
})
};
var utils = {
getNearest: function(coord){
var coord4326 =coord;
return new Promise(function(resolve, reject) {
//make sure the coord is on street
fetch(url_osrm_nearest + coord4326.join()).then(function(response) {
// Convert to JSON
return response.json();
}).then(function(json) {
if (json.code === 'Ok') resolve(json.waypoints[0].location);
else reject();
});
});
},
createFeature: function(coord) {
feature = new ol.Feature({
type: 'place',
geometry: new ol.geom.Point(coord)
});
//feature.setStyle(iconStyle3);
vectorSource.addFeature(feature);
},
createRoute: function(polyline) {
var route = new ol.format.Polyline({
factor: 1e5,
}).readGeometry(polyline);
feature = new ol.Feature({
type: 'route',
geometry: route
});
feature.setStyle(styles.route);
vectorSource.addFeature(feature);
},
to4326: function(coord) {
return ol.proj.transform([
parseFloat(coord[0]), parseFloat(coord[1])
]);
}
};
view = new ol.View({
center: [34.061624811814305,39.44893665949777],
zoom: 16,
projection: 'EPSG:4326',
});
const map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM(),
}),
vectorLayer
],
target: 'map',
view: view,
});
const markerEl = document.getElementById('geolocation_marker');
const marker = new ol.Overlay({
positioning: 'center-center',
element: markerEl,
stopEvent: false
});
map.addOverlay(marker);
const markerEl2 = document.getElementById('geolocation_marker_musteri');
const marker2 = new ol.Overlay({
positioning: 'center-center',
element: markerEl2,
stopEvent: false
});
map.addOverlay(marker2);
const positions = new ol.geom.LineString([], ('XYZM'));
feature.getGeometry().setCoordinates([longi_,lati_]);
utils.getNearest([longi_,lati_]);
utils.getNearest([longi__v,lati_]);
utils.createFeature([longi__v,lati_]);
var point1 = [longi_,lati_];
var point2 = [longi__v,lati_];
fetch(url_osrm_route + point1 + ';' + point2).then(function(r) {
return r.json();
}).then(function(json) {
if(json.code !== 'Ok') {
return;
}
utils.createRoute(json.routes[0].geometry);
It draws a path as follows.
I'm looking at the route in openstreetmap with the same coordinates. It gives the correct route there. By the way, the coordinates are someone dynamic, that is, the position of the device. The other coordinate is stationary.
Edit:
I've realized now. It draws a straight line between two points. It doesn't draw according to the road.
I tried hard and couldn't find the solution. I also used openrouteservice instead of osm for geometry.
function get_JSON(coor1,coor2)
{
let request = new XMLHttpRequest();
request.open('POST', "https://api.openrouteservice.org/v2/directions/driving-car/json");
request.setRequestHeader('Accept', 'application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8');
request.setRequestHeader('Content-Type', 'application/json');
request.setRequestHeader('Authorization', 'api_key');
request.onreadystatechange = function () {
if (this.readyState === 4) {
var data_json= JSON.parse(this.responseText);
utils.createRoute(data_json.routes[0].geometry);
}
};
const body = '{"coordinates":[['+coor1+'],['+coor2+']],"radiuses":120000}';
request.send(body);
}
I am working on two examples provides by the community of OpenLayers here: https://openlayers.org/en/latest/examples/
Here is the first script (Geolocation):
import 'ol/ol.css';
import Feature from 'ol/Feature';
import Geolocation from 'ol/Geolocation';
import Map from 'ol/Map';
import Point from 'ol/geom/Point';
import View from 'ol/View';
import {Circle as CircleStyle, Fill, Stroke, Style} from 'ol/style';
import {OSM, Vector as VectorSource} from 'ol/source';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
var view = new View({
center: [0, 0],
zoom: 2,
});
var map = new Map({
layers: [
new TileLayer({
source: new OSM(),
}) ],
target: 'map',
view: view,
});
var geolocation = new Geolocation({
// enableHighAccuracy must be set to true to have the heading value.
trackingOptions: {
enableHighAccuracy: true,
},
projection: view.getProjection(),
});
function el(id) {
return document.getElementById(id);
}
el('track').addEventListener('change', function () {
geolocation.setTracking(this.checked);
});
// update the HTML page when the position changes.
geolocation.on('change', function () {
el('accuracy').innerText = geolocation.getAccuracy() + ' [m]';
el('altitude').innerText = geolocation.getAltitude() + ' [m]';
el('altitudeAccuracy').innerText = geolocation.getAltitudeAccuracy() + ' [m]';
el('heading').innerText = geolocation.getHeading() + ' [rad]';
el('speed').innerText = geolocation.getSpeed() + ' [m/s]';
});
// handle geolocation error.
geolocation.on('error', function (error) {
var info = document.getElementById('info');
info.innerHTML = error.message;
info.style.display = '';
});
var accuracyFeature = new Feature();
geolocation.on('change:accuracyGeometry', function () {
accuracyFeature.setGeometry(geolocation.getAccuracyGeometry());
});
var positionFeature = new Feature();
positionFeature.setStyle(
new Style({
image: new CircleStyle({
radius: 6,
fill: new Fill({
color: '#3399CC',
}),
stroke: new Stroke({
color: '#fff',
width: 2,
}),
}),
})
);
geolocation.on('change:position', function () {
var coordinates = geolocation.getPosition();
positionFeature.setGeometry(coordinates ? new Point(coordinates) : null);
});
new VectorLayer({
map: map,
source: new VectorSource({
features: [accuracyFeature, positionFeature],
}),
});
and here is the second script (Draw_features):
import 'ol/ol.css';
import Draw from 'ol/interaction/Draw';
import Map from 'ol/Map';
import View from 'ol/View';
import {OSM, Vector as VectorSource} from 'ol/source';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
var raster = new TileLayer({
source: new OSM(),
});
var source = new VectorSource({wrapX: false});
var vector = new VectorLayer({
source: source,
});
var map = new Map({
layers: [raster, vector],
target: 'map',
view: new View({
center: [-11000000, 4600000],
zoom: 4,
}),
});
var typeSelect = document.getElementById('type');
var draw; // global so we can remove it later
function addInteraction() {
var value = typeSelect.value;
if (value !== 'None') {
draw = new Draw({
source: source,
type: typeSelect.value,
});
map.addInteraction(draw);
}
}
/**
* Handle change event.
*/
typeSelect.onchange = function () {
map.removeInteraction(draw);
addInteraction();
};
document.getElementById('undo').addEventListener('click', function () {
draw.removeLastPoint();
});
addInteraction();
My main goal is to use both scripts to create just one map that show the user his geolocation and enable him to draw some features.
I tried writing this index.html file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Draw Features</title>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://unpkg.com/elm-pep"></script>
<style>
.map {
width: 800px;
height:400px;
position : relative
}
</style>
</head>
<body>
<div>
</div>
<label for="track">
track position
<input id="track" type="checkbox"/>
</label>
<p>
position accuracy : <code id="accuracy"></code>
altitude : <code id="altitude"></code>
altitude accuracy : <code id="altitudeAccuracy"></code>
heading : <code id="heading"></code>
speed : <code id="speed"></code>
</p>
<form class="form-inline">
<label for="type">Geometry type: </label>
<select class="form-control mr-2 mb-2 mt-2" id="type">
<option value="Point">Point</option>
<option value="LineString">LineString</option>
<option value="Polygon">Polygon</option>
<option value="Circle">Circle</option>
<option value="None">None</option>
</select>
<input class="form-control mr-2 mb-2 mt-2" type="button" value="Undo" id="undo">
</form>
<div id="map" class="map"></div>
<script src="draw_features.js"></script>
<script src="geolocation.js"></script>
</body>
</html>
But all i get is two maps one bellow the other and not one map : see image below
So my questions are :
Is it possible to combine both scripts to create one map (without merging the two scripts in one file)
How to avoid re importing modules in script 2 that were already imported in script 2
Actually I am using ArcGIS API for JavaScript 4.7. I want to get name of hospital or street in particular area when draw polyline . How to achieve that ?
Suppose I draw a area through polyline. In this area there are some hospital or street ..etc . Now I need the name of hospitals or street within that area.
the result look like :-
[street1,street2, ...] ,
[hospital1,hospital2, ...]
Update
error :-esri.layers.graphics.QueryEngine", message: "Unsupported query" details: undefined}
this error appear when try to collect hospital name in selected area the user can draw multi polygon,polyline
require([
"esri/views/MapView",
"esri/Map",
"esri/Basemap",
"esri/layers/TileLayer",
"esri/layers/MapImageLayer",
"esri/widgets/Sketch/SketchViewModel",
"esri/geometry/geometryEngine",
"esri/widgets/CoordinateConversion",
"esri/geometry/support/webMercatorUtils",
"esri/Graphic",
"esri/layers/GraphicsLayer",
"esri/config",
"esri/core/urlUtils",
"esri/widgets/Search",
"esri/tasks/Locator",
"esri/layers/FeatureLayer",
"esri/widgets/Expand",
"dojo/domReady!"
], function (
MapView, Map, Basemap, TileLayer, MapImageLayer,
SketchViewModel,
geometryEngine,
CoordinateConversion,
webMercatorUtils,
Graphic, GraphicsLayer, esriConfig,
urlUtils,Search,Locator,FeatureLayer,Expand
) {
const hospitals =new FeatureLayer({
url: 'https://services.arcgis.com/fLeGjb7u4uXqeF9q/ArcGIS/rest/services/Hospitals/Feat
ureServer/0',
renderer: {
type: 'simple',
symbol: {
type: 'text',
color: 'green',
text: '\ue687',
font: {
size: 16,
family: 'CalciteWebCoreIcons'
},
haloColor: 'white',
haloSize: 2
}
},
outFields: ['*']
});
var tempGraphicsLayer = new GraphicsLayer();
var saveGraphicsLayer = new GraphicsLayer();
var updateGraphic;
let hospitalsLayerView = null;
let highlight = null;
var myMap;
myMap = new Map({
basemap: "streets", //satellite
layers: [hospitals,tempGraphicsLayer, saveGraphicsLayer]
});
view = new MapView({
center: [-75.1683665, 39.951817],// [54.49, 24.41] long, lat
container: "viewDiv",
map: myMap,
zoom: 14
});
var ccWidget = new CoordinateConversion({
view: view
});
const searchWidget = new Search({
sources: [{
locator: new Locator({ url:
"https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer"}),
countryCode:"AE",
singleLineFieldName: "SingleLine",
name: "Custom Geocoding Service",
localSearchOptions: {
minScale: 300000,
distance: 50000
},
placeholder: "Find a place",
maxResults: 3,
maxSuggestions: 6,
suggestionsEnabled: true,
minSuggestCharacters: 0
}],
view: view,
includeDefaultSources: false
});
view.ui.add(searchWidget, {
position: "top-right",
index: 1
});
view.ui.add(ccWidget, "bottom-left");
view.ui.add("topbar", "top-right");
var pointSymbol = { // symbol used for points
type: "simple-marker", // autocasts as new SimpleMarkerSymbol()
style: "square",
color: "#8A2BE2",
size: "16px",
outline: { // autocasts as new SimpleLineSymbol()
color: [255, 255, 255],
width: 3 // points
}
}
var polylineSymbol = { // symbol used for polylines
type: "simple-line", // autocasts as new SimpleLineSymbol()
color: "#8A2BE2",
width: "4",
style: "dash"
}
var polygonSymbol = { // symbol used for polygons
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: "rgba(138,43,226, 0.8)",
style: "solid",
outline: {
color: "white",
width: 1
}
}
var polygonBoundrySymbol = { // symbol used for polygons
type: "simple-line", // autocasts as new SimpleFillSymbol()
color: "red"
}
let drawBoundry = function(){
let boundryJson = $v('P0_USER_LIMITS');
if(boundryJson){
let boundry = Graphic.fromJSON(JSON.parse(boundryJson));
boundry.symbol = polygonBoundrySymbol;
tempGraphicsLayer.add(boundry);
return boundry;
}
}
view.when(function () {
$('.esri-view-root').on('click', '.esri-print__export-button',
function(e){
e.preventDefault();
saveExportedImg();
});
// create a new sketch view model
var sketchViewModel = new SketchViewModel({
view: view,
layer: tempGraphicsLayer,
pointSymbol: pointSymbol,
polylineSymbol: polylineSymbol,
polygonSymbol: polygonSymbol
});
hospitals.when(function () {
view.whenLayerView(hospitals).then(function (layerView){
hospitalsLayerView = layerView;
})
})
.catch(errorCallback);
sketchViewModel.on("draw-complete", addGraphic);
sketchViewModel.on("update-complete", addGraphic);
sketchViewModel.on("update-cancel", addGraphic);
sketchViewModel.on("vertex-add", addGraphic);
function addGraphic(evt) {
// console.log ('graphic.geometry',evt.geometry)
//let currentGraphic = popActiveGraphic(tempGraphicsLayer);
let currentGraphic = saveGraphicsLayer.graphics.items.pop();
selectFeatures(evt.geometry);
var geometry = evt.geometry;
var vertices = evt.vertices;
var symbol;
var attr = {
Name: "Selected Area",
X: $v('P24_X'),
Y: $v('P24_Y')
};
// Choose a valid symbol based on return geometry
switch (geometry.type) {
case "point":
symbol = pointSymbol;
break;
case "polyline":
symbol = polylineSymbol;
break;
default:
symbol = polygonSymbol;
break;
}
geometry = webMercatorUtils.webMercatorToGeographic(geometry)
var within = true;
//}
if(within){
let graphic = new Graphic({
geometry: geometry,
symbol: symbol,
//attributes: attr,
popupTemplate: {
title: "{Name}",
content: [{
type: "fields",
fieldInfos: [{
fieldName: "X"
}, {
fieldName: "Y"
}]
}]
}
});
tempGraphicsLayer.add(graphic);
if(currentGraphic){
geometry.rings.forEach( ring =>
currentGraphic.geometry.addRing(ring));
graphic = currentGraphic;
}
var saveObj = graphic.toJSON();
$x('P24_JSON').value = JSON.stringify(saveObj);
saveGraphicsLayer.add(graphic);
} else {
apex.message.alert('&G_MAP_BOUNDRY_MSG.');
}
updateGraphic = null;
}
window.loadGraphic = function(polygon){
if(polygon===undefined || polygon === ''){
console.error('no polygon');
} else {
var graphic = Graphic.fromJSON(JSON.parse(polygon));
if (graphic.geometry){
addMultiGraph(graphic);
view.center.longitude = graphic.geometry.centroid.longitude;
view.center.latitude = graphic.geometry.centroid.latitude;
view.center = [graphic.geometry.centroid.longitude,
graphic.geometry.centroid.latitude];
view.zoom = 12;
}
}
}
loadGraphic($v('P24_JSON'));
// *************************************
// activate the sketch to create a point
// *************************************
var drawPointButton = document.getElementById("pointButton");
drawPointButton.onclick = function () {
// set the sketch to create a point geometry
sketchViewModel.create("point");
setActiveButton(this);
};
// ****************************************
// activate the sketch to create a polyline
// ****************************************
var drawLineButton = document.getElementById("polylineButton");
drawLineButton.onclick = function () {
// set the sketch to create a polyline geometry
sketchViewModel.create("polyline");
setActiveButton(this);
};
// ***************************************
// activate the sketch to create a polygon
// ***************************************
var drawPolygonButton = document.getElementById("polygonButton");
drawPolygonButton.onclick = function () {
// set the sketch to create a polygon geometry
sketchViewModel.create("polygon");
setActiveButton(this);
};
// ***************************************
// activate the sketch to create a rectangle
// ***************************************
var drawRectangleButton = document.getElementById(
"rectangleButton");
drawRectangleButton.onclick = function () {
// set the sketch to create a polygon geometry
sketchViewModel.create("rectangle");
setActiveButton(this);
};
document.getElementById("resetBtn").onclick = function () {
sketchViewModel.reset();
tempGraphicsLayer.removeAll();
saveGraphicsLayer.removeAll();
setActiveButton();
drawBoundry();
};
function setActiveButton(selectedButton) {
// focus the view to activate keyboard shortcuts for sketching
view.focus();
var elements = document.getElementsByClassName("active");
for (var i = 0; i < elements.length; i++) {
elements[i].classList.remove("active");
}
if (selectedButton) {
selectedButton.classList.add("active");
}
}
// ************************************************************************************
// set up logic to handle geometry update and reflect the update on "tempGraphicsLayer"
// ************************************************************************************
function setUpClickHandler() {
view.on("click", function (evt) {
view.hitTest(evt).then(function (response) {
var results = response.results;
// Found a valid graphic
if (results.length && results[results.length - 1]
.graphic) {
// Check if we're already editing a graphic
if (!updateGraphic) {
// Save a reference to the graphic we intend to update
updateGraphic = results[results.length - 1].graphic;
// Remove the graphic from the GraphicsLayer
// Sketch will handle displaying the graphic while being updated
tempGraphicsLayer.remove(updateGraphic);
sketchViewModel.update(updateGraphic.geometry);
}
}
});
});
}
function selectFeatures(geometry) {
if (hospitalsLayerView) {
let query = hospitals.createQuery();
query.returnGeometry = true;
query.outFields = ["*"];
hospitalsLayerView.queryFeatures(query)
.then(function (results) {
console.log ('results.features',results.features);
const graphics = results.features;
if (highlight) {
highlight.remove();
}
highlight = hospitalsLayerView.highlight(graphics);
console.log ('hospitL',graphics.map(g =>
g.attributes.HOSPITAL_NAME).join(','));
// namesDiv.innerHTML = graphics.map(g =>
g.attributes.HOSPITAL_NAME).join(',');
}).catch(errorCallback);
}
}
function errorCallback(error) {
console.log('error:', error);
}
// ************************************************************************************
// returns graphic object if drawn on the map to contcat new graphics to it
// ************************************************************************************
function popActiveGraphic(graphicsLayer){
let length = graphicsLayer.graphics.length;
let count = 0;
if($v('P0_USER_LIMITS').length > 0){
count++;
}
if(length > count){ //active drawing detected
let result = graphicsLayer.graphics.items[length-1];
graphicsLayer.remove(result);
return result;
}
}
});
});
Thanks,
Well, here I made an example for you merging some ArcGIS examples.
Just select the hospitals using a polygon. The selected hospitals are highlighted and the names display in the text section.
In your case do the same thing with any other layer you want to query to get features data.
<html>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='initial-scale=1, maximum-scale=1, user-scalable=no'>
<title>Select Feature With Polygon</title>
<style>
html,
body {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#viewDiv {
padding: 0;
margin: 0;
height: 400px;
width: 100%;
}
#namesDiv {
margin: 10px;
height: 200px;
width: 100%;
font-style: italic;
font-weight: bold;
font-family: Arial, Helvetica, sans-serif;
font-size: 16px;
color: green;
overflow: auto;
}
</style>
<link rel='stylesheet' href='https://js.arcgis.com/4.15/esri/css/main.css'>
<script src='https://js.arcgis.com/4.15/'></script>
<script>
require([
'esri/Map',
'esri/views/MapView',
'esri/layers/FeatureLayer',
'esri/layers/GraphicsLayer',
'esri/widgets/Sketch/SketchViewModel',
'esri/Graphic',
'esri/widgets/Expand'
], function (
Map,
MapView,
FeatureLayer,
GraphicsLayer,
SketchViewModel,
Graphic,
Expand
) {
let hospitalsLayerView = null;
let highlight = null;
const hospitals = new FeatureLayer({
url: 'https://services.arcgis.com/fLeGjb7u4uXqeF9q/ArcGIS/rest/services/Hospitals/FeatureServer/0',
renderer: {
type: 'simple',
symbol: {
type: 'text',
color: 'green',
text: '\ue687',
font: {
size: 16,
family: 'CalciteWebCoreIcons'
},
haloColor: 'white',
haloSize: 2
}
},
outFields: ['*']
});
const polygonGraphicsLayer = new GraphicsLayer();
const map = new Map({
basemap: 'streets',
layers: [hospitals, polygonGraphicsLayer]
});
const view = new MapView({
container: 'viewDiv',
map: map,
center: [-75.1683665, 39.951817],
zoom: 14
});
const sketchViewModel = new SketchViewModel({
view: view,
layer: polygonGraphicsLayer,
pointSymbol: {
type: 'simple-marker',
color: [255, 255, 255, 0],
size: '1px',
outline: {
color: 'gray',
width: 0
}
}
});
sketchViewModel.on('create', function (event) {
if (event.state === 'complete') {
polygonGraphicsLayer.remove(event.graphic);
selectFeatures(event.graphic.geometry);
}
});
hospitals.when(function () {
view.whenLayerView(hospitals).then(function (layerView){
hospitalsLayerView = layerView;
})
})
.catch(errorCallback);
const namesDiv = document.getElementById('namesDiv');
view.ui.add('select-by-polygon', 'top-left');
const selectButton = document.getElementById('select-by-polygon');
selectButton.addEventListener('click', function () {
clearUpSelection();
sketchViewModel.create('polygon');
});
function selectFeatures(geometry) {
view.graphics.removeAll();
if (hospitalsLayerView) {
const query = {
geometry: geometry,
outFields: ['*']
};
hospitalsLayerView
.queryFeatures(query)
.then(function (results) {
const graphics = results.features;
if (highlight) {
highlight.remove();
}
highlight = hospitalsLayerView.highlight(graphics);
namesDiv.innerHTML = graphics.map(g => g.attributes.HOSPITAL_NAME).join(',');
})
.catch(errorCallback);
}
}
function clearUpSelection() {
view.graphics.removeAll();
namesDiv.innerHTML = null;
}
function errorCallback(error) {
console.log('error:', error);
}
});
</script>
</head>
<body>
<div id='viewDiv'>
<div
id="select-by-polygon"
class="esri-widget esri-widget--button esri-widget esri-interactive"
title="Select hospitals by polygon"
>
<span class="esri-icon-checkbox-unchecked"></span>
</div>
</div>
<div id="namesDiv"></div>
</body>
</html>