package.src.svg-legacy.helper.ShadowManager.ts Maven / Gradle / Ivy
/**
* @file Manages SVG shadow elements.
* @author Zhang Wenli
*/
import Definable from './Definable';
import Displayable from '../../graphic/Displayable';
import { Dictionary } from '../../core/types';
import { getIdURL, getShadowKey, hasShadow, normalizeColor } from '../../svg/helper';
import { createElement } from '../../svg/core';
type DisplayableExtended = Displayable & {
_shadowDom: SVGElement
}
/**
* Manages SVG shadow elements.
*
*/
export default class ShadowManager extends Definable {
private _shadowDomMap: Dictionary = {}
private _shadowDomPool: SVGFilterElement[] = []
constructor(zrId: number, svgRoot: SVGElement) {
super(zrId, svgRoot, ['filter'], '__filter_in_use__', '_shadowDom');
}
/**
* Add a new shadow tag in
*
* @param displayable zrender displayable element
* @return created DOM
*/
private _getFromPool(): SVGFilterElement {
let shadowDom = this._shadowDomPool.pop(); // Try to get one from trash.
if (!shadowDom) {
shadowDom = createElement('filter') as SVGFilterElement;
shadowDom.setAttribute('id', 'zr' + this._zrId + '-shadow-' + this.nextId++);
const domChild = createElement('feDropShadow');
shadowDom.appendChild(domChild);
this.addDom(shadowDom);
}
return shadowDom;
}
/**
* Update shadow.
*/
update(svgElement: SVGElement, displayable: Displayable) {
const style = displayable.style;
if (hasShadow(style)) {
// Try getting shadow from cache.
const shadowKey = getShadowKey(displayable);
let shadowDom = (displayable as DisplayableExtended)._shadowDom = this._shadowDomMap[shadowKey];
if (!shadowDom) {
shadowDom = this._getFromPool();
this._shadowDomMap[shadowKey] = shadowDom;
}
this.updateDom(svgElement, displayable, shadowDom);
}
else {
// Remove shadow
this.remove(svgElement, displayable);
}
}
/**
* Remove DOM and clear parent filter
*/
remove(svgElement: SVGElement, displayable: Displayable) {
if ((displayable as DisplayableExtended)._shadowDom != null) {
(displayable as DisplayableExtended)._shadowDom = null;
svgElement.removeAttribute('filter');
}
}
/**
* Update shadow dom
*
* @param displayable zrender displayable element
* @param shadowDom DOM to update
*/
updateDom(svgElement: SVGElement, displayable: Displayable, shadowDom: SVGElement) {
let domChild = shadowDom.children[0];
const style = displayable.style;
const globalScale = displayable.getGlobalScale();
const scaleX = globalScale[0];
const scaleY = globalScale[1];
if (!scaleX || !scaleY) {
return;
}
// TODO: textBoxShadowBlur is not supported yet
const offsetX = style.shadowOffsetX || 0;
const offsetY = style.shadowOffsetY || 0;
const blur = style.shadowBlur;
const normalizedColor = normalizeColor(style.shadowColor);
domChild.setAttribute('dx', offsetX / scaleX + '');
domChild.setAttribute('dy', offsetY / scaleY + '');
domChild.setAttribute('flood-color', normalizedColor.color);
domChild.setAttribute('flood-opacity', normalizedColor.opacity + '');
// Divide by two here so that it looks the same as in canvas
// See: https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-shadowblur
const stdDx = blur / 2 / scaleX;
const stdDy = blur / 2 / scaleY;
const stdDeviation = stdDx + ' ' + stdDy;
domChild.setAttribute('stdDeviation', stdDeviation);
// Fix filter clipping problem
shadowDom.setAttribute('x', '-100%');
shadowDom.setAttribute('y', '-100%');
shadowDom.setAttribute('width', '300%');
shadowDom.setAttribute('height', '300%');
// Store dom element in shadow, to avoid creating multiple
// dom instances for the same shadow element
(displayable as DisplayableExtended)._shadowDom = shadowDom;
svgElement.setAttribute('filter', getIdURL(shadowDom.getAttribute('id')));
}
removeUnused() {
const defs = this.getDefs(false);
if (!defs) {
// Nothing to remove
return;
}
let shadowDomsPool = this._shadowDomPool;
// let currentUsedShadow = 0;
const shadowDomMap = this._shadowDomMap;
for (let key in shadowDomMap) {
if (shadowDomMap.hasOwnProperty(key)) {
shadowDomsPool.push(shadowDomMap[key]);
}
// currentUsedShadow++;
}
// Reset the map.
this._shadowDomMap = {};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy