apexcharts
Version:
A JavaScript Chart Library
159 lines (140 loc) • 3.4 kB
JavaScript
// @ts-check
import SVGElement from './SVGElement'
import { SVGNS } from './math'
import { BrowserAPIs } from '../ssr/BrowserAPIs.js'
let filterCounter = 0
class SVGFilter extends SVGElement {
constructor() {
const node = BrowserAPIs.createElementNS(SVGNS, 'filter')
super(node)
this._id = 'SvgjsFilter' + ++filterCounter
this.attr('id', this._id)
}
/**
* @param {import('../types/internal').ChartStateW} w
* @param {number} h
* @param {number} x
* @param {number} y
*/
/**
* @param {number} w
* @param {number} h
* @param {number} [x]
* @param {number} [y]
*/
size(w, h, x, y) {
return this.attr({ width: w, height: h, x, y })
}
}
class FilterBuilder {
/**
* @param {any} filter
*/
constructor(filter) {
this.filter = filter
}
/**
* @param {object} attrs
*/
colorMatrix(attrs) {
return this._primitive('feColorMatrix', attrs)
}
/**
* @param {object} attrs
*/
offset(attrs) {
return this._primitive('feOffset', attrs)
}
/**
* @param {object} attrs
*/
gaussianBlur(attrs) {
return this._primitive('feGaussianBlur', attrs)
}
/**
* @param {object} attrs
*/
flood(attrs) {
return this._primitive('feFlood', attrs)
}
/**
* @param {object} attrs
*/
composite(attrs) {
return this._primitive('feComposite', attrs)
}
/**
* @param {string[]} sources
*/
merge(sources) {
const m = BrowserAPIs.createElementNS(SVGNS, 'feMerge')
/**
* @param {string} src
*/
sources.forEach((/** @type {any} */ src) => {
const mn = BrowserAPIs.createElementNS(SVGNS, 'feMergeNode')
mn.setAttribute('in', src)
m.appendChild(mn)
})
this.filter.node.appendChild(m)
return new SVGElement(m)
}
/**
* @param {string} tag
* @param {Record<string, any>} attrs
*/
_primitive(tag, attrs) {
const el = BrowserAPIs.createElementNS(SVGNS, tag)
for (const key in attrs) {
el.setAttribute(key, attrs[key])
}
this.filter.node.appendChild(el)
return new SVGElement(el)
}
}
// Install filter methods on SVGElement prototype
/**
* @param {any} ElementClass
*/
function installFilterMethods(ElementClass) {
/**
* @param {Function} fn
*/
ElementClass.prototype.filterWith = function (fn) {
const filter = new SVGFilter()
this._filter = filter
// Add filter to nearest <defs>
let svgRoot = this.node
while (svgRoot && svgRoot.nodeName !== 'svg') {
svgRoot = svgRoot.parentNode
}
if (svgRoot) {
let defs = svgRoot.querySelector('defs')
if (!defs) {
defs = BrowserAPIs.createElementNS(SVGNS, 'defs')
svgRoot.insertBefore(defs, svgRoot.firstChild)
}
defs.appendChild(filter.node)
}
fn(new FilterBuilder(filter))
this.attr('filter', 'url(#' + filter._id + ')')
return this
}
/**
* @param {boolean} all
*/
ElementClass.prototype.unfilter = function (all) {
if (this._filter) {
this.node.removeAttribute('filter')
if (all && this._filter.node && this._filter.node.parentNode) {
this._filter.node.parentNode.removeChild(this._filter.node)
}
this._filter = null
}
return this
}
ElementClass.prototype.filterer = function () {
return this._filter
}
}
export { SVGFilter, FilterBuilder, installFilterMethods }