HelpBot Assistant

How can I help you?

Working with data in Vue Chart component

3 Feb 202624 minutes to read

The Vue Chart component supports multiple data binding approaches to suit different application scenarios. Data can be bound from local JSON arrays, dynamically loaded on demand with lazy loading, or fetched from remote services using various adaptor patterns. This guide covers all available data binding methods, helping you choose the right approach for your use case based on data size, performance requirements, and backend architecture.

Choosing a data binding approach

| Method | Best For | Advantages | Considerations |
|——–|———-|————|—————–|
| Local data | Small to medium datasets | Simple setup, no network latency, instant rendering | All data must be in memory |
| Common datasource | Multiple series sharing data | Reduces redundancy, single update point | Limited to data common across series |
| Lazy loading | Large datasets with scrolling | Loads only visible data, better performance | Requires server-side pagination |
| Remote data (OData/WebAPI) | Backend-driven data | Scalable, centralized data management, real-time updates | Network latency, requires service setup |
| Offline mode | Data caching with client-side actions | Eliminates repeated requests, faster interactions | Initial load time, memory constraints |

Local data

Bind simple JSON data to the chart using the dataSource property in the series configuration. Map the JSON fields to the xName and yName properties to specify which data fields represent the x and y axis values.

<template>
  <div id="app">
    <ejs-chart id="container" :title='title' :primaryXAxis='primaryXAxis'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='month' yName='sales' name='Sales'> </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script setup>
import { provide } from "vue";

import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";


const seriesData = [
  { month: 'Jan', sales: 35 }, { month: 'Feb', sales: 28 },
  { month: 'Mar', sales: 34 }, { month: 'Apr', sales: 32 },
  { month: 'May', sales: 40 }, { month: 'Jun', sales: 32 },
  { month: 'Jul', sales: 35 }, { month: 'Aug', sales: 55 },
  { month: 'Sep', sales: 38 }, { month: 'Oct', sales: 30 },
  { month: 'Nov', sales: 25 }, { month: 'Dec', sales: 32 }
];
const primaryXAxis = {
  valueType: 'Category'
};
const title = "Olympic Medals";

provide('chart', [ColumnSeries, Category]);

</script>
<style>
#container {
  height: 350px;
}
</style>
<template>
    <div id="app">
         <ejs-chart id="container" :title='title' :primaryXAxis='primaryXAxis'>
            <e-series-collection>
                <e-series :dataSource='seriesData' type='Column' xName='month' yName='sales' name='Sales'> </e-series>
            </e-series-collection>
        </ejs-chart>
    </div>
</template>
<script>

import { ChartComponent, SeriesCollectionDirective, SeriesDirective, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";

export default {
name: "App",
components: {
    'ejs-chart': ChartComponent,
    'e-series-collection': SeriesCollectionDirective,
    'e-series': SeriesDirective
  },
  data() {
    return {
      seriesData: [
            { month: 'Jan', sales: 35 }, { month: 'Feb', sales: 28 },
            { month: 'Mar', sales: 34 }, { month: 'Apr', sales: 32 },
            { month: 'May', sales: 40 }, { month: 'Jun', sales: 32 },
            { month: 'Jul', sales: 35 }, { month: 'Aug', sales: 55 },
            { month: 'Sep', sales: 38 }, { month: 'Oct', sales: 30 },
            { month: 'Nov', sales: 25 }, { month: 'Dec', sales: 32 }
              ],
        primaryXAxis: {
           valueType: 'Category'
        },
      title: "Olympic Medals"
    };
  },
  provide: {
    chart: [ColumnSeries, Category]
  }
};
</script>
<style>
 #container {
    height: 350px;
 }
</style>

Common datasource

Bind the same JSON data to all series by setting the dataSource property at the chart level instead of the series level. This approach is useful when multiple series share the same dataset and you want to update data from a single source. Each series independently maps its own properties to the common data fields.

<template>
  <div id="app">
    <ejs-chart id="container" :title='title' :primaryXAxis='primaryXAxis' :dataSource='seriesData'>
      <e-series-collection>
        <e-series type='Column' xName='month' yName='sales'> </e-series>
        <e-series type='Column' xName='month' yName='sales1'> </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script setup>
import { provide } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";

const seriesData = [
  { month: 'Jan', sales: 35, sales1: 28 }, { month: 'Feb', sales: 28, sales1: 35 },
  { month: 'Mar', sales: 34, sales1: 32 }, { month: 'Apr', sales: 32, sales1: 34 },
  { month: 'May', sales: 40, sales1: 32 }, { month: 'Jun', sales: 32, sales1: 40 },
  { month: 'Jul', sales: 35, sales1: 55 }, { month: 'Aug', sales: 55, sales1: 35 },
  { month: 'Sep', sales: 38, sales1: 30 }, { month: 'Oct', sales: 30, sales1: 38 },
  { month: 'Nov', sales: 25, sales1: 32 }, { month: 'Dec', sales: 32, sales1: 25 }
];
const primaryXAxis = {
  valueType: 'Category'
};
const title = "Olympic Medals";

provide('chart', [ColumnSeries, Category]);

</script>
<style>
#container {
  height: 350px;
}
</style>
<template>
  <div id="app">
    <ejs-chart id="container" :title='title' :primaryXAxis='primaryXAxis' :dataSource='seriesData'>
      <e-series-collection>
        <e-series type='Column' xName='month' yName='sales'> </e-series>
        <e-series type='Column' xName='month' yName='sales1'> </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script>

import { ChartComponent, SeriesCollectionDirective, SeriesDirective, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";

export default {
  name: "App",
  components: {
    'ejs-chart': ChartComponent,
    'e-series-collection': SeriesCollectionDirective,
    'e-series': SeriesDirective
  },
  data() {
    return {
      seriesData: [
        { month: 'Jan', sales: 35, sales1: 28 }, { month: 'Feb', sales: 28, sales1: 35 },
        { month: 'Mar', sales: 34, sales1: 32 }, { month: 'Apr', sales: 32, sales1: 34 },
        { month: 'May', sales: 40, sales1: 32 }, { month: 'Jun', sales: 32, sales1: 40 },
        { month: 'Jul', sales: 35, sales1: 55 }, { month: 'Aug', sales: 55, sales1: 35 },
        { month: 'Sep', sales: 38, sales1: 30 }, { month: 'Oct', sales: 30, sales1: 38 },
        { month: 'Nov', sales: 25, sales1: 32 }, { month: 'Dec', sales: 32, sales1: 25 }
      ],
      primaryXAxis: {
        valueType: 'Category'
      },
      title: "Olympic Medals"
    };
  },
  provide: {
    chart: [ColumnSeries, Category]
  }
};
</script>
<style>
#container {
  height: 350px;
}
</style>

Remote data

Bind remote data from a web service by using the DataManager class. The DataManager simplifies communication with REST APIs, OData services, and custom web endpoints. It requires minimal configuration—typically just the service URL and an appropriate adaptor—then handles all request/response processing. Assign the DataManager instance to the dataSource property in the series, and map the response fields to xName and yName properties. You can also use the query property to filter, sort, or paginate data on the server.

<template>
  <div id="app">
    <ejs-chart id="container" :primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis' :title='title'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='CustomerID' yName='Freight' :query='queries'>
        </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script setup>
import { provide } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { DataManager, Query } from '@syncfusion/ej2-data';


let dataManager = new DataManager({
  url: 'https://services.syncfusion.com/vue/production/api/orders'
});
let query = new Query().take(5).where('Estimate', 'lessThan', 3, false);


const seriesData = dataManager;
const queries = query;
const primaryXAxis = {
  valueType: 'Category',
};
const primaryYAxis = {
  title: 'Freight rate in U.S. dollars'
};
const title = 'Container freight rate';

provide('chart', [ColumnSeries, Category]);

</script>
<style>
#container {
  height: 350px;
}
</style>
<template>
  <div id="app">
    <ejs-chart id="container" :primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis' :title='title'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='CustomerID' yName='Freight' :query='queries'>
        </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script>

import { ChartComponent, SeriesCollectionDirective, SeriesDirective, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { DataManager, Query } from '@syncfusion/ej2-data';



let dataManager = new DataManager({
  url: 'https://services.syncfusion.com/vue/production/api/orders'
});
let query = new Query().take(5).where('Estimate', 'lessThan', 3, false);

export default {
  name: "App",
  components: {
    'ejs-chart': ChartComponent,
    'e-series-collection': SeriesCollectionDirective,
    'e-series': SeriesDirective
  },
  data() {
    return {
      seriesData: dataManager,
      queries: query,
      primaryXAxis: {
        valueType: 'Category',
      },
      primaryYAxis: {
        title: 'Freight rate in U.S. dollars'
      },
      title: 'Container freight rate'
    };
  },
  provide: {
    chart: [ColumnSeries, Category]
  }
};
</script>
<style>
#container {
  height: 350px;
}
</style>

Binding data using ODataAdaptor

OData is a standardized protocol for creating and consuming data via REST APIs. Use the ODataAdaptor with DataManager to retrieve data from OData services. The adaptor automatically constructs the correct query syntax and handles standard OData conventions.
Example use case: Querying a product sales service that implements OData v3.0 filtering, sorting, and pagination.

<template>
  <div id="app">
    <ejs-chart id="container" :primaryXAxis='primaryXAxis' :title='title'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='CustomerID' yName='Freight' :query='queries'>
        </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script setup>
import { provide } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { DataManager, Query, ODataAdaptor } from '@syncfusion/ej2-data';


let dataManager = new DataManager({
  url: 'https://services.odata.org/V3/Northwind/Northwind.svc/Orders/',
  adaptor: new ODataAdaptor(),
  crossDomain: true
});
let query = new Query();


const seriesData = dataManager;
const queries = query;
const primaryXAxis = {
  valueType: 'Category'
};
const title = 'Order Details';

provide('chart', [ColumnSeries, Category]);

</script>
<style>
  #container {
    height: 350px;
  }
</style>
<template>
  <div id="app">
    <ejs-chart id="container" :primaryXAxis='primaryXAxis' :title='title'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='CustomerID' yName='Freight' :query='queries'>
        </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script>

import { ChartComponent, SeriesCollectionDirective, SeriesDirective, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { DataManager, Query, ODataAdaptor } from '@syncfusion/ej2-data';



let dataManager = new DataManager({
  url: 'https://services.odata.org/V3/Northwind/Northwind.svc/Orders/',
  adaptor: new ODataAdaptor(),
  crossDomain: true
});
let query = new Query();

export default {
  name: "App",
  components: {
    'ejs-chart': ChartComponent,
    'e-series-collection': SeriesCollectionDirective,
    'e-series': SeriesDirective
  },
  data() {
    return {
      seriesData: dataManager,
      queries: query,
      primaryXAxis: {
        valueType: 'Category'
      },
      title: 'Order Details'
    };
  },
  provide: {
    chart: [ColumnSeries, Category]
  }
};
</script>
<style>
  #container {
    height: 350px;
  }
</style>

Binding data using ODataV4Adaptor

ODataV4 is an improved and more standardized version of the OData protocol, with enhanced query capabilities and better JSON support. Use the ODataV4Adaptor to consume ODataV4 services. For more information on ODataV4 specifications, refer to the odata documentation.

When to use ODataV4Adaptor: If your backend service implements OData v4.0, prefer this adaptor over the older ODataAdaptor for better compliance and features.

<template>
  <div id="app">
    <ejs-chart id="container" :primaryXAxis='primaryXAxis' :title='title'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='CustomerID' yName='Freight' :query='queries'>
        </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script setup>
import { provide } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { DataManager, Query, ODataV4Adaptor } from '@syncfusion/ej2-data';


let dataManager = new DataManager({
  url: 'https://services.odata.org/V4/Northwind/Northwind.svc/Orders',
  adaptor: new ODataV4Adaptor()
});
let query = new Query();


const seriesData = dataManager;
const queries = query;
const primaryXAxis = {
  valueType: 'Category'
};
const title = 'Order Details';

provide('chart', [ColumnSeries, Category]);

</script>
<style>
  #container {
    height: 350px;
  }
</style>
<template>
  <div id="app">
    <ejs-chart id="container" :primaryXAxis='primaryXAxis' :title='title'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='CustomerID' yName='Freight' :query='queries'>
        </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script>

import { ChartComponent, SeriesCollectionDirective, SeriesDirective, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { DataManager, Query, ODataV4Adaptor } from '@syncfusion/ej2-data';



let dataManager = new DataManager({
  url: 'https://services.odata.org/V4/Northwind/Northwind.svc/Orders',
  adaptor: new ODataV4Adaptor()
});
let query = new Query();

export default {
  name: "App",
  components: {
    'ejs-chart': ChartComponent,
    'e-series-collection': SeriesCollectionDirective,
    'e-series': SeriesDirective
  },
  data() {
    return {
      seriesData: dataManager,
      queries: query,
      primaryXAxis: {
        valueType: 'Category'
      },
      title: 'Order Details'
    };
  },
  provide: {
    chart: [ColumnSeries, Category]
  }
};
</script>
<style>
  #container {
    height: 350px;
  }
</style>

Web API adaptor

Use the WebApiAdaptor to consume custom REST APIs that follow a standard response format. This adaptor is ideal for backends that do not implement OData but provide REST endpoints returning JSON data.
Expected response format:
The Web API must return a JSON object with two properties:

  • Items: Array of data objects for the chart
  • Count: Total number of records (useful for pagination)
<template>
  <div id="app">
    <ejs-chart id="container" :primaryXAxis='primaryXAxis' :title='title'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='CustomerID' yName='Freight' :query='queries'>
        </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script setup>
import { provide } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { DataManager, Query, WebApiAdaptor } from '@syncfusion/ej2-data';


let dataManager = new DataManager({
  url: 'https://services.syncfusion.com/vue/production/api/orders',
  adaptor: new WebApiAdaptor()
});
let query = new Query();


const seriesData = dataManager;
const queries = query;
const primaryXAxis = {
  valueType: 'Category'
};
const title = 'Order Details';

provide('chart', [ColumnSeries, Category]);

</script>
<style>
  #container {
    height: 350px;
  }
</style>
<template>
  <div id="app">
    <ejs-chart id="container" :primaryXAxis='primaryXAxis' :title='title'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='CustomerID' yName='Freight' :query='queries'>
        </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script>

import { ChartComponent, SeriesCollectionDirective, SeriesDirective, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { DataManager, Query, WebApiAdaptor } from '@syncfusion/ej2-data';



let dataManager = new DataManager({
  url: 'https://services.syncfusion.com/vue/production/api/orders',
  adaptor: new WebApiAdaptor()
});
let query = new Query();

export default {
  name: "App",
  components: {
    'ejs-chart': ChartComponent,
    'e-series-collection': SeriesCollectionDirective,
    'e-series': SeriesDirective
  },
  data() {
    return {
      seriesData: dataManager,
      queries: query,
      primaryXAxis: {
        valueType: 'Category'
      },
      title: 'Order Details'
    };
  },
  provide: {
    chart: [ColumnSeries, Category]
  }
};
</script>
<style>
  #container {
    height: 350px;
  }
</style>

Example response:

The Web API should structure its response as shown below. The Items array contains the actual data records, and Count indicates the total available records (supporting server-side pagination).

{
    Items: [{..}, {..}, {..}, ...],
    Count: 830
}

Custom adaptor

Create a custom adaptor by extending one of the built-in adaptors (typically ODataAdaptor) to add custom logic for request/response handling. Override the processResponse method to transform or enrich the response data. Common use cases include adding serial numbers, reformatting dates, or adding computed fields before the chart renders the data.

<template>
  <div id="app">
    <ejs-chart id="container" :primaryXAxis='primaryXAxis' :title='title'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='CustomerID' yName='Sno' :query='queries'>
        </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script setup>
import { provide } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { DataManager, Query, ODataAdaptor } from '@syncfusion/ej2-data';

class SerialNoAdaptor extends ODataAdaptor {
    processResponse() {
        let i = 0;
        //calling base class processResponse function
        let original = super.processResponse.apply(this, arguments);
        //Adding serial number
        original.result.forEach((item) => item['Sno'] = ++i);
        return { result: original.result, count: original.count };
    }
}

let dataManager = new DataManager({
  url: 'https://services.syncfusion.com/vue/production/api/orders',
  adaptor: new SerialNoAdaptor()
});
let query = new Query();


const seriesData = dataManager;
const queries = query;
const primaryXAxis = {
  valueType: 'Category'
};
const title = 'Order Details';

provide('chart', [ColumnSeries, Category]);

</script>
<style>
  #container {
    height: 350px;
  }
</style>
<template>
  <div id="app">
    <ejs-chart id="container" :primaryXAxis='primaryXAxis' :title='title'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='CustomerID' yName='Sno' :query='queries'>
        </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script>

import { ChartComponent, SeriesCollectionDirective, SeriesDirective, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { DataManager, Query, ODataAdaptor } from '@syncfusion/ej2-data';

class SerialNoAdaptor extends ODataAdaptor {
    processResponse() {
        let i = 0;
        //calling base class processResponse function
        let original = super.processResponse.apply(this, arguments);
        //Adding serial number
        original.result.forEach((item) => item['Sno'] = ++i);
        return { result: original.result, count: original.count };
    }
}

let dataManager = new DataManager({
  url: 'https://services.syncfusion.com/vue/production/api/orders',
  adaptor: new SerialNoAdaptor()
});
let query = new Query();

export default {
  name: "App",
  components: {
    'ejs-chart': ChartComponent,
    'e-series-collection': SeriesCollectionDirective,
    'e-series': SeriesDirective
  },
  data() {
    return {
      seriesData: dataManager,
      queries: query,
      primaryXAxis: {
        valueType: 'Category'
      },
      title: 'Order Details'
    };
  },
  provide: {
    chart: [ColumnSeries, Category]
  }
};
</script>
<style>
  #container {
    height: 350px;
  }
</style>

Offline mode

When using remote data binding, all filtering, sorting, and pagination normally happen on the server. To improve responsiveness and reduce server load, enable offline mode: the chart loads all data once during initialization, then handles all interactions client-side. Set the offline property of DataManager to true to activate this behavior.

Use offline mode when:

  • Your dataset is relatively small (fits comfortably in browser memory)
  • You want instant filtering and sorting without server round-trips
  • Network latency is a significant usability concern
  • You prefer to minimize server requests during user interactions

Caution: Offline mode loads the entire dataset at once, which may impact initial load time and memory usage for large datasets.

<template>
  <div id="app">
    <ejs-chart id="container" :primaryXAxis='primaryXAxis' :title='title'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='CustomerID' yName='Freight' :query='queries'>
        </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script setup>
import { provide } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { DataManager, Query, ODataAdaptor } from '@syncfusion/ej2-data';


let dataManager = new DataManager({
  url: 'https://services.syncfusion.com/vue/production/api/orders',
  adaptor: new ODataAdaptor(),
  offline: true
});
let query = new Query();


const seriesData = dataManager;
const queries = query;
const primaryXAxis = {
  valueType: 'Category'
};
const title = 'Order Details';

provide('chart', [ColumnSeries, Category]);

</script>
<style>
  #container {
    height: 350px;
  }
</style>
<template>
  <div id="app">
    <ejs-chart id="container" :primaryXAxis='primaryXAxis' :title='title'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='CustomerID' yName='Freight' :query='queries'>
        </e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script>

import { ChartComponent, SeriesCollectionDirective, SeriesDirective, ColumnSeries, Category } from "@syncfusion/ej2-vue-charts";
import { DataManager, Query, ODataAdaptor } from '@syncfusion/ej2-data';



let dataManager = new DataManager({
  url: 'https://services.syncfusion.com/vue/production/api/orders',
  adaptor: new ODataAdaptor(),
  offline: true
});
let query = new Query();

export default {
  name: "App",
  components: {
    'ejs-chart': ChartComponent,
    'e-series-collection': SeriesCollectionDirective,
    'e-series': SeriesDirective
  },
  data() {
    return {
      seriesData: dataManager,
      queries: query,
      primaryXAxis: {
        valueType: 'Category'
      },
      title: 'Order Details'
    };
  },
  provide: {
    chart: [ColumnSeries, Category]
  }
};
</script>
<style>
  #container {
    height: 350px;
  }
</style>

Empty points

Data points with null or undefined values are treated as empty points. Empty data points are skipped and not rendered in the chart. When using the points property to define individual data items, customize empty points with the emptyPointSettings property in the series configuration. By default, empty points create a gap in the series line or bar.

Default behavior: Empty points use the Gap mode, which leaves a blank space in the chart visualization.

<template>
  <div id="app">
    <ejs-chart id="container" :title='title' :primaryXAxis='primaryXAxis'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='month' yName='sales' name='Sales'
          :emptyPointSettings='emptyPointSettings1'></e-series>
        <e-series :dataSource='seriesData' type='Line' xName='month' yName='sales' name='Sales Compare'
          :emptyPointSettings='emptyPointSettings2'></e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script setup>
import { provide } from "vue";
import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, ColumnSeries, LineSeries, Category } from "@syncfusion/ej2-vue-charts";

const seriesData = [
  { month: 'Jan', sales: 35 }, { month: 'Feb', sales: null },
  { month: 'Mar', sales: 34 }, { month: 'Apr', sales: 32 },
  { month: 'May', sales: 40 }, { month: 'Jun', sales: 32 },
  { month: 'Jul', sales: undefined }, { month: 'Aug', sales: 55 },
  { month: 'Sep', sales: 38 }, { month: 'Oct', sales: 30 },
  { month: 'Nov', sales: 25 }, { month: 'Dec', sales: 32 }
];
const primaryXAxis = {
  valueType: 'Category'
};
const emptyPointSettings1 = {
  mode: "Average",
  fill: 'grey'
};
const emptyPointSettings2 = {
  mode: "Gap"
};
const title = "Olympic Medals";

provide('chart', [ColumnSeries, LineSeries, Category]);

</script>
<style>
#container {
  height: 350px;
}
</style>
<template>
  <div id="app">
    <ejs-chart id="container" :title='title' :primaryXAxis='primaryXAxis'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='month' yName='sales' name='Sales'
          :emptyPointSettings='emptyPointSettings1'></e-series>
        <e-series :dataSource='seriesData' type='Line' xName='month' yName='sales' name='Sales Compare'
          :emptyPointSettings='emptyPointSettings2'></e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script>
import { ChartComponent, SeriesCollectionDirective, SeriesDirective, ColumnSeries, LineSeries, Category } from "@syncfusion/ej2-vue-charts";

export default {
  name: "App",
  components: {
    "ejs-chart": ChartComponent,
    "e-series-collection": SeriesCollectionDirective,
    "e-series": SeriesDirective
  },
  data() {
    return {
      seriesData: [
        { month: 'Jan', sales: 35 }, { month: 'Feb', sales: null },
        { month: 'Mar', sales: 34 }, { month: 'Apr', sales: 32 },
        { month: 'May', sales: 40 }, { month: 'Jun', sales: 32 },
        { month: 'Jul', sales: undefined }, { month: 'Aug', sales: 55 },
        { month: 'Sep', sales: 38 }, { month: 'Oct', sales: 30 },
        { month: 'Nov', sales: 25 }, { month: 'Dec', sales: 32 }
      ],
      primaryXAxis: {
        valueType: 'Category'
      },
      emptyPointSettings1: {
        mode: "Average",
        fill: 'grey'
      },
      emptyPointSettings2: {
        mode: "Gap"
      },
      title: "Olympic Medals"
    };
  },
  provide: {
    chart: [ColumnSeries, LineSeries, Category]
  }
};
</script>
<style>
#container {
  height: 350px;
}
</style>

Customizing empty point

Assign a specific color to empty points by setting the fill property in the emptyPointSettings object. This allows you to visually distinguish empty data points from regular data in your chart. Border for a empty point can be set by border property.

<template>
  <div id="app">
    <ejs-chart id="container" :title='title' :primaryXAxis='primaryXAxis'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='month' yName='sales' name='Sales'
          :emptyPointSettings='emptyPointSettings'></e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script setup>
import { provide } from "vue";
import { ChartComponent as EjsChart, ColumnSeries, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, LineSeries, Category } from "@syncfusion/ej2-vue-charts";

const seriesData = [
  { month: 'Jan', sales: 35 }, { month: 'Feb', sales: null },
  { month: 'Mar', sales: 34 }, { month: 'Apr', sales: 32 },
  { month: 'May', sales: 40 }, { month: 'Jun', sales: 32 },
  { month: 'Jul', sales: undefined }, { month: 'Aug', sales: 55 },
  { month: 'Sep', sales: 38 }, { month: 'Oct', sales: 30 },
  { month: 'Nov', sales: 25 }, { month: 'Dec', sales: 32 }
];
const primaryXAxis = {
  valueType: 'Category'
};
const emptyPointSettings = {
  mode: "Average",
  fill: 'red',
  border: { width: 2, color: 'violet' }
};
const title = "Olympic Medals";

provide('chart', [ColumnSeries, LineSeries, Category]);

</script>
<style>
#container {
  height: 350px;
}
</style>
<template>
  <div id="app">
    <ejs-chart id="container" :title='title' :primaryXAxis='primaryXAxis'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Column' xName='month' yName='sales' name='Sales'
          :emptyPointSettings='emptyPointSettings'></e-series>
      </e-series-collection>
    </ejs-chart>
  </div>
</template>
<script>
import { ChartComponent, SeriesCollectionDirective, SeriesDirective, ColumnSeries, LineSeries, Category } from "@syncfusion/ej2-vue-charts";

export default {
  name: "App",
  components: {
    "ejs-chart": ChartComponent,
    "e-series-collection": SeriesCollectionDirective,
    "e-series": SeriesDirective
  },
  data() {
    return {
      seriesData: [
        { month: 'Jan', sales: 35 }, { month: 'Feb', sales: null },
        { month: 'Mar', sales: 34 }, { month: 'Apr', sales: 32 },
        { month: 'May', sales: 40 }, { month: 'Jun', sales: 32 },
        { month: 'Jul', sales: undefined }, { month: 'Aug', sales: 55 },
        { month: 'Sep', sales: 38 }, { month: 'Oct', sales: 30 },
        { month: 'Nov', sales: 25 }, { month: 'Dec', sales: 32 }
      ],
      primaryXAxis: {
        valueType: 'Category'
      },
      emptyPointSettings: {
        mode: "Average",
        fill: 'red',
        border: { width: 2, color: 'violet' }
      },
      title: "Olympic Medals"
    };
  },
  provide: {
    chart: [ColumnSeries, LineSeries, Category]
  }
};
</script>
<style>
#container {
  height: 350px;
}
</style>

Handling no data

When the chart has no data available to render, use the noDataTemplate property to display a custom layout within the chart area. This template can include messages, images, icons, or interactive elements (such as a load button) to guide the user. The template maintains design consistency and improves user experience when data is unavailable. Once data becomes available, the chart automatically updates and replaces the template with the visualization.

<template>
  <div id="app">
    <ejs-chart style='display:block' ref='chart' :theme='theme' :load='load' :loaded='loaded'
      :noDataTemplate='noDataTemplate' align='center' id='chartcontainer' :title='title' :subTitle='subTitle'
      :primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis' :chartArea='chartArea' :tooltip='tooltip'
      :width='width'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Line' xName='x' yName='y' :marker='marker'
          :animation='{ enable: true }' width='2'> </e-series>
      </e-series-collection>
    </ejs-chart>

    <div v-if="!hasData" class="no-data-button-overlay">
      <ejs-button content="Load Data" iconCss="e-icons e-refresh" cssClass="load-data-btn e-outline" :isPrimary="false"
        @click="loadData"></ejs-button>
    </div>
  </div>
</template>
<style>
#noDataTemplateContainer {
  height: inherit;
  width: inherit;
}

.no-data-button-overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  margin-top: 60px;
  /* Adjust this to position below the no-data message */
  z-index: 10;
}

.load-data-btn {
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  margin-top: 50px;
}

.light-bg {
  background-color: #fafafa;
  color: #000000;
}

.template-align img {
  max-width: 150px;
  /* Adjust size as needed */
  max-height: 150px;
  margin-top: 55px;
}

.template-align {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}
</style>
<script setup>
import { provide } from "vue";

import { ChartComponent as EjsChart, SeriesCollectionDirective as ESeriesCollection, SeriesDirective as ESeries, ColumnSeries, LineSeries, Category, Tooltip, DataLabel, Highlight, loaded } from "@syncfusion/ej2-vue-charts";
import { ButtonComponent } from "@syncfusion/ej2-vue-buttons";

import { ref } from 'vue';

let hasData = false;
let seriesData = [
  { x: 'January', y: 19173 },
  { x: 'February', y: 17726 },
  { x: 'March', y: 19874 },
  { x: 'April', y: 19391 },
  { x: 'May', y: 20072 },
  { x: 'June', y: 19233 }
];

//Initializing Primary X Axis
const primaryXAxis = {
  valueType: 'Category',
  majorGridLines: {
    width: 0
  },
  majorTickLines: {
    width: 0
  },
};

const chartArea = {
  border: { width: 0 }
};

const primaryYAxis = {
  title: 'Production (in million pounds)',
  titleStyle: {
    fontWeight: '600'
  },
  majorTickLines: {
    width: 0
  },
  lineStyle: {
    width: 0
  }
};

const marker = {
  visible: true,
  width: 7, height: 7
};
const load = (args) => {
  seriesData = hasData ? [
    { x: 'January', y: 19173 },
    { x: 'February', y: 17726 },
    { x: 'March', y: 19874 },
    { x: 'April', y: 19391 },
    { x: 'May', y: 20072 },
    { x: 'June', y: 19233 }
  ] : [];
};
const loadData = (args) => {
  seriesData = [
    { x: 'January', y: 19173 },
    { x: 'February', y: 17726 },
    { x: 'March', y: 19874 },
    { x: 'April', y: 19391 },
    { x: 'May', y: 20072 },
    { x: 'June', y: 19233 }
  ];
  hasData = true;

  const values = seriesData.map(d => d.y);
  const min = Math.min(...values);
  const max = Math.max(...values);
  const range = max - min;

  const chart = this.$refs.chart.ej2Instances;
  chart.primaryYAxis.minimum = Math.floor(min - range * 0.1);
  chart.primaryYAxis.maximum = Math.ceil(max + range * 0.1);
  chart.primaryYAxis.interval = Math.ceil(range / 5);
  chart.series[0].animation.enable = true;
  chart.refresh();
};


const noDataTemplate = `
                <div id="noDataTemplateContainer" class="light-bg">
                    <div class="template-align">    
                        <img src="no-data.png" alt="No Data"/>
                    </div>
                    <div class="template-align">
                        <p style="font-size: 15px; margin: 10px 0 10px;"><strong>No data available to display.</strong></p>
                    </div>
                </div>`;
const width = '100%';
const title = "Milk Production in US - 2025";
const subTitle = "Source: nass.usda.gov";
const tooltip = { enable: true, header: 'Milk Production', format: '${point.x} : <b>${point.y}M</b>' };

provide('chart', [Category, LineSeries, DataLabel, Tooltip, Highlight]);



</script>
<style>
#container {
  height: 350px;
}
</style>
<template>
  <div id="app">
    <ejs-chart style='display:block' ref='chart' :theme='theme' :load='load' :loaded='loaded'
      :noDataTemplate='noDataTemplate' align='center' id='chartcontainer' :title='title' :subTitle='subTitle'
      :primaryXAxis='primaryXAxis' :primaryYAxis='primaryYAxis' :chartArea='chartArea' :tooltip='tooltip'
      :width='width'>
      <e-series-collection>
        <e-series :dataSource='seriesData' type='Line' xName='x' yName='y' :marker='marker'
          :animation='{ enable: true }' width='2'> </e-series>
      </e-series-collection>
    </ejs-chart>

    <div v-if="!hasData" class="no-data-button-overlay">
      <ejs-button content="Load Data" iconCss="e-icons e-refresh" cssClass="load-data-btn e-outline" :isPrimary="false"
        @click="loadData"></ejs-button>
    </div>
  </div>
</template>
<script>

import { ChartComponent, SeriesCollectionDirective, SeriesDirective, ColumnSeries, LineSeries, Category, Tooltip, DataLabel, Highlight, loaded } from "@syncfusion/ej2-vue-charts";
import { ButtonComponent } from "@syncfusion/ej2-vue-buttons";

export default {
  name: "App",
  components: {
    'ejs-chart': ChartComponent,
    'ejs-button': ButtonComponent,
    'e-series-collection': SeriesCollectionDirective,
    'e-series': SeriesDirective
  },
  data() {
    return {
      hasData: false,
      seriesData: [
        { x: 'January', y: 19173 },
        { x: 'February', y: 17726 },
        { x: 'March', y: 19874 },
        { x: 'April', y: 19391 },
        { x: 'May', y: 20072 },
        { x: 'June', y: 19233 }
      ],

      //Initializing Primary X Axis
      primaryXAxis: {
        valueType: 'Category',
        majorGridLines: {
          width: 0
        },
        majorTickLines: {
          width: 0
        },
      },

      chartArea: {
        border: { width: 0 }
      },

      primaryYAxis: {
        title: 'Production (in million pounds)',
        titleStyle: {
          fontWeight: '600'
        },
        majorTickLines: {
          width: 0
        },
        lineStyle: {
          width: 0
        }
      },

      marker: {
        visible: true,
        width: 7, height: 7
      },

      noDataTemplate: `
                <div id="noDataTemplateContainer" class="light-bg">
                    <div class="template-align">    
                        <img src="no-data.png" alt="No Data"/>
                    </div>
                    <div class="template-align">
                        <p style="font-size: 15px; margin: 10px 0 10px;"><strong>No data available to display.</strong></p>
                    </div>
                </div>`,
      width: '100%',
      title: "Milk Production in US - 2025",
      subTitle: "Source: nass.usda.gov",
      tooltip: { enable: true, header: 'Milk Production', format: '${point.x} : <b>${point.y}M</b>' }
    };
  },
  provide: {
    chart: [Category, LineSeries, DataLabel, Tooltip, Highlight]
  },
  methods: {
    load(args) {
      this.seriesData = this.hasData ? [
        { x: 'January', y: 19173 },
        { x: 'February', y: 17726 },
        { x: 'March', y: 19874 },
        { x: 'April', y: 19391 },
        { x: 'May', y: 20072 },
        { x: 'June', y: 19233 }
      ] : [];
    },
    loaded(args) {
    },
    loadData() {
      this.seriesData = [
        { x: 'January', y: 19173 },
        { x: 'February', y: 17726 },
        { x: 'March', y: 19874 },
        { x: 'April', y: 19391 },
        { x: 'May', y: 20072 },
        { x: 'June', y: 19233 }
      ];
      this.hasData = true;

      const values = this.seriesData.map(d => d.y);
      const min = Math.min(...values);
      const max = Math.max(...values);
      const range = max - min;

      const chart = this.$refs.chart.ej2Instances;
      chart.primaryYAxis.minimum = Math.floor(min - range * 0.1);
      chart.primaryYAxis.maximum = Math.ceil(max + range * 0.1);
      chart.primaryYAxis.interval = Math.ceil(range / 5);
      chart.series[0].animation.enable = true;
      chart.refresh();
    }
  }
};
</script>
<style>
#container {
  height: 350px;
}

#noDataTemplateContainer {
  height: inherit;
  width: inherit;
}

.no-data-button-overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  margin-top: 60px;
  /* Adjust this to position below the no-data message */
  z-index: 10;
}

.load-data-btn {
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  margin-top: 50px;
}

.light-bg {
  background-color: #fafafa;
  color: #000000;
}

.template-align img {
  max-width: 150px;
  /* Adjust size as needed */
  max-height: 150px;
  margin-top: 55px;
}

.template-align {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}
</style>