Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable zoom plugin on treemap controller #141

Merged
merged 12 commits into from
Oct 12, 2022
3 changes: 2 additions & 1 deletion docs/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ module.exports = {
'captions',
'dividers',
'rtl',
'datalabels'
'datalabels',
'zoom'
],
'/': [
'',
Expand Down
78 changes: 78 additions & 0 deletions docs/samples/zoom.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Using Zoom plugin

```js chart-editor
// <block:setup:1>
const DATA_COUNT = 12;
const NUMBER_CFG = {count: DATA_COUNT, min: 2, max: 40};
// </block:setup>

// <block:utils:2>
function colorFromRaw(ctx, border) {
if (ctx.type !== 'data') {
return 'transparent';
}
const value = ctx.raw.v;
let alpha = (1 + Math.log(value)) / 5;
const color = 'orange';
if (border) {
alpha += 0.01;
}
return helpers.color(color)
.alpha(alpha)
.rgbString();
}
// </block:utils>

// <block:config:0>
const config = {
type: 'treemap',
data: {
datasets: [
{
label: 'My First dataset',
tree: Utils.numbers(NUMBER_CFG),
borderWidth: 0,
backgroundColor: (ctx) => colorFromRaw(ctx),
labels: {
display: true,
formatter: (ctx) => ctx.raw.v.toFixed(2),
font: {
size: 16
},
overflow: 'hidden'
}
}
],
},
options: {
plugins: {
zoom: {
zoom: {
wheel: {
enabled: true,
}
},
pan: {
enabled: true,
}
}
}
}
};

// </block:config>

const actions = [
{
name: 'Reset zoom',
handler(chart) {
chart.resetZoom();
}
},
];

module.exports = {
actions,
config,
};
```
3 changes: 2 additions & 1 deletion docs/scripts/register.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import Chart from 'chart.js/auto';
import {TreemapController, TreemapElement} from '../../dist/chartjs-chart-treemap.esm';
import ChartDataLabels from 'chartjs-plugin-datalabels';
import zoomPlugin from 'chartjs-plugin-zoom';

Chart.register(TreemapController, TreemapElement, ChartDataLabels);
Chart.register(TreemapController, TreemapElement, ChartDataLabels, zoomPlugin);
Chart.defaults.plugins.datalabels.display = false;

Chart.register({
Expand Down
37 changes: 37 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"chart.js": "^3.6.0",
"chartjs-adapter-date-fns": "^2.0.0",
"chartjs-plugin-datalabels": "^2.0.0",
"chartjs-plugin-zoom": "^1.2.0",
"chartjs-test-utils": "^0.5.0",
"concurrently": "^7.4.0",
"cross-env": "^7.0.3",
Expand Down
50 changes: 46 additions & 4 deletions src/controller.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Chart, DatasetController, registry} from 'chart.js';
import {toFont, valueOrDefault, isObject} from 'chart.js/helpers';
import {group, requireVersion, normalizeTreeToArray, getGroupKey} from './utils';
import {toFont, valueOrDefault, isObject, clipArea, unclipArea, defined} from 'chart.js/helpers';
import {group, requireVersion, normalizeTreeToArray, getGroupKey, minValue, maxValue} from './utils';
import {shouldDrawCaption, parseBorderWidth} from './element';
import squarify from './squarify';
import {version} from '../package.json';
Expand Down Expand Up @@ -78,30 +78,69 @@ function buildData(dataset, mainRect) {
: squarify(tree, mainRect, key);
}

function getMinMax(data, useTree) {
const vMax = useTree ? 1 : maxValue(data);
const vMin = useTree ? 0 : minValue(data, vMax);
return {vMin, vMax};
}

function getArea({xScale, yScale}, data, rtl, useTree) {
const {vMin, vMax} = getMinMax(data, useTree);
const xMin = xScale.getPixelForValue(0);
const xMax = xScale.getPixelForValue(1);
const yMin = yScale.getPixelForValue(vMin);
const yMax = yScale.getPixelForValue(vMax);
return {x: xMin, y: yMax, w: xMax - xMin, h: yMin - yMax, rtl};
}

export default class TreemapController extends DatasetController {
constructor(chart, datasetIndex) {
super(chart, datasetIndex);

this._rect = undefined;
this._key = undefined;
this._groups = undefined;
this._useTree = undefined;
}

initialize() {
this.enableOptionSharing = true;
super.initialize();
}

/**
* TODO: to be removed when https://github.com/kurkle/chartjs-chart-treemap/issues/137
* will be implemented
*/
updateRangeFromParsed(range, scale) {
if (range.updated) {
return;
}
range.updated = true;
if (scale.axis === 'x') {
range.min = 0;
range.max = 1;
return;
}
const me = this;
const dataset = me.getDataset();
const {vMin, vMax} = getMinMax(dataset.data, me._useTree);
range.min = vMin;
range.max = vMax;
}

update(mode) {
const me = this;
const meta = me.getMeta();
const dataset = me.getDataset();
if (!defined(me._useTree)) {
me._useTree = !!dataset.tree;
}
const groups = dataset.groups || (dataset.groups = []);
const area = me.chart.chartArea;
const key = dataset.key || '';
const rtl = !!dataset.rtl;

const mainRect = {x: area.left, y: area.top, w: area.right - area.left, h: area.bottom - area.top, rtl};
const mainRect = getArea(meta, dataset.data, rtl, me._useTree);

if (mode === 'reset' || rectNotEqual(me._rect, mainRect) || me._key !== key || arrayNotEqual(me._groups, groups)) {
me._rect = mainRect;
Expand Down Expand Up @@ -151,17 +190,20 @@ export default class TreemapController extends DatasetController {
draw() {
const me = this;
const ctx = me.chart.ctx;
const area = me.chart.chartArea;
const metadata = me.getMeta().data || [];
const dataset = me.getDataset();
const levels = (dataset.groups || []).length - 1;
const data = dataset.data;

clipArea(ctx, area);
for (let i = 0, ilen = metadata.length; i < ilen; ++i) {
const rect = metadata[i];
if (!rect.hidden) {
rect.draw(ctx, data[i], levels);
}
}
unclipArea(ctx);
}
}

Expand Down
14 changes: 12 additions & 2 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import {isObject} from 'chart.js/helpers';

const getValue = (item) => isObject(item) ? item.v : item;

export const maxValue = (data) => data.reduce(function(m, v) {
return (m > getValue(v) ? m : getValue(v));
}, 0);

export const minValue = (data, mx) => data.reduce(function(m, v) {
return (m < getValue(v) ? m : getValue(v));
}, mx);

export const getGroupKey = (lvl) => '' + lvl;

function scanTreeObject(key, treeLeafKey, obj, tree = [], lvl = 0, result = []) {
Expand Down Expand Up @@ -32,11 +42,11 @@ export function normalizeTreeToArray(key, treeLeafKey, obj) {
if (!data.length) {
return data;
}
const max = data.reduce(function(maxValue, element) {
const max = data.reduce(function(maxVal, element) {
// minus 2 because _leaf and value properties are added
// on top to groups ones
const keys = Object.keys(element).length - 2;
return maxValue > keys ? maxValue : keys;
return maxVal > keys ? maxVal : keys;
});
data.forEach(function(element) {
for (let i = 0; i < max; i++) {
Expand Down
42 changes: 42 additions & 0 deletions test/fixtures/basic/differentAxes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
export default {
tolerance: 0.0280,
config: {
type: 'treemap',
data: {
datasets: [{
label: 'Simple treemap',
data: [6, 6, 4, 3, 2, 2, 1],
backgroundColor: 'red',
labels: {
display: true,
formatter({chart, datasetIndex}) {
const meta = chart.getDatasetMeta(datasetIndex);
return 'x: ' + meta.xScale.id + ', y: ' + meta.yScale.id;
}
}
}]
},
options: {
events: [],
scales: {
a: {
type: 'linear',
display: false,
axis: 'x'
},
b: {
type: 'linear',
display: false,
axis: 'y'
},
}
}
},
options: {
spriteText: true,
canvas: {
height: 256,
width: 512
}
}
};
Binary file added test/fixtures/basic/differentAxes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions test/fixtures/basic/noXAxes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
export default {
tolerance: 0.0320,
config: {
type: 'treemap',
data: {
datasets: [{
label: 'Simple treemap',
data: [6, 6, 4, 3, 2, 2, 1],
backgroundColor: 'red',
labels: {
display: true,
formatter({chart, datasetIndex}) {
const meta = chart.getDatasetMeta(datasetIndex);
return 'x: ' + meta.xScale.id + ', y: ' + meta.yScale.id;
}
}
}]
},
options: {
events: [],
scales: {
a: {
type: 'linear',
display: false,
axis: 'y'
},
b: {
type: 'linear',
display: false,
axis: 'y'
},
}
}
},
options: {
spriteText: true,
canvas: {
height: 256,
width: 512
}
}
};
Binary file added test/fixtures/basic/noXAxes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading