UNPKG

@trutoo/funnel-graph

Version:

SVG Funnel Graph TypeScript Library.

824 lines (805 loc) 35.6 kB
(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 }); })));