BACKGROUND
I am not a web developer. I am sure I violate all sorts of best practices and code conventions. Feel free to suggest code optimizations if you're so inclined.
I am trying to simply add a building 'highlight' and change the cursor to pointer on hover. I don't want to change the fill inside the building like in the example below. I just want to add a highlight outline.
QUESTIONS
CONSIDERATIONS
CODE
This code was taken from this thread and adapted to my particular use.
It's possible that I unknowingly removed bits of the code that is causing the weird functionality.
Please pardon the indentation errors, this is just how it pastes into the syntax highlighter.
function changeCursor(response){
if (response.results.length > 0){
document.getElementById("viewDiv").style.cursor = "pointer";
} else {
document.getElementById("viewDiv").style.cursor = "default";
}
}
function getGraphics(response) {
// the topmost graphic from the click location
// and display select attribute values from the
// graphic to the user
var graphic = response.results[0].graphic;
var attributes = graphic.attributes;
var name = attributes.BUILDINGNAME;
dom.byId("info").style.visibility = "visible";
dom.byId("name").innerHTML = name;
// symbolize all line segments with the given
// storm name with the same symbol
var renderer = new UniqueValueRenderer({
field: "BUILDINGNAME",
defaultSymbol: buildings_lyr.renderer.symbol || buildings_lyr.renderer.defaultSymbol,
uniqueValueInfos: [{
value: name,
symbol: new SimpleFillSymbol({
color:blue,
outline: {
color: orange,
width: 1
}
})
}]
});
buildings_lyr.renderer = renderer;
}
view.on("pointer-move", function (evt) {
var screenPoint = {
x: evt.x,
y: evt.y
};
// the hitTest() checks to see if any graphics in the view
// intersect the given screen x, y coordinates
view.hitTest(screenPoint)
.then(function (response) {
if (response.results.length > 0) {
if (response.results[0].graphic.layer.title == 'buildings_app') {
const graphic = response.results.filter(function (result) {
return result.graphic.layer === buildings_lyr;
})
changeCursor(response);
//getGraphics(response); //!!Uncomment this when getGraphics is fixed
}
} else {
changeCursor(response);
}
});
});
buildings_lyr.then(function() {
var renderer = buildings_lyr.renderer.clone();
renderer.symbol.color = [255,255,255,1.0];
buildings_lyr.renderer = renderer;
});
Solved! Go to Solution.
Parker,
OK, this is what you are after then (full working sample, no flicker):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="description" content="[Highlight features with hover events - 4.11]">
<!--
ArcGIS API for JavaScript, https://js.arcgis.com
For more information about the view-hittest sample, read the original sample description at developers.arcgis.com.
https://developers.arcgis.com/javascript/latest/view-hittest/index.html
-->
<title>Highlight features with hover events - 4.11</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.11/esri/css/main.css">
<link rel="stylesheet" href="https://js.arcgis.com/4.11/dijit/themes/claro/claro.css">
<script src="https://js.arcgis.com/4.11/"></script>
<script>
var dialog, dRenderer;
require([
"esri/core/watchUtils",
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/renderers/UniqueValueRenderer",
"esri/symbols/SimpleLineSymbol",
"dojo/dom",
"dojo/dom-style",
"dijit/popup",
"dojo/domReady!"
], function (
watchUtils,
Map,
MapView,
FeatureLayer,
UniqueValueRenderer,
SimpleLineSymbol,
dom,
domStyle,
dijitPopup
) {
var layer = new FeatureLayer({
url: "https://services.arcgis.com/8Pc9XBTAsYuxx9Ny/arcgis/rest/services/BuildingFootprint2D_gdb/FeatureServer/0",
outFields: ["*"]
});
var map = new Map({
basemap: "dark-gray",
layers: [layer]
});
var view = new MapView({
container: "viewDiv",
map: map,
center: [-80.135073, 25.774479],
zoom: 16
});
function changeCursor(response) {
if (response.results.length > 0) {
document.getElementById("viewDiv").style.cursor = "pointer";
} else {
document.getElementById("viewDiv").style.cursor = "default";
}
}
function getGraphics(response) {
view.graphics.removeAll();
if (response.results.length > 0) {
var graphic = response.results[0].graphic;
graphic.symbol = {
type: "simple-fill",
style: "none",
outline: { // autocasts as new SimpleLineSymbol()
color: "orange",
width: 1
}
}
view.graphics.add(graphic);
}
}
view.when(function () {
view.whenLayerView(layer).then(function (lview) {
watchUtils.whenFalseOnce(lview, "updating", function () {
// Set up a click event handler and retrieve the screen x, y coordinates
view.on("pointer-move", function (evt) {
var screenPoint = {
x: evt.x,
y: evt.y
};
// the hitTest() checks to see if any graphics in the view
// intersect the given screen x, y coordinates
view.hitTest(screenPoint)
.then(function (response) {
changeCursor(response);
getGraphics(response);
});
});
});
});
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
Parker,
I am missing the part in your posted code where you are changing the layers renderer... I see you have getGraphics commented out so the only thing that is happening on mouse over is the cursor change. Maybe this is not the right code you pasted?
Sorry for the confusion Robert. I tried to address an issue between SimpleLine vs SimpleFill and pasted a branched version of my code which I haven't been able to get working. The code pasted below resulted in the behavior present in the original GIF.
However, I am still uncertain what you mean by the "the part in your posted code where you are changing the layers renderer". I thought that was happening on line 34?
function changeCursor(response){
if (response.results.length > 0){
document.getElementById("viewDiv").style.cursor = "pointer";
} else {
document.getElementById("viewDiv").style.cursor = "default";
}
}
function getGraphics(response) {
// the topmost graphic from the click location
// and display select attribute values from the
// graphic to the user
var graphic = response.results[0].graphic;
var attributes = graphic.attributes;
var name = attributes.BUILDINGNAME;
dom.byId("info").style.visibility = "visible";
dom.byId("name").innerHTML = name;
// symbolize all line segments with the given
// storm name with the same symbol
var renderer = new UniqueValueRenderer({
field: "BUILDINGNAME",
defaultSymbol: buildings_lyr.renderer.symbol || buildings_lyr.renderer.defaultSymbol,
uniqueValueInfos: [{
value: name,
symbol: new SimpleLineSymbol({
color: "orange",
width: 1,
cap: "round"
})
}]
});
buildings_lyr.renderer = renderer;
}
view.on("pointer-move", function (evt) {
var screenPoint = {
x: evt.x,
y: evt.y
};
// the hitTest() checks to see if any graphics in the view
// intersect the given screen x, y coordinates
view.hitTest(screenPoint)
.then(function (response) {
if (response.results.length > 0) {
if (response.results[0].graphic.layer.title == 'buildings_app') {
const graphic = response.results.filter(function (result) {
return result.graphic.layer === buildings_lyr;
})
changeCursor(response);
getGraphics(response);
}
} else {
changeCursor(response);
}
});
});
Parker,
The symbol would change at line 34 if you did not comment out the getGraphics line in your previous code.
function changeCursor(response){
if (response.results.length > 0){
document.getElementById("viewDiv").style.cursor = "pointer";
} else {
document.getElementById("viewDiv").style.cursor = "default";
}
}
function getGraphics(response) {
// the topmost graphic from the click location
// and display select attribute values from the
// graphic to the user
var graphic = response.results[0].graphic;
var attributes = graphic.attributes;
var name = attributes.BUILDINGNAME;
dom.byId("info").style.visibility = "visible";
dom.byId("name").innerHTML = name;
var renderer = new UniqueValueRenderer({
field: "BUILDINGNAME",
defaultSymbol: buildings_lyr.renderer.symbol || buildings_lyr.renderer.defaultSymbol,
uniqueValueInfos: [{
value: name,
symbol: {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [ 51, 51, 204, 0.9 ],
style: "solid",
outline: { // autocasts as new SimpleLineSymbol()
color: "orange",
width: 1
}
}
}]
});
buildings_lyr.renderer = renderer;
}
view.on("pointer-move", function (evt) {
var screenPoint = {
x: evt.x,
y: evt.y
};
// the hitTest() checks to see if any graphics in the view
// intersect the given screen x, y coordinates
view.hitTest(screenPoint)
.then(function (response) {
if (response.results.length > 0 && response.results[0].graphic.layer.title == 'buildings_app') {
changeCursor(response);
getGraphics(response);
} else {
changeCursor(response);
}
});
});
Thanks Robert - the commenting out of the getGraphics() function was a mistake. I understand that if it's commented out, it will not fire. I have adjusted the code accordingly.
Re: your previous comment, I tested the code you supplied and created a GIF of the behavior below. I have a few issues with how it's performing...
Parker,
OK, this is what you are after then (full working sample, no flicker):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="description" content="[Highlight features with hover events - 4.11]">
<!--
ArcGIS API for JavaScript, https://js.arcgis.com
For more information about the view-hittest sample, read the original sample description at developers.arcgis.com.
https://developers.arcgis.com/javascript/latest/view-hittest/index.html
-->
<title>Highlight features with hover events - 4.11</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.11/esri/css/main.css">
<link rel="stylesheet" href="https://js.arcgis.com/4.11/dijit/themes/claro/claro.css">
<script src="https://js.arcgis.com/4.11/"></script>
<script>
var dialog, dRenderer;
require([
"esri/core/watchUtils",
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/renderers/UniqueValueRenderer",
"esri/symbols/SimpleLineSymbol",
"dojo/dom",
"dojo/dom-style",
"dijit/popup",
"dojo/domReady!"
], function (
watchUtils,
Map,
MapView,
FeatureLayer,
UniqueValueRenderer,
SimpleLineSymbol,
dom,
domStyle,
dijitPopup
) {
var layer = new FeatureLayer({
url: "https://services.arcgis.com/8Pc9XBTAsYuxx9Ny/arcgis/rest/services/BuildingFootprint2D_gdb/FeatureServer/0",
outFields: ["*"]
});
var map = new Map({
basemap: "dark-gray",
layers: [layer]
});
var view = new MapView({
container: "viewDiv",
map: map,
center: [-80.135073, 25.774479],
zoom: 16
});
function changeCursor(response) {
if (response.results.length > 0) {
document.getElementById("viewDiv").style.cursor = "pointer";
} else {
document.getElementById("viewDiv").style.cursor = "default";
}
}
function getGraphics(response) {
view.graphics.removeAll();
if (response.results.length > 0) {
var graphic = response.results[0].graphic;
graphic.symbol = {
type: "simple-fill",
style: "none",
outline: { // autocasts as new SimpleLineSymbol()
color: "orange",
width: 1
}
}
view.graphics.add(graphic);
}
}
view.when(function () {
view.whenLayerView(layer).then(function (lview) {
watchUtils.whenFalseOnce(lview, "updating", function () {
// Set up a click event handler and retrieve the screen x, y coordinates
view.on("pointer-move", function (evt) {
var screenPoint = {
x: evt.x,
y: evt.y
};
// the hitTest() checks to see if any graphics in the view
// intersect the given screen x, y coordinates
view.hitTest(screenPoint)
.then(function (response) {
changeCursor(response);
getGraphics(response);
});
});
});
});
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
Many thanks Robert. I really appreciate your help. I'll take a look later today at adapting that working sample into my app.