# Musson Industrial’s Embr-Charts Module

**URL:** <https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618>\
**Category:** 3rd Party Modules\
**Tags:** perspective\
**Created:** [June 10, 2024, 12:53pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618 "2024-06-10T12:53:46Z")\
**Posts on this page:** 20\
**Page:** 14

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [June 19, 2025, 2:45am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/262 "2025-06-19T02:45:40Z")

</div>

Awesome 🎉

If you’ve got high density charts, I’d recommend disabling the drawing of points, it’ll speed things up by quite a bit.

---

<div class="post-metadata">

**Author:** ![hw79](https://avatars.discourse-cdn.com/v4/letter/h/838e76/32.png) [@hw79](https://forum.inductiveautomation.com/u/hw79)\
**Post date:** [June 20, 2025, 8:45pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/263 "2025-06-20T20:45:12Z")

</div>

Has anyone tried to do a heatmap using EMBR charts? I was thinking I could use matrix type to do it but am having trouble getting the scales.y.type = category to use the label from datasets.data.label to position the boxes.

---

<div class="post-metadata">

**Author:** ![Tim](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/tim/32/3361_2.png) [@Tim](https://forum.inductiveautomation.com/u/Tim)\
**Post date:** [June 24, 2025, 5:28pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/264 "2025-06-24T17:28:57Z")

</div>

I'm having some trouble with the Line component. I'm using Embr Charts 3.0.0 and Ignition 8.1.35. When using a line chart it is not updating to show the current props.series, the chart is always displaying the previous props.series data. I can display the props.series in a Text Area component and confirm it is correct and the chart displays the previous data. It does not matter if I bind directly on props.series with a query and transform or if I use a script to populate it. Even calling .refresh() after the script populates props.series or setting the redraw property true has no effect. The chart is always displaying the previous data instead of the current data.

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [June 24, 2025, 10:43pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/265 "2025-06-24T22:43:58Z")

</div>

> [@Tim](#):
>
> I'm having some trouble with the Line component.

Which component? Chart.js, ApexCharts, or Legacy ApexCharts?

Could you provide a `view.json` export that shows the problem?

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [June 25, 2025, 3:25am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/266 "2025-06-25T03:25:57Z")

</div>

> [@hw79](#):
>
> Has anyone tried to do a heatmap using EMBR charts?

The new ApexCharts component has a Heat Map example ready to go, and for the Chart.js component I'd recommend [this sample page](https://chartjs-chart-matrix.pages.dev/samples/category.html). We don't have access to the `helpers` object, so we handle mapping the colors ourselves.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/7/2/72dc64a0c2415b1b5b68fb738e91d73a50f59ff7.png)

> **view.json**
>
> ```json
> {
> "custom": {},
> "params": {},
> "props": {},
> "root": {
> "children": [
> {
> "meta": {
> "name": "Chartjs"
> },
> "position": {
> "height": 300,
> "width": 505,
> "x": 102,
> "y": 20
> },
> "props": {
> "data": {
> "datasets": [
> {
> "backgroundColor": "(context) \u003d\u003e {\nconst value \u003d context.dataset.data[context.dataIndex].v;\nconst alpha \u003d (value - 5) / 40;\n\nreturn `rgba(0, 128, 0, ${alpha})`;\n} ",
> "borderColor": "(context) \u003d\u003e {\nconst value \u003d context.dataset.data[context.dataIndex].v;\nconst alpha \u003d (value - 5) / 40;\n\nreturn `rgba(0, 100, 0, ${alpha})`;\n}",
> "data": [
> {
> "v": 11,
> "x": "A",
> "y": "X"
> },
> {
> "v": 12,
> "x": "A",
> "y": "Y"
> },
> {
> "v": 13,
> "x": "A",
> "y": "Z"
> },
> {
> "v": 21,
> "x": "B",
> "y": "X"
> },
> {
> "v": 22,
> "x": "B",
> "y": "Y"
> },
> {
> "v": 23,
> "x": "B",
> "y": "Z"
> },
> {
> "v": 31,
> "x": "C",
> "y": "X"
> },
> {
> "v": 32,
> "x": "C",
> "y": "Y"
> },
> {
> "v": 33,
> "x": "C",
> "y": "Z"
> }
> ],
> "height": "(context) \u003d\u003e (context.chart.chartArea || {}).height / 3 - 1",
> "label": "Matrix",
> "width": "(context) \u003d\u003e (context.chart.chartArea || {}).width / 3 - 1"
> }
> ]
> },
> "options": {
> "plugins": {
> "legend": {
> "display": false
> }
> },
> "scales": {
> "x": {
> "grid": {
> "display": false
> },
> "labels": [
> "A",
> "B",
> "C"
> ],
> "type": "category"
> },
> "y": {
> "grid": {
> "display": false
> },
> "labels": [
> "X",
> "Y",
> "Z"
> ],
> "offset": true,
> "type": "category"
> }
> }
> },
> "type": "matrix"
> },
> "type": "embr.chart.chart-js"
> },
> {
> "meta": {
> "name": "ApexCharts"
> },
> "position": {
> "height": 300,
> "width": 594,
> "x": 65,
> "y": 358
> },
> "props": {
> "options": {
> "colors": [
> "#008FFB"
> ],
> "dataLabels": {
> "enabled": false
> },
> "title": {
> "align": "left",
> "text": "Heat Map Chart"
> }
> },
> "series": [
> {
> "data": [
> {
> "fill": {
> "colors": [],
> "gradient": {
> "colorStops": [],
> "gradientToColors": [],
> "opacityFrom": [],
> "opacityTo": [],
> "stops": []
> },
> "image": {
> "src": []
> },
> "opacity": [],
> "pattern": {
> "style": []
> },
> "type": []
> },
> "x": 0,
> "y": 12
> },
> {
> "x": 1,
> "y": 16
> },
> {
> "x": 2,
> "y": 23
> },
> {
> "x": 3,
> "y": 36
> },
> {
> "x": 4,
> "y": 15
> },
> {
> "x": 5,
> "y": 50
> },
> {
> "x": 6,
> "y": 28
> },
> {
> "x": 7,
> "y": 42
> },
> {
> "x": 8,
> "y": 47
> },
> {
> "x": 9,
> "y": 56
> },
> {
> "x": 10,
> "y": 63
> },
> {
> "x": 11,
> "y": 52
> },
> {
> "x": 12,
> "y": 22
> },
> {
> "x": 13,
> "y": 37
> },
> {
> "x": 14,
> "y": 19
> },
> {
> "x": 15,
> "y": 32
> },
> {
> "x": 16,
> "y": 25
> },
> {
> "x": 17,
> "y": 44
> }
> ],
> "name": "Metric1"
> },
> {
> "data": [
> {
> "x": 0,
> "y": 33
> },
> {
> "x": 1,
> "y": 45
> },
> {
> "x": 2,
> "y": 18
> },
> {
> "x": 3,
> "y": 30
> },
> {
> "x": 4,
> "y": 41
> },
> {
> "x": 5,
> "y": 59
> },
> {
> "x": 6,
> "y": 22
> },
> {
> "x": 7,
> "y": 13
> },
> {
> "x": 8,
> "y": 50
> },
> {
> "x": 9,
> "y": 31
> },
> {
> "x": 10,
> "y": 27
> },
> {
> "x": 11,
> "y": 40
> },
> {
> "x": 12,
> "y": 52
> },
> {
> "x": 13,
> "y": 29
> },
> {
> "x": 14,
> "y": 56
> },
> {
> "x": 15,
> "y": 63
> },
> {
> "x": 16,
> "y": 19
> },
> {
> "x": 17,
> "y": 32
> }
> ],
> "name": "Metric2"
> },
> {
> "data": [
> {
> "x": 0,
> "y": 38
> },
> {
> "x": 1,
> "y": 50
> },
> {
> "x": 2,
> "y": 28
> },
> {
> "x": 3,
> "y": 63
> },
> {
> "x": 4,
> "y": 22
> },
> {
> "x": 5,
> "y": 54
> },
> {
> "x": 6,
> "y": 39
> },
> {
> "x": 7,
> "y": 51
> },
> {
> "x": 8,
> "y": 45
> },
> {
> "x": 9,
> "y": 60
> },
> {
> "x": 10,
> "y": 30
> },
> {
> "x": 11,
> "y": 42
> },
> {
> "x": 12,
> "y": 19
> },
> {
> "x": 13,
> "y": 57
> },
> {
> "x": 14,
> "y": 48
> },
> {
> "x": 15,
> "y": 31
> },
> {
> "x": 16,
> "y": 55
> },
> {
> "x": 17,
> "y": 28
> }
> ],
> "name": "Metric3"
> },
> {
> "data": [
> {
> "x": 0,
> "y": 22
> },
> {
> "x": 1,
> "y": 27
> },
> {
> "x": 2,
> "y": 33
> },
> {
> "x": 3,
> "y": 25
> },
> {
> "x": 4,
> "y": 40
> },
> {
> "x": 5,
> "y": 32
> },
> {
> "x": 6,
> "y": 48
> },
> {
> "x": 7,
> "y": 45
> },
> {
> "x": 8,
> "y": 52
> },
> {
> "x": 9,
> "y": 41
> },
> {
> "x": 10,
> "y": 37
> },
> {
> "x": 11,
> "y": 44
> },
> {
> "x": 12,
> "y": 27
> },
> {
> "x": 13,
> "y": 34
> },
> {
> "x": 14,
> "y": 29
> },
> {
> "x": 15,
> "y": 31
> },
> {
> "x": 16,
> "y": 46
> },
> {
> "x": 17,
> "y": 56
> }
> ],
> "name": "Metric4"
> },
> {
> "data": [
> {
> "x": 0,
> "y": 41
> },
> {
> "x": 1,
> "y": 39
> },
> {
> "x": 2,
> "y": 56
> },
> {
> "x": 3,
> "y": 44
> },
> {
> "x": 4,
> "y": 59
> },
> {
> "x": 5,
> "y": 38
> },
> {
> "x": 6,
> "y": 51
> },
> {
> "x": 7,
> "y": 43
> },
> {
> "x": 8,
> "y": 29
> },
> {
> "x": 9,
> "y": 50
> },
> {
> "x": 10,
> "y": 64
> },
> {
> "x": 11,
> "y": 36
> },
> {
> "x": 12,
> "y": 32
> },
> {
> "x": 13,
> "y": 40
> },
> {
> "x": 14,
> "y": 27
> },
> {
> "x": 15,
> "y": 42
> },
> {
> "x": 16,
> "y": 28
> },
> {
> "x": 17,
> "y": 46
> }
> ],
> "name": "Metric5"
> },
> {
> "data": [
> {
> "x": 0,
> "y": 45
> },
> {
> "x": 1,
> "y": 47
> },
> {
> "x": 2,
> "y": 38
> },
> {
> "x": 3,
> "y": 50
> },
> {
> "x": 4,
> "y": 62
> },
> {
> "x": 5,
> "y": 33
> },
> {
> "x": 6,
> "y": 56
> },
> {
> "x": 7,
> "y": 34
> },
> {
> "x": 8,
> "y": 39
> },
> {
> "x": 9,
> "y": 61
> },
> {
> "x": 10,
> "y": 42
> },
> {
> "x": 11,
> "y": 54
> },
> {
> "x": 12,
> "y": 28
> },
> {
> "x": 13,
> "y": 46
> },
> {
> "x": 14,
> "y": 43
> },
> {
> "x": 15,
> "y": 30
> },
> {
> "x": 16,
> "y": 41
> },
> {
> "x": 17,
> "y": 52
> }
> ],
> "name": "Metric6"
> },
> {
> "data": [
> {
> "x": 0,
> "y": 32
> },
> {
> "x": 1,
> "y": 36
> },
> {
> "x": 2,
> "y": 40
> },
> {
> "x": 3,
> "y": 46
> },
> {
> "x": 4,
> "y": 29
> },
> {
> "x": 5,
> "y": 35
> },
> {
> "x": 6,
> "y": 41
> },
> {
> "x": 7,
> "y": 54
> },
> {
> "x": 8,
> "y": 31
> },
> {
> "x": 9,
> "y": 50
> },
> {
> "x": 10,
> "y": 38
> },
> {
> "x": 11,
> "y": 47
> },
> {
> "x": 12,
> "y": 39
> },
> {
> "x": 13,
> "y": 42
> },
> {
> "x": 14,
> "y": 33
> },
> {
> "x": 15,
> "y": 48
> },
> {
> "x": 16,
> "y": 46
> },
> {
> "x": 17,
> "y": 44
> }
> ],
> "name": "Metric7"
> },
> {
> "data": [
> {
> "x": 0,
> "y": 39
> },
> {
> "x": 1,
> "y": 45
> },
> {
> "x": 2,
> "y": 51
> },
> {
> "x": 3,
> "y": 49
> },
> {
> "x": 4,
> "y": 37
> },
> {
> "x": 5,
> "y": 43
> },
> {
> "x": 6,
> "y": 35
> },
> {
> "x": 7,
> "y": 56
> },
> {
> "x": 8,
> "y": 32
> },
> {
> "x": 9,
> "y": 41
> },
> {
> "x": 10,
> "y": 48
> },
> {
> "x": 11,
> "y": 50
> },
> {
> "x": 12,
> "y": 37
> },
> {
> "x": 13,
> "y": 45
> },
> {
> "x": 14,
> "y": 43
> },
> {
> "x": 15,
> "y": 30
> },
> {
> "x": 16,
> "y": 51
> },
> {
> "x": 17,
> "y": 54
> }
> ],
> "name": "Metric8"
> },
> {
> "data": [
> {
> "x": 0,
> "y": 31
> },
> {
> "x": 1,
> "y": 44
> },
> {
> "x": 2,
> "y": 35
> },
> {
> "x": 3,
> "y": 55
> },
> {
> "x": 4,
> "y": 48
> },
> {
> "x": 5,
> "y": 34
> },
> {
> "x": 6,
> "y": 46
> },
> {
> "x": 7,
> "y": 52
> },
> {
> "x": 8,
> "y": 41
> },
> {
> "x": 9,
> "y": 36
> },
> {
> "x": 10,
> "y": 59
> },
> {
> "x": 11,
> "y": 32
> },
> {
> "x": 12,
> "y": 45
> },
> {
> "x": 13,
> "y": 50
> },
> {
> "x": 14,
> "y": 28
> },
> {
> "x": 15,
> "y": 43
> },
> {
> "x": 16,
> "y": 41
> },
> {
> "x": 17,
> "y": 39
> }
> ],
> "name": "Metric9"
> }
> ],
> "type": "heatmap"
> },
> "type": "embr.chart.apex-charts"
> }
> ],
> "meta": {
> "name": "root"
> },
> "type": "ia.container.coord"
> }
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![Tim](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/tim/32/3361_2.png) [@Tim](https://forum.inductiveautomation.com/u/Tim)\
**Post date:** [June 25, 2025, 1:55pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/267 "2025-06-25T13:55:07Z")

</div>

It is the ApexChart. This view demonstrates the issue I'm seeing.

```python
{
  "custom": {},
  "params": {},
  "props": {},
  "root": {
    "children": [
      {
        "events": {
          "component": {
            "onActionPerformed": {
              "config": {
                "script": "\timport math\n\n\tselection \u003d self.props.value\n\n\tdata_points \u003d []\n\tnow \u003d system.date.now()\n\tfor i in range(100):\n\t\ttimestamp \u003d system.date.addSeconds(now, i)\n\t\tif selection \u003d\u003d \u0027sine\u0027:\n\t\t\tvalue \u003d math.sin(i * 0.2) * 50 + 50\n\t\telse:\n\t\t\tvalue \u003d math.cos(i * 0.2) * 50 + 50\n\t\tdata_points.append({\u0027x\u0027: timestamp, \u0027y\u0027: value})\n\n\tseries_label \u003d \u0027Sine Wave\u0027 if selection \u003d\u003d \u0027sine\u0027 else \u0027Cosine Wave\u0027\n\ttransformed_data \u003d [\n\t {\n\t \u0027name\u0027: series_label,\n\t \u0027data\u0027: data_points\n\t }\n\t]\n\n\tchart \u003d self.getSibling(\u0027ApexLineChart\u0027)\n\tchart.props.series \u003d transformed_data"
              },
              "scope": "G",
              "type": "script"
            }
          }
        },
        "meta": {
          "name": "Dropdown"
        },
        "position": {
          "height": 36,
          "width": 256,
          "x": 48,
          "y": 32
        },
        "props": {
          "options": [
            {
              "label": "Sine Wave",
              "value": "sine"
            },
            {
              "label": "Cosine Wave",
              "value": "cosine"
            }
          ],
          "value": "sine"
        },
        "type": "ia.input.dropdown"
      },
      {
        "meta": {
          "name": "ApexLineChart"
        },
        "position": {
          "height": 300,
          "width": 500,
          "x": 48,
          "y": 96
        },
        "props": {
          "options": {
            "chart": {
              "zoom": {
                "enabled": false
              }
            },
            "xaxis": {
              "type": "datetime"
            }
          }
        },
        "type": "embr.chart.apex-charts"
      },
      {
        "meta": {
          "name": "TextArea"
        },
        "position": {
          "height": 299,
          "width": 614,
          "x": 48,
          "y": 463
        },
        "propConfig": {
          "props.text": {
            "binding": {
              "config": {
                "path": "../ApexLineChart.props.series"
              },
              "type": "property"
            }
          }
        },
        "type": "ia.input.text-area"
      }
    ],
    "meta": {
      "name": "root"
    },
    "type": "ia.container.coord"
  }
}

```

---

<div class="post-metadata">

**Author:** ![MMaynard](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mmaynard/32/3366_2.png) [@MMaynard](https://forum.inductiveautomation.com/u/MMaynard)\
**Post date:** [June 25, 2025, 2:39pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/268 "2025-06-25T14:39:52Z")

</div>

First off just want to see how impressive this project is.  
Been using ApexCharts for a long time now but just started converting over to Embr.

Only issue I am having trouble with is,

Is there a way to enable the drop shadows on the bars and lines in chartJS like apex has?

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [June 25, 2025, 2:46pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/269 "2025-06-25T14:46:08Z")

</div>

> [@Tim](#):
>
> It is the ApexChart. This view demonstrates the issue I'm seeing.

This is perfect, I can reproduce the issue.  
Will ~probably~ have a chance to fix it tonight/tomorrow.

It looks like a issue with the memoization of the `series` property when the entire object is replaced; changing individual `series[0].data` values works, but replacing the whole `series` property causes everything to lag by 1 render.

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [June 26, 2025, 1:49am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/270 "2025-06-26T01:49:49Z")

</div>

> [@bmusson](#):
>
> issue with the memoization of the `series` property

That's exactly what it was, version `3.0.1` includes a fix.

> **[Release @embr-modules/charts@3.0.1 · mussonindustrial/embr](https://github.com/mussonindustrial/embr/releases/tag/%40embr-modules%2Fcharts%403.0.1)**
>
> Patch Changes
> 
> @embr-modules/charts-web@3.0.1

Related Question:  
Is there a better way to create my props reducer that will retain object references?

```typescript
// Existing
  getPropsReducer(tree: PropertyTree): ChartProps {
    return {
      type: tree.readString('type'),
      options: tree.read('options', {}),
      series: tree.read('series', {}),
      redraw: tree.read('redraw', false),
      events: tree.read('events', {}),
      style: tree.readStyle('style'),
    } as never

```

Whenever _anything_ in the `PropertyTree` changes, I'm getting entirely new references for **all** of my component's properties. This makes React work way harder than it needs to.

For example, in the ApexCharts component, I only want to call `updateSeries` if the `series` property has changed. But by naively using a `useEffect(..., [props.props.series])`, the effect will be called for every render with any `PropertyTree` change, including changes that don't touch the `series` property.

To mitigate this I'm memoizing using deep comparison:

```typescript
  const series = useDeepCompareMemo(() => {
    return props.props.series
  }, [props.props.series])

```

This works, and `series` is maintained through other changes in the property tree.  
Is it expected that I need to do this? What are first party/other component authors doing?

---

<div class="post-metadata">

**Author:** ![Tim](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/tim/32/3361_2.png) [@Tim](https://forum.inductiveautomation.com/u/Tim)\
**Post date:** [June 26, 2025, 8:02pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/271 "2025-06-26T20:02:27Z")

</div>

I'm having trouble with the ApexCharts Radar. The props.options.xaxis.categories do not update on the chart in a web client, even though it works as expected in the designer.

The following view JSON demonstrates the issue.

```python
{
  "custom": {},
  "params": {},
  "props": {},
  "root": {
    "children": [
      {
        "events": {
          "component": {
            "onActionPerformed": {
              "config": {
                "script": "\tselection \u003d self.props.value\n\tif selection \u003d\u003d \u0027high\u0027:\n\t\tcategories \u003d [\u0027Speed\u0027, \u0027Power\u0027, \u0027Efficiency\u0027, \u0027Uptime\u0027]\n\t\tactual_data \u003d [95, 88, 92, 99]\n\t\ttitle_text \u003d \u0027High Performance Profile\u0027\n\telse:\n\t\tcategories \u003d [\u0027Speed\u0027, \u0027Power\u0027, \u0027Efficiency\u0027, \u0027Uptime\u0027]\n\t\tactual_data \u003d [65, 72, 55, 80]\n\t\ttitle_text \u003d \u0027Low Performance Profile\u0027\n\t\n\ttarget_data \u003d [100] * len(actual_data)\n\tseries_config \u003d [{\u0027name\u0027: \u0027Actual\u0027, \u0027data\u0027: actual_data}, {\u0027name\u0027: \u0027Target\u0027, \u0027data\u0027: target_data}]\n\toptions_config \u003d {\u0027xaxis\u0027: {\u0027categories\u0027: categories}, \u0027yaxis\u0027: {\u0027min\u0027: 0, \u0027max\u0027: 120}, \u0027title\u0027: {\u0027text\u0027: title_text}}\n\tchart \u003d self.getSibling(\u0027ApexRadarChart\u0027)\n\tchart.custom.chartConfig \u003d {\u0027series\u0027: series_config, \u0027options\u0027: options_config}"
              },
              "scope": "G",
              "type": "script"
            }
          }
        },
        "meta": {
          "name": "Dropdown"
        },
        "position": {
          "height": 36,
          "width": 256,
          "x": 48,
          "y": 32
        },
        "props": {
          "options": [
            {
              "label": "High Performance Profile",
              "value": "high"
            },
            {
              "label": "Low Performance Profile",
              "value": "low"
            }
          ],
          "value": "low"
        },
        "type": "ia.input.dropdown"
      },
      {
        "custom": {
          "chartConfig": {
            "options": {},
            "series": []
          }
        },
        "meta": {
          "name": "ApexRadarChart"
        },
        "position": {
          "height": 300,
          "width": 400,
          "x": 48,
          "y": 96
        },
        "propConfig": {
          "props.options": {
            "binding": {
              "config": {
                "path": "this.custom.chartConfig.options"
              },
              "type": "property"
            }
          },
          "props.series": {
            "binding": {
              "config": {
                "path": "this.custom.chartConfig.series"
              },
              "type": "property"
            }
          }
        },
        "props": {
          "type": "radar"
        },
        "type": "embr.chart.apex-charts"
      }
    ],
    "meta": {
      "name": "root"
    },
    "type": "ia.container.coord"
  }
}

```

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [June 27, 2025, 4:40am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/272 "2025-06-27T04:40:17Z")

</div>

Wow, this was a wild one. I'm going to try and document this as I understand it.

### The Perspective Part

1. Because your bindings are not persistent, the initial render of the chart will occur with the default schema.
2. Once the bindings resolve, the chart is updated with your options and series information.
  - If you try this with the Legacy component it will totally crash
  - The new component has "reasonable" defaults that allow the chart to attempt to render with undefined properties.

### The Embr Charts Part

1. The Embr Charts ApexCharts component property schema specifies the default for a new `series.data` item to be `{ x: 0, y: 0 }`.
  - Undefined `x` and `y` values can cause ApexCharts to freak out during the render stage.
  - With these defaults, the chart doesn't crash when a user clicks the `+` button to add a new item to the array.

2. Because of this, the `series` property was defaulting to an array of 1 series with a single data point of `{ x: 0, y: 0 }`.
  - This is weird, but was hard to notice without specifically looking for it.

### The ApexCharts Part

1. Rendering a series containing `{ x: 0, y: 0 }` seems to break the Radar chart's X-Axis.
2. The chart's `updateOptions` method refuses to work after rendering `{ x, y }` points in a Radar chart (even through the series is eventually updated after the binding resolves).

### The Fix

I just need to specify that the default `series` property should be an empty array 🤷‍♂️.

TLDR: Non-persistent bindings -\> default schema is rendered -\>line series data != radar series data -\> ApexCharts `updateOptions` method breaks.

Here's a local build, an official fix should be available next week.  
[Embr-Charts-3.0.2-RC.modl](https://forum.inductiveautomation.com/uploads/short-url/temGXQwEw1e3rs3i0h8z4mrosx0.modl) (2.7 MB)

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [July 10, 2025, 7:01am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/273 "2025-07-10T07:01:28Z")

</div>

Hey @bmusson , how would I enable `props.scales.x.ticks.display` on hover of the chart via JS (and remove after)?

The reason is, I have a table of these charts and I don't want it cluttering the view unless the user is actively looking at a chart (maybe... I want to see how it looks)

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/9/6/96269abaf83f2744cb76cdaed3b2e4d4823f45f7.png)

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/1/f/1f2bd446359deb304ca0a543195e5d1bf28f1151.png)

2nd Q:  
How can I show the timestack times in 24hr time?

I've tried adding this and setting to `false` but it didn't change anything (from [here](https://github.com/jkmnt/chartjs-scale-timestack?tab=readme-ov-file#options))

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/b/b/bb38c642e80ea144c33ff474ca1f230312bab9cd.png)

Sorry one more..  
3rd Q:  
How can I remove the tooltip on touch move end? I've found that if you touch and drag to move along the timeline to see different data point values in the tooltip, the tooltip stays there when you let go, and doesn't go away if for example you do the same thing on another chart. If you just touch and let go, then it removes the tooltips on the other charts and just shows it on the chart data point you touched.  
The intended behaviour for me is:

- for touch drags, the tooltip only shows while you're touching the screen and disappears when you let go
- for instantaneous touches, the tooltip stays and only disappears upon another touch event

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/7/0/702fed41efcd943f4e15bab1fb0277a344bbc5a2.png)

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [July 17, 2025, 9:54pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/274 "2025-07-17T21:54:46Z")

</div>

## 1. Enable Ticks on Hover

> [@nminchin](#):
>
> Hey @bmusson , how would I enable `props.scales.x.ticks.display` on hover of the chart via JS (and remove after)?

Here's a plugin configuration that will do this, stick it in the `props.plugins` array:

```js
// plugins[index].beforeInit
(chart) => {

    chart.options.scales.x.ticks.display = false;

    chart.canvas.addEventListener('mouseenter', () => {
        chart.options.scales.x.ticks.display = true
        chart.update('none')
    })

    chart.canvas.addEventListener('mouseleave', () => {
        chart.options.scales.x.ticks.display = false
        chart.update('none')
    })

}

```

## 2. 24hr Timestack X-Axis

> [@nminchin](#):
>
> 2nd Q:  
> How can I show the timestack times in 24hr time?
> 
> I've tried adding this and setting to `false` but it didn't change anything (from [here](https://github.com/jkmnt/chartjs-scale-timestack?tab=readme-ov-file#options))

The documentation is wrong, the namespace is actually `options.scales[id].timestack`.  
`options.scales.x.timestack.format_style.hour12 = false` should do what you want. It doesn't seem like changing this value will cause a render, it only evaluates when the chart first starts.

## 3. Remove Tooltip on Touch Move End

> [@nminchin](#):
>
> How can I remove the tooltip on touch move end?

Here's a plugin that should match the touch behavior you want:

```js
// plugins[index].beforeInit
(chart) => {
    let dragStartX = 0
    let dragStartY = 0
    let wasDragging = false
    const DRAG_THRESHOLD = 8

    const canvas = chart.canvas

    const clearTooltip = () => {
      chart.tooltip.setActiveElements([], { x: 0, y: 0 })
      chart.update('none')
    }

    const onTouchStart = (e) => {
      if (e.touches.length === 1) {
        dragStartX = e.touches[0].clientX
        dragStartY = e.touches[0].clientY
        wasDragging = false
      }
    }

    const onTouchMove = (e) => {
      if (e.touches.length === 1) {
        const dx = e.touches[0].clientX - dragStartX
        const dy = e.touches[0].clientY - dragStartY
        if (Math.hypot(dx, dy) > DRAG_THRESHOLD) {
          wasDragging = true
        }
      }
    }

    const onTouchEnd = (e) => {
      if (wasDragging) {
        clearTooltip();
      }
    }

    canvas.addEventListener('touchstart', onTouchStart, { passive: true })
    canvas.addEventListener('touchmove', onTouchMove, { passive: true })
    canvas.addEventListener('touchend', onTouchEnd, { passive: true })
  }

```

---

<div class="post-metadata">

**Author:** ![hw79](https://avatars.discourse-cdn.com/v4/letter/h/838e76/32.png) [@hw79](https://forum.inductiveautomation.com/u/hw79)\
**Post date:** [August 4, 2025, 12:06pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/275 "2025-08-04T12:06:17Z")

</div>

I found an example where the chart doesn't honor the built-in theme colors. if I set options.scales. x or y ticks or title .color when the chart initially starts the colors will not be recognized until the chart redraws.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/d/b/dbe3b69acc856bd267802251b45793b2436bdbfd.png)

![2025-08-04_06-57-11](https://us1.discourse-cdn.com/inductiveautomation/original/3X/8/4/844a1a116a0c5fed9f5eb9b22347dfbc9a3cff1b.gif)

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [August 13, 2025, 3:25am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/276 "2025-08-13T03:25:48Z")

</div>

## Notable Patch Release

The recently released versions `Embr-Charts-Ignition81-3.0.10` and `Embr-Charts-Ignition83Beta-3.0.3`contain a fix for a regression introduced in Kyvis-Labs version `1.0.23` that could cause changes to the series/options props to be ignored.

[Embr v8.1 - 2025.8.13](https://github.com/mussonindustrial/embr/releases/tag/releases%252F8.1%252F2025.8.13)  
[Embr v8.3 - 2025.8.13](https://github.com/mussonindustrial/embr/releases/tag/releases%252F8.3%252F2025.8.13)

> <https://github.com/mussonindustrial/embr/issues/347>
>
> Related to #305, it appears that the ApexCharts Legacy chart doesn't always refr…esh when binding data changes. I have attempted to change binding to series as well with same results.
> 
> Please see .gif with the same data bindings on the three chart versions and an export of the perspective view. I have also updated to your latest version today.
> 
> EDIT: My apologies as I have gotten the labeling incorrect, Apex Legacy (top), Embr (middle), Apex (bottom)
> 
> Thank you for your work and support.
> 
> !\[Image\](https://github.com/user-attachments/assets/b339d42f-07a5-4b47-bb7a-203be4aecc52)
> 
> \[EmbrTest\_2025-08-06\_0818.zip\](https://github.com/user-attachments/files/21608046/EmbrTest\_2025-08-06\_0818.zip)

I do not plan to submit any PRs to the `Kyvis-Labs` repo, so this marks the first point where the `ApexCharts (Legacy)`component is deviating its behavior from the original fork.

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [August 16, 2025, 2:10pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/277 "2025-08-16T14:10:10Z")

</div>

> [@hw79](#):
>
> when the chart initially starts the colors will not be recognized until the chart redraws

Can you provide an example view?

---

<div class="post-metadata">

**Author:** ![hw79](https://avatars.discourse-cdn.com/v4/letter/h/838e76/32.png) [@hw79](https://forum.inductiveautomation.com/u/hw79)\
**Post date:** [August 18, 2025, 11:20am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/278 "2025-08-18T11:20:30Z")

</div>

I sent you a DM with the chart.

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [August 18, 2025, 9:15pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/279 "2025-08-18T21:15:37Z")

</div>

> [@hw79](#):
>
> I found an example where the chart doesn't honor the built-in theme colors. if I set options.scales. x or y ticks or title .color when the chart initially starts the colors will not be recognized until the chart redraws.

Fixed in `Ignition81-3.1.0` and `Ignition83-3.1.0`.

[Embr v8.1 - 2025.8.18](https://github.com/mussonindustrial/embr/releases/tag/releases%2F8.1%2F2025.8.18)  
[Embr v8.3 - 2025.8.18](https://github.com/mussonindustrial/embr/releases/tag/releases%2F8.3%2F2025.8.18)

> <https://github.com/mussonindustrial/embr/issues/354>
>
> Reported here:
> https://forum.inductiveautomation.com/t/musson-industrial-s-embr-…charts-module/91618/275?u=bmusson

## Future Work

`ApexCharts@5.3.3` has a fixed a blocking issue with their `updateOptions` function, so we should be good to update.

> <https://github.com/apexcharts/apexcharts.js/issues/5067>
>
> \### Description
> 
> When attempting using \`updateOptions\` to change the category la…bels of an X-Axis, the category labels do not update.
> 
> \### Steps to Reproduce
> 
> 1. Render a Radar chart and define \`xaxis.categories\` as an array of labels.
> 2. Call \`chart.updateOptions()\` and pass a new array of labels for \`xaxis.categories\`. 
> 
> \### Expected Behavior
> The chart should render with new category labels.
> 
> \### Actual Behavior
> The original labels are retained, and nothing changes visually.
> 
> 
> \### Reproduction Link
> 
> Version 4.5.0 (WORKING)
> https://codepen.io/benmusson/pen/zxGeQZm
> 
> Version 4.7.0 (BROKEN)
> https://codepen.io/benmusson/pen/Eajrzap
> 
> \### Other Information
> I think this might be related to #5022?

Currently Embr-Charts includes `ApexCharts@3.54.1` (the same version Kyvis-Labs was including) which is very out of date at this point. `4.x.x` included a big change in the underlying SVG library that it supposed to provide a performance boost - so stay tuned.

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [September 17, 2025, 3:24pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/280 "2025-09-17T15:24:18Z")

</div>

Corresponding to the launch of `8.3`, the Embr `8.3` branch is now also out of beta!

[Embr v8.3 - 2025.9.17](https://github.com/mussonindustrial/embr/releases/tag/releases%252F8.3%252F2025.9.17)

### Bad News

`ApexCharts@5.0.0` introduced a change to the way ApexCharts is licensed.  
As of `5.0.0+` it is no longer MIT licensed; instead, it's now an annoying _"dual-license"_ model.

> **[Pricing – ApexCharts.js](https://www.apexcharts.com/pricing/)**
>
> ApexCharts Pricing. See various plans for ApexTree, ApexSankey, ApexGantt that offers professional support

Currently, Embr Charts includes `ApexCharts@3.54.1` which is licensed under an MIT license.

Our goal is for all Embr modules to remain free and open. We will not pursue any upgrades to versions of ApexCharts that would require module users to purchase any licenses.

If we were to introduce a paid ApexCharts module it would be sold as a separate module from Embr Charts under its own licensing terms.

### Future Work

- It looks like the latest release with an MIT license was `ApexCharts@4.7.0`, so we will be stuck with that 🤷‍♂️.
- Work is being done to add end-to-end tests to the Embr module suite, including visual regression testing.
  - Testing both 8.1 and 8.3 is too tedious to do by hand 😆
  - Updates to `ApexCharts@4.7.0` will come after E2E tests are added.

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [September 18, 2025, 11:56am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/282 "2025-09-18T11:56:50Z")

</div>

Please don't ping individuals on the forum like that. We're all volunteers, not IA Tech Support, and we're doing this on our own time for free. The good guys read all the posts of interest anyway.  
Thanks.

[Previous page](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618.md?page=13)

[Next page](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618.md?page=15)
