UNPKG

billboard.js

Version:

Re-usable easy interface JavaScript chart library, based on D3 v4+

142 lines (139 loc) 4.91 kB
/*! * Copyright (c) 2017 ~ present NAVER Corp. * billboard.js project is licensed under the MIT license * * billboard.js, JavaScript chart library * https://naver.github.io/billboard.js/ * * @version 4.0.1 */ import { select, namespaces } from 'd3-selection'; import { document as doc } from '../../../module/browser.js'; import { notEmpty, isObjectType, isFunction } from '../../../module/util/type-checks.js'; import { sanitize } from '../../../module/sanitize.js'; import { toArray } from '../../../module/util/object.js'; /** * Copyright (c) 2017 ~ present NAVER Corp. * billboard.js project is licensed under the MIT license */ /** * Check if point draw methods are valid * @param {string} point point type * @returns {boolean} * @private */ function _hasValidPointDrawMethods(point) { return isObjectType(point) && isFunction(point.create) && isFunction(point.update); } /** * Insert point info defs element * @param {string} point Point element * @param {string} id Point id * @private */ function _insertPointInfoDefs(point, id) { const $$ = this; const copyAttr = (from, target) => { const attribs = from.attributes; for (let i = 0, name; (name = attribs[i]); i++) { name = name.name; target.setAttribute(name, from.getAttribute(name)); } }; const doc$1 = new DOMParser().parseFromString(sanitize(point), "image/svg+xml"); const node = doc$1.documentElement; const clone = doc.createElementNS(namespaces.svg, node.nodeName.toLowerCase()); clone.id = id; clone.style.fill = "inherit"; clone.style.stroke = "inherit"; copyAttr(node, clone); if (node.childNodes?.length) { const parent = select(clone); if ("innerHTML" in clone) { parent.html(sanitize(node.innerHTML)); } else { toArray(node.childNodes).forEach(v => { copyAttr(v, parent.append(v.tagName).node()); }); } } $$.$el.defs.node().appendChild(clone); } var shapePointCommon = { /** * Check if point type option is valid * @param {string} type point type * @returns {boolean} * @private */ hasValidPointType(type) { // For point.pattern, allow additional SVG shape tags (polygon, ellipse, use) // These will be sanitized before use return /^(circle|rect(angle)?|polygon|ellipse|use)$/i.test(type || this.config.point_type); }, /** * Check if pattern point is set to be used on legend * @returns {boolean} * @private */ hasLegendDefsPoint() { const { config } = this; return config.legend_show && config.point_pattern?.length && config.legend_usePoint; }, getDefsPointId(id) { const { state: { datetimeId } } = this; return `${datetimeId}-point${id}`; }, /** * Get validated point pattern array * @returns {Array} Array of point types * @private */ getValidPointPattern() { const { config } = this; // Ensure point_type is restricted to 'circle' or 'rectangle' only const validPointType = /^(circle|rect(angle)?)$/i.test(config.point_type) ? config.point_type : "circle"; return notEmpty(config.point_pattern) ? config.point_pattern : [validPointType]; }, /** * Get generate point function * @returns {function} * @private */ generatePoint() { const $$ = this; const { $el, config } = $$; const ids = []; const pattern = $$.getValidPointPattern(); return function (method, context, ...args) { return function (d) { const id = $$.getTargetSelectorSuffix(d.id || d.data?.id || d); const element = select(this); ids.indexOf(id) < 0 && ids.push(id); let point = pattern[ids.indexOf(id) % pattern.length]; if ($$.hasValidPointType(point)) { point = $$[point]; } else if (!_hasValidPointDrawMethods(point || config.point_type)) { const pointId = $$.getDefsPointId(id); const defsPoint = $el.defs.select(`#${pointId}`); if (defsPoint.size() < 1) { _insertPointInfoDefs.call($$, point, pointId); } if (method === "create") { return $$.custom?.create.bind(context)(element, pointId, ...args); } else if (method === "update") { return $$.custom?.update.bind(context)(element, ...args); } } return point[method]?.bind(context)(element, ...args); }; }; } }; export { shapePointCommon as default };