From 66c63338f1ea679ec74161e958202bafbd49a00b Mon Sep 17 00:00:00 2001 From: Kasmine <736929286@qq.com> Date: Wed, 16 Dec 2020 10:02:24 +0800 Subject: [PATCH] =?UTF-8?q?refactor(demo):=20=E8=AF=BA=E8=B4=9D=E5=B0=94?= =?UTF-8?q?=E5=A5=96=E5=8F=AF=E8=A7=86=E5=8C=96=20demo=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20(#2106)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(case/demo): 诺贝奖可视化 demo 设置为主题切换适应 * refactor(case/demo): 简化诺贝奖可视化 demo --- examples/case/multi-view/demo/nobel-prize.ts | 273 +++++++++++-------- src/plots/multi-view/adaptor.ts | 2 +- 2 files changed, 162 insertions(+), 113 deletions(-) diff --git a/examples/case/multi-view/demo/nobel-prize.ts b/examples/case/multi-view/demo/nobel-prize.ts index d718208f0e..ed66978972 100644 --- a/examples/case/multi-view/demo/nobel-prize.ts +++ b/examples/case/multi-view/demo/nobel-prize.ts @@ -1,15 +1,37 @@ +// @ts-nocheck import { DataView } from '@antv/data-set'; import { Lab } from '@antv/g2plot'; +import { keys, groupBy } from '@antv/util'; -fetch('https://gw.alipayobjects.com/os/bmw-prod/738147f2-2cef-4591-8e0d-4fd5268c2e0a.json') +function generateYearData() { + const r = []; + for (let i = 1900; i <= 2016; i++) { + r.push({ year: i }); + } + return r; +} + +fetch('https://gw.alipayobjects.com/os/antfincdn/NHer2zyRYE/nobel-prize-data.json') .then((data) => data.json()) - .then((data) => { - const COLORS = ['#ff93a7', '#ff9300', '#bb82f3', '#6349ec', '#0074ff']; + .then((originalData) => { + const data = [...originalData.main, { year: 2016, number: 0, age: 0 }]; let currentYear = 1901; + const types = keys(groupBy(data, (d) => d.type)); + /** 散点图数据(各国诺贝尔奖获奖者的年龄分布) */ const getPointViewData = (year) => { - return data.map((d) => (d.year <= year ? d : { ...d, age: null })); + const r = data.map((d) => (d.year <= year ? d : { ...d, ageGroup: null })).filter((d) => d.age !== 0); + const ds = new DataView().source(r); + ds.transform({ + type: 'summary', // 别名 summary + fields: ['number'], // 统计字段集 + operations: ['sum'], // 统计操作集 + as: ['number'], // 存储字段集 + groupBy: ['country', 'ageGroup', 'type'], // 分组字段集 + }); + return ds.rows; }; + /** 占比环图数据(各领域诺贝尔奖获奖分布) */ const getIntervalViewData = (year) => { const ds = new DataView().source(data.map((d) => (d.year <= year ? d : { ...d, number: 0 }))); @@ -21,37 +43,51 @@ fetch('https://gw.alipayobjects.com/os/bmw-prod/738147f2-2cef-4591-8e0d-4fd5268c as: ['counts'], // 存储字段集 groupBy: ['type'], // 分组字段集 }); - return [...ds.rows, { type: 'other', counts: othersCnt }]; - }; - const getDataGroupByField = (field) => { - const transformData = [...data]; - for (let i = 1901; i < 2016; i++) { - if (!data.find((d) => d.year === i)) { - transformData.push({ - year: i, - number: 0, - name: '', - nickName: '', - age: 0, - country: '', - about: '', - type: '', - avatar: '', - }); - } - } - return new DataView() - .source(transformData) - .transform({ type: 'group', groupBy: [field] }) - .rows.map((d) => ({ [field]: d[0][field] })); + return [...ds.rows, { type: '其它', counts: othersCnt }]; }; + const yearData = generateYearData(); const labChart = new Lab.MultiView('container', { height: 500, padding: 'auto', appendPadding: [20, 0, 20, 0], legend: { type: { position: 'bottom' }, + number: false, + }, + tooltip: { + fields: ['country', 'age', 'number', 'ageGroup'], + showMarkers: false, + domStyles: { + 'g2-tooltip': { + minWidth: '200px', + }, + 'g2-tooltip-list-item': { + display: 'flex', + justifyContent: 'space-between', + }, + }, + customContent: (title, items) => { + const datum = items[0]?.data || {}; + const fixed = (v) => v.toFixed(0); + const tooltipItems = [ + { name: '年龄段:', value: `${fixed(Math.max(datum.ageGroup - 10, 0))}~${fixed(datum.ageGroup + 10)}` }, + { name: '奖项学科:', value: datum.type }, + { name: '获奖人数:', value: datum.number }, + ]; + let tooltipItemsStr = ''; + tooltipItems.forEach((item) => { + tooltipItemsStr += `
  • + ${item.name} + ${item.value} +
  • `; + }); + return ` +
    ${title}
    + + `; + }, }, views: [ { @@ -59,20 +95,35 @@ fetch('https://gw.alipayobjects.com/os/bmw-prod/738147f2-2cef-4591-8e0d-4fd5268c region: { start: { x: 0, y: 0.35 }, end: { x: 1, y: 0.65 } }, coordinate: { type: 'theta', - cfg: { innerRadius: 0.78, radius: 0.96 }, + cfg: { innerRadius: 0.84, radius: 0.96 }, }, geometries: [ { type: 'interval', - xField: '1', yField: 'counts', colorField: 'type', mapping: { - color: [...COLORS, '#D9D9D9'], + color: ({ type }) => { + const idx = types.indexOf(type); + const { colors10 = [] } = labChart.chart.getTheme(); + return colors10[idx] || '#D9D9D9'; + }, }, adjust: { type: 'stack' }, }, ], + annotations: [ + { + type: 'text', + content: 'G2Plot', + position: ['50%', '50%'], + style: { + textAlign: 'center', + fontWeight: 400, + fontSize: 28, + }, + }, + ], }, { data: getPointViewData(currentYear), @@ -89,15 +140,24 @@ fetch('https://gw.alipayobjects.com/os/bmw-prod/738147f2-2cef-4591-8e0d-4fd5268c tickLine: null, label: null, }, - age: { + ageGroup: { + tickLine: null, min: 20, max: 100, tickInterval: 20, - alias: '获奖\n年龄', + title: { + text: '获奖\n年龄', + autoRotate: false, + offset: 12, + style: { fontSize: 10, textBaseline: 'bottom' }, + }, label: { + offset: -4, style: { + textBaseline: 'bottom', fontSize: 10, }, + formatter: (v) => (v === '100' ? '' : v), }, grid: { line: { @@ -112,32 +172,29 @@ fetch('https://gw.alipayobjects.com/os/bmw-prod/738147f2-2cef-4591-8e0d-4fd5268c { type: 'point', xField: 'country', - yField: 'age', + yField: 'ageGroup', colorField: 'type', + sizeField: 'number', + adjust: { + type: 'dodge', + }, mapping: { - size: 3, + size: [2, 8], shape: 'circle', style: { + fillOpacity: 0.65, lineWidth: 0, }, - color: COLORS, }, }, - ], - }, - { - // 国家展示 - data: getDataGroupByField('country'), - region: { start: { x: 0.18, y: 0.18 }, end: { x: 0.82, y: 0.82 } }, - coordinate: { type: 'polar', cfg: { innerRadius: 0.99, radius: 1 } }, - geometries: [ { + // 国家标签 type: 'interval', xField: 'country', - yField: '1', label: { labelEmit: true, fields: ['country'], + offset: 50, style: { fontSize: 10, }, @@ -150,7 +207,7 @@ fetch('https://gw.alipayobjects.com/os/bmw-prod/738147f2-2cef-4591-8e0d-4fd5268c }, { // 年度 label 展示 - data: getDataGroupByField('year'), + data: yearData, region: { start: { x: 0.05, y: 0.05 }, end: { x: 0.95, y: 0.95 }, @@ -171,55 +228,40 @@ fetch('https://gw.alipayobjects.com/os/bmw-prod/738147f2-2cef-4591-8e0d-4fd5268c { type: 'line', xField: 'year', - yField: '0.9', label: { labelEmit: true, content: ({ year }) => { - return year === 1901 || Number(year) % 10 === 0 ? year : year === 2015 ? '' : '-'; + if (year === 1900) { + return ''; + } + if (year === 2016) { + return ' ALL '; + } + return Number(year) % 10 === 0 ? year : '-'; }, }, mapping: { color: 'transparent', }, }, - ], - }, - { - // 滑块 - data: getDataGroupByField('year'), - region: { - start: { x: 0.05, y: 0.05 }, - end: { x: 0.95, y: 0.95 }, - }, - coordinate: { type: 'polar', cfg: { innerRadius: 0.99, radius: 1 } }, - axes: { - 1: null, - year: { - // todo fix G2 tickCount 为 0,会死循环 - // tickCount: 0, - label: null, - }, - }, - geometries: [ { type: 'interval', xField: 'year', - yField: '1', label: { labelEmit: true, fields: ['year'], callback: (year) => { + const { defaultColor } = labChart.chart.getTheme(); return { style: { fill: year === currentYear ? 'rgba(255,255,255,0.85)' : 'transparent', }, - content: () => `${currentYear}`, + content: () => `${currentYear === 2016 ? ' ALL ' : currentYear}`, background: { padding: 2, - // @ts-ignore - radius: 2, style: { - fill: year === currentYear ? 'pink' : 'transparent', + radius: 1, + fill: year === currentYear ? defaultColor : 'transparent', }, }, }; @@ -235,45 +277,42 @@ fetch('https://gw.alipayobjects.com/os/bmw-prod/738147f2-2cef-4591-8e0d-4fd5268c }); labChart.render(); - // @ts-ignore - window.chart = labChart; - const dymaticView = labChart.chart.views[4]; - dymaticView.on('element:click', (evt) => { - const data = evt.data?.data; - if (data) { - if (typeof data?.year === 'number') { - currentYear = data.year; - rerender(currentYear); - } - } - }); - function rerender(y) { - labChart.chart.views[0].changeData(getIntervalViewData(y)); - labChart.chart.views[1].changeData(getPointViewData(y)); - dymaticView.geometries[0].label('year', (year) => ({ - labelEmit: true, - style: { - fill: year === y ? 'rgba(255,255,255,0.85)' : 'transparent', - }, - content: () => `${y}`, - background: { - padding: 2, - // @ts-ignore - radius: 2, + const view1 = labChart.chart.views[1]; + const view2 = labChart.chart.views[2]; + const view3 = labChart.chart.views[2]; + // 根据 view3 中创建的顺序,可知 滑块对应的第 2 个几何标记对象 geometry + const sliderBlock = view3.geometries[1]; + function rerender(specYear) { + view1.changeData(getIntervalViewData(specYear)); + view2.changeData(getPointViewData(specYear)); + sliderBlock.label('year', (year) => { + const { defaultColor } = labChart.chart.getTheme(); + return { + labelEmit: true, style: { - fill: year === y ? 'pink' : 'transparent', + fill: year === specYear ? 'rgba(255,255,255,0.85)' : 'transparent', }, - }, - })); - dymaticView.render(true); + content: () => `${specYear === 2016 ? ' ALL ' : specYear}`, + background: { + padding: 2, + style: { + radius: 1, + // 非当前年份,进行透明展示 + fill: year === specYear ? defaultColor : 'transparent', + }, + }, + }; + }); + // 传入参数 true,重新绘制,不重新触发更新流程。 + view3.render(true); } let interval; function start() { + clearInterval(interval); interval = setInterval(() => { - if (currentYear < 2016) { - currentYear += 1; + if (currentYear++ < 2016) { rerender(currentYear); } else { end(); @@ -285,15 +324,25 @@ fetch('https://gw.alipayobjects.com/os/bmw-prod/738147f2-2cef-4591-8e0d-4fd5268c interval = null; } - start(); - // 延迟绑定事件 - setTimeout(() => { - document.querySelector('#btn').addEventListener('click', () => { - if (!interval) { - start(); - } else { - end(); + function handldSlideBlockClick(evt) { + const data = evt.data?.data; + if (data) { + if (typeof data?.year === 'number') { + currentYear = data.year; + rerender(currentYear); } - }); - }, 500); + } + } + // 监听 element click 事件,指定当前年份,并且启动轮播 + view3.on('element:click', (evt) => { + handldSlideBlockClick(evt); + start(); + }); + // 监听 element click 事件,指定当前年份,并且暂停轮播 + view3.on('element:dblclick', (evt) => { + handldSlideBlockClick(evt); + end(); + }); + + start(); }); diff --git a/src/plots/multi-view/adaptor.ts b/src/plots/multi-view/adaptor.ts index a3b83feb74..ddad132842 100644 --- a/src/plots/multi-view/adaptor.ts +++ b/src/plots/multi-view/adaptor.ts @@ -64,7 +64,7 @@ function multiView(params: Params): Params { } }); - // 7. annotations + // 8. annotations each(annotations, (annotation) => { viewOfG2.annotation()[annotation.type]({ ...annotation,