2021SC@SDUSC
坐标轴
公共文件
在直角坐标系以及极坐标系等坐标轴组件中,存在着多个公共文件。
AxisView
AxisView通过extendComponentView方法扩展自Component Model,重写了render、remove以及dispose方法,定义了updateAxisPointer方法。
AxisBuilder
AxisBuilder中定义了axisLine、axisTickLabel以及axisName的渲染方法,主要代码如下
var builders = {
axisLine: function () {
...
this.group.add(new graphic.Line(graphic.subPixelOptimizeLine({
// Id for animation
anid: 'line',
shape: {
x1: pt1[0],
y1: pt1[1],
x2: pt2[0],
y2: pt2[1]
},
style: lineStyle,
strokeContainThreshold: opt.strokeContainThreshold || 5,
silent: true,
z2: 1
})));
var arrows = axisModel.get('axisLine.symbol');
var arrowSize = axisModel.get('axisLine.symbolSize');
var arrowOffset = axisModel.get('axisLine.symbolOffset') || 0;
if (typeof arrowOffset === 'number') {
arrowOffset = [arrowOffset, arrowOffset];
}
if (arrows != null) {
...
each([{
rotate: opt.rotation + Math.PI / 2,
offset: arrowOffset[0],
r: 0
}, {
rotate: opt.rotation - Math.PI / 2,
offset: arrowOffset[1],
r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0])
+ (pt1[1] - pt2[1]) * (pt1[1] - pt2[1]))
}], function (point, index) {
// 创建arrow symbole
if (arrows[index] !== 'none' && arrows[index] != null) {
var symbol = createSymbol(
arrows[index],
-symbolWidth / 2,
-symbolHeight / 2,
symbolWidth,
symbolHeight,
lineStyle.stroke,
true
);
// Calculate arrow position with offset
var r = point.r + point.offset;
var pos = [
pt1[0] + r * Math.cos(opt.rotation),
pt1[1] - r * Math.sin(opt.rotation)
];
symbol.attr({
rotation: point.rotate,
position: pos,
silent: true,
z2: 11
});
this.group.add(symbol);
}
}, this);
}
},
axisTickLabel: function () {
var axisModel = this.axisModel;
var opt = this.opt;
// 通过graphic.Line以及graphic.Text分别对tick及label进行渲染
var tickEls = buildAxisTick(this, axisModel, opt);
var labelEls = buildAxisLabel(this, axisModel, opt);
fixMinMaxLabelShow(axisModel, labelEls, tickEls);
},
axisName: function () {
...
var textEl = new graphic.Text({
// Id for animation
anid: 'name',
__fullText: name,
__truncatedText: truncatedText,
position: pos,
rotation: labelLayout.rotation,
silent: isSilent(axisModel),
z2: 1,
tooltip: (tooltipOpt && tooltipOpt.show)
? extend({
content: name,
formatter: function () {
return name;
},
formatterParams: formatterParams
}, tooltipOpt)
: null
});
graphic.setTextStyle(textEl.style, textStyleModel, {
text: truncatedText,
textFont: textFont,
textFill: textStyleModel.getTextColor()
|| axisModel.get('axisLine.lineStyle.color'),
textAlign: labelLayout.textAlign,
textVerticalAlign: labelLayout.textVerticalAlign
});
...
// FIXME
this._dumbGroup.add(textEl);
textEl.updateTransform();
this.group.add(textEl);
textEl.decomposeTransform();
}
};
AxisModelCreator
AxisModelCreator为生成AxisModel的方法,其在AxisModel的基础上扩展了getCategories、getOrdinalMeta、mergeDefaultAndTheme等方法,重写了defaultOption属性,并通过:
ComponentModel.registerSubTypeDefaulter(
axisName + 'Axis',
zrUtil.curry(axisTypeDefaulter, axisName)
);
来注册相应的Axis子类,如xAxis、yAxis、radiusAxis以及angleAxis等。
直角坐标轴 Axis
Axis为直角坐标系Grid中的坐标轴,包括xAxis(x轴)以及yAxis(y轴)。
AxisModel
AxisModel通过extend方法扩展自Component Model,重写了init、mergeOption、,并使用AxisModelCreator分别创建额xAxisModel以及yAxisModel,
CartesianAxisView
CartesianAxisView通过extend方法扩展自AxisView,重写了render方法,定义了splitLine以及splitArea方法,并扩展了xAxis以及yAxis View。主要代码如下:
var CartesianAxisView = AxisView.extend({
type: 'cartesianAxis',
axisPointerClass: 'CartesianAxisPointer',
render: function (axisModel, ecModel, api, payload) {
...
// 结合AxisBuilder
var axisBuilder = new AxisBuilder(axisModel, layout);
zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder);
...
CartesianAxisView.superCall(this, 'render', axisModel, ecModel, api, payload);
},
...
_splitLine: function (axisModel, gridModel) {
...
// Simple optimization
// Batching the lines if color are the same
for (var i = 0; i < ticksCoords.length; i++) {
...
this._axisGroup.add(new graphic.Line(graphic.subPixelOptimizeLine({
anid: tickValue != null ? 'line_' + ticksCoords[i].tickValue : null,
shape: {
x1: p1[0],
y1: p1[1],
x2: p2[0],
y2: p2[1]
},
style: zrUtil.defaults({
stroke: lineColors[colorIndex]
}, lineStyle),
silent: true
})));
}
},
_splitArea: function (axisModel, gridModel) {
...
for (var i = 1; i < ticksCoords.length; i++) {
...
this._axisGroup.add(new graphic.Rect({
anid: tickValue != null ? 'area_' + tickValue : null,
shape: {
x: x,
y: y,
width: width,
height: height
},
style: zrUtil.defaults({
fill: areaColors[colorIndex]
}, areaStyle),
silent: true
}));
colorIndex = (colorIndex + 1) % areaColorsLen;
}
this._splitAreaColors = newSplitAreaColors;
}
});
CartesianAxisView.extend({
type: 'xAxis'
});
CartesianAxisView.extend({
type: 'yAxis'
});
极坐标轴 AngleAxis&RadiusAxis
公共文件
AxisModel
AxisModel通过extend方法扩展自Component Model,定义了getCoordSysModel方法,并根据不同option创建了angle和radius Model,主要代码如下:
axisModelCreator('angle', PolarAxisModel, getAxisType, polarAxisDefaultExtendedOption.angle);
axisModelCreator('radius', PolarAxisModel, getAxisType, polarAxisDefaultExtendedOption.radius);
角度轴 AngleAxis
AngleAxis为极坐标Polar中的角度轴,
AngleAxisView
AngleAxisView通过extend方法扩展自AxisView,重写了render方法,并定义了axisLine、axisTick、axisLabel、splitLine以及splitArea等方法,主要代码如下:
render: function (angleAxisModel, ecModel) {
...
var angleAxis = angleAxisModel.axis;
var polar = angleAxis.polar;
var radiusExtent = polar.getRadiusAxis().getExtent();
var ticksAngles = angleAxis.getTicksCoords();
var labels = zrUtil.map(angleAxis.getViewLabels(), function (labelItem) {
var labelItem = zrUtil.clone(labelItem);
labelItem.coord = angleAxis.dataToCoord(labelItem.tickValue);
return labelItem;
});
...
},
_axisLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
var lineStyleModel = angleAxisModel.getModel('axisLine.lineStyle');
var circle = new graphic.Circle({
shape: {
cx: polar.cx,
cy: polar.cy,
r: radiusExtent[getRadiusIdx(polar)]
},
style: lineStyleModel.getLineStyle(),
z2: 1,
silent: true
});
circle.style.fill = null;
this.group.add(circle);
},
_axisTick: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
var tickModel = angleAxisModel.getModel('axisTick');
var tickLen = (tickModel.get('inside') ? -1 : 1) * tickModel.get('length');
var radius = radiusExtent[getRadiusIdx(polar)];
var lines = zrUtil.map(ticksAngles, function (tickAngleItem) {
return new graphic.Line({
shape: getAxisLineShape(polar, [radius, radius + tickLen], tickAngleItem.coord)
});
});
this.group.add(graphic.mergePath(
lines, {
style: zrUtil.defaults(
tickModel.getModel('lineStyle').getLineStyle(),
{
stroke: angleAxisModel.get('axisLine.lineStyle.color')
}
)
}
));
},
_axisLabel: function (angleAxisModel, polar, ticksAngles, radiusExtent, labels) {
...
// Use length of ticksAngles because it may remove the last tick to avoid overlapping
zrUtil.each(labels, function (labelItem, idx) {
...
var textEl = new graphic.Text({silent: true});
this.group.add(textEl);
graphic.setTextStyle(textEl.style, labelModel, {
x: p[0],
y: p[1],
textFill: labelModel.getTextColor() || angleAxisModel.get('axisLine.lineStyle.color'),
text: labelItem.formattedLabel,
textAlign: labelTextAlign,
textVerticalAlign: labelTextVerticalAlign
});
}, this);
},
_splitLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
...
for (var i = 0; i < ticksAngles.length; i++) {
var colorIndex = (lineCount++) % lineColors.length;
splitLines[colorIndex] = splitLines[colorIndex] || [];
splitLines[colorIndex].push(new graphic.Line({
shape: getAxisLineShape(polar, radiusExtent, ticksAngles[i].coord)
}));
}
// Simple optimization
// Batching the lines if color are the same
for (var i = 0; i < splitLines.length; i++) {
this.group.add(graphic.mergePath(splitLines[i], {
style: zrUtil.defaults({
stroke: lineColors[i % lineColors.length]
}, lineStyleModel.getLineStyle()),
silent: true,
z: angleAxisModel.get('z')
}));
}
},
_splitArea: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
...
for (var i = 1; i < ticksAngles.length; i++) {
var colorIndex = (lineCount++) % areaColors.length;
splitAreas[colorIndex] = splitAreas[colorIndex] || [];
splitAreas[colorIndex].push(new graphic.Sector({
shape: {
cx: polar.cx,
cy: polar.cy,
r0: r0,
r: r1,
startAngle: prevAngle,
endAngle: -ticksAngles[i].coord * RADIAN,
clockwise: clockwise
},
silent: true
}));
prevAngle = -ticksAngles[i].coord * RADIAN;
}
// Simple optimization
// Batching the lines if color are the same
for (var i = 0; i < splitAreas.length; i++) {
this.group.add(graphic.mergePath(splitAreas[i], {
style: zrUtil.defaults({
fill: areaColors[i % areaColors.length]
}, areaStyleModel.getAreaStyle()),
silent: true
}));
}
}
半径轴 RadiusAxis
RadiusAxis为极坐标Polar中的半径轴。
RadiusAxisView
RadiusAxisView通过extend方法扩展自AxisView,重写了render方法,并定义了splitLine、splitArea方法,主要代码如下:
_splitLine: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {
...
for (var i = 0; i < ticksCoords.length; i++) {
var colorIndex = (lineCount++) % lineColors.length;
splitLines[colorIndex] = splitLines[colorIndex] || [];
splitLines[colorIndex].push(new graphic.Circle({
shape: {
cx: polar.cx,
cy: polar.cy,
r: ticksCoords[i].coord
},
silent: true
}));
}
// Simple optimization
// Batching the lines if color are the same
for (var i = 0; i < splitLines.length; i++) {
this.group.add(graphic.mergePath(splitLines[i], {
style: zrUtil.defaults({
stroke: lineColors[i % lineColors.length],
fill: null
}, lineStyleModel.getLineStyle()),
silent: true
}));
}
},
_splitArea: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {
...
for (var i = 1; i < ticksCoords.length; i++) {
var colorIndex = (lineCount++) % areaColors.length;
splitAreas[colorIndex] = splitAreas[colorIndex] || [];
splitAreas[colorIndex].push(new graphic.Sector({
shape: {
cx: polar.cx,
cy: polar.cy,
r0: prevRadius,
r: ticksCoords[i].coord,
startAngle: 0,
endAngle: Math.PI * 2
},
silent: true
}));
prevRadius = ticksCoords[i].coord;
}
// Simple optimization
// Batching the lines if color are the same
for (var i = 0; i < splitAreas.length; i++) {
this.group.add(graphic.mergePath(splitAreas[i], {
style: zrUtil.defaults({
fill: areaColors[i % areaColors.length]
}, areaStyleModel.getAreaStyle()),
silent: true
}));
}
}
