liusuyi
2023-04-24 4737f1e038743ced243c9e52423404d9034d6107
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
 
import Path, { DEFAULT_PATH_STYLE, PathStyleProps } from '../graphic/Path';
import ZRImage, { ImageStyleProps } from '../graphic/Image';
import TSpan, { TSpanStyleProps } from '../graphic/TSpan';
import { getLineDash } from '../canvas/dashStyle';
import { map } from '../core/util';
import { normalizeColor } from './helper';
 
type AllStyleOption = PathStyleProps | TSpanStyleProps | ImageStyleProps;
 
const NONE = 'none';
const mathRound = Math.round;
 
function pathHasFill(style: AllStyleOption): style is PathStyleProps {
    const fill = (style as PathStyleProps).fill;
    return fill != null && fill !== NONE;
}
 
function pathHasStroke(style: AllStyleOption): style is PathStyleProps {
    const stroke = (style as PathStyleProps).stroke;
    return stroke != null && stroke !== NONE;
}
 
const strokeProps = ['lineCap', 'miterLimit', 'lineJoin'] as const;
const svgStrokeProps = map(strokeProps, prop => `stroke-${prop.toLowerCase()}`);
 
export default function mapStyleToAttrs(
    updateAttr: (key: string, val: string | number) => void,
    style: AllStyleOption,
    el: Path | TSpan | ZRImage,
    /**
     * Will try not to set the attribute if it's using default value if not using forceUpdate.
     * Mainly for reduce the generated size in svg-ssr mode.
     */
    forceUpdate: boolean
): void {
    const opacity = style.opacity == null ? 1 : style.opacity;
 
    // only set opacity. stroke and fill cannot be applied to svg image
    if (el instanceof ZRImage) {
        updateAttr('opacity', opacity);
        return;
    }
 
    if (pathHasFill(style)) {
        const fill = normalizeColor(style.fill as string);
        updateAttr('fill', fill.color);
        const fillOpacity = style.fillOpacity != null
            ? style.fillOpacity * fill.opacity * opacity
            : fill.opacity * opacity;
        if (forceUpdate || fillOpacity < 1) {
            updateAttr('fill-opacity', fillOpacity);
        }
    }
    else {
        updateAttr('fill', NONE);
    }
 
    if (pathHasStroke(style)) {
        const stroke = normalizeColor(style.stroke as string);
        updateAttr('stroke', stroke.color);
        const strokeScale = style.strokeNoScale
            ? (el as Path).getLineScale()
            : 1;
        const strokeWidth = (strokeScale ? (style.lineWidth || 0) / strokeScale : 0);
        const strokeOpacity = style.strokeOpacity != null
            ? style.strokeOpacity * stroke.opacity * opacity
            : stroke.opacity * opacity;
        const strokeFirst = style.strokeFirst;
 
        if (forceUpdate || strokeWidth !== 1) {
            updateAttr('stroke-width', strokeWidth);
        }
        // stroke then fill for text; fill then stroke for others
        if (forceUpdate || strokeFirst) {
            updateAttr('paint-order', strokeFirst ? 'stroke' : 'fill');
        }
        if (forceUpdate || strokeOpacity < 1) {
            updateAttr('stroke-opacity', strokeOpacity);
        }
 
        if (style.lineDash) {
            let [lineDash, lineDashOffset] = getLineDash(el);
            if (lineDash) {
                lineDashOffset = mathRound(lineDashOffset || 0);
                updateAttr('stroke-dasharray', lineDash.join(','));
                if (lineDashOffset || forceUpdate) {
                    updateAttr('stroke-dashoffset', lineDashOffset);
                }
            }
        }
        else if (forceUpdate) {
            // Reset if force update.
            updateAttr('stroke-dasharray', NONE);
        }
 
        // PENDING reset
        for (let i = 0; i < strokeProps.length; i++) {
            const propName = strokeProps[i];
            if (forceUpdate || style[propName] !== DEFAULT_PATH_STYLE[propName]) {
                const val = style[propName] || DEFAULT_PATH_STYLE[propName];
                // TODO reset
                val && updateAttr(svgStrokeProps[i], val);
            }
        }
    }
    else if (forceUpdate) {
        updateAttr('stroke', NONE);
    }
}