数据可视化中图表的低无一体

介绍

数据可视化提供了自定义图表模板的功能,以满足现有图表模板无法满足业务需求的情况。

如何使用

  1. 点击数据可视化页面头部的“图表模板”
    image.png
  2. 点击创建按钮后弹出图表模板表单,填写后提交保存
    image.png
  3. 找到刚刚创建的图表模板,点击操作栏中的“低无一体”按钮
    image.png
  4. 点击弹窗底部的“生成sdk”按钮
    image.png
  5. 上一步操作完成后会重新刷新页面,再次找到该条数据,点击“低无一体”按钮,再次进来可以看到“下载模板工程”的按钮已经可以点击了,点击该按钮就可以下载到该自定义图表模板的示例代码包文件kunlun-chart-sdk.zip
    image.png
  6. 解压kunlun-chart-sdk.zip后我们可以看到工程结构,在根目录下执行npm i安装依赖
    image.png
  7. 可以看到packages/kunlun-plugin/src/chart/CUSTOM_BAR.vue是我们自定义的图表vue组件,可以修改里面的自定义展示和逻辑处理
  8. 完成自定义代码后去根目录运行npm run build打包代码,打包后可以在packages/kunlun-plugin/dist下看到打包后的js和css文件(如模板中无css则不会生成css文件,无需理会)
    image.png
  9. 回到自定义图表模板的管理页面,找到对应的数据行,再次点击“低无一体”按钮,在弹窗内上传上一步生成的kunlun-plugin.umd.jskunlun-plugin.css文件,上传完成后点击弹窗底部的“确定”按钮保存
    image.png
  10. 进入图表的编辑页面,在图表分类选择处,可以看到柱状图的分类下有我们新增的“自定义柱状图”的子类,点击切换
    image.png
  11. 切换后可以看到图表已经从开始柱状图变成了我们在前面自定义的蓝色边框样式,内部是hello chart文字的图表。
    image.png

示例自定义图表组件

本例子以echarts的图表库实现柱状图,框架自带的是以G2的库实现的柱状图
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 '@kunlun/dependencies';
import {
  filterDimensionScaleColumns,
  isSameObj,
  ChartTypeEnum,
  IChartData,
  IChartDataResult,
  chartViewMixin,
  isNeedRerenderChart,
  isShowChatView,
  watchEchartsSize,
  ChartRenderEngine
} from '@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>
注册该模板
import { ChartRenderEngine, ChartRenderType, registerChartComponent } from '@kunlun/data-designer-core';
import component from './demo-echarts-bar.vue';

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

数据可视化中图表的低无一体

Oinone社区 作者:nation原创文章,如若转载,请注明出处:https://doc.oinone.top/designer/70.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
nation的头像nation数式员工
上一篇 2023年6月20日 pm4:07
下一篇 2023年11月2日 pm1:58

相关推荐

  • 如何把平台功能菜单加到项目中?

    概述 在使用Oinone低代码平台进行项目开发的过程中,会存在把平台默认提供的菜单加到自己的项目中。这篇文章介绍实现方式,以角色管理为例。 1. 低代码情况 即项目是通过后端代码初始化菜单的方式。 通常在 XXXMenu.java类通过@UxMenu注解的方式,代码片段如下: 此种情况与添加项目本地的菜单无区别,具体代码: @UxMenu(value = "账号管理", icon = "icon-yonghuguanli") class AccountManage { @UxMenu("用户管理") @UxRoute(value = CustomerCompanyUserProxy.MODEL_MODEL, title = "用户管理") class CompanyUserManage { } @UxMenu("角色管理") @UxRoute(value = AuthRole.MODEL_MODEL, module = AdminModule.MODULE_MODULE, title = "角色管理") class RoleManage { } @UxMenu("操作日志") @UxRoute(value = OperationLog.MODEL_MODEL, module = AdminModule.MODULE_MODULE/***菜单所挂载的模块**/) class OperateLog { } } 2. 无代码情况 在界面设计器中,新建菜单–>选择绑定已有页面,进行发布即可。

    2024年4月19日
    1.5K00
  • 创建与编辑一体化

    在业务操作中,用户通常期望能够在创建页面后立即进行编辑,以减少频繁切换页面的步骤。我们可以充分利用Oinone平台提供的创建与编辑一体化功能,使操作更加高效便捷。 通过拖拽实现表单页面设计 在界面设计器中,我们首先需要设计出对应的页面。完成页面设计后,将需要的动作拖入设计好的页面。这个动作的关键在于支持一个功能,即根据前端传入的数据是否包含id来判断是创建操作还是编辑操作。 动作的属性配置如下: 前端自定义动作 一旦页面配置完成,前端需要对这个动作进行自定义。以下是一个示例的代码: @SPI.ClassFactory( ActionWidget.Token({ actionType: [ActionType.Server], model: '模型', name: '动作的名称' }) ) export class CreateOrUpdateServerActionWidget extends ServerActionWidget { @Widget.Reactive() protected get updateData(): boolean { return true; } } 通过以上步骤,我们实现了一个更智能的操作流程,使用户能够在创建页面的同时进行即时的编辑,从而提高了整体操作效率。这种创建与编辑一体化的功能不仅使操作更加顺畅,同时也为用户提供了更灵活的工作流程。

    2023年11月21日
    1.4K00
  • 界面设计器 扩展字段的查询上下文

    默认情况下oinone平台对于查询条件,只提供的当前登录用户这一个配置,但是允许开发者扩展 开发者可以在前端代码的main.ts进行扩展 import { SessionContextOptions, ModelFieldType } from '@kunlun/dependencies'; const currentDeptOption = { ttype: ModelFieldType.String, value: '$#{currentDept}', displayName: '当前登录部门', label: '当前登录部门' }; SessionContextOptions.push(currentDeptOption as any); 加上上面的代码,然后再去界面设计器,我们就会发现,多了一个配置

    2023年11月8日
    1.3K00
  • 集成接口测试功能

    API、 WebService、数据库的测试功能

    2025年8月26日
    42800
  • 工作流动态表单最佳实践

    需求背景 为了提高操作效率并简化流程设计过程,应对伙伴们反映的在流程设计器中,即使填写/审批流程相同,不同模型也需重新配置的问题,我们引入了“动态表单”功能。此功能旨在减少重复配置的需求,通过设置节点名称和绑定视图,便可实现审批流程相同而视图不同,从而使得相同的审批流程可以被高效重复利用。 为确保伙伴们能够更加方便的使用动态表单,我们将典型示例整合至“工作流”中。本节将结合这些示例详细阐述“动态表单”功能的应用方法。 使用主要分为两个步骤:流程设计和动态表单配置。 流程设计 触发节点配置 应用:工作流 选择模型:动态表单任务 触发场景:更新数据时 选择更新字段:触发次数 填写/审批节点配置 动态表单按钮设置为启用状态。 数据来源设置为触发节点。 动态表单函数默认有一条内置函数,选中即可。 数据保存方式、填写人等信息,同从前使用方式。 在动态表单模式下,数据权限的管理将不再由流程设计器控制,而是由用户所填写的视图进行控制。 例如,若希望用户在“一审”阶段不能修改某字段,则应在设计视图时将相关字段设为只读模式。同样,若某些信息不宜在“一审”阶段展示给客户,相应字段应在设计过程中被设置为隐藏状态。 若需在“一审”节点接收“一填”阶段的结果,数据来源设置为“一填[动态表单]”。其他配置项保持不变,按照上述说明进行设置。 若希望“二填”节点的数据由用户填写,并希望内容处于空白状态,可将数据来源设置为“触发”节点。 通过这种配置,“二填”节点的数据将不会受到“一填”和“一审”节点数据的影响。 二审节点的配置同一审,此处省略。 “终审”节点希望接收到“一审”节点的数据,可以将数据来源设置为一审。 动态表单配置 首先创建动态表单任务:工作流->动态表单任务->创建,给流程起个名字。 节点任务配置 流程名:通过下拉菜单选择,数据为动态表单任务中,创建的流程信息。 节点名称:【强制】确保与流程设计中的节点名称完全一致,否则将无法正确匹配到对应节点的视图。 模型:选定用于绑定节点视图的模型。 视图:选择视图前须先确定模型,系统将自动列出所选模型下的通过UI创建的视图供选择。 查看配置效果 在工作流模块->动态表单->动态表单任务,点击“详情”,可以看到该流程所配置的节点信息。 动态表单任务详情页 流程触发 点击“触发”按钮将使触发次数自动递增。在流程设计器中配置触发节点时,我们已设定“触发次数”字段的变化作为流程启动的条件。 触发节点配置筛选条件 通过完成上述操作,我们已成功配置动态表单。现在可以利用触发节点的筛选条件,来确定触发按钮被点击后,所启动的流程。 自定义动态表单函数 如果所提供的示例未能满足您的需求,您可以根据自身的需求,对触发条件和动态表单函数进行相应的定制与调整。 动态表单函数定义规则如下: namespace:强制为 WorkflowFunctionConstant.FUNCTION_NAMESPACE。 fun:强制以 WorkflowFunctionConstant.WORKFLOW_CUSTOM_VIEW_FUNCTION_PREFIX 为前缀。 入参说明: 参数1:节点数据,例如,配合instanceof可以判断当前是填写节点(WriteNode)还是审批节点(ApprovalNode)。 参数2:触发节点的模型数据,如果您的触发节点不确定,可以通过Map接收参数。 参数3:该节点所配置数据来源的数据。 出参说明:视图,如果出参为null,流程终止运行,错误信息提示为“流程节点执行失败,动态表单函数获取视图为空”。 @Slf4j @Component @Fun(WorkflowFunctionConstant.FUNCTION_NAMESPACE) public class DynamicFormCustom { /** * 根据动态表单任务获取视图 * * @param node 节点数据 * @param dynamicFormTask 触发节点数据 * @param dataObj 源数据 */ @Function.fun(WorkflowFunctionConstant.WORKFLOW_CUSTOM_VIEW_FUNCTION_PREFIX + "fetchDynamicFormFunction") @Function.Advanced(displayName = "[内置]获取动态表单函数") @Function(name = "fetchDynamicFormFunction") public View fetchDynamicFormFunction(Node node, DynamicFormTask dynamicFormTask, Map<String, Object> dataObj) { DynamicFormTaskNode dynamicFormTaskNode = fetchDynamicFormTaskNode(node, dynamicFormTask); if (dynamicFormTaskNode == null) { return null; } dynamicFormTaskNode.fieldQuery(DynamicFormTaskNode::getView); return dynamicFormTaskNode.getView(); } private DynamicFormTaskNode fetchDynamicFormTaskNode(Node node, DynamicFormTask dynamicFormTask) { List<DynamicFormTaskNode> dynamicFormTaskNodeList = Models.origin().queryListByWrapper(Pops.<DynamicFormTaskNode>lambdaQuery() .from(DynamicFormTaskNode.MODEL_MODEL) .eq(DynamicFormTaskNode::getNodeName, node.getNodeName()) .eq(DynamicFormTaskNode::getTaskCode, dynamicFormTask.getCode()) ); if (CollectionUtils.isEmpty(dynamicFormTaskNodeList)) { return null; } if (dynamicFormTaskNodeList.size() > 1) { log.error("工作流动态获取表单函数视图匹配多个,{}", JsonUtils.toJSONString(dynamicFormTaskNodeList)); } return dynamicFormTaskNodeList.get(0); } }

    2024年8月22日
    3.4K00

Leave a Reply

登录后才能评论