How to get value for selected place in particular area when draw polyline or polygon through Javascript ArcGIS Api from TileLayer? - arcgis

Actually I am using ArcGIS API for JavaScript 4.7 and i have a custom internal layer . I want to get name of place particular area when draw polyline the column name is (PLC_NAME) . How to achieve that ?
Suppose I draw a area through polyline. In this area there are places . Now I need to get name of these places .
you can find the using code in below i am using the TileLayer.
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
) {
esriConfig.request.proxyUrl = "xxxxxxxxxxxxxxx";
urlUtils.addProxyRule({
urlPrefix: "xxxxxxxxxxxxxxxxxxx",
proxyUrl: "xxxxxxxxxxxxxxxxxx"
});
var tempGraphicsLayer = new GraphicsLayer();
var saveGraphicsLayer = new GraphicsLayer();
var updateGraphic;
let highlight = null;
'xxxxxxxxxxxxxxxxxxxxxxxxx';
var myMap;
var layer = new TileLayer({
url: mapUrl
});
var towerLayer = new MapImageLayer({
url: 'xxxxxxxxxxxxxxxxxxxxxxx'
});
myMap = new Map({
layers: [layer, tempGraphicsLayer, saveGraphicsLayer]
});
myMap.add(towerLayer);
view = new MapView({
center: [-55.1683665, 39.951817],
container: "viewDiv",
map: myMap,
zoom: 14
});
var ccWidget = new CoordinateConversion({
view: view
});
// Adds the search widget below other elements in
// the top left corner of the view
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"
}
// ################## U R HERE ################## ################## U R HERE ##################
################## U R HERE ##################
let drawBoundry = function(){
//let boundryJson = '&G_GEO_LIMITS.';
let boundryJson = $v('P0_USER_LIMITS');
if(boundryJson){
// let boundry = Graphic.fromJSON(JSON.parse('&G_GEO_LIMITS.'));
let boundry = Graphic.fromJSON(JSON.parse(boundryJson));
boundry.symbol = polygonBoundrySymbol;
tempGraphicsLayer.add(boundry);
return boundry;
}
}
/*
let boundry = drawBoundry();
*/
view.when(function () {
$('.esri-view-root').on('click', '.esri-print__export-button', function(e){
//console.log('event bubbling', e);
//console.log('event bubbling this', this);
e.preventDefault();
saveExportedImg();
});
// create a new sketch view model
var sketchViewModel = new SketchViewModel({
view: view,
layer: tempGraphicsLayer,
pointSymbol: pointSymbol,
polylineSymbol: polylineSymbol,
polygonSymbol: polygonSymbol
});
//setUpClickHandler();
// ************************************************************
// Get the completed graphic from the event and add it to view.
// This event fires when user presses
// * "C" key to finish sketching point, polygon or polyline.
// * Double-clicks to finish sketching polyline or polygon.
// * Clicks to finish sketching a point geometry.
// ***********************************************************
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();
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;
}
// Create a new graphic; add it to the GraphicsLayer
// console.log("b4 graphic");
geometry = webMercatorUtils.webMercatorToGeographic(geometry)
/*if(boundry){
var contains = geometryEngine.contains(boundry.geometry, geometry);
var within = geometryEngine.within(geometry, boundry.geometry);
} else {*/
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){
//currentGraphic.geometry.rings.push(geometry.rings[0]);
geometry.rings.forEach( ring => currentGraphic.geometry.addRing(ring));
//currentGraphic.geometry.addRing(geometry.rings);
//console.log('current active', geometry);
// console.log('current graphic', currentGraphic.geometry);
graphic = currentGraphic;
}
var saveObj = graphic.toJSON();
// console.log('saveObj', saveObj);
$x('P24_JSON').value = JSON.stringify(saveObj);
} else {
apex.message.alert('&G_MAP_BOUNDRY_MSG.');
}
updateGraphic = null;
}
function addMultiGraph(evt1) {
//let currentGraphic = popActiveGraphic(tempGraphicsLayer);
let currentGraphic = saveGraphicsLayer.graphics.items.pop();
var geometry = evt1.geometry;
var vertices = evt1.vertices;
var symbol;
// 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;
}
//console.log("ring",geometry.rings )
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));
}
var saveObj1 = graphic.toJSON();
//console.log('saveObj', graphic);
$x('P24_JSON').value = JSON.stringify(saveObj1);
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;
}
}
}
// *************************************
// 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);
};
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 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;
}
}
});
});

OK, you can resolve the queries on the client or on the server. Depends on your task what options you can pick on.
If you are going to use a spatial query, like the one you mention, and you will apply it on a FeatureLayer, you could solve it on the client. This is a good solution because you already have the features, you are seeing them. Here you have a question whis this situation, how-to-get-get-name-of-hospital-or-street-in-particular-area-when-draw-polyline.
Now, If you need to query something that might not be in your extent (you don't have the features) or you are not using a FeatureLayer, you probably will need to command the server to do this. But don't worry the library has several tools to work with, like QueryTask.
Here you have the same example of the answer link before but using QueryTask.
<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/MapImageLayer',
'esri/layers/GraphicsLayer',
'esri/widgets/Sketch/SketchViewModel',
'esri/Graphic',
'esri/widgets/Expand',
'esri/tasks/QueryTask',
'esri/tasks/support/Query'
], function (
Map,
MapView,
MapImageLayer,
GraphicsLayer,
SketchViewModel,
Graphic,
Expand,
QueryTask,
Query
) {
let highlight = null;
const states = new MapImageLayer({
url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer'
});
const queryTask = new QueryTask({
url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/2'
});
const polygonGraphicsLayer = new GraphicsLayer();
const selected = new GraphicsLayer();
const map = new Map({
basemap: 'streets',
layers: [states, polygonGraphicsLayer, selected]
});
const view = new MapView({
container: 'viewDiv',
map: map,
center: [-75.1683665, 39.951817],
zoom: 8
});
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);
}
});
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) {
selected.removeAll();
const query = new Query();
query.returnGeometry = true;
query.outFields = ['*'];
query.geometry = geometry;
queryTask
.execute(query)
.then(function (results) {
const graphics = results.features.map(r => {
r.symbol = {
type: 'simple-fill',
fill: 'none',
outline: {
color: 'cyan',
width: 2
}
};
return r;
});
selected.addMany(graphics);
namesDiv.innerHTML = graphics.map(g => g.attributes.NAME).join(',');
})
.catch(errorCallback);
}
function clearUpSelection() {
selected.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 counties by polygon"
>
<span class="esri-icon-checkbox-unchecked"></span>
</div>
</div>
<div id="namesDiv"></div>
</body>
</html>
To close I leave you this link to the documentation that explains very well all the possibilities, pros and cons.

Related

OpenLayers Vector tiles Styling Optimization

I am new to openlayers and vector layer and i am facing performance problem. I have 3 layers and each layer containing thousands of features. Is it the correct way of styling the layer or is there anything else we can do to further make it even faster even on low end computer. What else can be done in case of geoserver layergroup. How can we efficiently style it since it has many layers and how to get the layers from the layer group.
var gridsetName = "EPSG:900913";
var baseUrl = "http://localhost:8080/geoserver/gwc/service/wmts";
var style = "";
var format = "application/vnd.mapbox-vector-tile";
var layerCache = {};
var gardening_area_uncertainity = new Style({
stroke: new Stroke({
color: "rgba(200,20,20,0.8)",
width: 2,
}),
});
var gardening_point = new Style({
image: new Circle({
stroke: new Stroke({
width: 1,
color: "red",
}),
radius: 2,
}),
});
var layers = [
{
layer: "city:gardenings_point_uncertainity",
style: gardening_area_uncertainity,
},
{ layer: "city:gardening_aiming_area", style: gardening_area_uncertainity },
{ layer: "city:gardening_aiming_point", style: gardening_point },
];
var key = 0;
var styleForLayer = null;
var layerFeature = function (feature) {
//console.log("Type is:",feature.type_)
if (feature.get("layer") === "gardening_aiming_point") key = 1;
else if (feature.get("layer") === "gardenings_point_uncertainity") key = 2;
else if (feature.get("layer") === "gardening_aiming_area") key = 3;
styleForLayer = layerCache[key];
if (!styleForLayer) {
switch (feature.get("layer")) {
case "gardening_aiming_area":
styleForLayer = gardening_area_uncertainity;
break;
case "gardenings_point_uncertainity":
styleForLayer = gardening_area_uncertainity;
break;
case "gardening_aiming_point":
styleForLayer = gardening_point;
break;
}
layerCache[key] = styleForLayer;
}
return styleForLayer;
};
var i;
var view = new View({
center: [0, 0],
zoom: 2,
// constrainResolution:true,
extent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34],
});
var map = new Map({
layers: [
new TileLayer({
preload: Infinity,
source: new OSM({ cacheSize: 20000 }),
}),
],
target: "map",
view: view,
});
map
.getView()
.fit([-20037508.34, -20037508.34, 20037508.34, 20037508.34], map.getSize());
map.on("moveend", (evt) => {
console.log(map.getView().getZoom());
});
function constructSource() {
var url = baseUrl + "?";
for (var param in params) {
url = url + param + "=" + params[param] + "&";
}
url = url.slice(0, -1);
var source = new VectorTileSource({
url: url,
format: new MVT({}),
tileGrid: new WMTS({
tileSize: [256, 256],
origin: [-2.003750834e7, 2.003750834e7],
resolutions: resolutions,
}),
});
return source;
}
for (i = 0; i < layers.length; i++) {
//console.log('Layer',layers[i])
var params = {
REQUEST: "GetTile",
SERVICE: "WMTS",
VERSION: "1.0.0",
LAYER: layers[i].layer,
STYLE: style,
TILEMATRIX: gridsetName + ":{z}",
TILEMATRIXSET: gridsetName,
FORMAT: format,
TILECOL: "{x}",
TILEROW: "{y}",
};
var layer = new VectorTileLayer({
source: constructSource(),
preload: Infinity,
renderMode: "image",
style: layers[i].style,
});
map.addLayer(layer);
}

Multiple renderer in esri map

I have requirement which is using classbreakrenderer for showing clusters size as it breaks down, now i want to use one renderer which shows different different symbol for single cluster based on some attribute value.
I have tried to use UniqueValueRenderer but it not working.
Any suggestion
I have requirement which is using classbreakrenderer for showing clusters size as it breaks down, now i want to use one renderer which shows different different symbol for single cluster based on some attribute value.
I have tried to use UniqueValueRenderer but it not working.
I have requirement which is using classbreakrenderer for showing clusters size as it breaks down, now i want to use one renderer which shows different different symbol for single cluster based on some attribute value.
I have tried to use UniqueValueRenderer but it not working.
<script type="text/javascript">
window.dojoConfig = {
async: true,
packages: [
{
name: 'app',
location: window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + '/src'
}
]};
</script>
<!-- ArcGIS API for JavaScript library references -->
<script src="https://js.arcgis.com/3.15compact"></script>
<script>
require(["esri/map",
"esri/dijit/Geocoder",
"esri/dijit/HomeButton",
"esri/renderers/SimpleRenderer",
"esri/symbols/PictureMarkerSymbol",
"esri/layers/FeatureLayer",
"esri/InfoTemplate",
"esri/graphic",
"esri/graphicsUtils",
"app/clusterfeaturelayer",
"esri/symbols/SimpleMarkerSymbol",
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol",
"esri/symbols/PictureMarkerSymbol",
"esri/renderers/ClassBreaksRenderer",
"esri/renderers/HeatmapRenderer",
"esri/renderers/UniqueValueRenderer",
"dojo/_base/Color",
"dojo/on",
"dojo/dom-style",
"dojo/_base/fx",
"dojo/fx/easing",
"dojo/dom",
"dojo/domReady!"],
function (Map, Geocoder, HomeButton, SimpleRenderer, PictureMarkerSymbol, FeatureLayer, UniqueValueRenderer, InfoTemplate, Graphic, graphicsUtils, ClusterFeatureLayer, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, PictureMarkerSymbol, ClassBreaksRenderer, HeatmapRenderer, Color, on, domStyle, fx, easing, dom) {
// Locals
var map,
popup,
clusterLayer,
geocoder,
infoTemplate,
defaultSym,
selectedSym,
activeClusterElement;
// Create map
map = new Map("mapDiv", {
basemap: "dark-gray",
center: [-120, 50],
zoom: 3
});
// Create widget
geocoder = new Geocoder({
value: "California, United States",
autoNavigate: true,
maxLocations: 25,
autoComplete: true,
arcgisGeocoder: {
outFields: "Place_addr, PlaceName, Score"
},
map: map
}, "search");
geocoder.startup();
var home = new HomeButton({
map: map
}, "homeButton");
home.startup();
// Add raw points
// var featureLayer = new FeatureLayer("http://services.arcgis.com/oKgs2tbjK6zwTdvi/arcgis/rest/services/Major_World_Cities/FeatureServer/0", {
// infoTemplate: infoTemplate,
// outFields: ["*"]
// });
// map.addLayer(featureLayer);
// Add heatmap
// var featureLayer2 = new FeatureLayer("http://services.arcgis.com/oKgs2tbjK6zwTdvi/arcgis/rest/services/Major_World_Cities/FeatureServer/0");
// var heatmapRenderer = new HeatmapRenderer();
// featureLayer2.setRenderer(heatmapRenderer);
// map.addLayer(featureLayer2);
// Add clusters
map.on("load", function () {
// Add layer
addClusterLayer();
addClusterLayerEvents();
});
// Set popup
popup = map.infoWindow;
popup.highlight = false;
popup.titleInBody = false;
popup.domNode.className += " light";
//popup.domNode.style.marginTop = "-17px"; // for pins only
// Popup content
//infoTemplate = new InfoTemplate("Seismic Activity > 4.0", "<p>Location: ${NAME}</p><p>Magnitude: ${OTHER_MAG1}</p><p>Date: ${YEAR}/${MONTH}/${DAY}</p>");
infoTemplate = new InfoTemplate("<b>${CITY_NAME}</b>", "<p>COUNTRY: ${CNTRY_NAME}</p><p>STATE/PROVINCE: ${ADMIN_NAME}</p><p>POPULATION: ${POP}</p>");
// Option 1: Esri marker for single locations and selections
// defaultSym = new createPictureSymbol("./images/blue-cluster-pin.png", 0, 8, 9, 16);
// selectedSym = new createPictureSymbol("./images/blue-cluster-pin.png", 0, 9, 11, 20);
// Option 2: Use circle markers for symbols - Red
defaultSym = new SimpleMarkerSymbol("circle", 16,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([102,0,0, 0.55]), 3),
new Color([255, 255, 255, 1]));
selectedSym = new SimpleMarkerSymbol("circle", 16,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([102,0,0, 0.85]), 3),
new Color([255, 255, 255, 1]));
// Create a feature layer to get feature service
function addClusterLayer() {
var renderer,
renderer1,
small,
medium,
large,
xlarge;
// Add cluster renderer
clusterLayer = new ClusterFeatureLayer({
"url": "http://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/World_Cities/FeatureServer/0",
//"url": "http://services.arcgis.com/BG6nSlhZSAWtExvp/arcgis/rest/services/GlobalSeismographyNetwork/FeatureServer/0",
// "url": "http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Earthquakes/Since_1970/MapServer/0",
"distance": 95,
"id": "clusters",
"labelColor": "#fff",
"resolution": map.extent.getWidth() / map.width,
//"singleColor": "#888",
"singleSymbol": defaultSym,
"singleTemplate": infoTemplate,
"useDefaultSymbol": false,
"zoomOnClick": false,
"showSingles": true,
"objectIdField": "FID",
outFields: ["*"]
});
renderer = new ClassBreaksRenderer(defaultSym, "clusterCount");
// Red Clusters
small = new SimpleMarkerSymbol("circle", 25,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([212,116,60,0.5]), 15),
new Color([212,116,60,0.75]));
medium = new SimpleMarkerSymbol("circle", 50,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([178,70,37,0.5]), 15),
new Color([178,70,37,0.75]));
large = new SimpleMarkerSymbol("circle", 80,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([144,24,13,0.5]), 15),
new Color([144,24,13,0.75]));
xlarge = new SimpleMarkerSymbol("circle", 110,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([102,0,0,0.5]), 15),
new Color([102,0,0,0.75]));
// Break values - can adjust easily
renderer.addBreak(2, 50, small);
renderer.addBreak(50, 250, medium);
renderer.addBreak(250, 1000, large);
renderer.addBreak(1000, 50000, xlarge);
// Providing a ClassBreakRenderer is also optional
clusterLayer.setRenderer(renderer);
//added second renderer
var renderer1 = new UniqueValueRenderer(defaultSymbol, "CNTRY_NAME");
//add symbol for each possible value
renderer1.addValue("United States", new PictureMarkerSymbol({
"angle": 0,
"xoffset": 0,
"yoffset": 8,
"type": "esriPMS",
"url": "./images/blue-pin.png",
"contentType": "image/png",
"width": 24,
"height": 24
}));
renderer1.addValue("Argentina", new PictureMarkerSymbol({
"angle": 0,
"xoffset": 0,
"yoffset": 12,
"type": "esriPMS",
"url": "./images/blue-cluster-pin.png",
"contentType": "image/png",
"width": 24,
"height": 24
}));
//added to cluster
clusterLayer.setRenderer(renderer1);
map.addLayer(clusterLayer);
}
// Create png marker
// function createPictureSymbol(url, xOffset, yOffset, xWidth, yHeight) {
// return new PictureMarkerSymbol(
// {
// "angle": 0,
// "xoffset": xOffset,
// "yoffset": yOffset,
// "type": "esriPMS",
// "url": url,
// "contentType": "image/png",
// "width": xWidth,
// "height": yHeight
// }
// );
// }
// Create new graphic and add to map.graphics
function addSelectedFeature() {
var selIndex = map.infoWindow.selectedIndex,
selFeature;
if (selIndex !== -1) {
selFeature = map.infoWindow.features[selIndex];
// Remove old feature first
removeSelectedFeature();
// Add new graphic
map.infoWindow._lastSelected = new Graphic(selFeature.toJson());
map.infoWindow._lastSelected.setSymbol(selectedSym);
map.graphics.add(map.infoWindow._lastSelected);
}
}
// Remove graphic from map.graphics
function removeSelectedFeature() {
if (map.infoWindow._lastSelected) {
map.graphics.remove(map.infoWindow._lastSelected);
map.infoWindow._lastSelected = null;
}
}
// Highlight clusters
function setActiveClusterOpacity(elem, fillOpacity, strokeOpacity) {
var textElm;
if (elem) {
elem.setAttribute("fill-opacity", fillOpacity);
elem.setAttribute("stroke-opacity", strokeOpacity);
// Overide inherited properties for the text in the circle
textElm = elem.nextElementSibling;
if (textElm && textElm.nodeName === "text") {
textElm.setAttribute("fill-opacity", 1);
}
}
}
// Hide popup if selected feature is clustered
function onClustersShown(clusters) {
var i = 0,
extent;
if (map.infoWindow.isShowing && map.infoWindow._lastSelected) {
for (i; i < clusters.length; i++) {
if (clusters[i].attributes.clusterCount > 1) {
extent = clusterLayer._getClusterExtent(clusters[i]);
if (extent.contains(map.infoWindow._lastSelected.geometry)) {
map.infoWindow.hide();
break;
}
}
}
}
}
// Wire cluster layer events
function addClusterLayerEvents() {
// Mouse over events
clusterLayer.on("mouse-over", onMouseOverCluster);
clusterLayer.on("mouse-out", onMouseOutCluster);
// Clusters drawn
clusterLayer.on("clusters-shown", onClustersShown);
}
// Save the last selected graphic so we can highlight it
map.infoWindow.on("selection-change", function () {
addSelectedFeature();
animateInfoWindow();
});
// Clear selected graphic when infoWindow is hidden
map.infoWindow.on("hide", function () {
// re-activate cluster
setActiveClusterOpacity(activeClusterElement, 0.75, 0.5);
removeSelectedFeature();
});
// Popup enhancements
function onMouseOverCluster(e) {
if (e.graphic.attributes.clusterCount === 1) {
e.graphic._graphicsLayer.onClick(e);
} else {
if (e.target.nodeName === "circle") {
activeClusterElement = e.target;
setActiveClusterOpacity(activeClusterElement, 1, 1);
} else {
setActiveClusterOpacity(activeClusterElement, 1, 1);
}
}
}
function onMouseOutCluster(e) {
if (e.graphic.attributes.clusterCount > 1) {
if (e.target.nodeName === "circle" || e.target.nodeName === "text") {
setActiveClusterOpacity(activeClusterElement, 0.75, 0.5);
setActiveClusterOpacity(e.target, 0.75, 0.5);
}
}
}
function animateInfoWindow() {
domStyle.set(map.infoWindow.domNode, "opacity", 0);
fx.fadeIn({node: map.infoWindow.domNode,
duration: 150,
easing: easing.quadIn}).play();
}
// Click to close
map.on('click', function () {
if (map.infoWindow.isShowing) {
map.infoWindow.hide();
}
});
// ESC is pressed
map.on('key-down', function (e) {
if (e.keyCode === 27) {
map.infoWindow.hide();
}
});
// Dynamically reposition popups when map moves
map.on('extent-change', function () {
if (map.infoWindow.isShowing) {
map.infoWindow.reposition();
}
});
// Auto recenter map - optional
autoRecenter(map);
function autoRecenter(map) {
on(map, 'load', function (map) {
on(window, 'resize', map, map.resize);
});
on(map, 'resize', function(extent, width, height) {
map.__resizeCenter = map.extent.getCenter();
setTimeout(function() {
map.centerAt(map.__resizeCenter);
}, 100);
});
}
});
</script>
</head>
<body>
<div id="mapDiv"></div>
<div id="search"></div>
<div id="homeButton"></div>
</body>
</html>

How do I Set Up Clustering on Google Maps Web API

I'm trying to add clustering to Google Maps web project, but so far no luck. Here is what is working:
Added a few markers
Requested user location (code removed).
markercluster.js is the library file downloaded from the GitHub project and saved in the public.html file.
I have removed the API key for security.
JavaScript Code in HTML Body
var userPosition;
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
//center: {lat: -34.928499, lng: 138.600746},
center: {lat: -33.86882, lng: 151.209296},
zoom: 13
});
var markers = [
{coords:{lat:-34.923885, lng:138.562042}, content:'<p><strong>British Raj</strong></p>'},
{coords:{lat:-34.924476, lng:138.561141}, content:'<p><strong>Subway (Torrensville)</strong></p>'},
{coords:{lat:-34.843645, lng:138.507653}, content:'<p>Banyan Hotel Port Adelaide</p>'},
{coords:{lat:-34.92366, lng:138.567063}, content:'<p>Abyssinian Restaurant</p>'},
{coords:{lat:-34.923927, lng:138.561959}, content:'<p>Burger Foundry (Torrensville)</p>'}
];
var gmarkers = [];
for(var i = 0; i < markers.length; i++){
//addMarker(markers[i]);
gmarkers.push(addMarker(markers[i]));
}
function addMarker(props){
var marker = new google.maps.Marker({
position:props.coords,
map:map,
icon:'Layer 1.png'
});
if (props.content){
var infoWindow = new google.maps.InfoWindow({
content:props.content
});
marker.addListener('click', function(){
infoWindow.open(map, marker);
});
}
}
}
var markerCluster = new MarkerClusterer(map, gmarkers,{imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'});
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=API_KEY_REMOVED&callback=initMap"
async defer></script>
<script src="markercluster.js"></stript>
CSS
html, body{
height: 100%;
padding: 0;
margin: 0;
}
#map {
height: 80%;
weidth: 80%;
}
There are several issues with your code:
The creation of the MarkerClusterer is outside of the initMap function, so it runs before the API is loaded. Move that inside the initMap function.
The addMarker function doesn't return anything, so everytime you create a marker you add "undefined" to the gmarkers array (add: return marker; to the end of the function).
Based on the example in the documentation, you need to load markerclusterer.js before the Google Maps JavaScript API v3.
proof of concept fiddle
code snippet:
var userPosition;
var gmarkers = [];
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
//center: {lat: -34.928499, lng: 138.600746},
center: {
lat: -33.86882,
lng: 151.209296
},
zoom: 13
});
var markers = [
{coords:{lat:-34.923885, lng:138.562042}, content:'<p><strong>British Raj</strong></p>'},
{coords:{lat:-34.924476, lng:138.561141}, content:'<p><strong>Subway (Torrensville)</strong></p>'},
{coords:{lat:-34.843645, lng:138.507653}, content:'<p>Banyan Hotel Port Adelaide</p>'},
{coords:{lat:-34.92366, lng:138.567063}, content:'<p>Abyssinian Restaurant</p>'},
{coords:{lat:-34.923927, lng:138.561959}, content:'<p>Burger Foundry (Torrensville)</p>'}
];
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < markers.length; i++) {
//addMarker(markers[i]);
gmarkers.push(addMarker(markers[i]));
bounds.extend(markers[i].coords);
}
map.fitBounds(bounds);
function addMarker(props) {
var marker = new google.maps.Marker({
position: props.coords,
map: map,
});
if (props.content) {
var infoWindow = new google.maps.InfoWindow({
content: props.content
});
marker.addListener('click', function() {
infoWindow.open(map, marker);
});
}
return marker;
}
var markerCluster = new MarkerClusterer(map, gmarkers, {
imagePath: 'https://unpkg.com/#google/markerclustererplus#4.0.1/images/m'
});
}
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<div id="map"></div>
<script src="https://unpkg.com/#googlemaps/markerclustererplus/dist/index.min.js"></script>
<!-- Replace the value of the key parameter with your own API key. -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap">
</script>

Fabric JS 2.4.1 ClipPath Crop Not Working with a Dynamically Created rect Mask

I am making a editor using fabric js 2.4.1 and have completed all functionality except for the dynamic image cropping. The functionality involves creating a rectangle with the mouse over an image and clicking a crop button.
I have successfully done a proof of concept with a rectangle that was created statically but can't get it to render in my dynamic code. I don't think that the problem has to do with the dynamically created rect but I can't seem to isolate the problem. It has to be something simple that I'm overlooking and I think the problem might be in my crop button code.
document.getElementById("crop").addEventListener("click", function() {
if (target !== null && mask !== null) {
mask.setCoords();
target.clipPath = mask; // THIS LINE IS NOT WORKING!!!
//target.selectable = true;
target.setCoords();
console.log(target);
canvas.renderAll();
//canvas.remove(mask);
}
});
Here is a fiddle to the dynamic code that has the problem:
https://jsfiddle.net/Larry_Robertson/mqrv5fnt/
Here is a fiddle to the static code that I gained proof of concept from:
https://jsfiddle.net/Larry_Robertson/f34q67op/
Source code of Dynamic Version:
HTML
<canvas id="c" width="500" height="500" style="border:1px solid #ccc"></canvas>
<button id="crop">Crop</button>
JS
var canvas = new fabric.Canvas('c', {
selection: true
});
var rect, isDown, origX, origY, done, object, mask, target;
var src = "http://fabricjs.com/lib/pug.jpg";
fabric.Image.fromURL(src, function(img) {
img.selectable = false;
img.id = 'image';
object = img;
canvas.add(img);
});
canvas.on('object:added', function(e) {
target = null;
mask = null;
canvas.forEachObject(function(obj) {
//alert(obj.get('id'));
var id = obj.get('id');
if (id === 'image') {
target = obj;
}
if (id === 'mask') {
//alert('mask');
mask = obj;
}
});
});
document.getElementById("crop").addEventListener("click", function() {
if (target !== null && mask !== null) {
mask.setCoords();
target.clipPath = mask; // THIS LINE IS NOT WORKING!!!
//target.selectable = true;
target.setCoords();
console.log(target);
canvas.renderAll();
//canvas.remove(mask);
}
});
canvas.on('mouse:down', function(o) {
if (done) {
canvas.renderAll();
return;
}
isDown = true;
var pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
rect = new fabric.Rect({
left: origX,
top: origY,
//originX: 'left',
//originY: 'top',
width: pointer.x - origX,
height: pointer.y - origY,
//angle: 0,
fill: 'rgba(255,0,0,0.3)',
transparentCorners: false,
//selectable: true,
id: 'mask'
});
canvas.add(rect);
canvas.renderAll();
});
canvas.on('mouse:move', function(o) {
if (done) {
canvas.renderAll();
return;
}
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if (origX > pointer.x) {
rect.set({
left: Math.abs(pointer.x)
});
}
if (origY > pointer.y) {
rect.set({
top: Math.abs(pointer.y)
});
}
rect.set({
width: Math.abs(origX - pointer.x)
});
rect.set({
height: Math.abs(origY - pointer.y)
});
canvas.renderAll();
});
canvas.on('mouse:up', function(o) {
if (done) {
canvas.renderAll();
return;
}
isDown = false;
//rect.selectable = true;
rect.set({
selectable: true
});
rect.setCoords();
canvas.setActiveObject(rect);
canvas.bringToFront(rect);
canvas.renderAll();
//alert(rect);
rect.setCoords();
object.clipPath = rect;
object.selectable = true;
object.setCoords();
canvas.renderAll();
//canvas.remove(rect);
done = true;
});
You need to set the dirty parameter on image on true, so object's cache will be rerendered next render call.
Here is the fiddle:
https://jsfiddle.net/mqrv5fnt/115/
var canvas = new fabric.Canvas('c', {
selection: true
});
var rect, isDown, origX, origY, done, object, mask, target;
var src = "http://fabricjs.com/lib/pug.jpg";
fabric.Image.fromURL(src, function(img) {
img.selectable = false;
img.id = 'image';
object = img;
canvas.add(img);
});
canvas.on('object:added', function(e) {
target = null;
mask = null;
canvas.forEachObject(function(obj) {
//alert(obj.get('id'));
var id = obj.get('id');
if (id === 'image') {
target = obj;
}
if (id === 'mask') {
//alert('mask');
mask = obj;
}
});
});
document.getElementById("crop").addEventListener("click", function() {
if (target !== null && mask !== null) {
mask.setCoords();
target.clipPath = mask; // THIS LINE IS NOT WORKING!!!
target.dirty=true;
//target.selectable = true;
target.setCoords();
canvas.remove(mask);
canvas.renderAll();
//canvas.remove(mask);
}
});
canvas.on('mouse:down', function(o) {
if (done) {
canvas.renderAll();
return;
}
isDown = true;
var pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
rect = new fabric.Rect({
left: origX,
top: origY,
//originX: 'left',
//originY: 'top',
width: pointer.x - origX,
height: pointer.y - origY,
//angle: 0,
fill: 'rgba(255,0,0,0.3)',
transparentCorners: false,
//selectable: true,
id: 'mask'
});
canvas.add(rect);
canvas.renderAll();
});
canvas.on('mouse:move', function(o) {
if (done) {
canvas.renderAll();
return;
}
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if (origX > pointer.x) {
rect.set({
left: Math.abs(pointer.x)
});
}
if (origY > pointer.y) {
rect.set({
top: Math.abs(pointer.y)
});
}
rect.set({
width: Math.abs(origX - pointer.x)
});
rect.set({
height: Math.abs(origY - pointer.y)
});
canvas.renderAll();
});
canvas.on('mouse:up', function(o) {
if (done) {
canvas.renderAll();
return;
}
isDown = false;
//rect.selectable = true;
rect.set({
selectable: true
});
rect.setCoords();
canvas.setActiveObject(rect);
canvas.bringToFront(rect);
canvas.renderAll();
//alert(rect);
rect.setCoords();
object.clipPath = rect;
object.selectable = true;
object.setCoords();
canvas.renderAll();
//canvas.remove(rect);
done = true;
});

Google map API route from current location to marker

Working with the Google map API and routes or directions. I would like it such that when a user clicks a marker the route from the user's current location to that marker would render.
I have been studying the Google maps API documentation direction services example here.
Here is my attempt at adapting that. To me it seems this should work, so what am I missing? The route or direction between the user's current location and the marker is not rendering.
<!DOCTYPE html>
<html>
<body>
<h1>My First Google Map</h1>
<div id="googleMap" style="width:60%;height:800px;"></div>
<script>
var myLatLng;
function geoSuccess(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
var directionsService = new google.maps.DirectionsService;
var directionsDisplay = new google.maps.DirectionsRenderer;
myLatLng = {
lat: latitude,
lng: longitude
};
var mapProp = {
// center: new google.maps.LatLng(latitude, longitude), // puts your current location at the centre of the map,
zoom: 15,
mapTypeId: 'roadmap',
};
var map = new google.maps.Map(document.getElementById("googleMap"), mapProp);
var directionsService = new google.maps.DirectionsService;
var directionsDisplay = new google.maps.DirectionsRenderer;
//call renderer to display directions
directionsDisplay.setMap(map);
var bounds = new google.maps.LatLngBounds();
// var mapOptions = {
// mapTypeId: 'roadmap'
// };
// Multiple Markers
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
title: 'My location'
});
var markers = [
['Ragazzi', 53.201472, -6.111626],
['McDonalds', 53.200482, -6.111337],
['my location', latitude, longitude]
];
// Info Window Content
var infoWindowContent = [
['<div>' +
'<h3>Ragazzi</h3>' +
'<p>Cafe eatin place.</p>' + ' <button onclick="calculateAndDisplayRoute(marker, i)"> Get Directions</button>' + '</div>'
],
['<div class="info_content">' +
'<h3>McDonalds</h3>' +
'<p>Excellent food establishment, NOT!.</p>' + '<button onclick="calculateAndDisplayRoute(marker, i)"> Get Directions</button>' +
'</div>'
]
];
// Display multiple markers on a map
var infoWindow = new google.maps.InfoWindow(),
marker, i;
// Loop through our array of markers & place each one on the map
for (i = 0; i < markers.length; i++) {
var position = new google.maps.LatLng(markers[i][1], markers[i][2]);
bounds.extend(position);
marker = new google.maps.Marker({
position: position,
map: map,
title: markers[i][0]
});
// Allow each marker to have an info window
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infoWindow.setContent(infoWindowContent[i][0]);
infoWindow.open(map, marker);
}
})(marker, i));
marker.addListener('click', function() {
directionsService.route({
// origin: document.getElementById('start').value,
origin: myLatLng,
destination: marker.getPosition(),
travelMode: 'DRIVING'
}, function(response, status) {
if (status === 'OK') {
directionsDisplay.setDirections(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
});
// Automatically center the map fitting all markers on the screen
map.fitBounds(bounds);
}
}
// function calculateAndDisplayRoute(directionsService, directionsDisplay) {
// directionsService.route({
// // origin: document.getElementById('start').value,
// origin: myLatLng,
// destination: marker.getPosition(),
// travelMode: 'DRIVING'
// }, function(response, status) {
// if (status === 'OK') {
// console.log('all good');
// directionsDisplay.setDirections(response);
// } else {
// window.alert('Directions request failed due to ' + status);
// }
// });
// }
function geoError() {
alert("Geocoder failed.");
}
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(geoSuccess, geoError);
// alert("Geolocation is supported by this browser.");
} else {
alert("Geolocation is not supported by this browser.");
}
}
</script>
<script async src="https://maps.googleapis.com/maps/api/js?key=api key here"></script>
</body>
</html>
Thanks,
I have solved this. The problem was the line,
destination: marker.getPosition(),
was not correct. This was giving me the coordinates of my current location and not the marker clicked.
I set the latit and longit in the function that sets the infoWindow, which have been defined as a global variable,
// Allow each marker to have an info window
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infoWindow.setContent(infoWindowContent[i][0]);
infoWindow.open(map, marker);
latit = marker.getPosition().lat();
longit = marker.getPosition().lng();
// console.log("lat: " + latit);
// console.log("lng: " + longit);
}
})(marker, i));
Then these are set to the destination,
marker.addListener('click', function() {
directionsService.route({
// origin: document.getElementById('start').value,
origin: myLatLng,
// destination: marker.getPosition(),
destination: {
lat: latit,
lng: longit
},
travelMode: 'DRIVING'
}, function(response, status) {
if (status === 'OK') {
directionsDisplay.setDirections(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
});
The full code is here on github.
A gh-pages working example.