@antv/f2
Version:
Charts for mobile visualization.
149 lines • 4.78 kB
JavaScript
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import { extendMap, px2hd as defaultPx2hd } from '../util';
import { isFunction, omit } from '@antv/util';
import computeLayout from './css-layout';
import getShapeAttrs from './shape';
import getAnimation from './animation';
import { ELEMENT_DELETE } from './elementStatus';
import createClipElement from './createClipElement';
// 转换成布局所需要的布局树
function createNodeTree(element, container, px2hd) {
var key = element.key,
ref = element.ref,
_cache = element._cache,
type = element.type,
props = element.props,
status = element.status,
animation = element.animation;
var children = extendMap(props.children, function (child) {
return createNodeTree(child, container, px2hd);
});
// const { style, attrs } = props;
var style = px2hd(props.style);
var attrs = px2hd(props.attrs);
// 文本要自动计算文本的宽高, TODO, 后面再优化
if (type === 'text') {
var shape = container.addShape(type, {
attrs: _objectSpread({
x: 0,
y: 0
}, attrs)
});
var _shape$getBBox = shape.getBBox(),
width = _shape$getBBox.width,
height = _shape$getBBox.height;
style = _objectSpread({
width: width,
height: height
}, style);
// 无用,销毁掉
shape.remove(true);
}
return {
key: key,
ref: ref,
_cache: _cache,
type: type,
props: props,
children: children,
status: status,
animation: animation,
// 处理px2hd之后的配置
style: style,
attrs: attrs
};
}
function mergeLayout(parent, layout) {
if (!parent || !layout) return layout;
var parentLeft = parent.left,
parentTop = parent.top;
var left = layout.left,
top = layout.top;
return _objectSpread(_objectSpread({}, layout), {}, {
left: parentLeft + left,
top: parentTop + top
});
}
function createElement(node, container, parentLayout, animate) {
var _node$_cache = node._cache,
_cache = _node$_cache === void 0 ? {} : _node$_cache,
ref = node.ref,
type = node.type,
props = node.props,
attrs = node.attrs,
originLayout = node.layout,
renderChildren = node.renderChildren,
nodeChildren = node.children,
status = node.status,
animation = node.animation;
var layout = mergeLayout(parentLayout, originLayout);
// 该元素上一次的attrs
var lastAttrs = _cache.attrs;
var elementAttrs = _objectSpread(_objectSpread(_objectSpread({}, getShapeAttrs(type, layout)), status === ELEMENT_DELETE ? lastAttrs : null), attrs);
// 缓存这次新的attrs
_cache.attrs = elementAttrs;
if (elementAttrs.clip) {
var clip = elementAttrs.clip;
var clipConfig = isFunction(clip) ? clip(elementAttrs) : clip;
elementAttrs.clip = createClipElement(clipConfig.type, clipConfig);
}
var element;
if (type === 'group') {
element = container.addGroup(_objectSpread(_objectSpread({}, omit(props, ['children'])), {}, {
status: status,
attrs: elementAttrs
}));
// 如果元素被删除了,就不会有renderChildren, 直接拿node.children渲染
var children = renderChildren ? renderChildren : nodeChildren;
// 只有group才需要处理children
if (children && children.length) {
for (var i = 0, len = children.length; i < len; i++) {
createElement(children[i], element, layout, animate);
}
}
} else {
element = container.addShape(type, _objectSpread(_objectSpread({}, props), {}, {
status: status,
attrs: elementAttrs
}));
}
if (animate !== false) {
element.set('animation', getAnimation(element, animation, elementAttrs, lastAttrs));
}
if (ref) {
ref.current = element;
}
return element;
}
// 过滤删除的元素,让其不参与布局计算
function filterDeleteElement(node) {
var status = node.status,
children = node.children;
if (status === ELEMENT_DELETE) {
return null;
}
if (!children || !children.length) {
return node;
}
var newChildren = children.filter(function (child) {
return !!filterDeleteElement(child);
});
// 要保留引用
node.children = newChildren;
node.renderChildren = children;
return node;
}
function render(element, container, animate) {
var px2hd = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : defaultPx2hd;
if (!element) {
return;
}
var nodeTree = createNodeTree(element, container, px2hd);
var computeLayoutTree = filterDeleteElement(nodeTree);
computeLayout(computeLayoutTree);
return createElement(nodeTree, container, null, animate);
}
export { render };
export default (function (element, container, animate) {
return render(element, container, animate);
});