<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Generate a class breaks visualization | Sample | ArcGIS Maps SDK for JavaScript</title>
<link rel="stylesheet" href="https://js.arcgis.com/5.0/esri/themes/light/main.css" />
<!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
<script type="module" src="https://js.arcgis.com/5.0/"></script>
<arcgis-map zoom="11" center="-122.3487846, 47.58907">
<arcgis-zoom slot="top-left"></arcgis-zoom>
<arcgis-legend slot="bottom-left"></arcgis-legend>
<arcgis-basemap-toggle slot="bottom-right"></arcgis-basemap-toggle>
<calcite-panel id="infoDiv" slot="top-right">
<calcite-block expanded="" label="info block">
<calcite-select id="field-select">
<calcite-option value="NOHS_CY" label="no high school diploma"
>no high school diploma</calcite-option
<calcite-option value="NOHS_CY" label="no high school diploma"
>no high school diploma</calcite-option
<calcite-option value="NO_COL_DEG" label="no college degree" selected=""
>no college degree</calcite-option
<calcite-option value="HSGRAD_CY" label="high school diploma"
>high school diploma</calcite-option
<calcite-option value="COL_DEG" label="college degree">college degree</calcite-option>
<calcite-select id="class-select">
<calcite-option value="equal-interval" selected="">Equal interval</calcite-option>
<calcite-option value="quantile">Quantile</calcite-option>
<calcite-option value="natural-breaks">Natual Breaks</calcite-option>
<calcite-option value="manual">Manual</calcite-option>
max="10"></calcite-input>
<arcgis-slider-classed-color-legacy slot="top-right"></arcgis-slider-classed-color-legacy>
const [Map, FeatureLayer, colorRendererCreator, histogram, reactiveUtils] =
"@arcgis/core/layers/FeatureLayer.js",
"@arcgis/core/smartMapping/renderers/color.js",
"@arcgis/core/smartMapping/statistics/histogram.js",
"@arcgis/core/core/reactiveUtils.js",
const classedColorSlider = document.querySelector("arcgis-slider-classed-color-legacy");
classedColorSlider.precision = 1;
const layer = new FeatureLayer({
title: "Puget Sound block groups",
url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Puget_Sound_BG_demographics/FeatureServer/0",
// autocast as esri/PopupTemplate
title: "Block Group {FID_Block_Group}",
minimumFractionDigits: 0,
maximumFractionDigits: 0,
label: "No high school diploma",
minimumFractionDigits: 0,
maximumFractionDigits: 0,
label: "High school dipolma",
minimumFractionDigits: 0,
maximumFractionDigits: 0,
label: "No college degree",
minimumFractionDigits: 0,
maximumFractionDigits: 0,
minimumFractionDigits: 0,
maximumFractionDigits: 0,
definitionExpression: "EDUCBASECY > 0",
// get the arcgis-map component element and set the map and initial camera
const viewElement = document.querySelector("arcgis-map");
viewElement.map = new Map({
// wait for the scene element to be ready
await viewElement.viewOnReady();
const toggleElement = document.querySelector("arcgis-basemap-toggle");
// generate rounded arcade expression when user
const getValueExpression = (field) => {
return "Round( ( $feature." + field + " / $feature.EDUCBASECY ) * 100, 1)";
const sliderPlacement = document.getElementById("sliderPlacement");
const generateRenderer = async () => {
const fieldLabel = fieldSelect.selectedOption.label;
// default to natural-breaks when manual is selected for classification method
const classificationMethod =
classSelect.value === "manual" ? "natural-breaks" : classSelect.selectedOption.value;
valueExpression: getValueExpression(fieldSelect.value),
classificationMethod: classificationMethod,
numClasses: parseInt(numClassesInput.value),
title: "% population with " + fieldLabel,
// generate the renderer and set it on the layer
const rendererResponse = await colorRendererCreator.createClassBreaksRenderer(params);
layer.renderer = rendererResponse.renderer;
if (!viewElement.map.layers.includes(layer)) {
viewElement.map.add(layer);
if (classSelect.value === "manual") {
// if manual is selected, then add or update
// a classed color slider to allow the user to
// construct manual class breaks
classedColorSlider.style.display = "block";
updateColorSlider(rendererResponse);
classedColorSlider.style.display = "none";
// if manual classification method is selected, then create
// a classed color slider to allow user to manually modify
// the class breaks starting with the generated renderer
const updateColorSlider = async (rendererResult) => {
const histogramResult = await histogram({
valueExpression: getValueExpression(fieldSelect.value),
classedColorSlider.updateFromRendererResult(rendererResult, histogramResult);
// update the renderer based on the user's input
const changeEventHandler = async () => {
const renderer = layer.renderer.clone();
const updateClassBreakInfos = await classedColorSlider.updateClassBreakInfos(
renderer.classBreakInfos,
renderer.classBreakInfos = updateClassBreakInfos;
layer.renderer = renderer;
let abortController = null;
toggleElement.addEventListener("arcgisPropertyChange", async (event) => {
if (event.detail.name === "activeBasemap") {
abortController?.abort();
const { signal } = (abortController = new AbortController());
await reactiveUtils.whenOnce(() => !viewElement.updating, { signal });
if (error.name === "AbortError") {
throw error; // rethrow other errors
classedColorSlider.addEventListener("arcgisThumbChange", changeEventHandler);
classedColorSlider.addEventListener("arcgisThumbDrag", changeEventHandler);
// generate a new renderer each time the user changes an input parameter
const fieldSelect = document.getElementById("field-select");
fieldSelect.addEventListener("calciteSelectChange", generateRenderer);
const classSelect = document.getElementById("class-select");
classSelect.addEventListener("calciteSelectChange", generateRenderer);
const numClassesInput = document.getElementById("num-classes");
numClassesInput.addEventListener("calciteInputChange", generateRenderer);
await reactiveUtils.whenOnce(() => !viewElement.updating);