Musson Industrial’s Embr-Charts Module

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
{
  "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"
  }
}

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).

1 Like

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

1 Like

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!

1 Like

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.
(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.

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 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.
4 Likes

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.

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?

This.

3 Likes

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.

2 Likes

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 (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.

17 Likes

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

2 Likes

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.

	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.

Can you shared what distributedData looks like?

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

# 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
# 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)