From 703fba703c39668149fdbb8cc36bbf204f2e016c Mon Sep 17 00:00:00 2001 From: paleface001 Date: Sun, 12 Jan 2020 01:18:01 +0800 Subject: [PATCH] feat: add rect treemap layer --- __tests__/unit/treemap-spec.ts | 377 ++-------------- __tests__/unit/treemap-spec2.ts | 407 ++++++++++++++++++ src/plots/index.ts | 1 + src/plots/treemap/index.ts | 15 + src/plots/treemap/layer.ts | 88 ++++ src/plots/treemap/layout/squarify.ts | 2 +- .../treemap/layout/util/color-mapping.ts | 85 ++++ 7 files changed, 623 insertions(+), 352 deletions(-) create mode 100644 __tests__/unit/treemap-spec2.ts create mode 100644 src/plots/treemap/layout/util/color-mapping.ts diff --git a/__tests__/unit/treemap-spec.ts b/__tests__/unit/treemap-spec.ts index 8b7c0caaba..40dc036480 100644 --- a/__tests__/unit/treemap-spec.ts +++ b/__tests__/unit/treemap-spec.ts @@ -1,357 +1,32 @@ +import { Treemap } from '../../src'; import { mobile } from '../data/mobile'; -import { gdp } from '../data/gdp'; -import { dice } from '../../src/plots/treemap/layout/dice'; -import { slice } from '../../src/plots/treemap/layout/slice'; -import { squarify } from '../../src/plots/treemap/layout/squarify'; -import { VoronoiIterator } from '../../src/plots/treemap/layout/voronoi-iterator'; -import { weightedVoronoi } from '../../src/plots/treemap/layout/weighted-voronoi'; -import * as G from '@antv/g'; -import { each, clone,hasKey } from '@antv/util'; -import { triangulation } from '../../src/plots/treemap/layout/util/polygon'; -import { randomPointsInPolygon, randomPointsInCircle } from '../../src/plots/treemap/layout/util/random-position'; - -const canvasDiv = document.createElement('div'); -canvasDiv.style.width = '600px'; -canvasDiv.style.height = '400px'; -canvasDiv.id = 'test'; -document.body.appendChild(canvasDiv); - -const containerBBox = { - x: 0, - y: 0, - width: 600, - height: 400, -}; - -const canvas = new G.Canvas({ - containerId: 'test', - width: 600, - height: 400, - pixelRatio: 2, - renderer: 'canvas', -}); - -const data = processData(mobile); - -describe('tree layout', () => { - it('dice layout', () => { - const data = mobile[1]; - dice(data, containerBBox.x, containerBBox.y, containerBBox.width, containerBBox.height); - each(data.children, (d) => { - canvas.addShape('rect', { - attrs: { - x: d.x, - y: d.y, - width: d.width, - height: d.height, - fill: '#ccc', - stroke: 'black', - lineWidth: 1, - }, - }); - }); - canvas.draw(); - }); - - it('slice layout', () => { - const data = mobile[1]; - slice(data, containerBBox.x, containerBBox.y, containerBBox.width, containerBBox.height); - each(data.children, (d) => { - canvas.addShape('rect', { - attrs: { - x: d.x, - y: d.y, - width: d.width, - height: d.height, - fill: '#ccc', - stroke: 'black', - lineWidth: 1, - }, - }); - }); - canvas.draw(); - }); - it('squarify layout', () => { - const rows = squarify(data, containerBBox.x, containerBBox.y, containerBBox.width, containerBBox.height); - each(rows, (row) => { - each(row.children, (c) => { - const width = c.x1 - c.x0; - const height = c.y1 - c.y0; - drawRect(c.x0, c.y0, width, height); - }); - }); - }); - - it('triangulate polygon', () => { - const points = [ - [100, 10], - [300, 10], - [400, 300], - [10, 300], - ]; - const vertex = triangulation(points); - const polygonPath = []; - each(points, (p, index) => { - const flag = index === 0 ? 'M' : 'L'; - polygonPath.push([flag, p[0], p[1]]); - }); - const trianglePath = []; - for (let i = 0; i < vertex.length; i += 3) { - const p0 = points[vertex[i]]; - const p1 = points[vertex[i + 1]]; - const p2 = points[vertex[i + 2]]; - trianglePath.push( - ...[ - ['M', p0[0], p0[1]], - ['L', p1[0], p1[1]], - ['L', p2[0], p2[1]], - ['L', p0[0], p0[1]], - ] - ); - } - canvas.addShape('path', { - attrs: { - path: polygonPath, - fill: '#ccc', - }, - }); - canvas.addShape('path', { - attrs: { - path: trianglePath, - stroke: 'black', - lineWidth: 1, - }, - }); - canvas.draw(); - }); - - it('random points in ploygon', () => { - const polygon = [ - [100, 10], - [300, 10], - [400, 300], - [10, 300], - ]; - const points = randomPointsInPolygon(polygon, 500); - const polygonPath = []; - each(polygon, (p, index) => { - const flag = index === 0 ? 'M' : 'L'; - polygonPath.push([flag, p[0], p[1]]); - }); - canvas.addShape('path', { - attrs: { - path: polygonPath, - fill: '#ccc', - }, - }); - each(points, (p) => { - canvas.addShape('circle', { - attrs: { - x: p[0], - y: p[1], - r: 1, - fill: 'black', - }, - }); - canvas.draw(); - }); - canvas.draw(); - }); - - - it('weighted voronoi', () => { - const { x, y, width, height } = containerBBox; - const { children } = data; - const clipPolygon = [ - [x, y], - [x, height], - [width, height], - [width, y], - ]; - - each(children, (c, index) => { - c.weight = c.value; +import { each } from '@antv/util'; + +describe('treemap',()=>{ + const canvasDiv = document.createElement('div'); + canvasDiv.style.width = '800px'; + canvasDiv.style.height = '600px'; + canvasDiv.style.left = '30px'; + canvasDiv.style.top = '30px'; + canvasDiv.id = 'canvas1'; + document.body.appendChild(canvasDiv); + const data = processData(mobile); + it('initilize',()=>{ + const piePlot = new Treemap(canvasDiv, { + width: 800, + height: 600, + data, + maxLevel:2 + }); + piePlot.render(); }); - children.sort((a,b)=>{ - return b.weight - a.weight; - }) - const randomPoints = randomPointsInPolygon(clipPolygon, children.length); - //const randomPoints = spiralLayout(600,400, 10,10,children.length); - each(children, (c, index) => { - c.x = randomPoints[index][0]; - c.y = randomPoints[index][1]; - //c.weight = c.value / data.value; - }); - - const cells = weightedVoronoi(data.children, clipPolygon); - each(cells, (c) => { - const path = []; - each(c, (p, index) => { - const flag = index === 0 ? 'M' : 'L'; - path.push([flag, p[0], p[1]]); - }); - canvas.addShape('path', { - attrs: { - path, - fill: '#ccc', - stroke: 'black', - lineWidth: 1, - }, - }); - canvas.draw(); - }); - }); - - it('circle voronoi',()=>{ - const gdpData = processGdpData(); - const { children } = gdpData; - const { x, y, width, height } = containerBBox; - const cx = x + width/2; - const cy = y + height/2; - const radius = Math.min(width,height)*0.5; - const clipPolygon = createCircleClip(cx,cy,radius); - const randomPoints = randomPointsInPolygon(clipPolygon, children.length); - // const randomPoints = randomPointsInCircle(cx,cy,radius,children.length); - each(children, (c, index) => { - c.x = randomPoints[index][0]; - c.y = randomPoints[index][1]; - c.weight = gdpData.value / c.value; - }); - const cells = weightedVoronoi(children, clipPolygon); - each(cells, (c) => { - const path = []; - each(c, (p, index) => { - const flag = index === 0 ? 'M' : 'L'; - path.push([flag, p[0], p[1]]); - }); - path.push(['Z']); - canvas.addShape('path', { - attrs: { - path, - fill: '#ccc', - stroke: 'black', - lineWidth: 1, - }, - }); - canvas.draw(); - }); - }); - - it.only('recursive voronoi',()=>{ - const gdpData = processGdpData(); - const { children } = gdpData; - const { x, y, width, height } = containerBBox; - const cx = x + width/2; - const cy = y + height/2; - const radius = Math.min(width,height)*0.5; - const clipPolygon = createCircleClip(cx,cy,radius); - const cells = recursive(gdpData,clipPolygon,0); - each(cells,(c,index)=>{ - const root = c.site.originalObject.data.originalData; - recursive(root,c,1); - }); - }); }); function processData(data) { - let sumValue = 0; - each(data, (d) => { - sumValue += d.value; - }); - - return { name: 'root', value: sumValue, children: data }; -} - -function drawRect(x, y, width, height) { - canvas.addShape('rect', { - attrs: { - x: x, - y: y, - width: width, - height: height, - fill: '#ccc', - stroke: 'black', - lineWidth: 1, - }, - }); - canvas.draw(); -} - - -function createCircleClip(cx,cy,radius){ - const step = 50; - const interval = Math.PI * 2 / step; - const points = []; - for(let i = 0; i{ - if(d.year === 2016){ - const countries = d.countries; - const region = d.region_simple; - const population = d.population; - if(!hasKey(root,region)){ - root[region] = { name:region, region,value:0,children:[]}; - } - root[region].value += population; - sum += population; - root[region].children.push({name:countries,value: population,region}); - } - }); - - each(root,(r) =>{ - data.push(r); - }); - - return { name:'root', value:sum, children:data }; -} - -function recursive(root,cliper,iii){ - const colors = { - "Middle East and Africa": "#596F7E", - "Americas": "#168B98", - "Asia": "#ED5B67", - "Oceania": "#fd8f24", - "Europe": "#919c4c" - }; - const { children } = root; - // const randomPoints = randomPointsInPolygon(cliper,children.length); - each(children, (c, index) => { - c.weight = c.value; - }); - const shapeType = iii === 0 ? 'circle' : 'polygon'; - const iterator = new VoronoiIterator(clone(children), cliper,'polygon', 600, 400); - // const cells = weightedVoronoi(children, cliper); - const cells = iterator.polygons; - each(cells, (c,index) => { - const color = colors[c.site.originalObject.data.originalData.region]; - const path = []; - each(c, (p, index) => { - const flag = index === 0 ? 'M' : 'L'; - path.push([flag, p[0], p[1]]); - }); - path.push(['Z']); - canvas.addShape('path', { - attrs: { - path, - fill: iii === 0 ? color : null, - stroke: 'white', - lineWidth: iii === 0 ? 4 : 1 - }, + let sumValue = 0; + each(data, (d) => { + sumValue += d.value; }); - canvas.draw(); - }); - - return cells; -} \ No newline at end of file + + return { name: 'root', value: sumValue, children: data }; + } \ No newline at end of file diff --git a/__tests__/unit/treemap-spec2.ts b/__tests__/unit/treemap-spec2.ts new file mode 100644 index 0000000000..791bd6f097 --- /dev/null +++ b/__tests__/unit/treemap-spec2.ts @@ -0,0 +1,407 @@ +import { mobile } from '../data/mobile'; +import { dice } from '../../src/plots/treemap/layout/dice'; +import { slice } from '../../src/plots/treemap/layout/slice'; +import squarify from '../../src/plots/treemap/layout/squarify'; +import { VoronoiIterator } from '../../src/plots/treemap/layout/voronoi-iterator'; +import { weightedVoronoi } from '../../src/plots/treemap/layout/weighted-voronoi'; +import * as G from '@antv/g'; +import { each, clone,hasKey } from '@antv/util'; +import { triangulation } from '../../src/plots/treemap/layout/util/polygon'; +import { randomPointsInPolygon } from '../../src/plots/treemap/layout/util/random-position'; +import { getScale } from '@antv/scale'; +import { rgb2arr, arr2rgb } from '../../src/util/color'; + +const canvasDiv = document.createElement('div'); +canvasDiv.style.width = '600px'; +canvasDiv.style.height = '400px'; +canvasDiv.id = 'test'; +document.body.appendChild(canvasDiv); + +const containerBBox = { + x: 0, + y: 0, + width: 600, + height: 400, +}; + +const canvas = new G.Canvas({ + containerId: 'test', + width: 600, + height: 400, + pixelRatio: 2, + renderer: 'canvas', +}); + +const data = processData(mobile); + +describe('tree layout', () => { + it('dice layout', () => { + const data = mobile[1]; + dice(data, containerBBox.x, containerBBox.y, containerBBox.width, containerBBox.height); + each(data.children, (d) => { + canvas.addShape('rect', { + attrs: { + x: d.x0, + y: d.y0, + width: d.x1 - d.x0, + height: d.y1 - d.y0, + fill: '#ccc', + stroke: 'black', + lineWidth: 1, + }, + }); + }); + canvas.draw(); + }); + + it.only('slice layout', () => { + const data = mobile[1]; + slice(data, containerBBox.x, containerBBox.y, containerBBox.width, containerBBox.height); + each(data.children, (d) => { + canvas.addShape('rect', { + attrs: { + x: d.x0, + y: d.y0, + width: d.x1, + height: d.y1, + fill: '#ccc', + stroke: 'black', + lineWidth: 1, + }, + }); + }); + canvas.draw(); + }); + it('squarify layout', () => { + + const rows = squarify(data, containerBBox.x, containerBBox.y, containerBBox.width, containerBBox.height); + recursiveRect(rows,0); + }); + + it('triangulate polygon', () => { + const points = [ + [100, 10], + [300, 10], + [400, 300], + [10, 300], + ]; + const vertex = triangulation(points); + const polygonPath = []; + each(points, (p, index) => { + const flag = index === 0 ? 'M' : 'L'; + polygonPath.push([flag, p[0], p[1]]); + }); + const trianglePath = []; + for (let i = 0; i < vertex.length; i += 3) { + const p0 = points[vertex[i]]; + const p1 = points[vertex[i + 1]]; + const p2 = points[vertex[i + 2]]; + trianglePath.push( + ...[ + ['M', p0[0], p0[1]], + ['L', p1[0], p1[1]], + ['L', p2[0], p2[1]], + ['L', p0[0], p0[1]], + ] + ); + } + canvas.addShape('path', { + attrs: { + path: polygonPath, + fill: '#ccc', + }, + }); + canvas.addShape('path', { + attrs: { + path: trianglePath, + stroke: 'black', + lineWidth: 1, + }, + }); + canvas.draw(); + }); + + it('random points in ploygon', () => { + const polygon = [ + [100, 10], + [300, 10], + [400, 300], + [10, 300], + ]; + const points = randomPointsInPolygon(polygon, 500); + const polygonPath = []; + each(polygon, (p, index) => { + const flag = index === 0 ? 'M' : 'L'; + polygonPath.push([flag, p[0], p[1]]); + }); + canvas.addShape('path', { + attrs: { + path: polygonPath, + fill: '#ccc', + }, + }); + each(points, (p) => { + canvas.addShape('circle', { + attrs: { + x: p[0], + y: p[1], + r: 1, + fill: 'black', + }, + }); + canvas.draw(); + }); + canvas.draw(); + }); + + + it('weighted voronoi', () => { + const { x, y, width, height } = containerBBox; + const { children } = data; + const clipPolygon = [ + [x, y], + [x, height], + [width, height], + [width, y], + ]; + + each(children, (c, index) => { + c.weight = c.value; + }); + children.sort((a,b)=>{ + return b.weight - a.weight; + }) + const randomPoints = randomPointsInPolygon(clipPolygon, children.length); + //const randomPoints = spiralLayout(600,400, 10,10,children.length); + each(children, (c, index) => { + c.x = randomPoints[index][0]; + c.y = randomPoints[index][1]; + //c.weight = c.value / data.value; + }); + + const cells = weightedVoronoi(data.children, clipPolygon); + each(cells, (c) => { + const path = []; + each(c, (p, index) => { + const flag = index === 0 ? 'M' : 'L'; + path.push([flag, p[0], p[1]]); + }); + canvas.addShape('path', { + attrs: { + path, + fill: '#ccc', + stroke: 'black', + lineWidth: 1, + }, + }); + canvas.draw(); + }); + }); + + it('circle voronoi',()=>{ + const gdpData = processGdpData(); + const { children } = gdpData; + const { x, y, width, height } = containerBBox; + const cx = x + width/2; + const cy = y + height/2; + const radius = Math.min(width,height)*0.5; + const clipPolygon = createCircleClip(cx,cy,radius); + const randomPoints = randomPointsInPolygon(clipPolygon, children.length); + // const randomPoints = randomPointsInCircle(cx,cy,radius,children.length); + each(children, (c, index) => { + c.x = randomPoints[index][0]; + c.y = randomPoints[index][1]; + c.weight = gdpData.value / c.value; + }); + const cells = weightedVoronoi(children, clipPolygon); + each(cells, (c) => { + const path = []; + each(c, (p, index) => { + const flag = index === 0 ? 'M' : 'L'; + path.push([flag, p[0], p[1]]); + }); + path.push(['Z']); + canvas.addShape('path', { + attrs: { + path, + fill: '#ccc', + stroke: 'black', + lineWidth: 1, + }, + }); + canvas.draw(); + }); + }); + + it('recursive voronoi',()=>{ + const { x, y, width, height } = containerBBox; + const gdpData = processGdpData(); + const { children,value } = gdpData; + const cx = x + width/2; + const cy = y + height/2; + const radius = Math.min(width,height)*0.5; + // const clipPolygon = createCircleClip(cx,cy,radius); + /*const clipPolygon = [ + [x, y], + [x, height], + [width, height], + [width, y], + ];*/ + + const clipPolygon = [ + [x + width /2, y], + [x,y+height],[x+width,y+height] + ]; + + const cells = recursive(gdpData,clipPolygon,value,0); + each(cells,(c,index)=>{ + const root = c.site.originalObject.data.originalData; + recursive(root,c,value,1); + }); + }); +}); + +function processData(data) { + let sumValue = 0; + each(data, (d) => { + sumValue += d.value; + }); + + return { name: 'root', value: sumValue, children: data }; +} + +function drawRect(x, y, width, height,color) { + canvas.addShape('rect', { + attrs: { + x: x, + y: y, + width: width, + height: height, + fill: color, + stroke: 'black', + lineWidth: color === null ? 1 : 2, + }, + }); + canvas.draw(); +} + + +function createCircleClip(cx,cy,radius){ + const step = 50; + const interval = Math.PI * 2 / step; + const points = []; + for(let i = 0; i{ + if(d.year === 2016){ + const countries = d.countries; + const region = d.region_simple; + const population = d.population; + if(!hasKey(root,region)){ + root[region] = { name:region, region,value:0,children:[]}; + } + root[region].value += population; + sum += population; + root[region].children.push({name:countries,value: population,region}); + } + }); + + each(root,(r) =>{ + data.push(r); + }); + + return { name:'root', value:sum, children:data }; +} + +function recursive(root,cliper,sum,iii){ + const colors = { + "Middle East and Africa": "#5D7092", //#596F7E + "Americas": "#5AD8A6", //#168B98 + "Asia": "#E8684A", //#ED5B67 + "Oceania": "#5B8FF9", //#fd8f24 + "Europe": "#F6BD16" //#919c4c + }; + const { children } = root; + // const randomPoints = randomPointsInPolygon(cliper,children.length); + each(children, (c, index) => { + c.weight = c.value; + c.percent = c.value / root.value; + }); + const iterator = new VoronoiIterator(clone(children), cliper,'polygon', 600, 400); + // const cells = weightedVoronoi(children, cliper); + const cells = iterator.polygons; + each(cells, (c,index) => { + const data = c.site.originalObject.data.originalData; + const color = colors[data.region]; + const path = []; + each(c, (p, index) => { + const flag = index === 0 ? 'M' : 'L'; + path.push([flag, p[0], p[1]]); + }); + path.push(['Z']); + canvas.addShape('path', { + attrs: { + path, + fill: iii === 0 ? color : null, + stroke: 'white', + lineWidth: iii === 0 ? 4 : 1 + }, + }); + canvas.draw(); + }); + + return cells; +} + + +function recursiveRect(rows,i){ + + const COLOR_PLATE_20 = [ + '#5B8FF9', + '#BDD2FD', + '#5AD8A6', + '#BDEFDB', + '#5D7092', + '#C2C8D5', + '#F6BD16', + '#FBE5A2', + '#E8684A', + '#F6C3B7', + '#6DC8EC', + '#B6E3F5', + '#9270CA', + '#D3C6EA', + '#FF9D4D', + '#FFD8B8', + '#269A99', + '#AAD8D8', + '#FF99C3', + '#FFD6E7', + ]; + let index = 0; + each(rows, (row) => { + each(row.children, (c) => { + const width = c.x1 - c.x0; + const height = c.y1 - c.y0; + const color = i === 0 ? COLOR_PLATE_20[index] : null; + drawRect(c.x0, c.y0, width, height,color); + if(c.children){ + const c_rows = squarify(c, c.x0, c.y0, c.x1,c.y1); + recursiveRect(c_rows,1); + } + index ++; + }); + }); +} diff --git a/src/plots/index.ts b/src/plots/index.ts index 4720de35cd..bef061c907 100644 --- a/src/plots/index.ts +++ b/src/plots/index.ts @@ -23,3 +23,4 @@ export { default as Funnel, FunnelConfig } from './funnel'; export { default as Heatmap, HeatmapConfig } from './heatmap'; export { default as Matrix, MatrixConfig } from './matrix'; export { default as Waterfall, WaterfallConfig } from './waterfall'; +export { default as Treemap } from './treemap'; diff --git a/src/plots/treemap/index.ts b/src/plots/treemap/index.ts index e69de29bb2..124b48c911 100644 --- a/src/plots/treemap/index.ts +++ b/src/plots/treemap/index.ts @@ -0,0 +1,15 @@ +import * as _ from '@antv/util'; +import BasePlot, { PlotConfig } from '../../base/plot'; +import TreemapLayer, { TreemapViewConfig } from './layer'; + +export interface TreemapConfig extends TreemapViewConfig, PlotConfig {} + +export default class Treemap extends BasePlot { + public static getDefaultOptions: typeof TreemapLayer.getDefaultOptions = TreemapLayer.getDefaultOptions; + + public createLayers(props) { + const layerProps = _.deepMix({}, props); + layerProps.type = 'treemap'; + super.createLayers(layerProps); + } +} \ No newline at end of file diff --git a/src/plots/treemap/layer.ts b/src/plots/treemap/layer.ts index e69de29bb2..ca9925e46b 100644 --- a/src/plots/treemap/layer.ts +++ b/src/plots/treemap/layer.ts @@ -0,0 +1,88 @@ +import * as _ from '@antv/util'; +import { registerPlotType } from '../../base/global'; +import { LayerConfig } from '../../base/layer'; +import ViewLayer, { ViewConfig } from '../../base/view-layer'; +import { getComponent } from '../../components/factory'; +import { LooseMap } from '../../interface/types'; +import { DataItem } from '../../interface/config'; +import squarify from './layout/squarify'; + +export interface TreemapViewConfig extends ViewConfig { + data:any; + maxLevel?: number; +} + +export interface TreemapLayerConfig extends TreemapViewConfig, LayerConfig {} + +export default class TreemapLayer extends ViewLayer { + public static getDefaultOptions(): Partial { + return _.deepMix({}, super.getDefaultOptions(), { + maxLevel: 2, + padding:[0,0,0,0], + tooltip:{ + visible: false + }, + legend:{ + visible: false + } + }); + } + public type: string = 'line'; + + protected geometryParser(dim, type) { + return 'polygon'; + } + + protected processData(){ + const viewRange = this.getViewRange(); + const { data } = this.options; + const root = squarify(data, viewRange.x, viewRange.y, viewRange.width, viewRange.height); + const treemapData = []; + this.getAllNodes(root,treemapData); + this.options.xField = 'x'; + this.options.yField = 'y'; + return treemapData; + } + + protected axis(){} + protected coord() {} + protected addGeometry(){ + const rect: any = { + type: 'polygon', + position: { + fields: ['x', 'y'], + }, + color:{ + fields:['brand'] + }, + style:{ + values:[{ + lineWidth: 2, + stroke:'white' + }] + } + }; + this.setConfig('element', rect); + } + + private recursive(){ + } + + private getAllNodes(data,nodes){ + const viewRange = this.getViewRange(); + _.each(data,(d)=>{ + if(_.hasKey(d,'children')){ + this.getAllNodes(d.children,nodes); + } + if(d.x0){ + nodes.push({ + ...d, + x:[d.x0,d.x1,d.x1,d.x0], + y:[viewRange.height - d.y1,viewRange.height - d.y1,viewRange.height - d.y0,viewRange.height - d.y0] + }); + } + }); + } +} + +registerPlotType('treemap', TreemapLayer); \ No newline at end of file diff --git a/src/plots/treemap/layout/squarify.ts b/src/plots/treemap/layout/squarify.ts index 72df3dc7a2..d96943b361 100644 --- a/src/plots/treemap/layout/squarify.ts +++ b/src/plots/treemap/layout/squarify.ts @@ -6,7 +6,7 @@ import { slice } from './slice'; // 黄金分割 const ratio = (1 + Math.sqrt(5)) / 2; -export function squarify(root, x0, y0, x1, y1) { +export default function squarify(root, x0, y0, x1, y1) { const { children } = root; let value = root.value; children.sort((a, b) => { diff --git a/src/plots/treemap/layout/util/color-mapping.ts b/src/plots/treemap/layout/util/color-mapping.ts new file mode 100644 index 0000000000..b4590f1abc --- /dev/null +++ b/src/plots/treemap/layout/util/color-mapping.ts @@ -0,0 +1,85 @@ +import { getScale } from '@antv/scale'; + +const maxDepth = 4; +const LinearScale = getScale('linear'); +const hueScale = new LinearScale({ + max:20, + min:1 +}); +const hueRange = [1, 359]; +const lightnessScale = new LinearScale({ + max:maxDepth, + min:0 +}); +const lightnessRange = [0.55, 0.85]; + +const saturationScale = new LinearScale({ + max:maxDepth, + min:0 +}); +const saturationRange = [0.55, 0.85]; + +function createOrdinalCat(len){ + const cat = []; + for(let i = 0; i= 240 ? h - 240 : h + 120, m1, m2), + hsl2rgb(h, m1, m2), + hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2), + this.opacity +); +} + +function s(v){ + return v * 20; +} + +export function colorMapping(d,o,isLeaf){ + if (o === 0) { + return 'white'; + } + const c = s(d.percent); + const h = Math.floor(hue(c)) + Math.floor(lightness(o) * 45); + if (isLeaf) { + return hsl2rgb(h, 0.85, 0.85); + // return hsl(h, 0.85, 0.85).hex(); + } + return hsl2rgb(h, saturation(o), lightness(o)); + // return hsl(h, saturation(o), lightness(o)).hex(); +} \ No newline at end of file