package.src.svg-legacy.helper.PatternManager.ts Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of zrender Show documentation
Show all versions of zrender Show documentation
A lightweight graphic library providing 2d draw for Apache ECharts
The newest version!
/**
* @file Manages SVG pattern elements.
* @author Zhang Wenli
*/
import Definable from './Definable';
import * as zrUtil from '../../core/util';
import Displayable from '../../graphic/Displayable';
import {PatternObject} from '../../graphic/Pattern';
import {createOrUpdateImage} from '../../graphic/helper/image';
import WeakMap from '../../core/WeakMap';
import { getIdURL, isPattern, isSVGPattern } from '../../svg/helper';
import { createElement } from '../../svg/core';
const patternDomMap = new WeakMap();
/**
* Manages SVG pattern elements.
*
* @param zrId zrender instance id
* @param svgRoot root of SVG document
*/
export default class PatternManager extends Definable {
constructor(zrId: number, svgRoot: SVGElement) {
super(zrId, svgRoot, ['pattern'], '__pattern_in_use__');
}
/**
* Create new pattern DOM for fill or stroke if not exist,
* but will not update pattern if exists.
*
* @param svgElement SVG element to paint
* @param displayable zrender displayable element
*/
addWithoutUpdate(
svgElement: SVGElement,
displayable: Displayable
) {
if (displayable && displayable.style) {
const that = this;
zrUtil.each(['fill', 'stroke'], function (fillOrStroke: 'fill' | 'stroke') {
const pattern = displayable.style[fillOrStroke] as PatternObject;
if (isPattern(pattern)) {
const defs = that.getDefs(true);
// Create dom in if not exists
let dom = patternDomMap.get(pattern);
if (dom) {
// Pattern exists
if (!defs.contains(dom)) {
// __dom is no longer in defs, recreate
that.addDom(dom);
}
}
else {
// New dom
dom = that.add(pattern);
}
that.markUsed(displayable);
svgElement.setAttribute(fillOrStroke, getIdURL(dom.getAttribute('id')));
}
});
}
}
/**
* Add a new pattern tag in
*
* @param pattern zr pattern instance
*/
add(pattern: PatternObject): SVGElement {
if (!isPattern(pattern)) {
return;
}
let dom = createElement('pattern');
pattern.id = pattern.id == null ? this.nextId++ : pattern.id;
dom.setAttribute('id', 'zr' + this._zrId
+ '-pattern-' + pattern.id);
dom.setAttribute('patternUnits', 'userSpaceOnUse');
this.updateDom(pattern, dom);
this.addDom(dom);
return dom;
}
/**
* Update pattern.
*
* @param pattern zr pattern instance or color string
*/
update(pattern: PatternObject | string) {
if (!isPattern(pattern)) {
return;
}
const that = this;
this.doUpdate(pattern, function () {
const dom = patternDomMap.get(pattern);
that.updateDom(pattern, dom);
});
}
/**
* Update pattern dom
*
* @param pattern zr pattern instance
* @param patternDom DOM to update
*/
updateDom(pattern: PatternObject, patternDom: SVGElement) {
if (isSVGPattern(pattern)) {
// New SVGPattern will not been supported in the legacy SVG renderer.
// svg-legacy will been removed soon.
// const svgElement = pattern.svgElement;
// const isStringSVG = typeof svgElement === 'string';
// if (isStringSVG || svgElement.parentNode !== patternDom) {
// if (isStringSVG) {
// patternDom.innerHTML = svgElement;
// }
// else {
// patternDom.innerHTML = '';
// patternDom.appendChild(svgElement);
// }
// patternDom.setAttribute('width', pattern.svgWidth as any);
// patternDom.setAttribute('height', pattern.svgHeight as any);
// }
}
else {
let img: SVGElement;
const prevImage = patternDom.getElementsByTagName('image');
if (prevImage.length) {
if (pattern.image) {
// Update
img = prevImage[0];
}
else {
// Remove
patternDom.removeChild(prevImage[0]);
return;
}
}
else if (pattern.image) {
// Create
img = createElement('image');
}
if (img) {
let imageSrc;
const patternImage = pattern.image;
if (typeof patternImage === 'string') {
imageSrc = patternImage;
}
else if (patternImage instanceof HTMLImageElement) {
imageSrc = patternImage.src;
}
else if (patternImage instanceof HTMLCanvasElement) {
imageSrc = patternImage.toDataURL();
}
if (imageSrc) {
img.setAttribute('href', imageSrc);
// No need to re-render so dirty is empty
const hostEl = {
dirty: () => {}
};
const updateSize = (img: HTMLImageElement) => {
patternDom.setAttribute('width', img.width as any);
patternDom.setAttribute('height', img.height as any);
};
const createdImage = createOrUpdateImage(imageSrc, img as any, hostEl, updateSize);
if (createdImage && createdImage.width && createdImage.height) {
// Loaded before
updateSize(createdImage as HTMLImageElement);
}
patternDom.appendChild(img);
}
}
}
const x = pattern.x || 0;
const y = pattern.y || 0;
const rotation = (pattern.rotation || 0) / Math.PI * 180;
const scaleX = pattern.scaleX || 1;
const scaleY = pattern.scaleY || 1;
const transform = `translate(${x}, ${y}) rotate(${rotation}) scale(${scaleX}, ${scaleY})`;
patternDom.setAttribute('patternTransform', transform);
patternDomMap.set(pattern, patternDom);
}
/**
* Mark a single pattern to be used
*
* @param displayable displayable element
*/
markUsed(displayable: Displayable) {
if (displayable.style) {
if (isPattern(displayable.style.fill)) {
super.markDomUsed(patternDomMap.get(displayable.style.fill));
}
if (isPattern(displayable.style.stroke)) {
super.markDomUsed(patternDomMap.get(displayable.style.stroke));
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy