in src/chart/line/LineView.ts [276:376]
function getVisualGradient(
data: SeriesData,
coordSys: Cartesian2D | Polar,
api: ExtensionAPI
) {
const visualMetaList = data.getVisual('visualMeta');
if (!visualMetaList || !visualMetaList.length || !data.count()) {
// When data.count() is 0, gradient range can not be calculated.
return;
}
if (coordSys.type !== 'cartesian2d') {
if (__DEV__) {
console.warn('Visual map on line style is only supported on cartesian2d.');
}
return;
}
let coordDim: 'x' | 'y';
let visualMeta;
for (let i = visualMetaList.length - 1; i >= 0; i--) {
const dimInfo = data.getDimensionInfo(visualMetaList[i].dimension);
coordDim = (dimInfo && dimInfo.coordDim) as 'x' | 'y';
// Can only be x or y
if (coordDim === 'x' || coordDim === 'y') {
visualMeta = visualMetaList[i];
break;
}
}
if (!visualMeta) {
if (__DEV__) {
console.warn('Visual map on line style only support x or y dimension.');
}
return;
}
// If the area to be rendered is bigger than area defined by LinearGradient,
// the canvas spec prescribes that the color of the first stop and the last
// stop should be used. But if two stops are added at offset 0, in effect
// browsers use the color of the second stop to render area outside
// LinearGradient. So we can only infinitesimally extend area defined in
// LinearGradient to render `outerColors`.
const axis = coordSys.getAxis(coordDim);
// dataToCoord mapping may not be linear, but must be monotonic.
const colorStops: ColorStop[] = zrUtil.map(visualMeta.stops, function (stop) {
// offset will be calculated later.
return {
coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)),
color: stop.color
} as ColorStop;
});
const stopLen = colorStops.length;
const outerColors = visualMeta.outerColors.slice();
if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) {
colorStops.reverse();
outerColors.reverse();
}
const colorStopsInRange = clipColorStops(
colorStops, coordDim === 'x' ? api.getWidth() : api.getHeight()
);
const inRangeStopLen = colorStopsInRange.length;
if (!inRangeStopLen && stopLen) {
// All stops are out of range. All will be the same color.
return colorStops[0].coord < 0
? (outerColors[1] ? outerColors[1] : colorStops[stopLen - 1].color)
: (outerColors[0] ? outerColors[0] : colorStops[0].color);
}
const tinyExtent = 10; // Arbitrary value: 10px
const minCoord = colorStopsInRange[0].coord - tinyExtent;
const maxCoord = colorStopsInRange[inRangeStopLen - 1].coord + tinyExtent;
const coordSpan = maxCoord - minCoord;
if (coordSpan < 1e-3) {
return 'transparent';
}
zrUtil.each(colorStopsInRange, function (stop) {
stop.offset = (stop.coord - minCoord) / coordSpan;
});
colorStopsInRange.push({
// NOTE: inRangeStopLen may still be 0 if stoplen is zero.
offset: inRangeStopLen ? colorStopsInRange[inRangeStopLen - 1].offset : 0.5,
color: outerColors[1] || 'transparent'
});
colorStopsInRange.unshift({ // notice newColorStops.length have been changed.
offset: inRangeStopLen ? colorStopsInRange[0].offset : 0.5,
color: outerColors[0] || 'transparent'
});
const gradient = new graphic.LinearGradient(0, 0, 0, 0, colorStopsInRange, true);
gradient[coordDim] = minCoord;
gradient[coordDim + '2' as 'x2' | 'y2'] = maxCoord;
return gradient;
}