---
product: "AG Charts"
title: "Colour Scale"
description: "Use the Vue Colour Scale to map numeric data values to colours. Configure continuous gradients and discrete bins. Customise the Gradient Legend."
enterprise: true
framework: vue
version: "14.2.0"
related:
    - title: "Cross Lines"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/axes-cross-lines/"
    - title: "Legend"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/legend/"
    - title: "Formatters"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/formatters/"
    - title: "Stylers"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/stylers/"
    - title: "Series Bars"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/bars/"
    - title: "Series Fills"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/fills/"
    - title: "Series Labels"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/series-labels/"
    - title: "Series Markers"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/markers/"
    - title: "Style Segments"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/style-segments/"
    - title: "Annotations"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/annotations/"
    - title: "Background Regions"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/background-regions/"
    - title: "Error Bars"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/error-bars/"
llms: "https://www.ag-grid.com/charts/archive/14.2.0/llms.txt"
---

# Colour Scale

A Colour Scale maps numeric data values to colours, adding a visual dimension to the chart. This is used by series types that support a `colorKey`, such as [Heatmap](https://www.ag-grid.com/charts/archive/14.2.0/vue/heatmap-series/), [Treemap](https://www.ag-grid.com/charts/archive/14.2.0/vue/treemap-series/), [Sunburst](https://www.ag-grid.com/charts/archive/14.2.0/vue/sunburst-series/), and [Scatter](https://www.ag-grid.com/charts/archive/14.2.0/vue/scatter-series/) series.

## Simple Colour Scale

To use a Colour Scale, set the series `colorKey` property to a data field containing numeric values.

#### Simple Colour Scale

```ts
import { createApp, defineComponent, ref } from "vue";
import { AgCharts } from "ag-charts-vue3";
import type { AgChartOptions } from "ag-charts-types";
import {
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
  ModuleRegistry,
} from "ag-charts-enterprise";
import { getData } from "./data";

ModuleRegistry.registerModules([
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
]);

const ChartExample = defineComponent({
  template: `
    <ag-charts
      :options="options"
    />
  `,
  components: {
    "ag-charts": AgCharts,
  },
  setup(props) {
    const options = ref<AgCartesianChartOptions>({
      data: getData(),
      title: {
        text: "Service Quality Ratings",
      },
      subtitle: {
        text: "NPS Score (0–10)",
      },
      series: [
        {
          type: "heatmap",
          xKey: "segment",
          xName: "Segment",
          yKey: "service",
          yName: "Service",
          colorKey: "score",
          colorName: "Score",
          colorScale: {
            domain: [0, 10],
          },
        },
      ],
    });

    return {
      options,
    };
  },
});

createApp(ChartExample).mount("#app");
```

[Live example: Simple Colour Scale](https://www.ag-grid.com/charts/archive/14.2.0/vue3/colour-scale/examples/simple-colour-scale/)

```js
{
    series: [
        {
            type: 'heatmap',
            xKey: 'segment',
            yKey: 'service',
            colorKey: 'score',
            colorName: 'Score',
        },
    ],
}
```

In this configuration:

- `colorKey` is set to 'score', which supplies numeric values for the Colour Scale.
- `colorName` sets the title that appears next to the colour value in tooltips.
- The default colour scheme is applied as a continuous gradient across the data range.
- A [Gradient Legend](https://www.ag-grid.com/charts/archive/14.2.0/vue/colour-scale/#gradient-legend) is displayed, showing how colours map to values.

Colour Scales are supported on [Heatmap](https://www.ag-grid.com/charts/archive/14.2.0/vue/heatmap-series/), [Treemap](https://www.ag-grid.com/charts/archive/14.2.0/vue/treemap-series/) and [Sunburst](https://www.ag-grid.com/charts/archive/14.2.0/vue/sunburst-series/), [Scatter](https://www.ag-grid.com/charts/archive/14.2.0/vue/scatter-series/) and [Bubble](https://www.ag-grid.com/charts/archive/14.2.0/vue/bubble-series/) as well as all [Map](https://www.ag-grid.com/charts/archive/14.2.0/vue/maps/) series types.

## Domain

By default, the Colour Scale domain is derived from the data. Use `colorScale.domain` to set a fixed domain.

#### Domain

```ts
import { createApp, defineComponent, ref } from "vue";
import { AgCharts } from "ag-charts-vue3";
import type { AgChartOptions } from "ag-charts-types";
import {
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
  ModuleRegistry,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";

ModuleRegistry.registerModules([
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
]);

const ChartExample = defineComponent({
  template: `
    <div class="example-controls">
      <div class="controls-row">
        Domain:
        <div class="button-group" role="group" aria-label="Domain">
          <input type="radio" id="colour-scale-domain-auto" name="colour-scale-domain" value="auto" checked="" v-on:change="domainChange($event)">
            <label for="colour-scale-domain-auto">Auto</label>
            <input type="radio" id="colour-scale-domain-fixed" name="colour-scale-domain" value="fixed" v-on:change="domainChange($event)">
              <label for="colour-scale-domain-fixed">Fixed [1, 10]</label>
            </div>
          </div>
        </div>
        <ag-charts
          :options="options"
        />
  `,
  components: {
    "ag-charts": AgCharts,
  },
  setup(props) {
    const options = ref<AgCartesianChartOptions>({
      data: getData(),
      title: {
        text: "Service Quality Ratings",
      },
      subtitle: {
        text: "Average Rating",
      },
      series: [
        {
          type: "heatmap",
          xKey: "segment",
          xName: "Segment",
          yKey: "service",
          yName: "Service",
          colorKey: "score",
          colorName: "Score",
          colorScale: {
            fills: [
              { color: "tomato" },
              { color: "gold" },
              { color: "seagreen" },
            ],
          },
        },
      ],
      gradientLegend: {
        gradient: { preferredLength: 200 },
        scale: { interval: { step: 1 } },
      },
    });

    const domainChange = (event) => {
      const optionsCopy = clone(options.value);

      const type = event.target.value;
      const series = optionsCopy.series[0];
      series.colorScale = {
        ...series.colorScale,
        domain: type === "fixed" ? [1, 10] : undefined,
      };

      options.value = optionsCopy;
    };

    return {
      options,
      domainChange,
    };
  },
});

createApp(ChartExample).mount("#app");
```

[Live example: Domain](https://www.ag-grid.com/charts/archive/14.2.0/vue3/colour-scale/examples/fixed-domain/)

```js
{
    series: [
        {
            type: 'heatmap',
            xKey: 'segment',
            yKey: 'service',
            colorKey: 'score',
            colorScale: {
                fills: [{ color: 'tomato' }, { color: 'gold' }, { color: 'seagreen' }],
                domain: [1, 10],
            },
        },
    ],
}
```

In this example:

- Use the buttons to toggle `domain` between `[1, 10]` or the default of approximately 4 to 8.
- Using [Custom Colours](https://www.ag-grid.com/charts/archive/14.2.0/vue/colour-scale/#custom-colours), the lowest values are `tomato`, the middle values are `gold`, and the highest values are `seagreen`.
  - With the fixed domain, the lowest value is 1 which is not in the data, so no cells appear as `tomato`.
  - With the default domain, the lowest value in the domain is 4 and appears as `tomato`.
- Values outside a fixed domain are clamped. In this example of `[1, 10]`, a value of 0 would receive the same colour as 1.

## Discrete Mode

Use `colorScale.mode` to switch between a continuous gradient and discrete colour bins.

#### Discrete Mode

```ts
import { createApp, defineComponent, ref } from "vue";
import { AgCharts } from "ag-charts-vue3";
import type { AgChartOptions } from "ag-charts-types";
import {
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
  LegendModule,
  ModuleRegistry,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";

ModuleRegistry.registerModules([
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
  LegendModule,
]);

const ChartExample = defineComponent({
  template: `
    <div class="example-controls">
      <div class="controls-row">
        <span>Mode:</span>
        <div class="button-group" role="group" aria-label="Mode">
          <input type="radio" id="mode-discrete" name="mode" value="discrete" checked="" v-on:change="modeChange($event)">
            <label for="mode-discrete">Discrete</label>
            <input type="radio" id="mode-continuous" name="mode" value="continuous" v-on:change="modeChange($event)">
              <label for="mode-continuous">Continuous</label>
            </div>
          </div>
        </div>
        <ag-charts
          :options="options"
        />
  `,
  components: {
    "ag-charts": AgCharts,
  },
  setup(props) {
    const options = ref<AgCartesianChartOptions>({
      data: getData(),
      title: {
        text: "Service Quality Ratings",
      },
      subtitle: {
        text: "NPS Score (0–10)",
      },
      series: [
        {
          type: "heatmap",
          xKey: "segment",
          xName: "Segment",
          yKey: "service",
          yName: "Service",
          colorKey: "score",
          colorName: "Score",
          colorScale: {
            mode: "discrete",
            domain: [0, 10],
            fills: [
              { color: "tomato", stop: 7 },
              { color: "gold", stop: 9 },
              { color: "seagreen" },
            ],
          },
        },
      ],
      legend: {
        enabled: true,
      },
      gradientLegend: {
        enabled: false,
      },
    });

    const modeChange = (event) => {
      const optionsCopy = clone(options.value);

      const mode = event.target.value;
      const discrete = mode === "discrete";
      const series = optionsCopy.series[0];
      series.colorScale = { ...series.colorScale, mode };
      optionsCopy.legend = { enabled: discrete };
      optionsCopy.gradientLegend = { enabled: !discrete };

      options.value = optionsCopy;
    };

    return {
      options,
      modeChange,
    };
  },
});

createApp(ChartExample).mount("#app");
```

[Live example: Discrete Mode](https://www.ag-grid.com/charts/archive/14.2.0/vue3/colour-scale/examples/discrete-mode/)

```js
{
    series: [
        {
            type: 'heatmap',
            xKey: 'segment',
            yKey: 'service',
            colorKey: 'score',
            colorScale: {
                mode: 'discrete',
                domain: [0, 10],
                fills: [{ color: 'tomato', stop: 7 }, { color: 'gold', stop: 9 }, { color: 'seagreen' }],
            },
        },
    ],
}
```

In this example:

- In discrete mode, each data value receives a solid colour rather than a blended gradient.
- The number of bins is determined by the number of colours in the Colour Scale.
- Use [Colour Stops](https://www.ag-grid.com/charts/archive/14.2.0/vue/colour-scale/#colour-stops) to control the bin boundaries and the colours used.
- Discrete mode can use the [Gradient Legend](https://www.ag-grid.com/charts/archive/14.2.0/vue/colour-scale/#gradient-legend) if desired. See [Legends](https://www.ag-grid.com/charts/archive/14.2.0/vue/colour-scale/#legends) for details.

## Custom Colours

Use `colorScale.fills` to provide custom colours. Each item in the array specifies a `color` and an optional `stop` and `name`.

#### Custom Colours

```ts
import { createApp, defineComponent, ref } from "vue";
import { AgCharts } from "ag-charts-vue3";
import type { AgChartOptions } from "ag-charts-types";
import {
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
  LegendModule,
  ModuleRegistry,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";

const equalFills = [
  { color: "tomato" },
  { color: "gold" },
  { color: "seagreen" },
];

const stopFills = [
  { color: "tomato", stop: 7 },
  { color: "gold", stop: 9 },
  { color: "seagreen" },
];

const namedFills = [
  { color: "tomato", name: "Detractor", stop: 7 },
  { color: "gold", name: "Passive", stop: 9 },
  { color: "seagreen", name: "Promoter" },
];

ModuleRegistry.registerModules([
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
  LegendModule,
]);

const ChartExample = defineComponent({
  template: `
    <div class="example-controls">
      <div class="controls-row">
        <span>Mode:</span>
        <div class="button-group" role="group" aria-label="Mode">
          <input type="radio" id="mode-continuous" name="colour-scale-mode" value="continuous" checked="" v-on:change="modeChange($event)">
            <label for="mode-continuous">Continuous</label>
            <input type="radio" id="mode-discrete" name="colour-scale-mode" value="discrete" v-on:change="modeChange($event)">
              <label for="mode-discrete">Discrete</label>
            </div>
            <span class="gap-left">Fills:</span>
            <div class="button-group" role="group" aria-label="Fills">
              <input type="radio" id="fills-equal" name="colour-scale-fills" value="equal" checked="" v-on:change="fillsChange($event)">
                <label for="fills-equal">Equal</label>
                <input type="radio" id="fills-stops" name="colour-scale-fills" value="stops" v-on:change="fillsChange($event)">
                  <label for="fills-stops">Stops</label>
                  <input type="radio" id="fills-named" name="colour-scale-fills" value="named" v-on:change="fillsChange($event)">
                    <label for="fills-named">Named Stops</label>
                  </div>
                </div>
              </div>
              <ag-charts
                :options="options"
              />
  `,
  components: {
    "ag-charts": AgCharts,
  },
  setup(props) {
    const options = ref<AgCartesianChartOptions>({
      data: getData(),
      title: {
        text: "Service Quality Ratings",
      },
      subtitle: {
        text: "NPS Score (0–10)",
      },
      series: [
        {
          type: "heatmap",
          xKey: "segment",
          xName: "Segment",
          yKey: "service",
          yName: "Service",
          colorKey: "score",
          colorName: "Score",
          colorScale: {
            fills: equalFills,
            domain: [0, 10],
          },
        },
      ],
      gradientLegend: {
        enabled: true,
        position: "right",
        gradient: {
          preferredLength: 200,
        },
      },
      legend: {
        enabled: false,
      },
    });

    const modeChange = (event) => {
      const optionsCopy = clone(options.value);

      const mode = event.target.value;
      const series = optionsCopy.series[0];
      const discrete = mode === "discrete";
      series.colorScale = { ...series.colorScale, mode };
      optionsCopy.gradientLegend = {
        ...optionsCopy.gradientLegend,
        enabled: !discrete,
      };
      optionsCopy.legend = { ...optionsCopy.legend, enabled: discrete };

      options.value = optionsCopy;
    };
    const fillsChange = (event) => {
      const optionsCopy = clone(options.value);

      const type = event.target.value;
      const series = optionsCopy.series[0];
      const fills =
        type === "named"
          ? namedFills
          : type === "stops"
            ? stopFills
            : equalFills;
      series.colorScale = { ...series.colorScale, fills };

      options.value = optionsCopy;
    };

    return {
      options,
      modeChange,
      fillsChange,
    };
  },
});

createApp(ChartExample).mount("#app");
```

[Live example: Custom Colours](https://www.ag-grid.com/charts/archive/14.2.0/vue3/colour-scale/examples/colour-stops/)

### Colours

Without `stop` values, colours are spaced equally across the data domain.

```js
{
    colorScale: {
        fills: [{ color: 'tomato' }, { color: 'gold' }, { color: 'seagreen' }],
    },
}
```

### Colour Stops

With `stop` values, each colour is positioned at an explicit point in the domain. The `fills` array must be sorted in ascending `stop` order. The first and last fills default to the data minimum and maximum if no `stop` is set.

```js
{
    colorScale: {
        fills: [{ color: 'tomato', stop: 7 }, { color: 'gold', stop: 9 }, { color: 'seagreen' }],
    },
}
```

In continuous mode, each stop positions its colour at that value, and colours blend smoothly between stops:

- 0 → 7 is solid `tomato`.
- 7 → 9 interpolates from `tomato` to `gold`.
- 9 → 10 interpolates from `gold` to `seagreen`.

In discrete mode, each stop instead marks the start of the next bin:

- 0–6 is solid `tomato`.
- 7–8 is solid `gold`.
- 9–10 is solid `seagreen`.

### Named Stops

With `name` values, descriptive labels are used in the legend and tooltips instead of numeric ranges.

```js
{
    colorScale: {
        fills: [
            { color: 'tomato', name: 'Detractor', stop: 7 },
            { color: 'gold', name: 'Passive', stop: 9 },
            { color: 'seagreen', name: 'Promoter' },
        ],
    },
}
```

### Missing Data

Set `colorScale.missingDataFill` to set the colour for a datum that has no value for the `colorKey`.

#### Missing Data

```ts
import { createApp, defineComponent, ref } from "vue";
import { AgCharts } from "ag-charts-vue3";
import type { AgChartOptions } from "ag-charts-types";
import {
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
  ModuleRegistry,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";

ModuleRegistry.registerModules([
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
]);

const ChartExample = defineComponent({
  template: `
    <div class="example-controls">
      <div class="controls-row">
        Missing Data Fill:
        <div class="button-group" role="group" aria-label="Missing Data Fill">
          <input type="radio" id="missing-data-fill-on" name="missing-data-fill" value="true" checked="" v-on:change="missingFillChange($event)">
            <label for="missing-data-fill-on">On</label>
            <input type="radio" id="missing-data-fill-off" name="missing-data-fill" value="false" v-on:change="missingFillChange($event)">
              <label for="missing-data-fill-off">Off</label>
            </div>
          </div>
        </div>
        <ag-charts
          :options="options"
        />
  `,
  components: {
    "ag-charts": AgCharts,
  },
  setup(props) {
    const options = ref<AgCartesianChartOptions>({
      data: getData(),
      title: {
        text: "Service Quality Ratings",
      },
      subtitle: {
        text: "NPS Score (0–10)",
      },
      series: [
        {
          type: "heatmap",
          xKey: "segment",
          xName: "Segment",
          yKey: "service",
          yName: "Service",
          colorKey: "score",
          colorName: "Score",
          colorScale: {
            domain: [0, 10],
            missingDataFill: "#e0e0e0",
          },
        },
      ],
    });

    const missingFillChange = (event) => {
      const optionsCopy = clone(options.value);

      const enabled = event.target.value === "true";
      const series = optionsCopy.series[0];
      series.colorScale = {
        ...series.colorScale,
        missingDataFill: enabled ? "#e0e0e0" : undefined,
      };

      options.value = optionsCopy;
    };

    return {
      options,
      missingFillChange,
    };
  },
});

createApp(ChartExample).mount("#app");
```

[Live example: Missing Data](https://www.ag-grid.com/charts/archive/14.2.0/vue3/colour-scale/examples/missing-data/)

```js
{
    colorScale: {
        missingDataFill: '#e0e0e0',
    },
}
```

## Legends

The standard category [Legend](https://www.ag-grid.com/charts/archive/14.2.0/vue/legend/) can be used with [Discrete Colour Scales](https://www.ag-grid.com/charts/archive/14.2.0/vue/colour-scale/#discrete-mode), and the [Gradient Legend](https://www.ag-grid.com/charts/archive/14.2.0/vue/colour-scale/#gradient-legend) can be used with both discrete and continuous Colour Scales.

The default legend depends on the `colorScale.mode`, but can be overridden by explicitly enabling or disabling each legend.

#### Legend Type

```ts
import { createApp, defineComponent, ref } from "vue";
import { AgCharts } from "ag-charts-vue3";
import type { AgChartOptions } from "ag-charts-types";
import {
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
  LegendModule,
  ModuleRegistry,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";

ModuleRegistry.registerModules([
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
  LegendModule,
]);

const ChartExample = defineComponent({
  template: `
    <div class="example-controls">
      <div class="controls-row">
        <span>Mode:</span>
        <div class="button-group gap-right" role="group" aria-label="Mode">
          <input type="radio" id="mode-continuous" name="mode" value="continuous" checked="" v-on:change="modeChange($event)">
            <label for="mode-continuous">Continuous</label>
            <input type="radio" id="mode-discrete" name="mode" value="discrete" v-on:change="modeChange($event)">
              <label for="mode-discrete">Discrete</label>
            </div>
            <span>Gradient Legend:</span>
            <div class="button-group gap-right" role="group" aria-label="Gradient Legend">
              <input type="radio" id="gradient-on" name="gradient-legend" value="on" checked="" v-on:change="gradientLegendChange($event)">
                <label for="gradient-on">On</label>
                <input type="radio" id="gradient-off" name="gradient-legend" value="off" v-on:change="gradientLegendChange($event)">
                  <label for="gradient-off">Off</label>
                </div>
                <span>Category Legend:</span>
                <div class="button-group" role="group" aria-label="Category Legend">
                  <input type="radio" id="category-on" name="category-legend" value="on" v-on:change="categoryLegendChange($event)">
                    <label for="category-on">On</label>
                    <input type="radio" id="category-off" name="category-legend" value="off" checked="" v-on:change="categoryLegendChange($event)">
                      <label for="category-off">Off</label>
                    </div>
                  </div>
                </div>
                <ag-charts
                  :options="options"
                />
  `,
  components: {
    "ag-charts": AgCharts,
  },
  setup(props) {
    const options = ref<AgCartesianChartOptions>({
      data: getData(),
      title: {
        text: "Service Quality Ratings",
      },
      subtitle: {
        text: "NPS Score (0–10)",
      },
      series: [
        {
          type: "heatmap",
          xKey: "segment",
          xName: "Segment",
          yKey: "service",
          yName: "Service",
          colorKey: "score",
          colorName: "Score",
          colorScale: {
            domain: [0, 10],
            fills: [
              { color: "tomato", stop: 7 },
              { color: "gold", stop: 9 },
              { color: "seagreen" },
            ],
          },
        },
      ],
      gradientLegend: {
        enabled: true,
        gradient: {
          preferredLength: 200,
        },
      },
      legend: {
        enabled: false,
      },
    });

    const modeChange = (event) => {
      const optionsCopy = clone(options.value);

      const mode = event.target.value;
      const series = optionsCopy.series[0];
      series.colorScale = { ...series.colorScale, mode };

      options.value = optionsCopy;
    };
    const gradientLegendChange = (event) => {
      const optionsCopy = clone(options.value);

      const enabled = event.target.value === "on";
      optionsCopy.gradientLegend = { ...optionsCopy.gradientLegend, enabled };

      options.value = optionsCopy;
    };
    const categoryLegendChange = (event) => {
      const optionsCopy = clone(options.value);

      const enabled = event.target.value === "on";
      optionsCopy.legend = { ...optionsCopy.legend, enabled };

      options.value = optionsCopy;
    };

    return {
      options,
      modeChange,
      gradientLegendChange,
      categoryLegendChange,
    };
  },
});

createApp(ChartExample).mount("#app");
```

[Live example: Legend Type](https://www.ag-grid.com/charts/archive/14.2.0/vue3/colour-scale/examples/legend-choice/)

```js
{
    gradientLegend: {
        enabled: true,
    },
    legend: {
        enabled: false,
    },
}
```

### Gradient Legend

The Gradient Legend displays a colour bar alongside the chart to help match colours to values.

#### Gradient Legend

```ts
import { createApp, defineComponent, ref } from "vue";
import { AgCharts } from "ag-charts-vue3";
import type { AgChartOptions } from "ag-charts-types";
import {
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
  ModuleRegistry,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";

ModuleRegistry.registerModules([
  CategoryAxisModule,
  GradientLegendModule,
  HeatmapSeriesModule,
]);

const ChartExample = defineComponent({
  template: `
    <div class="example-controls">
      <div class="controls-row">
        Position:
        <div class="button-group" role="group" aria-label="Position">
          <input type="radio" id="gradient-legend-position-bottom" name="gradient-legend-position" value="bottom" v-on:change="positionChange($event)">
            <label for="gradient-legend-position-bottom">Bottom</label>
            <input type="radio" id="gradient-legend-position-right" name="gradient-legend-position" value="right" checked="" v-on:change="positionChange($event)">
              <label for="gradient-legend-position-right">Right</label>
              <input type="radio" id="gradient-legend-position-left" name="gradient-legend-position" value="left" v-on:change="positionChange($event)">
                <label for="gradient-legend-position-left">Left</label>
                <input type="radio" id="gradient-legend-position-top" name="gradient-legend-position" value="top" v-on:change="positionChange($event)">
                  <label for="gradient-legend-position-top">Top</label>
                </div>
              </div>
              <div class="controls-row">
                Thickness: <input type="range" min="5" max="60" value="16" step="1" v-on:input="setThickness($event)">
                <span id="thicknessValue">16</span> <span class="gap-left">Length:</span>
                <input type="range" min="50" max="500" value="100" step="10" v-on:input="setLength($event)">
                  <span id="lengthValue">100</span> <span class="gap-left">Padding:</span>
                  <input type="range" min="0" max="40" value="10" step="1" v-on:input="setPadding($event)">
                    <span id="paddingValue">10</span>
                  </div>
                </div>
                <ag-charts
                  :options="options"
                />
  `,
  components: {
    "ag-charts": AgCharts,
  },
  setup(props) {
    const options = ref<AgCartesianChartOptions>({
      data: getData(),
      title: {
        text: "Service Quality Ratings",
      },
      subtitle: {
        text: "NPS Score (0–10)",
      },
      series: [
        {
          type: "heatmap",
          xKey: "segment",
          xName: "Segment",
          yKey: "service",
          yName: "Service",
          colorKey: "score",
          colorName: "Score",
          colorScale: {
            domain: [0, 10],
            fills: [
              { color: "tomato", stop: 7 },
              { color: "gold", stop: 9 },
              { color: "seagreen" },
            ],
          },
        },
      ],
      gradientLegend: {
        enabled: true,
        position: "right",
        scale: {
          label: {
            fontStyle: "italic",
            color: "red",
          },
          padding: 10,
        },
      },
    });

    const positionChange = (event) => {
      const optionsCopy = clone(options.value);

      const position = event.target.value;
      optionsCopy.gradientLegend = { ...optionsCopy.gradientLegend, position };

      options.value = optionsCopy;
    };
    const setThickness = (event) => {
      const optionsCopy = clone(options.value);

      const thickness = Number(event.target.value);
      optionsCopy.gradientLegend = {
        ...optionsCopy.gradientLegend,
        gradient: { ...optionsCopy.gradientLegend?.gradient, thickness },
      };
      document.getElementById("thicknessValue").innerHTML = String(thickness);

      options.value = optionsCopy;
    };
    const setLength = (event) => {
      const optionsCopy = clone(options.value);

      const preferredLength = Number(event.target.value);
      optionsCopy.gradientLegend = {
        ...optionsCopy.gradientLegend,
        gradient: { ...optionsCopy.gradientLegend?.gradient, preferredLength },
      };
      document.getElementById("lengthValue").innerHTML =
        String(preferredLength);

      options.value = optionsCopy;
    };
    const setPadding = (event) => {
      const optionsCopy = clone(options.value);

      const padding = Number(event.target.value);
      optionsCopy.gradientLegend = {
        ...optionsCopy.gradientLegend,
        scale: { ...optionsCopy.gradientLegend?.scale, padding },
      };
      document.getElementById("paddingValue").innerHTML = String(padding);

      options.value = optionsCopy;
    };

    return {
      options,
      positionChange,
      setThickness,
      setLength,
      setPadding,
    };
  },
});

createApp(ChartExample).mount("#app");
```

[Live example: Gradient Legend](https://www.ag-grid.com/charts/archive/14.2.0/vue3/colour-scale/examples/gradient-legend/)

```js
{
    gradientLegend: {
        position: 'right',
        gradient: {
            thickness: 50,
            preferredLength: 400,
        },
    },
}
```

In the above example:

- `position` places the legend at the `'bottom'`, `'top'`, `'left'`, or `'right'` of the chart.
  - When the position is `left` or `right`, values are displayed in descending order. Use `reverseOrder` to change this.
- `gradient.thickness` controls the thickness of the gradient bar. This is the width when positioned left or right, or the height when positioned top or bottom.
- `gradient.preferredLength` sets the initial length of the gradient bar. The actual length may be adjusted to fit the chart dimensions or domain.
- Customise label appearance with `scale.label` (font, colour) and `scale.padding` (distance between bar and labels).

See the [API Reference](https://www.ag-grid.com/charts/archive/14.2.0/vue/colour-scale/#reference-AgGradientLegendOptions) for all options.

## API Reference

#### Colour Scale

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| fills | AgColorScaleColorStop[] |  | Configuration for two or more colours, and the values they are rendered at. |
| fills.color (required) | CssColor \| AgColorRef \| AgColorRefMixOnto \| AgColorRefMixOntoColor |  | Colour at this position. |
| fills.stop | number \| bigint |  | Position of this colour in the data domain. In continuous mode, the colour appears exactly at this value. In discrete mode, this is the first value of the next bin. |
| fills.name | string |  | Display name for this bin, used in legend and tooltip labels. |
| domain | [AgNumericValue, AgNumericValue] |  | Fixed domain for the colour scale. If unset, the domain is derived from the data extent. |
| mode | 'continuous' \| 'discrete' | continuous | Whether the fills should be rendered as a continuous gradient or discrete bins. |
| missingDataFill | CssColor |  | Fill colour for datums with no `colorKey` value. If unset, each series preserves its default behaviour for missing data. |

#### Gradient Legend

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| enabled | boolean |  | Whether to show the gradient legend. By default, the chart displays a gradient legend for series using a `colorKey`. |
| position | AgChartLegendPlacement \| AgChartLegendPositionOptions | 'bottom' | Position of the gradient legend. A placement keyword, or an object for fine-grained positioning. |
| gradient | AgGradientLegendBarOptions |  | Gradient bar configuration. |
| gradient.preferredLength | PixelSize |  | Preferred length of the gradient bar (may expand to fit labels or shrink to fit inside a chart). |
| gradient.thickness | PixelSize |  | The thickness of the gradient bar (width for vertical or height for horizontal layout). |
| spacing | PixelSize | 20 | The spacing in pixels to use outside the legend.  __Note:__ This only applies when `floating: false`. |
| reverseOrder | boolean |  | Reverse the display order of legend items if `true`. |
| scale | AgGradientLegendScaleOptions |  | Options for the numbers that appear below or to the side of the gradient. |
| scale.label | AgGradientLegendLabelOptions |  | Options for the labels on the scale. |
| scale.label.fontStyle | FontStyle |  | The font style to use for the labels. |
| scale.label.fontWeight | FontWeight |  | The font weight to use for the labels. |
| scale.label.fontSize | FontSize |  | The font size in pixels to use for the labels. |
| scale.label.fontFamily | FontFamily \| GoogleFontFamily \| Array<FontFamily \| GoogleFontFamily> |  | The font family to use for the labels. A single family name, or an array of names used as fallbacks. |
| scale.label.color | CssColor \| AgColorRef \| AgColorRefMixOnto \| AgColorRefMixOntoColor |  | The colour to use for the labels. A colour string, or a theme-colour reference object. |
| scale.label.minSpacing | PixelSize |  | Minimum gap in pixels between the axis labels before being removed to avoid collisions. |
| scale.label.format | string |  | Format string used when rendering labels. |
| scale.label.formatter | Formatter |  | Function used to render scale labels. If `value` is a number, `fractionDigits` will also be provided, which indicates the number of fractional digits used in the step between intervals; for example, an interval step of `0.0005` would have `fractionDigits` set to `4`. |
| scale.padding | PixelSize |  | Distance between the gradient box and the labels. |
| scale.interval | AgAxisContinuousIntervalOptions |  | Options for intervals on the scale. |
| scale.interval.step | number |  | The axis interval. Expressed in the units of the axis. If the configured interval results in too many items given the chart size, it will be ignored. `bigint` steps are accepted but precision is limited to the Number range. |
| scale.interval.maxSpacing | PixelSize |  | Maximum gap in pixels between items. |
| scale.interval.values | any[] |  | Array of values in axis units for specified intervals along the axis. The values in this array must be compatible with the axis type. |
| scale.interval.minSpacing | PixelSize |  | Minimum gap in pixels between intervals. |
| border | BorderOptions |  | The border around the legend. |
| border.enabled | boolean |  | Whether the associated elements and properties should be used in the chart. |
| border.stroke | CssColor \| AgColorRef \| AgColorRefMixOnto \| AgColorRefMixOntoColor |  | The colour for the stroke. |
| border.strokeWidth | PixelSize |  | The width of the stroke in pixels. |
| border.strokeOpacity | Opacity |  | The opacity of the stroke colour. |
| cornerRadius | PixelSize |  | The corner radius of the legend. |
| padding | PixelSize \| PaddingOptions |  | The padding between the border and legend items. A number applies uniform padding; an object sets each side. |
| fill | CssColor \| AgColorRef \| AgColorRefMixOnto \| AgColorRefMixOntoColor \| AgGradientColor \| AgPatternColor \| AgImageFill |  | The colour for filling shapes. A colour string, or an object for a gradient, pattern, or image fill. |
| fillOpacity | Opacity |  | The opacity of the fill colour. |
