@antv/f2
Version:
Charts for mobile visualization.
319 lines • 9.94 kB
JavaScript
import { __assign, __extends } from "tslib";
import { isEqual, Component, Children, jsx, createRef } from '@antv/f-engine';
import { each, findIndex, isArray, deepMix } from '@antv/util';
import CoordController from '../controller/coord';
import ScaleController from '../controller/scale';
import Theme from '../theme';
// 统计图表
var Chart = /** @class */function (_super) {
__extends(Chart, _super);
function Chart(props, context) {
var _this = _super.call(this, props) || this;
// 坐标系
_this.componentsPosition = [];
var theme = context.theme,
px2hd = context.px2hd;
// hack 处理,设置默认的主题样式
// 目前没想到其他更合适的方式,只能先这样处理
context.theme = deepMix(px2hd(Theme), theme);
var data = props.data;
_this.scale = new ScaleController(data);
_this.coord = new CoordController();
_this.coordRef = createRef();
// state
_this.state = {
filters: {}
};
return _this;
}
Chart.prototype.getStyle = function (props) {
var _a = this,
context = _a.context,
layout = _a.layout;
var theme = context.theme,
px2hd = context.px2hd;
var left = layout.left,
top = layout.top,
width = layout.width,
height = layout.height;
var customStyle = props.style;
return px2hd(__assign(__assign({
left: left,
top: top,
width: width,
height: height
}, theme.chart), customStyle));
};
Chart.prototype.willMount = function () {
var _a = this,
props = _a.props,
coord = _a.coord,
scale = _a.scale;
var scaleOptions = props.scale,
coordOption = props.coord;
this.resetCoordLayout();
// 初始化 scale
scale.create(scaleOptions);
// 初始化 coord
coord.create(coordOption);
};
// props 更新
Chart.prototype.willReceiveProps = function (nextProps, context) {
var _a = this,
scale = _a.scale,
coord = _a.coord,
lastProps = _a.props;
var nextStyle = nextProps.style,
nextData = nextProps.data,
nextScale = nextProps.scale;
var lastStyle = lastProps.style,
lastData = lastProps.data,
lastScale = lastProps.scale;
// style 更新
if (!isEqual(nextStyle, lastStyle) || context !== this.context) {
var style = this.getStyle(nextProps);
coord.updateLayout(style);
}
if (nextData !== lastData) {
scale.changeData(nextData);
}
// scale
if (!isEqual(nextScale, lastScale)) {
scale.update(nextScale);
}
};
Chart.prototype.willUpdate = function () {
this.coord.create(this.props.coord);
};
Chart.prototype.on = function (eventName, listener) {
var roolEl = this.coordRef.current;
if (!roolEl || !roolEl.gesture) return;
var gesture = roolEl.gesture;
gesture.on(eventName, listener);
};
Chart.prototype.off = function (eventName, listener) {
var roolEl = this.coordRef.current;
if (!roolEl || !roolEl.gesture) return;
var gesture = roolEl.gesture;
gesture.off(eventName, listener);
};
// 给需要显示的组件留空
Chart.prototype.layoutCoord = function (layout) {
this.coord.useLayout(layout);
};
Chart.prototype.resetCoordLayout = function () {
var _a = this,
coord = _a.coord,
props = _a.props;
var style = this.getStyle(props);
coord.updateLayout(style);
};
Chart.prototype.updateAdjust = function (adjust) {
this.adjust = adjust;
};
Chart.prototype.updateCoordLayout = function (layout) {
var _this = this;
if (isArray(layout)) {
layout.forEach(function (item) {
_this.layoutCoord(item);
});
return;
}
this.layoutCoord(layout);
};
Chart.prototype.updateCoordFor = function (component, layout) {
var _this = this;
if (!layout) return;
var componentsPosition = this.componentsPosition;
var componentPosition = {
component: component,
layout: layout
};
var existIndex = findIndex(componentsPosition, function (item) {
return item.component === component;
});
// 说明是已经存在的组件
if (existIndex > -1) {
componentsPosition.splice(existIndex, 1, componentPosition);
// 先重置,然后整体重新算一次
this.resetCoordLayout();
// 再整体计算前,需要去掉已经销毁的组件
this.removeComponentsPositionCache();
componentsPosition.forEach(function (componentPosition) {
var layout = componentPosition.layout;
_this.updateCoordLayout(layout);
});
return;
}
// 是新组件,直接添加
componentsPosition.push(componentPosition);
this.updateCoordLayout(layout);
};
Chart.prototype.removeComponentsPositionCache = function () {
var _a;
if (!((_a = this.componentsPosition) === null || _a === void 0 ? void 0 : _a.length)) return;
for (var i = this.componentsPosition.length; i > -1; i--) {
var item = this.componentsPosition[i];
if (item && item.component && item.component.destroyed) {
this.componentsPosition.splice(i, 1);
}
}
};
Chart.prototype.getGeometrys = function () {
// @ts-ignore
var children = this.children.children;
var geometrys = [];
Children.toArray(children).forEach(function (element) {
if (!element) return false;
var component = element.component;
// @ts-ignore
if (component && component.isGeometry) {
geometrys.push(component);
}
});
return geometrys;
};
/**
* calculate dataset's position on canvas
* @param {Object} record the dataset
* @return {Object} return the position
*/
Chart.prototype.getPosition = function (record) {
var coord = this.getCoord();
var xScale = this.getXScales()[0];
var xField = xScale.field;
var yScales = this.getYScales();
// default first
var yScale = yScales[0];
var yField = yScale.field;
for (var i = 0, len = yScales.length; i < len; i++) {
var scale = yScales[i];
var field = scale.field;
if (record[field]) {
yScale = scale;
yField = field;
break;
}
}
var x = xScale.scale(record[xField]);
var y = yScale.scale(record[yField]);
return coord.convertPoint({
x: x,
y: y
});
};
Chart.prototype.getSnapRecords = function (point, inCoordRange) {
var geometrys = this.getGeometrys();
if (!geometrys.length) return;
// @ts-ignore
return geometrys[0].getSnapRecords(point, inCoordRange);
};
Chart.prototype.getRecords = function (data, field) {
var geometrys = this.getGeometrys();
if (!geometrys.length) return;
// @ts-ignore
return geometrys[0].getRecords(data, field);
};
Chart.prototype.getLegendItems = function (point) {
var geometrys = this.getGeometrys();
if (!geometrys.length) return;
// @ts-ignore
return geometrys[0].getLegendItems(point);
};
Chart.prototype.setScale = function (field, option) {
this.scale.setScale(field, option);
};
Chart.prototype.getScale = function (field) {
return this.scale.getScale(field);
};
Chart.prototype.getScales = function () {
return this.scale.getScales();
};
Chart.prototype.getXScales = function () {
var geometrys = this.getGeometrys();
return geometrys.map(function (component) {
// @ts-ignore
return component.getXScale();
});
};
Chart.prototype.getYScales = function () {
var geometrys = this.getGeometrys();
return geometrys.map(function (component) {
// @ts-ignore
return component.getYScale();
});
};
Chart.prototype.getColorScales = function () {
var geometrys = this.getGeometrys();
return geometrys.map(function (component) {
// @ts-ignore
return component.getColorScale();
});
};
Chart.prototype.getLayout = function () {
return this.coord.layout;
};
Chart.prototype.getCoord = function () {
return this.coord.coord;
};
Chart.prototype.filter = function (field, condition) {
var _a;
var filters = this.state.filters;
this.setState({
filters: __assign(__assign({}, filters), (_a = {}, _a[field] = condition, _a))
});
};
Chart.prototype._getRenderData = function () {
var _a = this,
props = _a.props,
state = _a.state;
var data = props.data;
var filters = state.filters;
if (!filters || !Object.keys(filters).length) {
return data;
}
var filteredData = data;
each(filters, function (condition, field) {
if (!condition) return;
filteredData = filteredData.filter(function (record) {
return condition(record[field], record);
});
});
return filteredData;
};
Chart.prototype.render = function () {
var _this = this;
var _a = this,
props = _a.props,
scale = _a.scale,
chartLayout = _a.layout;
var children = props.children,
originData = props.data;
if (!originData) return null;
var data = this._getRenderData();
var layout = this.getLayout();
var coord = this.getCoord();
var scaleOptions = scale.getOptions();
var width = chartLayout.width,
height = chartLayout.height;
return jsx("group", {
ref: this.coordRef,
style: {
width: width,
height: height,
fill: 'transparent'
}
}, Children.map(children, function (child) {
return Children.cloneElement(child, {
data: data,
chart: _this,
layout: layout,
coord: coord,
// 传 scaleOptions 是为了让 child 感知到 props 的的变化,合理的做法的应该是传递 scale,但是现在无法感知到 scale 的变化, 所以暂时只能先这么处理,scaleOptions 子组件目前是使用不到的。
scaleOptions: scaleOptions
});
}));
};
return Chart;
}(Component);
export default Chart;