提交 49bbc701 编写于 作者: P pissang

feat(decal): provide pattern with svg element if renderer is svg.

上级 a951d441
...@@ -30,6 +30,7 @@ import Model from '../../model/Model'; ...@@ -30,6 +30,7 @@ import Model from '../../model/Model';
import { getECData } from '../../util/innerStore'; import { getECData } from '../../util/innerStore';
import { getSectorCornerRadius } from '../helper/pieHelper'; import { getSectorCornerRadius } from '../helper/pieHelper';
import {createOrUpdatePatternFromDecal} from '../../util/decal'; import {createOrUpdatePatternFromDecal} from '../../util/decal';
import ExtensionAPI from '../../ExtensionAPI';
const DEFAULT_SECTOR_Z = 2; const DEFAULT_SECTOR_Z = 2;
const DEFAULT_TEXT_Z = 4; const DEFAULT_TEXT_Z = 4;
...@@ -46,7 +47,7 @@ class SunburstPiece extends graphic.Sector { ...@@ -46,7 +47,7 @@ class SunburstPiece extends graphic.Sector {
private _seriesModel: SunburstSeriesModel; private _seriesModel: SunburstSeriesModel;
private _ecModel: GlobalModel; private _ecModel: GlobalModel;
constructor(node: TreeNode, seriesModel: SunburstSeriesModel, ecModel: GlobalModel) { constructor(node: TreeNode, seriesModel: SunburstSeriesModel, ecModel: GlobalModel, api: ExtensionAPI) {
super(); super();
this.z2 = DEFAULT_SECTOR_Z; this.z2 = DEFAULT_SECTOR_Z;
...@@ -62,15 +63,16 @@ class SunburstPiece extends graphic.Sector { ...@@ -62,15 +63,16 @@ class SunburstPiece extends graphic.Sector {
}); });
this.setTextContent(text); this.setTextContent(text);
this.updateData(true, node, seriesModel, ecModel); this.updateData(true, node, seriesModel, ecModel, api);
} }
updateData( updateData(
firstCreate: boolean, firstCreate: boolean,
node: TreeNode, node: TreeNode,
// state: 'emphasis' | 'normal' | 'highlight' | 'downplay', // state: 'emphasis' | 'normal' | 'highlight' | 'downplay',
seriesModel?: SunburstSeriesModel, seriesModel: SunburstSeriesModel,
ecModel?: GlobalModel ecModel: GlobalModel,
api: ExtensionAPI
) { ) {
this.node = node; this.node = node;
(node as DrawTreeNode).piece = this; (node as DrawTreeNode).piece = this;
...@@ -93,7 +95,7 @@ class SunburstPiece extends graphic.Sector { ...@@ -93,7 +95,7 @@ class SunburstPiece extends graphic.Sector {
const decal = node.getVisual('decal'); const decal = node.getVisual('decal');
if (decal) { if (decal) {
normalStyle.decal = createOrUpdatePatternFromDecal(decal, 2); normalStyle.decal = createOrUpdatePatternFromDecal(decal, api);
} }
const cornerRadius = getSectorCornerRadius(itemModel.getModel('itemStyle'), sectorShape); const cornerRadius = getSectorCornerRadius(itemModel.getModel('itemStyle'), sectorShape);
......
...@@ -116,7 +116,8 @@ class SunburstView extends ChartView { ...@@ -116,7 +116,8 @@ class SunburstView extends ChartView {
if (newNode) { if (newNode) {
// Update // Update
oldNode.piece.updateData( oldNode.piece.updateData(
false, newNode, seriesModel, ecModel); false, newNode, seriesModel, ecModel, api
);
// For tooltip // For tooltip
data.setItemGraphicEl(newNode.dataIndex, oldNode.piece); data.setItemGraphicEl(newNode.dataIndex, oldNode.piece);
...@@ -131,7 +132,8 @@ class SunburstView extends ChartView { ...@@ -131,7 +132,8 @@ class SunburstView extends ChartView {
const piece = new SunburstPiece( const piece = new SunburstPiece(
newNode, newNode,
seriesModel, seriesModel,
ecModel ecModel,
api
); );
group.add(piece); group.add(piece);
...@@ -158,14 +160,16 @@ class SunburstView extends ChartView { ...@@ -158,14 +160,16 @@ class SunburstView extends ChartView {
if (self.virtualPiece) { if (self.virtualPiece) {
// Update // Update
self.virtualPiece.updateData( self.virtualPiece.updateData(
false, virtualRoot, seriesModel, ecModel); false, virtualRoot, seriesModel, ecModel, api
);
} }
else { else {
// Add // Add
self.virtualPiece = new SunburstPiece( self.virtualPiece = new SunburstPiece(
virtualRoot, virtualRoot,
seriesModel, seriesModel,
ecModel ecModel,
api
); );
group.add(self.virtualPiece); group.add(self.virtualPiece);
} }
......
import WeakMap from 'zrender/src/core/WeakMap'; import WeakMap from 'zrender/src/core/WeakMap';
import {DecalObject, DecalDashArrayX, DecalDashArrayY} from 'zrender/src/graphic/Decal'; import {DecalObject, DecalDashArrayX, DecalDashArrayY} from 'zrender/src/graphic/Decal';
import Pattern from 'zrender/src/graphic/Pattern'; import { PatternObject } from 'zrender/src/graphic/Pattern';
import LRU from 'zrender/src/core/LRU'; import LRU from 'zrender/src/core/LRU';
import {brushSingle} from 'zrender/src/canvas/graphic';
import {defaults, createCanvas, map, isArray} from 'zrender/src/core/util'; import {defaults, createCanvas, map, isArray} from 'zrender/src/core/util';
import {getLeastCommonMultiple} from './number'; import {getLeastCommonMultiple} from './number';
import {createSymbol} from './symbol'; import {createSymbol} from './symbol';
import {util} from 'zrender/src/export'; import {util} from 'zrender/src/export';
import ExtensionAPI from '../ExtensionAPI';
import type SVGPainter from 'zrender/src/svg/Painter';
import type CanvasPainter from 'zrender/src/canvas/Painter';
const decalMap = new WeakMap<DecalObject, Pattern>(); const decalMap = new WeakMap<DecalObject, PatternObject>();
const decalCache = new LRU<HTMLCanvasElement>(100); const decalCache = new LRU<HTMLCanvasElement | SVGElement>(100);
const decalKeys = [ const decalKeys = [
'symbol', 'symbolSize', 'symbolKeepAspect', 'symbol', 'symbolSize', 'symbolKeepAspect',
...@@ -27,9 +29,11 @@ const decalKeys = [ ...@@ -27,9 +29,11 @@ const decalKeys = [
*/ */
export function createOrUpdatePatternFromDecal( export function createOrUpdatePatternFromDecal(
decalObject: DecalObject, decalObject: DecalObject,
dpr: number api: ExtensionAPI
): Pattern { ): PatternObject {
dpr = dpr || 1; const dpr = api.getDevicePixelRatio();
const zr = api.getZr();
const isSVG = zr.painter.type === 'svg';
if (decalObject.dirty) { if (decalObject.dirty) {
decalMap.delete(decalObject); decalMap.delete(decalObject);
...@@ -57,10 +61,10 @@ export function createOrUpdatePatternFromDecal( ...@@ -57,10 +61,10 @@ export function createOrUpdatePatternFromDecal(
decalOpt.backgroundColor = null; decalOpt.backgroundColor = null;
} }
const canvas = getPatternCanvas(); const pattern: PatternObject = { repeat: 'repeat' } as PatternObject;
const pattern = new Pattern(canvas, 'repeat'); setPatternnSource(pattern);
pattern.rotation = decalOpt.rotation; pattern.rotation = decalOpt.rotation;
pattern.scaleX = pattern.scaleY = 1 / dpr; pattern.scaleX = pattern.scaleY = isSVG ? 1 : 1 / dpr;
decalMap.set(decalObject, pattern); decalMap.set(decalObject, pattern);
...@@ -68,7 +72,7 @@ export function createOrUpdatePatternFromDecal( ...@@ -68,7 +72,7 @@ export function createOrUpdatePatternFromDecal(
return pattern; return pattern;
function getPatternCanvas(): HTMLCanvasElement { function setPatternnSource(pattern: PatternObject) {
const keys = [dpr]; const keys = [dpr];
let isValidKey = true; let isValidKey = true;
for (let i = 0; i < decalKeys.length; ++i) { for (let i = 0; i < decalKeys.length; ++i) {
...@@ -88,10 +92,11 @@ export function createOrUpdatePatternFromDecal( ...@@ -88,10 +92,11 @@ export function createOrUpdatePatternFromDecal(
let cacheKey; let cacheKey;
if (isValidKey) { if (isValidKey) {
cacheKey = keys.join(','); cacheKey = keys.join(',') + (isSVG ? '-svg' : '');
const cache = decalCache.get(cacheKey); const cache = decalCache.get(cacheKey);
if (cache) { if (cache) {
return cache; isSVG ? pattern.svgElement = cache as SVGElement
: pattern.image = cache as HTMLCanvasElement;
} }
} }
...@@ -100,29 +105,36 @@ export function createOrUpdatePatternFromDecal( ...@@ -100,29 +105,36 @@ export function createOrUpdatePatternFromDecal(
const lineBlockLengthsX = getLineBlockLengthX(dashArrayX); const lineBlockLengthsX = getLineBlockLengthX(dashArrayX);
const lineBlockLengthY = getLineBlockLengthY(dashArrayY); const lineBlockLengthY = getLineBlockLengthY(dashArrayY);
const canvas = createCanvas(); const canvas = !isSVG && createCanvas();
const svgRoot = isSVG && (zr.painter as SVGPainter).createSVGElement('g');
const pSize = getPatternSize(); const pSize = getPatternSize();
canvas.width = pSize.width * dpr; let ctx: CanvasRenderingContext2D;
canvas.height = pSize.height * dpr; if (canvas) {
canvas.width = pSize.width * dpr;
canvas.height = pSize.height * dpr;
ctx = canvas.getContext('2d');
}
brushDecal(); brushDecal();
if (isValidKey) { if (isValidKey) {
decalCache.put(cacheKey, canvas); decalCache.put(cacheKey, canvas || svgRoot);
} }
return canvas;
pattern.image = canvas;
pattern.svgElement = svgRoot;
pattern.svgWidth = pSize.width;
pattern.svgHeight = pSize.height;
/** /**
* Get minumum length that can make a repeatable pattern. * Get minumum length that can make a repeatable pattern.
* *
* @return {Object} pattern width and height * @return {Object} pattern width and height
*/ */
function getPatternSize() function getPatternSize(): {
: { width: number,
width: number, height: number,
height: number, lines: number
lines: number } {
}
{
/** /**
* For example, if dash is [[3, 2], [2, 1]] for X, it looks like * For example, if dash is [[3, 2], [2, 1]] for X, it looks like
* |--- --- --- --- --- ... * |--- --- --- --- --- ...
...@@ -160,10 +172,11 @@ export function createOrUpdatePatternFromDecal( ...@@ -160,10 +172,11 @@ export function createOrUpdatePatternFromDecal(
const columns = decalOpt.dashLineOffset const columns = decalOpt.dashLineOffset
? width / offsetMultipleX ? width / offsetMultipleX
: 2; : 2;
let height = lineBlockLengthY * columns; const height = lineBlockLengthY * columns;
if (__DEV__) { if (__DEV__) {
const warn = (attrName: string) => { const warn = (attrName: string) => {
/* eslint-disable-next-line */
console.warn(`Calculated decal size is greater than ${attrName} due to decal option settings so ${attrName} is used for the decal size. Please consider changing the decal option to make a smaller decal or set ${attrName} to be larger to avoid incontinuity.`); console.warn(`Calculated decal size is greater than ${attrName} due to decal option settings so ${attrName} is used for the decal size. Please consider changing the decal option to make a smaller decal or set ${attrName} to be larger to avoid incontinuity.`);
}; };
if (width > decalOpt.maxTileWidth) { if (width > decalOpt.maxTileWidth) {
...@@ -182,15 +195,14 @@ export function createOrUpdatePatternFromDecal( ...@@ -182,15 +195,14 @@ export function createOrUpdatePatternFromDecal(
} }
function brushDecal() { function brushDecal() {
const ctx = canvas.getContext('2d'); if (ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height);
if (decalOpt.backgroundColor) { if (decalOpt.backgroundColor) {
ctx.fillStyle = decalOpt.backgroundColor; ctx.fillStyle = decalOpt.backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillRect(0, 0, canvas.width, canvas.height);
}
} }
ctx.fillStyle = decalOpt.color;
let ySum = 0; let ySum = 0;
for (let i = 0; i < dashArrayY.length; ++i) { for (let i = 0; i < dashArrayY.length; ++i) {
ySum += dashArrayY[i]; ySum += dashArrayY[i];
...@@ -254,15 +266,21 @@ export function createOrUpdatePatternFromDecal( ...@@ -254,15 +266,21 @@ export function createOrUpdatePatternFromDecal(
} }
function brushSymbol(x: number, y: number, width: number, height: number) { function brushSymbol(x: number, y: number, width: number, height: number) {
const scale = isSVG ? 1 : dpr;
const symbol = createSymbol( const symbol = createSymbol(
decalOpt.symbol, decalOpt.symbol,
x * dpr, x * scale,
y * dpr, y * scale,
width * dpr, width * scale,
height * dpr height * scale
); );
symbol.style.fill = decalOpt.color; symbol.style.fill = decalOpt.color;
brushSingle(ctx, symbol); if (isSVG) {
svgRoot.appendChild((zr.painter as SVGPainter).paintOne(symbol));
}
else {
(zr.painter as CanvasPainter).paintOne(ctx, symbol);
}
} }
} }
} }
......
...@@ -22,8 +22,6 @@ import GlobalModel from '../model/Global'; ...@@ -22,8 +22,6 @@ import GlobalModel from '../model/Global';
import {createOrUpdatePatternFromDecal} from '../util/decal'; import {createOrUpdatePatternFromDecal} from '../util/decal';
export default function (ecModel: GlobalModel, api: ExtensionAPI) { export default function (ecModel: GlobalModel, api: ExtensionAPI) {
const dpr = api.getDevicePixelRatio();
ecModel.eachRawSeries(seriesModel => { ecModel.eachRawSeries(seriesModel => {
const data = seriesModel.getData(); const data = seriesModel.getData();
...@@ -32,7 +30,7 @@ export default function (ecModel: GlobalModel, api: ExtensionAPI) { ...@@ -32,7 +30,7 @@ export default function (ecModel: GlobalModel, api: ExtensionAPI) {
const decal = data.getItemVisual(idx, 'decal'); const decal = data.getItemVisual(idx, 'decal');
if (decal) { if (decal) {
const itemStyle = data.ensureUniqueItemVisual(idx, 'style'); const itemStyle = data.ensureUniqueItemVisual(idx, 'style');
itemStyle.decal = createOrUpdatePatternFromDecal(decal, dpr); itemStyle.decal = createOrUpdatePatternFromDecal(decal, api);
} }
}); });
} }
...@@ -40,7 +38,7 @@ export default function (ecModel: GlobalModel, api: ExtensionAPI) { ...@@ -40,7 +38,7 @@ export default function (ecModel: GlobalModel, api: ExtensionAPI) {
const decal = data.getVisual('decal'); const decal = data.getVisual('decal');
if (decal) { if (decal) {
const style = data.getVisual('style'); const style = data.getVisual('style');
style.decal = createOrUpdatePatternFromDecal(decal, dpr); style.decal = createOrUpdatePatternFromDecal(decal, api);
} }
} }
}); });
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册