UNPKG

d3plus-shape

Version:

Fancy SVG shapes for visualizations

1,131 lines (1,066 loc) 46.2 kB
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } /** @external BaseClass @see https://github.com/d3plus/d3plus-common#BaseClass */ import { min } from "d3-array"; import { color } from "d3-color"; import { pointer, select as _select, selectAll } from "d3-selection"; import { transition } from "d3-transition"; import { accessor, assign, attrize, BaseClass, configPrep, constant, elem, isObject, unique } from "d3plus-common"; import { colorContrast } from "d3plus-color"; import * as paths from "d3-shape"; import { strip, TextBox } from "d3plus-text"; import textures from "textures"; import Image from "../Image.js"; import pointDistance from "../geom/pointDistance.js"; /** @class Shape @extends external:BaseClass @desc An abstracted class for generating shapes. */ var Shape = /*#__PURE__*/function (_BaseClass) { _inherits(Shape, _BaseClass); var _super = _createSuper(Shape); /** @memberof Shape @desc Invoked when creating a new class instance, and sets any default parameters. @private */ function Shape() { var _this; var tagName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "g"; _classCallCheck(this, Shape); _this = _super.call(this); _this._activeOpacity = 0.25; _this._activeStyle = { "stroke": function stroke(d, i) { var c = _this._fill(d, i); if (["transparent", "none"].includes(c)) c = _this._stroke(d, i); return color(c).darker(1); }, "stroke-width": function strokeWidth(d, i) { var s = _this._strokeWidth(d, i) || 1; return s * 3; } }; _this._ariaLabel = constant(""); _this._backgroundImage = constant(false); _this._backgroundImageClass = new Image(); _this._data = []; _this._duration = 600; _this._fill = constant("black"); _this._fillOpacity = constant(1); _this._hoverOpacity = 0.5; _this._hoverStyle = { "stroke": function stroke(d, i) { var c = _this._fill(d, i); if (["transparent", "none"].includes(c)) c = _this._stroke(d, i); return color(c).darker(0.5); }, "stroke-width": function strokeWidth(d, i) { var s = _this._strokeWidth(d, i) || 1; return s * 2; } }; _this._id = function (d, i) { return d.id !== void 0 ? d.id : i; }; _this._label = constant(false); _this._labelClass = new TextBox(); _this._labelConfig = { fontColor: function fontColor(d, i) { return colorContrast(_this._fill(d, i)); }, fontSize: 12, padding: 5 }; _this._name = "Shape"; _this._opacity = constant(1); _this._pointerEvents = constant("visiblePainted"); _this._role = constant("presentation"); _this._rotate = constant(0); _this._rx = constant(0); _this._ry = constant(0); _this._scale = constant(1); _this._shapeRendering = constant("geometricPrecision"); _this._stroke = function (d, i) { return color(_this._fill(d, i)).darker(1).formatHex(); }; _this._strokeDasharray = constant("0"); _this._strokeLinecap = constant("butt"); _this._strokeOpacity = constant(1); _this._strokeWidth = constant(0); _this._tagName = tagName; _this._textAnchor = constant("start"); _this._texture = constant(false); _this._textureDefault = {}; _this._textureDefs = {}; _this._vectorEffect = constant("non-scaling-stroke"); _this._verticalAlign = constant("top"); _this._x = accessor("x", 0); _this._y = accessor("y", 0); return _this; } /** @memberof Shape @desc Given a specific data point and index, returns the aesthetic properties of the shape. @param {Object} *data point* @param {Number} *index* @private */ _createClass(Shape, [{ key: "_aes", value: function _aes() { return {}; } /** @memberof Shape @desc Adds event listeners to each shape group or hit area. @param {D3Selection} *update* The update cycle of the data binding. @private */ }, { key: "_applyEvents", value: function _applyEvents(handler) { var _this2 = this; var events = Object.keys(this._on); var _loop = function _loop(e) { handler.on(events[e], function (event, d, i) { if (!_this2._on[events[e]]) return; if (d.i !== void 0) i = d.i; if (d.nested && d.values) { var calcPoint = function calcPoint(d, i) { if (_this2._discrete === "x") return [_this2._x(d, i), cursor[1]];else if (_this2._discrete === "y") return [cursor[0], _this2._y(d, i)];else return [_this2._x(d, i), _this2._y(d, i)]; }; var cursor = pointer(event, _this2._select.node()), values = d.values.map(function (d) { return pointDistance(cursor, calcPoint(d, i)); }); i = values.indexOf(min(values)); d = d.values[i]; } _this2._on[events[e]].bind(_this2)(d, i, undefined, event); }); }; for (var e = 0; e < events.length; e++) { _loop(e); } } /** @memberof Shape @desc Provides the updated styling to the given shape elements. @param {HTMLElement} *elem* @param {Object} *style* @private */ }, { key: "_updateStyle", value: function _updateStyle(elem, style) { var that = this; if (elem.size() && elem.node().tagName === "g") elem = elem.selectAll("*"); /** @desc Determines whether a shape is a nested collection of data points, and uses the appropriate data and index for the given function context. @param {Object} *d* data point @param {Number} *i* index @private */ function styleLogic(d, i) { return typeof this !== "function" ? this : d.nested && d.key && d.values ? this(d.values[0], that._data.indexOf(d.values[0])) : this(d, i); } var styleObject = {}; for (var key in style) { if ({}.hasOwnProperty.call(style, key)) { styleObject[key] = styleLogic.bind(style[key]); } } elem.transition().duration(0).call(attrize, styleObject); } /** @memberof Shape @desc Provides the default styling to the shape elements. @param {HTMLElement} *elem* @private */ }, { key: "_applyStyle", value: function _applyStyle(elem) { var _this3 = this; var that = this; if (elem.size() && elem.node().tagName === "g") elem = elem.selectAll("*"); /** @desc Determines whether a shape is a nested collection of data points, and uses the appropriate data and index for the given function context. @param {Object} *d* data point @param {Number} *i* index @private */ function styleLogic(d, i) { return typeof this !== "function" ? this : d.nested && d.key && d.values ? this(d.values[0], that._data.indexOf(d.values[0])) : this(d, i); } elem.attr("fill", function (d, i) { var texture = _this3._getTextureKey.bind(_this3)(d, i); return texture ? _this3._textureDefs[texture].url() : styleLogic.bind(_this3._fill)(d, i); }).attr("fill-opacity", styleLogic.bind(this._fillOpacity)).attr("rx", styleLogic.bind(this._rx)).attr("ry", styleLogic.bind(this._ry)).attr("stroke", styleLogic.bind(this._stroke)).attr("stroke-dasharray", styleLogic.bind(this._strokeDasharray)).attr("stroke-linecap", styleLogic.bind(this._strokeLinecap)).attr("stroke-opacity", styleLogic.bind(this._strokeOpacity)).attr("stroke-width", styleLogic.bind(this._strokeWidth)).attr("vector-effect", styleLogic.bind(this._vectorEffect)); } /** @memberof Shape @desc Calculates the transform for the group elements. @param {HTMLElement} *elem* @private */ }, { key: "_applyTransform", value: function _applyTransform(elem) { var _this4 = this; elem.attr("transform", function (d, i) { return "\n translate(".concat(d.__d3plusShape__ ? d.translate ? d.translate : "".concat(_this4._x(d.data, d.i), ",").concat(_this4._y(d.data, d.i)) : "".concat(_this4._x(d, i), ",").concat(_this4._y(d, i)), ")\n scale(").concat(d.__d3plusShape__ ? d.scale || _this4._scale(d.data, d.i) : _this4._scale(d, i), ")\n rotate(").concat(d.__d3plusShape__ ? d.rotate ? d.rotate : _this4._rotate(d.data || d, d.i) : _this4._rotate(d.data || d, d.i), ")"); }); } /** @memberof Shape @desc Returns a full JSON string of the texture config for a given data point. @param {Object} *d* @param {Number} *i* @private */ }, { key: "_getTextureKey", value: function _getTextureKey(d, i) { var _this5 = this; var texture = this._texture(d, i); if (!texture) return false; /** @desc Determines whether a shape is a nested collection of data points, and uses the appropriate data and index for the given function context. @private */ var styleLogic = function styleLogic(_) { return typeof _ !== "function" ? _ : d.nested && d.key && d.values ? _(d.values[0], _this5._data.indexOf(d.values[0])) : _(d, i); }; var fallback = this._textureDefault; if (!isObject(texture)) texture = { texture: texture }; if (!texture.background) texture.background = styleLogic(this._fill); if (!texture.stroke && !fallback.stroke) texture.stroke = styleLogic(this._stroke); var paths = ["squares", "nylon", "waves", "woven", "crosses", "caps", "hexagons"]; if (paths.includes(texture.texture) || typeof texture.texture === "function") { texture.d = texture.texture; texture.texture = "paths"; } else if (texture.texture === "grid") { if (!texture.orientation && !fallback.orientation) texture.orientation = ["vertical", "horizontal"]; texture.texture = "lines"; } if (!texture.fill && texture.texture !== "paths") texture.fill = texture.stroke; var retObj = assign({}, fallback, texture); if (typeof retObj.d === "function") { retObj.d = retObj.d(retObj.size || 20); } return JSON.stringify(retObj); } /** @memberof Shape @desc Checks for nested data and uses the appropriate variables for accessor functions. @param {HTMLElement} *elem* @private */ }, { key: "_nestWrapper", value: function _nestWrapper(method) { return function (d, i) { return method(d.__d3plusShape__ ? d.data : d, d.__d3plusShape__ ? d.i : i); }; } /** @memberof Shape @desc Modifies existing shapes to show active status. @private */ }, { key: "_renderActive", value: function _renderActive() { var that = this; this._group.selectAll(".d3plus-Shape, .d3plus-Image, .d3plus-textBox").each(function (d, i) { if (!d) d = {}; if (!d.parentNode) d.parentNode = this.parentNode; var parent = d.parentNode; if (_select(this).classed("d3plus-textBox")) d = d.data; if (d.__d3plusShape__ || d.__d3plus__) { while (d && (d.__d3plusShape__ || d.__d3plus__)) { i = d.i; d = d.data; } } else i = that._data.indexOf(d); var group = !that._active || typeof that._active !== "function" || !that._active(d, i) ? parent : that._activeGroup.node(); if (group !== this.parentNode) { group.appendChild(this); if (this.className.baseVal.includes("d3plus-Shape")) { if (parent === group) _select(this).call(that._applyStyle.bind(that));else _select(this).call(that._updateStyle.bind(that, _select(this), that._activeStyle)); } } }); // this._renderImage(); // this._renderLabels(); this._group.selectAll("g.d3plus-".concat(this._name, "-shape, g.d3plus-").concat(this._name, "-image, g.d3plus-").concat(this._name, "-text")).attr("opacity", this._hover ? this._hoverOpacity : this._active ? this._activeOpacity : 1); } /** @memberof Shape @desc Modifies existing shapes to show hover status. @private */ }, { key: "_renderHover", value: function _renderHover() { var that = this; this._group.selectAll("g.d3plus-".concat(this._name, "-shape, g.d3plus-").concat(this._name, "-image, g.d3plus-").concat(this._name, "-text, g.d3plus-").concat(this._name, "-hover")).selectAll(".d3plus-Shape, .d3plus-Image, .d3plus-textBox").each(function (d, i) { if (!d) d = {}; if (!d.parentNode) d.parentNode = this.parentNode; var parent = d.parentNode; if (_select(this).classed("d3plus-textBox")) d = d.data; if (d.__d3plusShape__ || d.__d3plus__) { while (d && (d.__d3plusShape__ || d.__d3plus__)) { i = d.i; d = d.data; } } else i = that._data.indexOf(d); var group = !that._hover || typeof that._hover !== "function" || !that._hover(d, i) ? parent : that._hoverGroup.node(); if (group !== this.parentNode) group.appendChild(this); if (this.className.baseVal.includes("d3plus-Shape")) { if (parent === group) _select(this).call(that._applyStyle.bind(that));else _select(this).call(that._updateStyle.bind(that, _select(this), that._hoverStyle)); } }); // this._renderImage(); // this._renderLabels(); this._group.selectAll("g.d3plus-".concat(this._name, "-shape, g.d3plus-").concat(this._name, "-image, g.d3plus-").concat(this._name, "-text")).attr("opacity", this._hover ? this._hoverOpacity : this._active ? this._activeOpacity : 1); } /** @memberof Shape @desc Adds background image to each shape group. @private */ }, { key: "_renderImage", value: function _renderImage() { var _this6 = this; var imageData = []; this._update.merge(this._enter).data().forEach(function (datum, i) { var aes = _this6._aes(datum, i); if (aes.r || aes.width && aes.height) { var d = datum; if (datum.nested && datum.key && datum.values) { d = datum.values[0]; i = _this6._data.indexOf(d); } var height = aes.r ? aes.r * 2 : aes.height, url = _this6._backgroundImage(d, i), width = aes.r ? aes.r * 2 : aes.width; if (url) { var x = d.__d3plusShape__ ? d.translate ? d.translate[0] : _this6._x(d.data, d.i) : _this6._x(d, i), y = d.__d3plusShape__ ? d.translate ? d.translate[1] : _this6._y(d.data, d.i) : _this6._y(d, i); if (aes.x) x += aes.x; if (aes.y) y += aes.y; if (d.__d3plusShape__) { d = d.data; i = d.i; } imageData.push({ __d3plus__: true, data: d, height: height, i: i, id: _this6._id(d, i), url: url, width: width, x: x + -width / 2, y: y + -height / 2 }); } } }); this._backgroundImageClass.data(imageData).duration(this._duration).opacity(this._nestWrapper(this._opacity)).pointerEvents("none").select(elem("g.d3plus-".concat(this._name, "-image"), { parent: this._group, update: { opacity: this._active ? this._activeOpacity : 1 } }).node()).render(); } /** @memberof Shape @desc Adds labels to each shape group. @private */ }, { key: "_renderLabels", value: function _renderLabels() { var _this7 = this; var labelData = []; this._update.merge(this._enter).data().forEach(function (datum, i) { var d = datum; if (datum.nested && datum.key && datum.values) { d = datum.values[0]; i = _this7._data.indexOf(d); } var labels = _this7._label(d, i); if (_this7._labelBounds && labels !== false && labels !== undefined && labels !== null) { var bounds = _this7._labelBounds.bind(_this7)(d, i, _this7._aes(datum, i)); if (bounds) { if (labels.constructor !== Array) labels = [labels]; var x = d.__d3plusShape__ ? d.translate ? d.translate[0] : _this7._x(d.data, d.i) : _this7._x(d, i), y = d.__d3plusShape__ ? d.translate ? d.translate[1] : _this7._y(d.data, d.i) : _this7._y(d, i); if (d.__d3plusShape__) { d = d.data; i = d.i; } for (var l = 0; l < labels.length; l++) { var b = bounds.constructor === Array ? bounds[l] : Object.assign({}, bounds); var rotate = _this7._rotate(d, i); var r = d.labelConfig && d.labelConfig.rotate ? d.labelConfig.rotate : bounds.angle !== undefined ? bounds.angle : 0; r += rotate; var rotateAnchor = rotate !== 0 ? [b.x * -1 || 0, b.y * -1 || 0] : [b.width / 2, b.height / 2]; labelData.push({ __d3plus__: true, data: d, height: b.height, l: l, id: "".concat(_this7._id(d, i), "_").concat(l), r: r, rotateAnchor: rotateAnchor, text: labels[l], width: b.width, x: x + b.x, y: y + b.y }); } } } }); this._labelClass.data(labelData).duration(this._duration).fontOpacity(this._nestWrapper(this._opacity)).pointerEvents("none").rotate(function (d) { return d.__d3plus__ ? d.r : d.data.r; }).rotateAnchor(function (d) { return d.__d3plus__ ? d.rotateAnchor : d.data.rotateAnchor; }).select(elem("g.d3plus-".concat(this._name, "-text"), { parent: this._group, update: { opacity: this._active ? this._activeOpacity : 1 } }).node()).config(configPrep.bind(this)(this._labelConfig)).render(); } /** @memberof Shape @desc Renders the current Shape to the page. If a *callback* is specified, it will be called once the shapes are done drawing. @param {Function} [*callback*] @chainable */ }, { key: "render", value: function render(callback) { var _this8 = this; if (this._select === void 0) { this.select(_select("body").append("svg").style("width", "".concat(window.innerWidth, "px")).style("height", "".concat(window.innerHeight, "px")).style("display", "block").node()); } this._transition = transition(this._uuid).duration(this._duration); var data = this._data, key = this._id; if (this._dataFilter) { data = this._dataFilter(data); if (data.key) key = data.key; } if (this._sort) { data = data.sort(function (a, b) { while (a.__d3plusShape__ || a.__d3plus__) a = a.data; while (b.__d3plusShape__ || b.__d3plus__) b = b.data; return _this8._sort(a, b); }); } var textureSet = unique(data.map(this._getTextureKey.bind(this))).filter(Boolean); var existingTextureDefs = Object.keys(this._textureDefs); existingTextureDefs.forEach(function (key) { if (!textureSet.includes(key)) { _select(_this8._select.select("pattern#".concat(_this8._textureDefs[key].id())).node().parentNode).remove(); delete _this8._textureDefs[key]; } }); textureSet.forEach(function (key) { if (!existingTextureDefs.includes(key)) { var config = JSON.parse(key); var textureClass = config.texture; delete config.texture; var t = textures[textureClass](); var _loop2 = function _loop2(k) { if ({}.hasOwnProperty.call(t, k) && k in t) { if (k === "d") t[k](function () { return config[k]; });else config[k] instanceof Array ? t[k].apply(null, config[k]) : t[k](config[k]); } }; for (var k in config) { _loop2(k); } _this8._select.call(t); _this8._textureDefs[key] = t; } }); selectAll("g.d3plus-".concat(this._name, "-hover > *, g.d3plus-").concat(this._name, "-active > *")).each(function (d) { if (d && d.parentNode) d.parentNode.appendChild(this);else this.parentNode.removeChild(this); }); // Makes the update state of the group selection accessible. this._group = elem("g.d3plus-".concat(this._name, "-group"), { parent: this._select }); var update = this._update = elem("g.d3plus-".concat(this._name, "-shape"), { parent: this._group, update: { opacity: this._active ? this._activeOpacity : 1 } }).selectAll(".d3plus-".concat(this._name)).data(data, key); // Orders and transforms the updating Shapes. update.order(); if (this._duration) { update.transition(this._transition).call(this._applyTransform.bind(this)); } else { update.call(this._applyTransform.bind(this)); } // Makes the enter state of the group selection accessible. var enter = this._enter = update.enter().append(this._tagName).attr("class", function (d, i) { return "d3plus-Shape d3plus-".concat(_this8._name, " d3plus-id-").concat(strip(_this8._nestWrapper(_this8._id)(d, i))); }).call(this._applyTransform.bind(this)).attr("aria-label", this._ariaLabel).attr("role", this._role).attr("opacity", this._nestWrapper(this._opacity)); var enterUpdate = enter.merge(update); var enterUpdateRender = enterUpdate.attr("shape-rendering", this._nestWrapper(this._shapeRendering)); if (this._duration) { enterUpdateRender = enterUpdateRender.attr("pointer-events", "none").transition(this._transition).transition().delay(100).attr("pointer-events", this._pointerEvents); } enterUpdateRender.attr("opacity", this._nestWrapper(this._opacity)); // Makes the exit state of the group selection accessible. var exit = this._exit = update.exit(); if (this._duration) exit.transition().delay(this._duration).remove();else exit.remove(); this._renderImage(); this._renderLabels(); this._hoverGroup = elem("g.d3plus-".concat(this._name, "-hover"), { parent: this._group }); this._activeGroup = elem("g.d3plus-".concat(this._name, "-active"), { parent: this._group }); var hitAreas = this._group.selectAll(".d3plus-HitArea").data(this._hitArea && Object.keys(this._on).length ? data : [], key); hitAreas.order().call(this._applyTransform.bind(this)); var isLine = this._name === "Line"; if (isLine) { var curve = this._curve.bind(this)(this.config()); isLine && this._path.curve(paths["curve".concat(curve.charAt(0).toUpperCase()).concat(curve.slice(1))]).defined(this._defined).x(this._x).y(this._y); } var hitEnter = hitAreas.enter().append(isLine ? "path" : "rect").attr("class", function (d, i) { return "d3plus-HitArea d3plus-id-".concat(strip(_this8._nestWrapper(_this8._id)(d, i))); }).attr("fill", "black").attr("stroke", "black").attr("pointer-events", "painted").attr("opacity", 0).call(this._applyTransform.bind(this)); var that = this; var hitUpdates = hitAreas.merge(hitEnter).each(function (d) { var i = that._data.indexOf(d); var h = that._hitArea(d, i, that._aes(d, i)); return h && !(that._name === "Line" && parseFloat(that._strokeWidth(d, i)) > 10) ? _select(this).call(attrize, h) : _select(this).remove(); }); hitAreas.exit().remove(); this._applyEvents(this._hitArea ? hitUpdates : enterUpdate); setTimeout(function () { if (_this8._active) _this8._renderActive();else if (_this8._hover) _this8._renderHover(); if (callback) callback(); }, this._duration + 100); return this; } /** @memberof Shape @desc If *value* is specified, sets the highlight accessor to the specified function and returns the current class instance. @param {Function} [*value*] @chainable */ }, { key: "active", value: function active(_) { if (!arguments.length || _ === undefined) return this._active; this._active = _; if (this._group) { // this._renderImage(); // this._renderLabels(); this._renderActive(); } return this; } /** @memberof Shape @desc When shapes are active, this is the opacity of any shape that is not active. @param {Number} *value* = 0.25 @chainable */ }, { key: "activeOpacity", value: function activeOpacity(_) { return arguments.length ? (this._activeOpacity = _, this) : this._activeOpacity; } /** @memberof Shape @desc The style to apply to active shapes. @param {Object} *value* @chainable */ }, { key: "activeStyle", value: function activeStyle(_) { return arguments.length ? (this._activeStyle = assign({}, this._activeStyle, _), this) : this._activeStyle; } /** @memberof Shape @desc If *value* is specified, sets the aria-label attribute to the specified function or string and returns the current class instance. @param {Function|String} *value* @chainable */ }, { key: "ariaLabel", value: function ariaLabel(_) { return _ !== undefined ? (this._ariaLabel = typeof _ === "function" ? _ : constant(_), this) : this._ariaLabel; } /** @memberof Shape @desc If *value* is specified, sets the background-image accessor to the specified function or string and returns the current class instance. @param {Function|String} [*value* = false] @chainable */ }, { key: "backgroundImage", value: function backgroundImage(_) { return arguments.length ? (this._backgroundImage = typeof _ === "function" ? _ : constant(_), this) : this._backgroundImage; } /** @memberof Shape @desc If *data* is specified, sets the data array to the specified array and returns the current class instance. If *data* is not specified, returns the current data array. A shape will be drawn for each object in the array. @param {Array} [*data* = []] @chainable */ }, { key: "data", value: function data(_) { return arguments.length ? (this._data = _, this) : this._data; } /** @memberof Shape @desc Determines if either the X or Y position is discrete along a Line, which helps in determining the nearest data point on a line for a hit area event. @param {String} *value* @chainable */ }, { key: "discrete", value: function discrete(_) { return arguments.length ? (this._discrete = _, this) : this._discrete; } /** @memberof Shape @desc If *ms* is specified, sets the animation duration to the specified number and returns the current class instance. If *ms* is not specified, returns the current animation duration. @param {Number} [*ms* = 600] @chainable */ }, { key: "duration", value: function duration(_) { return arguments.length ? (this._duration = _, this) : this._duration; } /** @memberof Shape @desc If *value* is specified, sets the fill accessor to the specified function or string and returns the current class instance. @param {Function|String} [*value* = "black"] @chainable */ }, { key: "fill", value: function fill(_) { return arguments.length ? (this._fill = typeof _ === "function" ? _ : constant(_), this) : this._fill; } /** @memberof Shape @desc Defines the "fill-opacity" attribute for the shapes. @param {Function|Number} [*value* = 1] @chainable */ }, { key: "fillOpacity", value: function fillOpacity(_) { return arguments.length ? (this._fillOpacity = typeof _ === "function" ? _ : constant(_), this) : this._fillOpacity; } /** @memberof Shape @desc If *value* is specified, sets the highlight accessor to the specified function and returns the current class instance. @param {Function} [*value*] @chainable */ }, { key: "hover", value: function hover(_) { if (!arguments.length || _ === void 0) return this._hover; this._hover = _; if (this._group) { // this._renderImage(); // this._renderLabels(); this._renderHover(); } return this; } /** @memberof Shape @desc The style to apply to hovered shapes. @param {Object} *value* @chainable */ }, { key: "hoverStyle", value: function hoverStyle(_) { return arguments.length ? (this._hoverStyle = assign({}, this._hoverStyle, _), this) : this._hoverStyle; } /** @memberof Shape @desc If *value* is specified, sets the hover opacity to the specified function and returns the current class instance. @param {Number} [*value* = 0.5] @chainable */ }, { key: "hoverOpacity", value: function hoverOpacity(_) { return arguments.length ? (this._hoverOpacity = _, this) : this._hoverOpacity; } /** @memberof Shape @desc If *bounds* is specified, sets the mouse hit area to the specified function and returns the current class instance. If *bounds* is not specified, returns the current mouse hit area accessor. @param {Function} [*bounds*] The given function is passed the data point, index, and internally defined properties of the shape and should return an object containing the following values: `width`, `height`, `x`, `y`. @chainable @example function(d, i, shape) { return { "width": shape.width, "height": shape.height, "x": -shape.width / 2, "y": -shape.height / 2 }; } */ }, { key: "hitArea", value: function hitArea(_) { return arguments.length ? (this._hitArea = typeof _ === "function" ? _ : constant(_), this) : this._hitArea; } /** @memberof Shape @desc If *value* is specified, sets the id accessor to the specified function and returns the current class instance. @param {Function} [*value*] @chainable */ }, { key: "id", value: function id(_) { return arguments.length ? (this._id = _, this) : this._id; } /** @memberof Shape @desc If *value* is specified, sets the label accessor to the specified function or string and returns the current class instance. @param {Function|String|Array} [*value*] @chainable */ }, { key: "label", value: function label(_) { return arguments.length ? (this._label = typeof _ === "function" ? _ : constant(_), this) : this._label; } /** @memberof Shape @desc If *bounds* is specified, sets the label bounds to the specified function and returns the current class instance. If *bounds* is not specified, returns the current inner bounds accessor. @param {Function} [*bounds*] The given function is passed the data point, index, and internally defined properties of the shape and should return an object containing the following values: `width`, `height`, `x`, `y`. If an array is returned from the function, each value will be used in conjunction with each label. @chainable @example function(d, i, shape) { return { "width": shape.width, "height": shape.height, "x": -shape.width / 2, "y": -shape.height / 2 }; } */ }, { key: "labelBounds", value: function labelBounds(_) { return arguments.length ? (this._labelBounds = typeof _ === "function" ? _ : constant(_), this) : this._labelBounds; } /** @memberof Shape @desc A pass-through to the config method of the TextBox class used to create a shape's labels. @param {Object} [*value*] @chainable */ }, { key: "labelConfig", value: function labelConfig(_) { return arguments.length ? (this._labelConfig = assign(this._labelConfig, _), this) : this._labelConfig; } /** @memberof Shape @desc If *value* is specified, sets the opacity accessor to the specified function or number and returns the current class instance. @param {Number} [*value* = 1] @chainable */ }, { key: "opacity", value: function opacity(_) { return arguments.length ? (this._opacity = typeof _ === "function" ? _ : constant(_), this) : this._opacity; } /** @memberof Shape @desc If *value* is specified, sets the pointerEvents accessor to the specified function or string and returns the current class instance. @param {String} [*value*] @chainable */ }, { key: "pointerEvents", value: function pointerEvents(_) { return arguments.length ? (this._pointerEvents = typeof _ === "function" ? _ : constant(_), this) : this._pointerEvents; } /** @memberof Shape @desc If *value* is specified, sets the role attribute to the specified function or string and returns the current class instance. @param {Function|String} *value* @chainable */ }, { key: "role", value: function role(_) { return _ !== undefined ? (this._role = typeof _ === "function" ? _ : constant(_), this) : this._role; } /** @memberof Shape @desc If *value* is specified, sets the rotate accessor to the specified function or number and returns the current class instance. @param {Function|Number} [*value* = 0] @chainable */ }, { key: "rotate", value: function rotate(_) { return arguments.length ? (this._rotate = typeof _ === "function" ? _ : constant(_), this) : this._rotate; } /** @memberof Shape @desc Defines the "rx" attribute for the shapes. @param {Function|Number} [*value* = 0] @chainable */ }, { key: "rx", value: function rx(_) { return arguments.length ? (this._rx = typeof _ === "function" ? _ : constant(_), this) : this._rx; } /** @memberof Shape @desc Defines the "rx" attribute for the shapes. @param {Function|Number} [*value* = 0] @chainable */ }, { key: "ry", value: function ry(_) { return arguments.length ? (this._ry = typeof _ === "function" ? _ : constant(_), this) : this._ry; } /** @memberof Shape @desc If *value* is specified, sets the scale accessor to the specified function or string and returns the current class instance. @param {Function|Number} [*value* = 1] @chainable */ }, { key: "scale", value: function scale(_) { return arguments.length ? (this._scale = typeof _ === "function" ? _ : constant(_), this) : this._scale; } /** @memberof Shape @desc If *selector* is specified, sets the SVG container element to the specified d3 selector or DOM element and returns the current class instance. If *selector* is not specified, returns the current SVG container element. @param {String|HTMLElement} [*selector* = d3.select("body").append("svg")] @chainable */ }, { key: "select", value: function select(_) { return arguments.length ? (this._select = _select(_), this) : this._select; } /** @memberof Shape @desc If *value* is specified, sets the shape-rendering accessor to the specified function or string and returns the current class instance. @param {Function|String} [*value* = "geometricPrecision"] @chainable @example function(d) { return d.x; } */ }, { key: "shapeRendering", value: function shapeRendering(_) { return arguments.length ? (this._shapeRendering = typeof _ === "function" ? _ : constant(_), this) : this._shapeRendering; } /** @memberof Shape @desc If *value* is specified, sets the sort comparator to the specified function and returns the current class instance. @param {false|Function} [*value* = []] @chainable */ }, { key: "sort", value: function sort(_) { return arguments.length ? (this._sort = _, this) : this._sort; } /** @memberof Shape @desc If *value* is specified, sets the stroke accessor to the specified function or string and returns the current class instance. @param {Function|String} [*value* = "black"] @chainable */ }, { key: "stroke", value: function stroke(_) { return arguments.length ? (this._stroke = typeof _ === "function" ? _ : constant(_), this) : this._stroke; } /** @memberof Shape @desc Defines the "stroke-dasharray" attribute for the shapes. @param {Function|String} [*value* = "1"] @chainable */ }, { key: "strokeDasharray", value: function strokeDasharray(_) { return arguments.length ? (this._strokeDasharray = typeof _ === "function" ? _ : constant(_), this) : this._strokeDasharray; } /** @memberof Shape @desc Defines the "stroke-linecap" attribute for the shapes. Accepted values are `"butt"`, `"round"`, and `"square"`. @param {Function|String} [*value* = "butt"] @chainable */ }, { key: "strokeLinecap", value: function strokeLinecap(_) { return arguments.length ? (this._strokeLinecap = typeof _ === "function" ? _ : constant(_), this) : this._strokeLinecap; } /** @memberof Shape @desc Defines the "stroke-opacity" attribute for the shapes. @param {Function|Number} [*value* = 1] @chainable */ }, { key: "strokeOpacity", value: function strokeOpacity(_) { return arguments.length ? (this._strokeOpacity = typeof _ === "function" ? _ : constant(_), this) : this._strokeOpacity; } /** @memberof Shape @desc If *value* is specified, sets the stroke-width accessor to the specified function or string and returns the current class instance. @param {Function|Number} [*value* = 0] @chainable */ }, { key: "strokeWidth", value: function strokeWidth(_) { return arguments.length ? (this._strokeWidth = typeof _ === "function" ? _ : constant(_), this) : this._strokeWidth; } /** @memberof Shape @desc If *value* is specified, sets the text-anchor accessor to the specified function or string and returns the current class instance. @param {Function|String|Array} [*value* = "start"] @chainable */ }, { key: "textAnchor", value: function textAnchor(_) { return arguments.length ? (this._textAnchor = typeof _ === "function" ? _ : constant(_), this) : this._textAnchor; } /** @memberof Shape @desc Defines the texture used inside of each shape. This uses the [textures.js](https://riccardoscalco.it/textures/) package, and expects either a simple string (`"lines"` or `"circles"`) or a more complex Object containing the various properties of the texture (ie. `{texture: "lines", orientation: "3/8", stroke: "darkorange"}`). If multiple textures are necessary, provide an accsesor Function that returns the correct String/Object for each given data point and index. @param {String|Object|Function} [*value*] @chainable */ }, { key: "texture", value: function texture(_) { return arguments.length ? (this._texture = typeof _ === "function" ? _ : constant(_), this) : this._texture; } /** @memberof Shape @desc A series of global texture methods to be used for all textures (ie. `{stroke: "darkorange", strokeWidth: 2}`). @param {Object} [*value*] @chainable */ }, { key: "textureDefault", value: function textureDefault(_) { return arguments.length ? (this._textureDefault = assign(this._textureDefault, _), this) : this._textureDefault; } /** @memberof Shape @desc If *value* is specified, sets the vector-effect accessor to the specified function or string and returns the current class instance. @param {Function|String} [*value* = "non-scaling-stroke"] @chainable */ }, { key: "vectorEffect", value: function vectorEffect(_) { return arguments.length ? (this._vectorEffect = typeof _ === "function" ? _ : constant(_), this) : this._vectorEffect; } /** @memberof Shape @desc If *value* is specified, sets the vertical alignment accessor to the specified function or string and returns the current class instance. @param {Function|String|Array} [*value* = "start"] @chainable */ }, { key: "verticalAlign", value: function verticalAlign(_) { return arguments.length ? (this._verticalAlign = typeof _ === "function" ? _ : constant(_), this) : this._verticalAlign; } /** @memberof Shape @desc If *value* is specified, sets the x accessor to the specified function or number and returns the current class instance. @param {Function|Number} [*value*] @chainable @example function(d) { return d.x; } */ }, { key: "x", value: function x(_) { return arguments.length ? (this._x = typeof _ === "function" ? _ : constant(_), this) : this._x; } /** @memberof Shape @desc If *value* is specified, sets the y accessor to the specified function or number and returns the current class instance. @param {Function|Number} [*value*] @chainable @example function(d) { return d.y; } */ }, { key: "y", value: function y(_) { return arguments.length ? (this._y = typeof _ === "function" ? _ : constant(_), this) : this._y; } }]); return Shape; }(BaseClass); export { Shape as default };