|
POST
|
This is another one that cannot be done with documented means. However, it is easily done by replacing the _processUserInput method: const ccWidget = new CoordinateConversion({
view: view
});
ccWidget._processUserInput = function() {
alert("Convert clicked...");
};
view.ui.add(ccWidget, "bottom-left"); However, that will disconnect it from its default logic, and it would be entirely up to your custom code to handle the event. If you want to keep the existing default logic, then you would do something like this: const ccWidget = new CoordinateConversion({
view: view
});
ccWidget._defaultProcessUserInput = ccWidget._processUserInput;
ccWidget._processUserInput = function() {
var useDefault = false;
//custom code
if (useDefault)
this._defaultProcessUserInput();
};
view.ui.add(ccWidget, "bottom-left"); Note also that typing in the textbox will also cause this same handler to execute. Also...with all these hacks, my unsolicited opinion is that you may be better off creating your own widget/user interface, and leveraging the SDK's internal logic via an instance of CoordinateConversionViewModel.
... View more
05-18-2023
11:20 AM
|
0
|
0
|
827
|
|
POST
|
Yes, you can determine the tile scheme by poking around a bit in the application's source code using your browser's developer tools. For example, the tiling info can be seen by doing a search for tileInfo in the esriMap.js file, as shown below: As for the lods (levels of detail), it appears you can find information for those in the request to GetBackgrounds:
... View more
05-18-2023
10:49 AM
|
0
|
2
|
3231
|
|
POST
|
This is done by setting the currentLocation property. The documentation says that property is read-only, but that's incorrect. function visualize(latitude, longitude, ccWidget) {
ccWidget.currentLocation = Point.fromJSON({x:longitude,y:latitude,spatialReference:{wkid:4326}});
}
... View more
05-17-2023
11:25 AM
|
1
|
1
|
1134
|
|
POST
|
There's no documented way to do this, but you can still do something like this, which works in 4.26: function inputVisibleChanged(inputVisible) {
//custom logic here
alert(inputVisible);
}
const ccWidget = new CoordinateConversion({
view: view
});
ccWidget._originalToggleInputVisibility = ccWidget._toggleInputVisibility;
ccWidget._toggleInputVisibility = function() {
this._originalToggleInputVisibility.apply(this, arguments);
inputVisibleChanged(this._inputVisible);
};
ccWidget._originalOnConvertComplete = ccWidget._onConvertComplete;
ccWidget._onConvertComplete = function() {
this._originalOnConvertComplete.apply(this, arguments);
inputVisibleChanged(this._inputVisible);
};
... View more
05-16-2023
11:41 AM
|
0
|
0
|
608
|
|
POST
|
This appears to be a bug in the esri/chunks/calcite-input-date-picker module, and I don't think there's much you can do about it. You'll notice when you click on the arrow for the next month, the calender does flash briefly to the next month, but then gets reset. Whenever certain elements on the form are clicked, the values on the form are reset from a copy of the values in memory. Therefore, the value does get set to the next month when you click the arrow, but it immediately gets reset due to conflicting event handlers. Within the aforementioned module, this handler executes when you click one of the previous or next month arrows: this.handleArrowClick = (a,b)=>{
a.preventDefault();
this.calciteInternalDatePickerSelect.emit(b)
} If it were changed to this, it would work properly (note addition at line 3): this.handleArrowClick = (a,b)=>{
a.preventDefault();
a.cancelBubble = true; //added line
this.calciteInternalDatePickerSelect.emit(b)
} If you're hosting the API locally, you can apply this change. If not, perhaps it will get fixed in a future release.
... View more
05-12-2023
11:20 AM
|
1
|
0
|
1501
|
|
POST
|
@swiss_parks_network_nbernhard It seemed more fitting to reply here rather than in the idea thread. Basically, what I was saying there, was that you could create a Legend widget for each layer you want to display the symbology for. You then add each widget instance to the page. This is done by appending each widget's container node to an existing element on the page. I've made a crude example of this out of the Legend sample. On that page, replace the contents of the second script tag with this code, and then click the Refresh label at the top right. function addLegendForLayer(Legend, view, container, layer) {
var childElement = document.createElement("DIV");
container.appendChild(childElement);
const legend = new Legend({
view: view,
layerInfos: [
{
layer: layer,
title: "NY Educational Attainment"
}
],
container: childElement
});
}
require(["esri/views/MapView", "esri/widgets/Legend", "esri/WebMap"], (
MapView,
Legend,
WebMap
) => {
const webmap = new WebMap({
portalItem: {
// autocasts as new PortalItem()
id: "05e015c5f0314db9a487a9b46cb37eca"
}
});
const view = new MapView({
container: "viewDiv",
map: webmap
});
view.when(() => {
var container = document.createElement("DIV");
container.style.backgroundColor = "#FFFFFF";
// Add widget to the bottom right corner of the view
view.ui.add(container, "bottom-right");
addLegendForLayer(Legend, view, container, webmap.layers.getItemAt(0));
addLegendForLayer(Legend, view, container, webmap.layers.getItemAt(0));
});
}); This sample only had one layer, so for my example, I made two identical Legend widgets from the same layer. But, the main thing is that you can see that both Legend elements are present on the page. To the end user, this appears to be a single legend, but there's really multiple widgets there, one widget for each layer. With this kind of workflow, it would be fairly easy to add logic for adding/inserting Legend widgets in a particular order to your liking.
... View more
05-08-2023
06:25 PM
|
2
|
0
|
3202
|
|
POST
|
It's likely you'll have to replace the symbol object itself: // Rotate the arrow symbol based on the device's heading.
var newSymbol = arrowGraphic.symbol.clone();
newSymbol.angle = heading;
arrowGraphic.symbol = newSymbol; If that doesn't work, you might try replacing the graphic entirely: var newGraphic = arrowGraphic.clone();
newGraphic.symbol.angle = heading;
track.graphic = newGraphic;
... View more
04-26-2023
03:26 PM
|
0
|
2
|
1274
|
|
POST
|
The symbol definition looks good, but maybe try this instead when creating the FeatureLayer: const myFeatureLayer = new FeatureLayer({
url: "urlToFeatureLayer/FeatureServer/0",
title: "My Layer",
visible: true,
renderer: {
type: 'simple',
symbol: mySymbol
},
});
... View more
04-26-2023
10:09 AM
|
1
|
1
|
1724
|
|
POST
|
This problem has existed since 4.22 and lies in the esri/symbols/cim/CIMSymbolHelper module, particularly in the fromSimpleFillSymbol function: d.fromSimpleFillSymbol = function(a) {
const {color: c, style: b, outline: e} = a;
a = [];
const g = {
type: "CIMPolygonSymbol",
symbolLayers: a
};
var f = null;
if (e) {
const {cap: k, join: l, style: h} = e;
"solid" !== h && "none" !== h && "esriSLSSolid" !== h && "esriSLSNull" !== h && (f = [{
type: "CIMGeometricEffectDashes",
dashTemplate: R(h, k),
lineDashEnding: "NoConstraint",
scaleDash: !0,
offsetAlongLine: null
}]);
a.push({
type: "CIMSolidStroke",
color: u(e.color),
capStyle: P(k),
joinStyle: Q(l),
miterLimit: e.miterLimit,
width: e.width,
effects: f
})
}
//etc
}; The problem lies with line 9 of what's shown above; it should instead be something like: if ((e) && (e.style != "none") && (e.style != "esriSLSNull")) { Until this is fixed, the style "none" for SimpleFillSymbol outlines will be ignored. Another workaround, in addition to the one Undral mentioned, is to set your line symbol's opacity to zero (see line 7 below): const fillSymbol = {
type: "simple-fill",
color: [227, 139, 79, 1],
outline: {
type: "simple-line",
style: "none",
color: [255,0,0,0],
width: 5
}
};
... View more
04-21-2023
05:24 PM
|
0
|
0
|
6238
|
|
POST
|
What version of the API are you using? I saw a similar problem in 4.23, and it's discussed here.
... View more
04-20-2023
10:40 AM
|
0
|
0
|
1594
|
|
POST
|
A bug in the JavaScript Maps SDK causes features to be labeled improperly when the field from which labels are derived has a range domain (i.e. RangeDomain). Rather than the field's value being displayed, the field's domain name is displayed instead, as shown below: Displayed above is the Create a FeatureLayer with client-side graphics sample with some modifications that cause the issue to be seen. This can be reproduced by replacing the contents of the third script tag with the code below (a simple diff utility can show the changes): require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/layers/support/LabelClass",
"esri/layers/support/RangeDomain",
"esri/core/promiseUtils",
"esri/Graphic",
"esri/geometry/Point",
"esri/rest/locator"
], (
Map,
MapView,
FeatureLayer,
LabelClass,
RangeDomain,
promiseUtils,
Graphic,
Point,
locator
) => {
var labelIndex = 1;
const view = new MapView({
map: new Map({
basemap: "gray-vector"
}),
container: "viewDiv",
extent: {
spatialReference: {
wkid: 102100
},
xmin: -14488954,
ymin: 3457304,
xmax: -10656095,
ymax: 5250211
},
popup: {
dockEnabled: true,
dockOptions: {
position: "top-right",
breakpoint: false
}
}
});
view
.when()
.then(fetchImages)
.then(getFeaturesFromPromises)
.then(createLayer)
.then(addToView)
.catch((e) => {
console.error("Creating FeatureLayer from photos failed", e);
});
/**
* Fetches a list of images and returns a list of promises
*/
function fetchImages() {
const numPhotos = 18;
const graphicPromises = [];
const baseUrl =
"https://arcgis.github.io/arcgis-samples-javascript/sample-data/featurelayer-collection/photo-";
for (let i = 1; i <= numPhotos; i++) {
const url = baseUrl + i.toString() + ".jpg";
const graphicPromise = exifToGraphic(url, i);
graphicPromises.push(graphicPromise);
}
return promiseUtils.eachAlways(graphicPromises);
}
// Filters only promises that resolve with valid values (a graphic
// in this case) and resolves them as an array of graphics.
// In other words, each attempt at fetching an image returns a promise.
// Images that fail to fetch will be filtered out of the response array
// so the images that successfully load can be added to the layer.
function getFeaturesFromPromises(eachAlwaysResponses) {
return eachAlwaysResponses
.filter((graphicPromise) => {
return graphicPromise.value;
})
.map((graphicPromise) => {
return graphicPromise.value;
});
}
// Creates a client-side FeatureLayer from an array of graphics
function createLayer(graphics) {
return new FeatureLayer({
source: graphics,
objectIdField: "OBJECTID",
fields: [
{
name: "OBJECTID",
type: "oid"
},
{
name: "url",
type: "string"
},
{
name: "labeltest",
type: "integer",
domain: RangeDomain.fromJSON({
type: "range",
name: "d_LABELTEST",
range: [1,10000000]
})
}
],
labelingInfo: [
LabelClass.fromJSON({
"labelPlacement": "esriServerPolygonPlacementAlwaysHorizontal",
"where": null,
"labelExpression": "[labeltest]",
"useCodedValues": true,
"symbol": {
"type": "esriTS",
"color": [
230,
76,
0,
255
],
"backgroundColor": null,
"borderLineColor": null,
"borderLineSize": null,
"verticalAlignment": "bottom",
"horizontalAlignment": "left",
"rightToLeft": false,
"angle": 0,
"xoffset": 0,
"yoffset": 0,
"kerning": true,
"haloColor": [
255,
255,
255,
178
],
"haloSize": 1.25,
"font": {
"family": "Arial",
"size": 16,
"style": "normal",
"weight": "bold",
"decoration": "none"
}
},
"minScale": 0,
"maxScale": 0
})
],
popupTemplate: {
title: (event) => {
return locator
.locationToAddress({
location: event.graphic.geometry
})
.then((response) => {
return response.address;
})
.catch((error) => {
return "The middle of nowhere";
});
},
content: "<img src='{url}'>"
},
renderer: {
type: "simple",
symbol: {
type: "text",
color: "#7A003C",
text: "\ue661",
font: {
size: 20,
family: "CalciteWebCoreIcons"
}
}
}
});
}
// Adds a given layer to the map in the view
function addToView(layer) {
view.map.add(layer);
}
/**
* Fetches and loads an image from a url and gets the latitude/longitude
* GPS data from the EXIF data of the image. Returns a promise that
* resolves to a Graphic with a point geometry representing the location
* where the photo was taken.
*/
function exifToGraphic(url, id) {
return promiseUtils.create((resolve, reject) => {
const image = document.createElement("img");
image.src=url;
image.onload = () => {
image.load = image.onerror = null;
EXIF.getData(image, function () {
const latitude = EXIF.getTag(this, "GPSLatitude");
const latitudeDirection = EXIF.getTag(this, "GPSLatitudeRef");
const longitude = EXIF.getTag(this, "GPSLongitude");
const longitudeDirection = EXIF.getTag(this, "GPSLongitudeRef");
if (!latitude || !longitude) {
reject(
new Error(
"Photo doesn't contain GPS information: ",
this.src
)
);
return;
}
const location = new Point({
latitude: dmsDD(latitude, latitudeDirection),
longitude: dmsDD(longitude, longitudeDirection)
});
resolve(
new Graphic({
geometry: location,
attributes: {
url: url,
OBJECTID: id,
labeltest: labelIndex++
}
})
);
});
};
image.onerror = () => {
image.load = image.onerror = null;
reject(new Error("Error while loading the image"));
};
});
}
// Converts a DMS coordinate to decimal degrees
function dmsDD([degrees, minutes, seconds], direction) {
let dd = degrees + minutes / 60 + seconds / 3600;
if (direction === "S" || direction === "W") {
dd *= -1;
}
return dd;
}
}); The problem occurs in the esri/layers/support/labelFormatUtils module - in particular, line 15 of the function below: function t(b, f) {
if (null == b)
return "";
const a = f.domain;
if (a)
if ("codedValue" === a.type || "coded-value" === a.type)
for (var g of a.codedValues) {
if (g.code === b)
return g.name
}
else if ("range" === a.type) {
g = +b;
const h = "range"in a ? a.range[1] : a.maxValue;
if (("range"in a ? a.range[0] : a.minValue) <= g && g <= h)
return a.name
}
"date" === f.type || "esriFieldTypeDate" === f.type ? b = q.formatDate(b, q.convertDateFormatToIntlOptions("short-date")) : z.isNumericField(f) && (b = y.formatNumber(+b));
return b ? b : ""
} As can be seen, if the value is within the range of the domain, the domain's name is returned. This issue can be fixed by replacing "return a.name" with "return b". The code shown above is from version 4.26, but the problem goes at least as far back as 4.23.
... View more
04-19-2023
01:30 PM
|
1
|
2
|
1207
|
|
POST
|
Have you seen this thread? You'll find various proposed solutions to this kind of problem there.
... View more
04-13-2023
04:09 PM
|
0
|
1
|
2289
|
|
POST
|
You can download a copy of the API as described at the bottom of this page. You can also view the source code in your browser's developer tools (typically F12), most of which now provide tools for "beautifying" the code (i.e. formatting it to make it readable).
... View more
04-04-2023
10:15 AM
|
1
|
0
|
2459
|
|
POST
|
This just plain won't work out of the box, but that's not to say you can't work around it. We should first note that the documentation for LabelClass.where says "Only very basic SQL is supported." Perhaps if we better understood the qualifications for that, we could better understand why this fails. Fortunately, we can. The logic for evaluating the where clause of a LabelClass is found in the implementation of the LabelLayer class. Basically, it comes down to a private (and therefore undocumented) method called "_isWhere", which I have reproduced here: _isWhere: function(d, l) {
try {
if (!d)
return !0;
if (d) {
var t = d.split(" ");
if (3 === t.length)
return this._sqlEquation(l[this._removeQuotes(t[0])], t[1], this._removeQuotes(t[2]));
if (7 === t.length) {
var E = this._sqlEquation(l[this._removeQuotes(t[0])], t[1], this._removeQuotes(t[2]))
, G = t[3]
, n = this._sqlEquation(l[this._removeQuotes(t[4])], t[5], this._removeQuotes(t[6]));
switch (G) {
case "AND":
return E && n;
case "OR":
return E || n
}
}
}
return !1
} catch (F) {
console.log("Error.: can't parse \x3d " + d)
}
} With this, we can better understand what they mean by only basic SQL being supported. The problem happens because they split the where clause on spaces in order to evaluate it, and this implementation expects that the value portion of the expression will not have any spaces in it. This is why it fails out of the box for you, and there's really no way we can manipulate the expression to make it succeed. Instead, if we want to make this work, we'll have to alter the implementation. Fortunately, that's not terribly hard. Basically, within the first "require" statement of your application, you'll want to include a reference to "esri/layers/LabelLayer", and then you'll want to override the definition of the _isWhere function. I will use the sample referred to by @KenBuja as an example. First, we add the reference in the call to "require" (note changes on lines 5 and 14). require([
"esri/map",
"esri/geometry/Extent",
"esri/layers/FeatureLayer",
"esri/layers/LabelLayer", //added line
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol",
"esri/symbols/TextSymbol",
"esri/renderers/SimpleRenderer",
"esri/layers/LabelClass",
"esri/Color",
"dojo/domReady!"
], function(Map, Extent, FeatureLayer, LabelLayer, //modified line
SimpleLineSymbol, SimpleFillSymbol,
TextSymbol, SimpleRenderer, LabelClass, Color)
{ Immediately after this, we'll add our override of the _isWhere function: LabelLayer.prototype._isWhere = function(d, l) {
try {
if (!d)
return !0;
if (d) {
var t = d.split(" ");
if (3 === t.length)
return this._sqlEquation(l[this._removeQuotes(t[0])], t[1], this._removeQuotes(this._replaceSpaces(t[2])));
if (7 === t.length) {
var E = this._sqlEquation(l[this._removeQuotes(t[0])], t[1], this._removeQuotes(t[2]))
, G = t[3]
, n = this._sqlEquation(l[this._removeQuotes(t[4])], t[5], this._removeQuotes(t[6]));
switch (G) {
case "AND":
return E && n;
case "OR":
return E || n
}
}
}
return !1
} catch (F) {
console.log("Error.: can't parse \x3d " + d)
}
}; You will see it is exactly the same as the default implementation, except that I have added a call to a function "replaceSpaces" to the third argument on line 8. However, this function does not exist, so we will add it immediately afterwards: LabelLayer.prototype._replaceSpaces = function(a) {
return a.replace(/ /g, " ");
}; You'll see this function replaces any instances of the arbitrary placeholder " " with a space. With this in place, we can now replace any spaces in our where clause value with that placeholder, and things will work. In this case, as with Ken's suggestion, we could try: labelClass.where = "STATE_NAME = 'West Virginia'"; And it now works as expected. For clarity then, I've reproduced the entire contents within the script tag of the sample below. Modifications/additions are on lines 7, 16, 20-47, and 85. var map;
require([
"esri/map",
"esri/geometry/Extent",
"esri/layers/FeatureLayer",
"esri/layers/LabelLayer",
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol",
"esri/symbols/TextSymbol",
"esri/renderers/SimpleRenderer",
"esri/layers/LabelClass",
"esri/Color",
"dojo/domReady!"
], function(Map, Extent, FeatureLayer, LabelLayer,
SimpleLineSymbol, SimpleFillSymbol,
TextSymbol, SimpleRenderer, LabelClass, Color)
{
LabelLayer.prototype._isWhere = function(d, l) {
try {
if (!d)
return !0;
if (d) {
var t = d.split(" ");
if (3 === t.length)
return this._sqlEquation(l[this._removeQuotes(t[0])], t[1], this._removeQuotes(this._replaceSpaces(t[2])));
if (7 === t.length) {
var E = this._sqlEquation(l[this._removeQuotes(t[0])], t[1], this._removeQuotes(t[2]))
, G = t[3]
, n = this._sqlEquation(l[this._removeQuotes(t[4])], t[5], this._removeQuotes(t[6]));
switch (G) {
case "AND":
return E && n;
case "OR":
return E || n
}
}
}
return !1
} catch (F) {
console.log("Error.: can't parse \x3d " + d)
}
};
LabelLayer.prototype._replaceSpaces = function(a) {
return a.replace(/ /g, " ");
};
// load the map centered on the United States
var bbox = new Extent({"xmin": -1940058, "ymin": -814715, "xmax": 1683105, "ymax": 1446096, "spatialReference": {"wkid": 102003}});
//create the map and set the extent, making sure to "showLabels"
map = new Map("map", {
extent: bbox,
showLabels : true //very important that this must be set to true!
});
// create a renderer for the states layer to override default symbology
var statesColor = new Color("#666");
var statesLine = new SimpleLineSymbol("solid", statesColor, 1.5);
var statesSymbol = new SimpleFillSymbol("solid", statesLine, null);
var statesRenderer = new SimpleRenderer(statesSymbol);
// create the feature layer to render and label
var statesUrl = "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3";
var states = new FeatureLayer(statesUrl, {
id: "states",
outFields: ["*"]
});
states.setRenderer(statesRenderer);
// create a text symbol to define the style of labels
var statesLabel = new TextSymbol().setColor(statesColor);
statesLabel.font.setSize("14pt");
statesLabel.font.setFamily("arial");
//this is the very least of what should be set within the JSON
var json = {
"labelExpressionInfo": {"value": "{STATE_NAME}"}
};
//create instance of LabelClass (note: multiple LabelClasses can be passed in as an array)
var labelClass = new LabelClass(json);
labelClass.symbol = statesLabel; // symbol also can be set in LabelClass' json
labelClass.where = "STATE_NAME = 'West Virginia'";
states.setLabelingInfo([ labelClass ]);
map.addLayer(states);
});
... View more
04-03-2023
12:07 PM
|
2
|
2
|
2492
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 03-19-2024 10:37 AM | |
| 1 | 03-31-2026 02:34 PM | |
| 1 | 12-09-2025 09:35 AM | |
| 2 | 12-09-2025 09:06 AM | |
| 1 | 11-26-2025 12:29 PM |