Vue is a Javascript framework that assists in building user interfaces. Vue is awesome because it is easily picked up and integrated with other libraries and projects. We are going to take a deeper look into how we can set Zingchart up with Vue and use two way binding to allow more function. Our end product is going to look and function something like this:

Let's get started with calling in the Vue and Zingchart libraries using cdns.

<script src="https://cdn.zingchart.com/zingchart.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.js"></script>

Now that we have the libraries loaded we can move onto making the code. We will be making a template for our chart basis. We can make our new Vue app instance like so:

var app = new Vue({
    el: '#app',
    data: {}
});

Now we can use a div with id="app"  and use elements we place in our data object. Inside data lets add our chart configuration of the pie chart we want to display.

var app = new Vue({
    el: '#app',
    data: {
        chartConfig: {
            type: 'pie',
            theme: 'dark',
            backgroundColor: '#424242',
            globals: {
                fontFamily: 'Verdana',
            },
            title: {
            text: 'Goals',
        },
        legend: {
            toggleAction:'remove',
            mediaRules: [{
                maxWidth: 300,
                marginTop: 50,
                layout: 'h',
                align: 'center'
            }]
        },
        plot: {
            slice: '80%',
            refAngle:270,
            valueBox: [{
                fontSize: 12,
                mediaRules: [{
                    maxWidth: 450,
                    visible: false,
                }],
            type: 'all',
            placement:'out',
            text:'%t'
            },{
            fontSize: 10,
            mediaRules: [{
                maxWidth: 230,
                visible: false,
            }]
          }]
        },
        tooltip: {
            fontSize: 17,
            anchor: 'c',
            x: '50%',
            y: '54%',
            sticky: true,
            backgroundColor: 'none',
            borderWidth: 0,
            thousandsSeparator: ',',
            text: '<span style="color:%color">Plot text: %t</span><br><span style="color:%color">Plot Value: %v</span>',
            mediaRules: [{
                maxWidth: 250,
                fontSize: 14
            }]
        },
        series: [{
            values: [45],
            backgroundColor: '#9575cd',
            text: 'series 1'
        },{
            values: [55],
            backgroundColor: '#1de9b6',
            text: 'series 2'
        }]
      }
    }
});

Now that we have the chart configuration in the data object we can call the data via two way binding from an html to javascript end. 

Now we can call the information in our Vue instance into our html by using double handlebars {{}} . But this is a one way calling method so we are going to need to utilize a different method for it to become a two way binding method. Here we can do this by using v-model  which is a Form input binding. This will connect to our Vue instance and automatically update the values if you enter a value or string into the form input. We will be putting these in our html form inputs. Let's make one for Title Text, Plot 1 Value, Plot 1 text, Plot 2 Value and Plot 2 Text.

The html will go inside our div with id="app"  and will look like this:

<div id="app">
    <div id="controls">
        <section>
            <label>Title Text : </label>
            <input type="text" v-model="chartConfig.title.text" />
        </section>
        <section>
            <label>Plot 1 Value : </label>
            <input type="number" v-model.number="chartConfig.series[0].values[0]" />
        </section>
        <section>
            <label>Plot 1 text : </label>
            <input type="text" v-model="chartConfig.series[0].text" />
        </section>
        <section>
            <label>Plot 2 Value : </label>
            <input type="number" v-model.number="chartConfig.series[1].values[0]" />
        </section>
        <section>
            <label>Plot 2 Text : </label>
            <input type="text" v-model="chartConfig.series[1].text" />
        </section>
    </div>
</div>

Now that we have our two way binding in effect, we need to render the chart and use our chartConfig  to display the data. This will be done by using Vue components. We will be registering the component at the end of the Vue instance.

components: {
    'zingchart': ZingChartComponent,
}

Let's make the Zingchart component! Make sure to place it above the Vue instance as components must be pre-defined before the instance. 

var ZingChartComponent = Vue.component('zingchart-component', {});

We can add more to this so that we can add functionality and rendering. We are going to add properties to get data from the parent element:

props: {
    zcId: {type: String},
    zcHeight: {},
    zcWidth: {},
    zcValues: {type: Array},
    zcJson: {
        type: Object,
        default: function() {
            return {
                type: 'bar',
                series:[
                    {
                        values: [15,25,35,45,55,65]
                    }
                ]
            }
        }
    }
},

These are properties we need to render the chart. The data acts as the default values for the render method and chart. Because we use props all instances of the component will share the same objects. Now we are going to be calling different functions that will occur depending on which Vue event is fired. These will go inside your Zingchart component. We need a data function:

data: function() { 
    return {
        id: this.zcId || 'zingchart-autoId-' + Math.ceil(Math.random() * 1000000),
        width: this.zcWidth || '100%',
        height: this.zcHeight || 300,
        json: this.zcJson
    }
},

We must return new objects within data so they are not all referenced as we intend. Next mounted, which will run when the component is loaded and mounted with data:

mounted: function() {
    zingchart.render({
        id: this.id,
        height: this.height,
        width: this.width,
        data: this.json
    });
},

This is important because this includes our Zingchart render function. The chart will now be rendered when the component gets loaded. Next our destroy function which will call our Zingchart destroy method when the component is destroyed.

destroyed: function() {
    zingchart.exec(this.id, 'destroy');
},

Now we have a watch function which will serve multiple purposes. First, it will be watching for if the height or the width of the chart changes. Secondly, it will also change the JSON and chart itself if the JSON/values change. This allows us to use two way binding for our charts. We will be using Zingchart resize and setdata functions respectively. Furthermore, we must turn the deep object to true so that it will dig "deep" into our JSON since our JSON structure can get complicated. 

watch: {
    zcHeight: function(newValue, oldValue) {
        zingchart.exec(this.id, 'resize', {
         height: newValue,
            width: this.width
        });
    },
    zcWidth: function(newValue, oldValue) {
        zingchart.exec(this.id, 'resize', {
         height: this.height,
            width: newValue
        });
    },
    json: { // requires a handler function with deep property specified
        handler: function(newValue) {
            zingchart.exec(this.id, 'setdata', {
            data: newValue
            });
        },
        deep:true
    }
},

Finally, we call the template like so:
template: '<div :id="id"></div>'
This is to bind id  to zcId  to render the chart.
Your whole Zingchart component should look like this:

var ZingChartComponent = Vue.component('zingchart-component', {
    // create props to get data from the parent
    props: {
        zcId: {type: String},
  zcHeight: {},
        zcWidth: {},
        zcValues: {type: Array},
        zcJson: {
       type: Object,
            default: function() {
                return {
                    type: 'bar',
                    series:[
                        {
                            values: [15,25,35,45,55,65]
                        }
                    ]
                }
            }
        }
    },
    computed: {
    },
  /*
   * Data acts as the default values for the render method and chart.
   * If you use props all instances of the component will share the same
   * objects. You must return new objects within data so they are not all
   * referenced. Unless you want them to be. Which is not the case here.
   */
    data: function() {
        return {
            id: this.zcId || 'zingchart-autoId-' + Math.ceil(Math.random() * 1000000),
            width: this.zcWidth || '100%',
            height: this.zcHeight || 300,
            json: this.zcJson
        }
    },
    mounted: function() {
        zingchart.render({
            id: this.id,
            height: this.height,
            width: this.width,
            data: this.json
        });
    },
    destroyed: function() {
        zingchart.exec(this.id, 'destroy');
    },
    watch: {
        zcHeight: function(newValue, oldValue) {
       zingchart.exec(this.id, 'resize', {
             height: newValue,
                width: this.width
            });
       },
       zcWidth: function(newValue, oldValue) {
           zingchart.exec(this.id, 'resize', {
            height: this.height,
               width: newValue
           });
       },
       json: { // requires a handler function with deep property specified
           handler: function(newValue) {
               zingchart.exec(this.id, 'setdata', {
                   data: newValue
               });
           },
           deep:true
       }
    },
    template: '<div :id="id"></div>' // bind id to zcId to render  the chart
});

Congrats! We now have a two way binding Vue/Zingchart Pie Chart!

Here is how the chart will look:

Relative Links:

  1. Demo
Did this answer your question?