BizCharts使用采坑教程


 
了不起的BizCharts

最近項目的管理后台都在用阿里粑粑開源的管理框架Ant Design Pro,說真話,還是比較好用的。該框架內部也封裝了一些圖標插件,但是在最近的一個項目中發現,這些圖標可定制性還是差了點,不能滿足客戶需求。

好在它的后面也介紹了自己親生的BizChart可視化圖表組件,因為定制性比較高,但是api中的介紹又不是每個都有例子,更沒有組合使用的例子,經過度娘介紹,發現這片文章備受我青睞,我怕作者哪天不高興放棄了,所以轉存了一份,順便把自己實踐到的補充到后面。

原文

作為一個前端打字員,除了綠茶婊之外,最討厭的就是圖表:一個讓我傷心,一個讓我難過;比這更討厭的就是文檔寫得不清不楚的圖表庫(大概率是九年義務教育期間沒有學好語文),讓我又愛又恨!所以本篇博文會比較枯燥,只簡單描述一下使用BizCharts的過程,當然,重要的是總結遇到的坑(遵從一個坑不踩兩次,一個女生不泡兩次原則)。

By the way,提到BizCharts,讓我們感謝一下阿里巴巴:其開源了這個好用的(雖然偶爾不那么好用,還偶得挺經常的)的react圖表庫供大家使用,對使用react技術棧的前端打字員來說簡直就是福音。本文不會有過多的api解釋,具體的接口可以看官網文檔鬼門關。

正經篇幅

剛開始,視覺設計師哄我說:“我的要求並不高,待我從前一樣好”,啊呸,說錯了,“我的要求是:只要能把數據用直方圖展現出來就好了”,so easy

// 引入相關的組件
import { Chart, Axis, Tooltip, Geom } from 'bizcharts';

// 隨便mock一下數據
const str = ['we', 'are', 'the', 'black', 'gold', 'team'];
const mockData = () => {
    let result = [];

    for (let i = 0, len = 6; i < len; i++) {
        result.push({
            xAxis: ticks[i],
            yAxis: Math.floor(Math.random() * 100)
        });
    }

    return result;
};

// 圖表組件
<Chart
    width={ 600 }
    height={ 400 }
    data={ mockData() }
>
    {/* x軸,橫軸,以data數據的xAxis屬性值為柱子的值 */}
    <Axis name="xAxis" />
    {/* y軸,縱軸,以data數據的yAxis屬性值為柱子的值 */}
    <Axis name="yAxis" />
    {/* 鼠標hover直方圖柱子的時候,tooltip顯示的值 */}
    <Tooltip />
    {/* 幾何標記對象,主要用以描述你要畫的是什么圖形(直方圖、折線圖、餅狀圖、區域圖):interval是直方圖 */}
    <Geom
        type="interval"
        position="xAxis*yAxis"
    />
</Chart>

一波操作猛如狗,讓視覺設計師看看效果:

 
數據可視化,BizCharts圖表庫入坑歷程

note:此直方圖每一根柱子都是單點的,也就是其反映了某個橫坐標點的數據情況。加入我們需要一個連續區間柱子,那么作為xAxis的數據字段值應該為一個數組,包含兩個元素,表明區間的起始值。

const mockData = () => {
        let result = [];

        for (let i = 0, len = 6; i < len; i++) {
            result.push({
                xAxis: [i + 0.01, i + 1 - 0.01], // 如果不加減0.01,那么第一根柱子的終點跟第二根柱子的起點是同一個,會感覺兩個柱子粘在一起
                yAxis: Math.floor(Math.random() * 100)
            });
        }

        return result;
    };
 
BizChart2.jpg

視覺設計師:“emmmmmm,圖表長寬定死了會不會有點僵硬啊,高度可以寫死,寬度總得來個自適應吧?”

“毛悶台”

<Chart
        height={ 400 }
        data={ mockData() }
        forceFit // 我媽說了(guanfang wendang shuode),加上這個屬性就可以使圖表寬度自適應了,隔壁echart同學要學習一下
    >
</Chart>

效果秀一波

 
數據可視化,BizCharts圖表庫入坑歷程

視覺(蜜汁微笑):“猿子,你這玩意有bug啊”

“胡說,你這傻*不會用吧”

(理直氣壯)“哼哼,放大窗口圖表寬度確實會自適應,但是縮小就掛掉了(並不自適應),ahhhhhh”

(諂媚)“討厭,再給我兩分鍾~~讓我把bug結成冰。。。”

note: 實驗表明,如果Chart組件的父組件Father采用flex布局,即Father使用flex自適應寬度,那么就會出現上述的問題;所以,如果有多個圖表同行並列布局,請不要使用flex布局,給Father組件的寬度設置為百分比吧,此時的forceFit就會起作用了。同時,BizCharts對重繪設置了防抖,只有當停止縮放的時候才會重繪。

 
數據可視化,BizCharts圖表庫入坑歷程

(屌到飛起)“over,拿去用吧”

(一臉鄙視)“哇喔~好棒棒呀,敢不敢讓我調一點點小細節,我保證就一點點!”

“Come on baby!”

  1. 鼠標hover柱子的時候,為什么柱子后面有個很丑的方框,換個顏色吧!
  2. 鼠標hover柱子的時候,出現的tooltip樣式丑爆了,待會我給你設計一個吧
  3. 鼠標hover柱子的時候,柱子的顏色應該有所改變,對用戶比較友好!!!
  4. ...哎,你別拿刀啊~~~

把視覺殺了之后,需求還是要做的,先解決死者的第一個遺願。

Tooltip組件提供了一個屬性crosshairs,用以設置tooltip的輔助線和輔助框;默認情況下,此屬性會為’line’、‘area’、‘path’、‘areaStack’類型的Geom組件開啟垂直輔助線、為‘interval’類型的Geom組件展示矩形背景框。死者說的很丑的方框就是這個!

<Tooltip crosshairs={ false }/>

好的,把框去掉了!咦,我們不是說要修改它的顏色嗎?好的,改一下

<Tooltip
        crosshairs={{
            type: "rect" // 可選值:rect、x、y、cross,分別對應輔助狂、平行x軸輔助線、平行y軸輔助線,十字輔助線
            style: {
                fill: 'red', // 輔助框顏色
                shadowColor: 'red', // 輔助框周邊陰影的顏色
                shadowBlur: 1, // 輔助框周邊陰影的透明度
                opacity: 0 // 輔助框的透明度
            }
        }}
    />
 
數據可視化,BizCharts圖表庫入坑歷程

note:假如開啟的是輔助線,即type不是“rect”,那么上述的樣式定義將不起作用。究其原因,看了此組件的源碼之后才發現,描述輔助線樣式的屬性不是style對象,而是lineStyle對象,官方文檔並未說明這一點。

<Tooltip
        crosshairs={{
            type: "y"
            lineStyle: {
                stroke: 'red', // 輔助線顏色
                lineWidth: 4, // 輔助線寬度,單位為px
                opacity: 1 // 輔助線透明度
            }
        }}
    />
 
數據可視化,BizCharts圖表庫入坑歷程

看起來還是很容易就實現了死者的第一個遺願,就這樣懟死了視覺,是不是太殘忍了點?事已至此,繼續實現他的遺願吧。

第二個遺願是給tooltip換個樣式。既然要修改tooltip的樣式,就應該繼續對Tooltip組件下手。通過閱讀文檔,發現其還有一個itemTpl的屬性,也就是可以通過這個屬性定義tooltip的模板

// 定義一個模板
    // name-value是相關柱子的key-value值
    const tooltipsDisplayTpl = `
        <p class="chart-tooptip">
            <span class="chart-tooptip-right">{name}</span>
            <span>{value}</span>
        </p>
    `;

    /*
        // 重寫tooltip元素的樣式
        // 因為視覺已死,樣式是隨便搞的,就弄點黑色背景當默哀一下吧
        .g2-tooltip {
            background-color: rgba(44, 49, 68, 0.80) !important;
        }

        .chart-tooptip {
            margin: 0;
            color: white;
        }

        .chart-tooptip-right {
            margin-right: 12px;
        }
    */

    <Tooltip
        crosshairs={ false }
        itemTpl={ tooltipsDisplayTpl }
        showTitle={ false } // 去頭(標題,即橫軸對應的刻度),往往影響我顏值的不是我的身材,而是我的臉,所以不要臉了
    />
 
數據可視化,BizCharts圖表庫入坑歷程

note:如果想自定義tooltip展示的內容,還需要設置Geom組件的tooltip屬性,即將數據映射到Tooltip對象上;所以此屬性值如果為false的話,就不會向Tooltip組件傳遞任何數據(此時Tooltip只會顯示title);還可設置為字符串,展示字符串對應的數據字段;But, it's not the point,重點在於可自定義

// 定義數據返回的格式,name屬性對應的是itemTpl里面的同名變量
    const getTooltipData = (xAxis, yAxis) => {
        return {
            name: xAxis,
            value: yAxis
        };
    }

    <Geom
        type="interval"
        position="xAxis*yAxis"
        tooltip={["xAxis*yAxis", getTooltipData]}
    />

 
數據可視化,BizCharts圖表庫入坑歷程

第二個遺願也實現了,愧疚感也多了一點!最主要是寫代碼的時候老是覺得后面有人站着盯着我看。

說不定實現所有遺願就不會有這種感覺了呢,那就繼續第三個遺願吧:“改變鼠標hover柱子時候柱子的顏色”,翻遍了整個文檔,發現沒有關於hover的接口啊!看來視覺是要死不瞑目了,阿門。

就在我感覺到后背越發的涼颼颼的時候,我發現Geom組件有一個屬性active

 
數據可視化,BizCharts圖表庫入坑歷程

文檔就真的描述了那么兩句話,也沒例子。急病亂投醫的我只能嘗試一波,設置為true,得了,hover柱子的時候柱子顏色改變了!!!

<Geom
        type="interval"
        position="xAxis*yAxis"
        tooltip={["xAxis*yAxis", getTooltipData]}
        active={ true }
    />
 
數據可視化,BizCharts圖表庫入坑歷程

那如果需要自定義鼠標hover柱子的樣式呢?對照着Geom文檔的select屬性,又嘗試了一遍

<Geom
        type="interval"
        position="xAxis*yAxis"
        tooltip={["xAxis*yAxis", getTooltipData]}
        style={{ cursor: 'pointer' }} //  鼠標hover上去的時候,顯示小手手,免費送的
        active={[
            true,
            {
                style: {
                    fill: 'black',  // 柱子顏色,繼續默哀
                    shadowColor: 'red',  // 整體陰影顏色,包括邊緣
                    shadowBlur: 1,  // 陰影的透明度
                    opacity: 0 // 柱子顏色透明度
                }
            }
        ]}
    />

 
數據可視化,BizCharts圖表庫入坑歷程

(神氣的)“狗子,別死了,老子搞定啦”

“靠,我都裝死兩天了,你敢不敢再慢一點”

“那官方文檔就寫了一行字:只可意會不可言傳!我天分有限,意會了比較久”

“嘚瑟,看,又出bug了吧!你的表子一閃一閃的”

(掐着他脖子使勁晃)“那TM不是bug!!!”

 
數據可視化,BizCharts圖表庫入坑歷程

不過話說回來,當數據更新時,從舊數據切換到新數據,會很突兀,沒有緩沖過程,看着特別不舒服。我尋思着,在數據更新的時候,加個動畫唄!但是初始動畫生效了,更新動畫就不生效了(如看官們知道解決辦法,請不吝賜教)。由於趕着下班,我決定使用DataSet:一個用於管理表格數據的神器,據說更新數據的時候,其會給我弄個動畫(除此以外有方便地導入非 json 數據等等功能,下文有一些例子,具體細節我沒有詳細去研究,以后學習了再分享)。唔好理,總之好犀利!

// 安裝
    // npm install @antv/data-set

    // 引入
    import DataSet from '@antv/data-set';

    // 生成一個View實例,作為類的屬性,故不要在render方法里面生成這個實例
    dv = new DataSet().createView();

    render() {
        this.dv.source(data);

        <Chart
            height={ 400 }
            data={ this.dv }
            forceFit
        ></Chart>
    }
 
數據可視化,BizCharts圖表庫入坑歷程

“猿子,6啊!吃宵夜嗎?我的”

“雖然不怎么餓,但是你請就不一樣了,go”

吃了一桶泡面后......

“猿子,你看,宵夜也吃了·······”

“你又想干嘛···············”

簡直就是飽飯思淫欲啊!!!

”我只是覺得柱子的顏色可以漸變會顯得我們公司的產品更屌一點“

”狗子,你扛揍不?“

(可憐兮兮)”揍完之后可以加個漸變嗎......“

”......“

”我就知道你對我最好了,我給你捶背捏大腿吧~“

”滾一邊去“

<Geom
        type="interval"
        position="xAxis*yAxis"
        tooltip={["xAxis*yAxis", getTooltipData]}
        color={['xAxis', '#3DA4FF-#FFFFFF']}
    />
 
數據可視化,BizCharts圖表庫入坑歷程

(掐着我脖子使勁晃)”老子要的是從上往下漸變,不是從左往右漸變“

“別.....別.....掐.....我....改....改.....”

<Geom
        type="interval"
        position="xAxis*yAxis"
        tooltip={["xAxis*yAxis", getTooltipData]}
        color={['xAxis', 'l(90) 0:#3DA4FF 1:#FFFFFF']}
    />

 
數據可視化,BizCharts圖表庫入坑歷程

note:l是指線性漸變,90是指旋轉九十度(即從上到下漸變,看官們可以多試試幾個姿勢,啊呸,多試試幾個角度)

0和1標定的色值標明初始色值和終止色值,注意一點,色值不可以使用顏色名字,如“red”、“blue”等

可添加多個漸變色值,如

color="l(90) 0:#000000 0.5:#FFFFFF 1:#000000"

note:如果是area類型的Geom,那么第一種漸變方式是不起作用的,只能選用第二種

“狗子,我真要下班了”

“那個,你看都搞着漸變了,要不搞一波顏色分類”

”沒得談,goodbye!“

”宵夜我的“

”頂你個肺,又想用泡面忽悠我!!!“

”擼串,騙你我是狗“

”emmmmmm.....“

既然提到顏色分類,我們就接着提一下dv.transform 吧, dv.transform內置了一些基礎的函數:filter,map,pick,rename,reverse …… 具體可自行查看文檔

只需要添加 groupBy 字段,並且在傳入的原始數據data中添加對應的字段classify即可輕松搞定。

dv.transform({
        groupBy: ['classify'],  // 以classify字段進行分組 
    });

”猿子,顏色還是要自定義的哦“

(白眼)

<Geom
        position={'xAxis*yAxis'}
        color={['classify', classify => {
            // 這里根據不同字段返回不同顏色
            return classify === 'test' ? 'red' : 'yellow';
        }]}
        style={{ cursor: 'pointer' }}
    />

 
數據可視化,BizCharts圖表庫入坑歷程

作為一個有責任的前端打字員,有一點即使設計不要求的,我還是需要說明的,橫軸的刻度值是可以自定義的

<Axis
        name={xAxis}
        label={{
            textStyle: {
                fill: 'red',  // 顏色
                textBaseline: 'top'  // 對齊基線
            },
            formatter: (val) => {
                return `${ val }\n換行了`
            }
        }}
    /> 

 
數據可視化,BizCharts圖表庫入坑歷程

”狗子,擼串去!!!“

”要不還是吃個泡面????“

狗子,卒!


以下內容來自自己的總結


很顯然,本人沒有博主這枚猿有文化底蘊,辭藻上既不華麗麗,也沒有故事性,純屬就是論事,記筆記的形式。

1. 柱狀圖/點圖上顯示文字及格式化內容

該需求需要用到Label組件,她是Geon的子組件,上代碼

      <div>
        <Chart height={400} data={dv} forceFit>
          <Axis name="月份" />
          <Axis name="月均降雨量" />
          <Legend />
          <Tooltip
            crosshairs={{
              type: "y"
            }}
          />
          <Geom
            type="interval"
            position="月份*月均降雨量"
            color={"name"}
            adjust={[
              {
                type: "dodge",
                marginRatio: 1 / 32
              }
            ]}
          >
            <Label
                content={['月份*月均降雨量', (月份, 月均降雨量) => (`${月均降雨量}`)]}
                textStyle={{
                  textAlign: 'center', // 文本對齊方向,可取值為: start middle end
                  fill: '#404040', // 文本的顏色
                  fontSize: '14', // 文本大小
                  fontWeight: 'normal', // 文本粗細
                  rotate: 0, // 文字旋轉
                  textBaseline: 'top', // 文本基准線,可取 top middle bottom,默認為middle
                }}
              />
            </Geom>
        </Chart>
      </div>

效果:

 
image.png

2. 圖標上增加日期選擇onChange

import React, { PureComponent } from 'react';
import { Chart, Geom, Axis, Tooltip, Label } from 'bizcharts';
import { DatePicker } from 'antd';
import numeral from 'numeral';
import moment from 'moment';
import style from './index.less';

class AppTotalUsers extends PureComponent {
  numeralCount = count => numeral(count).format('0,0.00');

  wanCount = count => {
    let data;
    if (count < 10000) {
      data = count;
    } else {
      data = this.numeralCount(count / 10000);
      data = `${data} 萬`;
    }
    return data;
  };

  handleSelect = value => {
    const { callback } = this.props;
    const payload = { showDate: value };
    callback(payload);
  };

  // Can not select days before today and today
  disabledDate = current => current && current > moment().endOf('day');

  const  appChartData = [
      {
          "x": "用戶中心管理",
                "y": "23715",
                "date": "2019-03-22"
            },
            {
                "x": "測試app",
                "y": "2899",
                "date": "2019-03-22"
            }
        ];

  render() {
    const { appChartData, showDate } = this.props;
    const background = {
      fill: '#FFFFFF', // 圖表背景色-白色
      fillOpacity: 0, // 圖表背景透明度
    };

    const appScale = {
      y: {
        alias: '人數',
        type: 'pow',
      },
    };

    return (
      <div style={{ height: 390 }}>
        <div style={{ padding: '20px', background: '#FFFFFF' }}>
          <Chart height={300} data={appChartData} scale={appScale} forceFit background={background}>
            <span className={style.mainTitle}>歷史累計用戶人數(人)</span>
            <DatePicker
              className={style.dateSelect}
              allowClear={false}
              onChange={this.handleSelect}
              disabledDate={this.disabledDate}
              // value={moment(appChartData[0] && appChartData[0].date, 'YYYY-MM-DD')}
              value={moment(showDate, 'YYYY-MM-DD')}
            />
            <Axis name="x" />
            <Axis name="y" visible={false} />
            <Tooltip
              crosshairs={{
                type: 'y',
                title: '人數',
              }}
            />
            <Geom type="interval" position="x*y">
              {/* 柱子上作文章用這個子組件 */}
              <Label
                content={['x*y', (x, y) => this.wanCount(`${y}`)]}
                textStyle={{
                  textAlign: 'center', // 文本對齊方向,可取值為: start middle end
                  fill: '#404040', // 文本的顏色
                  fontSize: '12', // 文本大小
                  fontWeight: 'normal', // 文本粗細
                  rotate: 0, // 文字旋轉
                  textBaseline: 'top', // 文本基准線,可取 top middle bottom,默認為middle
                }}
              />
            </Geom>
          </Chart>
        </div>
      </div>
    );
  }
}

export default AppTotalUsers;

index.less文件

.chartDiv {
  padding: '0 20px';
  background-color: '#FFFFFF';
}

.mainTitle {
  font-weight: bold;
  font-size: 16px;
  padding: 10px;
}

.remark {
  font-weight: normal;
  font-size: 14px;
  padding-right: 30px;
  float: right;
}

.dateSelect {
  :global(.ant-calendar-picker-input) {
    border: none;
  }
  padding-right: 50px;
  float: right;
}

效果:


 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM