# 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:** 13

<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:** [May 10, 2025, 2:59am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/242 "2025-05-10T02:59:09Z")

</div>

> [@Tim](#):
>
> If I set datasets[n].backgroundColor to an array of color strings then this _does_ color the ring slices however I receive an error which causes the chart to error until refreshed.

Can you post a JSON export that shows your whole config (preferably with some sample data baked in)?

Here's an example of supplying an array to `data.datasets[index].backgroundColor`:

> **View JSON**
>
> ```python
> {
> "custom": {},
> "params": {},
> "props": {},
> "root": {
> "children": [
> {
> "meta": {
> "name": "Chartjs"
> },
> "position": {
> "height": 300,
> "width": 300,
> "x": 403,
> "y": 197
> },
> "props": {
> "data": {
> "datasets": [
> {
> "backgroundColor": [
> "#36A2EB",
> "#FFFFFF00",
> "#FFCE56",
> "transparent"
> ],
> "data": [
> 50,
> 20,
> 75,
> 25
> ],
> "label": "Dataset 1"
> },
> {
> "backgroundColor": [
> "#E73C3C",
> "#2ECC71",
> "blue"
> ],
> "data": [
> 20,
> 80,
> 10
> ],
> "label": "Dataset 2"
> }
> ],
> "labels": [
> "A",
> "B",
> "C",
> "D"
> ]
> },
> "type": "doughnut"
> },
> "type": "embr.chart.chart-js"
> }
> ],
> "meta": {
> "name": "root"
> },
> "type": "ia.container.coord"
> }
> }
> 
> ```

 ![java_OJSAqehS8C](https://us1.discourse-cdn.com/inductiveautomation/original/3X/0/4/04eb424dab1d798670bf4125774c1ed1c202b5bb.png)

Unfortunately the property browser complains about the schema, but AFAIK this isn't fixable without losing the color picker when `backgroundColor` is a single value.

Also, Chart.js supports hex color codes with alpha (`#RRGGBBAA`) as well as named colors (`transparent`).

---

<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:** [May 12, 2025, 2:35pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/243 "2025-05-12T14:35:41Z")

</div>

Thanks. I thought I was headed down the wrong path with datasets[n].backgroundColor and was focusing on options.plugins.colors.

---

<div class="post-metadata">

**Author:** ![louagejasper](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/louagejasper/32/86311_2.png) [@louagejasper](https://forum.inductiveautomation.com/u/louagejasper)\
**Post date:** [May 14, 2025, 1:21pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/244 "2025-05-14T13:21:07Z")

</div>

Would this be possible:

- When the user pan and zooms into the chart, would we be able to know the starttime and endtime of the selected frame through a property or event?

- The chart would default to a month of history with an aggregated query on Influx, but when zooming in close enough, we would need the data to be raw events.

Thanks for feedback!

---

<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:** [May 14, 2025, 2:39pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/245 "2025-05-14T14:39:38Z")

</div>

> [@louagejasper](#):
>
> When the user pan and zooms into the chart, would we be able to know the starttime and endtime of the selected frame through a property or event?

Yes, you can track the zoom/pan state by using the `onPan` and `onZoom` callback functions. Things have changed a bit since the last example, so I don't mind posting it again.

Setup:

1. Add a custom object property on the chart called `xAxis`.
2. Add the following arrow function to both `options.plugsin.zoom.pan.onPan` and `options.plugsin.zoom.zoom.onZoom`
3. When the chart is panned or zoomed, the x-axis start and end will be written to the custom property.

```javascript
(context) => { 
  const xAxis = context.chart.scales.x
  const customProps = this.store.custom

  customProps.write('xAxis.start', xAxis.start)
  customProps.write('xAxis.end', xAxis.end)
}

```

You can alternatively use `onPanComplete` and `onZoomComplete` if you only care about the end state.

> [@louagejasper](#):
>
> The chart would default to a month of history with an aggregated query on Influx, but when zooming in close enough, we would need the data to be raw events.

It's entirely possible, but it's up to you to script this to meet your needs.  
You can either drive the chart from the gateway or the client:

1. Gateway
  - Write the zoom/pan state back to the gateway.
  - Use the [JavaScript proxy](https://docs.mussonindustrial.com/ignition/embr-charts/components/chart-js/methods/getJavaScriptProxy/) for control of the chart, including inserting/appending data and re-rendering the chart.

2. Client
  - Use inline plugins to have the client directly request the data it needs when zooming/panning.
  - Data requests could be through Perspective messages or through REST API calls.

---

<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:** [May 15, 2025, 1:05am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/246 "2025-05-15T01:05:47Z")

</div>

I found the reason for my bug from a while back with the tooltip plugin not showing tooltips when displaying the x scale in timestack. The times need to be unix timestamps, not datetime strings. This would make sense (and will behave across timezones)... As soon as I change the timestamp strings to unix timestamps (millis), it works again. fwiw: I found it because I noticed errors being produced in the designer console that mentioned something about failing when running fromMillis.

---

<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:** [May 15, 2025, 10:47pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/247 "2025-05-15T22:47:43Z")

</div>

> [@bmusson](#):
>
> Additionally, if both the Kyvis-Labs module and Embr-Charts are installed simultaneously, Embr-Charts should register and use the ApexCharts (Legacy) component in place of the Kyvis-Labs version, effectively overriding it to ensure compatibility and consistency.

Question for the group:

If Embr-Charts finds the Kyvis-Lab’s ApexCharts installed, should it forcefully uninstall the Kyvis-Labs version? Or is that too intrusive/suprising?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [May 16, 2025, 12:31am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/248 "2025-05-16T00:31:18Z")

</div>

> [@bmusson](#):
>
> too intrusive/suprising?

This.

---

<div class="post-metadata">

**Author:** ![Benjamin\_Furlani](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/benjamin_furlani/32/66084_2.png) [@Benjamin\_Furlani](https://forum.inductiveautomation.com/u/Benjamin_Furlani)\
**Post date:** [May 16, 2025, 2:04am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/249 "2025-05-16T02:04:03Z")

</div>

I would agree with @pturmel ,

I can see someone "trying" something out and then uninstalling Embr for some reason and not realizing hey Apex Charts is gone and not understanding why.

---

<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:** [May 16, 2025, 2:51am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/250 "2025-05-16T02:51:46Z")

</div>

A teaser; I've been able to majorly reduce the time-to-first render.

"Legacy" component (identical client-side code as Kyvis Labs Apex Charts `1.0.22`):

Embr Charts version:

Head to head comparison:

Beta:  
[Embr-Charts-3.0.0-beta.modl](https://forum.inductiveautomation.com/uploads/short-url/q9ldb0sr7gqRRueiD8WklIifrbU.modl) (3.3 MB)

The remaining work is mainly polish:

- Complete the property tree schema (or as good as possible).
- Some tweaks to the example variants.
- General code organization/cleanup.

The ApexCharts (Legacy) component included in version `3.0.0` will be _identical_ to the latest Kyvis Labs version.

A following `3.1.0` version will include tweaks to the client-side code.

While the Kyvis Labs client-side code is written in TypeScript, it doesn't meet the aggressive linting settings used in Embr and some sections need to be rewritten in order to make the build system (and myself) happy.

---

<div class="post-metadata">

**Author:** ![richardNZ15](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/richardnz15/32/33373_2.png) [@richardNZ15](https://forum.inductiveautomation.com/u/richardNZ15)\
**Post date:** [May 28, 2025, 10:39pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/251 "2025-05-28T22:39:44Z")

</div>

Very exciting, glad there is a bit of a migration path for ApexCharts to this.

---

<div class="post-metadata">

**Author:** ![Benjamin\_Furlani](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/benjamin_furlani/32/66084_2.png) [@Benjamin\_Furlani](https://forum.inductiveautomation.com/u/Benjamin_Furlani)\
**Post date:** [June 5, 2025, 8:14pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/252 "2025-06-05T20:14:28Z")

</div>

Decided to try some of this out and well, I am not sure what I am doing wrong. . .

When I print it all looks exactly right but never is updating the chart.

```Python
	if self.view.params.chartId == payload["chart"]:
		#self.getChild("Chartjs").props.data.datasets = payload["data"]
		#system.perspective.print(payload["data"])
		component = self.getChild("Chartjs")
		chart = component.getJavaScriptProxy('chart')
		data = payload["data"]
		try:
			updateChart = '''() => this.update('none')'''

			for ds in range(len(data)):
				
				addLabels = '''(label,i) => {
					this.data.datasets[i] = {data:[],label:[]}
					console.log(this.data.datasets)
					this.data.datasets[i].label = label
				}'''
				chart.runBlocking(addLabels, { 'label': data[ds]["label"],"i":ds })

				addData = '''(data,i) => {
					const oldData = this.data.datasets[i]?.data ?? []
					const newData = oldData.concat(data)
					this.data.datasets[i].data = newData
				}'''

				distributedData = BlueRidge.Utils.distributeEvenly(data[ds]["data"], 100)
				for d in distributedData:
					chart.runBlocking(addData, {'data': d,"i":ds })
					
			
			chart.runBlocking(updateChart)
		except Exception,e:
			system.perspective.print(e)
		self.view.custom.loading = False

```

I should note the commented out code works and renders the chart. Just seeing if I can make it more smooth.

---

<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 5, 2025, 9:12pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/253 "2025-06-05T21:12:53Z")

</div>

Can you shared what `distributedData` looks like?

Here's a version that works for me, the only thing different is the `distributedData`:

```python
# Root Message Handler
def onMessageReceived(self, payload):

	#self.getChild("Chartjs").props.data.datasets = payload["data"]
	#system.perspective.print(payload["data"])
	component = self.getChild("Chartjs")
	chart = component.getJavaScriptProxy('chart')
	data = payload["data"]
	try:
		updateChart = '''() => this.update('none')'''
	
		for ds in range(len(data)):
			
			addLabels = '''(label,i) => {
				this.data.datasets[i] = {data:[],label:[]}
				console.log(this.data.datasets)
				this.data.datasets[i].label = label
			}'''
			chart.runBlocking(addLabels, { 'label': data[ds]["label"],"i":ds })
	
			addData = '''(data,i) => {
				const oldData = this.data.datasets[i]?.data ?? []
				const newData = oldData.concat(data)
				this.data.datasets[i].data = newData
			}'''
	
	# distributedData = BlueRidge.Utils.distributeEvenly(data[ds]["data"], 100)
			distributedData = [data[ds]["data"]]
			for d in distributedData:
				chart.runBlocking(addData, {'data': d,"i":ds })
				
		
		chart.runBlocking(updateChart)
	except Exception,e:
		system.perspective.print(e)
	self.view.custom.loading = False

```

```python
# Button Action
def runAction(self, event):
	payload = {
		"data": [
			{
				"label": "Data1",
				"data": [
					{ "x": 0, "y": 1 },
					{ "x": 10, "y": 2 }
				]
			},
			{	
				"label": "Data2",
				"data": [
					{ "x": 0, "y": 10 },
					{ "x": 10, "y": 20 }
				]
			}
		]
	}
		
		
		
	system.perspective.sendMessage('update-chart', payload)

```

---

<div class="post-metadata">

**Author:** ![Benjamin\_Furlani](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/benjamin_furlani/32/66084_2.png) [@Benjamin\_Furlani](https://forum.inductiveautomation.com/u/Benjamin_Furlani)\
**Post date:** [June 6, 2025, 2:25pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/254 "2025-06-06T14:25:28Z")

</div>

Here is the data.

> **Data**
>
> ```python
> [
> [
> {
> "x": "1748750414830L",
> "y": 313.0
> },
> {
> "x": "1748751135880L",
> "y": 317.0
> },
> {
> "x": "1748751796702L",
> "y": 309.0
> },
> {
> "x": "1748752398090L",
> "y": 306.0
> },
> {
> "x": "1748752998893L",
> "y": 311.0
> },
> {
> "x": "1748753659548L",
> "y": 311.0
> }
> ],
> [
> {
> "x": "1748750475291L",
> "y": 314.0
> },
> {
> "x": "1748751195954L",
> "y": 310.0
> },
> {
> "x": "1748751856562L",
> "y": 311.0
> },
> {
> "x": "1748752458068L",
> "y": 304.0
> },
> {
> "x": "1748753058809L",
> "y": 312.0
> },
> {
> "x": "1748753719692L",
> "y": 313.0
> }
> ],
> [
> {
> "x": "1748750535198L",
> "y": 310.0
> },
> {
> "x": "1748751255871L",
> "y": 311.0
> },
> {
> "x": "1748751917525L",
> "y": 308.0
> },
> {
> "x": "1748752518358L",
> "y": 309.0
> },
> {
> "x": "1748753118941L",
> "y": 310.0
> },
> {
> "x": "1748753779788L",
> "y": 307.0
> }
> ],
> [
> {
> "x": "1748750655221L",
> "y": 313.0
> },
> {
> "x": "1748751316024L",
> "y": 306.0
> },
> {
> "x": "1748751977713L",
> "y": 310.0
> },
> {
> "x": "1748752578355L",
> "y": 308.0
> },
> {
> "x": "1748753178789L",
> "y": 313.0
> },
> {
> "x": "1748753839925L",
> "y": 306.0
> }
> ],
> [
> {
> "x": "1748750715421L",
> "y": 314.0
> },
> {
> "x": "1748751376143L",
> "y": 307.0
> },
> {
> "x": "1748752037744L",
> "y": 304.0
> },
> {
> "x": "1748752638399L",
> "y": 309.0
> },
> {
> "x": "1748753239050L",
> "y": 305.0
> },
> {
> "x": "1748753959951L",
> "y": 305.0
> }
> ],
> [
> {
> "x": "1748750775480L",
> "y": 313.0
> },
> {
> "x": "1748751436244L",
> "y": 317.0
> },
> {
> "x": "1748752097908L",
> "y": 311.0
> },
> {
> "x": "1748752698618L",
> "y": 311.0
> },
> {
> "x": "1748753298986L",
> "y": 308.0
> }
> ],
> [
> {
> "x": "1748750835588L",
> "y": 312.0
> },
> {
> "x": "1748751496245L",
> "y": 310.0
> },
> {
> "x": "1748752157992L",
> "y": 313.0
> },
> {
> "x": "1748752758405L",
> "y": 308.0
> },
> {
> "x": "1748753359113L",
> "y": 313.0
> }
> ],
> [
> {
> "x": "1748750955682L",
> "y": 313.0
> },
> {
> "x": "1748751556248L",
> "y": 305.0
> },
> {
> "x": "1748752218003L",
> "y": 309.0
> },
> {
> "x": "1748752818503L",
> "y": 310.0
> },
> {
> "x": "1748753419163L",
> "y": 312.0
> }
> ],
> [
> {
> "x": "1748751015673L",
> "y": 315.0
> },
> {
> "x": "1748751616317L",
> "y": 308.0
> },
> {
> "x": "1748752278067L",
> "y": 306.0
> },
> {
> "x": "1748752878819L",
> "y": 308.0
> },
> {
> "x": "1748753539295L",
> "y": 307.0
> }
> ],
> [
> {
> "x": "1748751075695L",
> "y": 312.0
> },
> {
> "x": "1748751736563L",
> "y": 311.0
> },
> {
> "x": "1748752338002L",
> "y": 308.0
> },
> {
> "x": "1748752938485L",
> "y": 305.0
> },
> {
> "x": "1748753600120L",
> "y": 309.0
> }
> ]
> ]
> 
> ```

I just put them into even arrays and then loop through and append. Seems straight forward but maybe I am missing something.

---

<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 7, 2025, 8:18pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/255 "2025-06-07T20:18:57Z")

</div>

> [@Benjamin\_Furlani](#):
>
> ```python
> "x": "1748750414830L"
> 
> ```

I think this is the problem: the x-values are strings instead of longs.

Here's a working example with your data.

> **view.json**
>
> ```python
> {
> "custom": {},
> "params": {},
> "props": {},
> "root": {
> "children": [
> {
> "meta": {
> "name": "Chartjs"
> },
> "position": {
> "height": 300,
> "width": 300,
> "x": 131,
> "y": 217
> },
> "props": {
> "options": {
> "normalized": false,
> "plugins": {
> "zoom": {
> "pan": {
> "modifierKey": null
> }
> }
> },
> "scales": {
> "x": {
> "type": "time"
> },
> "y": {
> "type": "linear"
> }
> }
> }
> },
> "type": "embr.chart.chart-js"
> },
> {
> "events": {
> "component": {
> "onActionPerformed": {
> "config": {
> "script": "\t\t\n\tpayload \u003d {}\n\tsystem.perspective.sendMessage(\u0027update-chart\u0027, payload)"
> },
> "scope": "G",
> "type": "script"
> }
> }
> },
> "meta": {
> "name": "Button"
> },
> "position": {
> "height": 34,
> "width": 80,
> "x": 405,
> "y": 617
> },
> "type": "ia.input.button"
> }
> ],
> "meta": {
> "name": "root"
> },
> "scripts": {
> "customMethods": [
> {
> "name": "getData",
> "params": [],
> "script": "\treturn [\n\t[\n\t {\n\t \"x\": 1748750414830L,\n\t \"y\": 313.0\n\t },\n\t {\n\t \"x\": 1748751135880L,\n\t \"y\": 317.0\n\t },\n\t {\n\t \"x\": 1748751796702L,\n\t \"y\": 309.0\n\t },\n\t {\n\t \"x\": 1748752398090L,\n\t \"y\": 306.0\n\t },\n\t {\n\t \"x\": 1748752998893L,\n\t \"y\": 311.0\n\t },\n\t {\n\t \"x\": 1748753659548L,\n\t \"y\": 311.0\n\t }\n\t],\n\t [\n\t {\n\t \"x\": 1748750475291L,\n\t \"y\": 314.0\n\t },\n\t {\n\t \"x\": 1748751195954L,\n\t \"y\": 310.0\n\t },\n\t {\n\t \"x\": 1748751856562L,\n\t \"y\": 311.0\n\t },\n\t {\n\t \"x\": 1748752458068L,\n\t \"y\": 304.0\n\t },\n\t {\n\t \"x\": 1748753058809L,\n\t \"y\": 312.0\n\t },\n\t {\n\t \"x\": 1748753719692L,\n\t \"y\": 313.0\n\t }\n\t],\n\t [\n\t {\n\t \"x\": 1748750535198L,\n\t \"y\": 310.0\n\t },\n\t {\n\t \"x\": 1748751255871L,\n\t \"y\": 311.0\n\t },\n\t {\n\t \"x\": 1748751917525L,\n\t \"y\": 308.0\n\t },\n\t {\n\t \"x\": 1748752518358L,\n\t \"y\": 309.0\n\t },\n\t {\n\t \"x\": 1748753118941L,\n\t \"y\": 310.0\n\t },\n\t {\n\t \"x\": 1748753779788L,\n\t \"y\": 307.0\n\t }\n\t],\n\t [\n\t {\n\t \"x\": 1748750655221L,\n\t \"y\": 313.0\n\t },\n\t {\n\t \"x\": 1748751316024L,\n\t \"y\": 306.0\n\t },\n\t {\n\t \"x\": 1748751977713L,\n\t \"y\": 310.0\n\t },\n\t {\n\t \"x\": 1748752578355L,\n\t \"y\": 308.0\n\t },\n\t {\n\t \"x\": 1748753178789L,\n\t \"y\": 313.0\n\t },\n\t {\n\t \"x\": 1748753839925L,\n\t \"y\": 306.0\n\t }\n\t],\n\t [\n\t {\n\t \"x\": 1748750715421L,\n\t \"y\": 314.0\n\t },\n\t {\n\t \"x\": 1748751376143L,\n\t \"y\": 307.0\n\t },\n\t {\n\t \"x\": 1748752037744L,\n\t \"y\": 304.0\n\t },\n\t {\n\t \"x\": 1748752638399L,\n\t \"y\": 309.0\n\t },\n\t {\n\t \"x\": 1748753239050L,\n\t \"y\": 305.0\n\t },\n\t {\n\t \"x\": 1748753959951L,\n\t \"y\": 305.0\n\t }\n\t],\n\t [\n\t {\n\t \"x\": 1748750775480L,\n\t \"y\": 313.0\n\t },\n\t {\n\t \"x\": 1748751436244L,\n\t \"y\": 317.0\n\t },\n\t {\n\t \"x\": 1748752097908L,\n\t \"y\": 311.0\n\t },\n\t {\n\t \"x\": 1748752698618L,\n\t \"y\": 311.0\n\t },\n\t {\n\t \"x\": 1748753298986L,\n\t \"y\": 308.0\n\t }\n\t],\n\t [\n\t {\n\t \"x\": 1748750835588L,\n\t \"y\": 312.0\n\t },\n\t {\n\t \"x\": 1748751496245L,\n\t \"y\": 310.0\n\t },\n\t {\n\t \"x\": 1748752157992L,\n\t \"y\": 313.0\n\t },\n\t {\n\t \"x\": 1748752758405L,\n\t \"y\": 308.0\n\t },\n\t {\n\t \"x\": 1748753359113L,\n\t \"y\": 313.0\n\t }\n\t],\n\t [\n\t {\n\t \"x\": 1748750955682L,\n\t \"y\": 313.0\n\t },\n\t {\n\t \"x\": 1748751556248L,\n\t \"y\": 305.0\n\t },\n\t {\n\t \"x\": 1748752218003L,\n\t \"y\": 309.0\n\t },\n\t {\n\t \"x\": 1748752818503L,\n\t \"y\": 310.0\n\t },\n\t {\n\t \"x\": 1748753419163L,\n\t \"y\": 312.0\n\t }\n\t],\n\t [\n\t {\n\t \"x\": 1748751015673L,\n\t \"y\": 315.0\n\t },\n\t {\n\t \"x\": 1748751616317L,\n\t \"y\": 308.0\n\t },\n\t {\n\t \"x\": 1748752278067L,\n\t \"y\": 306.0\n\t },\n\t {\n\t \"x\": 1748752878819L,\n\t \"y\": 308.0\n\t },\n\t {\n\t \"x\": 1748753539295L,\n\t \"y\": 307.0\n\t }\n\t],\n\t [\n\t {\n\t \"x\": 1748751075695L,\n\t \"y\": 312.0\n\t },\n\t {\n\t \"x\": 1748751736563L,\n\t \"y\": 311.0\n\t },\n\t {\n\t \"x\": 1748752338002L,\n\t \"y\": 308.0\n\t },\n\t {\n\t \"x\": 1748752938485L,\n\t \"y\": 305.0\n\t },\n\t {\n\t \"x\": 1748753600120L,\n\t \"y\": 309.0\n\t }\n\t]\n\t] "
> }
> ],
> "extensionFunctions": null,
> "messageHandlers": [
> {
> "messageType": "update-chart",
> "pageScope": true,
> "script": "\n\tcomponent \u003d self.getChild(\"Chartjs\")\n\tchart \u003d component.getJavaScriptProxy(\u0027chart\u0027)\n\n\tdata \u003d self.getData()\n\t\n\tupdateChart \u003d \u0027\u0027\u0027() \u003d\u003e this.update(\u0027none\u0027)\u0027\u0027\u0027\n\taddData \u003d \u0027\u0027\u0027(data, i) \u003d\u003e {\n\t\tconst dataset \u003d this.data.datasets[i] ?? {}\n\t\t\n\t\tconst oldData \u003d dataset?.data ?? []\n\t\tdataset.data \u003d oldData.concat(data)\n\t\t\n\t\tthis.data.datasets[i] \u003d dataset\n\t}\u0027\u0027\u0027\n\n\tfor i, d in enumerate(data):\n\t\tchart.runAsync(addData, {\u0027data\u0027: d, \u0027i\u0027: i })\n\t\t\t\n\tchart.runAsync(updateChart)\n\t",
> "sessionScope": false,
> "viewScope": false
> }
> ]
> },
> "type": "ia.container.coord"
> }
> }
> 
> ```

Also, you can get away with using `runAsync` instead of `runBlocking` for a perceived speed boost.

1. JavaScript is single threaded.
2. The order of `runAsync` calls is guaranteed to be sequential.
3. Therefore: sequential `runAsync` calls will always run in the client in the order they are submitted.

By "firing and forgetting" with `runAsync` calls, you cut out a network ping-pong for each `addData` invocation while still being guaranteed that your data is added in order and the `updateChart` is called at the end.

And if you do want to know when the update is totally done, you could leave the `addData`'s as async and only block on the final `updateChart` call.

---

<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 11, 2025, 4:26am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/256 "2025-06-11T04:26:43Z")

</div>

# Embr-Charts v3.0.0

## The ApexCharts Update

This update adds two new components:

1. `ApexCharts` - [[documenation]](https://docs.mussonindustrial.com/ignition/embr-charts/components/apex-charts/)
  - This is a new implementation of the `ApexCharts` charting library as an Ignition component.
    - Simplified rendering lifecycle (i.e. quicker to render/update)
    - JavaScript proxy support for direct chart interaction.
    - Improved designer property schema support.
    - Expanded selection of default component variants.

2. `ApexCharts (Legacy)` - [[documention]](https://docs.mussonindustrial.com/ignition/embr-charts/components/apex-charts-legacy/)
  - A one-for-one replacement of the ApexCharts component from the [Kyvis-Labs/ignition-apexcharts-module](https://github.com/Kyvis-Labs/ignition-apexcharts-module).

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

> **[Release @embr-modules/charts@3.0.0 · mussonindustrial/embr](https://github.com/mussonindustrial/embr/releases/tag/%40embr-modules%2Fcharts%403.0.0)**
>
> Major Changes
> 
> 
> 36a7970: (JavaScript Proxy) getJavaScriptProxy no longer requires a propertyName.
> Previously, getJavaScriptProxy(propertyName) allowed a component delegate to proxy multiple propert...

## Other Changes

### Major Changes

- [36a7970](https://github.com/mussonindustrial/embr/commit/36a7970af1253c59092a9922d31ba6f81c84ccac): (JavaScript Proxy) `getJavaScriptProxy` no longer requires a `propertyName`.
  - Previously, `getJavaScriptProxy(propertyName)` allowed a component delegate to proxy multiple properties. However, since users couldn't interact with multiple proxy targets simultaneously, this design proved ineffective—requiring multiple proxy objects for multiple properties.Now, a component delegate may only return a single proxied object. This encourages bundling proxyable state into one object, improving usability for component consumers.The `getJavaScriptProxy(propertyName)` overload is still supported, but the `propertyName` is ignored.

### Patch Changes

- [36a7970](https://github.com/mussonindustrial/embr/commit/36a7970af1253c59092a9922d31ba6f81c84ccac): Migrate from deprecated `moduleDependencies` to supported `moduleDependencySpecs` in `build.gradle.kts`.

## Sponsorship

If you benefit from this module for commercial use, we ask you to consider sponsoring our efforts through [GitHub sponsors](https://github.com/sponsors/mussonindustrial). Your support will allow us to continue development of open-source modules and tools that benefit the entire community (plus there are some bonuses for sponsors 🙂).

## Download

[Embr-Charts-3.0.0.modl](https://github.com/mussonindustrial/embr/releases/download/%40embr-modules%2Fcharts%403.0.0/Embr-Charts-3.0.0.modl)

---

<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 13, 2025, 3:36pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/257 "2025-06-13T15:36:59Z")

</div>

do the Apex rendering enhancements affect the legacy module? I'm guessing no, but I don't want to uninstall the legacy module and refactor on several gateways if it's not needed.

---

<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 13, 2025, 4:50pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/258 "2025-06-13T16:50:31Z")

</div>

Actually, kind of yes. Travis just fixed the initial render bug in the Kyvis-Lab’s `1.0.23` release, which is the version included in Embr-Charts.

---

<div class="post-metadata">

**Author:** ![martin.johansson](https://avatars.discourse-cdn.com/v4/letter/m/7feea3/32.png) [@martin.johansson](https://forum.inductiveautomation.com/u/martin.johansson)\
**Post date:** [June 18, 2025, 5:28am UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/259 "2025-06-18T05:28:38Z")

</div>

What's the best way to install this when I have Kyvis installed (older version 10.0.19). I'm not using it in a critical way, but it is used in a few projects where you can shift between XYChart and ApexChart for testing purposes.

Should I:  
Uninstall Kyvis first, then install this?  
Install this, then uninstall Kyvis?  
Install this and keep Kyvis installed?

Sounds like it doesn't really matter as this will "overwrite" Kyvis. Just want to make sure and keep the gateway as "clean" as possible 🙂

---

<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 18, 2025, 12:16pm UTC](https://forum.inductiveautomation.com/t/musson-industrial-s-embr-charts-module/91618/260 "2025-06-18T12:16:09Z")

</div>

The best way is your first option:

1. Uninstall the Kyvis-Labs module.
2. Install Embr-Charts.

---

<div class="post-metadata">

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

</div>

Been a busy week or so and I am just now getting around to this.

That worked for me.

Makes all of these chart render pretty smooth

At least 100k datapoints or more per graph. Embr-Charts are awesome 🤷‍♂️

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

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

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