How to Render Class Breaks Colors with Dynamic Values?

485
2
11-05-2019 10:07 PM
victhomas
New Contributor III

Hello All,

So far, I've successfully rendered class breaks colors on the client side with various help from the API resource page.  While this is great to start off, but I do see a problem.  Currently the Min. and Max value for each class is hardcoded in from the feature layer REST url, and that is not good if you have a feature layer that is updating daily or weekly with new values in the attribute.  Is there any way or methods that would allow us to capture the feature layer attributes dynamically through code and put it in a variable?  So then it would be really easy to put those variables in place of the Min. and Max value for each class break. Below is the code that I have so far with the hardcoded Min. and Max value, thank you for your help. 

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no"/>
<title>Class Break Color Render</title>

<link
rel="stylesheet"
href="https://js.arcgis.com/4.13/esri/themes/light/main.css"
/>

<script src="https://js.arcgis.com/4.13/"></script>

<style>
html,
body,
#viewDiv
{
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>


<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/widgets/Legend"
], function(Map, MapView, FeatureLayer, Legend) {

const lightestColor = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: "#fffcd4",
style: "solid",
outline: {
width: 1,
color: [0, 0, 0]
}
};

const lightColor = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: "#b1cdc2",
style: "solid",
outline: {
width: 1,
color: [0, 0, 0]
}
};

const mediumColor = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: "#38627a",
style: "solid",
outline: {
width: 1,
color: [0, 0, 0]
}
};

const darkColor = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: "#0d2644",
style: "solid",
outline: {
width: 1,
color: [0, 0, 0]
}
};


var minNumber = 100000;
var maxNumber = 7000000;

const renderer = {
type: "class-breaks",
field: "OWNER_OCC",
legendOptions: {
title: "Number of Home Owner"
},
defaultSymbol: {
type: "simple-fill",
color: "black",
style: "cross",
outline: {
width: 0.5,
color: [50, 50, 50, 0.6]
}
},
defaultLabel: "No Data Available",
classBreakInfos: [
{
minValue: minNumber,
maxValue: 1000000,
symbol: lightestColor,
label: "< 1,000,000"
},
{
minValue: 1000001,
maxValue: 3000000,
symbol: lightColor,
label: "1,000,001 to 3,000,000"
},
{
minValue: 3000001,
maxValue: 5000000,
symbol: mediumColor,
label: "3,000,001 to 5,000,000"
},
{
minValue: 5000001,
maxValue: maxNumber,
symbol: darkColor,
label: "5,000,001 to " + maxNumber.toLocaleString()
}
]
};

const fLayer = new FeatureLayer({
url:
"https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3",
title: "U.S. Homeowner Number",
renderer: renderer,
popupTemplate: {
title: "Owner Occupancy for {STATE_NAME}",
content:
"{OWNER_OCC} are home owner. " +
"{RENTER_OCC} are home renter"
}

});

const map = new Map({
basemap: "gray-vector",
layers: [fLayer]
});

const view = new MapView({
container: "viewDiv",
map: map,
center: [-98.34, 40.28],
zoom: 4
});

const legend = new Legend({
view: view
});

view.ui.add(legend, "bottom-right");
});
</script>

</head>

<body>
<div id="viewDiv"></div>
</body>
</html>
0 Kudos
2 Replies
Noah-Sager
Esri Regular Contributor

Could you query the FeatureLayer and get all the values for the field of interest? Then put the results in an array, sort by value, and take the lowest value as the minValue, and the highest value as the maxValue?

https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3/query?where=1%3D1&tex...

0 Kudos
victhomas
New Contributor III

Thanks Noah for your response.  

Below is the code that I come up with esri/request. Instead of class breaks, I'm changing it to unique-value to be easier.   It pulled out the data values correctly(see console.log). But the layer will not render the colors because of the renderer: property in the new Featurelayer class.  The renderer property doesn't see the needed value from the esri/request, because inside of the esri/request it a promise().then and it doesn't return the value right away.  So any idea how to resolve this, or any help would welcome.  Thanks.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no"/>
<title>Map Color Render</title>

<link
rel="stylesheet"
href="https://js.arcgis.com/4.13/esri/themes/light/main.css"
/>

<script src="https://js.arcgis.com/4.13/"></script>

<style>
html,
body,
#viewDiv
{
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>


<script>

var someArray = [];
var tinyNum;
var smallNum;
var mediumNum;
var largeNum;
var behemothNum;


require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/widgets/Legend",
'esri/request'
], function(Map, MapView, FeatureLayer, Legend,esriRequest) {


let serviceURL = "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3";
let queryOptions = {
responseType: "json",
query:{
f: "json",
where: "OBJECTID IN (7,6,32,34,16)",
outFields: "*",
returnGeometry: false
}
}
esriRequest(serviceURL+"/query", queryOptions).then(response =>{

for(let i = 0; i< 5; i++)
{
someArray.push(response.data.features[i].attributes.POP2000);
//someArray.sort();
console.log(response.data.features[i].attributes.STATE_NAME +" Pop: "+response.data.features[i].attributes.POP2000);
}
someArray.sort((n1,n2) => n1-n2);
tinyNum = someArray[0];
smallNum = someArray[1];
mediumNum = someArray[2];
largeNum = someArray[3];
behemothNum = someArray[4];
for(let i =0; i< someArray.length; i++)
{
console.log(i+1+": "+someArray[i]);
}

});


const lightestColor = {
type: "simple-fill",
color: "#fffcd4",
style: "solid",
outline: {
width: 1,
color: [255, 255, 255]
}
};

const lightColor = {
type: "simple-fill",
color: "#b1cdc2",
style: "solid",
outline: {
width: 1,
color: [255, 255, 255]
}
};

const mediumColor = {
type: "simple-fill",
color: "#38627a",
style: "solid",
outline: {
width: 1,
color: [255, 255, 255]
}
};

const darkColor = {
type: "simple-fill",
color: "#0d2644",
style: "solid",
outline: {
width: 1,
color: [255, 255, 255]
}
};
const darkestColor = {
type: "simple-fill",
color: "#010812",
style: "solid",
outline: {
width: 1,
color: [255, 255, 255]
}
};

renderer = {
type: "unique-value",
field: "obligated_amt",
defaultSymbol: {
type: "simple-fill",
color: "black",
style: "cross",
outline: {
width: 0.5,
color: [50, 50, 50, 0.6]
}
},
defaultLabel: "No Data Available",
uniqueValueInfos:[
{
value: tinyNum,
symbol: lightestColor
},
{
value: smallNum,
symbol: lightColor
},
{
value: mediumNum,
symbol: mediumColor
},
{
value: largeNum,
symbol: darkColor
},
{
value: behemothNum,
symbol: darkestColor
},
]
};

const fLayer = new FeatureLayer({
url:"https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3",
outFields: ["*"],
renderer: renderer
});

const map = new Map({
basemap: "gray-vector",
layers: [fLayer]
});

const view = new MapView({
container: "viewDiv",
map: map,
center: [-98.34, 40.28],
zoom: 4
});


});


</script>

</head>

<body>
<div id="viewDiv"></div>
</body>
</html>‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos