您的位置:  首页 > 技术杂谈 > 正文

奔跑不止,万象更新|datart 蛰伏十月,浴火重生

2021-11-05 15:00 https://my.oschina.net/u/4270927/blog/5294416 跑象科技 次阅读 条评论

喜闻乐道的大型电视连续剧《davinci啥时更新》终于在21年初秋迎来了尾声,随之而来的是喜闻乐见的新品datart(数艺)正式发版。这一年,大家可以看到的是群里此起彼伏的这样

 

这样。。

 

还有这样。。

 

还能这样?

 

未曾看到的,是一个年轻老团队的奔跑不止,一代敏捷大数据的万象更新,话不多说,都在产品里!我们会继续以长青的心、长新的艺,迎接未来与大家共处共进的时光,在大家的审视中前行,在大家的支持中欣喜。

 


 

「datart 1.0 alpha」

回顾

时间回到2017年初秋,davinci正式在github开源,初版和二版的davinci主要精力放在如何通过配置化方式可以快速将数据做成所需的图表,以满足配置化可视化的需求。彼时我们借鉴了如superset等优秀的开源项目,希望可以开发出适合国人使用习惯的开源可视化平台,帮助企业敏捷完成“大数据的最后一公里”。

 

时间来到2018年初秋,davinci第三版横空出世,基本上将davinci第二版完全推倒重做,因为在平台迭代和社区打磨中,我们的想法逐渐发生了变化,我们希望davinci可以支持企业完成“大数据的最后十公里”,不只是用来制作可视化报表,还可以支持制作数据大屏、支持移动端、支持轻数据处理、支持被整合到其他系统中、支持不同团队协同工作等等。基于这样的认知,我们推倒,重来。

 

第三版davinci在社区中取得了巨大的成功,成百上千家企业在生产中使用了davinci,或者二开为其客户提供了产品和服务。同时我们也在不断思索,数据可视化平台的下一站在哪里?

 

展望

在异世界冒险者的游戏里,每位冒险者都有自己的定位和技能树发展路线,也都有HP(体力值)和MP(魔力值)。数据可视化平台作为一个平台产品,也有自己的产品定位和发展蓝图,也有自己的HP(工程力)和MP(智能力)。数据可视化平台的工程力升级的下一站,是开放化,每个可能扩展的点都应该可插拔化(source、view、chart、viz等),数据可视化平台的智能力升级的下一站,是增强分析,可视化不止局限于看到数据的现状,也可以看到数据的动向。

 

于是,我们推倒、重来,在2021年初秋,datart孕育而生:

 

datart 从产品设计到内核代码全部重写,以一个全新的认知抽象,承载其新的产品使命。初期 datart 会在工程力上迭代拉满,后期会在智能力上探索前行,在开放能力、智能能力、可塑能力上不断增强,打造开源可视化平台的不二首选。

 

在工具平台产品化的道路上,我们相信“重复的力量”,为了平台产品复用度的不断提升,我们愿意不断推倒重来。未来,datart 会在数据和艺术之间找到最佳平衡点,成为数据冒险者们征服数据异世界的传说级利器。

 

亮点

可视化

  • 支持单数据图表编辑、样式、设置、计算字段、筛选器、发布、分享、下载等
  • 支持仪表板/大屏编辑、样式、辅助插件、标签页、联动、跳转、控制器、发布、分享、下载等
  • 支持故事板编辑、设置、发布等
  • 支持可扩展插拔新图表组

 

数据视图

  • 支持视图SQL开发、测试、建模等
  • 支持配置变量、列权限、并发策略

 

数据源

  • 支持JDBC、FILE、HTTP数据源
  • 支持datart服务端数据聚合
  • 支持可扩展插拔新数据源

 

定时任务

  • 支持定时邮件发送图表
  • 支持定时微信发送图表

 

租户权限

  • 支持基于组织租户管理
  • 支持成员邀请、角色管理
  • 支持基于所有资源(可视化/数据视图/数据源/定时任务)的成员/角色细粒度权限管理

 

体验

部署完成进入系统,首次使用需要注册,点击右下角“注册账号”:

 

点击注册之后,会收到确认邮件:

 

 

确认邮件并激活之后,就可以登入系统使用了

 

主导航栏在左侧,首页是可视化目录的展示页面,现在还没有内容,让我们来快速创建一些可视化吧。

 

点击主导航栏上的“数据源”菜单来创建一个mysql数据源,输入名称、选择数据源类型并填写所需的参数,点击“测试连接”,测试成功之后就可以保存了:

 

 

然后点击主导航栏上的“数据视图”菜单,来编辑一个数据视图。点击数据视图右上角的加号按钮,选择“新建数据视图”, 中部的编辑器会创建一个新的页签:

 

在编辑器工具栏中选择刚刚创建的数据源,编写SQL,完成之后点击工具栏上的“执行”按钮,就可以在下方看到执行结果:

 

可以点击执行结果列头部的按钮来编辑字段类型和权限,编辑完成后,点击右上角的保存按钮保存数据视图:

 

接下来,开始创建数据图表和仪表板,点击主导航栏的“可视化”菜单进入可视化目录,并点击目录右上角的加号进行创建。

 

我们先创建一个公共数据图表:

 

 

创建完成后,在目录上选中刚创建的数据图表,右侧区域会显示该图表,由于刚创建还没有内容,点击右上角的编辑按钮进行编辑 :

 

进入编辑界面后,在左上角选择刚才创建的数据视图,出现字段之后,将字段拖拽到中间的“数据”栏中来制作图表:

 

在中间的“样式”栏中可以编辑图表的显示样式:

 

点击右上角保存,一张简单的公共数据图表就制作好了。

 

下面我们来创建一个仪表板,和数据图表的步骤一样,先点击目录右上角的加号,在目录上创建一个仪表板,仪表板可以选择“自动”和“自由”两种布局模式,不同的布局模式适合不同的使用场景;我们先创建一个自动布局的仪表板,同样,创建完成后在目录上选中它,然后在右侧区域点击编辑按钮来进行编辑:

 

在编辑界面,我们可以将刚刚创建的公共数据图表添加到仪表板中来,也可以直接在仪表板内创建数据图表:

 

一番操作,一个简单仪表板就制作出来了:

 

我们可以在左侧目录上选择刚创建的数据图表和仪表板来预览,同时可以在右侧区域顶部点击页签来快速切换:

 

接下来我们创建一个故事板,来演示刚刚创建的可视化作品。点击左上角的“演示”菜单,目录会切换为故事板列表,点击加号创建一个故事板,和仪表板一样,创建完成后在右侧点击编辑按钮来制作故事板:

 

点击左上角的加号按钮添加刚才创建的仪表板,并设置过渡动画,一个故事版就做好了。点击播放按钮,就可以播放刚才制作好的故事版了:

 

以上是 datart 创建可视化作品的一个简单演示,作为一个开源项目,最重要的当然还是它的开放能力,datart 支持用户自定义图表插件,无需重新编译前端代码就可以集成到系统里进行使用,下面介绍怎样简单制作一个自定义图表插件:

 

首先,我们从选择一个绘图引擎开始,如EChartJS是一个图表绘图引擎,而D3JS则是一个更纯粹的绘图引擎。datart很多图表是基于EChartJS的封装,当然也有很多其他优秀的绘图引擎可以选择,兼收并蓄是datart插件化的核心理念。

 

一个最基本的插件主要由以下几部分组成:

  • 图表设置配置项(可选项,定制化图形渲染配置以及基于数据视图的配置项)
  • 图表元信息(包含图表名称、图标信息等)
  • 图表依赖类库(第三方资源类库或CSS样式)
  • 图表生命周期函数(datart回调函数,函数中包含Dom Document,当前图表宽高等信息)

接下来,下面我们以D3JS为例来绘制一个散点图:


function D3JSScatterChart() {
    //【可选】扩展配置图表功能,可配合`数据视图`对数据处理
    config: {},

    //【必须】加载D3JS绘图引擎,此处只需给出CDN的链接即可,Datart会负责加载依赖。
    dependency: ['https://d3js.org/d3.v5.min.js'],

    //【必须】设置图表的基本信息,icon可从Datart Icon图标中选取,暂时不支持自定义
    meta: {
      id: 'demo-d3js-scatter-chart',
      name: '[Plugin Demo] D3JS 散点图',
      icon: 'star',
    },

    //【必须】Datart提供的生命周期函数,其他周期如onUpdated,onResize以及onUnMount
    onMount(options, context) {
      // 通过Datart context获取当前的Dom对象     
      const host = context.document.getElementById(options.containerId);
      var margin = { top: 10, right: 40, bottom: 30, left: 30 },
        width = context.width - margin.left - margin.right,
        height = context.height - margin.top - margin.bottom;

      //【以下内容可忽略】基于D3JS的绘制方法
      this.chart = context.window.d3
        .select(host)
        .append('svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

     // ... 散点图绘图代码已省略,具体参数和使用请参考D3JS手册
  };
}

有了这些基本配置,我们就可以将一个“静态”的散点图显示在datart的图表编辑器界面中并使用了。如果想实现更多高级功能,定制丰富的图表样式、定制基于数据视图的数据配置、定制服务端请求参数,要做到这些需要了解接下来介绍的图表设置配置项(Chart Config)、datart工具类(DHelper)以及生命周期上下文(datart Context),更多配置信息请参考datart用户手册

这里给出注释及完整代码:


/**
 * Datart
 *
 * Copyright 2021
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function D3JSScatterChart({ dHelper }) {
  return {
    config: {
      datas: [
        {
          label: 'metrics',
          key: 'metrics',
          required: true,
          type: 'group',
        },
        {
          label: 'deminsion',
          key: 'deminsion',
          required: true,
          type: 'aggregate',
        },
      ],
      styles: [
        {
          label: 'common.title',
          key: 'scatter',
          comType: 'group',
          rows: [
            {
              label: 'common.color',
              key: 'color',
              comType: 'fontColor',
            },
          ],
        },
      ],
      i18ns: [
        {
          lang: 'zh-CN',
          translation: {
            common: {
              title: '散点图配置',
              color: '气泡颜色',
            },
          },
        },
        {
          lang: 'en',
          translation: {
            common: {
              title: 'Scatter Setting',
              color: 'Bubble Color',
            },
          },
        },
      ],
    },

    isISOContainer: 'demo-d3js-scatter-chart',
    dependency: ['https://d3js.org/d3.v5.min.js'],
    meta: {
      id: 'demo-d3js-scatter-chart',
      name: '[Plugin Demo] D3JS 散点图',
      icon: 'sandiantu',
      requirements: [
        {
          group: [0, 999],
          aggregate: 2,
        },
      ],
    },

    onMount(options, context) {
      if (!context.document) {
        return;
      }

      const host = context.document.getElementById(options.containerId);
      var margin = { top: 10, right: 40, bottom: 30, left: 30 },
        width = context.width - margin.left - margin.right,
        height = context.height - margin.top - margin.bottom;

      // 初始化D3JS绘图区域
      this.chart = context.window.d3
        .select(host)
        .append('svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
    },

    onUpdated(options, context) {
      if (!options.dataset || !options.dataset.columns || !options.config) {
        return;
      }

      // 获取当前绘图区域的宽高
      const clientWidth = context.window.innerWidth;
      const clientHeight = context.window.innerHeight;
      const margin = { top: 40, right: 40, bottom: 40, left: 40 };
      const width = clientWidth - margin.left - margin.right;
      const height = clientHeight - margin.top - margin.bottom;

      // 获取散点图数据及配置
      const { data, style } = this.getOptions(options.dataset, options.config);

      // 绘制基于百分比的横纵坐标轴散点图, 以下是D3JS绘图逻辑
      var x = context.window.d3
        .scaleLinear()
        .domain([0, 100]) // This is the min and the max of the data: 0 to 100 if percentages
        .range([0, width]); // This is the corresponding value I want in Pixel

      this.chart
        .append('g')
        .attr('transform', 'translate(0,' + height + ')')
        .call(context.window.d3.axisBottom(x));

      // X scale and Axis
      var y = context.window.d3
        .scaleLinear()
        .domain([0, 100]) // This is the min and the max of the data: 0 to 100 if percentages
        .range([height, 0]); // This is the corresponding value I want in Pixel

      this.chart.append('g').call(context.window.d3.axisLeft(y));

      // Add 3 dots for 0, 50 and 100%
      this.chart
        .selectAll('whatever')
        .data(data)
        .enter()
        .append('circle')
        .attr('cx', function (d) {
          return x(d.x);
        })
        .attr('cy', function (d) {
          return y(d.y);
        })
        .style('fill', style.color)
        .attr('r', 7);

      this.chart.selectAll('whatever').style('color', 'blue');
    },

    getOptions(dataset, config) {
      // 当前服务端返回的数据集
      const dataConfigs = config.datas || [];

      // 获取样式配置信息
      const styleConfigs = config.styles;
      const groupConfigs = dataConfigs
        .filter(c => c.type === 'group')
        .flatMap(config => config.rows || []);

      // 获取指标类型配置信息
      const aggregateConfigs = dataConfigs
        .filter(c => c.type === 'aggregate')
        .flatMap(config => config.rows || []);

      // 数据转换,根据Datart提供了Helper转换工具
      const objDataColumns = dHelper.transfromToObjectArray(
        dataset.rows,
        dataset.columns,
      );

      const data = objDataColumns.map(dc => {
        return {
          x: dc[dHelper.getValueByColumnKey(aggregateConfigs[0])],
          y: dc[dHelper.getValueByColumnKey(aggregateConfigs[1])],
        };
      });

      var xMinValue = Math.min(...data.map(o => o.x));
      var xMaxValue = Math.max(...data.map(o => o.y));

      var yMinValue = Math.min(...data.map(o => o.y));
      var yMaxValue = Math.max(...data.map(o => o.y));

      // 获取用户配置
      const color = dHelper.getStyleValueByGroup(
        styleConfigs,
        'scatter',
        'color',
      );

      return {
        style: {
          color,
        },
        data: data.map(d => {
          return {
            x: ((d.x || xMinValue - xMinValue) * 100) / (xMaxValue - xMinValue),
            y: ((d.y || yMinValue - yMinValue) * 100) / (yMaxValue - yMinValue),
          };
        }),
      };
    },
  };
}

最终效果图如下:

 

玩转

datart github 下载地址:

https://github.com/running-elephant/datart.git

git@github.com:running-elephant/datart.git

https://github.com/running-elephant/datart/releases/tag/1.0.0-alpha.0

 

百度网盘:

链接:
https://pan.baidu.com/s/1zW_jsTJk4lYxM6VZDoKGJg

提取码:bzuc

 

更多跑象科技资讯:

《36氪首发|从实时数据处理服务切入,「跑象科技」完成近千万元天使轮融资》

https://36kr.com/p/1218126964609668


彩蛋,datart主创团队:

 

From 跑象科技

敏捷大数据求

小星星啦~

如果您喜欢我们的平台

就请移步到Github

帮我们点一下Star吧~

您的举手之劳对我们的鼓励

啦!

 

同时,也欢迎您加入微信群,和技术大神们点对点交流哦~

图片

长按添加加群小助手

烦请告知小助手您的信息来源哦~如:“微信公众号”、“知乎专栏”、“CSDN”、“今日头条”等等~

 长按二维码 一键关注新动向

  • 0
    感动
  • 0
    路过
  • 0
    高兴
  • 0
    难过
  • 0
    搞笑
  • 0
    无聊
  • 0
    愤怒
  • 0
    同情
热度排行
友情链接