diff --git a/plugins/legend.js b/plugins/legend.js
index f6e2afb87..965c49cb2 100644
--- a/plugins/legend.js
+++ b/plugins/legend.js
@@ -1,501 +1,475 @@
import Taucharts from 'taucharts';
import * as d3 from 'd3-format';
- var utils = Taucharts.api.utils;
- var pluginsSDK = Taucharts.api.pluginsSDK;
- var RESET_SELECTOR = '.tau-chart__legend__reset';
- var COLOR_ITEM_SELECTOR = '.tau-chart__legend__item-color';
- var COLOR_TOGGLE_SELECTOR = '.tau-chart__legend__guide--color__overlay';
- var SIZE_TICKS_COUNT = 4;
- var FONT_SIZE = 13;
-
- var counter = 0;
- var getId = function () {
- return ++counter;
- };
-
- const xml = Taucharts.api.utils.xml;
+const utils = Taucharts.api.utils;
+const pluginsSDK = Taucharts.api.pluginsSDK;
+const RESET_SELECTOR = '.tau-chart__legend__reset';
+const COLOR_ITEM_SELECTOR = '.tau-chart__legend__item-color';
+const COLOR_TOGGLE_SELECTOR = '.tau-chart__legend__guide--color__overlay';
+const SIZE_TICKS_COUNT = 4;
+const FONT_SIZE = 13;
+
+let counter = 0;
+const getId = () => ++counter;
+
+const xml = Taucharts.api.utils.xml;
+
+const splitEvenly = (domain, parts) => {
+ const min = domain[0];
+ const max = domain[1];
+ const segment = ((max - min) / (parts - 1));
+ const chunks = utils.range(parts - 2).map(n => min + segment * (n + 1));
+ return [min].concat(chunks).concat(max);
+};
+
+const splitRealValuesEvenly = (values, count, funcType) => {
+
+ if (values.length < 3) {
+ return values.slice(0);
+ }
+ if (count < 3) {
+ return [values[0], values[values.length - 1]];
+ }
- var splitEvenly = function (domain, parts) {
- var min = domain[0];
- var max = domain[1];
- var segment = ((max - min) / (parts - 1));
- var chunks = utils.range(parts - 2).map(function (n) {
- return (min + segment * (n + 1));
+ const neg = (values[0] < 0 ? Math.abs(values[0]) : 0);
+ const repeat = x => x;
+ const sqrt = x => Math.sqrt(x + neg);
+ const square = x => x ** 2 - neg;
+ const input = (funcType === 'sqrt' ? sqrt : repeat);
+ const ouput = (funcType === 'sqrt' ? square : repeat);
+
+ values = values.map(input);
+ let result = [values[0]];
+ const length = (values[values.length - 1] - values[0]);
+ const halfStep = (0.5 * length / (count - 1));
+
+ const steps = utils.range(1, count - 1)
+ .map(i => {
+ const mid = (length * i / (count - 1));
+ return {
+ min: mid - halfStep,
+ mid,
+ max: mid + halfStep,
+ diff: Number.MAX_VALUE,
+ closest: null
+ };
});
- return [min].concat(chunks).concat(max);
+ let si = 0;
+ let step;
+ const nextStep = () => {
+ if (si === steps.length) {
+ return;
+ }
+ const prevStep = step;
+ step = steps[si++];
+ step.min = Math.max(
+ (step.min),
+ ((prevStep && prevStep.closest !== null ? prevStep.closest : result[0]) + halfStep)
+ );
};
+ nextStep();
- var splitRealValuesEvenly = function (values, count, funcType) {
-
- if (values.length < 3) {
- return values.slice(0);
+ values.forEach(value => {
+ if (value < step.min) {
+ return;
+ }
+ if (value > step.max) {
+ nextStep();
+ }
+ const diff = Math.abs(value - step.mid);
+ if (diff < step.diff && diff < halfStep) {
+ step.diff = diff;
+ step.closest = value;
+ } else {
+ nextStep();
}
- if (count < 3) {
- return [values[0], values[values.length - 1]];
+ if (diff === 0) {
+ nextStep();
}
+ });
- var neg = (values[0] < 0 ? Math.abs(values[0]) : 0);
- var repeat = function (x) {
- return x;
- };
- var sqrt = function (x) {
- return Math.sqrt(x + neg);
- };
- var square = function (x) {
- return (Math.pow(x, 2) - neg);
- };
- var input = (funcType === 'sqrt' ? sqrt : repeat);
- var ouput = (funcType === 'sqrt' ? square : repeat);
-
- values = values.map(input);
- var result = [values[0]];
- var length = (values[values.length - 1] - values[0]);
- var halfStep = (0.5 * length / (count - 1));
-
- var steps = utils.range(1, count - 1)
- .map(function (i) {
- var mid = (length * i / (count - 1));
- return {
- min: mid - halfStep,
- mid: mid,
- max: mid + halfStep,
- diff: Number.MAX_VALUE,
- closest: null
- };
- });
- var si = 0;
- var step;
- var nextStep = function () {
- if (si === steps.length) {
- return;
- }
- var prevStep = step;
- step = steps[si++];
- step.min = Math.max(
- (step.min),
- ((prevStep && prevStep.closest !== null ? prevStep.closest : result[0]) + halfStep)
- );
- };
- nextStep();
-
- values.forEach(function (value) {
- if (value < step.min) {
- return;
- }
- if (value > step.max) {
- nextStep();
- }
- var diff = Math.abs(value - step.mid);
- if (diff < step.diff && diff < halfStep) {
- step.diff = diff;
- step.closest = value;
- } else {
- nextStep();
- }
- if (diff === 0) {
- nextStep();
- }
- });
+ steps.forEach(s => {
+ if (s.closest !== null) {
+ result.push(s.closest);
+ }
+ });
- steps.forEach(function (s) {
- if (s.closest !== null) {
- result.push(s.closest);
- }
- });
+ result.push(values[values.length - 1]);
- result.push(values[values.length - 1]);
+ result = result.map(ouput);
- result = result.map(ouput);
+ return result;
+};
- return result;
- };
+const log10 = x => Math.log(x) / Math.LN10;
- var log10 = function (x) {
- return Math.log(x) / Math.LN10;
- };
+const getExponent = x => {
+ if (x === 0) {
+ return 0;
+ }
+ return Math.floor(log10(Math.abs(x)));
+};
+
+const removeRedundantZeros = ((() => {
+ const zerosAfterDot = /\.0+([^\d].*)?$/;
+ const zerosAfterNotZero = /(\.\d+?)0+([^\d].*)?$/;
+ return str => str
+ .replace(zerosAfterDot, '$1')
+ .replace(zerosAfterNotZero, '$1$2');
+}))();
+
+const d3Format3S = d3.format('.3s');
+const shortNumFormat = num => removeRedundantZeros(d3Format3S(num));
+
+const getNumberFormatter = (start, end) => {
+
+ const max = Math.max(Math.abs(start), Math.abs(end));
+ const absExp = getExponent(max);
+ const diff = (start * end > 0 ? Math.abs(end - start) : max);
+ const diffExp = getExponent(diff);
+ const absExpVsDiffExp = Math.abs(absExp - diffExp);
+
+ if (Math.abs(absExp) > 3 && absExpVsDiffExp <= 3) {
+ // Short format
+ // 1k, 500k, 1M.
+ return shortNumFormat;
+ }
- var getExponent = function (x) {
- if (x === 0) {
- return 0;
- }
- return Math.floor(log10(Math.abs(x)));
+ // Show necessary digits:
+ // 100001, 100002, 100003;
+ // 0.10001, 0.10002, 0.10003.
+ return num => {
+ const numExp = getExponent(max - num);
+ const trailingDigits = Math.min((
+ (diffExp < 0 ? Math.abs(diffExp) : 0) +
+ (numExp < diffExp ? 1 : 0)
+ ), 20); // NOTE: `toFixed` accepts values between 0 and 20.
+ return removeRedundantZeros(num.toFixed(trailingDigits));
};
+};
+
+function ChartLegend(xSettings) {
+ let firstRender = true;
+ const settings = utils.defaults(
+ xSettings || {},
+ {
+ formatters: {},
+ onSelect: () => {
+ }
+ });
- var removeRedundantZeros = (function () {
- var zerosAfterDot = /\.0+([^\d].*)?$/;
- var zerosAfterNotZero = /(\.\d+?)0+([^\d].*)?$/;
- return function (str) {
- return str
- .replace(zerosAfterDot, '$1')
- .replace(zerosAfterNotZero, '$1$2');
- };
- })();
-
- var d3Format3S = d3.format('.3s');
- var shortNumFormat = function (num) {
- return removeRedundantZeros(d3Format3S(num));
+ const doEven = n => {
+ n = Math.round(n);
+ return n % 2 ? n + 1 : n;
};
- var getNumberFormatter = function (start, end) {
+ const isEmpty = x => (x === null) || (x === '') || (typeof x === 'undefined');
- var max = Math.max(Math.abs(start), Math.abs(end));
- var absExp = getExponent(max);
- var diff = (start * end > 0 ? Math.abs(end - start) : max);
- var diffExp = getExponent(diff);
- var absExpVsDiffExp = Math.abs(absExp - diffExp);
+ const isDateDomain = domain => domain.every(v => utils.isDate(v));
- if (Math.abs(absExp) > 3 && absExpVsDiffExp <= 3) {
- // Short format
- // 1k, 500k, 1M.
- return shortNumFormat;
- }
+ const createIsRowMatchInterceptor = (dim, val) => row => {
+ const d = row[dim];
+ const r = JSON.stringify(isEmpty(d) ? null : d);
+ return (val === r);
+ };
- // Show necessary digits:
- // 100001, 100002, 100003;
- // 0.10001, 0.10002, 0.10003.
- return function (num) {
- var numExp = getExponent(max - num);
- var trailingDigits = Math.min((
- (diffExp < 0 ? Math.abs(diffExp) : 0) +
- (numExp < diffExp ? 1 : 0)
- ), 20); // NOTE: `toFixed` accepts values between 0 and 20.
- return removeRedundantZeros(num.toFixed(trailingDigits));
- };
+ const _delegateEvent = (element, eventName, selector, callback) => {
+ element.addEventListener(eventName, e => {
+ let target = e.target;
+ while (target !== e.currentTarget && target !== null) {
+ if (target.matches(selector)) {
+ callback(e, target);
+ }
+ target = target.parentNode;
+ }
+ });
};
- function ChartLegend(xSettings) {
+ return {
- var settings = utils.defaults(
- xSettings || {},
- {
- formatters: {},
- });
+ init(chart) {
+ this.instanceId = getId();
- var doEven = function (n) {
- n = Math.round(n);
- return n % 2 ? n + 1 : n;
- };
+ this._chart = chart;
+ this._currentFilters = {};
+ this._legendColorByScaleId = {};
+ this._legendOrderState = {};
- var isEmpty = function (x) {
- return (x === null) || (x === '') || (typeof x === 'undefined');
- };
+ const spec = this._chart.getSpec();
- var isDateDomain = function (domain) {
- return domain.every(function (v) {
- return utils.isDate(v);
- });
- };
-
- var createIsRowMatchInterceptor = function (dim, val) {
- return function (row) {
- var d = row[dim];
- var r = JSON.stringify(isEmpty(d) ? null : d);
- return (val === r);
- };
- };
-
- var _delegateEvent = function (element, eventName, selector, callback) {
- element.addEventListener(eventName, function (e) {
- var target = e.target;
- while (target !== e.currentTarget && target !== null) {
- if (target.matches(selector)) {
- callback(e, target);
- }
- target = target.parentNode;
+ const reducer = scaleType => (memo, k) => {
+ const s = spec.scales[k];
+ if (s.type === scaleType && s.dim) {
+ memo.push(k);
}
- });
- };
-
- return {
+ return memo;
+ };
- init: function (chart) {
- this.instanceId = getId();
+ this._color = Object
+ .keys(spec.scales)
+ .reduce(reducer('color'), [])
+ .filter(scale => chart.getScaleInfo(scale).discrete);
+
+ this._fill = Object
+ .keys(spec.scales)
+ .reduce(reducer('color'), [])
+ .filter(scale => !chart.getScaleInfo(scale).discrete);
+
+ this._size = Object
+ .keys(spec.scales)
+ .reduce(reducer('size'), []);
+
+ const hasColorScales = (this._color.length > 0);
+ const hasFillScales = (this._fill.length > 0);
+ const hasSizeScales = (this._size.length > 0);
+ this._assignStaticBrewersOrEx();
+
+ if (hasColorScales || hasFillScales || hasSizeScales) {
+
+ switch (settings.position) {
+ case 'left':
+ this._container = this._chart.insertToLeftSidebar(this._containerTemplate);
+ break;
+ case 'right':
+ this._container = this._chart.insertToRightSidebar(this._containerTemplate);
+ break;
+ case 'top':
+ this._container = this._chart.insertToHeader(this._containerTemplate);
+ break;
+ case 'bottom':
+ this._container = this._chart.insertToFooter(this._containerTemplate);
+ break;
+ default:
+ this._container = this._chart.insertToRightSidebar(this._containerTemplate);
+ break;
+ }
- this._chart = chart;
- this._currentFilters = {};
- this._legendColorByScaleId = {};
- this._legendOrderState = {};
+ if (hasColorScales) {
+ _delegateEvent(
+ this._container,
+ 'click',
+ RESET_SELECTOR,
+ (e, currentTarget) => {
+ this._toggleLegendItem(currentTarget, 'reset');
+ });
- var spec = this._chart.getSpec();
+ _delegateEvent(
+ this._container,
+ 'click',
+ COLOR_ITEM_SELECTOR,
+ (e, currentTarget) => {
+ const mode = (e.ctrlKey || e.target.matches(COLOR_TOGGLE_SELECTOR) ?
+ 'leave-others' :
+ 'focus-single');
+ this._toggleLegendItem(currentTarget, mode);
+ });
- var reducer = function (scaleType) {
- return function (memo, k) {
- var s = spec.scales[k];
- if (s.type === scaleType && s.dim) {
- memo.push(k);
+ _delegateEvent(
+ this._container,
+ 'mouseover',
+ COLOR_ITEM_SELECTOR,
+ (e, currentTarget) => {
+ this._highlightToggle(currentTarget, true);
}
- return memo;
- };
- };
-
- this._color = Object
- .keys(spec.scales)
- .reduce(reducer('color'), [])
- .filter(function (scale) {
- return chart.getScaleInfo(scale).discrete;
- });
-
- this._fill = Object
- .keys(spec.scales)
- .reduce(reducer('color'), [])
- .filter(function (scale) {
- return !chart.getScaleInfo(scale).discrete;
- });
-
- this._size = Object
- .keys(spec.scales)
- .reduce(reducer('size'), []);
-
- var hasColorScales = (this._color.length > 0);
- var hasFillScales = (this._fill.length > 0);
- var hasSizeScales = (this._size.length > 0);
-
- this._assignStaticBrewersOrEx();
-
- if (hasColorScales || hasFillScales || hasSizeScales) {
-
- switch (settings.position) {
- case 'left':
- this._container = this._chart.insertToLeftSidebar(this._containerTemplate);
- break;
- case 'right':
- this._container = this._chart.insertToRightSidebar(this._containerTemplate);
- break;
- case 'top':
- this._container = this._chart.insertToHeader(this._containerTemplate);
- break;
- case 'bottom':
- this._container = this._chart.insertToFooter(this._containerTemplate);
- break;
- default:
- this._container = this._chart.insertToRightSidebar(this._containerTemplate);
- break;
- }
-
- if (hasColorScales) {
- _delegateEvent(
- this._container,
- 'click',
- RESET_SELECTOR,
- function (e, currentTarget) {
- this._toggleLegendItem(currentTarget, 'reset');
- }.bind(this));
-
- _delegateEvent(
- this._container,
- 'click',
- COLOR_ITEM_SELECTOR,
- function (e, currentTarget) {
- var mode = (e.ctrlKey || e.target.matches(COLOR_TOGGLE_SELECTOR) ?
- 'leave-others' :
- 'focus-single');
- this._toggleLegendItem(currentTarget, mode);
- }.bind(this));
-
- _delegateEvent(
- this._container,
- 'mouseover',
- COLOR_ITEM_SELECTOR,
- function (e, currentTarget) {
- this._highlightToggle(currentTarget, true);
- }.bind(this)
- );
-
- _delegateEvent(
- this._container,
- 'mouseout',
- COLOR_ITEM_SELECTOR,
- function (e, currentTarget) {
- this._highlightToggle(currentTarget, false);
- }.bind(this)
- );
- }
- }
- },
-
- destroy() {
- const filters = this._currentFilters;
- const chart = this._chart;
- Object.keys(filters)
- .forEach((id) => chart.removeFilter(filters[id]));
-
- if (this._container && this._container.parentElement) {
- this._clearPanel();
- this._container.parentElement.removeChild(this._container);
+ );
+
+ _delegateEvent(
+ this._container,
+ 'mouseout',
+ COLOR_ITEM_SELECTOR,
+ (e, currentTarget) => {
+ this._highlightToggle(currentTarget, false);
+ }
+ );
}
- },
-
- onSpecReady: function (chart, specRef) {
- this._formatters = pluginsSDK.getFieldFormatters(specRef, settings.formatters);
- },
+ }
+ },
- _getFormat(dim) {
- return (this._formatters[dim] ?
- this._formatters[dim].format :
- (x) => String(x));
- },
+ destroy() {
+ const filters = this._currentFilters;
+ const chart = this._chart;
+ Object.keys(filters)
+ .forEach((id) => chart.removeFilter(filters[id]));
- onRender: function () {
+ if (this._container && this._container.parentElement) {
this._clearPanel();
- this._drawColorLegend();
- this._drawFillLegend();
- this._drawSizeLegend();
- },
-
- // tslint:disable max-line-length
- _containerTemplate: '
',
- _template: utils.template([
- '',
- '<%=top%>',
- '
<%=name%>
',
- '<%=items%>',
- '
'
- ].join('')),
- _itemTemplate: utils.template([
- '\' data-dim=\'<%= dim %>\' data-value=\'<%= value %>\' class="tau-chart__legend__item tau-chart__legend__item-color <%=classDisabled%>">',
- '
',
- '
<%=label%>',
- '
'
- ].join('')),
- _resetTemplate: utils.template([
- ''
- ].join('')),
- // tslint:enable max-line-length
-
- _clearPanel: function () {
- if (this._container) {
- clearTimeout(this._scrollTimeout);
- this._getScrollContainer().removeEventListener('scroll', this._scrollListener);
- this._container.innerHTML = '';
- }
- },
+ this._container.parentElement.removeChild(this._container);
+ }
+ },
+
+ onSpecReady(chart, specRef) {
+ this._formatters = pluginsSDK.getFieldFormatters(specRef, settings.formatters);
+ },
+ _getFormat(dim) {
+ return (this._formatters[dim] ?
+ this._formatters[dim].format :
+ (x) => String(x));
+ },
+
+ onRender() {
+ if (firstRender && settings.selectedCategories && settings.selectedCategories.length !== 0) {
+ let legendColorByScales = this._getLegendColorByScales();
+ Object.keys(legendColorByScales).forEach((key) => {
+ legendColorByScales[key].legendColorItems.forEach(({value: val, dim}) => {
+ if(settings.selectedCategories.indexOf(JSON.parse(val)) === -1) {
+ const key = dim + val;
+ const isRowMatch = createIsRowMatchInterceptor(dim, val);
+ this._currentFilters[key] = this._chart.addFilter({
+ tag: 'legend',
+ predicate(row) {
+ return !isRowMatch(row);
+ }
+ });
+ }
+ });
+ });
+ firstRender = false;
+ this._chart.refresh();
+ return;
+ }
+ this._clearPanel();
+ this._drawColorLegend();
+ this._drawFillLegend();
+ this._drawSizeLegend();
+ },
+
+ // tslint:disable max-line-length
+ _containerTemplate: '',
+ _template: utils.template([
+ '',
+ '<%=top%>',
+ '
<%=name%>
',
+ '<%=items%>',
+ '
'
+ ].join('')),
+ _itemTemplate: utils.template([
+ '\' data-dim=\'<%= dim %>\' data-value=\'<%= value %>\' class="tau-chart__legend__item tau-chart__legend__item-color <%=classDisabled%>">',
+ '
',
+ '
<%=label%>',
+ '
'
+ ].join('')),
+ _resetTemplate: utils.template([
+ ''
+ ].join('')),
+ // tslint:enable max-line-length
+
+ _clearPanel() {
+ if (this._container) {
+ clearTimeout(this._scrollTimeout);
+ this._getScrollContainer().removeEventListener('scroll', this._scrollListener);
+ this._container.innerHTML = '';
+ }
+ },
- _drawFillLegend: function () {
- var self = this;
+ _drawFillLegend() {
+ const self = this;
- self._fill.forEach(function (c) {
- var firstNode = self
- ._chart
- .select(function (unit) {
- return (unit.config.color === c);
- })
- [0];
+ self._fill.forEach(c => {
+ const firstNode = self
+ ._chart
+ .select(unit => unit.config.color === c)
+ [0];
- if (firstNode) {
+ if (firstNode) {
- var guide = firstNode.config.guide || {};
+ const guide = firstNode.config.guide || {};
- var fillScale = firstNode.getScale('color');
+ const fillScale = firstNode.getScale('color');
- var domain = fillScale.domain().sort(function (a, b) {
- return a - b;
- });
+ const domain = fillScale.domain().sort((a, b) => a - b);
- var isDate = isDateDomain(domain);
+ const isDate = isDateDomain(domain);
- var numDomain = (isDate ?
- domain.map(Number) :
- domain);
+ const numDomain = (isDate ?
+ domain.map(Number) :
+ domain);
- var numFormatter = getNumberFormatter(numDomain[0], numDomain[numDomain.length - 1]);
- var dateFormatter = (function () {
- var spec = self._chart.getSpec();
- var formatter = pluginsSDK.extractFieldsFormatInfo(spec)[fillScale.dim].format;
- if (!formatter) {
- formatter = function (x) {
- return new Date(x);
- };
- }
- return function (x) {
- return String(formatter(x));
- };
- })();
+ const numFormatter = getNumberFormatter(numDomain[0], numDomain[numDomain.length - 1]);
+ const dateFormatter = ((() => {
+ const spec = self._chart.getSpec();
+ let formatter = pluginsSDK.extractFieldsFormatInfo(spec)[fillScale.dim].format;
+ if (!formatter) {
+ formatter = x => new Date(x);
+ }
+ return x => String(formatter(x));
+ }))();
- var formatter = (isDate ?
- dateFormatter :
- numFormatter);
+ const formatter = (isDate ?
+ dateFormatter :
+ numFormatter);
- var brewerLength = fillScale.brewer.length;
- var title = ((guide.color || {}).label || {}).text || fillScale.dim;
+ const brewerLength = fillScale.brewer.length;
+ const title = ((guide.color || {}).label || {}).text || fillScale.dim;
- var getTextWidth = function (text) {
- return (text.length * FONT_SIZE * 0.618);
- };
- var labelsCount = (!fillScale.isInteger ? 3 :
+ const getTextWidth = text => text.length * FONT_SIZE * 0.618;
+ const labelsCount = (!fillScale.isInteger ? 3 :
((numDomain[1] - numDomain[0]) % 3 === 0) ? 4 :
((numDomain[1] - numDomain[0]) % 2 === 0) ? 3 : 2
- );
- var splitted = splitEvenly(numDomain, labelsCount);
- var labels = (isDate ? splitted.map(function (x) {
- return new Date(x);
- }) : splitted).map(formatter);
- if (labels[0] === labels[labels.length - 1]) {
- labels = [labels[0]];
- }
+ );
+ const splitted = splitEvenly(numDomain, labelsCount);
+ let labels = (isDate ? splitted.map(x => new Date(x)) : splitted).map(formatter);
+ if (labels[0] === labels[labels.length - 1]) {
+ labels = [labels[0]];
+ }
- self._container
- .insertAdjacentHTML('beforeend', self._template({
- name: title,
- top: null,
- items: ''
- }));
- var container = self._container
- .lastElementChild
- .querySelector('.tau-chart__legend__gradient-wrapper');
- var width = container.getBoundingClientRect().width;
- var totalLabelsW = labels.reduce(function (sum, label) {
- return (sum + getTextWidth(label));
- }, 0);
- var isVerticalLayout = false;
- if (totalLabelsW > width) {
- if (labels.length > 1 &&
- getTextWidth(labels[0]) + getTextWidth(labels[labels.length - 1]) > width
- ) {
- isVerticalLayout = true;
- } else {
- labels = [labels[0], labels[labels.length - 1]];
- }
+ self._container
+ .insertAdjacentHTML('beforeend', self._template({
+ name: title,
+ top: null,
+ items: ''
+ }));
+ const container = self._container
+ .lastElementChild
+ .querySelector('.tau-chart__legend__gradient-wrapper');
+ const width = container.getBoundingClientRect().width;
+ const totalLabelsW = labels.reduce((sum, label) => sum + getTextWidth(label), 0);
+ let isVerticalLayout = false;
+ if (totalLabelsW > width) {
+ if (labels.length > 1 &&
+ getTextWidth(labels[0]) + getTextWidth(labels[labels.length - 1]) > width
+ ) {
+ isVerticalLayout = true;
+ } else {
+ labels = [labels[0], labels[labels.length - 1]];
}
+ }
- var barSize = 20;
- var layout = (isVerticalLayout ?
- (function () {
- var height = 120;
- var dy = (FONT_SIZE * (0.618 - 1) / 2);
+ const barSize = 20;
+ const layout = (isVerticalLayout ?
+ ((() => {
+ const height = 120;
+ const dy = (FONT_SIZE * (0.618 - 1) / 2);
return {
- width: width,
- height: height,
+ width,
+ height,
barX: 0,
barY: 0,
barWidth: barSize,
barHeight: height,
textAnchor: 'start',
- textX: utils.range(labelsCount).map(function () {
- return 25;
- }),
+ textX: utils.range(labelsCount).map(() => 25),
textY: (labels.length === 1 ?
(height / 2 + FONT_SIZE * 0.618) :
- labels.map(function (_, i) {
- var t = ((labels.length - 1 - i) / (labels.length - 1));
+ labels.map((_, i) => {
+ const t = ((labels.length - 1 - i) / (labels.length - 1));
return (FONT_SIZE * (1 - t) + height * t + dy);
}))
};
- })() :
- (function () {
- var padL = (getTextWidth(labels[0]) / 2);
- var padR = (getTextWidth(labels[labels.length - 1]) / 2);
- var indent = 8;
+ }))() :
+ ((() => {
+ const padL = (getTextWidth(labels[0]) / 2);
+ const padR = (getTextWidth(labels[labels.length - 1]) / 2);
+ const indent = 8;
return {
- width: width,
+ width,
height: (barSize + indent + FONT_SIZE),
barX: 0,
barY: 0,
@@ -504,524 +478,492 @@ import * as d3 from 'd3-format';
textAnchor: 'middle',
textX: (labels.length === 1 ?
[width / 2] :
- labels.map(function (_, i) {
- var t = (i / (labels.length - 1));
+ labels.map((_, i) => {
+ const t = (i / (labels.length - 1));
return (padL * (1 - t) + (width - padR) * t);
})),
- textY: utils.range(labelsCount).map(function () {
- return (barSize + indent + FONT_SIZE);
- })
+ textY: utils.range(labelsCount).map(() => barSize + indent + FONT_SIZE)
};
- })()
- );
-
- var stops = splitEvenly(numDomain, brewerLength)
- .map(function (x, i) {
- var p = (i / (brewerLength - 1)) * 100;
- return xml('stop', {
- offset: `${p}%`,
- style: `stop-color:${fillScale(x)};stop-opacity:1"`
- });
+ }))()
+ );
+
+ const stops = splitEvenly(numDomain, brewerLength)
+ .map((x, i) => {
+ const p = (i / (brewerLength - 1)) * 100;
+ return xml('stop', {
+ offset: `${p}%`,
+ style: `stop-color:${fillScale(x)};stop-opacity:1"`
});
+ });
- var gradientId = 'legend-gradient-' + self.instanceId;
-
- var gradient = (
- xml('svg',
- {
- class: 'tau-chart__legend__gradient',
- width: layout.width,
- height: layout.height
- },
- xml('defs',
- xml('linearGradient',
- {
- id: gradientId,
- x1: '0%',
- y1: (isVerticalLayout ? '100%' : '0%'),
- x2: (isVerticalLayout ? '0%' : '100%'),
- y2: '0%'
- },
- ...stops
- )
- ),
- xml('rect', {
- class: 'tau-chart__legend__gradient__bar',
- x: layout.barX,
- y: layout.barY,
- width: layout.barWidth,
- height: layout.barHeight,
- fill: 'url(#' + gradientId + ')'
- }),
- ...labels.map(function (text, i) {
- return xml('text', {
- x: layout.textX[i],
- y: layout.textY[i],
- 'text-anchor': layout.textAnchor
- }, text);
- })
- )
- );
-
- container
- .insertAdjacentHTML('beforeend', gradient);
- }
- });
- },
-
- _drawSizeLegend: function () {
- var self = this;
-
- self._size.forEach(function (c) {
- var firstNode = self
- ._chart
- .select(function (unit) {
- return (unit.config.size === c);
- })
- [0];
+ const gradientId = `legend-gradient-${self.instanceId}`;
+
+ const gradient = (
+ xml('svg',
+ {
+ class: 'tau-chart__legend__gradient',
+ width: layout.width,
+ height: layout.height
+ },
+ xml('defs',
+ xml('linearGradient',
+ {
+ id: gradientId,
+ x1: '0%',
+ y1: (isVerticalLayout ? '100%' : '0%'),
+ x2: (isVerticalLayout ? '0%' : '100%'),
+ y2: '0%'
+ },
+ ...stops
+ )
+ ),
+ xml('rect', {
+ class: 'tau-chart__legend__gradient__bar',
+ x: layout.barX,
+ y: layout.barY,
+ width: layout.barWidth,
+ height: layout.barHeight,
+ fill: `url(#${gradientId})`
+ }),
+ ...labels.map((text, i) => xml('text', {
+ x: layout.textX[i],
+ y: layout.textY[i],
+ 'text-anchor': layout.textAnchor
+ }, text))
+ )
+ );
+
+ container
+ .insertAdjacentHTML('beforeend', gradient);
+ }
+ });
+ },
- if (firstNode) {
+ _drawSizeLegend() {
+ const self = this;
- var guide = firstNode.config.guide || {};
+ self._size.forEach(c => {
+ const firstNode = self
+ ._chart
+ .select(unit => unit.config.size === c)
+ [0];
- var sizeScale = firstNode.getScale('size');
+ if (firstNode) {
- var domain = sizeScale.domain().sort(function (a, b) {
- return a - b;
- });
- if (!Array.isArray(domain) || !domain.every(isFinite)) {
- return;
- }
+ const guide = firstNode.config.guide || {};
- var title = ((guide.size || {}).label || {}).text || sizeScale.dim;
-
- var first = domain[0];
- var last = domain[domain.length - 1];
-
- var values = [first];
- if ((last - first)) {
- var count = log10(last - first);
- var xF = Math.round((4 - count));
- var base = Math.pow(10, xF);
-
- var realValues = utils.unique(
- self._chart
- .getDataSources({
- excludeFilter: ['legend']
- })[sizeScale.source]
- .data
- .map(function (d) {
- return d[sizeScale.dim];
- })
- .filter(function (s) {
- return (s >= first && s <= last);
- }))
- .sort(function (a, b) {
- return (a - b);
- });
- var steps = splitRealValuesEvenly(realValues, SIZE_TICKS_COUNT, sizeScale.funcType);
+ const sizeScale = firstNode.getScale('size');
- values = utils.unique(steps
- .map(function (x) {
- return (Math.round(x * base) / base);
- }));
- }
+ const domain = sizeScale.domain().sort((a, b) => a - b);
+ if (!Array.isArray(domain) || !domain.every(isFinite)) {
+ return;
+ }
- var castNum = getNumberFormatter(values[0], values[values.length - 1]);
+ const title = ((guide.size || {}).label || {}).text || sizeScale.dim;
+
+ const first = domain[0];
+ const last = domain[domain.length - 1];
+
+ let values = [first];
+ if ((last - first)) {
+ const count = log10(last - first);
+ const xF = Math.round((4 - count));
+ const base = 10 ** xF;
+
+ const realValues = utils.unique(
+ self._chart
+ .getDataSources({
+ excludeFilter: ['legend']
+ })[sizeScale.source]
+ .data
+ .map(d => d[sizeScale.dim])
+ .filter(s => s >= first && s <= last))
+ .sort((a, b) => a - b);
+ const steps = splitRealValuesEvenly(realValues, SIZE_TICKS_COUNT, sizeScale.funcType);
+
+ values = utils.unique(steps
+ .map(x => Math.round(x * base) / base));
+ }
- var getTextWidth = function (text) {
- return (text.length * FONT_SIZE * 0.618);
- };
- values.reverse();
- var sizes = values.map(sizeScale);
- var maxSize = Math.max.apply(null, sizes);
-
- var labels = values.map(castNum);
- self._container
- .insertAdjacentHTML('beforeend', self._template({
- name: title,
- top: null,
- items: ''
- }));
- var container = self._container
- .lastElementChild
- .querySelector('.tau-chart__legend__size-wrapper');
- var width = container.getBoundingClientRect().width;
- var maxLabelW = Math.max.apply(null, labels.map(getTextWidth));
- var isVerticalLayout = false;
- if (maxLabelW > width / 4 || labels.length === 1) {
- isVerticalLayout = true;
- }
+ const castNum = getNumberFormatter(values[0], values[values.length - 1]);
+
+ const getTextWidth = text => text.length * FONT_SIZE * 0.618;
+ values.reverse();
+ const sizes = values.map(sizeScale);
+ const maxSize = Math.max.apply(null, sizes);
+
+ const labels = values.map(castNum);
+ self._container
+ .insertAdjacentHTML('beforeend', self._template({
+ name: title,
+ top: null,
+ items: ''
+ }));
+ const container = self._container
+ .lastElementChild
+ .querySelector('.tau-chart__legend__size-wrapper');
+ const width = container.getBoundingClientRect().width;
+ const maxLabelW = Math.max.apply(null, labels.map(getTextWidth));
+ let isVerticalLayout = false;
+ if (maxLabelW > width / 4 || labels.length === 1) {
+ isVerticalLayout = true;
+ }
- var layout = (isVerticalLayout ?
- (function () {
- var gap = FONT_SIZE;
- var padT = (sizes[0] / 2);
- var padB = (sizes[sizes.length - 1] / 2);
- var indent = 8;
- var cy = [padT];
- for (var i = 1, n, p; i < sizes.length; i++) {
+ const layout = (isVerticalLayout ?
+ ((() => {
+ const gap = FONT_SIZE;
+ const padT = (sizes[0] / 2);
+ const padB = (sizes[sizes.length - 1] / 2);
+ const indent = 8;
+ const cy = [padT];
+ for (let i = 1, n, p; i < sizes.length; i++) {
p = (sizes[i - 1] / 2);
n = (sizes[i] / 2);
cy.push(cy[i - 1] + Math.max(FONT_SIZE * 1.618, p + gap + n));
}
- var dy = (FONT_SIZE * 0.618 / 2);
+ const dy = (FONT_SIZE * 0.618 / 2);
return {
- width: width,
+ width,
height: (cy[cy.length - 1] + Math.max(padB, FONT_SIZE / 2)),
- circleX: utils.range(sizes.length).map(function () {
- return (maxSize / 2);
- }),
+ circleX: utils.range(sizes.length).map(() => maxSize / 2),
circleY: cy,
textAnchor: 'start',
- textX: utils.range(labels.length).map(function () {
- return (maxSize + indent);
- }),
- textY: cy.map(function (y) {
- return (y + dy);
- })
+ textX: utils.range(labels.length).map(() => maxSize + indent),
+ textY: cy.map(y => y + dy)
};
- })() :
- (function () {
- var padL = Math.max(
+ }))() :
+ ((() => {
+ const padL = Math.max(
getTextWidth(labels[0]) / 2,
sizes[0] / 2
);
- var padR = Math.max(
+ const padR = Math.max(
getTextWidth(labels[labels.length - 1]) / 2,
sizes[sizes.length - 1] / 2
);
- var gap = (width - sizes.reduce(function (sum, n, i) {
- return (sum + (i === 0 || i === sizes.length - 1 ? n / 2 : n));
- }, 0) - padL - padR) / (SIZE_TICKS_COUNT - 1);
- var indent = 8;
- var cx = [padL];
- for (var i = 1, n, p; i < sizes.length; i++) {
+ const gap = (width - sizes
+ .reduce((sum, n, i) => {
+ return sum + (i === 0 || i === sizes.length - 1 ? n / 2 : n);
+ }, 0) - padL - padR) / (SIZE_TICKS_COUNT - 1);
+ const indent = 8;
+ const cx = [padL];
+ for (let i = 1, n, p; i < sizes.length; i++) {
p = (sizes[i - 1] / 2);
n = (sizes[i] / 2);
cx.push(cx[i - 1] + p + gap + n);
}
- var cy = sizes.map(function (size) {
- return (maxSize - size / 2);
- });
+ const cy = sizes.map(size => maxSize - size / 2);
return {
- width: width,
+ width,
height: (maxSize + indent + FONT_SIZE),
circleX: cx,
circleY: cy,
textAnchor: 'middle',
textX: cx,
- textY: utils.range(labels.length).map(function () {
- return (maxSize + indent + FONT_SIZE);
- }),
+ textY: utils.range(labels.length).map(() => maxSize + indent + FONT_SIZE),
};
- })()
- );
-
- var sizeLegend = (
- xml('svg',
- {
- class: 'tau-chart__legend__size',
- width: layout.width,
- height: layout.height
- },
- ...sizes.map(function (size, i) {
- return xml('circle', {
- class: (
- 'tau-chart__legend__size__item__circle ' +
- (firstNode.config.color ? 'color-definite' : 'color-default-size')
- ),
- cx: layout.circleX[i],
- cy: layout.circleY[i],
- r: (size / 2)
- });
- }),
- ...labels.map(function (text, i) {
- return xml('text', {
- class: 'tau-chart__legend__size__item__label',
- x: layout.textX[i],
- y: layout.textY[i],
- 'text-anchor': layout.textAnchor
- }, text);
- })
- )
- );
-
- container
- .insertAdjacentHTML('beforeend', sizeLegend);
- }
- });
- },
-
- _drawColorLegend: function () {
- var self = this;
-
- self._color.forEach(function (c) {
- var firstNode = self
- ._chart
- .select(function (unit) {
- return (unit.config.color === c);
- })
- [0];
+ }))()
+ );
+
+ const sizeLegend = (
+ xml('svg',
+ {
+ class: 'tau-chart__legend__size',
+ width: layout.width,
+ height: layout.height
+ },
+ ...sizes.map((size, i) => xml('circle', {
+ class: (
+ `tau-chart__legend__size__item__circle ${firstNode.config.color ?
+ 'color-definite' :
+ 'color-default-size'}`
+ ),
+ cx: layout.circleX[i],
+ cy: layout.circleY[i],
+ r: (size / 2)
+ })),
+ ...labels.map((text, i) => xml('text', {
+ class: 'tau-chart__legend__size__item__label',
+ x: layout.textX[i],
+ y: layout.textY[i],
+ 'text-anchor': layout.textAnchor
+ }, text))
+ )
+ );
+
+ container
+ .insertAdjacentHTML('beforeend', sizeLegend);
+ }
+ });
+ },
+ _getLegendColorByScales() {
+ const self = this;
+ return self._color.reduce((legendColorsInfo, c) => {
+ const firstNode = self
+ ._chart
+ .select(unit => unit.config.color === c)
+ [0];
- if (firstNode) {
+ if (firstNode) {
- var guide = firstNode.config.guide || {};
+ const guide = firstNode.config.guide || {};
- var colorScale = firstNode.getScale('color');
- var dataSource = self
- ._chart
- .getDataSources({excludeFilter: ['legend']});
+ const colorScale = firstNode.getScale('color');
+ const dataSource = self
+ ._chart
+ .getDataSources({excludeFilter: ['legend']});
- var domain = utils.unique(dataSource[colorScale.source].data
- .map(function (x) {
- return x[colorScale.dim];
- }));
+ let domain = utils.unique(dataSource[colorScale.source].data
+ .map(x => x[colorScale.dim]));
- var colorScaleConfig = self._chart.getSpec().scales[c];
- var isDate = isDateDomain(domain);
+ const colorScaleConfig = self._chart.getSpec().scales[c];
+ const isDate = isDateDomain(domain);
- if (colorScaleConfig.order) {
- domain = utils.union(utils.intersection(colorScaleConfig.order, domain), domain);
- } else if (colorScaleConfig.dimType === 'order' && isDate) {
- domain = domain.sort(function (a, b) {
- return new Date(a) - new Date(b);
- });
- } else {
- var orderState = self._legendOrderState[c];
- domain = domain.sort(function (a, b) {
- var diff = orderState[a] - orderState[b];
- return (diff && (diff / Math.abs(diff)));
- });
- }
-
- var title = ((guide.color || {}).label || {}).text || colorScale.dim;
- var noVal = ((guide.color || {}).tickFormatNullAlias || ('No ' + title));
-
- const format = self._getFormat(colorScale.dim);
+ if (colorScaleConfig.order) {
+ domain = utils.union(utils.intersection(colorScaleConfig.order, domain), domain);
+ } else if (colorScaleConfig.dimType === 'order' && isDate) {
+ domain = domain.sort((a, b) => new Date(a) - new Date(b));
+ } else {
+ const orderState = self._legendOrderState[c];
+ domain = domain.sort((a, b) => {
+ const diff = orderState[a] - orderState[b];
+ return (diff && (diff / Math.abs(diff)));
+ });
+ }
- var legendColorItems = domain.map(function (d) {
- var val = JSON.stringify(isEmpty(d) ? null : d);
- var key = colorScale.dim + val;
+ const title = ((guide.color || {}).label || {}).text || colorScale.dim;
+ const noVal = ((guide.color || {}).tickFormatNullAlias || (`No ${title}`));
- return {
- scaleId: c,
- dim: colorScale.dim,
- color: colorScale(d),
- disabled: self._currentFilters.hasOwnProperty(key),
- label: format(d),
- value: val
- };
- });
+ const format = self._getFormat(colorScale.dim);
- self._legendColorByScaleId[c] = legendColorItems;
- self._container
- .insertAdjacentHTML('beforeend', self._template({
- name: title,
- top: self._resetTemplate({
- classDisabled: (legendColorItems.some(function (d) {
- return d.disabled;
- }) ? '' : 'disabled')
- }),
- items: legendColorItems
- .map(function (d) {
- return self._itemTemplate({
- scaleId: d.scaleId,
- dim: utils.escape(d.dim),
- color: d.color,
- cssClass: (colorScale.toClass(d.color)),
- cssColor: (d.disabled ? 'transparent' : colorScale.toColor(d.color)),
- borderColor: colorScale.toColor(d.color),
- classDisabled: d.disabled ? 'disabled' : '',
- label: utils.escape(isEmpty(d.label) ? noVal : d.label),
- value: utils.escape(d.value)
- });
- })
- .join('')
- }));
- }
- });
+ let legendColorItems = domain.map(d => {
+ const val = JSON.stringify(isEmpty(d) ? null : d);
+ const key = colorScale.dim + val;
- if (self._color.length > 0) {
- self._updateResetButtonPosition();
- self._scrollTimeout = null;
- self._scrollListener = function () {
- var reset = self._container.querySelector(RESET_SELECTOR);
- reset.style.display = 'none';
- if (self._scrollTimeout) {
- clearTimeout(self._scrollTimeout);
- }
- self._scrollTimeout = setTimeout(function () {
- self._updateResetButtonPosition();
- reset.style.display = '';
- self._scrollTimeout = null;
- }, 250);
+ return {
+ scaleId: c,
+ dim: colorScale.dim,
+ color: colorScale(d),
+ disabled: self._currentFilters.hasOwnProperty(key),
+ label: format(d),
+ value: val
+ };
+ });
+ legendColorsInfo[c] = {
+ legendColorItems,
+ title,
+ colorScale,
+ noVal,
};
- self._getScrollContainer().addEventListener('scroll', self._scrollListener);
}
- },
-
- _toggleLegendItem: function (target, mode) {
+ return legendColorsInfo;
+ }, {});
+ },
+ _drawColorLegend() {
+ const self = this;
+ const legendColorByScales = this._getLegendColorByScales();
+ Object.keys(legendColorByScales).forEach((key) => {
+ const {legendColorItems, title, colorScale, noVal} = legendColorByScales[key];
+ self._container
+ .insertAdjacentHTML('beforeend', self._template({
+ name: title,
+ top: self._resetTemplate({
+ classDisabled: (legendColorItems.some(function (d) {
+ return d.disabled;
+ }) ? '' : 'disabled')
+ }),
+ items: legendColorItems
+ .map(function (d) {
+ return self._itemTemplate({
+ scaleId: d.scaleId,
+ dim: utils.escape(d.dim),
+ color: d.color,
+ cssClass: (colorScale.toClass(d.color)),
+ cssColor: (d.disabled ? 'transparent' : colorScale.toColor(d.color)),
+ borderColor: colorScale.toColor(d.color),
+ classDisabled: d.disabled ? 'disabled' : '',
+ label: utils.escape(isEmpty(d.label) ? noVal : d.label),
+ value: utils.escape(d.value)
+ });
+ })
+ .join('')
+ }));
+ });
- var filters = this._currentFilters;
- var colorNodes = (target ? Array.prototype.filter.call(
- target.parentNode.childNodes,
- function (el) {
- return el.matches(COLOR_ITEM_SELECTOR);
+ if (self._color.length > 0) {
+ self._updateResetButtonPosition();
+ self._scrollTimeout = null;
+ self._scrollListener = () => {
+ const reset = self._container.querySelector(RESET_SELECTOR);
+ reset.style.display = 'none';
+ if (self._scrollTimeout) {
+ clearTimeout(self._scrollTimeout);
}
- ) : null);
-
- var getColorData = function (node) {
- var dim = node.getAttribute('data-dim');
- var val = node.getAttribute('data-value');
- return {
- sid: node.getAttribute('data-scale-id'),
- dim: dim,
- val: val,
- key: (dim + val)
- };
+ self._scrollTimeout = setTimeout(() => {
+ self._updateResetButtonPosition();
+ reset.style.display = '';
+ self._scrollTimeout = null;
+ }, 250);
};
- var isColorHidden = function (key) {
- return (key in filters);
- };
- var toggleColor = function (node, show) {
- var data = getColorData(node);
- if (isColorHidden(data.key) !== show) {
- return;
- }
- if (show) {
- var filterId = filters[data.key];
- delete filters[data.key];
- node.classList.remove('disabled');
- this._chart.removeFilter(filterId);
- } else {
- node.classList.add('disabled');
- var isRowMatch = createIsRowMatchInterceptor(data.dim, data.val);
- filters[data.key] = this._chart.addFilter({
- tag: 'legend',
- predicate: function (row) {
- return !isRowMatch(row);
- }
- });
- }
- }.bind(this);
- var isTarget = function (node) {
- return (node === target);
- };
- var isTargetHidden = (target ? isColorHidden(getColorData(target).key) : false);
-
- var setGuideBackground = function (node, visible) {
- node.querySelector('.tau-chart__legend__guide')
- .style.backgroundColor = (visible ? '' : 'transparent');
+ self._getScrollContainer().addEventListener('scroll', self._scrollListener);
+ }
+ },
+
+ _toggleLegendItem(target, mode) {
+ const filters = this._currentFilters;
+ const colorNodes = (target ? Array.prototype.filter.call(
+ target.parentNode.childNodes,
+ el => el.matches(COLOR_ITEM_SELECTOR)
+ ) : null);
+
+ const getColorData = node => {
+ const dim = node.getAttribute('data-dim');
+ const val = node.getAttribute('data-value');
+ return {
+ sid: node.getAttribute('data-scale-id'),
+ dim,
+ val,
+ key: (dim + val)
};
-
- if (mode === 'reset') {
- colorNodes.forEach(function (node) {
- toggleColor(node, true);
- setGuideBackground(node, true);
- });
- } else if (mode === 'leave-others') {
- colorNodes.forEach(function (node) {
- if (isTarget(node)) {
- toggleColor(node, isTargetHidden);
+ };
+ const isColorHidden = key => key in filters;
+ const toggleColor = (node, show) => {
+ const data = getColorData(node);
+ if (isColorHidden(data.key) !== show) {
+ return;
+ }
+ if (show) {
+ const filterId = filters[data.key];
+ delete filters[data.key];
+ node.classList.remove('disabled');
+ this._chart.removeFilter(filterId);
+ } else {
+ node.classList.add('disabled');
+ const isRowMatch = createIsRowMatchInterceptor(data.dim, data.val);
+ filters[data.key] = this._chart.addFilter({
+ tag: 'legend',
+ predicate(row) {
+ return !isRowMatch(row);
}
});
- setGuideBackground(target, isTargetHidden);
- } else if (mode === 'focus-single') {
- var onlyTargetIsVisible = (!isTargetHidden && colorNodes.every(function (node) {
- return (isTarget(node) || isColorHidden(getColorData(node).key));
- }));
- colorNodes.forEach(function (node) {
- var show = (isTarget(node) || onlyTargetIsVisible);
- toggleColor(node, show);
- });
- if (isTargetHidden) {
- setGuideBackground(target, true);
- }
}
+ };
+ const isTarget = node => node === target;
+ const isTargetHidden = (target ? isColorHidden(getColorData(target).key) : false);
- this._chart.refresh();
- },
-
- _highlightToggle: function (target, doHighlight) {
+ const setGuideBackground = (node, visible) => {
+ node.querySelector('.tau-chart__legend__guide')
+ .style.backgroundColor = (visible ? '' : 'transparent');
+ };
- if (target.matches('.disabled')) {
- return;
+ if (mode === 'reset') {
+ colorNodes.forEach(node => {
+ toggleColor(node, true);
+ setGuideBackground(node, true);
+ });
+ } else if (mode === 'leave-others') {
+ colorNodes.forEach(node => {
+ if (isTarget(node)) {
+ toggleColor(node, isTargetHidden);
+ }
+ });
+ setGuideBackground(target, isTargetHidden);
+ } else if (mode === 'focus-single') {
+ const onlyTargetIsVisible = (
+ !isTargetHidden && colorNodes.every(node => isTarget(node) || isColorHidden(getColorData(node).key))
+ );
+ colorNodes.forEach(node => {
+ const show = (isTarget(node) || onlyTargetIsVisible);
+ toggleColor(node, show);
+ });
+ if (isTargetHidden) {
+ setGuideBackground(target, true);
}
+ }
+ const selectedCategories = colorNodes
+ .filter((node) => !isColorHidden(getColorData(node).key))
+ .map((node) => JSON.parse(getColorData(node).val));
+ settings.onSelect({
+ selectedCategories: selectedCategories
+ });
+ this._chart.refresh();
+ },
- // var scaleId = target.getAttribute('data-scale-id');
- var dim = target.getAttribute('data-dim');
- var val = target.getAttribute('data-value');
-
- var isRowMatch = doHighlight ?
- (createIsRowMatchInterceptor(dim, val)) :
- (function (row) { return null; });
-
- this._chart
- .select(function (unit) {
- // return unit.config.color === scaleId;
- // use all found elements
- return true;
- })
- .forEach(function (unit) {
- unit.fire('highlight', isRowMatch);
- });
- },
-
- _getScrollContainer: function () {
- return this._container.parentNode.parentNode;
- },
-
- _updateResetButtonPosition: function () {
- var reset = this._container.querySelector(RESET_SELECTOR);
- reset.style.top = this._getScrollContainer().scrollTop + 'px';
- },
-
- _generateColorMap: function (domain, defBrewer) {
-
- var limit = defBrewer.length; // 20;
-
- return domain.reduce(function (memo, val, i) {
- memo[val] = defBrewer[i % limit];
- return memo;
- },
- {});
- },
-
- _assignStaticBrewersOrEx: function () {
- var self = this;
- self._color.forEach(function (c) {
- var scaleConfig = self
- ._chart
- .getSpec()
- .scales[c];
+ _highlightToggle(target, doHighlight) {
- var fullLegendDataSource = self
- ._chart
- .getDataSources({excludeFilter: ['legend']});
+ if (target.matches('.disabled')) {
+ return;
+ }
- var fullLegendDomain = self
- ._chart
- .getScaleFactory(fullLegendDataSource)
- .createScaleInfoByName(c)
- .domain();
+ // var scaleId = target.getAttribute('data-scale-id');
+ const dim = target.getAttribute('data-dim');
+ const val = target.getAttribute('data-value');
- if (!scaleConfig.brewer || Array.isArray(scaleConfig.brewer)) {
- var defBrewer = scaleConfig.brewer || utils.range(20).map(function (i) {
- return 'color20-' + (1 + i);
- });
- scaleConfig.brewer = self._generateColorMap(fullLegendDomain, defBrewer);
- }
+ const isRowMatch = doHighlight ?
+ (createIsRowMatchInterceptor(dim, val)) :
+ (row => null);
- self._legendOrderState[c] = fullLegendDomain.reduce(function (memo, x, i) {
- memo[x] = i;
- return memo;
- }, {});
+ this._chart
+ .select(unit => // return unit.config.color === scaleId;
+ // use all found elements
+ true)
+ .forEach(unit => {
+ unit.fire('highlight', isRowMatch);
});
- }
- };
- }
+ },
+
+ _getScrollContainer() {
+ return this._container.parentNode.parentNode;
+ },
+
+ _updateResetButtonPosition() {
+ const reset = this._container.querySelector(RESET_SELECTOR);
+ reset.style.top = `${this._getScrollContainer().scrollTop}px`;
+ },
+
+ _generateColorMap(domain, defBrewer) {
+
+ const limit = defBrewer.length; // 20;
+
+ return domain.reduce((memo, val, i) => {
+ memo[val] = defBrewer[i % limit];
+ return memo;
+ },
+ {});
+ },
+
+ _assignStaticBrewersOrEx() {
+ const self = this;
+ self._color.forEach(c => {
+ const scaleConfig = self
+ ._chart
+ .getSpec()
+ .scales[c];
+
+ const fullLegendDataSource = self
+ ._chart
+ .getDataSources({excludeFilter: ['legend']});
+
+ const fullLegendDomain = self
+ ._chart
+ .getScaleFactory(fullLegendDataSource)
+ .createScaleInfoByName(c)
+ .domain();
+
+ if (!scaleConfig.brewer || Array.isArray(scaleConfig.brewer)) {
+ const defBrewer = scaleConfig.brewer || utils.range(20).map(i => `color20-${1 + i}`);
+ scaleConfig.brewer = self._generateColorMap(fullLegendDomain, defBrewer);
+ }
+
+ self._legendOrderState[c] = fullLegendDomain.reduce((memo, x, i) => {
+ memo[x] = i;
+ return memo;
+ }, {});
+ });
+ }
+ };
+}
- Taucharts.api.plugins.add('legend', ChartLegend);
+Taucharts.api.plugins.add('legend', ChartLegend);
export default ChartLegend;