d3plus-shape
Version:
Fancy SVG shapes for visualizations
262 lines (249 loc) • 10.6 kB
JavaScript
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); }
import { select as _select } from "d3-selection";
import { transition } from "d3-transition";
import { accessor, constant } from "d3plus-common";
/**
@class Image
@desc Creates SVG images based on an array of data.
@example <caption>a sample row of data</caption>
var data = {"url": "file.png", "width": "100", "height": "50"};
@example <caption>passed to the generator</caption>
new Image().data([data]).render();
@example <caption>creates the following</caption>
<image class="d3plus-Image" opacity="1" href="file.png" width="100" height="50" x="0" y="0"></image>
@example <caption>this is shorthand for the following</caption>
image().data([data])();
@example <caption>which also allows a post-draw callback function</caption>
image().data([data])(function() { alert("draw complete!"); })
*/
var Image = /*#__PURE__*/function () {
/**
@memberof Image
@desc Invoked when creating a new class instance, and sets any default parameters.
@private
*/
function Image() {
_classCallCheck(this, Image);
this._duration = 600;
this._height = accessor("height");
this._id = accessor("id");
this._opacity = constant(1);
this._pointerEvents = constant("auto");
this._select;
this._url = accessor("url");
this._width = accessor("width");
this._x = accessor("x", 0);
this._y = accessor("y", 0);
}
/**
@memberof Image
@desc Renders the current Image to the page. If a *callback* is specified, it will be called once the images are done drawing.
@param {Function} [*callback*]
@chainable
*/
_createClass(Image, [{
key: "render",
value: function render(callback) {
var _this = 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());
var images = this._select.selectAll(".d3plus-Image").data(this._data, this._id);
var enter = images.enter().append("image").attr("class", "d3plus-Image").attr("opacity", 0).attr("width", 0).attr("height", 0).attr("x", function (d, i) {
return _this._x(d, i) + _this._width(d, i) / 2;
}).attr("y", function (d, i) {
return _this._y(d, i) + _this._height(d, i) / 2;
});
var t = transition().duration(this._duration),
that = this,
update = enter.merge(images);
update.attr("xlink:href", this._url).style("pointer-events", this._pointerEvents).transition(t).attr("opacity", this._opacity).attr("width", function (d, i) {
return _this._width(d, i);
}).attr("height", function (d, i) {
return _this._height(d, i);
}).attr("x", function (d, i) {
return _this._x(d, i);
}).attr("y", function (d, i) {
return _this._y(d, i);
}).each(function (d, i) {
var image = _select(this),
link = that._url(d, i);
var fullAddress = link.indexOf("http://") === 0 || link.indexOf("https://") === 0;
if (!fullAddress || link.indexOf(window.location.hostname) === 0) {
var img = new Image();
img.src = link;
img.crossOrigin = "Anonymous";
img.onload = function () {
var canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
var context = canvas.getContext("2d");
context.drawImage(this, 0, 0);
image.attr("xlink:href", canvas.toDataURL("image/png"));
};
}
});
images.exit().transition(t).attr("width", function (d, i) {
return _this._width(d, i);
}).attr("height", function (d, i) {
return _this._height(d, i);
}).attr("x", function (d, i) {
return _this._x(d, i);
}).attr("y", function (d, i) {
return _this._y(d, i);
}).attr("opacity", 0).remove();
if (callback) setTimeout(callback, this._duration + 100);
return this;
}
/**
@memberof Image
@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. An <image> tag 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 Image
@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 Image
@desc If *value* is specified, sets the height accessor to the specified function or number and returns the current class instance.
@param {Function|Number} [*value*]
@chainable
@example
function(d) {
return d.height;
}
*/
}, {
key: "height",
value: function height(_) {
return arguments.length ? (this._height = typeof _ === "function" ? _ : constant(_), this) : this._height;
}
/**
@memberof Image
@desc If *value* is specified, sets the id accessor to the specified function and returns the current class instance.
@param {Function} [*value*]
@chainable
@example
function(d) {
return d.id;
}
*/
}, {
key: "id",
value: function id(_) {
return arguments.length ? (this._id = _, this) : this._id;
}
/**
@memberof Image
@desc Sets the opacity of the image.
@param {Number} [*value* = 1]
@chainable
*/
}, {
key: "opacity",
value: function opacity(_) {
return arguments.length ? (this._opacity = typeof _ === "function" ? _ : constant(_), this) : this._opacity;
}
/**
@memberof Image
@desc If *value* is specified, sets the pointer-events accessor to the specified function or string and returns the current class instance.
@param {Function|String} [*value* = "auto"]
@chainable
*/
}, {
key: "pointerEvents",
value: function pointerEvents(_) {
return arguments.length ? (this._pointerEvents = typeof _ === "function" ? _ : constant(_), this) : this._pointerEvents;
}
/**
@memberof Image
@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 Image
@desc If *value* is specified, sets the URL accessor to the specified function and returns the current class instance.
@param {Function} [*value*]
@chainable
@example
function(d) {
return d.url;
}
*/
}, {
key: "url",
value: function url(_) {
return arguments.length ? (this._url = _, this) : this._url;
}
/**
@memberof Image
@desc If *value* is specified, sets the width accessor to the specified function or number and returns the current class instance.
@param {Function|Number} [*value*]
@chainable
@example
function(d) {
return d.width;
}
*/
}, {
key: "width",
value: function width(_) {
return arguments.length ? (this._width = typeof _ === "function" ? _ : constant(_), this) : this._width;
}
/**
@memberof Image
@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 || 0;
}
*/
}, {
key: "x",
value: function x(_) {
return arguments.length ? (this._x = typeof _ === "function" ? _ : constant(_), this) : this._x;
}
/**
@memberof Image
@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 || 0;
}
*/
}, {
key: "y",
value: function y(_) {
return arguments.length ? (this._y = typeof _ === "function" ? _ : constant(_), this) : this._y;
}
}]);
return Image;
}();
export { Image as default };