Hi All:
I am making a map and would like to use a picturemarkersymbol with a local png to symbolize a mapimagelayer's sublayer. I have tried what is in the documentation to the tune of:
renderer: { type: "simple", symbol: { type: "picture-marker", url: 'img/busStop.png', width: 22, height: 22 } }
Now, if I put a png from another source in there (say from a google image search), it will show up on the map fine. This way, not so much. Could somebody lead me in the right direction?
Thanks!
Solved! Go to Solution.
Michael,
OK I have verified that there seems to be a bug where locally hosted images do not work. This is something you will have to report to esri tech support. Here is a sample that demos the issue. The Picturemarker symbol works if you have a directory called images and a image named search-pointer.png as it will work when adding it to the view as a graphic but will not work if used as a sublayers renderer symbol:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>MapImageLayer - Toggle sublayer visibility - 4.11</title>
<link rel="stylesheet" href="http://js.arcgis.com/4.11/esri/themes/light/main.css" />
<script src="http://js.arcgis.com/4.11/"></script>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/MapImageLayer",
"esri/symbols/PictureMarkerSymbol",
"esri/Graphic"
], function (Map, MapView, MapImageLayer, PictureMarkerSymbol, Graphic) {
/*****************************************************************
* Create a renderer for the dynamic data layer (table).
*****************************************************************/
var renderer = {
type: "simple", // autocasts as new SimpleRenderer()
symbol: {
type: "simple-line", // autocasts as new SimpleLineSymbol()
color: [255, 255, 255, 0.5],
width: 0.75,
style: "long-dash-dot-dot"
}
};
var pms = new PictureMarkerSymbol({
url: 'images/search-pointer.png', //this does not for a sublayer symbol
//url: 'https://js.arcgis.com/3.28/esri/dijit/Search/images/search-pointer.png', //this works
width: "22px",
height: "22px"
});
/*****************************************************************
* Create a MapImageLayer instance pointing to a Map Service
* containing data about US Cities, Counties, States and Highways.
* Define sublayers with visibility for each layer in Map Service.
*****************************************************************/
var layer = new MapImageLayer({
url: "http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer",
sublayers: [{
id: 2,
visible: true
},
{
id: 4,
visible: false,
title: "Railroads",
renderer: renderer,
source: {
// indicates the source of the sublayer is a dynamic data layer
type: "data-layer",
// this object defines the data source of the layer
// in this case it's a feature class table from a file geodatabase
dataSource: {
type: "table",
// workspace name
workspaceId: "MyDatabaseWorkspaceIDSSR2",
// table name
dataSourceName: "ss6.gdb.Railroads"
}
}
},
{
id: 1,
visible: true
},
{
id: 0,
renderer: {
type: 'simple',
symbol: pms
},
visible: true
}
]
});
/*****************************************************************
* Add the layer to a map
*****************************************************************/
var map = new Map({
basemap: "dark-gray",
layers: [layer]
});
var view = new MapView({
container: "viewDiv",
map: map,
zoom: 4,
center: [-99, 39]
});
view.when( function(){
var gra = new Graphic({
geometry: view.center,
symbol: pms
});
view.graphics.add(gra);
});
/*****************************************************************
* Wait for Layer to load and update the page to refelect which
* layers are visible in the Map Service.
*****************************************************************/
layer.when(function () {
layer.sublayers.map(function (sublayer) {
var id = sublayer.id;
var visible = sublayer.visible;
var node = document.querySelector(
".sublayers-item[data-id='" + id + "']"
);
if (visible) {
node.classList.add("visible-layer");
}
});
});
/*****************************************************************
* Listen for when buttons on the page have been clicked to turn
* layers on and off in the Map Service.
*****************************************************************/
var sublayersElement = document.querySelector(".sublayers");
sublayersElement.addEventListener("click", function (event) {
var id = event.target.getAttribute("data-id");
if (id) {
var sublayer = layer.findSublayerById(parseInt(id));
var node = document.querySelector(
".sublayers-item[data-id='" + id + "']"
);
sublayer.visible = !sublayer.visible;
node.classList.toggle("visible-layer");
}
});
});
</script>
<style>
html,
body {
font-family: sans-serif;
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#viewDiv {
position: absolute;
right: 0;
left: 0;
top: 0;
bottom: 60px;
}
.footer {
position: absolute;
bottom: 0;
height: 60px;
width: 100%;
}
.sublayers {
margin: 0 auto;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
overflow: auto;
}
.sublayers-item {
flex-grow: 4;
background-color: rgba(34, 111, 14, 0.5);
color: #fff;
margin: 1px;
width: 50%;
padding: 20px;
overflow: auto;
text-align: center;
cursor: pointer;
font-size: 0.7em;
}
.visible-layer {
color: #fff;
background-color: #226f0e;
}
</style>
</head>
<body>
<div id="viewDiv"></div>
<div class="footer">
<div class="sublayers">
<div class="sublayers-item" data-id="0">Cities</div>
<div class="sublayers-item" data-id="1">Highways</div>
<div class="sublayers-item" data-id="4">Railroads</div>
<div class="sublayers-item" data-id="2">States</div>
</div>
</div>
</body>
</html>
Michael,
So in your app in the folder where you have your .html file you have a img folder that has a busStop.png file and that file is named with the exact same cAsE?
Something like that. I have a script that loads the image as follows:
bufferLayers = new MapImageLayer({
// The layers must be in reverse order of how they are displayed in the REST interface otherwise
// it tries to render them dynamically which is not possible in 10.31.
url: bufferLayersURL,
title: "Other Map Features",
visible: true,
sublayers: [
{
id: busStopsPedJoinLayerID,
title: "Pedestrian-Bus Stop Buffers Join",
outFields: ["*"],
visible: false
},
,
,
,
,
label: 'Bus Stop Location'
},
popupTemplate: Bus Stop',
outFields: ["*"],
content: busStopContent
}
},
,
label: 'School Location'
},
popupTemplate: (<1mi)",
outFields: ["*"],
content: schoolContent
}
}
]
});
The weird part is that if I change the bus stop icon to “../img/busStop.png” it works fine, but the schools no longer show up. Neither show up if I load both locally. The only way to make it work is to use the janky web hosted images as above. Do I have to use a fully qualified location? As in publish it to the server then use an address as above?
Best,
Michael Collins
d +1 (646) 791-8814 | c +1 (651) 323-8431
An Equal Opportunity Employer
Michael,
I'm confused there is nothing in the code you shared that has anything to do with using a local png file...?
Hey Robert:
If I change what I sent to you to what is below, as I mentioned in my previous email (sorry it was unclear), I see no symbols. So…
Both png files hosted external => everything is fine
Bus stop png file local, school file external => bus stop shows up, but school does not
Both files local => nothing shows up
bufferLayers = new MapImageLayer({
// The layers must be in reverse order of how they are displayed in the REST interface otherwise
// it tries to render them dynamically which is not possible in 10.31.
url: bufferLayersURL,
title: "Other Map Features",
visible: true,
sublayers: [
{
id: busStopsPedJoinLayerID,
title: "Pedestrian-Bus Stop Buffers Join",
outFields: ["*"],
visible: false
},
,
,
,
,
label: 'Bus Stop Location'
},
popupTemplate: Bus Stop',
outFields: ["*"],
content: busStopContent
}
},
,
label: 'School Location'
},
popupTemplate: (<1mi)",
outFields: ["*"],
content: schoolContent
}
}
]
});
Michael Collins, E.I.T.
d +1 (646) 791-8814 | c +1 (651) 323-8431
An Equal Opportunity Employer
Michael,
I am still not seeing where in the provided code you are setting the sublayers renderer or your renderer code so that I can verify your code.
Strange, the sublayers in question are being stripped out, this should be clearer:
,
label: 'Bus Stop Location'
},
popupTemplate: Bus Stop',
outFields: ["*"],
content: busStopContent
}
},
,
label: 'School Location'
}
Michael Collins, E.I.T.
d +1 (646) 791-8814 | c +1 (651) 323-8431
An Equal Opportunity Employer
Michael,
OK I have verified that there seems to be a bug where locally hosted images do not work. This is something you will have to report to esri tech support. Here is a sample that demos the issue. The Picturemarker symbol works if you have a directory called images and a image named search-pointer.png as it will work when adding it to the view as a graphic but will not work if used as a sublayers renderer symbol:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>MapImageLayer - Toggle sublayer visibility - 4.11</title>
<link rel="stylesheet" href="http://js.arcgis.com/4.11/esri/themes/light/main.css" />
<script src="http://js.arcgis.com/4.11/"></script>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/MapImageLayer",
"esri/symbols/PictureMarkerSymbol",
"esri/Graphic"
], function (Map, MapView, MapImageLayer, PictureMarkerSymbol, Graphic) {
/*****************************************************************
* Create a renderer for the dynamic data layer (table).
*****************************************************************/
var renderer = {
type: "simple", // autocasts as new SimpleRenderer()
symbol: {
type: "simple-line", // autocasts as new SimpleLineSymbol()
color: [255, 255, 255, 0.5],
width: 0.75,
style: "long-dash-dot-dot"
}
};
var pms = new PictureMarkerSymbol({
url: 'images/search-pointer.png', //this does not for a sublayer symbol
//url: 'https://js.arcgis.com/3.28/esri/dijit/Search/images/search-pointer.png', //this works
width: "22px",
height: "22px"
});
/*****************************************************************
* Create a MapImageLayer instance pointing to a Map Service
* containing data about US Cities, Counties, States and Highways.
* Define sublayers with visibility for each layer in Map Service.
*****************************************************************/
var layer = new MapImageLayer({
url: "http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer",
sublayers: [{
id: 2,
visible: true
},
{
id: 4,
visible: false,
title: "Railroads",
renderer: renderer,
source: {
// indicates the source of the sublayer is a dynamic data layer
type: "data-layer",
// this object defines the data source of the layer
// in this case it's a feature class table from a file geodatabase
dataSource: {
type: "table",
// workspace name
workspaceId: "MyDatabaseWorkspaceIDSSR2",
// table name
dataSourceName: "ss6.gdb.Railroads"
}
}
},
{
id: 1,
visible: true
},
{
id: 0,
renderer: {
type: 'simple',
symbol: pms
},
visible: true
}
]
});
/*****************************************************************
* Add the layer to a map
*****************************************************************/
var map = new Map({
basemap: "dark-gray",
layers: [layer]
});
var view = new MapView({
container: "viewDiv",
map: map,
zoom: 4,
center: [-99, 39]
});
view.when( function(){
var gra = new Graphic({
geometry: view.center,
symbol: pms
});
view.graphics.add(gra);
});
/*****************************************************************
* Wait for Layer to load and update the page to refelect which
* layers are visible in the Map Service.
*****************************************************************/
layer.when(function () {
layer.sublayers.map(function (sublayer) {
var id = sublayer.id;
var visible = sublayer.visible;
var node = document.querySelector(
".sublayers-item[data-id='" + id + "']"
);
if (visible) {
node.classList.add("visible-layer");
}
});
});
/*****************************************************************
* Listen for when buttons on the page have been clicked to turn
* layers on and off in the Map Service.
*****************************************************************/
var sublayersElement = document.querySelector(".sublayers");
sublayersElement.addEventListener("click", function (event) {
var id = event.target.getAttribute("data-id");
if (id) {
var sublayer = layer.findSublayerById(parseInt(id));
var node = document.querySelector(
".sublayers-item[data-id='" + id + "']"
);
sublayer.visible = !sublayer.visible;
node.classList.toggle("visible-layer");
}
});
});
</script>
<style>
html,
body {
font-family: sans-serif;
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#viewDiv {
position: absolute;
right: 0;
left: 0;
top: 0;
bottom: 60px;
}
.footer {
position: absolute;
bottom: 0;
height: 60px;
width: 100%;
}
.sublayers {
margin: 0 auto;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
overflow: auto;
}
.sublayers-item {
flex-grow: 4;
background-color: rgba(34, 111, 14, 0.5);
color: #fff;
margin: 1px;
width: 50%;
padding: 20px;
overflow: auto;
text-align: center;
cursor: pointer;
font-size: 0.7em;
}
.visible-layer {
color: #fff;
background-color: #226f0e;
}
</style>
</head>
<body>
<div id="viewDiv"></div>
<div class="footer">
<div class="sublayers">
<div class="sublayers-item" data-id="0">Cities</div>
<div class="sublayers-item" data-id="1">Highways</div>
<div class="sublayers-item" data-id="4">Railroads</div>
<div class="sublayers-item" data-id="2">States</div>
</div>
</div>
</body>
</html>