Moreal D3.js Wiki

導(dǎo)讀

此文乃<Moreal D3.js Wiki>的學(xué)習(xí)筆記(https://kb.moreal.co/d3/), 簡略看了一下感覺甚好. 以下這段話摘自此網(wǎng)站:
What is this document and who is it intended for?
Since Mike Bostock, creator of the D3 library, shared the excellent D3.js library with all of us, we thought we should give something back in return to the community. Although this document has been initially created for internal use, we felt that sharing it might help some people struggling to get the grasp of the basics (and even some more advanced features) of the vast D3.js library. There might be more efficient ways to handle specific functions, but while we gain more experience, this document will keep evolving with us. Enjoy!

D3 Basic Usage

D3采用鏈?zhǔn)綄懛? select/selectAll選擇元素, enter新增元素:

    const dataset = [4, 8, 7, 42, 3];

    d3.select('.chart').append('div')
      .selectAll('div')
      .data(dataset)
      .enter().append('div')
      .attr('class', 'd3box')
      .text(d => d);
  • 通過append新增一個div.
  • 在selectAll虛擬創(chuàng)建N個div(N由data決定)
  • 通過data函數(shù), 將數(shù)據(jù)源綁定到dom元素上, 通過enter().append的操作, 將之前虛擬創(chuàng)建的div按照數(shù)組順序, 一一創(chuàng)建出來.
  • 給創(chuàng)建出來的每個div, 賦值class和text.


    image.png

    這里實(shí)際上涉及到d3中重要的三個函數(shù):

  • enter: 提供數(shù)據(jù), dom中不存在匹配的元素, 新增.
  • update: 提供數(shù)據(jù), dom中存在匹配的元素, 更新.
  • exit: 提供元素, 沒有匹配的數(shù)據(jù), 刪除.
    d3.selectAll('.d3box').data([32, 12])
      .text(d => d)
      .exit().remove();

這時候, 非[32, 12]的dom元素將會被刪除.

    d3.selectAll('.d3box').data([32, 12, 32, 45, 67, 31, 34, 2])
      .enter().append('div')
      .attr('class', 'd3box')
      .text(d => d);

這時候, 多余出來的數(shù)據(jù), 將被更新到dom上.

Chart Dimensions

我們在繪圖時候, 最好要增加繪圖區(qū)域的margin(外間距). 主要原因有兩個: 1. 為了美觀. 2. 如果存在坐標(biāo)軸, 則正好存在空間繪制.
所以一般代碼都會這么寫:

    const width = 960;
    const height = 500;
    const margin = {top: 20, right: 20, bottom: 20, left: 20};

    d3.select('svg')
      .attrs({
        width: width + margin.left + margin.right,
        height: height + margin.top + margin.bottom
      });

Labels

一個繪圖, 通常會由label說明:

    const xaxisLabel = svg.append('text')
      .attrs({
        class: 'd3-chart-label label-x-axis',
        x: width / 2,
        y: height + (margin.bottom / 2),
        dy: '1em',
        'text-anchor': 'end'
      })
      .text('x Axis Label');

    const yaxisLabel = svg.append('text')
      .attrs({
        class: 'd3-chart-label label-y-axis',
        x: -height / 2,
        y: margin.left,
        dy: '1em',
        transform: 'rotate(-90)',
        'text-anchor': 'middle',
      })
      .text('y Axis Label');

xaxisLabel比較好理解, 將文本水平放置在位置(width / 2, height + (margin.bottom / 2))的位置. 但是由于yaxisLabel的文字是豎向的, 所以我們可以先將文本放在(-height / 2, margin.left)上, 再逆時針旋轉(zhuǎn)90度(rotate(-90))即可.

Scales

Scales通常用于處理domain和range的關(guān)系.

    const dataset = [
      {"name":"Nick", "level":1232},
      {"name":"George", "level":922},
      {"name":"Alekos", "level":1651},
      {"name":"Kostas", "level":201}
    ];
    const opacityScale = d3.scaleLinear()
      .domain([0, d3.max(dataset, d => d.level)])
      .range([.2, 1]);
    const colorScale = d3.scaleOrdinal()
      .domain(["Nick", "George", "Alekos", "Kostas"])
      .range(["red", "orange", "yellow", "green"]);

這里通過scaleLinear將[0, 1651]線性映射到[.2, 1]上. 而通過scaleOrdinal將名字和顏色一一對應(yīng)起來.

Axes

常用的坐標(biāo)軸可分為以下幾類:1. 線性坐標(biāo)軸, 例如從0, 1, 2, ...,10作為x軸. 2. 時間坐標(biāo)軸.

    const width = 500;
    const height = 500;
    const margin = {top: 20, right: 20, bottom: 20, left: 20};
    const points = [3, 6, 2, 7, 9, 1];

    const svg = d3.select('svg').attrs({
      width: width + margin.left + margin.right,
      height: height + margin.top + margin.bottom
    });

    const x = d3.scaleLinear().domain([0, 10]).range([margin.left, width + margin.left]);
    const y = d3.scaleLinear().domain([d3.min(points), d3.max(points)]).range([height + margin.top, margin.top]);

    const gx = svg.append('g').attr('transform', `translate(0,${height + margin.top})`);
    const gy = svg.append('g').attr('transform', `translate(${margin.left}, 0)`);

    const xAxis = d3.axisBottom(x);
    const yAxis = d3.axisLeft(y);

    gx.call(xAxis);
    gy.call(yAxis);

    svg.selectAll('circle').data(points)
      .enter().append('circle')
      .attrs({cx: (d, i) => x(i), cy: d => y(d), r: 5})
      .style('fill', 'green');

這里簡單實(shí)現(xiàn)了一個散點(diǎn)圖, 效果如下:


image.png

代碼簡單解釋如下:

  • 使用scaleLinear將x軸的[0, 10]映射到寬度[margin.left, width + margin.left]上, 將y軸的[min, max]映射到高度[height + margin.top, margin.top]上. margin的存在導(dǎo)致x/y軸有空間進(jìn)行繪制.
  • 為x/y創(chuàng)建繪圖空間gx/gy, 并設(shè)置位置(transform, translate)
  • 使用d3.axisBottom/axisLeft分別創(chuàng)建下x坐標(biāo)軸和y坐標(biāo)軸, 并在gx/gy中call, 生成坐標(biāo)軸.
  • 繪制散點(diǎn)圖.

Tooltips

任何一個繪圖, 都應(yīng)該存在tooltips, 最簡單的實(shí)現(xiàn)方式是加入: title.

    svg.selectAll('circle').data(points)
      .enter().append('circle')
      .attrs({cx: (d, i) => x(i), cy: d => y(d), r: 5})
      .style('fill', 'green')
      .append('title')
      .text(String);

如果需要更加智能化, 則需要手動編寫mousemove/mouseout函數(shù), 然后定義一個tooltips的div, move時候顯示, out后隱藏.

Line Chart

一個簡單的線圖代碼如下:

    const width = 500;
    const height = 500;
    const margin = {top: 20, right: 20, bottom: 20, left: 20};
    const dataset = [
      {
        'date': '2011-07-01T19:14:34.000Z',
        'value': 58.13
      },
      {
        'date': '2011-07-01T19:13:34.000Z',
        'value': 53.98
      },
      {
        'date': '2011-07-01T19:12:34.000Z',
        'value': 67.00
      },
      {
        'date': '2011-07-01T19:11:34.000Z',
        'value': 89.70
      },
      {
        'date': '2011-07-01T19:10:34.000Z',
        'value': 99.00
      }
    ];

    const parseDate = d3.timeParse('%Y-%m-%dT%H:%M:%S.%LZ');
    dataset.forEach(d => {
      d.date = parseDate(d.date);
      d.value = +d.value;
    });

    const svg = d3.select('svg').attrs({
      width: width + margin.left + margin.right,
      height: height + margin.top + margin.bottom
    });
    const x = d3.scaleTime().domain(d3.extent(dataset, d => d.date)).range([margin.left, margin.left + width]);
    const y = d3.scaleLinear().domain([0, 1.05 * d3.max(dataset, d => d.value)]).range([margin.top + height, margin.top]);
    const gx = svg.append('g').attr('transform', `translate(0, ${height + margin.top})`);
    const gy = svg.append('g').attr('transform', `translate(${margin.left}, 0)`);
    const xAxis = d3.axisBottom(x).ticks(5);
    const yAxis = d3.axisLeft(y).ticks(4);
    gx.call(xAxis);
    gy.call(yAxis);

    const line = d3.line()
      .x(d => x(d.date))
      .y(d => y(d.value));

    svg.append('path').data([dataset])
      .styles({
        fill: 'none',
        stroke: 'steelblue',
        'stroke-width': '2px'
      })
      .attr('d', line);

效果圖如下:


image.png
  • 使用d3.timeParse將字符串時間格式化為Date類型.
  • 提供margin用于繪制坐標(biāo)軸.
  • 使用d3.axisBottom/d3.axisLeft繪制底部坐標(biāo)軸和坐標(biāo)坐標(biāo)軸. 使用ticks(N)進(jìn)行間隔設(shè)置.
  • 使用path進(jìn)行線條的繪制.

Line Chart with Vertical Line

我們要達(dá)到一個效果, 鼠標(biāo)移上去后, 會有一條豎直的線:

    const focus = svg.append('g').append('line')
      .styles({ display: 'none', 'stroke-width': 2, stroke: 'black' });
    svg.on('mousemove', function () {
      const x = d3.mouse(this)[0];
      if (x >= margin.left && x <= margin.left + width) {
        focus.attrs({ x1: x, y1: height + margin.top, x2: x, y2: margin.top })
          .style('display', '');
      } else {
        focus.style('display', 'none');
      }
    }).on('mouseout', function () {
      focus.style('display', 'none');
    });

原理很簡單. 我們創(chuàng)建一個line, 然后隱藏它. 在mousemove/mouseout情況下顯示/隱藏它即可.

Line Chart with Area Fill

如果想繪制面積圖, 則需要做以下兩點(diǎn):

  • 填充顏色需要設(shè)置: style('fill', '#f1f1f1')
  • 使用d3.area代替d3.line, 并且需要提供x, y0, y1, 形成線條. 無數(shù)個x就形成了面積圖.
    const area = d3.area()
      .x(d => x(d.date))
      .y0(y(0))
      .y1(d => y(d.value));

    svg.append('path').data([dataset])
      .styles({
        fill: '#f1f1f1',
        stroke: 'steelblue',
        'stroke-width': '2px'
      })
      .attr('d', area);

Line Chart with Brush Zoom

如果想得到畫刷的效果, 可直接使用d3.brushX:

    svg.append('g').attr('class', 'brush')
      .call(d3.brushX().extent([[margin.left, margin.top], [width + margin.left, height + margin.top]]));
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谆焊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子揭斧,更是在濱河造成了極大的恐慌遭顶,老刑警劉巖溶握,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脊凰,死亡現(xiàn)場離奇詭異燕垃,居然都是意外死亡俏橘,警方通過查閱死者的電腦和手機(jī)允华,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寥掐,“玉大人靴寂,你說我怎么就攤上這事〔苷蹋” “怎么了榨汤?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長怎茫。 經(jīng)常有香客問我收壕,道長,這世上最難降的妖魔是什么轨蛤? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任蜜宪,我火速辦了婚禮,結(jié)果婚禮上祥山,老公的妹妹穿的比我還像新娘圃验。我一直安慰自己,他們只是感情好缝呕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布澳窑。 她就那樣靜靜地躺著,像睡著了一般供常。 火紅的嫁衣襯著肌膚如雪摊聋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天栈暇,我揣著相機(jī)與錄音麻裁,去河邊找鬼。 笑死源祈,一個胖子當(dāng)著我的面吹牛煎源,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播香缺,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼手销,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了图张?” 一聲冷哼從身側(cè)響起原献,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤馏慨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后姑隅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體写隶,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年讲仰,在試婚紗的時候發(fā)現(xiàn)自己被綠了慕趴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡鄙陡,死狀恐怖冕房,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情趁矾,我是刑警寧澤耙册,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站毫捣,受9級特大地震影響详拙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蔓同,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一饶辙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧斑粱,春花似錦弃揽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尚揣,卻和暖如春涌矢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惑艇。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工蒿辙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拇泛,地道東北人滨巴。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像俺叭,于是被迫代替她去往敵國和親恭取。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案熄守? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,754評論 1 92
  • D3是用于數(shù)據(jù)可視化的Javascript庫蜈垮。使用SVG耗跛,Canvas和HTML。結(jié)合強(qiáng)大的可視化技術(shù)和數(shù)據(jù)驅(qū)動的...
    Evelynzzz閱讀 7,896評論 7 5
  • d3 (核心部分)選擇集d3.select - 從當(dāng)前文檔中選擇一系列元素攒发。d3.selectAll - 從當(dāng)前文...
    謝大見閱讀 3,445評論 1 4
  • 精心打扮滿心歡喜地走出家門 期待美味的食物和可愛的人 站到川流不息的路上等候出租車 一等就是二十分鐘 好心情漸漸淡...
    強(qiáng)壯的手臂閱讀 391評論 0 0
  • 網(wǎng)絡(luò)騙局有多少调塌? 電信詐騙少不了! 人們警惕提高了惠猿, 新型詐騙出現(xiàn)了羔砾! 理療按摩解疲勞, 掏錢買卡關(guān)門了偶妖! 騙子跑...
    安子墨閱讀 1,199評論 0 0