Mapping Side Effects to Behaviours

In this section, we will learn how to map side effects to behaviours

You can map a behaviour with a side effect such that whenever the behaviour changes, the side effect occurs. This mapping will be levied everytime the particular behaviour of a canvas changes. This is not dependant on the physical action associated with the behaviour and hence, even when a behaviour is dynamically dispatched, the side effect is triggered.

Let's try and understand how this works with the simple cars.json data.

Mapping a side effect to a particular behaviour

Let's consider that we need to map the tooltip side effect every time we select something. To do so, we will create a canvas of Miles_per_Gallon vs Cylinders and colored by Origin:

main
run-button
run-button
reset-button
loadData('/static/cars.json').then((res) => {    
  let node = document.getElementById('chart-container');    
  const env = muze();    
  const canvas = env.canvas();    
  const DataModel = muze.DataModel;  	
  loadData('/static/cars-schema.json').then((schema) => {
    const dataModelInstance = new DataModel(res, schema);
          canvas
          	.width(600)
          	.height(400)
			.rows(['Miles_per_Gallon'])
			.columns(['Cylinders'])
    		.color('Origin')
    		.layers([{
              	mark: 'bar'
            }])
			.data(dataModelInstance)
    		.mount(node)
    });
})

In order to map the particular side effect with a behaviour, we will use the mapSideEffects method from the Action Model for the canvas as below:

ActionModel
        .for(canvas)
        .mapSideEffects({
              select: ['tooltip']
         }) 

In the above code sample, we have used the mapSideEffects to map the select behaviour with the tooltip. Thus, everytime we select something on the chart(the physical action for which is the click event), we will get a tooltip for that change. You can checkout the change in the example below:

main
run-button
run-button
reset-button

loadData('/static/cars.json').then((res) => {    
  let node = document.getElementById('chart-container');    
  const env = muze();    
  const canvas = env.canvas();    
  const DataModel = muze.DataModel;  
  const ActionModel = muze.ActionModel;  
  loadData('/static/cars-schema.json').then((schema) => {
    const dataModelInstance = new DataModel(res, schema);
          canvas
          	.width(600)
          	.height(400)
			.rows(['Miles_per_Gallon'])
			.columns(['Cylinders'])
    		.color('Origin')
    		.layers([{
              	mark: 'bar'
            }])
			.data(dataModelInstance)
    		.mount(node)
    ActionModel
		.for(canvas)
		.mapSideEffects({
        select: ['tooltip']
    })
    });
})

Dispatch a behaviour with a side effect dynamically

We can also dispatch a behaviour dynamically by providing the appropriate side effect. This won't bind the side effect to a behaviour, rather it will be effective only for that particular dispatch. Changing the behaviour in any other manner will not create this side effect. Hence, we can dynamically change our visualization as per requirement.

Dispatching a behaviour works the same way as in a physical action. Let's consider we need to draw a crossline to highlight the selection. To do so we need to dispatch the behaviour and along with that we will add the side effect to it:

canvas
        .firebolt()
        .dispatchBehaviour('select', {
                criteria: {
                        Origin: ['Japan']
                }, 
                sideEffects: ['crossline'] 
        })
main
run-button
run-button
reset-button

loadData('/static/cars.json').then((res) => {    
  let node = document.getElementById('chart-container');    
  const env = muze();    
  const canvas = env.canvas();    
  const DataModel = muze.DataModel;  
  const ActionModel = muze.ActionModel;  
  loadData('/static/cars-schema.json').then((schema) => {
    const dataModelInstance = new DataModel(res, schema);
          canvas
          	.width(600)
          	.height(400)
			.rows(['Miles_per_Gallon'])
			.columns(['Origin'])
    		//.color('Origin')//
    		.layers([{
              	mark: 'bar'
            }])
			.data(dataModelInstance)
    		.mount(node)
	canvas.once('canvas.done', function(){
canvas
		.firebolt()
		.dispatchBehaviour('select', {
				criteria: {
						Origin: ['Japan']
				}, 
				sideEffects: ['crossline'] 
		})
    });
  })
})

To break it down, we are dispatching the select behaviour with the side effect crossline. This will create a crossline for the bars in the canvas which are made from Japan.

You can dispatch a behaviour with multiple side effects which will be put into effect instantly.

main
run-button
run-button
reset-button

loadData('/static/cars.json').then((res) => {    
  let node = document.getElementById('chart-container');    
  const env = muze();    
  const canvas = env.canvas();    
  const DataModel = muze.DataModel;  
  const ActionModel = muze.ActionModel;  
  loadData('/static/cars-schema.json').then((schema) => {
    const dataModelInstance = new DataModel(res, schema);
          canvas
          	.width(600)
          	.height(400)
			.rows(['Miles_per_Gallon'])
			.columns(['Cylinders'])
    		.color('Origin')
    		.layers([{
              	mark: 'bar'
            }])
			.data(dataModelInstance)
    		.mount(node)
  
canvas
		.firebolt()
		.dispatchBehaviour('select', {
				criteria: {
						Cylinders: ['4']
				}, 
				sideEffects: ['crossline', 'tooltip'] 
		})
    });
})

Here we have dispatched the select behaviour with the side effects: crossline and tooltip

Wrapping up

We learnt about how we can map side effects to behaviours. To summarize:

  • A side effect is mapped to a particular behaviour and whenever that behaviour changes, the side effect is triggered
  • We can map a side effect to a behaviour such that the particular behaviour triggers the side effect
  • We can also dynamically dispatch a behaviour with a particular side effect(s)