@antv/f2
Version:
Charts for mobile visualization.
281 lines • 9.08 kB
JavaScript
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
var _excluded = ["transformFrom"];
import { isArray, isBoolean, isUndefined, pick } from '@antv/util';
import Children from '../children';
import { compareRenderTree, renderJSXElement } from '../jsx';
import { render } from '../jsx/render';
import Component from './component';
import equal from './equal';
function pickElement(element) {
if (!element) return element;
return Children.map(element, function (item) {
if (!item) return item;
// 只需要这几个元素就可以了
return pick(item, ['key', 'ref', 'type', 'props']);
});
}
function renderShape(component, children, animate) {
var container = component.container,
context = component.context,
updater = component.updater,
__lastElement = component.__lastElement,
transformFrom = component.transformFrom,
componentAnimate = component.animate;
// 先清空绘制内容
container.clear();
animate = isBoolean(animate) ? animate : componentAnimate;
var px2hd = context.px2hd;
var lastElement = __lastElement || transformFrom && transformFrom.__lastElement;
// children 是 shape 的 jsx 结构, component.render() 返回的结构
var shapeElement = renderJSXElement(children, context, updater);
// @ts-ignore
component.__lastElement = shapeElement;
var renderElement = animate !== false ? compareRenderTree(shapeElement, lastElement) : shapeElement;
if (!renderElement) return null;
// 生成G的节点树, 存在数组的情况是根节点有变化,之前的树删除,新的树创建
if (isArray(renderElement)) {
return renderElement.map(function (element) {
return render(element, container, animate, px2hd);
});
} else {
return render(renderElement, container, animate, px2hd);
}
}
function setComponentAnimate(child, parent) {
var parentAnimate = parent.animate;
// 如果父组件不需要动画,子组件全不不执行动画
if (parentAnimate === false) {
child.animate = false;
return;
}
var childProps = child.props;
var childAnimate = childProps.animate;
child.animate = isBoolean(childAnimate) ? childAnimate : parentAnimate;
}
function getTransformComponent(component) {
if (!component) return null;
// @ts-ignore
var __lastElement = component.__lastElement,
children = component.children;
if (__lastElement) {
return component;
}
if (!children) {
return null;
}
var componentFromChildren = null;
Children.map(children, function (item) {
if (componentFromChildren) return;
if (!item) return;
var component = getTransformComponent(item.component);
if (component) {
componentFromChildren = component;
}
});
return componentFromChildren;
}
function getTransformFromComponentRef(transformFromRef) {
if (!transformFromRef || !transformFromRef.current) {
return null;
}
var transformFromComponent = transformFromRef.current;
return getTransformComponent(transformFromComponent);
}
function createComponent(parent, element) {
var type = element.type,
props = element.props,
ref = element.ref;
var container = parent.container,
context = parent.context,
updater = parent.updater,
transformFrom = parent.transformFrom;
var transformFromRef = props.transformFrom,
receiveProps = _objectWithoutProperties(props, _excluded);
var component;
// @ts-ignore
if (type.prototype && type.prototype.isF2Component) {
// @ts-ignore
component = new type(receiveProps, context, updater);
} else {
component = new Component(receiveProps, context, updater);
component.render = function () {
// @ts-ignore
return type(this.props, context, updater);
};
}
// 设置ref
if (ref) {
ref.current = component;
}
// 因为view 可能在子组件,所以这里要透传到子组件
if (transformFrom) {
// @ts-ignore
component.transformFrom = transformFrom;
}
if (transformFromRef) {
var transformFromComponent = transformFromRef ? getTransformFromComponentRef(transformFromRef) : null;
// @ts-ignore
component.transformFrom = transformFromComponent;
}
var zIndex = props.zIndex;
// 每个组件都新建一个独立容器
component.container = container.addGroup({
zIndex: zIndex
});
component.context = context;
component.updater = updater;
return component;
}
function renderComponent(component) {
Children.map(component, function (item) {
var lastChildren = item.children;
var mount = isUndefined(lastChildren);
if (mount) {
if (item.willMount) item.willMount();
} else if (item.willUpdate) {
item.willUpdate();
}
});
Children.map(component, function (item) {
var lastChildren = item.children;
var mount = isUndefined(lastChildren);
var newChildren = item.render();
renderChildren(item, newChildren, lastChildren);
if (mount) {
if (item.didMount) item.didMount();
} else if (item.didUpdate) {
item.didUpdate();
}
});
}
function destroyElement(elements) {
Children.map(elements, function (element) {
if (!element) return;
var component = element.component;
if (!component) {
return;
}
if (component.willUnmount) {
component.willUnmount();
}
destroyElement(component.children);
var container = component.container;
container.remove(true);
if (component.didUnmount) {
component.didUnmount();
}
component.destroy();
});
}
function diffElement(parent, nextElement, lastElement) {
if (!nextElement && !lastElement) {
return null;
}
// 删除
if (!nextElement && lastElement) {
destroyElement(lastElement);
return null;
}
// 新建
if (nextElement && !lastElement) {
return nextElement;
}
// diff
var nextType = nextElement.type,
nextProps = nextElement.props;
var lastType = lastElement.type,
lastProps = lastElement.props,
lastComponent = lastElement.component;
if (nextType !== lastType) {
destroyElement(lastElement);
return nextElement;
}
// 保留component, 等下一阶段处理
nextElement.component = lastComponent;
if (equal(nextProps, lastProps) && lastComponent.context === parent.context) {
return null;
}
return nextElement;
}
function diff(parent, nextChildren, lastChildren) {
// destroy
// 生命周期的几个阶段
// should create / update
// create / Receive props
// willMount / willUpdate
// render
// didMount / didUpdate
var childrenArray = [];
// 1. 第一轮比较, 直接destroy的元素处理掉,destroy 的元素不需要进入下一阶段
Children.compare(nextChildren, lastChildren, function (next, last) {
var element = diffElement(parent, next, last);
if (element) {
childrenArray = childrenArray.concat(Children.toArray(element).filter(Boolean));
}
});
// 2. 处理 shouldCreate 和 shouldUpdate
var shouldProcessChildren = childrenArray.filter(function (element) {
var component = element.component,
props = element.props;
// 说明是新增的元素,需要新建
if (!component) return true;
// 不需要更新
if (component.shouldUpdate && component.shouldUpdate(props) === false) {
return false;
}
return true;
});
// 3. 处理 create 和 Receive props
var shouldRenderComponent = shouldProcessChildren.map(function (element) {
var component = element.component;
if (!component) {
component = createComponent(parent, element);
} else {
var props = element.props;
if (component.willReceiveProps) {
component.willReceiveProps(props, parent.context);
}
var zIndex = props.zIndex;
component.container.set('zIndex', zIndex);
component.props = props;
component.context = parent.context;
}
element.component = component;
setComponentAnimate(component, parent);
return component;
});
// 4. 处理 render
renderComponent(shouldRenderComponent);
// 按子组件顺序渲染内容
childrenArray.forEach(function (element) {
var component = element.component;
var parentGroup = parent.container;
parentGroup.add(component.container);
});
return nextChildren;
}
function isContainer(children) {
if (!children) return false;
if (!isArray(children)) {
var type = children.type;
return typeof type === 'function';
}
for (var i = 0, len = children.length; i < len; i++) {
if (isContainer(children[i])) {
return true;
}
}
return false;
}
function renderChildren(parent, nextChildren, lastChildren) {
// react 生成的 element 是 not extensible 的,这里新建一个新对象,并把需要的内容pick 出来
nextChildren = pickElement(nextChildren);
parent.children = nextChildren;
if (isContainer(nextChildren)) {
nextChildren = diff(parent, nextChildren, lastChildren);
} else {
renderShape(parent, nextChildren);
}
return nextChildren;
}
export { renderChildren, diff, renderComponent, renderShape, destroyElement };