> For the complete documentation index, see [llms.txt](https://docs.mapbox.com/mapbox-gl-js/ja/llms.txt)

# Control symbol scaling with setScaleFactor

This example demonstrates how to use [`setScaleFactor`](https://docs.mapbox.com/mapbox-gl-js/ja/api/map/#map#setscalefactor) to dynamically scale symbol layers on the map. The example displays rally race waypoints with icons and text labels.

The control panel allows you to:

-   **Scale Factor**: Adjusts the global scale factor for all symbol layers using `map.setScaleFactor()`.
-   **Icon Size Scale Range**: Sets the minimum and maximum scaling limits for icons using the `icon-size-scale-range` layout property.
-   **Text Size Scale Range**: Sets the minimum and maximum scaling limits for text using the `text-size-scale-range` layout property.

In the example, you can experiment with different scale factor values and scale ranges to see how they affect the appearance of the symbols on the map. "Icon Size Scale Range" and "Text Size Scale Range" allow you to control the minimum and maximum scaling limits for icons and text of the custom layer, respectively, providing flexibility in how symbols are displayed at different scale levels. For example, if you set `icon-size-scale-range` to `[1, 1]`, the icons will not scale regardless of the scale factor value.

> Example code:

**JavaScript**

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Control symbol scaling with setScaleFactor</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v3.29.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v3.29.0/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<style>
    .map-overlay {
        font:
            12px/20px 'Helvetica Neue',
            Arial,
            Helvetica,
            sans-serif;
        position: absolute;
        width: 220px;
        top: 0;
        left: 0;
        padding: 10px;
    }

    .map-overlay .map-overlay-inner {
        background-color: #fff;
        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
        border-radius: 3px;
        padding: 10px;
        margin-bottom: 10px;
    }

    .map-overlay-inner fieldset {
        border: none;
        padding: 0;
        margin: 0 0 10px 0;
    }

    .map-overlay-inner label {
        display: block;
        font-weight: bold;
        margin-bottom: 5px;
    }

    .map-overlay-inner input[type='range'] {
        width: 100%;
        cursor: ew-resize;
    }

    .map-overlay-inner .range-value {
        font-size: 11px;
        color: #666;
        margin-top: 2px;
    }

    .map-overlay-inner .dual-range {
        display: flex;
        gap: 10px;
    }

    .map-overlay-inner .dual-range > div {
        flex: 1;
    }

    .map-overlay-inner .dual-range label {
        font-weight: normal;
        font-size: 11px;
    }
</style>

<div id="map"></div>

<div class="map-overlay top">
    <div class="map-overlay-inner">
        <fieldset>
            <label>Scale Factor: <span id="scale-factor-value">1.0</span></label>
            <input id="scale-factor" type="range" min="0.5" max="3" step="0.1" value="1">
        </fieldset>
        <fieldset>
            <label>Icon Size Scale Range</label>
            <div class="dual-range">
                <div>
                    <label>Min: <span id="icon-min-value">0.8</span></label>
                    <input id="icon-size-min" type="range" min="0.1" max="5" step="0.1" value="0.8">
                </div>
                <div>
                    <label>Max: <span id="icon-max-value">2.0</span></label>
                    <input id="icon-size-max" type="range" min="0.1" max="5" step="0.1" value="2">
                </div>
            </div>
        </fieldset>
        <fieldset>
            <label>Text Size Scale Range</label>
            <div class="dual-range">
                <div>
                    <label>Min: <span id="text-min-value">0.8</span></label>
                    <input id="text-size-min" type="range" min="0.1" max="5" step="0.1" value="0.8">
                </div>
                <div>
                    <label>Max: <span id="text-max-value">2.0</span></label>
                    <input id="text-size-max" type="range" min="0.1" max="5" step="0.1" value="2">
                </div>
            </div>
        </fieldset>
    </div>
</div>

<script>
    // Rally Finland waypoints - a fictional stage route around Jyväskylä
    const rallyWaypoints = {
        type: 'FeatureCollection',
        features: [
            {
                type: 'Feature',
                properties: { name: 'Start', order: 1 },
                geometry: { type: 'Point', coordinates: [25.7473, 62.2426] }
            },
            {
                type: 'Feature',
                properties: { name: '01', order: 2 },
                geometry: { type: 'Point', coordinates: [25.7821, 62.2589] }
            },
            {
                type: 'Feature',
                properties: { name: '02', order: 3 },
                geometry: { type: 'Point', coordinates: [25.8234, 62.2712] }
            },
            {
                type: 'Feature',
                properties: { name: '03', order: 4 },
                geometry: { type: 'Point', coordinates: [25.8612, 62.2534] }
            },
            {
                type: 'Feature',
                properties: { name: '04', order: 5 },
                geometry: { type: 'Point', coordinates: [25.8923, 62.2321] }
            },
            {
                type: 'Feature',
                properties: { name: 'Finish', order: 6 },
                geometry: { type: 'Point', coordinates: [25.9245, 62.2198] }
            }
        ]
    };

    const map = new mapboxgl.Map({
        // TO MAKE THE MAP APPEAR YOU MUST
        // ADD YOUR ACCESS TOKEN FROM
        // https://account.mapbox.com
        accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN',
        container: 'map',
        style: 'mapbox://styles/gl-js-team/cmleyrmcy002f01qthcccbolv',
        center: [25.83, 62.245],
        zoom: 11.5
    });

    map.on('style.load', () => {
        map.addSource('rally-waypoints', {
            type: 'geojson',
            data: rallyWaypoints
        });

        map.addLayer({
            id: 'rally-waypoints',
            type: 'symbol',
            source: 'rally-waypoints',
            layout: {
                'icon-image': 'bicycle',
                'icon-size': 1.5,
                'icon-size-scale-range': [0.8, 2],
                'text-field': ['get', 'name'],
                'text-font': ['DIN Pro Medium', 'Arial Unicode MS Regular'],
                'text-size': 14,
                'text-size-scale-range': [0.8, 2],
                'text-offset': [0, 1.2],
                'text-anchor': 'top',
                'icon-allow-overlap': true,
                'text-allow-overlap': true
            },
            paint: {
                'icon-color': '#e74c3c',
                'text-color': '#2c3e50',
                'text-halo-color': '#ffffff',
                'text-halo-width': 1
            }
        });
    });

    // Scale Factor slider
    const scaleFactorSlider = document.getElementById('scale-factor');
    const scaleFactorValue = document.getElementById('scale-factor-value');

    scaleFactorSlider.addEventListener('input', (e) => {
        const value = parseFloat(e.target.value);
        scaleFactorValue.textContent = value.toFixed(1);
        map.setScaleFactor(value);
    });

    // Icon Size Scale Range sliders
    const iconMinSlider = document.getElementById('icon-size-min');
    const iconMaxSlider = document.getElementById('icon-size-max');
    const iconMinValue = document.getElementById('icon-min-value');
    const iconMaxValue = document.getElementById('icon-max-value');

    function updateIconSizeScaleRange() {
        const min = parseFloat(iconMinSlider.value);
        const max = parseFloat(iconMaxSlider.value);
        iconMinValue.textContent = min.toFixed(1);
        iconMaxValue.textContent = max.toFixed(1);
        map.setLayoutProperty('rally-waypoints', 'icon-size-scale-range', [
            min,
            max
        ]);
    }

    iconMinSlider.addEventListener('input', updateIconSizeScaleRange);
    iconMaxSlider.addEventListener('input', updateIconSizeScaleRange);

    // Text Size Scale Range sliders
    const textMinSlider = document.getElementById('text-size-min');
    const textMaxSlider = document.getElementById('text-size-max');
    const textMinValue = document.getElementById('text-min-value');
    const textMaxValue = document.getElementById('text-max-value');

    function updateTextSizeScaleRange() {
        const min = parseFloat(textMinSlider.value);
        const max = parseFloat(textMaxSlider.value);
        textMinValue.textContent = min.toFixed(1);
        textMaxValue.textContent = max.toFixed(1);
        map.setLayoutProperty('rally-waypoints', 'text-size-scale-range', [
            min,
            max
        ]);
    }

    textMinSlider.addEventListener('input', updateTextSizeScaleRange);
    textMaxSlider.addEventListener('input', updateTextSizeScaleRange);
</script>

</body>
</html>
```

**React**

```jsx
import React, { useState, useEffect, useRef } from 'react';
import * as mapboxgl from 'mapbox-gl/esm';

import 'mapbox-gl/dist/mapbox-gl.css';

// Rally Finland waypoints - a fictional stage route around Jyväskylä
const rallyWaypoints = {
  type: 'FeatureCollection',
  features: [
    {
      type: 'Feature',
      properties: { name: 'Start', order: 1 },
      geometry: { type: 'Point', coordinates: [25.7473, 62.2426] }
    },
    {
      type: 'Feature',
      properties: { name: '01', order: 2 },
      geometry: { type: 'Point', coordinates: [25.7821, 62.2589] }
    },
    {
      type: 'Feature',
      properties: { name: '02', order: 3 },
      geometry: { type: 'Point', coordinates: [25.8234, 62.2712] }
    },
    {
      type: 'Feature',
      properties: { name: '03', order: 4 },
      geometry: { type: 'Point', coordinates: [25.8612, 62.2534] }
    },
    {
      type: 'Feature',
      properties: { name: '04', order: 5 },
      geometry: { type: 'Point', coordinates: [25.8923, 62.2321] }
    },
    {
      type: 'Feature',
      properties: { name: 'Finish', order: 6 },
      geometry: { type: 'Point', coordinates: [25.9245, 62.2198] }
    }
  ]
};

const MapboxExample = () => {
  const mapContainerRef = useRef();
  const mapRef = useRef();

  const [scaleFactor, setScaleFactor] = useState(1);
  const [iconSizeMin, setIconSizeMin] = useState(0.8);
  const [iconSizeMax, setIconSizeMax] = useState(2);
  const [textSizeMin, setTextSizeMin] = useState(0.8);
  const [textSizeMax, setTextSizeMax] = useState(2);
  const [styleLoaded, setStyleLoaded] = useState(false);

  useEffect(() => {
    mapRef.current = new mapboxgl.Map({
      // TO MAKE THE MAP APPEAR YOU MUST
      // ADD YOUR ACCESS TOKEN FROM
      // https://account.mapbox.com
      accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN',
      container: mapContainerRef.current,
      style: 'mapbox://styles/gl-js-team/cmleyrmcy002f01qthcccbolv',
      center: [25.83, 62.245],
      zoom: 11.5
    });

    mapRef.current.on('style.load', () => {
      setStyleLoaded(true);

      mapRef.current.addSource('rally-waypoints', {
        type: 'geojson',
        data: rallyWaypoints
      });

      mapRef.current.addLayer({
        id: 'rally-waypoints',
        type: 'symbol',
        source: 'rally-waypoints',
        layout: {
          'icon-image': 'bicycle',
          'icon-size': 1.5,
          'icon-size-scale-range': [0.8, 2],
          'text-field': ['get', 'name'],
          'text-font': ['DIN Pro Medium', 'Arial Unicode MS Regular'],
          'text-size': 14,
          'text-size-scale-range': [0.8, 2],
          'text-offset': [0, 1.2],
          'text-anchor': 'top',
          'icon-allow-overlap': true,
          'text-allow-overlap': true
        },
        paint: {
          'icon-color': '#e74c3c',
          'text-color': '#2c3e50',
          'text-halo-color': '#ffffff',
          'text-halo-width': 1
        }
      });
    });

    return () => mapRef.current.remove();
  }, []);

  useEffect(() => {
    if (!styleLoaded) return;
    mapRef.current.setScaleFactor(scaleFactor);
  }, [scaleFactor, styleLoaded]);

  useEffect(() => {
    if (!styleLoaded) return;
    mapRef.current.setLayoutProperty(
      'rally-waypoints',
      'icon-size-scale-range',
      [iconSizeMin, iconSizeMax]
    );
  }, [iconSizeMin, iconSizeMax, styleLoaded]);

  useEffect(() => {
    if (!styleLoaded) return;
    mapRef.current.setLayoutProperty(
      'rally-waypoints',
      'text-size-scale-range',
      [textSizeMin, textSizeMax]
    );
  }, [textSizeMin, textSizeMax, styleLoaded]);

  const mapOverlayStyle = {
    font: "12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif",
    position: 'absolute',
    width: '220px',
    top: '0',
    left: '0',
    padding: '10px'
  };

  const mapOverlayInnerStyle = {
    backgroundColor: '#fff',
    boxShadow: '0 1px 2px rgba(0, 0, 0, 0.1)',
    borderRadius: '3px',
    padding: '10px',
    marginBottom: '10px'
  };

  const fieldsetStyle = {
    border: 'none',
    padding: '0',
    margin: '0 0 10px 0'
  };

  const labelStyle = {
    display: 'block',
    fontWeight: 'bold',
    marginBottom: '5px'
  };

  const inputStyle = {
    width: '100%',
    cursor: 'ew-resize'
  };

  const dualRangeStyle = {
    display: 'flex',
    gap: '10px'
  };

  const dualRangeItemStyle = {
    flex: 1
  };

  const smallLabelStyle = {
    fontWeight: 'normal',
    fontSize: '11px',
    display: 'block',
    marginBottom: '3px'
  };

  return (
    <>
      <div ref={mapContainerRef} style={{ height: '100%' }} />
      <div className="map-overlay" style={mapOverlayStyle}>
        <div className="map-overlay-inner" style={mapOverlayInnerStyle}>
          <fieldset style={fieldsetStyle}>
            <label style={labelStyle}>
              Scale Factor: {scaleFactor.toFixed(1)}
            </label>
            <input
              type="range"
              min="0.5"
              max="3"
              step="0.1"
              value={scaleFactor}
              onChange={(e) => setScaleFactor(parseFloat(e.target.value))}
              style={inputStyle}
            />
          </fieldset>
          <fieldset style={fieldsetStyle}>
            <span style={labelStyle}>Icon Size Scale Range</span>
            <div style={dualRangeStyle}>
              <div style={dualRangeItemStyle}>
                <label style={smallLabelStyle}>
                  Min: {iconSizeMin.toFixed(1)}
                </label>
                <input
                  type="range"
                  min="0.1"
                  max="5"
                  step="0.1"
                  value={iconSizeMin}
                  onChange={(e) => setIconSizeMin(parseFloat(e.target.value))}
                  style={inputStyle}
                />
              </div>
              <div style={dualRangeItemStyle}>
                <label style={smallLabelStyle}>
                  Max: {iconSizeMax.toFixed(1)}
                </label>
                <input
                  type="range"
                  min="0.1"
                  max="5"
                  step="0.1"
                  value={iconSizeMax}
                  onChange={(e) => setIconSizeMax(parseFloat(e.target.value))}
                  style={inputStyle}
                />
              </div>
            </div>
          </fieldset>
          <fieldset style={fieldsetStyle}>
            <span style={labelStyle}>Text Size Scale Range</span>
            <div style={dualRangeStyle}>
              <div style={dualRangeItemStyle}>
                <label style={smallLabelStyle}>
                  Min: {textSizeMin.toFixed(1)}
                </label>
                <input
                  type="range"
                  min="0.1"
                  max="5"
                  step="0.1"
                  value={textSizeMin}
                  onChange={(e) => setTextSizeMin(parseFloat(e.target.value))}
                  style={inputStyle}
                />
              </div>
              <div style={dualRangeItemStyle}>
                <label style={smallLabelStyle}>
                  Max: {textSizeMax.toFixed(1)}
                </label>
                <input
                  type="range"
                  min="0.1"
                  max="5"
                  step="0.1"
                  value={textSizeMax}
                  onChange={(e) => setTextSizeMax(parseFloat(e.target.value))}
                  style={inputStyle}
                />
              </div>
            </div>
          </fieldset>
        </div>
      </div>
    </>
  );
};

export default MapboxExample;
```