<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Customize ColorSlider Histogram | Sample | ArcGIS Maps SDK for JavaScript</title>
<!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
<script type="module" src="https://js.arcgis.com/5.0/"></script>
<arcgis-map scale="577790" center="-117.8099, 34.0441">
<arcgis-zoom slot="top-left"></arcgis-zoom>
<calcite-card slot="top-right">
<h2>Median Household Income</h2>
This app allows you to explore median household incomes in the Los Angeles Area. The
slider contains two lines that indicate values of interest: the federal poverty level and
the low-income threshold for a family of four in Los Angeles.
<arcgis-slider-color-legacy precision="2"></arcgis-slider-color-legacy>
const [Map, FeatureLayer, colorRendererCreator, colorSymbology, histogram, Color, intl] =
"@arcgis/core/layers/FeatureLayer.js",
"@arcgis/core/smartMapping/renderers/color.js",
"@arcgis/core/smartMapping/symbology/color.js",
"@arcgis/core/smartMapping/statistics/histogram.js",
const colorSlider = document.querySelector("arcgis-slider-color-legacy");
await colorSlider.componentOnReady();
// listen to arcgisThumbChange and arcgisThumbDrag events
// update the layer's renderer to match the slider's color stops
colorSlider.addEventListener("arcgisThumbChange", updateRendererFromSlider);
colorSlider.addEventListener("arcgisThumbDrag", updateRendererFromSlider);
colorSlider.addEventListener("arcgisPropertyChange", updateRendererFromSlider);
const layer = new FeatureLayer({
id: "340a8efc331f4cd59fecbc4ab8e2a311",
definitionExpression: "MEDHINC_CY > 0",
const viewElement = document.querySelector("arcgis-map");
viewElement.map = new Map({
id: "3582b744bba84668b52a16b0b6942544",
// configure parameters for the color renderer generator
// the layer must be specified along with a field name
// or arcade expression. The basemap and other properties determine
// the appropriate default color scheme.
const redAndGreenScheme = colorSymbology.getSchemeByName({
basemap: viewElement.map.basemap,
theme: "above-and-below",
// flip the red and green scheme so green is on top
const moneyScheme = colorSymbology.flipColors(redAndGreenScheme);
theme: "above-and-below",
colorScheme: moneyScheme,
const rendererResult = await colorRendererCreator.createContinuousRenderer(colorParams);
// set the renderer to the layer and add it to the map
const vv = rendererResult.visualVariable;
layer.renderer = rendererResult.renderer;
const histogramResult = await histogram({
// create reference to histogram bar elements for updating
// their style as the user drags slider thumbs
const histogramConfig = {
barCreatedFunction: (index, element) => {
const bin = histogramResult.bins[index];
const midValue = (bin.maxValue - bin.minValue) / 2 + bin.minValue;
const color = getColorFromValue(colorSlider.stops, midValue);
element.setAttribute("fill", color.toHex());
bins: histogramResult.bins,
{ label: "HUD low income", value: 83500 },
{ label: "Fed poverty line", value: 25750 },
colorSlider.updateFromRendererResult(rendererResult, histogramResult);
colorSlider.histogramConfig = histogramConfig;
colorSlider.labelFormatFunction = (value) => {
return intl.formatNumber(value, {
currencyDisplay: "symbol",
maximumFractionDigits: 0,
minimumFractionDigits: 0,
function updateRendererFromSlider() {
const renderer = layer.renderer.clone();
const colorVariable = renderer.visualVariables[0].clone();
colorVariable.stops = colorSlider.stops;
renderer.visualVariables = [colorVariable];
layer.renderer = renderer;
bars.forEach((bar, index) => {
const bin = colorSlider.histogramConfig.bins[index];
const midValue = (bin.maxValue - bin.minValue) / 2 + bin.minValue;
const color = getColorFromValue(colorSlider.stops, midValue);
bar.setAttribute("fill", color.toHex());
// infers the color for a given value
// based on the stops from a ColorVariable
function getColorFromValue(stops, value) {
let maxStop = stops[stops.length - 1];
const minStopValue = minStop.value;
const maxStopValue = maxStop.value;
if (value < minStopValue) {
if (value > maxStopValue) {
const exactMatches = stops.filter((stop) => {
return stop.value === value;
if (exactMatches.length > 0) {
return exactMatches[0].color;
stops.forEach((stop, i) => {
if (!minStop && !maxStop && stop.value >= value) {
const weightedPosition = (value - minStop.value) / (maxStop.value - minStop.value);
return Color.blendColors(minStop.color, maxStop.color, weightedPosition);