thsc-datav-dynamic-chart

动态图表组件

Usage no npm install needed!

<script type="module">
  import thscDatavDynamicChart from 'https://cdn.skypack.dev/thsc-datav-dynamic-chart';
</script>

README

动态柱状图

用于展示随着时间趋势进行变化的数据,比如排名。

调用方式

程序设计思路

动态柱状图(DynamicHistogram)

时间轴控制栏(Timeline)

时间轴有一个需要注意的地方:下一帧动画必须等待上一帧动画结束后,才能执行。

单线程同步队列(区别于线程池的并发消费队列)。

setTimeout+调用自身,套娃执行。

配置项说明

人员信息

这个组件是ifind的AI创新企业库项目中提出来的,因此第一版的产品需求、交互和UI设计都是源自ifind这边的人员,具体信息如下:

职责 姓名
产品经理 郭颍安
交互设计 朱亦吴
UI设计 罗伟胤、贾柯柯(提供渐变色)
前端业务开发 王超明

防踩坑指南

折线图自定义坐标刻度数量,必须使用tickValues

因为我们的坐标轴采用的是scalePoint比例尺,这种比例尺是不支持通过axis.ticks()来设置刻度数量的,默认会把所有刻度都显示出来。

另外tickValues设置的数据,必须在你绘图的真实数据范围内,比如你的真实数据是2010年到2020年的,那么tickValues就不能设置2000

一定要配置defaultDate

注意一定要配置defaultDate,否则会出现柱子能绘制,但是文本无法绘制的问题。

因为不设置的话,如果默认初始化后马上执行chart.playByDate(xxx),会导致短时间绘制两帧的数据,而第一帧尚未执行到transition的结束动画就会结束掉,这样结束动画中修改属性的操作就不会执行,比如不会将fill-opacity设置为1,就会导致文本无法显示。

更新日志

2020.09.27.01 【v0.0.1】

增加了如下功能: 1、支持柱子悬浮显示tooltip:通过tooltip配置项进行设置 2、支持点击柱子后改变柱子颜色的功能:通过histogram.bar.style配置项进行设置;注意,点击交互仅在暂停动画后生效,以避免页面展示太乱 3、根据UI稿,开放了更多的配置项,比如:设置柱子高度:histogram.bar.height 4、支持不显示动画:通过animation.show进行设置 5、支持默认展示某个日期:通过defaultDate进行设置,可以用于默认进来展示静态图的功能 6、可以设置自动播放的时间间隔:通过play.intervalTime进行设置 其他配置项可以看下demo.html中的说明信息

注意: 1、颜色渐变这个,目前颜色是随机生成的;等UI给我色表后,会再更新上去 2、圆角目前仅支持四个角设置相同的圆角,尚不支持左侧直角、右侧圆角 3、左侧省份和柱子之间的那根粗一点的线尚不支持

2020.09.27.02 【v0.1.0】

增加了如下功能:

1、支持渐变色:通过histogram.bar.style.color配置,页面展示多少根柱子就配置多少对颜色

2、增加了获取当前动画播放状态的接口:

const status = dynamicHistogram.getStatus();
switch (status) {
    case DynamicHistogram.STATUS.DISABLED:
        alert('未开启动画')
        break;
    case DynamicHistogram.STATUS.PLAYING:
        alert('动画正在播放中...')
        break;
    case DynamicHistogram.STATUS.PAUSED:
        alert('动画已暂停')
        break;
    case DynamicHistogram.STATUS.FINISHED:
        alert('动画已播放结束')
        break;
    }
}

状态说明:

// 动画当前的状态:0-未开启动画,1-播放中,2-暂停,3-播放结束
DynamicHistogram.STATUS = {
  DISABLED: 0,
  PLAYING: 1,
  PAUSED: 2,
  FINISHED: 3
};

3、增加了柱子的点击回调函数:通过histogram.bar.action.onClick配置:

histogram: {
    bar: {
        action: {
            // 点击的回调函数,第一个参数是柱子的数据,第二个参数是当前播放的日期
            onClick: function (data, date) {
                console.log(`您点击了${data.name}这个柱子,当前播放到了这个日期:${date}`);
            },
        },
    }
}

2020.09.27.03 【v0.2.0】

修正了如下BUG:

1、切换标签页后,动画乱掉的问题

增加了如下功能:

1、动画步进的回调:

  animation: {
    // 事件回调函数
    action: {
      // 动画播放完成的回调
      onFinished() {
        console.log('动画播放完了');
      },
    },
  },

2、动画播放完后的回调:

  animation: {
    // 事件回调函数
    action: {
      // 每次步进的回调
      onStep(date) {
        console.log(`当前播放的时间:${date}`);
      },
    },
  },

2020.09.27.04 【v0.3.0】

增加了如下功能:

1、柱子左侧文本的格式化函数:

histogram: {
    title: {
      formatter(data) {
        if (data.name.length > 3) {
          return `${data.name.substr(0, 3)}...`;
        }
        return data.name;
      },
    },
}

2020.09.28.01 【v0.4.0】

增加了如下功能:

1、增加重新绘制的方法:

dynamicHistogram.redraw(data, option);

修正了如下BUG:

1、最后一个年份不会播放

2020.09.28.02 【v0.4.1】

修正了如下BUG:

1、点击暂停之后,再点击恢复,会跳过一个年份

2、修正从头播放时,动画不连续、部分柱子出现空白的问题。需要修改从头播放的调用方式,如下:

document.querySelector('#replay').onclick = () => {
    dynamicHistogram.playByDate(1960, function () {
        dynamicHistogram.resume();
    });
}

2020.10.19.01 【v0.5.0】更新了一大波内容

修改了CDN链接地址

增加了DynamicLine类

padding的配置由数组改为了字符串,且需要带上px单位

histogram配置更名为series

x轴的tickFormat默认去掉了千分位的格式

默认不再隐藏y轴刻度,需要设置option.axis.y.show: false才会隐藏y轴刻度

(TODO)tooltip的init方法从constructor中移除了,老的DynamicHistogram中请记得主动调用init方法

待修复的BUG/待完善的功能:

(Done)多条线的情况下,会重复绘图

(Done)坐标轴从scaleTime改为point,否则非交易日会有问题

(Done)折线图和柱状图不兼容的问题

独立于d3.js打包

_formatData没考虑日期有-/的情况

update方法抽离出来,应该有一个总控的update,并且都已pure function的模式去写各个组件的子update方法,通过参数进行控制,比如动画时长这种。

足够丰富的demo展示效果

tooltip闪烁的问题

第一个点没动画的问题

最后一个axisPointer和阴影有空隙的问题(偶现)

(Done)柱状图的tooltip无法显示

--是我把init方法注释掉了

待记录的笔记:

动态折线图

阴影

2020.10.28.01 【v0.6.0】(比例尺切换)

将x轴的比例尺从d3.scaleTime改为d3.scalePoint

(对应需要修改的配置项为:)

1、传入的原始数据的date属性,从Date对象改为普通的数字或者字符串

2、label.formatter需要调整,直接返回date即可

3、series.axis.x.tickFormat需要调整,直接返回d即可

4、series.tooltip.formatter需要调整,直接返回date即可

2020.10.29.01 【v0.6.1】(折线图动画修复)

playByDate(date)传入的date参数必须是纯数字,比如2019、20201029这种

2020.11.27.01 【v0.7.0】(柱状图优化)

BUG类

1、修正柱子颜色配置未生效的问题

2、修正柱子右侧标签无法formatter的问题,现在可以通过option.series.value.format进行设置

3、修正初始动画出现会延时一个动画周期的问题

4、修正柱子右侧标签的位置无法调整的问题,现在可以通过诸如transform: "translateY(-5px)"这样的CSS配置项进行调整

功能类

1、增加了背景图的配置项option.grid.background.style.background

2、支持给柱子左侧的文本设置对齐方式:state.option.series.title.style.textAnchor: start | middle | end | inherit

3、支持在柱子左侧显示排名信息,可以是图标和纯数字,通过option.series.icon进行设置,类似这样:

// 图标
icon: {
    show: true,
    content: [
      {
        type: 'url',
        value: 'http://datav.iwencai.com/micro-video/page/images/title.png',
      },
      {
        type: 'url',
        value: 'http://s.thsi.cn/js/company/hithink_design/assets/hux-logo_ok.png',
      },
      {
        type: 'url',
        value: 'http://datav.iwencai.com/micro-video/page/images/title.png',
      },
    ],
    style: {
      image: {
        radius: 10,
      },
      text: {
        fill: '#272841',
        opacity: 1,
        // stroke: '#00F',
        fontWeight: 'bold',
        fontSize: 15,
        transform: "translateY(-2px)",
      }
    },
},

2020.11.28.01 【v0.8.0】(Rank图优化)

BUG类

1、修正柱子默认的透明度

2、修正柱子右侧数值默认加了百分号的问题,现在可以通过option.value.formatter对右侧数值进行自定义格式化

3、新柱子出现时,默认文本全透明,以避免左上角出现文本重叠的问题

功能类

1、现在可以通过option.bar.style对柱子进行个性化样式设置

2、将柱子名称的位置改到了柱子左侧

3、增加了排名的展示,位于柱子左侧;支持图标和数字两种形式

2020.12.02.01 【v0.9.0】(Rank、Histogram优化)

功能类

1、现在可以通过icon.style.image.width和icon.style.image.height对图标的大小进行设置

2020.12.04.01 【v0.10.0】(Rank、Histogram优化)

功能类

1、现在可以通过splitLine给绘图区域添加背景分割线

// 页面上的分割线
splitLine: [{
    // 方向:horizontal水平,vertical垂直
    orientation: 'vertical',
    left: 100,
    // 线的宽度
    thickness: 1,
    // 线条的数量
    number: 4,
    // 样式
    style: {
        fill: 'red',
        opacity: 0.1,
        transform: "translateY(-10px)"
    },
}],

2020.12.07.01 【v0.11.0】(Rank、Histogram优化)

功能类

1、可以通过bar.style.radius对rank图的圆角大小进行设置

2、可以通过bar.style.x对rank图的柱子设置左侧偏移量;注意该设置区别于transform,会改变柱子长度(自适应)

3、调整了splitLine的left属性,将其重命名为x

4、由于bar和splitLine的位置是具有关联性的,因此不建议对这2个元素设置transform属性,否则会导致二者的相对位置出现问题;如果必须设置,则二者的transform的值需要完全一致。

2020.12.09.01 【v0.12.0】(Rank优化)

功能类

1、增加了custom配置项,可以自定义绘制图形

/**
* 自定义的内容区域
* @param {D3Object} g 某一行的D3的g元素
* @param {object} data 单个数据
* @param {number} index 当前数据的下标,从0开始,最大值为数据长度减去1
* @param {boolean} staticMode 是否为静态模式(静态模式是指初始的时候,一次性加载全屏数据)
*/ 
custom: (g, data, index, staticMode) => {
    console.log(data, index);
    const customGroup = g.append('g').attr('class', 'customGroup')
    .attr('x', 0)
    .attr('width', 300);

    const text = customGroup
    .append('text')
    .datum(data)
    .attr('class', 'myCustomText')
    // TODO:这个视具体数据字段名来设置
    .attr('value', (d) => d.price)
    .attr('text-anchor', 'end')
    .attr('x', 550)
    .attr('y', 0)
    .attr('fill', 'red')
    .text((d) => {
        if (index > 7 && index < 10) {
            return `涨跌幅:${d.price}`;
        }
        return `${d.price}`;
    });

    // 图标
    const icon = customGroup
    .append("svg:image")
    .datum(data)
    .attr("xlink:href", (d) => {
        if (d.price > 200) {
            return "./assets/a.png";
        } else if (d.price < 200) {
            return "./assets/c.png";
        }
        return "./assets/b.png";

    })
    .attr('x', 550)
    .attr('y', -20)
    .attr("width", "20")
    .attr("height", "20");

    const backgroundBar = customGroup
    .append('rect')
    .attr('fill-opacity', 0.2)
    .attr('height', 30)
    .attr('x', 30)
    .attr('rx', 0)
    // 渐变色
    .style('fill', '#000')

    if (staticMode) {
        text.attr('fill-opacity', 1);
        icon.attr('opacity', 1);
        backgroundBar.attr('width', 600);

    } else {
        // 后续顶部出现的柱子,如果一开始就把各个元素画上去,会和上一次的元素叠加,比较难看,因此这里用了动画延迟画上去
        text.attr('fill-opacity', 0)
            .transition()
            .duration(1500)
            .attr('fill-opacity', 1);

        icon.attr('fill-opacity', 0)
            .transition()
            .duration(1500)
            .attr('opacity', 1);

        backgroundBar.attr('width', 0)
            .transition()
            .duration(1500)
            .attr('width', 600);
    }
},

2、增加了绘制每一根柱子的回调函数animation.action.onTip:

  animation: {
    show: true,
    action: {
      // 每根柱子的绘制
      onTick(lineGroup, index) {
      if (index >= 7) {
        const text = lineGroup.select('.myCustomText');
        const value = text.attr('value');
        text.text(`涨跌幅:${value}`);
      }
      },
    },
  },

3、增加了grid.margin配置项,可以设置绘图区域的边距,注意目前仅grid.margin[0]是有效的(即marginTop):

// 绘图区域
grid: {
    // 图表左右上下间距
    margin: [30, 150, 0, 130],
},

2021.02.05 【v0.13.0】(折线图回调信息中增加位置数据)

功能类

1、折线图回调信息中增加位置数据,便于业务方自定义绘制特殊的标记。

具体内容为:

(Done)1、this.getCurrentData拆分为2个方法,其中一个计算数据的方法,返回当前时间的每个点的数据

(Done)2、onStep传入每个点的数据、每个点的坐标位置信息(通过scale计算)

(Done)3、将绘图的svg元素传递给用户(如何限制用户不去修改这个元素自身?我应该单独创建一个custom的g元素暴露给用户)

4、提供一些绘图的基础函数,方便用户快速绘制圆点啥的

--div和页面的坐标如何转换呢?是相同的么?我试试

--提供参考的snippet也行,让用户可以照着二次修改

5、精简包的大小

6、修改代码使其符合ESLint规范

7、恢复文件大小检查.check_file_size.sh

2021.02.07 【v0.13.0】通过Rollup实现按需加载,精简代码体积

优化类

是否需要剔除对D3的引入?或者自动判断,如果页面上没有D3,就自动引入D3.js

三种图的配置文件是否要分开?强行统一成一个,会存在问题。

记得恢复注释掉的从package.json中获取版本号的功能

2021.02.08 【v0.14.0】折线图增加取消阴影的功能

功能类

通过将series.area.style.opacity设置为0,可以实现取消阴影的功能。

2021.02.19 【v0.15.0】折线图设置Y轴文字样式和domain

功能类

通过series.axis.y.domain,可以自由定义Y轴的范围。

2021.06.02:该配置已废弃,改为通过axis.max和axis.min设置范围的最大最小值;domain字段用来设置轴线的样式

2021.02.20 【v0.15.1】修正多实例无法绘制的问题

BUG类

将全局、跨实例唯一的state改为和类的实例绑定

优化类

对图形增加了UUID的设计,解决当一个页面存在多个实例时,元素ID冲突的问题。

注意由于现在每个实例的根元素都有一个唯一的id属性,因此步进回调配置项(onStep)添加了第四个参数,将每个实例的根元素(这是一个DIV)对象返回给用户,方便用户画自定义的HTML内容,类似这样:

// 每次步进的回调
onStep(date, data, container, divContainer) {
  // console.log(`当前播放的时间:${date}`, data);
  console.log('container', container);
  console.log('parent', container.parentNode);

  const point = data[0];
  const radius = 10;
  const lineWidth = 2;
  if (date % 30 === 0) {
    const group = container.append('g').attr('transform', `translate(${point.x}, ${point.y})`).attr('class', 'customCircle');

    // 画圆圈-外圈
    group.append('circle').attr('r', 15).attr('fill', 'rgba(0, 0, 0, 0.1)').attr('stroke', '#393682').attr('stroke-width', lineWidth).attr('stroke-dasharray', '5 2');

    // 画圆圈-内圈
    group.append('circle').attr('r', radius).attr('fill', '#393682');

    // 画圆圈-文本
    group.append('text').attr('x', -5).attr('y', 6).style('font-weight', 'bold').text(eventNumber);

    // 画圆圈和label的连线
    group.append('line')
    .attr('class', 'testline')
    .attr('x1', 0)
    .attr('y1', -1 * radius)
    .attr('x2', 0)
    .attr('y2', - 130)
    .attr('stroke', '#393682')
    .attr('stroke-width', lineWidth)
    .attr('stroke-dasharray', '5 2');

    // 画div
    const label = document.createElement('div');
    label.style = `position:absolute; width: 200px; height: 50px; left: ${point.x + 128}px; top: ${point.y - 100}px; background-color: rgba(0, 0, 100, 0.1);`;
    label.innerHTML = `日期:${point.date}<br/>
    股价:${point.value}元`;
    divContainer.append(() => label);
    
    eventNumber ++;
  }
},

TODO:

一些写死的id需要改为动态

柱状图相关的代码需要修改state

2021.02.22 【v2.0.0】 (向前不兼容)支持多Y轴设计,增加版本号管理

教训:之前设计配置文件的时候没有考虑后续扩展,把Y轴的配置设计成了一个,现在如果要扩展,就得修改配置结构了(甚至原始数据结构都可能得修改),无法向前兼容。

坐标轴相关的配置,需要由之前的对象形式,改为数组形式,类似这样:

// 坐标轴
axis: [
  {
    show: true,
    // 坐标轴(axis)位于直角坐标系(grid)中的位置, 可选类型有 bottom | left | top | right
    position: 'bottom',
    // 坐标轴的x、y偏移量,用于微调坐标文字的位置
    offset: [0, 0],
    // 显示几个刻度/数值(大致数值,不一定精准)
    tickNumber: 6,
    tickValues: xTicks,
    // 刻度数值的格式自定义
    tickFormat(d) {
      return d;
    },
    style: {
      // 刻度线和刻度上的文本的颜色
      color: '#70717D',
      opacity: 1,
      fontSize: 12,
      // 刻度线的颜色
      tickColor: '#ECECF7',
    },
  },
  {
    show: true,
    position: 'left',
    // 坐标轴的x、y偏移量,用于微调坐标文字的位置
    offset: [0, 0],
    // 坐标轴的范围,默认是按照原始数据的最大最小进行设置;如果设置为null,则采用默认值
    domain: [0, null],
    // 显示几个刻度/数值
    tickNumber: 5,
    tickFormat(d) {
      return d;
    },
    style: {
      // 刻度线和刻度上的文本的颜色
      // color: '#70717D',
      color: 'red',
      opacity: 1,
      // stroke: '#00F',
      // fontWeight: 'bold',
      fontSize: 30,
      // 刻度线的颜色
      tickColor: '#ECECF7',
    },
  },
  {
    show: true,
    position: 'right',
    // 坐标轴的x、y偏移量,用于微调坐标文字的位置
    offset: [0, 0],
    // 坐标轴的范围,默认是按照原始数据的最大最小进行设置;如果设置为null,则采用默认值
    domain: [0, null],
    // 显示几个刻度/数值
    tickNumber: 5,
    tickFormat(d) {
      return d;
    },
    style: {
      // 刻度线和刻度上的文本的颜色
      // color: '#70717D',
      color: 'red',
      opacity: 1,
      // stroke: '#00F',
      // fontWeight: 'bold',
      fontSize: 30,
      // 刻度线的颜色
      tickColor: '#ECECF7',
    },
  },
],

TODO1:目前仍然只是一个临时设计,仅支持上下左右四个轴(left、right、top、bottom),且仍然只支持一个统一的X轴数据和Y轴数据,不支持针对不同数据设置不同的轴。

接下去需要将轴和数据的对应关系在配置中进行绑定;且能绑定某一个具体的数据项。

yScale也不能只有一个,否则无法针对不同数据设置不同的Y轴范围;目前我临时处理,挖了一个坑在这里(代码中搜索:临时处理,这里写死了多个Y轴的情况下,每个Y轴显示的数据范围都必须是一致的)。

TODO2:其他的页面子元素也有类似问题,比如label、tooltip等等,不应该在子元素类内部处理多个的情况,应该是在最外面的类里面实例化多个子元素。

2021.06.02 【v2.1.0】增加坐标轴线的样式设置功能,修改axis.domain的定义

改为通过axis.max和axis.min设置范围的最大最小值;domain字段用来设置轴线的样式

2021.06.09 【v2.2.0】Rank排名柱状图增加倒序功能

针对DynamicRank组件,增加了倒序功能,适用于诸如“北向资金流出”等场景,数值越小的,越靠后出现。

可以通过配置项的reverse进行设置,默认情况下reverse=false,表示正序排列。

2021.06.17 【v2.3.0】折线图增加设置坐标轴刻度值和轴线距离的功能

通过配置项的axis.tickPadding进行设置。

2021.11.15 【v2.4.0】柱状图优化

柱状图增加指定某些数据一直显示的功能

通过配置项的alwaysShow进行设置:

alwaysShow: [
    {
        name: '马拉维',
    },
    {
        name: '阿尔及利亚',
    },
],

alwaysShow的值为数组,以便支持设置多个数据项;

每个数据项的格式为一个JSON对象,方便后续扩展功能(比如高亮)

柱状图增加柱子颜色回调、增加对负数的支持

通过配置项的series.bar.style.color,可以给柱子颜色设置回调函数:

color: function (datum) {
    return datum.value > 0 ? '#00F' : '#0F0';
},

负数通过绝对值绘图,需要配置series.bar.absolute = true

bar: {
    absolute: true,
}

柱状图支持高亮背景

支持高亮背景,通过配置项的highlight进行设置:

// 需要高亮的数据,一般用于指定当前股票
highlight: [
    {
        name: '瑞士',
        style: {
            radius: 2,
            // 柱子的高度
            height: 20,
            width: 500,
            fill: 'lightblue',
            transform: 'translate(-100px, -2px)',
        },
    },
],

(不兼容的修改)修改icon为rank

option.series.icon更名为option.series.rank,使其更加符合实际含义

支持时间轴控制栏

新增了时间轴Timeline类:

const timelineOption = {
    // 左侧操作按钮(播放、暂停、重播)
    operation: {
        // 整体样式
        style: {
            transform: 'translate(10px, 0)',
            backgroundColor:'#CCC',
            width: '50px',
        },
        // 子元素的配置
        children: {
            play: {
                html: '<div title="播放" style="width:20px; height:20px;">播</div>',
            },
            replay: {
                html: '<div  title="重新播放" style="width:20px; height:20px;; display:none">重</div>',
            },
            pause: {
                html: '<div  title="暂停" style="width:20px; height:20px; display:none">暂</div>',
            },
        },
    },
    // 右侧进度区域
    progress: {
        // 整体样式
        style: {
            // 右侧进度区域的大小,该配置不能缺少
            width: '70%',
        },
        children: {
            // 背景横条
            background: {
                style: {
                    backgroundColor: '#F6F6F6',
                    position: 'absolute',
                    height: '4px',
                    opacity: 1,
                },
            },
            // 进度横条
            progress: {
                style: {
                    backgroundColor: '#E8E8E8',
                    position: 'absolute',
                    height: '4px',
                    opacity: 1,
                },
            },
            // 刻度数值
            axis: {
                // 显示的刻度
                tickValues: [1960, 1990, 2021],
                tickFormat: function (d) {
                    return `${d}年`;
                },
                style: {
                    fontSize: '10px',
                    color:'red',
                    left: '-10px',
                    top: '-15px',
                }
            },
            // 拖动滑块时显示的日期label
            label: {
                html: '<div style="touch-action: none;position:relative; float: left;top: -29px; width:45px; height:20px;border-radius:5px; background-color:#9EB6CF;font-size:10px;color:#323232; visibility:hidden"></div>',
                formatter: function (d) {
                    return `${d}年`;
                },
            },
            // 滑块
            marker: {
                html: '<div style="touch-action: none;position:relative; float: left;top: -29px; width:20px; height:20px; background-color:yellow;border: solid 2px; border-color: #CCC;border-radius: 8px; box-shadow: 2px 2px 2px #ccc; visibility: hidden"></div>',
            },
        },
    },
};
// dynamicHistogram为图形的实例
timeline = new Timeline('#timeline', timelineOption, dynamicHistogram);

支持自定义柱子右侧数值的文本格式

通过series.value.formatter进行设置:

series: {
    value: {
        // 格式化文本,参数是当前这根柱子的数值
        formatter: function (val) {
            return val + '元';
        },
    },
}

支持指定排名字段

通过series.rank.key进行设置:

series: {
    rank: {
        // 排名字段,如果没有设置该配置项,或者设置了但是给出的实际数据中没有该字段,则默认采用value字段进行排序
        key: 'rank',
    },
}

修改播放结束后的按钮状态

目前播放结束后,按钮状态会自动设置为播放状态,方便用户重新播放动画。

默认展示时间轴滑块

目前默认会展示时间轴上的滑块了。

修正时间轴操作按钮有时候点击会消失的问题

原因是因为之前事件绑定在了父元素上面,而父元素的大小比里面的子元素(操作按钮)大一些,所以点击到父元素的部分区域,会导致事件处理逻辑有误,现已修正。

修正alwaysShow传前20名,会报错的问题

支持滑块自由拖动,不再有时间限制

播放过程中,动画没播完的时候可以拖动,拖动时先播放完当前正在播放的动画,待用户选中时间后再播放拖动的变动动画(引入队列机制)

修正柱子右侧数值默认被格式化为英文千位制格式的问题

之前默认会增加英文逗号进行数值分割,现已去掉

修正第一次加载拖动时,拖动条浮窗label显示为空的问题

开放排名文字自定义内容和样式

可以通过rank.formatter自定义排名文字的内容:

rank: {
    formatter: function (datum) {
        return datum.rank;
    }
}

该配置可以实现比如“无数据是排名显示横岗”这类的功能。

可以通过rank.style.text自定义排名文字的样式,比如要自定义排名前三的颜色,可以这样设置:

rank: {
    style: {
        text: {
            // 注意回调参数是一个数组,下标为0的才是原始数据
            fill: function (datum) {
                switch (datum[0].rank) {
                    case 1:
                        return '#F00';
                    case 2:
                        return '#0F0';
                    case 3:
                        return '#00F';
                }
                return '#999999';
            }
        }
    }
}

注意:如果想要排名信息全部由数字显示,请去掉rank.content这项配置(即图标相关的配置项)。

支持首尾2个tickValue内部对齐

坐标轴支持显示刻度线

通过Timeline的progress.children.axisLine进行设置:

// 刻度线
axisLine: {
  style: {
    backgroundColor:'red',
    width: '1px',
    height: '10px',
    top: '5px',
  }
},

修正播放时拖动滑块,暂停按钮不会变成播放按钮的问题

增加对空数据的支持

现在value可以设置为null,表示数据为空;空数据默认会排在最后。

当柱子少于maxDisplayNumber时,靠顶部排列,不再均匀分布

支持禁用选中交互

如果不设置series.bar.action,则取消选中交互。

修正第一帧无法暂停的问题

修正频繁拖动时间轴滑块和点击播放按钮时,绘制图形会缺少一部分的问题

该问题产生的原因,是在上一帧动画尚未播放结束的情况下,调用了下一帧动画的渲染,导致上一帧的部分图形因为没有绘制完成而缺失了。

解决方案是通过队列机制,来处理时间轴控制栏的交互:

  • 时间轴的所有交互动作都会进入一个操作队列playQueue
  • 统一调用播放函数(playByDate)的代码,封装为consumePlayQueue方法,在该方法内部,通过调用自身的方式,保证动画的顺序执行
  • 每一帧,都会从playQueue中取最后一个数据(即最新加入的交互动作),执行该动作,并清空队列

这样可以保证用户的操作一定是顺序执行的,且一定是在上一个动画执行完毕后,才执行最新的一个交互动作(中间的交互动作全部自动丢弃)。

支持给刻度线设置宽度

通过axis下的style.tickWidth设置:

style: {
  // 刻度线的宽度
  tickWidth: '0.5px',
},

支持设置Y轴轴线的样式

通过axis下的domain进行设置:

domain: {
  style: {
    opacity: 1,
    color: '#0F0',
    top: 20,
    marginTop: 20,
    strokeWidth: 5,
  },
},

将时间轴刻度线的层级调高

目前刻度线的层级高于进度条

调整第一帧的动效

第一帧的动效不再进行Y轴方向的位移,仅进行X轴方向柱子长度的增加。

增加onStepFinished回调,以解决timeline和图表并发播放动画的问题

通过animation.action.onStepFinished进行配置:

// 每次步进执行完动画后的回调
onStepFinished(date) {
  console.log(`当前帧动画已播放结束:${date}`);
  if (timeline) {
    timeline.playing = false;
  }
},

destroy方法中,增加中断requestAnimationFrame的判断逻辑

避免当销毁图表对象后,因为RAF仍然在执行,导致内存中的数据没有被回收的问题。

现在销毁图表,需要先调用destroy方法,类似这样:

let dynamicHistogram = new DynamicHistogram('#chart1', originalData, option1);
dynamicHistogram.playByDate(2012, () => {
    dynamicHistogram.resume();
});
timeline = new Timeline('#timeline1', timelineOption, dynamicHistogram);

setTimeout(() => {
    // 必须先调用destroy方法
    dynamicHistogram.destroy();
    option1 = null;
    dynamicHistogram = null;
    timeline = null;

    let dynamicHistogram2 = null;
    let timeline2 = null;
    document.querySelector('#chart1').innerHTML = '';
    document.querySelector('#timeline1').innerHTML = '';

    const option2 = deepClone(option);
    option2.animation.action.onStep = (date) => {
      timeline2 && timeline2.update(date);
    }
    dynamicHistogram2 = new DynamicHistogram('#chart1', originalData, option2);
    timeline2 = new Timeline('#timeline1', timelineOption, dynamicHistogram2);
    timeline2.update(2021);
}, 3000)

柱子支持左侧非圆角

通过series.bar.clip进行设置:

clip: {
  // 裁剪区域的宽度,其值一般和bar.style.radius的圆角保持一致(高度无需设置,自动和绘图区域高度保持一致)
  width: 2,
  // 必须和页面背景色设置为同样的颜色和透明度
  fill: '#CCC',
}

修正柱状图右侧数值文本的动画正负突变的问题

前后两帧如果出现正负数切换时,柱子颜色不再过渡变化

修正播放后快速点击暂停,暂停不生效的问题

修正直接点击滑块,滑块会消失的问题

修正拖动滑块后,点击播放,等播了几个日期后,再点击滑块,滑块会跳到之前的日期的问题