UNPKG

svg-text

Version:

Utilities for working with SVG, including SvgText for multiline text.

1,673 lines (1,453 loc) 116 kB
/*! svg-text v0.5.1 */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["SvgText"] = factory(); else root["SvgText"] = factory(); })(this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.SvgUtil = undefined; var _SvgText = __webpack_require__(1); var _SvgText2 = _interopRequireDefault(_SvgText); var _svg = __webpack_require__(2); var _math = __webpack_require__(5); var math = _interopRequireWildcard(_math); var _keys = __webpack_require__(3); var keys = _interopRequireWildcard(_keys); var _text = __webpack_require__(11); var text = _interopRequireWildcard(_text); var _style = __webpack_require__(8); var style = _interopRequireWildcard(_style); var _lodash = __webpack_require__(12); var _lodash2 = _interopRequireDefault(_lodash); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var SvgUtil = exports.SvgUtil = (0, _lodash2.default)({ createElement: _svg.createElement }, math, keys, text, style); exports.default = _SvgText2.default; /***/ }, /* 1 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _svg = __webpack_require__(2); var _math = __webpack_require__(5); var _keys = __webpack_require__(3); var _style = __webpack_require__(8); var _render = __webpack_require__(9); var _render2 = _interopRequireDefault(_render); var _lodash = __webpack_require__(4); var _lodash2 = _interopRequireDefault(_lodash); var _lodash3 = __webpack_require__(6); var _lodash4 = _interopRequireDefault(_lodash3); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var _svgEl = null; var _styleEl = null; var SvgText = function () { /** * @construtor * @param {object} options * @param {SVGElement} options.element to append the text into * @param {string} options.text * @param {number=} options.x * @param {number=} options.y * @param {number=} options.width * @param {number=} options.height * @param {number=} options.maxWidth * @param {number=} options.maxHeight * @param {number=} options.maxLines * @param {string=} options.align [left|center|right] Default is left * @param {string=} options.verticalAlign [top|middle|bottom] Default is top * @param {string=} options.textOverflow [clip|ellipsis|custom] Default is clip * @param {string=} options.selectorNamespace * @param {string=} options.className * @param {object=} options.style Styles to be written as CSS to a `style` element. * @param {object=} options.styleElement The `style` element to write styles to. * @param {object=} options.attrs Attributes applied to the `text` element * @param {object=} options.rect Attributes applied to an underlying `rect` * @param {array=} options.padding [top, right, bottom, left] * @param {array=} options.margin [top, right, bottom, left] */ function SvgText(options) { _classCallCheck(this, SvgText); this.options = updateOptions(options); this.uid = this.options.uid; this.rect = this.options.rect ? (0, _svg.createRect)(this.options) : null; this.text = createText(this.options); writeStyleAsCss(this.options); var compStyle = window.getComputedStyle(this.text, null); this.fontSize = parseFloat(compStyle.getPropertyValue('font-size')); this.lineHeight = parseFloat(compStyle.getPropertyValue('line-height')) || this.fontSize * 1.2; this.lines = (0, _render2.default)(this.text, this.options, this.lineHeight); this.bounds = sizeBounds(this.text, this.options); sizeRect(this.rect, this.bounds, this.options.rect); offsetByMargin(this.bounds, this.options.margin); moveText(this.text, this.options, { fontSize: this.fontSize, lineHeight: this.lineHeight, lines: this.lines }); } /** * Transforms `text` into a form ready to be opened in Adobe Illustrator. * @param {SVG text element} textWeb SVG element prepared for the web. * @param {SVG text element} textAi Duplicate SVG element to be prepared for Illustrator. * @param {string} font The font as a name that Illustrator will recognize. */ _createClass(SvgText, null, [{ key: 'forIllustrator', value: function forIllustrator(textWeb, textAi, font) { var compStyle = window.getComputedStyle(textWeb, null); if (font) { textAi.setAttribute('font-family', font); } textAi.setAttribute('font-size', compStyle.getPropertyValue('font-size')); textAi.setAttribute('line-height', compStyle.getPropertyValue('line-height')); textAi.setAttribute('fill', compStyle.getPropertyValue('fill')); textAi.setAttribute('fill-opacity', compStyle.getPropertyValue('fill-opacity')); textAi.removeAttribute('class'); return textAi; } }, { key: 'writeStyle', value: function writeStyle(selector, css, style) { var styleEl = style || SvgText.style || null; if (styleEl && SvgText.svg) { selector = getSelectorNamespace(SvgText.svg) + ' ' + selector; (0, _style.writeStyle)(selector, css, styleEl); } } }, { key: 'svg', set: function set(value) { _svgEl = value; }, get: function get() { return _svgEl; } }, { key: 'style', set: function set(value) { _styleEl = value; }, get: function get() { return _styleEl; } }]); return SvgText; }(); exports.default = SvgText; function updateOptions(options) { options.uid = uid(); options = updateEnvironment(options); options = updateClassname(options); options = (0, _math.updateSizeOptions)(options); options.attrs = options.attrs && _typeof(options.attrs) === 'object' ? (0, _keys.normalizeKeys)(options.attrs, 'css') : {}; return options; } // Ensure svg, selectorNamespace, and style properties are set. function updateEnvironment(options) { options.svg = options.svg || _svgEl || null; options.styleElement = options.styleElement || _styleEl || null; var svgEl = options.element || document.body; while (svgEl && svgEl.nodeName.toUpperCase() !== 'SVG') { svgEl = svgEl.parentElement; } svgEl = svgEl || document.body; if (svgEl.nodeName.toUpperCase() !== 'SVG') { svgEl = (0, _svg.createElement)('svg', { width: 640, height: 480, 'data-svgtext': getSvgUid() }); (options.element || document.body).appendChild(svgEl); } options.svg = svgEl; if (!options.svg.hasAttribute('data-svgtext')) { options.svg.setAttribute('data-svgtext', getSvgUid()); } if (!options.selectorNamespace || typeof options.selectorNamespace !== 'string') { options.selectorNamespace = getSelectorNamespace(options.svg); } options.styleElement = options.styleElement || options.svg.querySelector('style'); if (!options.styleElement) { options.styleElement = document.createElement('style'); var firstChild = options.svg.childNodes[0]; if (firstChild) { options.svg.insertBefore(options.styleElement, firstChild); } else { options.svg.appendChild(options.styleElement); } } options.element = options.element || options.svg; _svgEl = options.svg; _styleEl = options.styleElement; return options; } // Set default className to 'svg-text svg-text-[uid]'. function updateClassname(options) { if (!options.className || typeof options.className !== 'string') { options.className = 'svg-text'; } options.className += '.' + options.className.split(' ')[0] + '-' + options.uid; return options; } function offsetByMargin(bounds, margin) { bounds.x -= margin[3]; bounds.y -= margin[0]; bounds.width += margin[3] + margin[1]; bounds.height += margin[0] + margin[2]; } // Create the text element. function createText(options) { var textOptions = (0, _keys.normalizeKeys)((0, _lodash4.default)({}, options.attrs, { 'ai-id': options.uid })); var text = (0, _svg.createElement)('text', textOptions); if (options.className) { text.setAttribute('class', options.className.replace(/\./, ' ')); } options.element.appendChild(text); return text; } function writeStyleAsCss(options) { if (options.style && options.styleElement) { var selectorNamespace = options.selectorNamespace || null; var className = options.className ? ('.' + options.className).replace(' ', '.') : null; var textClassName = className ? 'text' + className : null; var selector = [selectorNamespace ? selectorNamespace + ' ' : '', textClassName || ''].join(''); if (selector) { (0, _style.writeStyle)(selector, options.style, options.styleElement); } } } function sizeBounds(text, options) { var p = options.padding; var textRect = text.getBoundingClientRect(); var bounds = { x: options.x, y: options.y, width: textRect.width, height: textRect.height }; bounds.width = (0, _math.isPosNum)(options.width) ? options.width : textRect.width + p[3] + p[1]; if (options.align === 'right') { bounds.x -= bounds.width; } else if (options.align === 'center') { bounds.x -= bounds.width / 2; } bounds.height = (0, _math.isPosNum)(options.height) ? options.height : textRect.height + p[0] + p[2]; if (options.verticalAlign === 'bottom') { bounds.y -= bounds.height; } else if (options.verticalAlign === 'middle') { bounds.y -= bounds.height / 2; } return bounds; } function sizeRect(rect, bounds, rectSize) { if (rect) { rect.setAttribute('width', (0, _lodash2.default)(rectSize.width) ? rectSize.width : bounds.width); rect.setAttribute('height', (0, _lodash2.default)(rectSize.height) ? rectSize.height : bounds.height); rect.setAttribute('x', bounds.x + ((0, _lodash2.default)(rectSize.x) ? rectSize.x : 0)); rect.setAttribute('y', bounds.y + ((0, _lodash2.default)(rectSize.y) ? rectSize.y : 0)); } } function moveText(text, options, attrs) { alignText(text, options.align); options = verticalAlignText(text, options, attrs); text.setAttribute('transform', 'translate(' + options.textPos.x + ',' + options.textPos.y + ')'); } function alignText(text, align) { if (align === 'center') { text.setAttribute('text-anchor', 'middle'); } else if (align === 'right') { text.setAttribute('text-anchor', 'end'); } else if (text.hasAttribute('text-anchor')) { text.removeAttribute('text-anchor'); } } function verticalAlignText(text, options, attrs) { options.textPos.y += attrs.fontSize; if (options.verticalAlign === 'middle') { options.textPos.y -= Math.max(attrs.lineHeight, textHeight(text, options, attrs)) / 2; } else if (options.verticalAlign === 'bottom') { options.textPos.y -= textHeight(text, options, attrs); } return options; } function textHeight(text, options, attrs) { return Math.max(attrs.fontSize, (0, _math.isPosNum)(options.textPos.height) ? options.textPos.height : text.getBoundingClientRect().height); } function getSelectorNamespace(svg) { var svgId = svg.getAttribute('id'); if (svgId) { return 'svg#' + svgId; } else { var svgAttr = svg.getAttribute('data-svgtext'); return 'svg[data-svgtext="' + svgAttr + '"]'; } } // Each text field gets its own unique id so it styles can be namespaced to it // and also so original SVG text elements can be synced with Illustrator SVG. var __uid = 0; function uid() { return __uid++; } function getSvgUid() { var maxId = 0; var svgEls = document.querySelectorAll('svg[data-svgtext]'); for (var i = 0; i < svgEls.length; i++) { var id = +svgEls[i].getAttribute('data-svgtext'); maxId = isNaN(id) ? maxId : Math.max(id, maxId); } return maxId + 1; } /***/ }, /* 2 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; exports.createElement = createElement; exports.createRect = createRect; exports.appendTspan = appendTspan; exports.createTspan = createTspan; exports.writeInnerHTML = writeInnerHTML; var _keys = __webpack_require__(3); /** * Convenience/util function to create SVG elements. */ function createElement(name, attrs) { var node = document.createElementNS('http://www.w3.org/2000/svg', name); if (attrs && (typeof attrs === 'undefined' ? 'undefined' : _typeof(attrs)) === 'object') { attrs = (0, _keys.normalizeKeys)(attrs, 'css'); var keys = Object.keys(attrs); for (var i = 0; i < keys.length; i++) { node.setAttribute(keys[i], attrs[keys[i]]); } } return node; } /** * Create a rect for background color and borders. Width and height will be * added later once text width and height are known. */ function createRect(options) { var rectOptions = (0, _keys.normalizeKeys)(options.rect, 'css'); if (!rectOptions.hasOwnProperty('fill')) { // If `fill` is not specified, make invisible not black. rectOptions['fill-opacity'] = 0; } var rect = createElement('rect', rectOptions); if (options.element) { options.element.appendChild(rect); } return rect; } /** * Create and append a `tspan`. */ function appendTspan(text, str, x, y) { var tspan = createTspan(str, x, y); text.appendChild(tspan); return tspan; } /** * Create a new `tspan`. */ function createTspan(str) { var x = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; var y = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; var tspan = createElement('tspan', { x: x, y: y }); writeInnerHTML(tspan, str); return tspan; } /** * Because `innerHTML` does not work with SVG in older browsers. */ function writeInnerHTML(svgEl, content) { svgEl.innerHTML = content; var tempEl = document.createElement('div'); tempEl.innerHTML = '<svg>' + content + '</svg>'; Array.prototype.slice.call(svgEl.childNodes).forEach(function (el) { svgEl.removeChild(el); }); Array.prototype.slice.call(tempEl.childNodes[0].childNodes).forEach(function (el) { svgEl.appendChild(el); }); return svgEl; } /***/ }, /* 3 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; exports.toJs = toJs; exports.toCss = toCss; exports.normalizeKeys = normalizeKeys; var _lodash = __webpack_require__(4); var _lodash2 = _interopRequireDefault(_lodash); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * @param {string} prop - String in JavaScript-ready camel case. * @returns {string} String hyphenated in CSS style. */ function toJs(prop) { return prop.replace(/-([a-z])/g, function (match, p1) { return p1.toUpperCase(); }); } /** * @param {string} prop - String in JavaScript-ready camel case. * @returns {string} String hyphenated in CSS style. */ function toCss(prop) { return prop.replace(/([A-Z])/g, function (match, p1) { return '-' + p1.toLowerCase(); }); } /** * Returns a copy of @param object with keys transformed to the desired style, * either 'js' or 'css'. */ function normalizeKeys(object, style) { var normalizedObj = {}; if (object && (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object') { var keys = Object.keys(object); keys.forEach(function (key) { var normalizedKey = style === 'js' ? toJs(key) : toCss(key); var value = addUnits(key, object[key]); normalizedObj[normalizedKey] = value; }); } return normalizedObj; } // Default units are pixels (px) so add 'px' to raw numbers. function addUnits(key, value) { switch (key) { case 'font-size': case 'fontSize': case 'line-height': case 'lineHeight': if ((0, _lodash2.default)(value)) { value += 'px'; } break; } return value; } /***/ }, /* 4 */ /***/ function(module, exports) { /* WEBPACK VAR INJECTION */(function(global) {/** * lodash (Custom Build) <https://lodash.com/> * Build: `lodash modularize exports="npm" -o ./` * Copyright jQuery Foundation and other contributors <https://jquery.org/> * Released under MIT license <https://lodash.com/license> * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ /** Detect free variable `global` from Node.js. */ var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; /** Detect free variable `self`. */ var freeSelf = typeof self == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = freeGlobal || freeSelf || Function('return this')(); /* Built-in method references for those with the same name as other `lodash` methods. */ var nativeIsFinite = root.isFinite; /** * Checks if `value` is a finite primitive number. * * **Note:** This method is based on * [`Number.isFinite`](https://mdn.io/Number/isFinite). * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a finite number, * else `false`. * @example * * _.isFinite(3); * // => true * * _.isFinite(Number.MIN_VALUE); * // => true * * _.isFinite(Infinity); * // => false * * _.isFinite('3'); * // => false */ function isFinite(value) { return typeof value == 'number' && nativeIsFinite(value); } module.exports = isFinite; /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }, /* 5 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.isPosNum = isPosNum; exports.minNum = minNum; exports.maxNum = maxNum; exports.autoNum = autoNum; exports.toArrayLen4 = toArrayLen4; exports.bestSize = bestSize; exports.updateSizeOptions = updateSizeOptions; var _keys = __webpack_require__(3); var _lodash = __webpack_require__(4); var _lodash2 = _interopRequireDefault(_lodash); var _lodash3 = __webpack_require__(6); var _lodash4 = _interopRequireDefault(_lodash3); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Tests if a value is a valid number and also >= 0. * @returns {boolean} */ function isPosNum(n) { return (0, _lodash2.default)(n) && n >= 0; } /** * Returns the minimum numeric value amongst the arguments, or else "auto". */ function minNum() { return minMax('min', arguments); } /** * Returns the maximum numeric value amongst the arguments, or else "auto". */ function maxNum() { return minMax('max', arguments); } /** * If @param value is "auto", return @param altNum instead. */ function autoNum(value, altNum) { return isPosNum(value) ? value : altNum; } function minMax(compare, args) { var value = 'auto'; for (var i = 0; i < args.length; i++) { var n = args[i]; if (isPosNum(n)) { if (isPosNum(value)) { if (compare === 'min' && n < value || compare === 'max' && n > value) { value = n; } } else if (value === 'auto') { value = n; } } } return value; } /** * Transforms value into an array with 4 numbers. * @param {string|number} value - '10px' or 10 * @returns {number[]} of length 4 */ function toArrayLen4(value) { var array; var i; if (Array.isArray(value)) { array = value.slice(0, 4); } else if (typeof value === 'string') { var parts = value.replace(/^(\s+)|(\s+)$/g, '').split(/\s+/g).slice(0, 4); array = parts.length ? parts : [value]; } else if ((0, _lodash2.default)(value)) { array = [value]; } else { return [0, 0, 0, 0]; } switch (array.length) { case 1: for (i = 1; i < 4; i++) { array[i] = array[0]; } break; case 2: array[2] = array[0]; array[3] = array[1]; break; case 3: array[3] = array[1]; break; default: break; } for (i = 0; i < 4; i++) { array[i] = parseFloat(array[i]); if (isNaN(array[i])) { array[i] = 0; } } return array; } /** * Returns the preferred width or height amongst width and maxWidth or height * and maxHeight values in options. */ function bestSize(options, dimension) { var maxProp = dimension === 'height' ? 'maxHeight' : 'maxWidth'; var prop = dimension === 'height' ? 'height' : 'width'; var maxOk = isPosNum(options[maxProp]); var valOk = isPosNum(options[prop]); if (maxOk && valOk) { return Math.min(options[maxProp], options[prop]); } else if (maxOk) { return options[maxProp]; } else if (valOk) { return options[prop]; } else { return 'auto'; } } /** * Validates and updates x, y, width, height, maxWidth, maxHeight options. */ function updateSizeOptions(options) { options = (0, _lodash4.default)({}, options); options.padding = toArrayLen4(options.padding); options.margin = toArrayLen4(options.margin); options.x = addMarginToX(+(options.x || 0), options.align, options.margin); options.y = addMarginToY(+(options.y || 0), options.verticalAlign, options.margin); options.width = isPosNum(options.width) ? options.width : 'auto'; options.maxWidth = isPosNum(options.maxWidth) ? options.maxWidth : 'auto'; options.height = isPosNum(options.height) ? options.height : 'auto'; options.maxHeight = isPosNum(options.maxHeight) ? options.maxHeight : 'auto'; options.maxLines = isPosNum(options.maxLines) ? options.maxLines : 'auto'; // options.width = minNum(options.width, options.maxWidth); if (isPosNum(options.outerWidth)) { var maxWidth = options.outerWidth - options.margin[3] - options.margin[1]; options.maxWidth = isPosNum(options.maxWidth) ? Math.min(maxWidth, options.maxWidth) : maxWidth; } if (isPosNum(options.outerHeight)) { var maxHeight = options.outerHeight - options.margin[0] - options.margin[2]; options.maxHeight = isPosNum(options.maxHeight) ? Math.min(maxHeight, options.maxHeight) : maxHeight; } options.textPos = createTextPos(options); return options; } function createTextPos(options) { var padding = options.padding; var rect = { x: addMarginToX(options.x, options.align, options.padding), y: addMarginToY(options.y, options.verticalAlign, options.padding), width: isPosNum(options.width) ? Math.max(0, options.width - padding[3] - padding[1]) : 'auto', height: isPosNum(options.height) ? Math.max(0, options.height - padding[0] - padding[2]) : 'auto', maxWidth: isPosNum(options.maxWidth) ? Math.max(0, options.maxWidth - padding[3] - padding[1]) : 'auto', maxHeight: isPosNum(options.maxHeight) ? Math.max(0, options.maxHeight - padding[0] - padding[2]) : 'auto' }; rect.width = minNum(rect.width, rect.maxWidth); return rect; } // Also works for padding. function addMarginToX(x, align, margin) { if (align === 'right') { x -= margin[1]; } else if (align === 'center') { x += margin[3] / 2; x -= margin[1] / 2; } else { x += margin[3]; } return x; } function addMarginToY(y, verticalAlign, margin) { if (verticalAlign === 'bottom') { y -= margin[2]; } else if (verticalAlign === 'middle') { y += margin[0] / 2; y -= margin[2] / 2; } else { y += margin[0]; } return y; } /***/ }, /* 6 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global, module) {/** * lodash (Custom Build) <https://lodash.com/> * Build: `lodash modularize exports="npm" -o ./` * Copyright jQuery Foundation and other contributors <https://jquery.org/> * Released under MIT license <https://lodash.com/license> * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ /** Used as the size to enable large array optimizations. */ var LARGE_ARRAY_SIZE = 200; /** Used to stand-in for `undefined` hash values. */ var HASH_UNDEFINED = '__lodash_hash_undefined__'; /** Used as references for various `Number` constants. */ var MAX_SAFE_INTEGER = 9007199254740991; /** `Object#toString` result references. */ var argsTag = '[object Arguments]', arrayTag = '[object Array]', boolTag = '[object Boolean]', dateTag = '[object Date]', errorTag = '[object Error]', funcTag = '[object Function]', genTag = '[object GeneratorFunction]', mapTag = '[object Map]', numberTag = '[object Number]', objectTag = '[object Object]', promiseTag = '[object Promise]', regexpTag = '[object RegExp]', setTag = '[object Set]', stringTag = '[object String]', symbolTag = '[object Symbol]', weakMapTag = '[object WeakMap]'; var arrayBufferTag = '[object ArrayBuffer]', dataViewTag = '[object DataView]', float32Tag = '[object Float32Array]', float64Tag = '[object Float64Array]', int8Tag = '[object Int8Array]', int16Tag = '[object Int16Array]', int32Tag = '[object Int32Array]', uint8Tag = '[object Uint8Array]', uint8ClampedTag = '[object Uint8ClampedArray]', uint16Tag = '[object Uint16Array]', uint32Tag = '[object Uint32Array]'; /** * Used to match `RegExp` * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). */ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; /** Used to match `RegExp` flags from their coerced string values. */ var reFlags = /\w*$/; /** Used to detect host constructors (Safari). */ var reIsHostCtor = /^\[object .+?Constructor\]$/; /** Used to detect unsigned integer values. */ var reIsUint = /^(?:0|[1-9]\d*)$/; /** Used to identify `toStringTag` values of typed arrays. */ var typedArrayTags = {}; typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = typedArrayTags[uint32Tag] = true; typedArrayTags[argsTag] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = typedArrayTags[errorTag] = typedArrayTags[funcTag] = typedArrayTags[mapTag] = typedArrayTags[numberTag] = typedArrayTags[objectTag] = typedArrayTags[regexpTag] = typedArrayTags[setTag] = typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; /** Used to identify `toStringTag` values supported by `_.clone`. */ var cloneableTags = {}; cloneableTags[argsTag] = cloneableTags[arrayTag] = cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = cloneableTags[boolTag] = cloneableTags[dateTag] = cloneableTags[float32Tag] = cloneableTags[float64Tag] = cloneableTags[int8Tag] = cloneableTags[int16Tag] = cloneableTags[int32Tag] = cloneableTags[mapTag] = cloneableTags[numberTag] = cloneableTags[objectTag] = cloneableTags[regexpTag] = cloneableTags[setTag] = cloneableTags[stringTag] = cloneableTags[symbolTag] = cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; cloneableTags[errorTag] = cloneableTags[funcTag] = cloneableTags[weakMapTag] = false; /** Detect free variable `global` from Node.js. */ var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; /** Detect free variable `self`. */ var freeSelf = typeof self == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = freeGlobal || freeSelf || Function('return this')(); /** Detect free variable `exports`. */ var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; /** Detect free variable `module`. */ var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; /** Detect the popular CommonJS extension `module.exports`. */ var moduleExports = freeModule && freeModule.exports === freeExports; /** Detect free variable `process` from Node.js. */ var freeProcess = moduleExports && freeGlobal.process; /** Used to access faster Node.js helpers. */ var nodeUtil = (function() { try { return freeProcess && freeProcess.binding('util'); } catch (e) {} }()); /* Node.js helper references. */ var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; /** * Adds the key-value `pair` to `map`. * * @private * @param {Object} map The map to modify. * @param {Array} pair The key-value pair to add. * @returns {Object} Returns `map`. */ function addMapEntry(map, pair) { // Don't return `map.set` because it's not chainable in IE 11. map.set(pair[0], pair[1]); return map; } /** * Adds `value` to `set`. * * @private * @param {Object} set The set to modify. * @param {*} value The value to add. * @returns {Object} Returns `set`. */ function addSetEntry(set, value) { // Don't return `set.add` because it's not chainable in IE 11. set.add(value); return set; } /** * A faster alternative to `Function#apply`, this function invokes `func` * with the `this` binding of `thisArg` and the arguments of `args`. * * @private * @param {Function} func The function to invoke. * @param {*} thisArg The `this` binding of `func`. * @param {Array} args The arguments to invoke `func` with. * @returns {*} Returns the result of `func`. */ function apply(func, thisArg, args) { switch (args.length) { case 0: return func.call(thisArg); case 1: return func.call(thisArg, args[0]); case 2: return func.call(thisArg, args[0], args[1]); case 3: return func.call(thisArg, args[0], args[1], args[2]); } return func.apply(thisArg, args); } /** * A specialized version of `_.forEach` for arrays without support for * iteratee shorthands. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns `array`. */ function arrayEach(array, iteratee) { var index = -1, length = array ? array.length : 0; while (++index < length) { if (iteratee(array[index], index, array) === false) { break; } } return array; } /** * Appends the elements of `values` to `array`. * * @private * @param {Array} array The array to modify. * @param {Array} values The values to append. * @returns {Array} Returns `array`. */ function arrayPush(array, values) { var index = -1, length = values.length, offset = array.length; while (++index < length) { array[offset + index] = values[index]; } return array; } /** * A specialized version of `_.reduce` for arrays without support for * iteratee shorthands. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} [accumulator] The initial value. * @param {boolean} [initAccum] Specify using the first element of `array` as * the initial value. * @returns {*} Returns the accumulated value. */ function arrayReduce(array, iteratee, accumulator, initAccum) { var index = -1, length = array ? array.length : 0; if (initAccum && length) { accumulator = array[++index]; } while (++index < length) { accumulator = iteratee(accumulator, array[index], index, array); } return accumulator; } /** * The base implementation of `_.times` without support for iteratee shorthands * or max array length checks. * * @private * @param {number} n The number of times to invoke `iteratee`. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns the array of results. */ function baseTimes(n, iteratee) { var index = -1, result = Array(n); while (++index < n) { result[index] = iteratee(index); } return result; } /** * The base implementation of `_.unary` without support for storing metadata. * * @private * @param {Function} func The function to cap arguments for. * @returns {Function} Returns the new capped function. */ function baseUnary(func) { return function(value) { return func(value); }; } /** * Gets the value at `key` of `object`. * * @private * @param {Object} [object] The object to query. * @param {string} key The key of the property to get. * @returns {*} Returns the property value. */ function getValue(object, key) { return object == null ? undefined : object[key]; } /** * Checks if `value` is a host object in IE < 9. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a host object, else `false`. */ function isHostObject(value) { // Many host objects are `Object` objects that can coerce to strings // despite having improperly defined `toString` methods. var result = false; if (value != null && typeof value.toString != 'function') { try { result = !!(value + ''); } catch (e) {} } return result; } /** * Converts `map` to its key-value pairs. * * @private * @param {Object} map The map to convert. * @returns {Array} Returns the key-value pairs. */ function mapToArray(map) { var index = -1, result = Array(map.size); map.forEach(function(value, key) { result[++index] = [key, value]; }); return result; } /** * Creates a unary function that invokes `func` with its argument transformed. * * @private * @param {Function} func The function to wrap. * @param {Function} transform The argument transform. * @returns {Function} Returns the new function. */ function overArg(func, transform) { return function(arg) { return func(transform(arg)); }; } /** * Converts `set` to an array of its values. * * @private * @param {Object} set The set to convert. * @returns {Array} Returns the values. */ function setToArray(set) { var index = -1, result = Array(set.size); set.forEach(function(value) { result[++index] = value; }); return result; } /** Used for built-in method references. */ var arrayProto = Array.prototype, funcProto = Function.prototype, objectProto = Object.prototype; /** Used to detect overreaching core-js shims. */ var coreJsData = root['__core-js_shared__']; /** Used to detect methods masquerading as native. */ var maskSrcKey = (function() { var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); return uid ? ('Symbol(src)_1.' + uid) : ''; }()); /** Used to resolve the decompiled source of functions. */ var funcToString = funcProto.toString; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** Used to infer the `Object` constructor. */ var objectCtorString = funcToString.call(Object); /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var objectToString = objectProto.toString; /** Used to detect if a method is native. */ var reIsNative = RegExp('^' + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' ); /** Built-in value references. */ var Buffer = moduleExports ? root.Buffer : undefined, Symbol = root.Symbol, Uint8Array = root.Uint8Array, getPrototype = overArg(Object.getPrototypeOf, Object), objectCreate = Object.create, propertyIsEnumerable = objectProto.propertyIsEnumerable, splice = arrayProto.splice; /* Built-in method references for those with the same name as other `lodash` methods. */ var nativeGetSymbols = Object.getOwnPropertySymbols, nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, nativeKeys = overArg(Object.keys, Object), nativeMax = Math.max; /* Built-in method references that are verified to be native. */ var DataView = getNative(root, 'DataView'), Map = getNative(root, 'Map'), Promise = getNative(root, 'Promise'), Set = getNative(root, 'Set'), WeakMap = getNative(root, 'WeakMap'), nativeCreate = getNative(Object, 'create'); /** Used to detect maps, sets, and weakmaps. */ var dataViewCtorString = toSource(DataView), mapCtorString = toSource(Map), promiseCtorString = toSource(Promise), setCtorString = toSource(Set), weakMapCtorString = toSource(WeakMap); /** Used to convert symbols to primitives and strings. */ var symbolProto = Symbol ? Symbol.prototype : undefined, symbolValueOf = symbolProto ? symbolProto.valueOf : undefined; /** * Creates a hash object. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function Hash(entries) { var index = -1, length = entries ? entries.length : 0; this.clear(); while (++index < length) { var entry = entries[index]; this.set(entry[0], entry[1]); } } /** * Removes all key-value entries from the hash. * * @private * @name clear * @memberOf Hash */ function hashClear() { this.__data__ = nativeCreate ? nativeCreate(null) : {}; } /** * Removes `key` and its value from the hash. * * @private * @name delete * @memberOf Hash * @param {Object} hash The hash to modify. * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function hashDelete(key) { return this.has(key) && delete this.__data__[key]; } /** * Gets the hash value for `key`. * * @private * @name get * @memberOf Hash * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function hashGet(key) { var data = this.__data__; if (nativeCreate) { var result = data[key]; return result === HASH_UNDEFINED ? undefined : result; } return hasOwnProperty.call(data, key) ? data[key] : undefined; } /** * Checks if a hash value for `key` exists. * * @private * @name has * @memberOf Hash * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function hashHas(key) { var data = this.__data__; return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key); } /** * Sets the hash `key` to `value`. * * @private * @name set * @memberOf Hash * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the hash instance. */ function hashSet(key, value) { var data = this.__data__; data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; return this; } // Add methods to `Hash`. Hash.prototype.clear = hashClear; Hash.prototype['delete'] = hashDelete; Hash.prototype.get = hashGet; Hash.prototype.has = hashHas; Hash.prototype.set = hashSet; /** * Creates an list cache object. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function ListCache(entries) { var index = -1, length = entries ? entries.length : 0; this.clear(); while (++index < length) { var entry = entries[index]; this.set(entry[0], entry[1]); } } /** * Removes all key-value entries from the list cache. * * @private * @name clear * @memberOf ListCache */ function listCacheClear() { this.__data__ = []; } /** * Removes `key` and its value from the list cache. * * @private * @name delete * @memberOf ListCache * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function listCacheDelete(key) { var data = this.__data__, index = assocIndexOf(data, key); if (index < 0) { return false; } var lastIndex = data.length - 1; if (index == lastIndex) { data.pop(); } else { splice.call(data, index, 1); } return true; } /** * Gets the list cache value for `key`. * * @private * @name get * @memberOf ListCache * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function listCacheGet(key) { var data = this.__data__, index = assocIndexOf(data, key); return index < 0 ? undefined : data[index][1]; } /** * Checks if a list cache value for `key` exists. * * @private * @name has * @memberOf ListCache * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function listCacheHas(key) { return assocIndexOf(this.__data__, key) > -1; } /** * Sets the list cache `key` to `value`. * * @private * @name set * @memberOf ListCache * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the list cache instance. */ function listCacheSet(key, value) { var data = this.__data__, index = assocIndexOf(data, key); if (index < 0) { data.push([key, value]); } else { data[index][1] = value; } return this; } // Add methods to `ListCache`. ListCache.prototype.clear = listCacheClear; ListCache.prototype['delete'] = listCacheDelete; ListCache.prototype.get = listCacheGet; ListCache.prototype.has = listCacheHas; ListCache.prototype.set = listCacheSet; /** * Creates a map cache object to store key-value pairs. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function MapCache(entries) { var index = -1, length = entries ? entries.length : 0; this.clear(); while (++index < length) { var entry = entries[index]; this.set(entry[0], entry[1]); } } /** * Removes all key-value entries from the map. * * @private * @name clear * @memberOf MapCache */ function mapCacheClear() { this.__data__ = { 'hash': new Hash, 'map': new (Map || ListCache), 'string': new Hash }; } /** * Removes `key` and its value from the map. * * @private * @name delete * @memberOf MapCache * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function mapCacheDelete(key) { return getMapData(this, key)['delete'](key); } /** * Gets the map value for `key`. * * @private * @name get * @memberOf MapCache * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function mapCacheGet(key) { return getMapData(this, key).get(key); } /** * Checks if a map value for `key` exists. * * @private * @name has * @memberOf MapCache * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function mapCacheHas(key) { return getMapData(this, key).has(key); } /** * Sets the map `key` to `value`. * * @private * @name set * @memberOf MapCache * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the map cache instance. */ function mapCacheSet(key, value) { getMapData(this, key).set(key, value); return this; } // Add methods to `MapCache`. MapCache.prototype.clear = mapCacheClear; MapCache.prototype['delete'] = mapCacheDelete; MapCache.prototype.get = mapCacheGet; MapCache.prototype.has = mapCacheHas; MapCache.prototype.set = mapCacheSet; /** * Creates a stack cache object to store key-value pairs. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function Stack(entries) { this.__data__ = new ListCache(entries); } /** * Removes all key-value entries from the stack. * * @private * @name clear * @memberOf Stack */ function stackClear() { this.__data__ = new ListCache; } /** * Removes `key` and its value from the stack. * * @private * @name delete * @memberOf Stack * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function stackDelete(key) { return this.__data__['delete'](key); } /** * Gets the stack value for `key`. * * @private * @name get * @memberOf Stack * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function stackGet(key) { return this.__data__.get(key); } /** * Checks if a stack value for `key` exists. * * @private * @name has * @memberOf Stack * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function stackHas(key) { return this.__data__.has(key); } /** * Sets the stack `key` to `value`. * * @private * @name set * @memberOf Stack * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the stack cache instance. */ function stackSet(key, value) { var cache = this.__data__; if (cache instanceof ListCache) { var pairs = cache.__data__; if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { pairs.push([key, value]); return this; } cache = this.__data__ = new MapCache(pairs); } cache.set(key, value); return this; } // Add methods to `Stack`. Stack.prototype.clear = stackClear; Stack.prototype['delete'] = stackDelete; Stack.prototype.get = stackGet; Stack.prototype.has = stackHas; Stack.prototype.set = stackSet; /** * Creates an array of the enumerable property names of the array-like `v