| import { keys, map } from '../core/util'; | 
| import { encodeHTML } from '../core/dom'; | 
|   | 
| export type CSSSelectorVNode = Record<string, string> | 
| export type CSSAnimationVNode = Record<string, Record<string, string>> | 
|   | 
| export const SVGNS = 'http://www.w3.org/2000/svg'; | 
| export const XLINKNS = 'http://www.w3.org/1999/xlink'; | 
| export const XMLNS = 'http://www.w3.org/2000/xmlns/'; | 
| export const XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace'; | 
|   | 
| export function createElement(name: string) { | 
|     return document.createElementNS(SVGNS, name); | 
| } | 
|   | 
| export type SVGVNodeAttrs = Record<string, string | number | undefined | boolean> | 
| export interface SVGVNode { | 
|     tag: string, | 
|     attrs: SVGVNodeAttrs, | 
|     children?: SVGVNode[], | 
|     text?: string | 
|   | 
|     // For patching | 
|     elm?: Node | 
|     key: string | 
| }; | 
| export function createVNode( | 
|     tag: string, | 
|     key: string, | 
|     attrs?: SVGVNodeAttrs, | 
|     children?: SVGVNode[], | 
|     text?: string | 
| ): SVGVNode { | 
|     return { | 
|         tag, | 
|         attrs: attrs || {}, | 
|         children, | 
|         text, | 
|         key | 
|     }; | 
| } | 
|   | 
| function createElementOpen(name: string, attrs?: SVGVNodeAttrs) { | 
|     const attrsStr: string[] = []; | 
|     if (attrs) { | 
|         // eslint-disable-next-line | 
|         for (let key in attrs) { | 
|             const val = attrs[key]; | 
|             let part = key; | 
|             // Same with the logic in patch. | 
|             if (val === false) { | 
|                 continue; | 
|             } | 
|             else if (val !== true && val != null) { | 
|                 part += `="${val}"`; | 
|             } | 
|             attrsStr.push(part); | 
|         } | 
|     } | 
|     return `<${name} ${attrsStr.join(' ')}>`; | 
| } | 
|   | 
| function createElementClose(name: string) { | 
|     return `</${name}>`; | 
| } | 
|   | 
| export function vNodeToString(el: SVGVNode, opts?: { | 
|     newline?: boolean | 
| }) { | 
|     opts = opts || {}; | 
|     const S = opts.newline ? '\n' : ''; | 
|     function convertElToString(el: SVGVNode): string { | 
|         const {children, tag, attrs} = el; | 
|         return createElementOpen(tag, attrs) | 
|             + encodeHTML(el.text) | 
|             + (children ? `${S}${map(children, child => convertElToString(child)).join(S)}${S}` : '') | 
|             + createElementClose(tag); | 
|     } | 
|     return convertElToString(el); | 
| } | 
|   | 
| export function getCssString( | 
|     selectorNodes: Record<string, CSSSelectorVNode>, | 
|     animationNodes: Record<string, CSSAnimationVNode>, | 
|     opts?: { | 
|         newline?: boolean | 
|     } | 
| ) { | 
|     opts = opts || {}; | 
|     const S = opts.newline ? '\n' : ''; | 
|     const bracketBegin = ` {${S}`; | 
|     const bracketEnd = `${S}}`; | 
|     const selectors = map(keys(selectorNodes), className => { | 
|         return className + bracketBegin + map(keys(selectorNodes[className]), attrName => { | 
|             return `${attrName}:${selectorNodes[className][attrName]};`; | 
|         }).join(S) + bracketEnd; | 
|     }).join(S); | 
|     const animations = map(keys(animationNodes), (animationName) => { | 
|         return `@keyframes ${animationName}${bracketBegin}` + map(keys(animationNodes[animationName]), percent => { | 
|             return percent + bracketBegin + map(keys(animationNodes[animationName][percent]), attrName => { | 
|                 let val = animationNodes[animationName][percent][attrName]; | 
|                 // postprocess | 
|                 if (attrName === 'd') { | 
|                     val = `path("${val}")`; | 
|                 } | 
|                 return `${attrName}:${val};`; | 
|             }).join(S) + bracketEnd; | 
|         }).join(S) + bracketEnd; | 
|     }).join(S); | 
|   | 
|     if (!selectors && !animations) { | 
|         return ''; | 
|     } | 
|   | 
|     return ['<![CDATA[', selectors, animations, ']]>'].join(S); | 
| } | 
|   | 
|   | 
| export interface BrushScope { | 
|     zrId: string | 
|   | 
|     shadowCache: Record<string, string> | 
|     gradientCache: Record<string, string> | 
|     patternCache: Record<string, string> | 
|     clipPathCache: Record<string, string> | 
|   | 
|     defs: Record<string, SVGVNode> | 
|   | 
|     cssNodes: Record<string, CSSSelectorVNode> | 
|     cssAnims: Record<string, Record<string, Record<string, string>>> | 
|   | 
|     cssClassIdx: number | 
|     cssAnimIdx: number | 
|   | 
|     shadowIdx: number | 
|     gradientIdx: number | 
|     patternIdx: number | 
|     clipPathIdx: number | 
|     // configs | 
|     /** | 
|      * If create animates nodes. | 
|      */ | 
|     animation?: boolean, | 
|   | 
|     /** | 
|      * If will update. Some optimization for string generation can't be applied. | 
|      */ | 
|     willUpdate?: boolean | 
|   | 
|     /** | 
|      * If compress the output string. | 
|      */ | 
|     compress?: boolean | 
| } | 
|   | 
| export function createBrushScope(zrId: string): BrushScope { | 
|     return { | 
|         zrId, | 
|         shadowCache: {}, | 
|         patternCache: {}, | 
|         gradientCache: {}, | 
|         clipPathCache: {}, | 
|         defs: {}, | 
|   | 
|         cssNodes: {}, | 
|         cssAnims: {}, | 
|   | 
|         cssClassIdx: 0, | 
|         cssAnimIdx: 0, | 
|   | 
|         shadowIdx: 0, | 
|         gradientIdx: 0, | 
|         patternIdx: 0, | 
|         clipPathIdx: 0 | 
|     }; | 
| } | 
|   | 
| export function createSVGVNode( | 
|     width: number | string, | 
|     height: number | string, | 
|     children?: SVGVNode[], | 
|     useViewBox?: boolean | 
| ) { | 
|     return createVNode( | 
|         'svg', | 
|         'root', | 
|         { | 
|             'width': width, | 
|             'height': height, | 
|             'xmlns': SVGNS, | 
|             'xmlns:xlink': XLINKNS, | 
|             'version': '1.1', | 
|             'baseProfile': 'full', | 
|             'viewBox': useViewBox ? `0 0 ${width} ${height}` : false | 
|         }, | 
|         children | 
|     ); | 
| } |