UNPKG

@yunser/ui-std

Version:

UI standard specification.

2,064 lines 81.8 kB
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StdUI = exports._if = exports.ui = void 0;
// const uiUtil = require('./util')
const helper_1 = require("./helper");
// import * as fs from 'fs'
const Color = require("color");
const angleToCoordinates = require("css-gradient-angle-to-svg-gradient-coordinates");
// const angleToCoordinates = require('css-gradient-angle-to-svg-gradient-coordinates')
const svgpath = require('svgpath');
const caster = require('svg-path-bounding-box');
var parse = require('parse-svg-path');
var translate = require('translate-svg-path');
var serialize = require('serialize-svg-path');
const svg_default_stroke_dasharray = '8';
function max(arr) {
    let max = arr[0];
    for (let num of arr) {
        if (num > max) {
            max = num;
        }
    }
    return max;
}
function getStyle(node) {
    if (node.visible == false) {
        return {
            display: 'none',
        };
    }
    return {};
}
function styleToText(style) {
    return Object.keys(style).map(key => `${key}: ${style[key]}`).join(';');
}
function getStyleText(node) {
    return styleToText(getStyle(node));
}
function getTransform(node, center) {
    if (node.rotate) {
        return `translate(${center.x}, ${center.y}) rotate(${node.rotate}) translate(${-center.x}, ${-center.y})`;
    }
    return null;
}
function breakPoint() {
    throw new Error('breakPoint');
}
const Align = {
    Center: 'center',
};
exports.ui = {
    Align,
};
const BORDER_INSIDE = true;
// const bbbox = caster(
//     'M300,200 h-150 a150,150 0 1,0 150,-150 z'
// )
//     // .toString()
// console.log('bbbox', bbbox)
// console.log('a', a)
const NodeType = {
    Root: 'root',
    // if (node.type == 'root') {
};
function calcPolygon(node) {
    function min(arr) {
        let min = arr[0];
        for (let num of arr) {
            if (num < min) {
                min = num;
            }
        }
        return min;
    }
    let xList = node.points.map(item => item.x);
    let yList = node.points.map(item => item.y);
    let left = min(xList);
    let right = max(xList);
    let top = min(yList);
    let bottom = max(yList);
    // console.log('left', left, right, top, bottom)
    // for (let pt of node.points) {
    //     if (pt.x < left) {
    //     }
    // }
    const height = bottom - top;
    const width = right - left;
    return {
        left,
        right,
        top,
        bottom,
        height,
        width,
    };
}
const StdUiNodeType = {
    Root: 'root',
    Rect: 'rect',
    Text: 'text',
    Image: 'image',
    Circle: 'circle',
    Ellipse: 'ellipse',
    Polygon: 'polygon',
    Polyline: 'polyline',
    Line: 'line',
    Path: 'path',
};
// console.log('uiUtil', uiUtil, uiUtil.treeMap)
function objectSomeAttr(obj, attrs) {
    let result = {};
    for (let attr of attrs) {
        if (obj[attr] != undefined) {
            result[attr] = obj[attr];
        }
    }
    return result;
}
// const uiObj: StdUiRoot = {
//     "_type": "root",
//     "width": 1000,
//     "height": 1000,
//     "_children": [
//         {
//             "_type": "rect",
//             "x": 0,
//             "y": 0,
//             "width": 100,
//             "height": 100,
//             "color": "#f00",
//             radius: 8,
//         },
//         {
//             "_type": "rect",
//             "x": 100,
//             "y": 100,
//             "width": 100,
//             "height": 100,
//             "color": "#09c"
//         },
//         {
//             "_type": "circle",
//             "cx": 150,
//             "cy": 50,
//             // "width": 100,
//             // "height": 100,
//             radius: 50,
//             "color": "#f00"
//         },
//         {
//             "_type": "rect",
//             "x": 200,
//             "y": 0,
//             "width": 100,
//             "height": 100,
//             // "color": "#09c",
//             // "stroke": "#09c",
//             "border": {
//                 color: "#09c",
//                 width: 10,
//             }
//         },
//         {
//             "_type": "text",
//             "x": 200,
//             "y": 0,
//             // "width": 100,
//             // "height": 100,
//             "color": "#f00",
//             // radius: 8,
//             text: '你好',
//             textSize: 100,
//         },
//         {
//             "_type": "circle",
//             "cx": 350,
//             "cy": 50,
//             // "width": 100,
//             // "height": 100,
//             radius: 50,
//             "border": {
//                 color: "#09c",
//                 width: 1,
//             }
//             // "color": "#f00"
//         },
//         {
//             "_type": "line",
//             "x1": 0,
//             "y1": 100,
//             x2: 100,
//             y2: 200,
//             "border": {
//                 color: "#f00",
//                 width: 1,
//             }
//             // "width": 100,
//             // "height": 100,
//             // "color": "#f00",
//             // radius: 8,
//         },
//     ]
// }
function convertUiObj2XmlObject(obj) {
    let out = helper_1.uiUtil.treeMap(obj, {
        childrenKey: '_children',
        nodeHandler(node) {
            // let type
            let attrs = {};
            for (let key in node) {
                if (!key.match(/^_/)) {
                    attrs[key] = node[key];
                }
            }
            // if (node._type == 'root') {
            //     type = 'root'
            // } else if (node._type == 'tag') {
            //     type = node.name
            //     attrs = node.attribs
            // } else {
            //     if (node._type == 'text') {
            //         console.log('node', node)
            //         const { data } = node
            //         if (data.match(/^\s+$/)) {
            //             return null
            //         }
            //     } 
            //     type = 'other:' + node._type
            // }
            let result = {
                type: node._type,
                // children: node._children as any,
                attr: attrs,
                // _type: type,
                // ...attrs,
            };
            return result;
        }
    });
    return out;
}
function _if(condition, obj) {
    return condition ? [obj] : [];
}
exports._if = _if;
function convertUiObj2HtmlObject(rootObj) {
    function calcLine(node) {
        let x = Math.min(node.x1, node.x2);
        let y = Math.min(node.y1, node.y2);
        let width = Math.abs(node.x1 - node.x2);
        let height = Math.abs(node.y1 - node.y2);
        return {
            x,
            y,
            width,
            height,
        };
    }
    function getTranslatePoints(points, translate) {
        return points.map(item => {
            return {
                x: item.x + translate.x,
                y: item.y + translate.y,
            };
        });
    }
    function commonStyle(node) {
        let ret = {};
        // TODO 0
        if (node.opacity) {
            ret.opacity = node.opacity;
        }
        if (node.shadow) {
            const shadow = node.shadow;
            const color = Color(shadow.color || '#000');
            const rgb = color.object();
            const rgba = `rgba(${rgb.r * 255}, ${rgb.g * 255}, ${rgb.b * 255}, ${shadow.alpha || 1})`;
            ret['box-shadow'] = `${shadow.x || 0}px ${shadow.y || 0}px ${shadow.blur || 0}px ${shadow.spread || 0}px ${rgba}`;
        }
        // shadow: {
        //     x: 5,
        //         y: 5,
        //             blur: 10,
        //                 alpha: 0.2,
        //             },
        return ret;
    }
    function borderStyle(node) {
        let ret = {};
        if (node.border) {
            ret.border = `${node.border.width || 1}px solid ${node.border.color || '#000'}`;
        }
        return ret;
    }
    function borderRadius(node) {
        let ret = {};
        if (node.borderRadius) {
            ret['border-radius'] = `${node.borderRadius || 0}px`;
        }
        return ret;
    }
    function fillStyle(node) {
        let ret = {};
        // if (node.border) {
        //     ret.border = `${node.border.width || 1}px solid ${node.border.color || '#000'}`
        // }
        if (node.fill) {
            const gradient = node.fill;
            if (node.fill.type == 'linearGradient') {
                if (gradient.stops) {
                    ret['background-image'] = `linear-gradient(to ${gradient.direction}deg, ${gradient.stops.map(stop => `${stop.color}`).join(', ')})`;
                }
                else {
                    ret['background-image'] = `linear-gradient(to ${node.fill.direction}, ${node.fill.colors[0]}, ${node.fill.colors[1]})`;
                }
            }
            // direction: 'bottom',
            // colors: ['#09c', '#c90'],
        }
        // fill: {
        //     type: '',
        //     },
        else if (node.color != null) {
            ret['background-color'] = node.color || '#fff';
        }
        return ret;
    }
    function getHtmlStyle(attrs) {
        let _arr = [];
        for (let key in attrs) {
            _arr.push(`${key}: ${attrs[key]}`);
        }
        return _arr.join('; ');
    }
    return {
        type: 'html',
        children: [
            {
                type: 'head',
                children: [
                    {
                        type: 'style',
                        _data: `* {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            background-color: #fff;
        }
        @font-face {
  font-family: 'iconfont';  /* Project id 2831085 */
  src: url('//at.alicdn.com/t/font_2831085_rw79b312ut.woff2?t=1632424896907') format('woff2'),
       url('//at.alicdn.com/t/font_2831085_rw79b312ut.woff?t=1632424896907') format('woff'),
       url('//at.alicdn.com/t/font_2831085_rw79b312ut.ttf?t=1632424896907') format('truetype');
}
.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-shixinzhengfangxing:before {
  content: "\e606";
}


`
                    }
                ]
            },
            {
                type: 'body',
                children: [
                    helper_1.uiUtil.treeMap(rootObj, {
                        childrenKey: '_children',
                        nodeHandler(node) {
                            // if (node._type == StdUiNodeType.Rect) {
                            //     return {}
                            // }
                            if (node._type === StdUiNodeType.Root) {
                                return {
                                    type: 'div',
                                    attr: {
                                        class: 'std-ui-root',
                                        style: getHtmlStyle({
                                            width: node.width,
                                            height: node.height,
                                            // border: '1px solid #999',
                                            'background-color': node.color || '#fff'
                                        })
                                    },
                                };
                            }
                            if (node._type == StdUiNodeType.Rect) {
                                // let _attr = objectSomeAttr(attrs, ['width', 'height', 'x', 'y'])
                                let _node = {
                                    type: 'div',
                                    attr: {
                                        style: getHtmlStyle(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, commonStyle(node)), { position: 'absolute', left: node.x || 0, top: node.y || 0, width: node.width, height: node.height }), borderStyle(node)), borderRadius(node)), fillStyle(node)))
                                    },
                                };
                                return _node;
                            }
                            if (node._type == StdUiNodeType.Circle) {
                                // let _attr = objectSomeAttr(attrs, ['width', 'height', 'x', 'y'])
                                let style = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, commonStyle(node)), { position: 'absolute', left: ((node.cx || 0) - (node.radius || 0)) || 0, top: ((node.cy || 0) - (node.radius || 0)) || 0, width: (node.radius || 0) * 2, height: (node.radius || 0) * 2 }), borderStyle(node)), fillStyle(node)), { 'border-radius': `${(node.radius || 0)}px` });
                                let _node = {
                                    type: 'div',
                                    attr: {
                                        style: getHtmlStyle(style)
                                    },
                                    // _data: '元',
                                };
                                return _node;
                            }
                            if (node._type == StdUiNodeType.Ellipse) {
                                // let _attr = objectSomeAttr(attrs, ['width', 'height', 'x', 'y'])
                                let rx = node.rx || 0;
                                let ry = node.ry || 0;
                                let style = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, commonStyle(node)), { position: 'absolute', left: ((node.cx || 0) - (node.rx || 0)) || 0, top: ((node.cy || 0) - (node.ry || 0)) || 0, width: (node.rx || 0) * 2, height: (node.ry || 0) * 2 }), borderStyle(node)), fillStyle(node)), { 'border-radius': `${rx}px ${rx}px ${rx}px ${rx}px/${ry}px ${ry}px ${ry}px ${ry}px` });
                                let _node = {
                                    type: 'div',
                                    attr: {
                                        style: getHtmlStyle(style)
                                    },
                                    // _data: '元',
                                };
                                return _node;
                            }
                            if (node._type == StdUiNodeType.Polygon) {
                                // let _attr = objectSomeAttr(attrs, ['width', 'height', 'x', 'y'])
                                const { left, top, width, height } = calcPolygon(node);
                                let _node = {
                                    type: 'div',
                                    attr: {
                                        class: 'polygon',
                                        style: getHtmlStyle(Object.assign(Object.assign({}, commonStyle(node)), { position: 'absolute', left: left, top: top, width: width, height: height }))
                                    },
                                    _data: helper_1.uiUtil.xmlObj2Xml(convertUiObj2SvgObject({
                                        _type: 'svg',
                                        width: 100,
                                        height: 100,
                                        color: null,
                                        _children: [
                                            Object.assign(Object.assign({}, node), { points: getTranslatePoints(node.points, {
                                                    x: 0 - left,
                                                    y: 0 - top,
                                                }) })
                                        ],
                                    })),
                                };
                                return _node;
                            }
                            if (node._type == StdUiNodeType.Polyline) {
                                // let _attr = objectSomeAttr(attrs, ['width', 'height', 'x', 'y'])
                                const { left, top, width, height } = calcPolygon(node);
                                let _node = {
                                    type: 'div',
                                    attr: {
                                        class: 'polygon',
                                        style: getHtmlStyle(Object.assign(Object.assign({}, commonStyle(node)), { position: 'absolute', left: left, top: top, width: width, height: height }))
                                    },
                                    _data: helper_1.uiUtil.xmlObj2Xml(convertUiObj2SvgObject({
                                        _type: 'svg',
                                        width: 100,
                                        height: 100,
                                        color: null,
                                        _children: [
                                            Object.assign(Object.assign({}, node), { points: getTranslatePoints(node.points, {
                                                    x: 0 - left,
                                                    y: 0 - top,
                                                }) })
                                        ],
                                    })),
                                };
                                return _node;
                            }
                            if (node._type == StdUiNodeType.Line) {
                                // let _attr = objectSomeAttr(attrs, ['width', 'height', 'x', 'y'])
                                const { x, y, width, height } = calcLine(node);
                                let _node = {
                                    type: 'div',
                                    attr: {
                                        class: 'line',
                                        style: getHtmlStyle(Object.assign(Object.assign({}, commonStyle(node)), { position: 'absolute', left: x, top: y, width: width, height: height }))
                                    },
                                    _data: helper_1.uiUtil.xmlObj2Xml(convertUiObj2SvgObject({
                                        _type: 'svg',
                                        width: 100,
                                        height: 100,
                                        color: null,
                                        _children: [
                                            Object.assign(Object.assign({}, node), { x1: (node.x1 || 0) - x, y1: (node.y1 || 0) - y, x2: (node.x2 || 0) - x, y2: (node.y2 || 0) - y })
                                        ],
                                    })),
                                };
                                return _node;
                            }
                            if (node._type == StdUiNodeType.Path) {
                                // let _attr = objectSomeAttr(attrs, ['width', 'height', 'x', 'y'])
                                // const { x, y, width, height } = calcLine(node)
                                const bbbox = caster(node.d);
                                // .toString()
                                // console.log('bbbox', bbbox)
                                const newD = serialize(translate(parse(node.d), 0 - bbbox.x1, 0 - bbbox.y1));
                                // console.log('newD', newD)
                                let _node = {
                                    type: 'div',
                                    attr: {
                                        class: 'path',
                                        style: getHtmlStyle(Object.assign(Object.assign({}, commonStyle(node)), { position: 'absolute', left: bbbox.x1, top: bbbox.y1, width: bbbox.width, height: bbbox.height }))
                                    },
                                    _data: helper_1.uiUtil.xmlObj2Xml(convertUiObj2SvgObject({
                                        _type: 'svg',
                                        width: bbbox.width,
                                        height: bbbox.height,
                                        color: null,
                                        _children: [
                                            Object.assign(Object.assign({}, node), { d: newD })
                                        ],
                                    })),
                                };
                                return _node;
                            }
                            if (node._type == StdUiNodeType.Image) {
                                // let _attr = objectSomeAttr(attrs, ['width', 'height', 'x', 'y'])
                                let _node = {
                                    type: 'img',
                                    attr: {
                                        src: node.href,
                                        style: getHtmlStyle(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, commonStyle(node)), { position: 'absolute', left: node.x || 0, top: node.y || 0, width: node.width, height: node.height }), borderStyle(node)), borderRadius(node)), { 'background-color': node.color || '#fff' }))
                                    },
                                };
                                return _node;
                            }
                            if (node._type == StdUiNodeType.Text) {
                                // let _attr = objectSomeAttr(attrs, ['width', 'height', 'x', 'y'])
                                let style = Object.assign(Object.assign({}, commonStyle(node)), { position: 'absolute', left: node.x || 0, top: node.y || 0, 
                                    // width: node.width,
                                    // height: node.height,
                                    // border: '1px solid #999',
                                    // 'color': node.color || '#000',
                                    'color': node.color || '#000', 'font-size': `${node.textSize || 14}px`, 'line-height': `${node.lineHeight || node.textSize || 14}px` });
                                if (node.fill) {
                                    let reverseDirection = {
                                        top: 'bottom',
                                        bottom: 'top',
                                        left: 'right',
                                        right: 'left',
                                    };
                                    if (node.fill.type == 'linearGradient') {
                                        style['background-image'] = `-webkit-linear-gradient(${reverseDirection[node.fill.direction]}, ${node.fill.colors[0]}, ${node.fill.colors[1]})`;
                                        style['-webkit-background-clip'] = 'text';
                                        style['-webkit-text-fill-color'] = 'transparent';
                                        // style['background-image'] = `linear-gradient(to ${node.fill.direction}, ${node.fill.colors[0]}, ${node.fill.colors[1]})`
                                    }
                                    // direction: 'bottom',
                                    // colors: ['#09c', '#c90'],
                                }
                                if (node.fontFamily) {
                                    style['font-family'] = node.fontFamily;
                                }
                                // style['outline'] = '1px solid #f00'
                                if (node.width) {
                                    style['width'] = `${node.width}px`;
                                }
                                if (node.height) {
                                    style['height'] = `${node.height}px`;
                                }
                                style['display'] = `flex`;
                                if (node.align == exports.ui.Align.Center) {
                                    style['justify-content'] = `center`;
                                }
                                if (node.vAlign == exports.ui.Align.Center) {
                                    style['align-items'] = `center`;
                                }
                                // node['class'] = 'iconfont'
                                if (node.border) {
                                    let stroke = `${node.border.width || 1}px ${node.border.color || '#000'}`;
                                    style['text-stroke'] = stroke;
                                    style['-webkit-text-stroke'] = stroke;
                                }
                                let _node = {
                                    type: 'div',
                                    attr: {
                                        // 'class': 'iconfont icon-shixinzhengfangxing',
                                        style: getHtmlStyle(style),
                                    },
                                    _data: node.text
                                };
                                return _node;
                            }
                            return {
                                type: 'div',
                                // _data: 
                                // attr: _attr,
                            };
                        }
                    })
                ]
            },
        ]
    };
}
function convertUiObj2SvgObject(rootObj, toSvgOpts = {
    borderPosition: BorderPositionKey.Center,
}) {
    // console.log('rootObj', JSON.stringify(rootObj, null, 4))
    // breakPoint()
    function createShadow(shadow, node) {
        const id = (0, helper_1.uid)(8);
        const color = Color(shadow.color || '#000');
        const rgb = color.object();
        // console.log('rgb', rgb)
        // console.log('color', )
        // fillStyle = {
        //     color: color.rgb().array().join(','),
        let json = {
            type: 'filter',
            attr: {
                id,
                // x: node.x,
                // y: node.x,
                width: 400,
                height: 400, // TODO
            },
            children: [
                {
                    type: 'feOffset',
                    attr: {
                        result: "offOut",
                        in: "SourceAlpha",
                        dx: shadow.x || 0,
                        dy: shadow.y || 0,
                    },
                },
                {
                    type: 'feGaussianBlur',
                    attr: {
                        result: "blurOut",
                        in: "offOut",
                        stdDeviation: shadow.blur ? (shadow.blur / 2) : 0,
                    },
                },
                {
                    type: 'feMorphology',
                    attr: {
                        in: "feGaussianBlur",
                        operator: "dilate",
                        radius: shadow.spread || 0,
                        result: "big",
                    },
                },
                {
                    type: 'feBlend',
                    attr: {
                        in: "SourceGraphic",
                        in2: "big",
                        mode: "normal",
                    },
                    children: [],
                },
                {
                    type: 'feColorMatrix',
                    attr: {
                        type: "matrix",
                        values: `0 0 0 0 ${rgb.r / 255}
            0 0 0 0 ${rgb.g / 255}
            0 0 0 0 ${rgb.b / 255}
            0 0 0 ${shadow.alpha || 1} 0`,
                        // radius: shadow.spread || 0,
                        // result: "big",
                    },
                },
                {
                    type: 'feBlend',
                    attr: {
                        in: "SourceGraphic",
                        // in2: "big",
                        mode: "normal",
                    },
                    children: [],
                },
                // <feBlend mode="normal" in="SourceGraphic" in2 = "effect1_dropShadow" result = "shape" />
            ],
        };
        return {
            id,
            json,
        };
    }
    function createInnerShadow(shadow, node) {
        const id = (0, helper_1.uid)(8);
        const color = Color(shadow.color || '#000');
        const rgb = color.object();
        // console.log('rgb', rgb)
        // console.log('color', )
        // fillStyle = {
        //     color: color.rgb().array().join(','),
        let json = {
            type: 'filter',
            attr: {
                id,
                // x: node.x,
                // y: node.x,
                // width: 400, // TODO
                // height: 400, // TODO
                x: "-15.5%",
                y: "-15.5%",
                width: "131.0%",
                height: "131.0%",
                filterUnits: "objectBoundingBox",
            },
            children: [
                {
                    type: 'feGaussianBlur',
                    attr: {
                        result: "shadowBlurInner1",
                        in: "SourceAlpha",
                        stdDeviation: shadow.blur ? (shadow.blur / 2) : 0,
                    },
                },
                {
                    type: 'feOffset',
                    attr: {
                        result: "shadowOffsetInner1",
                        in: "shadowBlurInner1",
                        dx: shadow.x || 0,
                        dy: shadow.y || 0,
                    },
                },
                {
                    type: 'feComposite',
                    attr: {
                        in: "shadowOffsetInner1",
                        in2: "SourceAlpha",
                        operator: "arithmetic",
                        k2: "-1",
                        k3: "1",
                        result: "shadowInnerInner1",
                    },
                },
                {
                    type: 'feColorMatrix',
                    attr: {
                        type: "matrix",
                        in: 'shadowInnerInner1',
                        values: `0 0 0 0 ${rgb.r / 255}
            0 0 0 0 ${rgb.g / 255}
            0 0 0 0 ${rgb.b / 255}
            0 0 0 ${shadow.alpha || 1} 0`,
                        // radius: shadow.spread || 0,
                        // result: "big",
                    },
                },
            ],
        };
        return {
            id,
            json,
        };
    }
    function createBlur(blur, node) {
        const id = (0, helper_1.uid)(8);
        // 100 -> 282
        // 0 -> 0
        // 40 正常
        let json = {
            type: 'filter',
            attr: {
                id,
                // 太大一般不会怎样,x 不能随便设置,不然可能显示不出来
                x: "-400%",
                y: "-400%",
                width: "881.0%",
                height: "881.0%", // TODO
            },
            children: [
                {
                    type: 'feGaussianBlur',
                    attr: {
                        in: "SourceGraphic",
                        stdDeviation: blur,
                    },
                },
            ],
        };
        return {
            id,
            json,
        };
    }
    const defs = [];
    function createTextBg(backgroundColor) {
        const id = (0, helper_1.uid)(16);
        defs.push({
            type: 'filter',
            attr: {
                id,
                x: 0,
                y: 0,
                width: 1,
                height: 1,
            },
            children: [
                {
                    type: 'feFlood',
                    attr: {
                        'flood-color': backgroundColor,
                    },
                },
                {
                    type: 'feComposite',
                    attr: {
                        in: 'SourceGraphic',
                    },
                },
            ],
        });
        return id;
    }
    function setStroke(attrs, _attr) {
        if (attrs.border) {
            const { width = 1, color = '#000' } = attrs.border;
            _attr.stroke = color;
            // svg stroke-width 有默认值,不能为空
            // if (width > 0) {
            // }
            _attr['stroke-width'] = width;
            if (attrs.border.opacity != 1) {
                _attr['stroke-opacity'] = attrs.border.opacity || 1;
            }
            if (attrs.border.dashed) {
                _attr['stroke-dasharray'] = Array.isArray(attrs.border.dashed) ? attrs.border.dashed.join(' ') : svg_default_stroke_dasharray;
            }
        }
    }
    function fillAndStroke(attrs, _attr) {
        if (attrs.fill) {
            if (attrs.fill.type == 'linearGradient') {
                let ret = createLinearGradient(attrs.fill);
                defs.push(ret.json);
                _attr.fill = `url(#${ret.id})`;
            }
        }
        else {
            if (attrs.color) {
                _attr.fill = attrs.color;
            }
            else {
                _attr.fill = 'none';
            }
        }
        setStroke(attrs, _attr);
    }
    function handleShadow(attrs, _attr, node) {
        if (attrs.shadow) {
            let ret = createShadow(attrs.shadow, node);
            defs.push(ret.json);
            _attr.filter = `url(#${ret.id})`;
        }
        if (attrs.innerShadow) {
            let ret = createInnerShadow(attrs.innerShadow, node);
            defs.push(ret.json);
            _attr.filter = `url(#${ret.id})`;
        }
    }
    function handleCommon(node, attrs) {
        handleBlur(node, attrs);
    }
    function handleBlur(node, attrs) {
        if (node.blur) {
            let ret = createBlur(node.blur, node);
            defs.push(ret.json);
            attrs.filter = `url(#${ret.id})`;
        }
    }
    function handleOpacity(attrs, _attr) {
        if (attrs.opacity) {
            _attr.opacity = attrs.opacity;
        }
    }
    let out = helper_1.uiUtil.treeMap(rootObj, {
        childrenKey: '_children',
        nodeHandler(node) {
            var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
            // let type
            let attrs = {};
            for (let key in node) {
                if (!key.match(/^_/)) {
                    attrs[key] = node[key];
                }
            }
            // if (node._type == 'root') {
            //     type = 'root'
            // } else if (node._type == 'tag') {
            //     type = node.name
            //     attrs = node.attribs
            // } else {
            //     if (node._type == 'text') {
            //         console.log('node', node)
            //         const { data } = node
            //         if (data.match(/^\s+$/)) {
            //             return null
            //         }
            //     } 
            //     type = 'other:' + node._type
            // }
            let _type = node._type;
            if (_type === 'root') {
                const attrs = {
                    xmlns: 'http://www.w3.org/2000/svg',
                    version: '1.1',
                };
                if (node.width) {
                    attrs.width = node.width;
                }
                if (node.height) {
                    attrs.height = node.height;
                }
                return {
                    type: 'svg',
                    attr: Object.assign(Object.assign({}, attrs), node._svgProps),
                };
            }
            if (_type === StdUiNodeType.Rect) {
                let _attr = {};
                const borderPosition = ((_a = node.border) === null || _a === void 0 ? void 0 : _a.position) || toSvgOpts.borderPosition;
                const borderWidth = ((_b = attrs.border) === null || _b === void 0 ? void 0 : _b.width) || 0;
                if (borderPosition == BorderPositionKey.Inside) {
                    _attr.x = attrs.x + borderWidth / 2;
                    _attr.y = attrs.y + borderWidth / 2;
                    _attr.width = attrs.width - borderWidth;
                    _attr.height = attrs.height - borderWidth;
                }
                else if (borderPosition == BorderPositionKey.Center) {
                    // const borderWidth = attrs.border?.width || 0
                    _attr.x = attrs.x;
                    _attr.y = attrs.y;
                    // _attr.width = attrs.width - borderWidth / 2
                    // _attr.height = attrs.height - borderWidth / 2
                    _attr.width = attrs.width;
                    _attr.height = attrs.height;
                }
                else {
                    // borderPosition == BorderPositionKey.Outside
                    _attr.x = attrs.x - borderWidth / 2;
                    _attr.y = attrs.y - borderWidth / 2;
                    _attr.width = attrs.width + borderWidth;
                    _attr.height = attrs.height + borderWidth;
                }
                // let _attr = objectSomeAttr(attrs, ['width', 'height', 'x', 'y'])
                fillAndStroke(attrs, _attr);
                if (attrs.radius) {
                    _attr.rx = attrs.radius;
                    _attr.ry = attrs.radius;
                }
                handleShadow(attrs, _attr, node);
                handleOpacity(attrs, _attr);
                handleCommon(node, _attr);
                if (attrs.borderRadius) {
                    _attr.rx = attrs.borderRadius;
                    _attr.ry = attrs.borderRadius;
                }
                const center = {
                    x: _attr.x + _attr.width / 2,
                    y: _attr.y + _attr.height / 2,
                };
                let _node = {
                    type: 'rect',
                    attr: Object.assign(Object.assign(Object.assign({}, _attr), node._svgProps), { transform: getTransform(node, center) || undefined, style: getStyleText(node) || undefined }),
                };
                return _node;
            }
            if (_type === 'image') {
                let _attr = {};
                if (BORDER_INSIDE && !(toSvgOpts === null || toSvgOpts === void 0 ? void 0 : toSvgOpts.forceImage)) {
                    const borderWidth = ((_c = attrs.border) === null || _c === void 0 ? void 0 : _c.width) || 0;
                    _attr.x = attrs.x + borderWidth / 2;
                    _attr.y = attrs.y + borderWidth / 2;
                    _attr.width = attrs.width - borderWidth;
                    _attr.height = attrs.height - borderWidth;
                }
                else {
                    _attr.x = attrs.x;
                    _attr.y = attrs.y;
                    _attr.width = attrs.width;
                    _attr.height = attrs.height;
                }
                // fillAndStroke(attrs, _attr)
                setStroke(attrs, _attr);
                if (attrs.radius) {
                    _attr.rx = attrs.radius;
                    _attr.ry = attrs.radius;
                }
                if (!(toSvgOpts === null || toSvgOpts === void 0 ? void 0 : toSvgOpts.forceImage)) {
                    createImage(node, _attr, defs);
                }
                // defs.push(ret.json)
                // _attr.fill = `url(#pattern0)`
                handleShadow(attrs, _attr, node);
                handleOpacity(attrs, _attr);
                setStroke(attrs, _attr);
                handleCommon(node, _attr);
                if (attrs.borderRadius) {
                    _attr.rx = attrs.borderRadius;
                    _attr.ry = attrs.borderRadius;
                }
                const center = {
                    x: _attr.x + _attr.width / 2,
                    y: _attr.y + _attr.height / 2,
                };
                if (toSvgOpts === null || toSvgOpts === void 0 ? void 0 : toSvgOpts.forceImage) {
                    _attr.href = attrs.href;
                    let _node = {
                        type: 'image',
                        attr: Object.assign(Object.assign(Object.assign({}, _attr), node._svgProps), { transform: getTransform(node, center) || undefined, style: getStyleText(node) || undefined }),
                    };
                    return _node;
                }
                else {
                    let _node = {
                        type: 'rect',
                        attr: Object.assign(Object.assign(Object.assign({}, _attr), node._svgProps), { transform: getTransform(node, center) || undefined, style: getStyleText(node) || undefined }),
                    };
                    return _node;
                }
            }
            if (_type === StdUiNodeType.Circle) {
                // let _attr: any = {}
                let _attr = objectSomeAttr(attrs, ['cx', 'cy']);
                fillAndStroke(attrs, _attr);
                handleShadow(attrs, _attr, node);
                handleOpacity(attrs, _attr);
                if (!attrs.radius) {
                    throw new Error('circle need radius attr');
                }
                const borderPosition = ((_d = node.border) === null || _d === void 0 ? void 0 : _d.position) || toSvgOpts.borderPosition;
                const borderWidth = ((_e = attrs.border) === null || _e === void 0 ? void 0 : _e.width) || 0;
                if (borderPosition == BorderPositionKey.Inside) {
                    _attr.r = attrs.radius - borderWidth / 2;
                }
                else if (borderPosition == BorderPositionKey.Center) {
                    _attr.r = attrs.radius;
                    // _attr.r = attrs.radius - borderWidth / 4
                }
                else {
                    // outside
                    _attr.r = attrs.radius + borderWidth / 2;
                }
                const center = {
                    x: _attr.cx,
                    y: _attr.cy,
                };
                let _node = {
                    type: 'circle',
                    attr: Object.assign(Object.assign(Object.assign({}, _attr), node._svgProps), { transform: getTransform(node, center) || undefined, style: getStyleText(node) || undefined }),
                };
                return _node;
            }
            if (_type === StdUiNodeType.Text) {
                let _attr = objectSomeAttr(attrs, ['x', 'y']);
                let _style = Object.assign({}, getStyle(node));
                const lineHeight = node.lineHeight || attrs.textSize * 1; // TODO
                const fontSize = node.textSize || 12;
                if (attrs.textSize) {
                    // Sketch 默认行高 1.4
                    // 
                    _style['font-size'] = `${attrs.textSize}px`;
                    _style['line-height'] = `${lineHeight}px`;
                }
                if (attrs.fontFamily) {
                    _style['font-family'] = `${attrs.fontFamily}`;
                }
                // style += `outline: 1px dashed #666;`
                const { fontStyle = {} } = node;
                const { bold = false, italic = false, underline = false } = fontStyle;
                if (bold) {
                    _style['font-weight'] = `bold`;
                }
                if (italic) {
                    _style['font-style'] = `italic`;
                }
                if (underline) {
                    _style['text-decoration'] = `underline`;
                }
                const extraStyle = node._svgStyle || {};
                for (let key in extraStyle) {
                    _style[key] = extraStyle[key];
                }
                fillAndStroke(attrs, _attr);
                handleShadow(attrs, _attr, node);
                handleOpacity(attrs, _attr);
                _attr.style = styleToText(_style);
                // _attr['dominant-baseline'] = 'text-before-edge'
                // refer https://www.zhihu.com/question/58620241
                // _attr['alignment-baseline'] = 'before-edge'
                _attr['alignment-baseline'] = 'hanging';
                // Attribute("alignment-baseline", "hanging");
                if (attrs.centerd) {
                    _attr['text-anchor'] = 'middle'; // 水平方向居中
                    _attr['alignment-baseline'] = undefined;
                    _attr['dominant-baseline'] = 'middle';
                    // : ; 
                    // : middle; //垂直居中
                }
                if (attrs.align == exports.ui.Align.Center) {
                    _attr['text-anchor'] = 'middle'; // 水平方向居中
                    if (attrs.width) {
                        _attr.x = parseFloat(attrs.x) + parseFloat(attrs.width) / 2;
                    }
                }
                if (attrs.vAlign == exports.ui.Align.Center) {
                    _attr['alignment-baseline'] = 'middle';
                    // _attr['dominant-baseline'] = 'middle'
                    if (attrs.height) {
                        _attr.y = parseFloat(attrs.y) + parseFloat(attrs.height) / 2;
                    }
                }
                if (attrs.backgroundColor) {
                    const id = createTextBg(attrs.backgroundColor);
                    _attr.filter = `url(#${id})`;
                }
                // baselineY = lineHeight ? fontSize
                // 105 = (140 - 100) / 2 + 100 * 0.85
                // 136 = (200 - 100) / 2 + 100 * 0.85
                // 143 = (200 - 120) / 2 + 120 * 0.8583333333333333
                // baselineY = (lineHeight - fontSize) / 2 + fontSize * 0.8583333333333333
                const baselineY = (lineHeight - fontSize) / 2 + fontSize * 0.8583333333333333;
                const children = [];
                if (node.rich) {
                    node.rich.forEach((row, rowIdx) => {
                        row.forEach((cell, colIdx) => {
                            const attr = {
                                // x: _attr.x,
                                // y: _attr.y + lineHeight,
                                y: _attr.y + rowIdx * lineHeight + baselineY,
                            };
                            if (colIdx == 0) {
                                attr.x = _attr.x;
                            }
                            const _style = {};
                            const extraStyle = cell._svgStyle || {};
                            for (let key in extraStyle) {
                                _style[key] = extraStyle[key];
                            }
                            attr.style = styleToText(_style);
                            children.push({
                                type: 'tspan',
                                attr: Object.assign(Object.assign({}, attr), cell._svgProps),
                                _data: cell.text,
                            });
                        });
                    });
                }
                else {
                    const lines = attrs.text.split('\n');
                    lines.forEach((line, lineIdx) => {
                        children.push({
                            type: 'tspan',
                            attr: {
                                x: _attr.x,
                                // y: _attr.y + lineHeight,
                                y: _attr.y + lineIdx * lineHeight + baselineY,
                            },
                            _data: line
                        });
                    });
                }
                let _node = {
                    type: 'text',
                    attr: Object.assign(Object.assign({}, _attr), node._svgProps),
                    // _data: attrs.text
                    children,
                    // children: [
                    //     {
                    //     },
                    //     // {
                    //     //     type: 'tspan',
                    //     //     // attr: {
                    //     //     //     x: _attr.x,
                    //     //     //     y: _attr.y + lineHeight,
                    //     //     // },
                    //     //     _data: 'append'
                    //     // }
                    // ]
                };
                // < tspan xmlns = "http://www.w3.org/2000/svg" x = "100" y = "106" > 你好 < /tspan>
                return _node;
            }
            if (_type === 'line') {
                let _attr = objectSomeAttr(attrs, ['x1', 'y1', 'x2', 'y2']);
                handleOpacity(attrs, _attr);
                // if (attrs.radius) {
                //     _attr.r = attrs.radius
                // }
                // if (attrs.color) {
                //     _attr.fill = attrs.color
                // }
                // let style = ''
                // if (attrs.textSize) {
                //     style += `font-size: ${attrs.textSize}px`
                // }
                // _attr.style = style
                // _attr['stroke'] = '#000'
                // if (attrs.color) {
                //     _attr.stroke = attrs.color
                // } else {
                //     _attr.stroke = '#000'
                // }
                // _attr['stroke-width'] = 1
                const { border = {} } = attrs;
                const { color = '#000', width = 1 } = border;
                _attr.stroke = color;
                _attr['stroke-width'] = width;
                const center = {
                    x: (_attr.x1 + _attr.x2) / 2,
                    y: (_attr.y1 + _attr.y2) / 2,
                };
                let _node = {
                    type: 'line',
                    attr: Object.assign(Object.assign(Object.assign({}, _attr), node._svgProps), { transform: getTransform(node, center) || undefined, style: getStyleText(node) || undefined }),
                    // _data: attrs.text
                    // _attrs: attrs,
                };
                // < tspan xmlns = "http://www.w3.org/2000/svg" x = "100" y = "106" > 你好 < /tspan>
                return _node;
            }
            if (_type === StdUiNodeType.Polygon) {
                let _attr = objectSomeAttr(attrs, []);
                const { left, top, width, height } = calcPolygon(node);
                const center = {
                    x: left + width / 2,
                    y: top + height / 2,
                };
                fillAndStroke(attrs, _attr);
                handleShadow(attrs, _attr, node);
                handleOpacity(attrs, _attr);
                if (attrs.points) {
                    const borderPosition = ((_f = node.border) === null || _f === void 0 ? void 0 : _f.position) || toSvgOpts.borderPosition;
                    const borderWidth = ((_g = attrs.border) === null || _g === void 0 ? void 0 : _g.width) || 0;
                    if (borderPosition == BorderPositionKey.Inside || borderPosition == BorderPositionKey.Outside) {
                        const scale = (width - borderWidth * (borderPosition == BorderPositionKey.Inside ? 1 : -1)) / width;
                        _attr['points'] = attrs.points.map(pt => `${pt.x},${pt.y}`).join(' ');
                        _attr['points'] = attrs.points
                            .map(pt => {
                            return {
                                x: center.x + (pt.x - center.x) * scale,
                                y: center.y + (pt.y - center.y) * scale,
                            };
                        })
                            .map(pt => `${pt.x},${pt.y}`).join(' ');
                    }
                    else {
                        _attr['points'] = attrs.points.map(pt => `${pt.x},${pt.y}`).join(' ');
                    }
                }
                let _node = {
                    type: 'polygon',
                    attr: Object.assign(Object.assign(Object.assign({}, _attr), node._svgProps), { transform: getTransform(node, center) || undefined, style: getStyleText(node) || undefined }),
                    // _attrs: attrs,
                };
                return _node;
            }
            if (_type === 'polyline') {
                let _attr = objectSomeAttr(attrs, []);
                // if (attrs.color) {
                //     _attr.fill = attrs.color
                // } else {
                //     _attr.fill = 'none'
                // }
                const { left, top, width: _width, height } = calcPolygon(node);
                const center = {
                    x: left + _width / 2,
                    y: top + height / 2,
                };
                const { border = {} } = attrs;
                const { color = '#000', width = 1 } = border;
                _attr.stroke = color;
                _attr['stroke-width'] = width;
                handleOpacity(attrs, _attr);
                // if (attrs.border) {
                // } else {
                // }
                // if (attrs.color) {
                //     _attr.stroke = attrs.color
                // } else {
                //     _attr.stroke = '#000'
                // }
                _attr.fill = 'none';
                if (attrs.points) {
                    _attr['points'] = attrs.points.map(pt => `${pt.x},${pt.y}`).join(' ');
                }
                // if (attrs.radius) {
                //     _attr.rx = attrs.radius
                //     _attr.ry = attrs.radius
                // }
                let _node = {
                    type: 'polyline',
                    attr: Object.assign(Object.assign(Object.assign({}, _attr), node._svgProps), { transform: getTransform(node, center) || undefined, style: getStyleText(node) || undefined }),
                    // _attrs: attrs,
                };
                return _node;
            }
            if (_type === StdUiNodeType.Ellipse) {
                let _attr = {};
                _attr.cx = attrs.cx;
                _attr.cy = attrs.cy;
                const borderPosition = ((_h = node.border) === null || _h === void 0 ? void 0 : _h.position) || toSvgOpts.borderPosition;
                const borderWidth = ((_j = attrs.border) === null || _j === void 0 ? void 0 : _j.width) || 0;
                if (borderPosition == BorderPositionKey.Inside) {
                    _attr.rx = attrs.rx - borderWidth / 2;
                    _attr.ry = attrs.ry - borderWidth / 2;
                }
                else if (borderPosition == BorderPositionKey.Center) {
                    _attr.rx = attrs.rx - borderWidth / 4;
                    _attr.ry = attrs.ry - borderWidth / 4;
                }
                else {
                    // outside
                    _attr.rx = attrs.rx;
                    _attr.ry = attrs.ry;
                }
                fillAndStroke(attrs, _attr);
                handleShadow(attrs, _attr, node);
                handleOpacity(attrs, _attr);
                let _node = {
                    type: 'ellipse',
                    attr: Object.assign(Object.assign(Object.assign({}, _attr), node._svgProps), { transform: getTransform(node, { x: attrs.cx, y: attrs.cy }) || undefined, style: getStyleText(node) || undefined }),
                    // _attrs: attrs,
                };
                return _node;
            }
            if (_type === 'path') {
                let _attr = {};
                fillAndStroke(attrs, _attr);
                handleShadow(attrs, _attr, node);
                handleOpacity(attrs, _attr);
                // if (attrs.points) {
                //     _attr['points'] = attrs.points.map(pt => `${pt.x},${pt.y}`).join(' ')
                // }
                // let borderWidth = 0
                // if (attrs.border) {
                //     // _attr.stroke = attrs.border.color || '#000'
                //     borderWidth = attrs.border.width || 1
                // }
                let pathD = attrs.d;
                // console.log('pathD', pathD)
                const bbox = caster(pathD);
                const center = {
                    x: bbox.x1 + bbox.width / 2,
                    y: bbox.y1 + bbox.height / 2,
                };
                const borderPosition = ((_k = node.border) === null || _k === void 0 ? void 0 : _k.position) || toSvgOpts.borderPosition;
                const borderWidth = ((_l = attrs.border) === null || _l === void 0 ? void 0 : _l.width) || 0;
                if (borderPosition == BorderPositionKey.Inside) {
                    // const bbox = caster(pathD)
                    if (bbox.width != 0) {
                        // console.log('bbox', bbox, (bbox.width - (borderWidth)) / bbox.width)
                        const transformedD = svgpath(pathD)
                            .translate(-bbox.x1, -bbox.y1)
                            .scale((bbox.width - (borderWidth)) / bbox.width)
                            // .rel()
                            .translate(bbox.x1 + borderWidth / 2, bbox.y1 + borderWidth / 2)
                            // .round(1)
                            .toString();
                        pathD = transformedD;
                        // console.log('pathD', pathD)
                    }
                }
                else if (borderPosition == BorderPositionKey.Outside) {
                    // const bbox = caster(pathD)
                    if (bbox.width != 0) {
                        // console.log('bbox', bbox, (bbox.width - (borderWidth)) / bbox.width)
                        const transformedD = svgpath(pathD)
                            .translate(-bbox.x1, -bbox.y1)
                            .scale((bbox.width + (borderWidth)) / bbox.width)
                            // .rel()
                            .translate(bbox.x1 - borderWidth / 2, bbox.y1 - borderWidth / 2)
                            // .round(1)
                            .toString();
                        pathD = transformedD;
                        // console.log('pathD', pathD)
                    }
                }
                _attr.d = pathD;
                // breakPoint()
                if (node.arrow) {
                    const { start = false, end = false } = node.arrow;
                    function addArrow(direction, type) {
                        var _a;
                        const markerId = (0, helper_1.uid)(16);
                        // 0 14
                        // 10 30
                        const markerLength = 14 + borderWidth * ((30 - 14) / (10 - 0));
                        // const markerWidth = borderWidth + 10
                        // const markerLength = 30
                        // 0 10
                        // 10 26
                        const markerWidth = 10 + borderWidth * ((26 - 10) / (10 - 0));
                        // const markerWidth = 26
                        const markerColor = ((_a = node.border) === null || _a === void 0 ? void 0 : _a.color) || '#000';
                        // console.log('markerWidth', markerWidth)
                        // console.log('markerLength', markerLength)
                        // console.log('refX', markerLength / 30 * 18)
                        // breakPoint()
                        defs.push({
                            type: 'marker',
                            attr: {
                                xmlns: "http://www.w3.org/2000/svg",
                                id: markerId,
                                markerWidth: markerLength,
                                markerHeight: markerWidth,
                                refX: markerLength / 30 * 18,
                                refY: markerWidth / 2,
                                viewBox: `0 0 ${markerLength} ${markerWidth}`,
                                orient: "auto",
                                markerUnits: "userSpaceOnUse",
                                // 'stroke-dasharray': "0,0",
                            },
                            children: [
                                {
                                    type: 'path',
                                    attr: {
                                        // end
                                        d: direction == 'start' ? `M${markerLength},0 L0,${markerWidth / 2} L${markerLength},${markerWidth} L${markerLength},0`
                                            : `M0,0 L${markerLength},${markerWidth / 2} L0,${markerWidth} L0,0`,
                                        // d: direction == 'start' ? `M${markerLength},0 L0,${markerWidth / 2} L${markerLength},${markerWidth}`
                                        //     : `M0,0 L${markerLength},${markerWidth / 2} L0,${markerWidth}`,
                                        // fill: 'none',
                                        fill: type == 'normal' ? 'none' : type == 'dashedArrow' ? '#fff' : markerColor,
                                        stroke: markerColor,
                                        'stroke-width': "2",
                                    }
                                }
                            ]
                        });
                        _attr['marker-' + direction] = `url(#${markerId})`;
                    }
                    if (start) {
                        addArrow('start', start);
                    }
                    if (end) {
                        addArrow('end', end);
                    }
                }
                let _node = {
                    type: 'path',
                    attr: Object.assign(Object.assign(Object.assign({}, _attr), node._svgProps), { transform: getTransform(node, center) || undefined, style: getStyleText(node) || undefined }),
                };
                return _node;
            }
            if (_type === 'group') {
                let _attr = objectSomeAttr(attrs, ['d']);
                handleOpacity(attrs, _attr);
                let _node = {
                    type: 'g',
                    attr: Object.assign(Object.assign(Object.assign({}, _attr), node._svgProps), { style: getStyleText(node) || undefined }),
                    // _attrs: attrs,
                };
                return _node;
            }
            if (attrs.border) {
                attrs.stroke = attrs.border.color;
                attrs['stroke-width'] = attrs.border.width || 1;
                // TODO
                delete attrs.border;
            }
            let result = {
                type: node._type,
                // children: node._children as any,
                attr: Object.assign(Object.assign({}, attrs), node._svgProps),
                // _attrs: attrs,
                // _type: type,
                // ...attrs,
            };
            return result;
        }
    });
    function createImage(node, _attr, defs) {
        const patternId = `pattern${(0, helper_1.uid)(8)}`;
        const imgId = `image${(0, helper_1.uid)(8)}`;
        defs.push({
            type: 'pattern',
            attr: {
                id: patternId,
                patternContentUnits: "objectBoundingBox",
                width: "1",
                height: "1",
            },
            children: [
                {
                    type: 'use',
                    attr: {
                        href: `#${imgId}`,
                        transform: "scale(0.005)",
                    },
                }
            ]
        });
        defs.push({
            type: 'image',
            attr: {
                id: imgId,
                width: node.originWidth,
                height: node.originWidth,
                // width: 200,
                // height: 200,
                href: node.href,
            }
        });
        _attr.fill = `url(#${patternId})`;
    }
    function createLinearGradient(gradient) {
        const { direction, colors = [], stops = [], from, to } = gradient;
        // colors: ['#09c', '#c90'],
        const [color1, color2] = colors;
        const id = (0, helper_1.uid)(8);
        let dradientAttrs = {
            right: {
                x1: "0%",
                y1: "0%",
                x2: "100%",
                y2: "0%",
            },
            left: {
                x1: "100%",
                y1: "0%",
                x2: "0%",
                y2: "0%",
            },
            top: {
                x1: "0%",
                y1: "100%",
                x2: "0%",
                y2: "0%",
            },
            bottom: {
                x1: "0%",
                y1: "0%",
                x2: "0%",
                y2: "100%",
            },
        };
        let dradientAttr;
        if (from && to) {
            dradientAttr = {
                x1: (from.x * 100) + '%',
                y1: (from.y * 100) + '%',
                x2: (to.x * 100) + '%',
                y2: (to.y * 100) + '%',
            };
        }
        else if (typeof direction == 'string') {
            dradientAttr = dradientAttrs[direction];
        }
        else {
            const coordinates = angleToCoordinates(direction);
            dradientAttr = {
                x1: (coordinates.x1 * 100) + '%',
                y1: (coordinates.y1 * 100) + '%',
                x2: (coordinates.x2 * 100) + '%',
                y2: (coordinates.y2 * 100) + '%',
            };
            // console.log('coordinates', coordinates)
            // throw new Error('asd')
        }
        // if (direction == 'right') {
        //     dradientAttr = 
        // }
        let children;
        if (stops.length > 0) {
            children = stops.map(stop => {
                return {
                    type: 'stop',
                    attr: {
                        offset: (stop.position * 100) + '%',
                        style: `stop-color:${stop.color};stop-opacity:1`,
                    },
                };
            });
            // ret['background-image'] = `linear-gradient(to ${gradient.direction}deg, ${gradient.stops.map(stop => `${stop.color}`).join(', ')})`
        }
        else {
            children = [
                {
                    type: 'stop',
                    attr: {
                        offset: "0%",
                        style: `stop-color:${color1};stop-opacity:1`,
                    },
                },
                {
                    type: 'stop',
                    attr: {
                        offset: "100%",
                        style: `stop-color:${color2};stop-opacity:1`,
                    },
                },
            ];
        }
        return {
            id,
            json: {
                type: 'linearGradient',
                attr: Object.assign({ id }, dradientAttr),
                children,
            }
        };
    }
    // bg
    out.children = [
        {
            type: 'defs',
            attr: {},
            children: defs,
        },
        // 背景在前面
        {
            type: 'rect',
            attr: {
                x: 0,
                y: 0,
                width: rootObj.width,
                height: rootObj.height,
                fill: rootObj.color == null ? 'none' : (rootObj.color || '#fff'),
            },
        },
        {
            type: 'g',
            attr: {},
            children: out.children,
        },
    ];
    // out.children.unshift()
    // console.debug(out)
    return out;
}
// html css box-sizing border-box 默认 inside
// svg default center
// Sketch default center,can set
const BorderPositionKey = {
    Inside: 'inside',
    Outside: 'outside',
    Center: 'center',
};
class StdUI {
    constructor(doc) {
        this.root = doc.root;
    }
    toSvg(toSvgOpts) {
        // console.log('svgObj', JSON.stringify(convertUiObj2SvgObject(uiObj), null, 4))
        // fs.writeFileSync('out.svg', , 'utf8')
        const result = helper_1.uiUtil.xmlObj2Xml(convertUiObj2SvgObject(this.root, toSvgOpts));
        return result.replace(/\s+?<tspan/g, '<tspan');
    }
    toProcessOn() {
        function createNode(node, otherAttr) {
            let fillStyle = {};
            if (node.color) {
                const color = Color(node.color);
                // console.log('color', )
                fillStyle = {
                    color: color.rgb().array().join(','),
                    "type": "solid"
                };
            }
            return Object.assign({ "parent": "", "link": "", "shapeStyle": {
                    "alpha": 1
                }, "textBlock": [
                    {
                        "position": {
                            "w": "w-20",
                            "x": 10,
                            "h": "h",
                            "y": 0
                        },
                        "text": ""
                    }
                ], "lineStyle": {}, "children": [], "resizeDir": [
                    "tl",
                    "tr",
                    "br",
                    "bl"
                ], fillStyle, "theme": {}, "category": "basic", "locked": false, "group": "" }, otherAttr);
        }
        function createRect(node) {
            return createNode(node, {
                "name": "rectangle",
                "anchors": [
                    {
                        "x": "w/2",
                        "y": "0"
                    },
                    {
                        "x": "w/2",
                        "y": "h"
                    },
                    {
                        "x": "0",
                        "y": "h/2"
                    },
                    {
                        "x": "w",
                        "y": "h/2"
                    }
                ],
                "title": "矩形",
                "props": {
                    "zindex": 1,
                    "w": node.width,
                    "x": node.x,
                    "h": node.height,
                    "y": node.y,
                    "angle": 0
                },
                "path": [
                    {
                        "actions": [
                            {
                                "x": "0",
                                "action": "move",
                                "y": "0"
                            },
                            {
                                "x": "w",
                                "action": "line",
                                "y": "0"
                            },
                            {
                                "x": "w",
                                "action": "line",
                                "y": "h"
                            },
                            {
                                "x": "0",
                                "action": "line",
                                "y": "h"
                            },
                            {
                                "action": "close"
                            }
                        ]
                    }
                ],
                "id": (0, helper_1.uid)(13),
                "attribute": {
                    "container": false,
                    "rotatable": true,
                    "visible": true,
                    "collapsable": false,
                    "collapsed": false,
                    "linkable": true,
                    "markerOffset": 5
                },
            });
        }
        function createCircle(node) {
            return createNode(node, {
                "textBlock": [
                    {
                        "position": {
                            "w": "w-20",
                            "x": 10,
                            "h": "h",
                            "y": 0
                        },
                        "text": ""
                    }
                ],
                "anchors": [
                    {
                        "x": "w/2",
                        "y": "0"
                    },
                    {
                        "x": "w/2",
                        "y": "h"
                    },
                    {
                        "x": "0",
                        "y": "h/2"
                    },
                    {
                        "x": "w",
                        "y": "h/2"
                    }
                ],
                "title": "圆形",
                "fontStyle": {},
                "dataAttributes": [],
                "props": {
                    "zindex": 1,
                    "x": node.cx - node.radius,
                    "y": node.cy - node.radius,
                    "w": node.radius * 2,
                    "h": node.radius * 2,
                    "angle": 0
                },
                "path": [
                    {
                        "actions": [
                            {
                                "x": "0",
                                "action": "move",
                                "y": "h/2"
                            },
                            {
                                "y1": "-h/6",
                                "x": "w",
                                "action": "curve",
                                "x1": "0",
                                "y2": "-h/6",
                                "y": "h/2",
                                "x2": "w"
                            },
                            {
                                "y1": "h+h/6",
                                "x": "0",
                                "action": "curve",
                                "x1": "w",
                                "y2": "h+h/6",
                                "y": "h/2",
                                "x2": "0"
                            },
                            {
                                "action": "close"
                            }
                        ]
                    }
                ],
                "lineStyle": {},
                "children": [],
                "resizeDir": [
                    "tl",
                    "tr",
                    "br",
                    "bl"
                ],
                "name": "round",
                "theme": {},
                "id": (0, helper_1.uid)(13),
                "attribute": {
                    "container": false,
                    "rotatable": true,
                    "visible": true,
                    "collapsable": false,
                    "collapsed": false,
                    "linkable": true,
                    "markerOffset": 5
                },
            });
        }
        function createLine(node) {
            return {
                "linkerType": "normal",
                "lineStyle": {
                    "endArrowStyle": "none"
                },
                "name": "linker",
                "from": {
                    "x": node.x1,
                    "y": node.y1
                },
                "to": {
                    "x": node.x2,
                    "y": node.y2
                },
                "id": (0, helper_1.uid)(14),
                "text": "",
                "locked": false,
                "props": {
                    "zindex": 1
                },
                "dataAttributes": [],
                "group": "",
                "points": []
            };
        }
        function createText(node) {
            let fontStyle = {
                size: node.textSize || 14
            };
            const color = Color(node.color);
            // console.log('color', )
            if (node.color) {
                fontStyle.color = color.rgb().array().join(',');
            }
            return createNode(node, {
                "name": "text",
                "parent": "",
                "link": "",
                "shapeStyle": {
                    "alpha": 1
                },
                "textBlock": [
                    {
                        "position": {
                            "w": "w",
                            "x": 0,
                            "h": "h",
                            "y": 0
                        },
                        "text": node.text
                    }
                ],
                "anchors": [
                    {
                        "x": "w/2",
                        "y": "0"
                    },
                    {
                        "x": "w/2",
                        "y": "h"
                    },
                    {
                        "x": "0",
                        "y": "h/2"
                    },
                    {
                        "x": "w",
                        "y": "h/2"
                    }
                ],
                "title": "文本",
                fontStyle,
                "props": {
                    "zindex": 1,
                    "x": node.x,
                    "w": (node.textSize || 14) * node.text.length,
                    "h": node.textSize || 14,
                    "y": node.y,
                    "angle": 0
                },
                "path": [
                    {
                        "lineStyle": {
                            "lineWidth": 0
                        },
                        "fillStyle": {
                            "type": "none"
                        },
                        "actions": [
                            {
                                "x": "0",
                                "action": "move",
                                "y": "0"
                            },
                            {
                                "x": "w",
                                "action": "line",
                                "y": "0"
                            },
                            {
                                "x": "w",
                                "action": "line",
                                "y": "h"
                            },
                            {
                                "x": "0",
                                "action": "line",
                                "y": "h"
                            },
                            {
                                "action": "close"
                            }
                        ]
                    }
                ],
                "lineStyle": {
                    "lineColor": "229,115,115"
                },
                "children": [],
                "resizeDir": [
                    "tl",
                    "tr",
                    "br",
                    "bl"
                ],
                "theme": {},
                "attribute": {
                    "container": false,
                    "rotatable": true,
                    "visible": true,
                    "collapsable": false,
                    "collapsed": false,
                    "linkable": true,
                    "markerOffset": 5
                },
                "category": "basic",
                "locked": false,
                "group": ""
            });
        }
        let elementMap = {};
        helper_1.uiUtil.treeMap(this.root, {
            childrenKey: '_children',
            nodeHandler(node) {
                if (node._type == 'rect') {
                    let rect = createRect(node);
                    elementMap[rect.id] = rect;
                    return rect;
                }
                if (node._type == 'circle') {
                    let rect = createCircle(node);
                    elementMap[rect.id] = rect;
                    return rect;
                }
                if (node._type == 'line') {
                    let rect = createLine(node);
                    elementMap[rect.id] = rect;
                    return rect;
                }
                if (node._type == 'text') {
                    let rect = createText(node);
                    elementMap[rect.id] = rect;
                    return rect;
                }
                // if (node._type == 'text') {
                //     let rect = createText(node)
                //     elementMap[rect.id] = rect
                // }
                return {};
                // TODO 没有适配 root
                // throw new Error(`unknow type ${node._type}`)
            }
        });
        const obj = {
            "diagram": {
                "elements": {
                    "elements": elementMap,
                    "page": {
                        "padding": 0,
                        "backgroundColor": "transparent",
                        "orientation": "portrait",
                        "gridSize": 25,
                        "width": this.root.width,
                        "showGrid": true,
                        "lineJumps": false,
                        "height": this.root.height,
                    }
                }
            },
            "meta": {
                "diagramInfo": {
                    "title": "未命名文件",
                    "category": "flow"
                },
                "id": "6132cea2e0b34d35500338d3",
                "type": "ProcessOn Schema File",
                "version": "1.0"
            }
        };
        return JSON.stringify(obj, null, 4);
    }
    toHtml() {
        return helper_1.uiUtil.xmlObj2Xml(convertUiObj2HtmlObject(this.root));
    }
}
exports.StdUI = StdUI;
//# sourceMappingURL=index.js.map