@trutoo/funnel-graph
Version:
SVG Funnel Graph TypeScript Library.
824 lines (805 loc) • 35.6 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.fg = {}));
}(this, (function (exports) { 'use strict';
var setAttrs = function (element, attributes) {
if (typeof attributes === 'object') {
Object.keys(attributes).forEach(function (key) {
element.setAttribute(key, attributes[key]);
});
}
};
var removeAttrs = function (element) {
var attributes = [];
for (var _i = 1; _i < arguments.length; _i++) {
attributes[_i - 1] = arguments[_i];
}
attributes.forEach(function (attribute) {
element.removeAttribute(attribute);
});
};
var createSVGElement = function (element, container, attributes) {
var el = document.createElementNS('http://www.w3.org/2000/svg', element);
if (typeof attributes === 'object') {
setAttrs(el, attributes);
}
if (container) {
container.appendChild(el);
}
return el;
};
var generateLegendBackground = function (color, direction) {
if (direction === void 0) { direction = 'horizontal'; }
if (typeof color === 'string') {
return "background-color: " + color;
}
if (color.length === 1) {
return "background-color: " + color[0];
}
return "background-image: linear-gradient(" + (direction === 'horizontal' ? 'to right, ' : '') + color.join(', ') + ")";
};
var defaultColors = ['#003f5c', '#2f4b7c', '#665191', '#a05195', '#d45087', '#f95d6a', '#ff7c43', '#ffa600'];
var getDefaultColors = function (sets) {
if (sets == 1)
return [defaultColors[0], defaultColors[3]];
var colors = [];
var len = defaultColors.length;
for (var i = 0; i < sets; i++) {
var colorIndex = Math.round((len / Math.min(sets, len)) * (i % len));
colors.push(defaultColors[colorIndex]);
}
return colors;
};
/*
Used in comparing existing values to value provided on update
It is limited to comparing arrays on purpose
Name is slightly unusual, in order not to be confused with Lodash method
*/
var areEqual = function (value, newValue) {
// If values are not of the same type
var type = Object.prototype.toString.call(value);
if (type !== Object.prototype.toString.call(newValue))
return false;
if (type !== '[object Array]')
return false;
if (value.length !== newValue.length)
return false;
for (var i = 0; i < value.length; i++) {
// if the it's a two dimensional array
var currentType = Object.prototype.toString.call(value[i]);
if (currentType !== Object.prototype.toString.call(newValue[i]))
return false;
if (currentType === '[object Array]') {
// if row lengths are not equal then arrays are not equal
if (value[i].length !== newValue[i].length)
return false;
// compare each element in the row
for (var j = 0; j < value[i].length; j++) {
if (value[i][j] !== newValue[i][j]) {
return false;
}
}
}
else if (value[i] !== newValue[i]) {
// if it's a one dimensional array element
return false;
}
}
return true;
};
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __spreadArray(to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
}
var roundPoint = function (number) { return Math.round(number * 10) / 10; };
var formatNumber = function (number) { return number.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); };
var createCurves = function (x1, y1, x2, y2) {
return " C" + roundPoint((x2 + x1) / 2) + "," + y1 + " " + (roundPoint((x2 + x1) / 2) + "," + y2 + " " + x2 + "," + y2);
};
var createVerticalCurves = function (x1, y1, x2, y2) {
return " C" + x1 + "," + roundPoint((y2 + y1) / 2) + " " + (x2 + "," + roundPoint((y2 + y1) / 2) + " " + x2 + "," + y2);
};
/*
A funnel segment is draw in a clockwise direction.
Path 1-2 is drawn,
then connected with a straight vertical line 2-3,
then a line 3-4 is draw (using YNext points going in backwards direction)
then path is closed (connected with the starting point 1).
1---------->2
^ |
| v
4<----------3
On the graph on line 20 it works like this:
A#0, A#1, A#2, A#3, B#3, B#2, B#1, B#0, close the path.
Points for path "B" are passed as the YNext param.
*/
var createPath = function (X, Y, YNext) {
var str = "M" + X[0] + "," + Y[0];
for (var i = 0; i < X.length - 1; i++) {
str += createCurves(X[i], Y[i], X[i + 1], Y[i + 1]);
}
str += " L" + __spreadArray([], X).pop() + "," + __spreadArray([], YNext).pop();
for (var i = X.length - 1; i > 0; i--) {
str += createCurves(X[i], YNext[i], X[i - 1], YNext[i - 1]);
}
str += ' Z';
return str;
};
/*
In a vertical path we go counter-clockwise
1<----------4
| ^
v |
2---------->3
*/
var createVerticalPath = function (X, XNext, Y) {
var str = "M" + X[0] + "," + Y[0];
for (var i = 0; i < X.length - 1; i++) {
str += createVerticalCurves(X[i], Y[i], X[i + 1], Y[i + 1]);
}
str += " L" + __spreadArray([], XNext).pop() + "," + __spreadArray([], Y).pop();
for (var i = X.length - 1; i > 0; i--) {
str += createVerticalCurves(XNext[i], Y[i], XNext[i - 1], Y[i - 1]);
}
str += ' Z';
return str;
};
var isLayered = function (data) {
return !!data.values && Array.isArray(data.values[0]);
};
var layerMaxLength = function (data) {
return data.values.reduce(function (max, valueSet) {
return Math.max(max, valueSet.length);
}, 0);
};
var layerSums = function (data) {
return data.values.map(function (valueSet) {
return valueSet.reduce(function (sum, value) { return sum + (value || 0); }, 0);
});
};
var layerPercentages = function (data) {
return data.values.map(function (valueSet) {
var total = valueSet.reduce(function (sum, value) { return sum + (value || 0); }, 0);
return valueSet.map(function (value) { return (total === 0 ? 0 : roundPoint(((value || 0) * 100) / total)); });
});
};
/**
* An example of a two-dimensional funnel graph
* #0..................
* ...#1................
* ......
* #0********************#1** #2.........................#3 (A)
* *******************
* #2*************************#3 (B)
* #2+++++++++++++++++++++++++#3 (C)
* +++++++++++++++++++
* #0++++++++++++++++++++#1++ #2-------------------------#3 (D)
* ------
* ---#1----------------
* #0-----------------
* Main axis is the primary axis of the graph.
* In a horizontal graph it's the X axis, and Y is the cross axis.
* However we use the names "main" and "cross" axis,
* because in a vertical graph the primary axis is the Y axis
* and the cross axis is the X axis.
* First step of drawing the funnel graph is getting the coordinates of points,
* that are used when drawing the paths.
* There are 4 paths in the example above: A, B, C and D.
* Such funnel has 3 labels and 3 subLabels.
* This means that the main axis has 4 points (number of labels + 1)
* One the ASCII illustrated graph above, those points are illustrated with a # symbol.
*/
var generateMainAxisPoints = function (data, size) {
var points = [];
for (var i = 0; i <= data.values.length; i++) {
points.push(roundPoint((size * i) / data.values.length));
}
return points;
};
var generateCrossAxisPoints = function (data, size) {
var points = [];
// get half of the graph container height or width, since funnel shape is symmetric
// we use this when calculating the "A" shape
var dimension = size / 2;
if (isLayered(data)) {
var totalValues = layerSums(data);
var max_1 = Math.max.apply(Math, totalValues);
// duplicate last value
totalValues.push(__spreadArray([], totalValues).pop());
// get points for path "A"
points.push(totalValues.map(function (value) { return roundPoint(((max_1 - value) / max_1) * dimension); }));
// percentages with duplicated last value
var percentagesFull = layerPercentages(data);
var pointsOfFirstPath = points[0];
var length_1 = layerMaxLength(data);
for (var i = 1; i < length_1; i++) {
var p = points[i - 1];
var newPoints = [];
for (var j = 0; j < data.values.length; j++) {
var percentage = percentagesFull[j][i - 1] || 0;
newPoints.push(roundPoint(
// eslint-disable-next-line comma-dangle
p[j] + (size - pointsOfFirstPath[j] * 2) * (percentage / 100)));
}
// duplicate the last value as points #2 and #3 have the same value on the cross axis
newPoints.push(__spreadArray([], newPoints).pop());
points.push(newPoints);
}
// add points for path "D", that is simply the "inverted" path "A"
points.push(pointsOfFirstPath.map(function (point) { return size - point; }));
}
else {
// As you can see on the visualization above points #2 and #3 have the same cross axis coordinate
// so we duplicate the last value
var max_2 = Math.max.apply(Math, data.values);
var values = __spreadArray([], data.values).concat(__spreadArray([], data.values).pop());
// if the graph is simple (not two-dimensional) then we have only paths "A" and "D"
// which are symmetric. So we get the points for "A" and then get points for "D" by subtracting "A"
// points from graph cross dimension length
points.push(values.map(function (value) { return roundPoint(((max_2 - value) / max_2) * dimension); }));
points.push(points[0].map(function (point) { return size - point; }));
}
return points;
};
var FunnelGraph = /** @class */ (function () {
function FunnelGraph(options) {
this.container = null;
this.graphContainer = null;
this.containerSelector = '';
if (options.container instanceof Element)
this.container = options.container;
else
this.containerSelector = options.container;
var colors = getDefaultColors(isLayered(options.data) ? layerMaxLength(options.data) : 1);
this.data = __assign({ labels: [], colors: colors, subLabels: [] }, options.data);
this.gradientDirection =
options.gradientDirection && options.gradientDirection === 'vertical' ? 'vertical' : 'horizontal';
this.direction = options.direction && options.direction === 'vertical' ? 'vertical' : 'horizontal';
this.displayPercent = options.displayPercent || false;
this.width = options.width || 0;
this.height = options.height || 0;
this.subLabelValue = options.subLabelValue || 'percent';
}
//------------------------------------------------------------------------------------
// RENDER
//------------------------------------------------------------------------------------
FunnelGraph.prototype.createContainer = function () {
if (!this.container) {
if (!this.containerSelector) {
throw new Error('Container must either be a selector string or an Element.');
}
this.container = document.querySelector(this.containerSelector);
if (!this.container) {
throw new Error("Container cannot be found (selector: " + this.containerSelector + ").");
}
}
this.container.classList.add('fg');
this.graphContainer = document.createElement('div');
this.graphContainer.classList.add('fg-container');
this.container.appendChild(this.graphContainer);
if (this.direction === 'vertical') {
this.container.classList.add('fg--vertical');
}
};
FunnelGraph.prototype.makeSVG = function () {
if (!this.graphContainer)
return;
var svg = this.graphContainer.querySelector('svg');
if (!svg) {
svg = createSVGElement('svg', this.graphContainer, {
width: this.getWidth().toString(),
height: this.getHeight().toString(),
});
this.graphContainer.appendChild(svg);
}
var paths = svg.querySelectorAll('path');
var valuesNum = this.getCrossAxisPoints().length - 1;
for (var i = 0; i < valuesNum; i++) {
var path = paths[i];
if (!path) {
path = createSVGElement('path', svg);
svg.appendChild(path);
}
var color = isLayered(this.data) ? this.data.colors[i] : this.data.colors;
var fillMode = typeof color === 'string' || color.length === 1 ? 'solid' : 'gradient';
if (fillMode === 'solid') {
setAttrs(path, {
fill: Array.isArray(color) ? color[0] : color,
stroke: Array.isArray(color) ? color[0] : color,
});
}
else if (fillMode === 'gradient') {
this.applyGradient(svg, path, color, i + 1);
}
}
for (var i = valuesNum; i < paths.length; i++) {
paths[i].remove();
}
};
FunnelGraph.prototype.drawPaths = function () {
var svg = this.getSVG();
if (!svg)
return;
var paths = svg.querySelectorAll('path');
var definitions = this.getPathDefinitions();
definitions.forEach(function (definition, index) {
paths[index].setAttribute('d', definition);
});
};
FunnelGraph.prototype.addLabels = function () {
var _this = this;
if (!this.container)
return;
var holder = document.createElement('div');
holder.setAttribute('class', 'fg-labels');
var percentages = this.getPercentages();
percentages.forEach(function (percentage, index) {
var _a;
var labelElement = document.createElement('div');
labelElement.setAttribute('class', "fg-label");
var title = document.createElement('div');
title.setAttribute('class', 'fg-label__title');
title.textContent = _this.data.labels[index] || '';
var value = document.createElement('div');
value.setAttribute('class', 'fg-label__value');
var valueNumber = isLayered(_this.data) ? _this.getLayerSums()[index] : _this.data.values[index];
value.textContent = formatNumber(valueNumber || 0);
var percentageValue = document.createElement('div');
percentageValue.setAttribute('class', 'fg-label__percentage');
percentageValue.textContent = percentage.toString() + "%";
labelElement.appendChild(value);
labelElement.appendChild(title);
if (_this.displayPercent) {
labelElement.appendChild(percentageValue);
}
if (isLayered(_this.data) && ((_a = _this.data.subLabels) === null || _a === void 0 ? void 0 : _a.length)) {
var segmentPercentages = document.createElement('div');
segmentPercentages.setAttribute('class', 'fg-label__segments');
var percentageList_1 = '<ul class="fg-label__segment-list">';
var twoDimPercentages_1 = _this.getLayerPercentages();
_this.data.subLabels.forEach(function (subLabel, j) {
var data = _this.data;
var subLabelDisplayValue = _this.subLabelValue === 'percent'
? (twoDimPercentages_1[index][j] || 0) + "%"
: formatNumber(data.values[index][j] || 0);
percentageList_1 += "\n <li class=\"fg-label__segment-item\">" + subLabel + ":\n <span class=\"fg-label__segment-label\">" + subLabelDisplayValue + "</span>\n </li>";
});
percentageList_1 += '</ul>';
segmentPercentages.innerHTML = percentageList_1;
labelElement.appendChild(segmentPercentages);
}
holder.appendChild(labelElement);
});
this.container.appendChild(holder);
};
FunnelGraph.prototype.addSubLabels = function () {
var _this = this;
var _a;
if (!this.container || !isLayered(this.data) || !((_a = this.data.subLabels) === null || _a === void 0 ? void 0 : _a.length))
return;
var subLabelsHolder = document.createElement('div');
subLabelsHolder.setAttribute('class', 'fg-sub-labels');
var subLabelsHTML = '';
this.data.subLabels.forEach(function (subLabel, index) {
if (!_this.data.colors)
return;
subLabelsHTML += "\n <div class=\"fg-sub-label\">\n <div class=\"fg-sub-label__color\"\n style=\"" + generateLegendBackground(_this.data.colors[index], _this.gradientDirection) + "\"></div>\n <div class=\"fg-sub-label__title\">" + subLabel + "</div>\n </div>";
});
subLabelsHolder.innerHTML = subLabelsHTML;
this.container.appendChild(subLabelsHolder);
};
FunnelGraph.prototype.applyGradient = function (svg, path, colors, index) {
if (index === void 0) { index = 0; }
var defs = svg.querySelector('defs');
if (!defs)
defs = createSVGElement('defs', svg);
var gradientName = "funnelGradient-" + index;
var gradient = defs.querySelector("#" + gradientName);
if (!gradient) {
gradient = createSVGElement('linearGradient', defs, {
id: gradientName,
});
}
if (this.gradientDirection === 'vertical') {
setAttrs(gradient, {
x1: '0',
x2: '0',
y1: '0',
y2: '1',
});
}
var stops = gradient.querySelectorAll("stop");
var numberOfColors = colors.length;
for (var i = 0; i < numberOfColors; i++) {
var stop_1 = stops[i];
var attributes = {
'stop-color': colors[i],
offset: Math.round((100 * i) / (numberOfColors - 1)) + "%",
};
if (stop_1) {
setAttrs(stop_1, attributes);
}
else {
createSVGElement('stop', gradient, attributes);
}
}
for (var i = numberOfColors; i < stops.length; i++) {
stops[i].remove();
}
setAttrs(path, {
fill: "url(\"#" + gradientName + "\")",
stroke: "url(\"#" + gradientName + "\")",
});
};
//------------------------------------------------------------------------------------
// GETTERS
//------------------------------------------------------------------------------------
FunnelGraph.prototype.getMainAxisPoints = function () {
var fullDimension = this.isVertical() ? this.getHeight() : this.getWidth();
return generateMainAxisPoints(this.data, fullDimension);
};
FunnelGraph.prototype.getCrossAxisPoints = function () {
var fullDimension = this.isVertical() ? this.getWidth() : this.getHeight();
return generateCrossAxisPoints(this.data, fullDimension);
};
FunnelGraph.prototype.getGraphType = function () {
return isLayered(this.data) ? 'layered' : 'normal';
};
FunnelGraph.prototype.isVertical = function () {
return this.direction === 'vertical';
};
FunnelGraph.prototype.getDataSize = function () {
return this.data.values.length;
};
FunnelGraph.prototype.getSubDataSize = function () {
if (Array.isArray(this.data.values[0]))
return this.data.values[0].length;
return 0;
};
FunnelGraph.prototype.getFullDimension = function () {
return this.isVertical() ? this.getHeight() : this.getWidth();
};
FunnelGraph.prototype.setValues = function (values) {
this.data.values = values;
return this;
};
FunnelGraph.prototype.setDirection = function (direction) {
this.direction = direction;
return this;
};
FunnelGraph.prototype.setHeight = function (height) {
this.height = height;
return this;
};
FunnelGraph.prototype.setWidth = function (width) {
this.width = width;
return this;
};
FunnelGraph.prototype.getLayerSums = function () {
if (!isLayered(this.data))
return [];
return layerSums(this.data);
};
FunnelGraph.prototype.getLayerPercentages = function () {
if (!isLayered(this.data))
return [];
return layerPercentages(this.data);
};
FunnelGraph.prototype.getPercentages = function () {
var values = [];
if (isLayered(this.data)) {
values = this.getLayerSums();
}
else {
values = __spreadArray([], this.data.values);
}
var max = Math.max.apply(Math, values);
return values.map(function (value) { return (value ? roundPoint((value * 100) / max) : 0); });
};
FunnelGraph.prototype.getSVG = function () {
if (!this.container)
return;
var svg = this.container.querySelector('svg');
if (!svg) {
throw new Error('No SVG found inside of the container');
}
return svg;
};
FunnelGraph.prototype.getWidth = function () {
var _a;
return this.width || ((_a = this.graphContainer) === null || _a === void 0 ? void 0 : _a.clientWidth) || 0;
};
FunnelGraph.prototype.getHeight = function () {
var _a;
return this.height || ((_a = this.graphContainer) === null || _a === void 0 ? void 0 : _a.clientHeight) || 0;
};
FunnelGraph.prototype.getPathDefinitions = function () {
var crossAxisPoints = this.getCrossAxisPoints();
var valuesNum = crossAxisPoints.length - 1;
var paths = [];
for (var i = 0; i < valuesNum; i++) {
if (this.isVertical()) {
var x = crossAxisPoints[i];
var xNext = crossAxisPoints[i + 1];
var y = this.getMainAxisPoints();
var d = createVerticalPath(x, xNext, y);
paths.push(d);
}
else {
var x = this.getMainAxisPoints();
var y = crossAxisPoints[i];
var yNext = crossAxisPoints[i + 1];
var d = createPath(x, y, yNext);
paths.push(d);
}
}
return paths;
};
FunnelGraph.prototype.getPathMedian = function (i) {
var crossAxisPoints = this.getCrossAxisPoints();
if (this.isVertical()) {
var cross_1 = crossAxisPoints[i];
var next_1 = crossAxisPoints[i + 1];
var y_1 = this.getMainAxisPoints();
var x_1 = [];
var xNext_1 = [];
cross_1.forEach(function (point, index) {
var m = (point + next_1[index]) / 2;
x_1.push(m - 1);
xNext_1.push(m + 1);
});
return createVerticalPath(x_1, xNext_1, y_1);
}
var x = this.getMainAxisPoints();
var cross = crossAxisPoints[i];
var next = crossAxisPoints[i + 1];
var y = [];
var yNext = [];
cross.forEach(function (point, index) {
var m = (point + next[index]) / 2;
y.push(m - 1);
yNext.push(m + 1);
});
return createPath(x, y, yNext);
};
//------------------------------------------------------------------------------------
// PUBLIC API
//------------------------------------------------------------------------------------
FunnelGraph.prototype.makeVertical = function () {
var svg = this.getSVG();
if (!this.container || !svg)
return;
if (this.direction === 'vertical')
return true;
this.direction = 'vertical';
this.container.classList.add('fg--vertical');
var height = this.getHeight().toString();
var width = this.getWidth().toString();
setAttrs(svg, { height: height, width: width });
this.drawPaths();
return true;
};
FunnelGraph.prototype.makeHorizontal = function () {
var svg = this.getSVG();
if (!this.container || !svg)
return;
if (this.direction === 'horizontal')
return true;
this.direction = 'horizontal';
this.container.classList.remove('fg--vertical');
var height = this.getHeight().toString();
var width = this.getWidth().toString();
setAttrs(svg, { height: height, width: width });
this.drawPaths();
return true;
};
FunnelGraph.prototype.toggleDirection = function () {
if (this.direction === 'horizontal') {
this.makeVertical();
}
else {
this.makeHorizontal();
}
};
FunnelGraph.prototype.gradientMakeVertical = function () {
if (!this.graphContainer)
return false;
if (this.gradientDirection === 'vertical')
return true;
this.gradientDirection = 'vertical';
var gradients = this.graphContainer.querySelectorAll('linearGradient');
for (var i = 0; i < gradients.length; i++) {
setAttrs(gradients[i], {
x1: '0',
x2: '0',
y1: '0',
y2: '1',
});
}
return true;
};
FunnelGraph.prototype.gradientMakeHorizontal = function () {
if (!this.graphContainer)
return false;
if (this.gradientDirection === 'horizontal')
return true;
this.gradientDirection = 'horizontal';
var gradients = this.graphContainer.querySelectorAll('linearGradient');
for (var i = 0; i < gradients.length; i++) {
removeAttrs(gradients[i], 'x1', 'x2', 'y1', 'y2');
}
return true;
};
FunnelGraph.prototype.gradientToggleDirection = function () {
if (this.gradientDirection === 'horizontal') {
this.gradientMakeVertical();
}
else {
this.gradientMakeHorizontal();
}
};
FunnelGraph.prototype.updateWidth = function (width) {
var svg = this.getSVG();
if (!svg)
return;
this.width = width;
setAttrs(svg, { width: width.toString() });
this.drawPaths();
return true;
};
FunnelGraph.prototype.updateHeight = function (height) {
var svg = this.getSVG();
if (!svg)
return;
this.height = height;
setAttrs(svg, { height: height.toString() });
this.drawPaths();
return true;
};
FunnelGraph.prototype.updateData = function (data, reset) {
if (reset === void 0) { reset = false; }
if (!this.container)
return;
var redraw = false;
if (reset) {
this.data = {
values: [],
labels: [],
subLabels: [],
colors: [],
};
redraw = true;
}
if (data.colors) {
this.data.colors = data.colors;
redraw = true;
}
else if (data.values && data.values.length != this.data.values.length) {
this.data.colors = getDefaultColors(isLayered(data) ? layerMaxLength(data) : 1);
redraw = true;
}
if (data.values) {
this.data.values = data.values;
redraw = true;
}
if (isLayered(data) && data.subLabels) {
var subLabels = this.container.querySelector('.fg-sub-labels');
if (subLabels)
subLabels.remove();
this.data.subLabels = data.subLabels;
this.addSubLabels();
}
if (data.labels) {
var labels = this.container.querySelector('.fg-labels');
if (labels)
labels.remove();
this.data.labels = data.labels;
this.addLabels();
}
if (redraw) {
this.makeSVG();
this.drawPaths();
}
};
FunnelGraph.prototype.update = function (options) {
if (!this.container)
return;
if (typeof options.displayPercent !== 'undefined') {
if (this.displayPercent !== options.displayPercent) {
if (this.displayPercent === true) {
this.container.querySelectorAll('.fg-label__percentage').forEach(function (label) {
label.remove();
});
}
else {
var percentages_1 = this.getPercentages();
this.container.querySelectorAll('.fg-label').forEach(function (label, index) {
var percentage = percentages_1[index];
var percentageValue = document.createElement('div');
percentageValue.setAttribute('class', 'fg-label__percentage');
if (percentage !== 100) {
percentageValue.textContent = percentage.toString() + "%";
label.appendChild(percentageValue);
}
});
}
}
}
if (typeof options.height !== 'undefined') {
this.updateHeight(options.height);
}
if (typeof options.width !== 'undefined') {
this.updateWidth(options.width);
}
if (typeof options.gradientDirection !== 'undefined') {
if (options.gradientDirection === 'vertical') {
this.gradientMakeVertical();
}
else if (options.gradientDirection === 'horizontal') {
this.gradientMakeHorizontal();
}
}
if (typeof options.direction !== 'undefined') {
if (options.direction === 'vertical') {
this.makeVertical();
}
else if (options.direction === 'horizontal') {
this.makeHorizontal();
}
}
if (typeof options.data !== 'undefined') {
this.updateData(options.data);
}
};
FunnelGraph.prototype.draw = function () {
this.createContainer();
this.makeSVG();
this.addLabels();
if (isLayered(this.data)) {
this.addSubLabels();
}
this.drawPaths();
};
return FunnelGraph;
}());
exports.FunnelGraph = FunnelGraph;
exports.areEqual = areEqual;
exports.createCurves = createCurves;
exports.createPath = createPath;
exports.createSVGElement = createSVGElement;
exports.createVerticalCurves = createVerticalCurves;
exports.createVerticalPath = createVerticalPath;
exports.defaultColors = defaultColors;
exports.formatNumber = formatNumber;
exports.generateLegendBackground = generateLegendBackground;
exports.getDefaultColors = getDefaultColors;
exports.isLayered = isLayered;
exports.removeAttrs = removeAttrs;
exports.roundPoint = roundPoint;
exports.setAttrs = setAttrs;
Object.defineProperty(exports, '__esModule', { value: true });
})));