• 首页
  • 产品中心
    • 数式Oinone四大产品

      低代码开发平台无代码开发平台集成开发平台AI大模型开发
    • 数式Oinone体系能力

      用户与组织权限管理文件管理消息中心国际化业务审计
    • 数式Oinone核心产品特性

      低无一体面向软件公司场景无限制应用级扩容可分可合
  • 服务中心
    • 客户服务

      预约演示方案咨询私有部署找人定制
    • 开发者

      问答下载
    • Oinone学院

      社区学习

    《精讲面向软件公司的低代码平台——以Oinone为例》

  • 合作伙伴
    渠道申请伙伴名录专家库
  • 关于数式
0571-88757863

Visual Construction:Low-Code and No-Code Integration for Charts in Data Visualization


I. Overview

Data visualization provides the function of custom chart templates to meet business requirements that cannot be satisfied by existing chart templates.

II. How to Use

  1. Click "Chart Templates" at the top of the data visualization page
  2. Click the Create button to pop up the chart template form, fill it in and submit for saving
  3. Locate the newly created chart template and click the "Low-Code & No-Code Integration" button in the operation bar
  4. Click the "Generate SDK" button at the bottom of the pop-up window
  5. After completing the above operation, the page will refresh. Locate the data again, click the "Low-Code & No-Code Integration" button. Now the "Download Template Project" button is clickable. Click it to download the sample code package kunlun-chart-sdk.zip for the custom chart template
  6. After unzipping kunlun-chart-sdk.zip, view the project structure. Execute npm i in the root directory to install dependencies
  7. The custom chart Vue component is located at packages/kunlun-plugin/src/chart/CUSTOM_BAR.vue, where you can modify the custom display and logical processing
  8. After completing the custom code, run npm run build in the root directory to package the code. The packaged JS and CSS files will be found in packages/kunlun-plugin/dist (CSS file will not be generated if there is no CSS in the template, which can be ignored)
  9. Return to the management page of custom chart templates, locate the corresponding data row, click the "Low-Code & No-Code Integration" button again. Upload the generated kunlun-plugin.umd.js and kunlun-plugin.css files in the pop-up window, then click "Confirm" at the bottom to save
  10. Enter the chart editing page, and in the chart category selection, you can see the newly added subcategory "Custom Bar Chart" under the bar chart category. Click to switch
  11. After switching, the chart will change from the default bar chart to the custom chart with a blue border and the text hello chart inside.

II. Example Custom Chart Component

This example implements a bar chart using the echarts library, while the framework's built-in bar chart uses the G2 library. demo-echarts-bar.vue

<template>
  <div class="data-designer-chart-instance demo-echarts-bar" ref="designerChartViewRef">
    <div class="data-designer-chart-container" ref="designerChartViewInnerRef"></div>
  </div>
</template>
<script lang="ts">
  import { defineComponent, onMounted, ref, watch } from 'vue';
  import DataSet from '@antv/data-set';

  import * as echarts from 'echarts/core';
  import { ECharts, EChartsCoreOption } from 'echarts/core';
  import { GridComponent } from 'echarts/components';
  import { BarChart, BarSeriesOption } from 'echarts/charts';
  import { CanvasRenderer } from 'echarts/renderers';
  import { deepClone } from '@oinone/kunlun-dependencies';
  import {
    filterDimensionScaleColumns,
    isSameObj,
    ChartTypeEnum,
    IChartData,
    IChartDataResult,
    chartViewMixin,
    isNeedRerenderChart,
    isShowChatView,
    watchEchartsSize,
    ChartRenderEngine
  } from '@oinone/kunlun-data-designer-core';

  echarts.use([GridComponent, BarChart, CanvasRenderer]);

  export default defineComponent({
    props: {
      ...chartViewMixin.props
    },
    data() {
      return {
        engine: ChartRenderEngine.ECHARTS,
        chartType: [ChartTypeEnum.MAP_CHINA]
      };
    },
    mixins: [chartViewMixin],
    setup(props, { emit }) {
      const chart = ref<ECharts>();
      const designerChartViewRef = ref<HTMLElement>(null as any);
      const designerChartViewInnerRef = ref<HTMLElement>(null as any);
      onMounted(() => {
        initChart();
      });
      let option = {} as EChartsCoreOption;

      function initChart() {
        chart.value = echarts.init(designerChartViewInnerRef.value);
        option = {
          yAxis: {
            type: 'value'
          }
        };
      }

      let oldChartData = {} as IChartData;
      watch(
        () => props.chartData,
        (newVal) => {
          if (!newVal || !chart.value) {
            return;
          }
          if (!isNeedRerenderChart(newVal, oldChartData)) {
            oldChartData = deepClone(newVal);
            return;
          }
          render(chart.value!, newVal, props.chartDataResult);
          oldChartData = deepClone(newVal);
        },
        {
          immediate: true,
          deep: true
        }
      );
      let oldChartDataResult = {} as IChartDataResult;

      function watchDataList(chartData: IChartData, chartDataResult: IChartDataResult) {
        oldChartDataResult = deepClone(props.chartDataResult);
        if (!chart.value) {
          initChart();
        }
        render(chart.value!, chartData, chartDataResult);
      }

      // 监听数据的变动自动重新渲染
      watch(
        () => props.chartDataResult.data,
        () => {
          if (isSameObj(oldChartDataResult, props.chartDataResult)) {
            return;
          }
          if (!designerChartViewRef.value) {
            onMounted(() => {
              watchDataList(props.chartData, props.chartDataResult);
            });
          } else {
            watchDataList(props.chartData, props.chartDataResult);
          }
        },
        { immediate: true, deep: true }
      );

      /**
     * 自定义渲染逻辑
     * @param chart echarts图表对象
     * @param chartData 图表模板的定义
     * @param chartDataResult chartDataResult.data存放的是后端返回的图表数据
     */
      function render(chart: ECharts, chartData: IChartData, chartDataResult: IChartDataResult) {
        if (!isShowChatView(chartData)) {
          return;
        }
        if (!isSameObj(chartData, chartDataResult.chartData)) {
          return;
        }

        const {
          scales = [],
          dimensions = [],
        } = filterDimensionScaleColumns(chartData);

        const dataList = !scales.length || !dimensions.length ? [] : ((chartDataResult.data! || []) as any[]);

        dataList.forEach((a) => {
          if (dimensions.length && !a.name) {
            a.name = a[dimensions[0].chartField.displayName];
          }
          if (scales.length && !a.value) {
            a.value = a[scales[0].chartField.displayName] || null;
          }
        });
        const dv = new DataSet.DataView().source(dataList);

        option.xAxis = {
          type: 'category',
          data: dv.rows?.map((a) => a?.name)
        };
        option.series = [
          {
            type: 'bar',
            data: dv.rows?.map((a) => a?.value)
          } as BarSeriesOption
        ];
        chart.setOption(option);
      }

      // 监听图表容器大小
      watchEchartsSize(props, chart!);

      return { designerChartViewRef, designerChartViewInnerRef, chart };
    }
  });
</script>

(Ⅰ) Registering the Template

import { ChartRenderEngine, ChartRenderType, registerChartComponent } from '@oinone/kunlun-data-designer-core';
import component from './demo-echarts-bar.vue';

registerChartComponent({
  engine: ChartRenderEngine.ECHARTS,
  render: ChartRenderType.CANVAS,
  chartTemplateCode: 'test002'
},
  {
    component
  } as any
);

(Ⅲ) Effect Display

Edit this page
Last Updated:1/15/26, 4:02 AM
Prev
Feature Introduction:Data Visualization - How to Reference Charts, Reports, and Dashboards in Projects
Next
Visual Query:Data Visualization - How to Customize Query Data Methods
默认页脚
Copyright © 2026 Mr.Hope