You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

379 lines
17 KiB

4 months ago
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Selection = void 0;
exports.select = select;
exports.maybeAppend = maybeAppend;
var tslib_1 = require("tslib");
var util_1 = require("@antv/util");
var shapes_1 = require("../shapes");
var group_1 = require("./group");
function error(msg) {
throw new Error(msg);
}
/**
* A simple implementation of d3-selection for @antv/g.
* It has the core features of d3-selection and extended ability.
* Every methods of selection returns new selection if elements
* are mutated(e.g. append, remove), otherwise return the selection itself(e.g. attr, style).
* @see https://github.com/d3/d3-selection
* @see https://github.com/antvis/g
* @todo Nested selections.
* @todo More useful functor.
*/
var Selection = /** @class */ (function () {
function Selection(elements, data, parent, document, selections, transitions, updateElements) {
if (elements === void 0) { elements = null; }
if (data === void 0) { data = null; }
if (parent === void 0) { parent = null; }
if (document === void 0) { document = null; }
if (selections === void 0) { selections = [null, null, null, null, null]; }
if (transitions === void 0) { transitions = []; }
if (updateElements === void 0) { updateElements = []; }
_Selection_instances.add(this);
this._elements = Array.from(elements);
this._data = data;
this._parent = parent;
this._document = document;
this._enter = selections[0];
this._update = selections[1];
this._exit = selections[2];
this._merge = selections[3];
this._split = selections[4];
this._transitions = transitions;
this._facetElements = updateElements;
}
Selection.prototype.selectAll = function (selector) {
var elements = typeof selector === 'string' ? this._parent.querySelectorAll(selector) : selector;
return new _a(elements, null, this._elements[0], this._document);
};
Selection.prototype.selectFacetAll = function (selector) {
var elements = typeof selector === 'string' ? this._parent.querySelectorAll(selector) : selector;
return new _a(this._elements, null, this._parent, this._document, undefined, undefined, elements);
};
/**
* @todo Replace with querySelector which has bug now.
*/
Selection.prototype.select = function (selector) {
var element = typeof selector === 'string' ? this._parent.querySelectorAll(selector)[0] || null : selector;
return new _a([element], null, element, this._document);
};
Selection.prototype.append = function (node) {
var _this = this;
var callback = typeof node === 'function' ? node : function () { return _this.createElement(node); };
var elements = [];
if (this._data !== null) {
// For empty selection, append new element to parent.
// Each element is bind with datum.
for (var i = 0; i < this._data.length; i++) {
var d = this._data[i];
var _b = tslib_1.__read(Array.isArray(d) ? d : [d, null], 2), datum = _b[0], from = _b[1];
var newElement = callback(datum, i);
newElement.__data__ = datum;
if (from !== null)
newElement.__fromElements__ = from;
this._parent.appendChild(newElement);
elements.push(newElement);
}
return new _a(elements, null, this._parent, this._document);
}
// For non-empty selection, append new element to
// selected element and return new selection.
for (var i = 0; i < this._elements.length; i++) {
var element = this._elements[i];
var datum = element.__data__;
var newElement = callback(datum, i);
element.appendChild(newElement);
elements.push(newElement);
}
return new _a(elements, null, elements[0], this._document);
};
Selection.prototype.maybeAppend = function (id, node) {
var element = tslib_1.__classPrivateFieldGet(this, _Selection_instances, "m", _Selection_maybeAppend).call(this, id[0] === '#' ? id : "#".concat(id), node);
element.attr('id', id);
return element;
};
Selection.prototype.maybeAppendByClassName = function (className, node) {
var cls = className.toString();
var element = tslib_1.__classPrivateFieldGet(this, _Selection_instances, "m", _Selection_maybeAppend).call(this, cls[0] === '.' ? cls : ".".concat(cls), node);
element.attr('className', cls);
return element;
};
Selection.prototype.maybeAppendByName = function (name, node) {
var element = tslib_1.__classPrivateFieldGet(this, _Selection_instances, "m", _Selection_maybeAppend).call(this, "[name=\"".concat(name, "\"]"), node);
element.attr('name', name);
return element;
};
/**
* Bind data to elements, and produce three selection:
* Enter: Selection with empty elements and data to be bind to elements.
* Update: Selection with elements to be updated.
* Exit: Selection with elements to be removed.
*/
Selection.prototype.data = function (data, id, groupId) {
var e_1, _b;
if (id === void 0) { id = function (d) { return d; }; }
if (groupId === void 0) { groupId = function () { return null; }; }
// An Array of new data.
var enter = [];
// An Array of elements to be updated.
var update = [];
// A Set of elements to be removed.
var exit = new Set(this._elements);
// An Array of data to be merged into one element.
var merge = [];
// A Set of elements to be split into multiple datum.
var split = new Set();
// A Map from key to each element.
var keyElement = new Map(this._elements.map(function (d, i) { return [id(d.__data__, i), d]; }));
// A Map from key to exist element. The Update Selection
// can get element from this map, this is for diff among
// facets.
var keyUpdateElement = new Map(this._facetElements.map(function (d, i) { return [id(d.__data__, i), d]; }));
// A Map from groupKey to a group of elements.
var groupKeyElements = (0, group_1.group)(this._elements, function (d) { return groupId(d.__data__); });
// Diff data with selection(elements with data).
// !!! Note
// The switch is strictly ordered, not not change the order of them.
for (var i = 0; i < data.length; i++) {
var datum = data[i];
var key = id(datum, i);
var groupKey = groupId(datum, i);
// Append element to update selection if incoming data has
// exactly the same key with elements.
if (keyElement.has(key)) {
var element = keyElement.get(key);
element.__data__ = datum;
element.__facet__ = false;
update.push(element);
exit.delete(element);
keyElement.delete(key);
// Append element to update selection if incoming data has
// exactly the same key with updateElements.
}
else if (keyUpdateElement.has(key)) {
var element = keyUpdateElement.get(key);
element.__data__ = datum;
// Flag this element should update its parentNode.
element.__facet__ = true;
update.push(element);
keyUpdateElement.delete(key);
// Append datum to merge selection if existed elements has
// its key as groupKey.
}
else if (groupKeyElements.has(key)) {
var group_3 = groupKeyElements.get(key);
merge.push([datum, group_3]);
try {
for (var group_2 = (e_1 = void 0, tslib_1.__values(group_3)), group_2_1 = group_2.next(); !group_2_1.done; group_2_1 = group_2.next()) {
var element = group_2_1.value;
exit.delete(element);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (group_2_1 && !group_2_1.done && (_b = group_2.return)) _b.call(group_2);
}
finally { if (e_1) throw e_1.error; }
}
groupKeyElements.delete(key);
// Append element to split selection if incoming data has
// groupKey as its key, and bind to datum for it.
}
else if (keyElement.has(groupKey)) {
var element = keyElement.get(groupKey);
if (element.__toData__)
element.__toData__.push(datum);
else
element.__toData__ = [datum];
split.add(element);
exit.delete(element);
}
else {
enter.push(datum);
}
}
// Create new selection with enter, update and exit.
var S = [
new _a([], enter, this._parent, this._document),
new _a(update, null, this._parent, this._document),
new _a(exit, null, this._parent, this._document),
new _a([], merge, this._parent, this._document),
new _a(split, null, this._parent, this._document),
];
return new _a(this._elements, null, this._parent, this._document, S);
};
Selection.prototype.merge = function (other) {
var elements = tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(this._elements), false), tslib_1.__read(other._elements), false);
var transitions = tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(this._transitions), false), tslib_1.__read(other._transitions), false);
return new _a(elements, null, this._parent, this._document, undefined, transitions);
};
Selection.prototype.createElement = function (type) {
if (this._document) {
return this._document.createElement(type, {});
}
var Ctor = _a.registry[type];
if (Ctor)
return new Ctor();
return error("Unknown node type: ".concat(type));
};
/**
* Apply callback for each selection(enter, update, exit)
* and merge them into one selection.
*/
Selection.prototype.join = function (enter, update, exit, merge, split) {
if (enter === void 0) { enter = function (d) { return d; }; }
if (update === void 0) { update = function (d) { return d; }; }
if (exit === void 0) { exit = function (d) { return d.remove(); }; }
if (merge === void 0) { merge = function (d) { return d; }; }
if (split === void 0) { split = function (d) { return d.remove(); }; }
var newEnter = enter(this._enter);
var newUpdate = update(this._update);
var newExit = exit(this._exit);
var newMerge = merge(this._merge);
var newSplit = split(this._split);
return newUpdate.merge(newEnter).merge(newExit).merge(newMerge).merge(newSplit);
};
Selection.prototype.remove = function () {
var _loop_1 = function (i) {
var element = this_1._elements[i];
var transition = this_1._transitions[i];
if (transition) {
transition.then(function () { return element.remove(); });
}
else {
element.remove();
}
};
var this_1 = this;
// Remove node immediately if there is no transition,
// otherwise wait until transition finished.
for (var i = 0; i < this._elements.length; i++) {
_loop_1(i);
}
return new _a([], null, this._parent, this._document, undefined, this._transitions);
};
Selection.prototype.each = function (callback) {
for (var i = 0; i < this._elements.length; i++) {
var element = this._elements[i];
var datum = element.__data__;
callback.call(element, datum, i);
}
return this;
};
Selection.prototype.attr = function (key, value) {
var callback = typeof value !== 'function' ? function () { return value; } : value;
return this.each(function (d, i) {
if (value !== undefined)
this[key] = callback.call(this, d, i);
});
};
Selection.prototype.style = function (key, value, callable) {
if (callable === void 0) { callable = true; }
var callback = typeof value !== 'function' || !callable ? function () { return value; } : value;
return this.each(function (d, i) {
if (value !== undefined)
this.style[key] = callback.call(this, d, i);
});
};
Selection.prototype.styles = function (style, callable) {
if (style === void 0) { style = {}; }
if (callable === void 0) { callable = true; }
return this.each(function (d, i) {
var _this = this;
Object.entries(style).forEach(function (_b) {
var _c = tslib_1.__read(_b, 2), key = _c[0], value = _c[1];
var callback = typeof value !== 'function' || !callable ? function () { return value; } : value;
if (value !== undefined)
_this.attr(key, callback.call(_this, d, i));
});
});
};
Selection.prototype.update = function (option, callable) {
if (callable === void 0) { callable = true; }
var callback = typeof option !== 'function' || !callable ? function () { return option; } : option;
return this.each(function (d, i) {
if (option && this.update)
this.update(callback.call(this, d, i));
});
};
/** if current stage is maybeAppend, skip update stage */
Selection.prototype.maybeUpdate = function (option, callable) {
if (callable === void 0) { callable = true; }
var callback = typeof option !== 'function' || !callable ? function () { return option; } : option;
return this.each(function (d, i) {
if (option && this.update)
this.update(callback.call(this, d, i));
});
};
Selection.prototype.transition = function (callback) {
var T = this._transitions;
var newTransitions = new Array(this._elements.length);
this.each(function (d, i) {
newTransitions[i] = callback.call(this, d, i);
});
this._transitions = (0, util_1.flatten)(newTransitions);
return this;
};
Selection.prototype.on = function (event, handler) {
this.each(function () {
this.addEventListener(event, handler);
});
return this;
};
Selection.prototype.call = function (callback) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
callback.call.apply(callback, tslib_1.__spreadArray([this._parent, this], tslib_1.__read(args), false));
return this;
};
Selection.prototype.node = function () {
return this._elements[0];
};
Selection.prototype.nodes = function () {
return this._elements;
};
Selection.prototype.transitions = function () {
return this._transitions.filter(function (t) { return !!t; });
};
Selection.prototype.parent = function () {
return this._parent;
};
var _Selection_instances, _a, _Selection_maybeAppend;
_a = Selection, _Selection_instances = new WeakSet(), _Selection_maybeAppend = function _Selection_maybeAppend(selector, node) {
var element = this._elements[0];
var child = element.querySelector(selector);
if (child)
return new _a([child], null, this._parent, this._document);
var newChild = typeof node === 'string' ? this.createElement(node) : node();
element.appendChild(newChild);
return new _a([newChild], null, this._parent, this._document);
};
Selection.registry = {
g: shapes_1.Group,
rect: shapes_1.Rect,
circle: shapes_1.Circle,
path: shapes_1.Path,
text: shapes_1.Text,
ellipse: shapes_1.Ellipse,
image: shapes_1.Image,
line: shapes_1.Line,
polygon: shapes_1.Polygon,
polyline: shapes_1.Polyline,
html: shapes_1.HTML,
};
return Selection;
}());
exports.Selection = Selection;
function select(node) {
return new Selection([node], null, node, node.ownerDocument);
}
function maybeAppend(parent, selector, node) {
if (!parent.querySelector(selector)) {
return select(parent).append(node);
}
return select(parent).select(selector);
}
//# sourceMappingURL=selection.js.map