Răsfoiți Sursa

更改存储结构为本地

huangyan 6 luni în urmă
părinte
comite
bd99288ead

+ 26 - 18
backend/app/controller/file.go

@@ -26,6 +26,7 @@ type Template struct {
 	Data     any    `json:"data" validate:"required"`
 	Type     int    `json:"type" validate:"required"`
 	ImageUrl string `json:"imageUrl" validate:"required"`
+	DataUrl  string `json:"dataUrl" validate:"required"`
 }
 
 // SaveTemplate 保存文件到MongoDB
@@ -67,19 +68,25 @@ func SaveTemplate(c *gin.Context) {
 		if err != nil {
 			simple_zap.WithCtx(context.TODO()).Sugar().Warn(err, "base64解码失败")
 			e2.ResponseWithMsg(c, e2.ERROR, "图片转换失败")
-			panic(err)
 			return
 		}
 		var url = global.DownloadSetting.Imageurl + file.Name + ".png"
+		err := utils.SaveDataToFile(file.Data, file.Name)
+		if err != nil {
+			simple_zap.WithCtx(context.TODO()).Sugar().Warn(err, "写入文件失败")
+			e2.ResponseWithMsg(c, e2.ERROR, "写入文件失败")
+		}
+		var dataurl = global.DownloadSetting.FileUrl + file.Name + ".json"
 		doc := bson.M{
-			"name": file.Name,
-			"type": file.Type,
-			"data": file.Data,
-			"uuid": uuid,
-			"url":  url,
+			"name":    file.Name,
+			"type":    file.Type,
+			"data":    nil,
+			"uuid":    uuid,
+			"url":     url,
+			"dataurl": dataurl,
 		}
 		// 当文件名字相同并且文件类型为1是替换文件
-		_, err := global.MongoCon.ReplaceOne(context.TODO(), filter, doc, options.Replace().SetUpsert(true))
+		_, err = global.MongoCon.ReplaceOne(context.TODO(), filter, doc, options.Replace().SetUpsert(true))
 		if err != nil {
 			simple_zap.WithCtx(context.TODO()).Sugar().Warn(err, "替换文件失败")
 			e2.ResponseWithMsg(c, e2.ERROR, "替换文件失败")
@@ -98,12 +105,19 @@ func SaveTemplate(c *gin.Context) {
 		return
 	}
 	var url = global.DownloadSetting.Imageurl + file.Name + formatInt + ".png"
+	err = utils.SaveDataToFile(file.Data, file.Name+formatInt)
+	if err != nil {
+		simple_zap.WithCtx(context.TODO()).Sugar().Warn(err, "写入文件失败")
+		e2.ResponseWithMsg(c, e2.ERROR, "写入文件失败")
+	}
+	var dataurl = global.DownloadSetting.FileUrl + file.Name + formatInt + ".json"
 	doc := bson.M{
-		"name": file.Name,
-		"type": file.Type,
-		"data": file.Data,
-		"uuid": uuid,
-		"url":  url,
+		"name":    file.Name,
+		"type":    file.Type,
+		"data":    nil,
+		"uuid":    uuid,
+		"url":     url,
+		"dataurl": dataurl,
 	}
 	// 保存文件到MongoDB
 	_, err = global.MongoCon.InsertOne(context.TODO(), doc)
@@ -187,12 +201,6 @@ func GetTemplates(c *gin.Context) {
 	if uuid == "undefined" {
 		uuid = "test"
 	}
-	//hex, err2 := primitive.ObjectIDFromHex(_id)
-	//if err2 != nil {
-	//	simple_zap.WithCtx(context.Background()).Sugar().Warn(err2, "_id错误")
-	//	e2.ResponseWithMsg(c, e2.ERROR, "_id错误")
-	//	return
-	//}
 	var result map[string]interface{}
 	err := global.MongoCon.FindOne(context.Background(), bson.M{"name": name}).Decode(&result)
 	if err != nil {

+ 1 - 0
backend/app/router.go

@@ -19,6 +19,7 @@ func InitRouter() error {
 	engine.Static("/libs", "./frontend/dist/libs")
 	engine.StaticFile("/favicon.ico", "./frontend/dist/favicon.ico")
 	engine.Use(static.Serve("/download/image", static.LocalFile(global.DownloadSetting.Path, true)))
+	engine.Use(static.Serve("/download/file", static.LocalFile(global.DownloadSetting.FilePath, true)))
 	//静态资源访问地址
 	engine.GET("/download", controller.GetImage)
 	gin.SetMode(global.ServerSetting.Mode)

+ 5 - 36
backend/configs/config.yaml

@@ -1,28 +1,3 @@
-database:
-  # 数据库类型
-  dialect: mysql
-  # host地址
-  host: 127.0.0.1
-  # 端口
-  port: 3306
-  # 数据库名称
-  db: lc_oauth
-  # 数据库用户名
-  userName: root
-  # 数据库密码
-  password: 123456
-  # 其他配置参数
-  otherParams: charset=utf8mb4&parseTime=True&loc=Local
-  # 最大空闲连接数
-  maxIdleConn: 20
-  # 最大连接数
-  maxOpenConn: 200
-  # 连接超时关闭时间,单位:秒
-  connMaxLifetime: 60
-jwt:
-  secret: "xxxxx"
-  refresh_expire: 168
-  Issuer: "lc_oauth"
 # 服务相关配置
 server:
   # 启动模式 debug、release
@@ -30,24 +5,18 @@ server:
   # http服务信息
   insecureServingInfo:
   # 监听端口
-  port: ":8080"
-subMail:
-  appid: "97173"
-  signature: "f639a60e41ee0554921d89884f5ff87e"
-redis:
-  addr: "116.204.6.184:6379"
-  password: "123456"
-  db: 0
-nats:
-  NatsServer_Url: "nats://127.0.0.0:4222"
+  port: ":8888"
 mongo:
-    url: "mongodb://bzd_file:X7EeS6Yja5tGfXBR@116.204.6.184:27017/bzd_file"
+    url: "mongodb://mongo_exisCi:mongo_CxCEWF@124.220.100.95:27017/"
     password: ""
     db: 0
 download:
   # 存储路径
   imageurl: "/download/image/"
   path: "backend/static/images"
+  # 存储路径
+  fileurl: "/download/file/"
+  filepath: "backend/static/files"
 swag:
   # 将环境变量 NAME_OF_ENV_VARIABLE设置为任意值,则 /swagger/*any 返回404响应
   enable: "NAME_OF_ENV_VARIABLE"

+ 38 - 0
backend/global/mongo.go

@@ -3,12 +3,16 @@ package global
 import (
 	"context"
 	"file_upload/backend/simple_zap"
+	"fmt"
 	"go.mongodb.org/mongo-driver/mongo"
+	"go.mongodb.org/mongo-driver/mongo/gridfs"
 	"go.mongodb.org/mongo-driver/mongo/options"
 	"go.mongodb.org/mongo-driver/mongo/readpref"
+	"io"
 )
 
 var MongoCon *mongo.Collection
+var MongoGridFS *gridfs.Bucket
 
 func SetupMongo() {
 	clientOptions := options.Client().ApplyURI(MongoSetting.Url)
@@ -24,4 +28,38 @@ func SetupMongo() {
 	}
 	database := connect.Database("bzd_file")
 	MongoCon = database.Collection("file")
+	MongoGridFS, err = gridfs.NewBucket(database)
+	if err != nil {
+		simple_zap.WithCtx(context.Background()).Sugar().Warn(err)
+		panic(err)
+	}
+}
+func UploadFileToGridFS(fileName string, fileData []byte) (string, error) {
+	uploadStream, err := MongoGridFS.OpenUploadStream(fileName)
+	if err != nil {
+		return "", fmt.Errorf("无法打开上传流: %v", err)
+	}
+	defer uploadStream.Close()
+
+	_, err = uploadStream.Write(fileData)
+	if err != nil {
+		return "", fmt.Errorf("写入文件数据时出错: %v", err)
+	}
+
+	return uploadStream.FileID.(string), nil
+}
+
+func DownloadFileFromGridFS(fileID string) ([]byte, error) {
+	downloadStream, err := MongoGridFS.OpenDownloadStream(fileID)
+	if err != nil {
+		return nil, fmt.Errorf("无法打开下载流: %v", err)
+	}
+	defer downloadStream.Close()
+
+	fileData, err := io.ReadAll(downloadStream)
+	if err != nil {
+		return nil, fmt.Errorf("读取文件数据时出错: %v", err)
+	}
+
+	return fileData, nil
 }

+ 2 - 0
backend/global/setting.go

@@ -56,6 +56,8 @@ type Mongo struct {
 type Download struct {
 	Path     string `json:"path"`
 	Imageurl string `json:"imageurl"`
+	FilePath string `json:"filepath"`
+	FileUrl  string `json:"fileurl"`
 }
 
 var (

+ 1 - 1
backend/simple_zap/simple_zap.go

@@ -13,7 +13,7 @@ var Logger *zap.Logger
 
 func init() {
 	hook := lumberjack.Logger{
-		Filename:   "/backend/log/app.log",
+		Filename:   "./backend/log/app.log",
 		MaxSize:    1,
 		Compress:   true,
 		MaxAge:     30,

+ 29 - 0
backend/utils/saveDataToFile.go

@@ -0,0 +1,29 @@
+package utils
+
+import (
+	"encoding/json"
+	"errors"
+	"file_upload/backend/global"
+	"os"
+)
+
+func SaveDataToFile(data interface{}, fileName string) error {
+	// 序列化 data 为 JSON 格式的字节切片
+	jsonData, err := json.MarshalIndent(data, "", "    ")
+	if err != nil {
+		return errors.New("无法序列化数据")
+	}
+	// 创建文件
+	filpath := global.DownloadSetting.FilePath + "/" + fileName
+	file, err := os.Create(filpath + ".json")
+	if err != nil {
+		return errors.New("无法创建文件")
+	}
+	defer file.Close()
+	// 写入文件
+	_, err = file.Write(jsonData)
+	if err != nil {
+		return errors.New("无法写入文件")
+	}
+	return nil
+}

Fișier diff suprimat deoarece este prea mare
+ 0 - 0
frontend/dist/assets/index.34676768.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
frontend/dist/assets/index.a51c0360.js


BIN
frontend/dist/favicon.ico


+ 0 - 17
frontend/dist/index.html

@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <link rel="icon" href="/favicon.ico" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>在线小白板</title>
-    <link href="/libs/jsonTree.css" rel="stylesheet" />
-    <script type="module" crossorigin src="/assets/index.a51c0360.js"></script>
-    <link rel="stylesheet" href="/assets/index.34676768.css">
-  </head>
-  <body>
-    <div id="app"></div>
-    <script src="/libs/jsonTree.js"></script>
-    
-  </body>
-</html>

+ 0 - 1
frontend/dist/libs/icons.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="11" height="22"><defs><linearGradient id="a"><stop offset="0"/><stop offset="1" stop-opacity="0"/></linearGradient><radialGradient xlink:href="#a" cx="9.739" cy="9.716" fx="9.739" fy="9.716" r="3.709" gradientUnits="userSpaceOnUse"/></defs><g stroke="#000" fill="none"><g transform="translate(-129.5 -333.862) translate(0 .188)"><rect transform="matrix(.962 0 0 .971 4.943 11.548)" ry="2" rx="2" y="332.362" x="130" height="10.337" width="10.432" opacity=".5"/><g><path d="M132 339.175h6" opacity=".5"/><path d="M135 336.175v6" opacity=".5"/></g></g><g transform="translate(-129.5 -333.862)"><rect width="10.432" height="10.337" x="130" y="332.362" rx="2" ry="2" transform="matrix(.962 0 0 .971 4.943 22.736)" opacity=".5"/><path d="M132 350.362h6" opacity=".5"/></g></g></svg>

+ 0 - 107
frontend/dist/libs/jsonTree.css

@@ -1,107 +0,0 @@
-/*
- * JSON Tree Viewer
- * http://github.com/summerstyle/jsonTreeViewer
- *
- * Copyright 2017 Vera Lobacheva (http://iamvera.com)
- * Released under the MIT license (LICENSE.txt)
- */
-
-/* Background for the tree. May use for <body> element */
-.jsontree_bg {
-    background: #FFF;
-}
-
-/* Styles for the container of the tree (e.g. fonts, margins etc.) */
-.jsontree_tree {
-    margin-left: 30px;
-    font-family: 'PT Mono', monospace;
-    font-size: 14px;
-}
-
-/* Styles for a list of child nodes */
-.jsontree_child-nodes {
-    display: none;
-    margin-left: 35px; 
-    margin-bottom: 5px;
-    line-height: 2;
-}
-.jsontree_node_expanded > .jsontree_value-wrapper > .jsontree_value > .jsontree_child-nodes {
-    display: block;
-}
-
-/* Styles for labels */
-.jsontree_label-wrapper {
-    float: left;
-    margin-right: 8px;
-}
-.jsontree_label {
-    font-weight: normal;
-    vertical-align: top;
-    color: #000;
-    position: relative;
-    padding: 1px;
-    border-radius: 4px;
-    cursor: default;
-}
-.jsontree_node_marked > .jsontree_label-wrapper > .jsontree_label {
-    background: #fff2aa;
-}
-
-/* Styles for values */
-.jsontree_value-wrapper {
-    display: block;
-    overflow: hidden;
-}
-.jsontree_node_complex > .jsontree_value-wrapper {
-    overflow: inherit;
-}
-.jsontree_value { 
-    vertical-align: top;
-    display: inline;
-}
-.jsontree_value_null {
-    color: #777;
-    font-weight: bold;
-}
-.jsontree_value_string {
-    color: #025900;
-    font-weight: bold;
-}
-.jsontree_value_number {
-    color: #000E59;
-    font-weight: bold;
-}
-.jsontree_value_boolean {
-    color: #600100;
-    font-weight: bold;
-}
-
-/* Styles for active elements */
-.jsontree_expand-button {
-    position: absolute;
-    top: 3px;
-    left: -15px;
-    display: block;
-    width: 11px;
-    height: 11px;
-    background-image: url('icons.svg');
-}
-.jsontree_node_expanded > .jsontree_label-wrapper > .jsontree_label > .jsontree_expand-button {
-    background-position: 0 -11px;
-}
-.jsontree_show-more {
-    cursor: pointer;
-}
-.jsontree_node_expanded > .jsontree_value-wrapper > .jsontree_value > .jsontree_show-more {
-    display: none;
-}
-.jsontree_node_empty > .jsontree_label-wrapper > .jsontree_label > .jsontree_expand-button,
-.jsontree_node_empty > .jsontree_value-wrapper > .jsontree_value > .jsontree_show-more {
-    display: none !important;
-}
-.jsontree_node_complex > .jsontree_label-wrapper > .jsontree_label {
-    cursor: pointer;
-}
-.jsontree_node_empty > .jsontree_label-wrapper > .jsontree_label {
-    cursor: default !important;
-}

+ 0 - 819
frontend/dist/libs/jsonTree.js

@@ -1,819 +0,0 @@
-/**
- * JSON Tree library (a part of jsonTreeViewer)
- * http://github.com/summerstyle/jsonTreeViewer
- *
- * Copyright 2017 Vera Lobacheva (http://iamvera.com)
- * Released under the MIT license (LICENSE.txt)
- */
-
-var jsonTree = (function() {
-    
-    /* ---------- Utilities ---------- */
-    var utils = {
-        
-        /*
-         * Returns js-"class" of value
-         * 
-         * @param val {any type} - value
-         * @returns {string} - for example, "[object Function]"
-         */
-        getClass : function(val) {
-            return Object.prototype.toString.call(val);
-        },
-        
-        /**
-         * Checks for a type of value (for valid JSON data types).
-         * In other cases - throws an exception
-         * 
-         * @param val {any type} - the value for new node
-         * @returns {string} ("object" | "array" | "null" | "boolean" | "number" | "string")
-         */
-        getType : function(val) {
-            if (val === null) {
-                return 'null';
-            }
-            
-            switch (typeof val) {
-                case 'number':
-                    return 'number';
-                
-                case 'string':
-                    return 'string';
-                
-                case 'boolean':
-                    return 'boolean';
-            }
-            
-            switch(utils.getClass(val)) {
-                case '[object Array]':
-                    return 'array';
-                
-                case '[object Object]':
-                    return 'object';
-            }
-            
-            throw new Error('Bad type: ' + utils.getClass(val));
-        },
-        
-        /**
-         * Applies for each item of list some function
-         * and checks for last element of the list
-         * 
-         * @param obj {Object | Array} - a list or a dict with child nodes
-         * @param func {Function} - the function for each item
-         */
-        forEachNode : function(obj, func) {
-            var type = utils.getType(obj),
-                isLast;
-        
-            switch (type) {
-                case 'array':
-                    isLast = obj.length - 1;
-                    
-                    obj.forEach(function(item, i) {
-                        func(i, item, i === isLast);
-                    });
-                    
-                    break;
-                
-                case 'object':
-                    var keys = Object.keys(obj).sort();
-                    
-                    isLast = keys.length - 1;
-                    
-                    keys.forEach(function(item, i) {
-                        func(item, obj[item], i === isLast);
-                    });
-                    
-                    break;
-            }
-            
-        },
-        
-        /**
-         * Implements the kind of an inheritance by
-         * using parent prototype and
-         * creating intermediate constructor
-         * 
-         * @param Child {Function} - a child constructor
-         * @param Parent {Function} - a parent constructor
-         */
-        inherits : (function() {
-            var F = function() {};
-            
-            return function(Child, Parent) {
-                F.prototype = Parent.prototype;
-                Child.prototype = new F();
-                Child.prototype.constructor = Child;
-            };
-        })(),
-        
-        /*
-         * Checks for a valid type of root node*
-         *
-         * @param {any type} jsonObj - a value for root node
-         * @returns {boolean} - true for an object or an array, false otherwise
-         */
-        isValidRoot : function(jsonObj) {
-            switch (utils.getType(jsonObj)) {
-                case 'object':
-                case 'array':
-                    return true;
-                default:
-                    return false;
-            }
-        },
-
-        /**
-         * Extends some object
-         */
-        extend : function(targetObj, sourceObj) {
-            for (var prop in sourceObj) {
-                if (sourceObj.hasOwnProperty(prop)) {
-                    targetObj[prop] = sourceObj[prop];
-                }
-            }
-        }
-    };
-    
-    
-    /* ---------- Node constructors ---------- */
-    
-    /**
-     * The factory for creating nodes of defined type.
-     * 
-     * ~~~ Node ~~~ is a structure element of an onject or an array
-     * with own label (a key of an object or an index of an array)
-     * and value of any json data type. The root object or array
-     * is a node without label.
-     * {...
-     * [+] "label": value,
-     * ...}
-     * 
-     * Markup:
-     * <li class="jsontree_node [jsontree_node_expanded]">
-     *     <span class="jsontree_label-wrapper">
-     *         <span class="jsontree_label">
-     *             <span class="jsontree_expand-button" />
-     *             "label"
-     *         </span>
-     *         :
-     *     </span>
-     *     <(div|span) class="jsontree_value jsontree_value_(object|array|boolean|null|number|string)">
-     *         ...
-     *     </(div|span)>
-     * </li>
-     *
-     * @param label {string} - key name
-     * @param val {Object | Array | string | number | boolean | null} - a value of node
-     * @param isLast {boolean} - true if node is last in list of siblings
-     * 
-     * @return {Node}
-     */
-    function Node(label, val, isLast) {
-        var nodeType = utils.getType(val);
-        
-        if (nodeType in Node.CONSTRUCTORS) {
-            return new Node.CONSTRUCTORS[nodeType](label, val, isLast);
-        } else {
-            throw new Error('Bad type: ' + utils.getClass(val));
-        }
-    }
-    
-    Node.CONSTRUCTORS = {
-        'boolean' : NodeBoolean,
-        'number'  : NodeNumber,
-        'string'  : NodeString,
-        'null'    : NodeNull,
-        'object'  : NodeObject,
-        'array'   : NodeArray  
-    };
-    
-    
-    /*
-     * The constructor for simple types (string, number, boolean, null)
-     * {...
-     * [+] "label": value,
-     * ...}
-     * value = string || number || boolean || null
-     *
-     * Markup:
-     * <li class="jsontree_node">
-     *     <span class="jsontree_label-wrapper">
-     *         <span class="jsontree_label">"age"</span>
-     *         :
-     *     </span>
-     *     <span class="jsontree_value jsontree_value_(number|boolean|string|null)">25</span>
-     *     ,
-     * </li>
-     *
-     * @abstract
-     * @param label {string} - key name
-     * @param val {string | number | boolean | null} - a value of simple types
-     * @param isLast {boolean} - true if node is last in list of parent childNodes
-     */
-    function _NodeSimple(label, val, isLast) {
-        if (this.constructor === _NodeSimple) {
-            throw new Error('This is abstract class');
-        }
-        
-        var self = this,
-            el = document.createElement('li'),
-            labelEl,
-            template = function(label, val) {
-                var str = '\
-                    <span class="jsontree_label-wrapper">\
-                        <span class="jsontree_label">"' +
-                            label +
-                        '"</span> : \
-                    </span>\
-                    <span class="jsontree_value-wrapper">\
-                        <span class="jsontree_value jsontree_value_' + self.type + '">' +
-                            val +
-                        '</span>' +
-                        (!isLast ? ',' : '') + 
-                    '</span>';
-    
-                return str;
-            };
-            
-        self.label = label;
-        self.isComplex = false;
-    
-        el.classList.add('jsontree_node');
-        el.innerHTML = template(label, val);
-    
-        self.el = el;
-
-        labelEl = el.querySelector('.jsontree_label');
-    
-        labelEl.addEventListener('click', function(e) {
-            if (e.altKey) {
-                self.toggleMarked();
-                return;
-            }
-
-            if (e.shiftKey) {
-                document.getSelection().removeAllRanges();
-                alert(self.getJSONPath());
-                return;
-            }
-        }, false);
-    }
-
-    _NodeSimple.prototype = {
-        constructor : _NodeSimple,
-
-        /**
-         * Mark node
-         */
-        mark : function() {
-            this.el.classList.add('jsontree_node_marked');    
-        },
-
-        /**
-         * Unmark node
-         */
-        unmark : function() {
-            this.el.classList.remove('jsontree_node_marked');    
-        },
-
-        /**
-         * Mark or unmark node
-         */
-        toggleMarked : function() {
-            this.el.classList.toggle('jsontree_node_marked');    
-        },
-
-        /**
-         * Expands parent node of this node
-         *
-         * @param isRecursive {boolean} - if true, expands all parent nodes
-         *                                (from node to root)
-         */
-        expandParent : function(isRecursive) {
-            if (!this.parent) {
-                return;
-            }
-               
-            this.parent.expand(); 
-            this.parent.expandParent(isRecursive);
-        },
-
-        /**
-         * Returns JSON-path of this 
-         * 
-         * @param isInDotNotation {boolean} - kind of notation for returned json-path
-         *                                    (by default, in bracket notation)
-         * @returns {string}
-         */
-        getJSONPath : function(isInDotNotation) {
-            if (this.isRoot) {
-                return "$";
-            }
-
-            var currentPath;
-
-            if (this.parent.type === 'array') {
-                currentPath = "[" + this.label + "]";
-            } else {
-                currentPath = isInDotNotation ? "." + this.label : "['" + this.label + "']";
-            }
-
-            return this.parent.getJSONPath(isInDotNotation) + currentPath; 
-        }
-    };
-    
-    
-    /*
-     * The constructor for boolean values
-     * {...
-     * [+] "label": boolean,
-     * ...}
-     * boolean = true || false
-     *
-     * @constructor
-     * @param label {string} - key name
-     * @param val {boolean} - value of boolean type, true or false
-     * @param isLast {boolean} - true if node is last in list of parent childNodes
-     */
-    function NodeBoolean(label, val, isLast) {
-        this.type = "boolean";
-    
-        _NodeSimple.call(this, label, val, isLast);
-    }
-    utils.inherits(NodeBoolean,_NodeSimple);
-    
-    
-    /*
-     * The constructor for number values
-     * {...
-     * [+] "label": number,
-     * ...}
-     * number = 123
-     *
-     * @constructor
-     * @param label {string} - key name
-     * @param val {number} - value of number type, for example 123
-     * @param isLast {boolean} - true if node is last in list of parent childNodes
-     */
-    function NodeNumber(label, val, isLast) {
-        this.type = "number";
-    
-        _NodeSimple.call(this, label, val, isLast);
-    }
-    utils.inherits(NodeNumber,_NodeSimple);
-    
-    
-    /*
-     * The constructor for string values
-     * {...
-     * [+] "label": string,
-     * ...}
-     * string = "abc"
-     *
-     * @constructor
-     * @param label {string} - key name
-     * @param val {string} - value of string type, for example "abc"
-     * @param isLast {boolean} - true if node is last in list of parent childNodes
-     */
-    function NodeString(label, val, isLast) {
-        this.type = "string";
-    
-        _NodeSimple.call(this, label, '"' + val + '"', isLast);
-    }
-    utils.inherits(NodeString,_NodeSimple);
-    
-    
-    /*
-     * The constructor for null values
-     * {...
-     * [+] "label": null,
-     * ...}
-     *
-     * @constructor
-     * @param label {string} - key name
-     * @param val {null} - value (only null)
-     * @param isLast {boolean} - true if node is last in list of parent childNodes
-     */
-    function NodeNull(label, val, isLast) {
-        this.type = "null";
-    
-        _NodeSimple.call(this, label, val, isLast);
-    }
-    utils.inherits(NodeNull,_NodeSimple);
-    
-    
-    /*
-     * The constructor for complex types (object, array)
-     * {...
-     * [+] "label": value,
-     * ...}
-     * value = object || array
-     *
-     * Markup:
-     * <li class="jsontree_node jsontree_node_(object|array) [expanded]">
-     *     <span class="jsontree_label-wrapper">
-     *         <span class="jsontree_label">
-     *             <span class="jsontree_expand-button" />
-     *             "label"
-     *         </span>
-     *         :
-     *     </span>
-     *     <div class="jsontree_value">
-     *         <b>{</b>
-     *         <ul class="jsontree_child-nodes" />
-     *         <b>}</b>
-     *         ,
-     *     </div>
-     * </li>
-     *
-     * @abstract
-     * @param label {string} - key name
-     * @param val {Object | Array} - a value of complex types, object or array
-     * @param isLast {boolean} - true if node is last in list of parent childNodes
-     */
-    function _NodeComplex(label, val, isLast) {
-        if (this.constructor === _NodeComplex) {
-            throw new Error('This is abstract class');
-        }
-        
-        var self = this,
-            el = document.createElement('li'),
-            template = function(label, sym) {
-                var comma = (!isLast) ? ',' : '',
-                    str = '\
-                        <div class="jsontree_value-wrapper">\
-                            <div class="jsontree_value jsontree_value_' + self.type + '">\
-                                <b>' + sym[0] + '</b>\
-                                <span class="jsontree_show-more">&hellip;</span>\
-                                <ul class="jsontree_child-nodes"></ul>\
-                                <b>' + sym[1] + '</b>' +
-                            '</div>' + comma +
-                        '</div>';
-    
-                if (label !== null) {
-                    str = '\
-                        <span class="jsontree_label-wrapper">\
-                            <span class="jsontree_label">' +
-                                '<span class="jsontree_expand-button"></span>' +
-                                '"' + label +
-                            '"</span> : \
-                        </span>' + str;
-                }
-    
-                return str;
-            },
-            childNodesUl,
-            labelEl,
-            moreContentEl,
-            childNodes = [];
-    
-        self.label = label;
-        self.isComplex = true;
-    
-        el.classList.add('jsontree_node');
-        el.classList.add('jsontree_node_complex');
-        el.innerHTML = template(label, self.sym);
-    
-        childNodesUl = el.querySelector('.jsontree_child-nodes');
-    
-        if (label !== null) {
-            labelEl = el.querySelector('.jsontree_label');
-            moreContentEl = el.querySelector('.jsontree_show-more');
-    
-            labelEl.addEventListener('click', function(e) {
-                if (e.altKey) {
-                    self.toggleMarked();
-                    return;
-                }
-
-                if (e.shiftKey) {
-                    document.getSelection().removeAllRanges();
-                    alert(self.getJSONPath());
-                    return;
-                }
-
-                self.toggle(e.ctrlKey || e.metaKey);
-            }, false);
-            
-            moreContentEl.addEventListener('click', function(e) {
-                self.toggle(e.ctrlKey || e.metaKey);
-            }, false);
-    
-            self.isRoot = false;
-        } else {
-            self.isRoot = true;
-            self.parent = null;
-    
-            el.classList.add('jsontree_node_expanded');
-        }
-    
-        self.el = el;
-        self.childNodes = childNodes;
-        self.childNodesUl = childNodesUl;
-    
-        utils.forEachNode(val, function(label, node, isLast) {
-            self.addChild(new Node(label, node, isLast));
-        });
-    
-        self.isEmpty = !Boolean(childNodes.length);
-        if (self.isEmpty) {
-            el.classList.add('jsontree_node_empty');
-        }
-    }
-
-    utils.inherits(_NodeComplex, _NodeSimple);
-    
-    utils.extend(_NodeComplex.prototype, {
-        constructor : _NodeComplex,
-        
-        /*
-         * Add child node to list of child nodes
-         *
-         * @param child {Node} - child node
-         */
-        addChild : function(child) {
-            this.childNodes.push(child);
-            this.childNodesUl.appendChild(child.el);
-            child.parent = this;
-        },
-    
-        /*
-         * Expands this list of node child nodes
-         *
-         * @param isRecursive {boolean} - if true, expands all child nodes
-         */
-        expand : function(isRecursive){
-            if (this.isEmpty) {
-                return;
-            }
-            
-            if (!this.isRoot) {
-                this.el.classList.add('jsontree_node_expanded');
-            }
-    
-            if (isRecursive) {
-                this.childNodes.forEach(function(item, i) {
-                    if (item.isComplex) {
-                        item.expand(isRecursive);
-                    }
-                });
-            }
-        },
-    
-        /*
-         * Collapses this list of node child nodes
-         *
-         * @param isRecursive {boolean} - if true, collapses all child nodes
-         */
-        collapse : function(isRecursive) {
-            if (this.isEmpty) {
-                return;
-            }
-            
-            if (!this.isRoot) {
-                this.el.classList.remove('jsontree_node_expanded');
-            }
-    
-            if (isRecursive) {
-                this.childNodes.forEach(function(item, i) {
-                    if (item.isComplex) {
-                        item.collapse(isRecursive);
-                    }
-                });
-            }
-        },
-    
-        /*
-         * Expands collapsed or collapses expanded node
-         *
-         * @param {boolean} isRecursive - Expand all child nodes if this node is expanded
-         *                                and collapse it otherwise
-         */
-        toggle : function(isRecursive) {
-            if (this.isEmpty) {
-                return;
-            }
-            
-            this.el.classList.toggle('jsontree_node_expanded');
-            
-            if (isRecursive) {
-                var isExpanded = this.el.classList.contains('jsontree_node_expanded');
-                
-                this.childNodes.forEach(function(item, i) {
-                    if (item.isComplex) {
-                        item[isExpanded ? 'expand' : 'collapse'](isRecursive);
-                    }
-                });
-            }
-        },
-
-        /**
-         * Find child nodes that match some conditions and handle it
-         * 
-         * @param {Function} matcher
-         * @param {Function} handler
-         * @param {boolean} isRecursive
-         */
-        findChildren : function(matcher, handler, isRecursive) {
-            if (this.isEmpty) {
-                return;
-            }
-            
-            this.childNodes.forEach(function(item, i) {
-                if (matcher(item)) {
-                    handler(item);
-                }
-
-                if (item.isComplex && isRecursive) {
-                    item.findChildren(matcher, handler, isRecursive);
-                }
-            });
-        }
-    });
-    
-    
-    /*
-     * The constructor for object values
-     * {...
-     * [+] "label": object,
-     * ...}
-     * object = {"abc": "def"}
-     *
-     * @constructor
-     * @param label {string} - key name
-     * @param val {Object} - value of object type, {"abc": "def"}
-     * @param isLast {boolean} - true if node is last in list of siblings
-     */
-    function NodeObject(label, val, isLast) {
-        this.sym = ['{', '}'];
-        this.type = "object";
-    
-        _NodeComplex.call(this, label, val, isLast);
-    }
-    utils.inherits(NodeObject,_NodeComplex);
-    
-    
-    /*
-     * The constructor for array values
-     * {...
-     * [+] "label": array,
-     * ...}
-     * array = [1,2,3]
-     *
-     * @constructor
-     * @param label {string} - key name
-     * @param val {Array} - value of array type, [1,2,3]
-     * @param isLast {boolean} - true if node is last in list of siblings
-     */
-    function NodeArray(label, val, isLast) {
-        this.sym = ['[', ']'];
-        this.type = "array";
-    
-        _NodeComplex.call(this, label, val, isLast);
-    }
-    utils.inherits(NodeArray, _NodeComplex);
-    
-    
-    /* ---------- The tree constructor ---------- */
-    
-    /*
-     * The constructor for json tree.
-     * It contains only one Node (Array or Object), without property name.
-     * CSS-styles of .tree define main tree styles like font-family,
-     * font-size and own margins.
-     *
-     * Markup:
-     * <ul class="jsontree_tree clearfix">
-     *     {Node}
-     * </ul>
-     *
-     * @constructor
-     * @param jsonObj {Object | Array} - data for tree
-     * @param domEl {DOMElement} - DOM-element, wrapper for tree
-     */
-    function Tree(jsonObj, domEl) {
-        this.wrapper = document.createElement('ul');
-        this.wrapper.className = 'jsontree_tree clearfix';
-        
-        this.rootNode = null;
-        
-        this.sourceJSONObj = jsonObj;
-
-        this.loadData(jsonObj);
-        this.appendTo(domEl);
-    }
-    
-    Tree.prototype = {
-        constructor : Tree,
-        
-        /**
-         * Fill new data in current json tree
-         *
-         * @param {Object | Array} jsonObj - json-data
-         */
-        loadData : function(jsonObj) {
-            if (!utils.isValidRoot(jsonObj)) {
-                alert('The root should be an object or an array');
-                return;
-            }
-
-            this.sourceJSONObj = jsonObj;
-            
-            this.rootNode = new Node(null, jsonObj, 'last');
-            this.wrapper.innerHTML = '';
-            this.wrapper.appendChild(this.rootNode.el);
-        },
-        
-        /**
-         * Appends tree to DOM-element (or move it to new place)
-         *
-         * @param {DOMElement} domEl 
-         */
-        appendTo : function(domEl) {
-            domEl.appendChild(this.wrapper);
-        },
-        
-        /**
-         * Expands all tree nodes (objects or arrays) recursively
-         *
-         * @param {Function} filterFunc - 'true' if this node should be expanded
-         */
-        expand : function(filterFunc) {
-            if (this.rootNode.isComplex) {
-                if (typeof filterFunc == 'function') {
-                    this.rootNode.childNodes.forEach(function(item, i) {
-                        if (item.isComplex && filterFunc(item)) {
-                            item.expand();
-                        }
-                    });
-                } else {
-                    this.rootNode.expand('recursive');
-                }
-            }
-        },
-       
-        /**
-         * Collapses all tree nodes (objects or arrays) recursively
-         */
-        collapse : function() {
-            if (typeof this.rootNode.collapse === 'function') {
-                this.rootNode.collapse('recursive');
-            }
-        },
-
-        /**
-         * Returns the source json-string (pretty-printed)
-         * 
-         * @param {boolean} isPrettyPrinted - 'true' for pretty-printed string
-         * @returns {string} - for exemple, '{"a":2,"b":3}'
-         */
-        toSourceJSON : function(isPrettyPrinted) {
-            if (!isPrettyPrinted) {
-                return JSON.stringify(this.sourceJSONObj);
-            }
-
-            var DELIMETER = "[%^$#$%^%]",
-                jsonStr = JSON.stringify(this.sourceJSONObj, null, DELIMETER);
-
-            jsonStr = jsonStr.split("\n").join("<br />");
-            jsonStr = jsonStr.split(DELIMETER).join("&nbsp;&nbsp;&nbsp;&nbsp;");
-
-            return jsonStr;
-        },
-
-        /**
-         * Find all nodes that match some conditions and handle it
-         */
-        findAndHandle : function(matcher, handler) {
-            this.rootNode.findChildren(matcher, handler, 'isRecursive');
-        },
-
-        /**
-         * Unmark all nodes
-         */
-        unmarkAll : function() {
-            this.rootNode.findChildren(function(node) {
-                return true;
-            }, function(node) {
-                node.unmark();
-            }, 'isRecursive');
-        }
-    };
-
-    
-    /* ---------- Public methods ---------- */
-    return {
-        /**
-         * Creates new tree by data and appends it to the DOM-element
-         * 
-         * @param jsonObj {Object | Array} - json-data
-         * @param domEl {DOMElement} - the wrapper element
-         * @returns {Tree}
-         */
-        create : function(jsonObj, domEl) {
-            return new Tree(jsonObj, domEl);
-        }
-    };
-})();

+ 0 - 4814
frontend/dist/tiny-whiteboard/tiny-whiteboard.es.js

@@ -1,4814 +0,0 @@
-var __defProp = Object.defineProperty;
-var __defProps = Object.defineProperties;
-var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
-var __getOwnPropSymbols = Object.getOwnPropertySymbols;
-var __hasOwnProp = Object.prototype.hasOwnProperty;
-var __propIsEnum = Object.prototype.propertyIsEnumerable;
-var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
-var __spreadValues = (a, b) => {
-  for (var prop in b || (b = {}))
-    if (__hasOwnProp.call(b, prop))
-      __defNormalProp(a, prop, b[prop]);
-  if (__getOwnPropSymbols)
-    for (var prop of __getOwnPropSymbols(b)) {
-      if (__propIsEnum.call(b, prop))
-        __defNormalProp(a, prop, b[prop]);
-    }
-  return a;
-};
-var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
-var __async = (__this, __arguments, generator) => {
-  return new Promise((resolve, reject) => {
-    var fulfilled = (value) => {
-      try {
-        step(generator.next(value));
-      } catch (e) {
-        reject(e);
-      }
-    };
-    var rejected = (value) => {
-      try {
-        step(generator.throw(value));
-      } catch (e) {
-        reject(e);
-      }
-    };
-    var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
-    step((generator = generator.apply(__this, __arguments)).next());
-  });
-};
-var eventemitter3 = { exports: {} };
-(function(module) {
-  var has = Object.prototype.hasOwnProperty, prefix = "~";
-  function Events() {
-  }
-  if (Object.create) {
-    Events.prototype = /* @__PURE__ */ Object.create(null);
-    if (!new Events().__proto__)
-      prefix = false;
-  }
-  function EE(fn, context, once) {
-    this.fn = fn;
-    this.context = context;
-    this.once = once || false;
-  }
-  function addListener(emitter, event, fn, context, once) {
-    if (typeof fn !== "function") {
-      throw new TypeError("The listener must be a function");
-    }
-    var listener = new EE(fn, context || emitter, once), evt = prefix ? prefix + event : event;
-    if (!emitter._events[evt])
-      emitter._events[evt] = listener, emitter._eventsCount++;
-    else if (!emitter._events[evt].fn)
-      emitter._events[evt].push(listener);
-    else
-      emitter._events[evt] = [emitter._events[evt], listener];
-    return emitter;
-  }
-  function clearEvent(emitter, evt) {
-    if (--emitter._eventsCount === 0)
-      emitter._events = new Events();
-    else
-      delete emitter._events[evt];
-  }
-  function EventEmitter2() {
-    this._events = new Events();
-    this._eventsCount = 0;
-  }
-  EventEmitter2.prototype.eventNames = function eventNames() {
-    var names = [], events, name;
-    if (this._eventsCount === 0)
-      return names;
-    for (name in events = this._events) {
-      if (has.call(events, name))
-        names.push(prefix ? name.slice(1) : name);
-    }
-    if (Object.getOwnPropertySymbols) {
-      return names.concat(Object.getOwnPropertySymbols(events));
-    }
-    return names;
-  };
-  EventEmitter2.prototype.listeners = function listeners(event) {
-    var evt = prefix ? prefix + event : event, handlers = this._events[evt];
-    if (!handlers)
-      return [];
-    if (handlers.fn)
-      return [handlers.fn];
-    for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
-      ee[i] = handlers[i].fn;
-    }
-    return ee;
-  };
-  EventEmitter2.prototype.listenerCount = function listenerCount(event) {
-    var evt = prefix ? prefix + event : event, listeners = this._events[evt];
-    if (!listeners)
-      return 0;
-    if (listeners.fn)
-      return 1;
-    return listeners.length;
-  };
-  EventEmitter2.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
-    var evt = prefix ? prefix + event : event;
-    if (!this._events[evt])
-      return false;
-    var listeners = this._events[evt], len = arguments.length, args, i;
-    if (listeners.fn) {
-      if (listeners.once)
-        this.removeListener(event, listeners.fn, void 0, true);
-      switch (len) {
-        case 1:
-          return listeners.fn.call(listeners.context), true;
-        case 2:
-          return listeners.fn.call(listeners.context, a1), true;
-        case 3:
-          return listeners.fn.call(listeners.context, a1, a2), true;
-        case 4:
-          return listeners.fn.call(listeners.context, a1, a2, a3), true;
-        case 5:
-          return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
-        case 6:
-          return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
-      }
-      for (i = 1, args = new Array(len - 1); i < len; i++) {
-        args[i - 1] = arguments[i];
-      }
-      listeners.fn.apply(listeners.context, args);
-    } else {
-      var length = listeners.length, j;
-      for (i = 0; i < length; i++) {
-        if (listeners[i].once)
-          this.removeListener(event, listeners[i].fn, void 0, true);
-        switch (len) {
-          case 1:
-            listeners[i].fn.call(listeners[i].context);
-            break;
-          case 2:
-            listeners[i].fn.call(listeners[i].context, a1);
-            break;
-          case 3:
-            listeners[i].fn.call(listeners[i].context, a1, a2);
-            break;
-          case 4:
-            listeners[i].fn.call(listeners[i].context, a1, a2, a3);
-            break;
-          default:
-            if (!args)
-              for (j = 1, args = new Array(len - 1); j < len; j++) {
-                args[j - 1] = arguments[j];
-              }
-            listeners[i].fn.apply(listeners[i].context, args);
-        }
-      }
-    }
-    return true;
-  };
-  EventEmitter2.prototype.on = function on(event, fn, context) {
-    return addListener(this, event, fn, context, false);
-  };
-  EventEmitter2.prototype.once = function once(event, fn, context) {
-    return addListener(this, event, fn, context, true);
-  };
-  EventEmitter2.prototype.removeListener = function removeListener(event, fn, context, once) {
-    var evt = prefix ? prefix + event : event;
-    if (!this._events[evt])
-      return this;
-    if (!fn) {
-      clearEvent(this, evt);
-      return this;
-    }
-    var listeners = this._events[evt];
-    if (listeners.fn) {
-      if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
-        clearEvent(this, evt);
-      }
-    } else {
-      for (var i = 0, events = [], length = listeners.length; i < length; i++) {
-        if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) {
-          events.push(listeners[i]);
-        }
-      }
-      if (events.length)
-        this._events[evt] = events.length === 1 ? events[0] : events;
-      else
-        clearEvent(this, evt);
-    }
-    return this;
-  };
-  EventEmitter2.prototype.removeAllListeners = function removeAllListeners(event) {
-    var evt;
-    if (event) {
-      evt = prefix ? prefix + event : event;
-      if (this._events[evt])
-        clearEvent(this, evt);
-    } else {
-      this._events = new Events();
-      this._eventsCount = 0;
-    }
-    return this;
-  };
-  EventEmitter2.prototype.off = EventEmitter2.prototype.removeListener;
-  EventEmitter2.prototype.addListener = EventEmitter2.prototype.on;
-  EventEmitter2.prefixed = prefix;
-  EventEmitter2.EventEmitter = EventEmitter2;
-  {
-    module.exports = EventEmitter2;
-  }
-})(eventemitter3);
-var EventEmitter = eventemitter3.exports;
-const createCanvas = (width, height, opt = { noStyle: false, noTranslate: false, className: "" }) => {
-  let canvas = document.createElement("canvas");
-  if (!opt.noStyle) {
-    canvas.style.cssText = `
-      position: absolute;
-      left: 0;
-      top: 0;
-    `;
-  }
-  if (opt.className) {
-    canvas.className = opt.className;
-  }
-  let ctx = canvas.getContext("2d");
-  canvas.width = width;
-  canvas.height = height;
-  if (!opt.noTranslate) {
-    ctx.translate(canvas.width / 2, canvas.height / 2);
-  }
-  return {
-    canvas,
-    ctx
-  };
-};
-const getTowPointDistance = (x1, y1, x2, y2) => {
-  return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
-};
-const getPointToLineDistance = (x, y, x1, y1, x2, y2) => {
-  if (x1 === x2) {
-    return Math.abs(x - x1);
-  } else {
-    let B = 1;
-    let A, C;
-    A = (y1 - y2) / (x2 - x1);
-    C = 0 - B * y1 - A * x1;
-    return Math.abs((A * x + B * y + C) / Math.sqrt(A * A + B * B));
-  }
-};
-const checkIsAtSegment = (x, y, x1, y1, x2, y2, dis = 10) => {
-  if (getPointToLineDistance(x, y, x1, y1, x2, y2) > dis) {
-    return false;
-  }
-  let dis1 = getTowPointDistance(x, y, x1, y1);
-  let dis2 = getTowPointDistance(x, y, x2, y2);
-  let dis3 = getTowPointDistance(x1, y1, x2, y2);
-  let max = Math.sqrt(dis * dis + dis3 * dis3);
-  if (dis1 <= max && dis2 <= max) {
-    return true;
-  }
-  return false;
-};
-const radToDeg = (rad) => {
-  return rad * (180 / Math.PI);
-};
-const degToRad = (deg) => {
-  return deg * (Math.PI / 180);
-};
-const getTowPointRotate = (cx, cy, tx, ty, fx, fy) => {
-  return radToDeg(Math.atan2(ty - cy, tx - cx) - Math.atan2(fy - cy, fx - cx));
-};
-const getRotatedPoint = (x, y, cx, cy, rotate) => {
-  let deg = radToDeg(Math.atan2(y - cy, x - cx));
-  let del = deg + rotate;
-  let dis = getTowPointDistance(x, y, cx, cy);
-  return {
-    x: Math.cos(degToRad(del)) * dis + cx,
-    y: Math.sin(degToRad(del)) * dis + cy
-  };
-};
-const getElementCenterPoint = (element) => {
-  let { x, y, width, height } = element;
-  return {
-    x: x + width / 2,
-    y: y + height / 2
-  };
-};
-const transformPointReverseRotate = (x, y, cx, cy, rotate) => {
-  if (rotate !== 0) {
-    let rp = getRotatedPoint(x, y, cx, cy, -rotate);
-    x = rp.x;
-    y = rp.y;
-  }
-  return {
-    x,
-    y
-  };
-};
-const transformPointOnElement = (x, y, element) => {
-  let center = getElementCenterPoint(element);
-  return transformPointReverseRotate(x, y, center.x, center.y, element.rotate);
-};
-const getElementCornerPoint = (element, dir) => {
-  let { x, y, width, height } = element;
-  switch (dir) {
-    case "topLeft":
-      return {
-        x,
-        y
-      };
-    case "topRight":
-      return {
-        x: x + width,
-        y
-      };
-    case "bottomRight":
-      return {
-        x: x + width,
-        y: y + height
-      };
-    case "bottomLeft":
-      return {
-        x,
-        y: y + height
-      };
-  }
-};
-const getElementRotatedCornerPoint = (element, dir) => {
-  let center = getElementCenterPoint(element);
-  let dirPos = getElementCornerPoint(element, dir);
-  return getRotatedPoint(dirPos.x, dirPos.y, center.x, center.y, element.rotate);
-};
-const checkPointIsInRectangle = (x, y, rx, ry, rw, rh) => {
-  if (typeof rx === "object") {
-    let element = rx;
-    rx = element.x;
-    ry = element.y;
-    rw = element.width;
-    rh = element.height;
-  }
-  return x >= rx && x <= rx + rw && y >= ry && y <= ry + rh;
-};
-const getBoundingRect = (pointArr = [], returnCorners = false) => {
-  let minX = Infinity;
-  let maxX = -Infinity;
-  let minY = Infinity;
-  let maxY = -Infinity;
-  pointArr.forEach((point) => {
-    let [x2, y2] = point;
-    if (x2 < minX) {
-      minX = x2;
-    }
-    if (x2 > maxX) {
-      maxX = x2;
-    }
-    if (y2 < minY) {
-      minY = y2;
-    }
-    if (y2 > maxY) {
-      maxY = y2;
-    }
-  });
-  let x = minX;
-  let y = minY;
-  let width = maxX - minX;
-  let height = maxY - minY;
-  if (returnCorners) {
-    return [
-      {
-        x,
-        y
-      },
-      {
-        x: x + width,
-        y
-      },
-      {
-        x: x + width,
-        y: y + height
-      },
-      {
-        x,
-        y: y + height
-      }
-    ];
-  }
-  return {
-    x,
-    y,
-    width,
-    height
-  };
-};
-const deepCopy = (obj) => {
-  return JSON.parse(JSON.stringify(obj));
-};
-const getFontString = (fontSize, fontFamily) => {
-  return `${fontSize}px ${fontFamily}`;
-};
-const splitTextLines = (text) => {
-  return text.replace(/\r\n?/g, "\n").split("\n");
-};
-let textCheckEl = null;
-const getTextActWidth = (text, style) => {
-  if (!textCheckEl) {
-    textCheckEl = document.createElement("div");
-    textCheckEl.style.position = "fixed";
-    textCheckEl.style.left = "-99999px";
-    document.body.appendChild(textCheckEl);
-  }
-  let { fontSize, fontFamily } = style;
-  textCheckEl.innerText = text;
-  textCheckEl.style.fontSize = fontSize + "px";
-  textCheckEl.style.fontFamily = fontFamily;
-  let { width } = textCheckEl.getBoundingClientRect();
-  return width;
-};
-const getMaxFontSizeInWidth = (text, width, style) => {
-  let fontSize = 12;
-  while (getTextActWidth(text, __spreadProps(__spreadValues({}, style), {
-    fontSize: fontSize + 1
-  })) < width) {
-    fontSize++;
-  }
-  return fontSize;
-};
-const getWrapTextActWidth = (element) => {
-  let { text } = element;
-  let textArr = splitTextLines(text);
-  let maxWidth = -Infinity;
-  textArr.forEach((textRow) => {
-    let width = getTextActWidth(textRow, element.style);
-    if (width > maxWidth) {
-      maxWidth = width;
-    }
-  });
-  return maxWidth;
-};
-const getWrapTextMaxRowTextNumber = (text) => {
-  let textArr = splitTextLines(text);
-  let maxNumber = -Infinity;
-  textArr.forEach((textRow) => {
-    if (textRow.length > maxNumber) {
-      maxNumber = textRow.length;
-    }
-  });
-  return maxNumber;
-};
-const getTextElementSize = (element) => {
-  let { text, style } = element;
-  let width = getWrapTextActWidth(element);
-  const lines = Math.max(splitTextLines(text).length, 1);
-  let lineHeight = style.fontSize * style.lineHeightRatio;
-  let height = lines * lineHeight;
-  return {
-    width,
-    height
-  };
-};
-const throttle = (fn, ctx, time = 100) => {
-  let timer = null;
-  return (...args) => {
-    if (timer) {
-      return;
-    }
-    timer = setTimeout(() => {
-      fn.call(ctx, ...args);
-      timer = null;
-    }, time);
-  };
-};
-const computedLineWidthBySpeed = (speed, lastLineWidth, baseLineWidth = 2) => {
-  let lineWidth = 0;
-  let maxLineWidth = baseLineWidth;
-  let maxSpeed = 10;
-  let minSpeed = 0.5;
-  if (speed >= maxSpeed) {
-    lineWidth = baseLineWidth;
-  } else if (speed <= minSpeed) {
-    lineWidth = maxLineWidth + 1;
-  } else {
-    lineWidth = maxLineWidth - (speed - minSpeed) / (maxSpeed - minSpeed) * maxLineWidth;
-  }
-  if (lastLineWidth === -1) {
-    lastLineWidth = maxLineWidth;
-  }
-  return lineWidth * (1 / 2) + lastLineWidth * (1 / 2);
-};
-const downloadFile = (file, fileName) => {
-  let a = document.createElement("a");
-  a.href = file;
-  a.download = fileName;
-  a.click();
-};
-const getElementCorners = (element) => {
-  let topLeft = getElementRotatedCornerPoint(element, "topLeft");
-  let topRight = getElementRotatedCornerPoint(element, "topRight");
-  let bottomLeft = getElementRotatedCornerPoint(element, "bottomLeft");
-  let bottomRight = getElementRotatedCornerPoint(element, "bottomRight");
-  return [topLeft, topRight, bottomLeft, bottomRight];
-};
-const getMultiElementRectInfo = (elementList = []) => {
-  if (elementList.length <= 0) {
-    return {
-      minx: 0,
-      maxx: 0,
-      miny: 0,
-      maxy: 0
-    };
-  }
-  let minx = Infinity;
-  let maxx = -Infinity;
-  let miny = Infinity;
-  let maxy = -Infinity;
-  elementList.forEach((element) => {
-    let pointList = element.getEndpointList();
-    pointList.forEach(({ x, y }) => {
-      if (x < minx) {
-        minx = x;
-      }
-      if (x > maxx) {
-        maxx = x;
-      }
-      if (y < miny) {
-        miny = y;
-      }
-      if (y > maxy) {
-        maxy = y;
-      }
-    });
-  });
-  return {
-    minx,
-    maxx,
-    miny,
-    maxy
-  };
-};
-const createImageObj = (url) => {
-  return new Promise((resolve) => {
-    let img = new Image();
-    img.setAttribute("crossOrigin", "anonymous");
-    img.onload = () => {
-      resolve(img);
-    };
-    img.onerror = () => {
-      resolve(null);
-    };
-    img.src = url;
-  });
-};
-let nodeKeyIndex = 0;
-const createNodeKey = () => {
-  return nodeKeyIndex++;
-};
-var utils = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
-  __proto__: null,
-  createCanvas,
-  getTowPointDistance,
-  getPointToLineDistance,
-  checkIsAtSegment,
-  radToDeg,
-  degToRad,
-  getTowPointRotate,
-  getRotatedPoint,
-  getElementCenterPoint,
-  transformPointReverseRotate,
-  transformPointOnElement,
-  getElementCornerPoint,
-  getElementRotatedCornerPoint,
-  checkPointIsInRectangle,
-  getBoundingRect,
-  deepCopy,
-  getFontString,
-  splitTextLines,
-  getTextActWidth,
-  getMaxFontSizeInWidth,
-  getWrapTextActWidth,
-  getWrapTextMaxRowTextNumber,
-  getTextElementSize,
-  throttle,
-  computedLineWidthBySpeed,
-  downloadFile,
-  getElementCorners,
-  getMultiElementRectInfo,
-  createImageObj,
-  createNodeKey
-}, Symbol.toStringTag, { value: "Module" }));
-const CORNERS = {
-  TOP_LEFT: "topLeft",
-  TOP_RIGHT: "topRight",
-  BOTTOM_RIGHT: "bottomRight",
-  BOTTOM_LEFT: "bottomLeft"
-};
-const DRAG_ELEMENT_PARTS = {
-  BODY: "body",
-  ROTATE: "rotate",
-  TOP_LEFT_BTN: "topLeftBtn",
-  TOP_RIGHT_BTN: "topRightBtn",
-  BOTTOM_RIGHT_BTN: "bottomRightBtn",
-  BOTTOM_LEFT_BTN: "bottomLeftBtn"
-};
-const HIT_DISTANCE = 10;
-const checkIsAtMultiSegment = (segments, rp) => {
-  let res = false;
-  segments.forEach((seg) => {
-    if (res)
-      return;
-    if (checkIsAtSegment(rp.x, rp.y, ...seg, HIT_DISTANCE)) {
-      res = true;
-    }
-  });
-  return res;
-};
-const checkIsAtRectangleEdge = (element, rp) => {
-  let { x, y, width, height } = element;
-  let segments = [
-    [x, y, x + width, y],
-    [x + width, y, x + width, y + height],
-    [x + width, y + height, x, y + height],
-    [x, y + height, x, y]
-  ];
-  return checkIsAtMultiSegment(segments, rp) ? element : null;
-};
-const checkIsAtRectangleInner = (element, rp) => {
-  return checkPointIsInRectangle(rp.x, rp.y, element) ? element : null;
-};
-const getCircleRadius = (width, height) => {
-  return Math.min(Math.abs(width), Math.abs(height)) / 2;
-};
-const checkIsAtCircleEdge = (element, rp) => {
-  let { width, height, x, y } = element;
-  let radius = getCircleRadius(width, height);
-  let dis = getTowPointDistance(rp.x, rp.y, x + radius, y + radius);
-  let onCircle = dis >= radius - HIT_DISTANCE && dis <= radius + HIT_DISTANCE;
-  return onCircle ? element : null;
-};
-const checkIsAtLineEdge = (element, rp) => {
-  let segments = [];
-  let len = element.pointArr.length;
-  let arr = element.pointArr;
-  for (let i = 0; i < len - 1; i++) {
-    segments.push([...arr[i], ...arr[i + 1]]);
-  }
-  return checkIsAtMultiSegment(segments, rp) ? element : null;
-};
-const checkIsAtFreedrawLineEdge = (element, rp) => {
-  let res = null;
-  element.pointArr.forEach((point) => {
-    if (res)
-      return;
-    let dis = getTowPointDistance(rp.x, rp.y, point[0], point[1]);
-    if (dis <= HIT_DISTANCE) {
-      res = element;
-    }
-  });
-  return res;
-};
-const checkIsAtDiamondEdge = (element, rp) => {
-  let { x, y, width, height } = element;
-  let segments = [
-    [x + width / 2, y, x + width, y + height / 2],
-    [x + width, y + height / 2, x + width / 2, y + height],
-    [x + width / 2, y + height, x, y + height / 2],
-    [x, y + height / 2, x + width / 2, y]
-  ];
-  return checkIsAtMultiSegment(segments, rp) ? element : null;
-};
-const checkIsAtTriangleEdge = (element, rp) => {
-  let { x, y, width, height } = element;
-  let segments = [
-    [x + width / 2, y, x + width, y + height],
-    [x + width, y + height, x, y + height],
-    [x, y + height, x + width / 2, y]
-  ];
-  return checkIsAtMultiSegment(segments, rp) ? element : null;
-};
-const checkIsAtArrowEdge = (element, rp) => {
-  let pointArr = element.pointArr;
-  let x = pointArr[0][0];
-  let y = pointArr[0][1];
-  let tx = pointArr[pointArr.length - 1][0];
-  let ty = pointArr[pointArr.length - 1][1];
-  let segments = [[x, y, tx, ty]];
-  return checkIsAtMultiSegment(segments, rp) ? element : null;
-};
-var checkHit = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
-  __proto__: null,
-  checkIsAtMultiSegment,
-  checkIsAtRectangleEdge,
-  checkIsAtRectangleInner,
-  getCircleRadius,
-  checkIsAtCircleEdge,
-  checkIsAtLineEdge,
-  checkIsAtFreedrawLineEdge,
-  checkIsAtDiamondEdge,
-  checkIsAtTriangleEdge,
-  checkIsAtArrowEdge
-}, Symbol.toStringTag, { value: "Module" }));
-const drawWrap = (ctx, fn, fill = false) => {
-  ctx.beginPath();
-  fn();
-  ctx.stroke();
-  if (fill) {
-    ctx.fill();
-  }
-};
-const drawRect = (ctx, x, y, width, height, fill = false) => {
-  drawWrap(ctx, () => {
-    ctx.rect(x, y, width, height);
-    if (fill) {
-      ctx.fillRect(x, y, width, height);
-    }
-  });
-};
-const drawDiamond = (ctx, x, y, width, height, fill = false) => {
-  drawWrap(
-    ctx,
-    () => {
-      ctx.moveTo(x + width / 2, y);
-      ctx.lineTo(x + width, y + height / 2);
-      ctx.lineTo(x + width / 2, y + height);
-      ctx.lineTo(x, y + height / 2);
-      ctx.closePath();
-    },
-    fill
-  );
-};
-const drawTriangle = (ctx, x, y, width, height, fill = false) => {
-  drawWrap(
-    ctx,
-    () => {
-      ctx.moveTo(x + width / 2, y);
-      ctx.lineTo(x + width, y + height);
-      ctx.lineTo(x, y + height);
-      ctx.closePath();
-    },
-    fill
-  );
-};
-const drawCircle = (ctx, x, y, r, fill = false) => {
-  drawWrap(
-    ctx,
-    () => {
-      ctx.arc(x, y, r, 0, 2 * Math.PI);
-    },
-    fill
-  );
-};
-const drawLine = (ctx, points) => {
-  drawWrap(ctx, () => {
-    let first = true;
-    points.forEach((point) => {
-      if (first) {
-        first = false;
-        ctx.moveTo(point[0], point[1]);
-      } else {
-        ctx.lineTo(point[0], point[1]);
-      }
-    });
-  });
-};
-const drawArrow = (ctx, pointArr) => {
-  let x = pointArr[0][0];
-  let y = pointArr[0][1];
-  let tx = pointArr[pointArr.length - 1][0];
-  let ty = pointArr[pointArr.length - 1][1];
-  drawWrap(
-    ctx,
-    () => {
-      ctx.moveTo(x, y);
-      ctx.lineTo(tx, ty);
-    },
-    true
-  );
-  let l = 30;
-  let deg = 30;
-  let lineDeg = radToDeg(Math.atan2(ty - y, tx - x));
-  drawWrap(
-    ctx,
-    () => {
-      let plusDeg = deg - lineDeg;
-      let _x = tx - l * Math.cos(degToRad(plusDeg));
-      let _y = ty + l * Math.sin(degToRad(plusDeg));
-      ctx.moveTo(_x, _y);
-      ctx.lineTo(tx, ty);
-    },
-    true
-  );
-  drawWrap(ctx, () => {
-    let plusDeg = 90 - lineDeg - deg;
-    let _x = tx - l * Math.sin(degToRad(plusDeg));
-    let _y = ty - l * Math.cos(degToRad(plusDeg));
-    ctx.moveTo(_x, _y);
-    ctx.lineTo(tx, ty);
-  });
-};
-const transformFreeLinePoint = (point, opt) => {
-  let { x, y } = opt.app.coordinate.transform(point[0], point[1]);
-  return [x - opt.cx, y - opt.cy, ...point.slice(2)];
-};
-const drawFreeLine = (ctx, points, opt) => {
-  for (let i = 0; i < points.length - 1; i++) {
-    drawWrap(
-      ctx,
-      () => {
-        let point = transformFreeLinePoint(points[i], opt);
-        let nextPoint = transformFreeLinePoint(points[i + 1], opt);
-        drawLineSegment(
-          ctx,
-          point[0],
-          point[1],
-          nextPoint[0],
-          nextPoint[1],
-          nextPoint[2]
-        );
-      },
-      true
-    );
-  }
-};
-const drawLineSegment = (ctx, mx, my, tx, ty, lineWidth = 0) => {
-  drawWrap(ctx, () => {
-    if (lineWidth > 0) {
-      ctx.lineWidth = lineWidth;
-    }
-    ctx.moveTo(mx, my);
-    ctx.lineTo(tx, ty);
-    ctx.lineCap = "round";
-    ctx.lineJoin = "round";
-  });
-};
-const drawText = (ctx, textObj, x, y, width, height) => {
-  let { text, style } = textObj;
-  let lineHeight = style.fontSize * style.lineHeightRatio;
-  drawWrap(ctx, () => {
-    ctx.font = getFontString(style.fontSize, style.fontFamily);
-    ctx.textBaseline = "middle";
-    let textArr = splitTextLines(text);
-    textArr.forEach((textRow, index) => {
-      ctx.fillText(textRow, x, y + (index * lineHeight + lineHeight / 2));
-    });
-  });
-};
-const drawImage = (ctx, element, x, y, width, height) => {
-  drawWrap(ctx, () => {
-    let ratio = width / height;
-    let showWidth = 0;
-    let showHeight = 0;
-    if (ratio > element.ratio) {
-      showHeight = height;
-      showWidth = element.ratio * height;
-    } else {
-      showWidth = width;
-      showHeight = width / element.ratio;
-    }
-    ctx.drawImage(element.imageObj, x, y, showWidth, showHeight);
-  });
-};
-var draw = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
-  __proto__: null,
-  drawWrap,
-  drawRect,
-  drawDiamond,
-  drawTriangle,
-  drawCircle,
-  drawLine,
-  drawArrow,
-  drawFreeLine,
-  drawLineSegment,
-  drawText,
-  drawImage
-}, Symbol.toStringTag, { value: "Module" }));
-class Coordinate {
-  constructor(app) {
-    this.app = app;
-  }
-  addScrollY(y) {
-    return y + this.app.state.scrollY;
-  }
-  addScrollX(x) {
-    return x + this.app.state.scrollX;
-  }
-  subScrollY(y) {
-    return y - this.app.state.scrollY;
-  }
-  subScrollX(x) {
-    return x - this.app.state.scrollX;
-  }
-  transformToCanvasCoordinate(x, y) {
-    x -= this.app.width / 2;
-    y -= this.app.height / 2;
-    return {
-      x,
-      y
-    };
-  }
-  transformToScreenCoordinate(x, y) {
-    x += this.app.width / 2;
-    y += this.app.height / 2;
-    return {
-      x,
-      y
-    };
-  }
-  transform(x, y) {
-    let t = this.transformToCanvasCoordinate(x, y);
-    return {
-      x: this.subScrollX(t.x),
-      y: this.subScrollY(t.y)
-    };
-  }
-  windowToContainer(x, y) {
-    return {
-      x: x - this.app.left,
-      y: y - this.app.top
-    };
-  }
-  containerToWindow(x, y) {
-    return {
-      x: x + this.app.left,
-      y: y + this.app.top
-    };
-  }
-  scale(x, y) {
-    let { state } = this.app;
-    let wp = this.transformToCanvasCoordinate(x, y);
-    let sp = this.transformToScreenCoordinate(
-      wp.x * state.scale,
-      wp.y * state.scale
-    );
-    return {
-      x: sp.x,
-      y: sp.y
-    };
-  }
-  reverseScale(x, y) {
-    let { state } = this.app;
-    let tp = this.transformToCanvasCoordinate(x, y);
-    let sp = this.transformToScreenCoordinate(
-      tp.x / state.scale,
-      tp.y / state.scale
-    );
-    return {
-      x: sp.x,
-      y: sp.y
-    };
-  }
-  gridAdsorbent(x, y) {
-    let { gridConfig, showGrid } = this.app.state;
-    if (!showGrid) {
-      return {
-        x,
-        y
-      };
-    }
-    let gridSize = gridConfig.size;
-    return {
-      x: x - x % gridSize,
-      y: y - y % gridSize
-    };
-  }
-}
-class Event extends EventEmitter {
-  constructor(app) {
-    super();
-    this.app = app;
-    this.coordinate = app.coordinate;
-    this.isMousedown = false;
-    this.mousedownPos = {
-      x: 0,
-      y: 0,
-      unGridClientX: 0,
-      unGridClientY: 0,
-      originClientX: 0,
-      originClientY: 0
-    };
-    this.mouseOffset = {
-      x: 0,
-      y: 0,
-      originX: 0,
-      originY: 0
-    };
-    this.lastMousePos = {
-      x: 0,
-      y: 0
-    };
-    this.mouseDistance = 0;
-    this.lastMouseTime = Date.now();
-    this.mouseDuration = 0;
-    this.mouseSpeed = 0;
-    this.onMousedown = this.onMousedown.bind(this);
-    this.onMousemove = this.onMousemove.bind(this);
-    this.onMouseup = this.onMouseup.bind(this);
-    this.onDblclick = this.onDblclick.bind(this);
-    this.onMousewheel = this.onMousewheel.bind(this);
-    this.onKeydown = this.onKeydown.bind(this);
-    this.onKeyup = this.onKeyup.bind(this);
-    this.onContextmenu = this.onContextmenu.bind(this);
-    this.bindEvent();
-  }
-  bindEvent() {
-    this.app.container.addEventListener("mousedown", this.onMousedown);
-    this.app.container.addEventListener("mousemove", this.onMousemove);
-    this.app.container.addEventListener("mouseup", this.onMouseup);
-    this.app.container.addEventListener("dblclick", this.onDblclick);
-    this.app.container.addEventListener("mousewheel", this.onMousewheel);
-    this.app.container.addEventListener("contextmenu", this.onContextmenu);
-    window.addEventListener("keydown", this.onKeydown);
-    window.addEventListener("keyup", this.onKeyup);
-  }
-  unbindEvent() {
-    this.app.container.removeEventListener("mousedown", this.onMousedown);
-    this.app.container.removeEventListener("mousemove", this.onMousemove);
-    this.app.container.removeEventListener("mouseup", this.onMouseup);
-    this.app.container.removeEventListener("dblclick", this.onDblclick);
-    this.app.container.removeEventListener("mousewheel", this.onMousewheel);
-    this.app.container.removeEventListener("contextmenu", this.onContextmenu);
-    window.removeEventListener("keydown", this.onKeydown);
-    window.removeEventListener("keyup", this.onKeyup);
-  }
-  transformEvent(e) {
-    let { coordinate } = this.app;
-    let wp = coordinate.windowToContainer(e.clientX, e.clientY);
-    let { x, y } = coordinate.reverseScale(wp.x, wp.y);
-    x = coordinate.addScrollX(x);
-    y = coordinate.addScrollY(y);
-    let unGridClientX = x;
-    let unGridClientY = y;
-    let gp = coordinate.gridAdsorbent(x, y);
-    let newEvent = {
-      originEvent: e,
-      unGridClientX,
-      unGridClientY,
-      clientX: gp.x,
-      clientY: gp.y
-    };
-    return newEvent;
-  }
-  onMousedown(e) {
-    e = this.transformEvent(e);
-    this.isMousedown = true;
-    this.mousedownPos.x = e.clientX;
-    this.mousedownPos.y = e.clientY;
-    this.mousedownPos.unGridClientX = e.unGridClientX;
-    this.mousedownPos.unGridClientY = e.unGridClientY;
-    this.mousedownPos.originClientX = e.originEvent.clientX;
-    this.mousedownPos.originClientY = e.originEvent.clientY;
-    this.emit("mousedown", e, this);
-  }
-  onMousemove(e) {
-    e = this.transformEvent(e);
-    let x = e.clientX;
-    let y = e.clientY;
-    if (this.isMousedown) {
-      this.mouseOffset.x = x - this.mousedownPos.x;
-      this.mouseOffset.y = y - this.mousedownPos.y;
-      this.mouseOffset.originX = e.originEvent.clientX - this.mousedownPos.originClientX;
-      this.mouseOffset.originY = e.originEvent.clientY - this.mousedownPos.originClientY;
-    }
-    let curTime = Date.now();
-    this.mouseDuration = curTime - this.lastMouseTime;
-    this.mouseDistance = getTowPointDistance(
-      x,
-      y,
-      this.lastMousePos.x,
-      this.lastMousePos.y
-    );
-    this.mouseSpeed = this.mouseDistance / this.mouseDuration;
-    this.emit("mousemove", e, this);
-    this.lastMouseTime = curTime;
-    this.lastMousePos.x = x;
-    this.lastMousePos.y = y;
-  }
-  onMouseup(e) {
-    e = this.transformEvent(e);
-    this.isMousedown = false;
-    this.mousedownPos.x = 0;
-    this.mousedownPos.y = 0;
-    this.emit("mouseup", e, this);
-  }
-  onDblclick(e) {
-    e = this.transformEvent(e);
-    this.emit("dblclick", e, this);
-  }
-  onMousewheel(e) {
-    e = this.transformEvent(e);
-    this.emit("mousewheel", e.originEvent.wheelDelta < 0 ? "down" : "up");
-  }
-  onContextmenu(e) {
-    e.stopPropagation();
-    e.preventDefault();
-    e = this.transformEvent(e);
-    this.emit("contextmenu", e, this);
-  }
-  onKeydown(e) {
-    this.emit("keydown", e, this);
-  }
-  onKeyup(e) {
-    this.emit("keyup", e, this);
-  }
-}
-class BaseElement extends EventEmitter {
-  constructor(opts = {}, app) {
-    super();
-    this.app = app;
-    this.groupId = opts.groupId || "";
-    this.type = opts.type || "";
-    this.key = createNodeKey();
-    this.isCreating = true;
-    this.isActive = true;
-    this.isSelected = false;
-    this.startX = 0;
-    this.startY = 0;
-    this.x = opts.x || 0;
-    this.y = opts.y || 0;
-    this.width = opts.width || 0;
-    this.height = opts.height || 0;
-    this.startRotate = 0;
-    this.rotate = opts.rotate || 0;
-    this.noRender = false;
-    this.style = __spreadValues({
-      strokeStyle: "",
-      fillStyle: "",
-      lineWidth: "small",
-      lineDash: 0,
-      globalAlpha: 1
-    }, opts.style || {});
-    this.dragElement = null;
-  }
-  serialize() {
-    return {
-      groupId: this.groupId,
-      type: this.type,
-      width: this.width,
-      height: this.height,
-      x: this.x,
-      y: this.y,
-      rotate: this.rotate,
-      style: __spreadValues({}, this.style)
-    };
-  }
-  render() {
-    throw new Error("\u5B50\u7C7B\u9700\u8981\u5B9E\u73B0\u8BE5\u65B9\u6CD5\uFF01");
-  }
-  setGroupId(groupId) {
-    this.groupId = groupId;
-  }
-  getGroupId() {
-    return this.groupId;
-  }
-  removeGroupId() {
-    this.groupId = "";
-  }
-  hasGroup() {
-    return !!this.groupId;
-  }
-  renderDragElement() {
-    if (this.isActive && !this.isCreating) {
-      this.dragElement.showAll();
-      this.dragElement.render();
-    } else if (this.isSelected) {
-      this.dragElement.onlyShowBody();
-      this.dragElement.render();
-    }
-  }
-  handleStyle(style) {
-    Object.keys(style).forEach((key) => {
-      if (key === "lineWidth") {
-        if (style[key] === "small") {
-          style[key] = 2;
-        } else if (style[key] === "middle") {
-          style[key] = 4;
-        } else if (style[key] === "large") {
-          style[key] = 6;
-        }
-      }
-      if (style[key] === "") {
-        if (this.app.state[key] !== void 0 && this.app.state[key] !== null && this.app.state[key] !== "") {
-          style[key] = this.app.state[key];
-        }
-      }
-    });
-    return style;
-  }
-  setStyle(style = {}) {
-    let _style = this.handleStyle(style);
-    Object.keys(_style).forEach((key) => {
-      if (key === "lineDash") {
-        if (_style.lineDash > 0) {
-          this.app.ctx.setLineDash([_style.lineDash]);
-        }
-      } else if (_style[key] !== void 0 && _style[key] !== "" && _style[key] !== null) {
-        this.app.ctx[key] = _style[key];
-      }
-    });
-    return this;
-  }
-  warpRender(renderFn) {
-    let { x, y, width, height, rotate, style } = this;
-    let { x: tx, y: ty } = this.app.coordinate.transform(x, y);
-    let halfWidth = width / 2;
-    let halfHeight = height / 2;
-    let cx = tx + halfWidth;
-    let cy = ty + halfHeight;
-    this.app.ctx.save();
-    this.app.ctx.translate(cx, cy);
-    this.app.ctx.rotate(degToRad(rotate));
-    this.setStyle(style);
-    renderFn({
-      halfWidth,
-      halfHeight,
-      tx,
-      ty,
-      cx,
-      cy
-    });
-    this.app.ctx.restore();
-    return this;
-  }
-  saveState() {
-    let { rotate, x, y } = this;
-    this.startRotate = rotate;
-    this.startX = x;
-    this.startY = y;
-    return this;
-  }
-  move(ox, oy) {
-    let { startX, startY } = this;
-    this.x = startX + ox;
-    this.y = startY + oy;
-    this.emit("elementPositionChange", this.x, this.y);
-    return this;
-  }
-  updateRect(x, y, width, height) {
-    this.updatePos(x, y);
-    this.updateSize(width, height);
-    return this;
-  }
-  updateSize(width, height) {
-    this.width = width;
-    this.height = height;
-    this.emit("elementSizeChange", this.width, this.height);
-    return this;
-  }
-  updatePos(x, y) {
-    this.x = x;
-    this.y = y;
-    this.emit("elementPositionChange", this.x, this.y);
-    return this;
-  }
-  offsetRotate(or) {
-    this.updateRotate(this.startRotate + or);
-    return this;
-  }
-  updateRotate(rotate) {
-    rotate = rotate % 360;
-    if (rotate < 0) {
-      rotate = 360 + rotate;
-    }
-    this.rotate = parseInt(rotate);
-    this.emit("elementRotateChange", this.rotate);
-  }
-  rotateByCenter(rotate, cx, cy) {
-    this.offsetRotate(rotate);
-    let np = getRotatedPoint(this.startX, this.startY, cx, cy, rotate);
-    this.updatePos(np.x, np.y);
-  }
-  isHit(x, y) {
-    throw new Error("\u5B50\u7C7B\u9700\u8981\u5B9E\u73B0\u8BE5\u65B9\u6CD5!");
-  }
-  startResize(resizeType, e) {
-    this.dragElement.startResize(resizeType, e);
-    return this;
-  }
-  endResize() {
-    this.dragElement.endResize();
-    return this;
-  }
-  resize(...args) {
-    this.dragElement.handleResizeElement(...args);
-    return this;
-  }
-  getEndpointList() {
-    return getElementCorners(this);
-  }
-}
-class DragElement extends BaseElement {
-  constructor(element, app, opts = {}) {
-    super(
-      {
-        type: "dragElement",
-        notNeedDragElement: true
-      },
-      app
-    );
-    this.opts = __spreadValues({
-      lockRatio: false
-    }, opts);
-    this.style = {
-      strokeStyle: this.app.state.dragStrokeStyle,
-      fillStyle: "transparent",
-      lineWidth: "small",
-      lineDash: 0,
-      globalAlpha: 1
-    };
-    this.element = element;
-    this.offset = 5;
-    this.size = 10;
-    this.resizeType = "";
-    this.diagonalPoint = {
-      x: 0,
-      y: 0
-    };
-    this.mousedownPosAndElementPosOffset = {
-      x: 0,
-      y: 0
-    };
-    this.elementRatio = 0;
-    this.hideParts = [];
-  }
-  setHideParts(parts = []) {
-    this.hideParts = parts;
-  }
-  showAll() {
-    this.setHideParts([]);
-  }
-  onlyShowBody() {
-    this.setHideParts([
-      DRAG_ELEMENT_PARTS.ROTATE,
-      DRAG_ELEMENT_PARTS.TOP_LEFT_BTN,
-      DRAG_ELEMENT_PARTS.TOP_RIGHT_BTN,
-      DRAG_ELEMENT_PARTS.BOTTOM_RIGHT_BTN,
-      DRAG_ELEMENT_PARTS.BOTTOM_LEFT_BTN
-    ]);
-  }
-  update() {
-    this.x = this.element.x - this.offset;
-    this.y = this.element.y - this.offset;
-    this.width = this.element.width + this.offset * 2;
-    this.height = this.element.height + this.offset * 2;
-    this.rotate = this.element.rotate;
-  }
-  render() {
-    if (this.element.hasGroup())
-      return;
-    this.update();
-    let { width, height } = this;
-    this.warpRender(({ halfWidth, halfHeight }) => {
-      this.app.ctx.save();
-      if (!this.hideParts.includes(DRAG_ELEMENT_PARTS.BODY)) {
-        this.app.ctx.setLineDash([5]);
-        drawRect(this.app.ctx, -halfWidth, -halfHeight, width, height);
-        this.app.ctx.restore();
-      }
-      if (!this.hideParts.includes(DRAG_ELEMENT_PARTS.TOP_LEFT_BTN)) {
-        drawRect(
-          this.app.ctx,
-          -halfWidth - this.size,
-          -halfHeight - this.size,
-          this.size,
-          this.size
-        );
-      }
-      if (!this.hideParts.includes(DRAG_ELEMENT_PARTS.TOP_RIGHT_BTN)) {
-        drawRect(
-          this.app.ctx,
-          -halfWidth + this.element.width + this.size,
-          -halfHeight - this.size,
-          this.size,
-          this.size
-        );
-      }
-      if (!this.hideParts.includes(DRAG_ELEMENT_PARTS.BOTTOM_RIGHT_BTN)) {
-        drawRect(
-          this.app.ctx,
-          -halfWidth + this.element.width + this.size,
-          -halfHeight + this.element.height + this.size,
-          this.size,
-          this.size
-        );
-      }
-      if (!this.hideParts.includes(DRAG_ELEMENT_PARTS.BOTTOM_LEFT_BTN)) {
-        drawRect(
-          this.app.ctx,
-          -halfWidth - this.size,
-          -halfHeight + this.element.height + this.size,
-          this.size,
-          this.size
-        );
-      }
-      if (!this.hideParts.includes(DRAG_ELEMENT_PARTS.ROTATE)) {
-        drawCircle(
-          this.app.ctx,
-          -halfWidth + this.element.width / 2 + this.size / 2,
-          -halfHeight - this.size * 2,
-          this.size
-        );
-      }
-    });
-  }
-  checkPointInDragElementWhere(x, y) {
-    let part = "";
-    let rp = transformPointOnElement(x, y, this.element);
-    if (checkPointIsInRectangle(rp.x, rp.y, this)) {
-      part = DRAG_ELEMENT_PARTS.BODY;
-    } else if (getTowPointDistance(
-      rp.x,
-      rp.y,
-      this.x + this.width / 2,
-      this.y - this.size * 2
-    ) <= this.size) {
-      part = DRAG_ELEMENT_PARTS.ROTATE;
-    } else if (this._checkPointIsInBtn(rp.x, rp.y, CORNERS.TOP_LEFT)) {
-      part = DRAG_ELEMENT_PARTS.TOP_LEFT_BTN;
-    } else if (this._checkPointIsInBtn(rp.x, rp.y, CORNERS.TOP_RIGHT)) {
-      part = DRAG_ELEMENT_PARTS.TOP_RIGHT_BTN;
-    } else if (this._checkPointIsInBtn(rp.x, rp.y, CORNERS.BOTTOM_RIGHT)) {
-      part = DRAG_ELEMENT_PARTS.BOTTOM_RIGHT_BTN;
-    } else if (this._checkPointIsInBtn(rp.x, rp.y, CORNERS.BOTTOM_LEFT)) {
-      part = DRAG_ELEMENT_PARTS.BOTTOM_LEFT_BTN;
-    }
-    if (this.hideParts.includes(part)) {
-      part = "";
-    }
-    return part;
-  }
-  _checkPointIsInBtn(x, y, dir) {
-    let _x = 0;
-    let _y = 0;
-    switch (dir) {
-      case CORNERS.TOP_LEFT:
-        _x = this.x - this.size;
-        _y = this.y - this.size;
-        break;
-      case CORNERS.TOP_RIGHT:
-        _x = this.x + this.width;
-        _y = this.y - this.size;
-        break;
-      case CORNERS.BOTTOM_RIGHT:
-        _x = this.x + this.width;
-        _y = this.y + this.height;
-        break;
-      case CORNERS.BOTTOM_LEFT:
-        _x = this.x - this.size;
-        _y = this.y + this.height;
-        break;
-    }
-    return checkPointIsInRectangle(x, y, _x, _y, this.size, this.size);
-  }
-  startResize(resizeType, e) {
-    this.resizeType = resizeType;
-    if (this.opts.lockRatio) {
-      this.elementRatio = this.element.width / this.element.height;
-    }
-    if (resizeType === DRAG_ELEMENT_PARTS.BODY) {
-      this.element.saveState();
-    } else if (resizeType === DRAG_ELEMENT_PARTS.ROTATE) {
-      this.element.saveState();
-    } else if (resizeType === DRAG_ELEMENT_PARTS.TOP_LEFT_BTN) {
-      this.handleDragMousedown(e, CORNERS.TOP_LEFT);
-    } else if (resizeType === DRAG_ELEMENT_PARTS.TOP_RIGHT_BTN) {
-      this.handleDragMousedown(e, CORNERS.TOP_RIGHT);
-    } else if (resizeType === DRAG_ELEMENT_PARTS.BOTTOM_RIGHT_BTN) {
-      this.handleDragMousedown(e, CORNERS.BOTTOM_RIGHT);
-    } else if (resizeType === DRAG_ELEMENT_PARTS.BOTTOM_LEFT_BTN) {
-      this.handleDragMousedown(e, CORNERS.BOTTOM_LEFT);
-    }
-  }
-  endResize() {
-    this.resizeType = "";
-    this.diagonalPoint = {
-      x: 0,
-      y: 0
-    };
-    this.mousedownPosAndElementPosOffset = {
-      x: 0,
-      y: 0
-    };
-    this.elementRatio = 0;
-  }
-  handleDragMousedown(e, corner) {
-    let centerPos = getElementCenterPoint(this.element);
-    let pos = getElementRotatedCornerPoint(this.element, corner);
-    this.diagonalPoint.x = 2 * centerPos.x - pos.x;
-    this.diagonalPoint.y = 2 * centerPos.y - pos.y;
-    this.mousedownPosAndElementPosOffset.x = e.clientX - pos.x;
-    this.mousedownPosAndElementPosOffset.y = e.clientY - pos.y;
-    this.element.saveState();
-  }
-  handleResizeElement(e, mx, my, offsetX, offsetY) {
-    let resizeType = this.resizeType;
-    if (resizeType === DRAG_ELEMENT_PARTS.BODY) {
-      this.handleMoveElement(offsetX, offsetY);
-    } else if (resizeType === DRAG_ELEMENT_PARTS.ROTATE) {
-      this.handleRotateElement(e, mx, my);
-    } else if (resizeType === DRAG_ELEMENT_PARTS.TOP_LEFT_BTN) {
-      this.handleStretchElement(
-        e,
-        (newCenter, rp) => {
-          return {
-            width: (newCenter.x - rp.x) * 2,
-            height: (newCenter.y - rp.y) * 2
-          };
-        },
-        (rp) => {
-          return {
-            x: rp.x,
-            y: rp.y
-          };
-        },
-        (newRatio, newRect) => {
-          let x = newRect.x;
-          let y = newRect.y;
-          if (newRatio > this.elementRatio) {
-            x = newRect.x + newRect.width - this.elementRatio * newRect.height;
-          } else if (newRatio < this.elementRatio) {
-            y = newRect.y + (newRect.height - newRect.width / this.elementRatio);
-          }
-          return {
-            x,
-            y
-          };
-        }
-      );
-    } else if (resizeType === DRAG_ELEMENT_PARTS.TOP_RIGHT_BTN) {
-      this.handleStretchElement(
-        e,
-        (newCenter, rp) => {
-          return {
-            width: (rp.x - newCenter.x) * 2,
-            height: (newCenter.y - rp.y) * 2
-          };
-        },
-        (rp, newSize) => {
-          return {
-            x: rp.x - newSize.width,
-            y: rp.y
-          };
-        },
-        (newRatio, newRect) => {
-          let x = newRect.x;
-          let y = newRect.y;
-          if (newRatio > this.elementRatio) {
-            x = newRect.x + this.elementRatio * newRect.height;
-          } else if (newRatio < this.elementRatio) {
-            x = newRect.x + newRect.width;
-            y = newRect.y + (newRect.height - newRect.width / this.elementRatio);
-          }
-          return {
-            x,
-            y
-          };
-        }
-      );
-    } else if (resizeType === DRAG_ELEMENT_PARTS.BOTTOM_RIGHT_BTN) {
-      this.handleStretchElement(
-        e,
-        (newCenter, rp) => {
-          return {
-            width: (rp.x - newCenter.x) * 2,
-            height: (rp.y - newCenter.y) * 2
-          };
-        },
-        (rp, newSize) => {
-          return {
-            x: rp.x - newSize.width,
-            y: rp.y - newSize.height
-          };
-        },
-        (newRatio, newRect) => {
-          let x = newRect.x;
-          let y = newRect.y;
-          if (newRatio > this.elementRatio) {
-            x = newRect.x + this.elementRatio * newRect.height;
-            y = newRect.y + newRect.height;
-          } else if (newRatio < this.elementRatio) {
-            x = newRect.x + newRect.width;
-            y = newRect.y + newRect.width / this.elementRatio;
-          }
-          return {
-            x,
-            y
-          };
-        }
-      );
-    } else if (resizeType === DRAG_ELEMENT_PARTS.BOTTOM_LEFT_BTN) {
-      this.handleStretchElement(
-        e,
-        (newCenter, rp) => {
-          return {
-            width: (newCenter.x - rp.x) * 2,
-            height: (rp.y - newCenter.y) * 2
-          };
-        },
-        (rp, newSize) => {
-          return {
-            x: rp.x,
-            y: rp.y - newSize.height
-          };
-        },
-        (newRatio, newRect) => {
-          let x = newRect.x;
-          let y = newRect.y;
-          if (newRatio > this.elementRatio) {
-            x = newRect.x + newRect.width - this.elementRatio * newRect.height;
-            y = newRect.y + newRect.height;
-          } else if (newRatio < this.elementRatio) {
-            y = newRect.y + newRect.width / this.elementRatio;
-          }
-          return {
-            x,
-            y
-          };
-        }
-      );
-    }
-  }
-  handleMoveElement(offsetX, offsetY) {
-    this.element.move(offsetX, offsetY);
-  }
-  handleRotateElement(e, mx, my) {
-    let centerPos = getElementCenterPoint(this.element);
-    let rotate = getTowPointRotate(
-      centerPos.x,
-      centerPos.y,
-      e.clientX,
-      e.clientY,
-      mx,
-      my
-    );
-    this.element.offsetRotate(rotate);
-  }
-  stretchCalc(x, y, calcSize, calcPos) {
-    let newCenter = {
-      x: (x + this.diagonalPoint.x) / 2,
-      y: (y + this.diagonalPoint.y) / 2
-    };
-    let rp = transformPointReverseRotate(
-      x,
-      y,
-      newCenter.x,
-      newCenter.y,
-      this.element.rotate
-    );
-    let newSize = calcSize(newCenter, rp);
-    let isWidthReverse = false;
-    if (newSize.width < 0) {
-      newSize.width = 0;
-      isWidthReverse = true;
-    }
-    let isHeightReverse = false;
-    if (newSize.height < 0) {
-      newSize.height = 0;
-      isHeightReverse = true;
-    }
-    let newPos = calcPos(rp, newSize);
-    let newRect = {
-      x: newPos.x,
-      y: newPos.y,
-      width: newSize.width,
-      height: newSize.height
-    };
-    if (isWidthReverse || isHeightReverse) {
-      newRect.x = this.element.x;
-      newRect.y = this.element.y;
-    }
-    return {
-      newRect,
-      newCenter
-    };
-  }
-  handleStretchElement(e, calcSize, calcPos, fixPos) {
-    let actClientX = e.clientX - this.mousedownPosAndElementPosOffset.x;
-    let actClientY = e.clientY - this.mousedownPosAndElementPosOffset.y;
-    let { newRect, newCenter } = this.stretchCalc(
-      actClientX,
-      actClientY,
-      calcSize,
-      calcPos
-    );
-    if (this.opts.lockRatio) {
-      this.fixStretch(newRect, newCenter, calcSize, calcPos, fixPos);
-      return;
-    }
-    this.element.updateRect(newRect.x, newRect.y, newRect.width, newRect.height);
-  }
-  fixStretch(newRect, newCenter, calcSize, calcPos, fixPos) {
-    let newRatio = newRect.width / newRect.height;
-    let fp = fixPos(newRatio, newRect);
-    let rp = getRotatedPoint(
-      fp.x,
-      fp.y,
-      newCenter.x,
-      newCenter.y,
-      this.element.rotate
-    );
-    let fixNewRect = this.stretchCalc(rp.x, rp.y, calcSize, calcPos).newRect;
-    if (fixNewRect.width === 0 && fixNewRect.height === 0) {
-      return;
-    }
-    this.element.updateRect(
-      fixNewRect.x,
-      fixNewRect.y,
-      fixNewRect.width,
-      fixNewRect.height
-    );
-  }
-}
-class Rectangle extends BaseElement {
-  constructor(...args) {
-    super(...args);
-    this.dragElement = new DragElement(this, this.app);
-  }
-  render() {
-    let { width, height } = this;
-    this.warpRender(({ halfWidth, halfHeight }) => {
-      drawRect(this.app.ctx, -halfWidth, -halfHeight, width, height, true);
-    });
-    this.renderDragElement();
-  }
-  isHit(x, y) {
-    let rp = transformPointOnElement(x, y, this);
-    return checkIsAtRectangleEdge(this, rp);
-  }
-}
-class Circle extends BaseElement {
-  constructor(...args) {
-    super(...args);
-    this.dragElement = new DragElement(this, this.app, {
-      lockRatio: true
-    });
-  }
-  render() {
-    let { width, height } = this;
-    this.warpRender(({ halfWidth, halfHeight }) => {
-      drawCircle(this.app.ctx, 0, 0, getCircleRadius(width, height), true);
-    });
-    this.renderDragElement();
-  }
-  isHit(x, y) {
-    let rp = transformPointOnElement(x, y, this);
-    return checkIsAtCircleEdge(this, rp);
-  }
-}
-class Diamond extends BaseElement {
-  constructor(...args) {
-    super(...args);
-    this.dragElement = new DragElement(this, this.app);
-  }
-  render() {
-    let { width, height } = this;
-    this.warpRender(({ halfWidth, halfHeight }) => {
-      drawDiamond(this.app.ctx, -halfWidth, -halfHeight, width, height, true);
-    });
-    this.renderDragElement();
-  }
-  isHit(x, y) {
-    let rp = transformPointOnElement(x, y, this);
-    return checkIsAtDiamondEdge(this, rp);
-  }
-  getEndpointList() {
-    let { x, y, width, height, rotate } = this;
-    let points = [
-      [x + width / 2, y],
-      [x + width, y + height / 2],
-      [x + width / 2, y + height],
-      [x, y + height / 2]
-    ];
-    let center = getElementCenterPoint(this);
-    return points.map((point) => {
-      return getRotatedPoint(point[0], point[1], center.x, center.y, rotate);
-    });
-  }
-}
-class Triangle extends BaseElement {
-  constructor(...args) {
-    super(...args);
-    this.dragElement = new DragElement(this, this.app);
-  }
-  render() {
-    let { width, height } = this;
-    this.warpRender(({ halfWidth, halfHeight }) => {
-      drawTriangle(this.app.ctx, -halfWidth, -halfHeight, width, height, true);
-    });
-    this.renderDragElement();
-  }
-  isHit(x, y) {
-    let rp = transformPointOnElement(x, y, this);
-    return checkIsAtTriangleEdge(this, rp);
-  }
-  getEndpointList() {
-    let { x, y, width, height, rotate } = this;
-    let points = [
-      [x + width / 2, y],
-      [x + width, y + height],
-      [x, y + height]
-    ];
-    let center = getElementCenterPoint(this);
-    return points.map((point) => {
-      return getRotatedPoint(point[0], point[1], center.x, center.y, rotate);
-    });
-  }
-}
-class BaseMultiPointElement extends BaseElement {
-  constructor(opts = {}, app) {
-    super(opts, app);
-    this.startPointArr = [];
-    this.pointArr = opts.pointArr || [];
-    this.startWidth = 0;
-    this.startHeight = 0;
-    this.fictitiousPoint = {
-      x: 0,
-      y: 0
-    };
-  }
-  serialize() {
-    let base = super.serialize();
-    return __spreadProps(__spreadValues({}, base), {
-      pointArr: [...this.pointArr]
-    });
-  }
-  addPoint(x, y, ...args) {
-    if (!Array.isArray(this.pointArr)) {
-      return;
-    }
-    this.pointArr.push([x, y, ...args]);
-    return this;
-  }
-  updateMultiPointBoundingRect() {
-    let rect = getBoundingRect(this.pointArr);
-    this.x = rect.x;
-    this.y = rect.y;
-    this.width = rect.width;
-    this.height = rect.height;
-    return this;
-  }
-  updateFictitiousPoint(x, y) {
-    this.fictitiousPoint.x = x;
-    this.fictitiousPoint.y = y;
-  }
-  saveState() {
-    let { rotate, x, y, width, height, pointArr } = this;
-    this.startRotate = rotate;
-    this.startX = x;
-    this.startY = y;
-    this.startPointArr = deepCopy(pointArr);
-    this.startWidth = width;
-    this.startHeight = height;
-    return this;
-  }
-  move(ox, oy) {
-    this.pointArr = this.startPointArr.map((point) => {
-      return [point[0] + ox, point[1] + oy, ...point.slice(2)];
-    });
-    let { startX, startY } = this;
-    this.x = startX + ox;
-    this.y = startY + oy;
-    return this;
-  }
-  updateRect(x, y, width, height) {
-    let { startWidth, startHeight, startPointArr } = this;
-    let scaleX = width / startWidth;
-    let scaleY = height / startHeight;
-    this.pointArr = startPointArr.map((point) => {
-      let nx = point[0] * scaleX;
-      let ny = point[1] * scaleY;
-      return [nx, ny, ...point.slice(2)];
-    });
-    let rect = getBoundingRect(this.pointArr);
-    let offsetX = rect.x - x;
-    let offsetY = rect.y - y;
-    this.pointArr = this.pointArr.map((point) => {
-      return [point[0] - offsetX, point[1] - offsetY, ...point.slice(2)];
-    });
-    this.updatePos(x, y);
-    this.updateSize(width, height);
-    return this;
-  }
-  rotateByCenter(rotate, cx, cy) {
-    this.pointArr = this.startPointArr.map((point) => {
-      let np = getRotatedPoint(point[0], point[1], cx, cy, rotate);
-      return [np.x, np.y, ...point.slice(2)];
-    });
-    this.updateMultiPointBoundingRect();
-  }
-  getEndpointList() {
-    return this.pointArr.map((point) => {
-      let center = getElementCenterPoint(this);
-      let np = getRotatedPoint(
-        point[0],
-        point[1],
-        center.x,
-        center.y,
-        this.rotate
-      );
-      return {
-        x: np.x,
-        y: np.y
-      };
-    });
-  }
-}
-class Freedraw extends BaseMultiPointElement {
-  constructor(...args) {
-    super(...args);
-    this.dragElement = new DragElement(this, this.app);
-    this.lastLineWidth = -1;
-  }
-  render() {
-    let { pointArr } = this;
-    this.warpRender(({ cx, cy }) => {
-      drawFreeLine(this.app.ctx, pointArr, {
-        app: this.app,
-        cx,
-        cy
-      });
-    });
-    this.renderDragElement();
-  }
-  isHit(x, y) {
-    let rp = transformPointOnElement(x, y, this);
-    return checkIsAtFreedrawLineEdge(this, rp);
-  }
-  singleRender(mx, my, tx, ty, lineWidth) {
-    this.app.ctx.save();
-    this.setStyle(this.style);
-    drawLineSegment(this.app.ctx, mx, my, tx, ty, lineWidth);
-    this.app.ctx.restore();
-  }
-}
-class Arrow extends BaseMultiPointElement {
-  constructor(...args) {
-    super(...args);
-    this.dragElement = new DragElement(this, this.app);
-  }
-  render() {
-    let { pointArr, fictitiousPoint } = this;
-    this.warpRender(({ cx, cy }) => {
-      let realtimePoint = [];
-      if (pointArr.length > 0 && this.isCreating) {
-        let { x: fx, y: fy } = this.app.coordinate.transform(
-          fictitiousPoint.x - cx,
-          fictitiousPoint.y - cy
-        );
-        realtimePoint = [[fx, fy]];
-      }
-      drawArrow(
-        this.app.ctx,
-        pointArr.map((point) => {
-          let { x, y } = this.app.coordinate.transform(point[0], point[1]);
-          return [x - cx, y - cy];
-        }).concat(realtimePoint)
-      );
-    });
-    this.renderDragElement();
-  }
-  isHit(x, y) {
-    let rp = transformPointOnElement(x, y, this);
-    return checkIsAtArrowEdge(this, rp);
-  }
-}
-class Image$1 extends BaseElement {
-  constructor(opts = {}, app) {
-    super(opts, app);
-    this.dragElement = new DragElement(this, this.app, {
-      lockRatio: true
-    });
-    this.url = opts.url || "";
-    this.imageObj = opts.imageObj || null;
-    this.ratio = opts.ratio || 1;
-  }
-  serialize() {
-    let base = super.serialize();
-    return __spreadProps(__spreadValues({}, base), {
-      url: this.url,
-      ratio: this.ratio
-    });
-  }
-  render() {
-    let { width, height } = this;
-    this.warpRender(({ halfWidth, halfHeight }) => {
-      drawImage(this.app.ctx, this, -halfWidth, -halfHeight, width, height);
-    });
-    this.renderDragElement();
-  }
-  isHit(x, y) {
-    let rp = transformPointOnElement(x, y, this);
-    return checkIsAtRectangleInner(this, rp);
-  }
-}
-class Line extends BaseMultiPointElement {
-  constructor(opts = {}, app) {
-    super(opts, app);
-    this.dragElement = new DragElement(this, this.app);
-    this.isSingle = opts.isSingle;
-  }
-  render() {
-    let { pointArr, fictitiousPoint } = this;
-    this.warpRender(({ cx, cy }) => {
-      let realtimePoint = [];
-      if (pointArr.length > 0 && this.isCreating) {
-        let { x: fx, y: fy } = this.app.coordinate.transform(
-          fictitiousPoint.x - cx,
-          fictitiousPoint.y - cy
-        );
-        realtimePoint = [[fx, fy]];
-      }
-      drawLine(
-        this.app.ctx,
-        pointArr.map((point) => {
-          let { x, y } = this.app.coordinate.transform(point[0], point[1]);
-          return [x - cx, y - cy];
-        }).concat(realtimePoint)
-      );
-    });
-    this.renderDragElement();
-  }
-  isHit(x, y) {
-    let rp = transformPointOnElement(x, y, this);
-    return checkIsAtLineEdge(this, rp);
-  }
-}
-class Text extends BaseElement {
-  constructor(opts = {}, app) {
-    var _a, _b, _c, _d;
-    super(opts, app);
-    this.dragElement = new DragElement(this, this.app, {
-      lockRatio: true
-    });
-    this.text = opts.text || "";
-    this.style.fillStyle = ((_a = opts.style) == null ? void 0 : _a.fillStyle) || this.app.state.strokeStyle || "#000";
-    this.style.fontSize = ((_b = opts.style) == null ? void 0 : _b.fontSize) || this.app.state.fontSize || 18;
-    this.style.lineHeightRatio = ((_c = opts.style) == null ? void 0 : _c.lineHeightRatio) || 1.5;
-    this.style.fontFamily = ((_d = opts.style) == null ? void 0 : _d.fontFamily) || this.app.state.fontFamily || "\u5FAE\u8F6F\u96C5\u9ED1, Microsoft YaHei";
-  }
-  serialize() {
-    let base = super.serialize();
-    return __spreadProps(__spreadValues({}, base), {
-      text: this.text
-    });
-  }
-  render() {
-    this.warpRender(({ halfWidth, halfHeight }) => {
-      drawText(this.app.ctx, this, -halfWidth, -halfHeight);
-    });
-    this.renderDragElement();
-  }
-  isHit(x, y) {
-    let rp = transformPointOnElement(x, y, this);
-    return checkIsAtRectangleInner(this, rp);
-  }
-  updateRect(x, y, width, height) {
-    let { text, style } = this;
-    let fontSize = Math.floor(
-      height / splitTextLines(text).length / style.lineHeightRatio
-    );
-    this.style.fontSize = fontSize;
-    super.updateRect(x, y, width, height);
-  }
-  updateTextSize() {
-    let { width, height } = getTextElementSize(this);
-    this.width = width;
-    this.height = height;
-  }
-}
-class Elements$1 {
-  constructor(app) {
-    this.app = app;
-    this.elementList = [];
-    this.activeElement = null;
-    this.isCreatingElement = false;
-    this.isResizing = false;
-    this.resizingElement = null;
-    this.handleResize = throttle(this.handleResize, this, 16);
-  }
-  serialize(stringify = false) {
-    let data = this.elementList.map((element) => {
-      return element.serialize();
-    });
-    return stringify ? JSON.stringify(data) : data;
-  }
-  getElementsNum() {
-    return this.elementList.length;
-  }
-  hasElements() {
-    return this.elementList.length > 0;
-  }
-  addElement(element) {
-    this.elementList.push(element);
-    return this;
-  }
-  unshiftElement(element) {
-    this.elementList.unshift(element);
-    return this;
-  }
-  insertElement(element, index) {
-    this.elementList.splice(index, 0, element);
-  }
-  deleteElement(element) {
-    let index = this.getElementIndex(element);
-    if (index !== -1) {
-      this.elementList.splice(index, 1);
-      if (element.isActive) {
-        this.cancelActiveElement(element);
-      }
-    }
-    return this;
-  }
-  deleteAllElements() {
-    this.activeElement = null;
-    this.elementList = [];
-    this.isCreatingElement = false;
-    this.isResizing = false;
-    this.resizingElement = null;
-    return this;
-  }
-  getElementIndex(element) {
-    return this.elementList.findIndex((item) => {
-      return item === element;
-    });
-  }
-  createElementsFromData(data) {
-    data.forEach((item) => {
-      let element = this.pureCreateElement(item);
-      element.isActive = false;
-      element.isCreating = false;
-      this.addElement(element);
-    });
-    this.app.group.initIdToElementList(this.elementList);
-    return this;
-  }
-  hasActiveElement() {
-    return !!this.activeElement;
-  }
-  setActiveElement(element) {
-    this.cancelActiveElement();
-    this.activeElement = element;
-    if (element) {
-      element.isActive = true;
-    }
-    this.app.emit("activeElementChange", this.activeElement);
-    return this;
-  }
-  cancelActiveElement() {
-    if (!this.hasActiveElement()) {
-      return this;
-    }
-    this.activeElement.isActive = false;
-    this.activeElement = null;
-    this.app.emit("activeElementChange", this.activeElement);
-    return this;
-  }
-  checkIsHitElement(e) {
-    let x = e.unGridClientX;
-    let y = e.unGridClientY;
-    for (let i = this.elementList.length - 1; i >= 0; i--) {
-      let element = this.elementList[i];
-      if (element.isHit(x, y)) {
-        return element;
-      }
-    }
-    return null;
-  }
-  pureCreateElement(opts = {}) {
-    switch (opts.type) {
-      case "rectangle":
-        return new Rectangle(opts, this.app);
-      case "diamond":
-        return new Diamond(opts, this.app);
-      case "triangle":
-        return new Triangle(opts, this.app);
-      case "circle":
-        return new Circle(opts, this.app);
-      case "freedraw":
-        return new Freedraw(opts, this.app);
-      case "image":
-        return new Image$1(opts, this.app);
-      case "arrow":
-        return new Arrow(opts, this.app);
-      case "line":
-        return new Line(opts, this.app);
-      case "text":
-        return new Text(opts, this.app);
-      default:
-        return null;
-    }
-  }
-  createElement(opts = {}, callback = () => {
-  }, ctx = null, notActive) {
-    if (this.hasActiveElement() || this.isCreatingElement) {
-      return this;
-    }
-    let element = this.pureCreateElement(opts);
-    if (!element) {
-      return this;
-    }
-    this.addElement(element);
-    if (!notActive) {
-      this.setActiveElement(element);
-    }
-    this.isCreatingElement = true;
-    callback.call(ctx, element);
-    return this;
-  }
-  copyElement(element, notActive = false, pos) {
-    return new Promise((resolve) => __async(this, null, function* () {
-      if (!element) {
-        return resolve();
-      }
-      let data = this.app.group.handleCopyElementData(element.serialize());
-      if (data.type === "image") {
-        data.imageObj = yield createImageObj(data.url);
-      }
-      this.createElement(
-        data,
-        (element2) => {
-          this.app.group.handleCopyElement(element2);
-          element2.startResize(DRAG_ELEMENT_PARTS.BODY);
-          let ox = 20;
-          let oy = 20;
-          if (pos) {
-            ox = pos.x - element2.x - element2.width / 2;
-            oy = pos.y - element2.y - element2.height / 2;
-          }
-          let gridAdsorbentPos = this.app.coordinate.gridAdsorbent(ox, oy);
-          element2.resize(
-            null,
-            null,
-            null,
-            gridAdsorbentPos.x,
-            gridAdsorbentPos.y
-          );
-          element2.isCreating = false;
-          if (notActive) {
-            element2.isActive = false;
-          }
-          this.isCreatingElement = false;
-          resolve(element2);
-        },
-        this,
-        notActive
-      );
-    }));
-  }
-  creatingRectangleLikeElement(type, x, y, offsetX, offsetY) {
-    this.createElement({
-      type,
-      x,
-      y,
-      width: offsetX,
-      height: offsetY
-    });
-    this.activeElement.updateSize(offsetX, offsetY);
-  }
-  creatingCircle(x, y, e) {
-    this.createElement({
-      type: "circle",
-      x,
-      y
-    });
-    let radius = getTowPointDistance(e.clientX, e.clientY, x, y);
-    this.activeElement.updateSize(radius, radius);
-  }
-  creatingFreedraw(e, event) {
-    this.createElement({
-      type: "freedraw"
-    });
-    let element = this.activeElement;
-    let lineWidth = computedLineWidthBySpeed(
-      event.mouseSpeed,
-      element.lastLineWidth
-    );
-    element.lastLineWidth = lineWidth;
-    element.addPoint(e.clientX, e.clientY, lineWidth);
-    let { coordinate, ctx, state } = this.app;
-    let tfp = coordinate.transformToCanvasCoordinate(
-      coordinate.subScrollX(event.lastMousePos.x),
-      coordinate.subScrollY(event.lastMousePos.y)
-    );
-    let ttp = coordinate.transformToCanvasCoordinate(
-      coordinate.subScrollX(e.clientX),
-      coordinate.subScrollY(e.clientY)
-    );
-    ctx.save();
-    ctx.scale(state.scale, state.scale);
-    element.singleRender(tfp.x, tfp.y, ttp.x, ttp.y, lineWidth);
-    ctx.restore();
-  }
-  creatingImage(e, { width, height, imageObj, url, ratio }) {
-    let gp = this.app.coordinate.gridAdsorbent(
-      e.unGridClientX - width / 2,
-      e.unGridClientY - height / 2
-    );
-    this.createElement({
-      type: "image",
-      x: gp.x,
-      y: gp.y,
-      url,
-      imageObj,
-      width,
-      height,
-      ratio
-    });
-  }
-  editingText(element) {
-    if (element.type !== "text") {
-      return;
-    }
-    element.noRender = true;
-    this.setActiveElement(element);
-  }
-  completeEditingText() {
-    let element = this.activeElement;
-    if (!element || element.type !== "text") {
-      return;
-    }
-    if (!element.text.trim()) {
-      this.deleteElement(element);
-      this.setActiveElement(null);
-      return;
-    }
-    element.noRender = false;
-  }
-  completeCreateArrow(e) {
-    this.activeElement.addPoint(e.clientX, e.clientY);
-  }
-  creatingArrow(x, y, e) {
-    this.createElement(
-      {
-        type: "arrow",
-        x,
-        y
-      },
-      (element) => {
-        element.addPoint(x, y);
-      }
-    );
-    this.activeElement.updateFictitiousPoint(e.clientX, e.clientY);
-  }
-  creatingLine(x, y, e, isSingle = false, notCreate = false) {
-    if (!notCreate) {
-      this.createElement(
-        {
-          type: "line",
-          x,
-          y,
-          isSingle
-        },
-        (element2) => {
-          element2.addPoint(x, y);
-        }
-      );
-    }
-    let element = this.activeElement;
-    if (element) {
-      element.updateFictitiousPoint(e.clientX, e.clientY);
-    }
-  }
-  completeCreateLine(e, completeCallback = () => {
-  }) {
-    let element = this.activeElement;
-    let x = e.clientX;
-    let y = e.clientY;
-    if (element && element.isSingle) {
-      element.addPoint(x, y);
-      completeCallback();
-    } else {
-      this.createElement({
-        type: "line",
-        isSingle: false
-      });
-      element = this.activeElement;
-      element.addPoint(x, y);
-      element.updateFictitiousPoint(x, y);
-    }
-  }
-  completeCreateElement() {
-    this.isCreatingElement = false;
-    let element = this.activeElement;
-    if (!element) {
-      return this;
-    }
-    if (["freedraw", "arrow", "line"].includes(element.type)) {
-      element.updateMultiPointBoundingRect();
-    }
-    element.isCreating = false;
-    this.app.emitChange();
-    return this;
-  }
-  setActiveElementStyle(style = {}) {
-    if (!this.hasActiveElement()) {
-      return this;
-    }
-    Object.keys(style).forEach((key) => {
-      this.activeElement.style[key] = style[key];
-      if (key === "fontSize" && this.activeElement.type === "text") {
-        this.activeElement.updateTextSize();
-      }
-    });
-    return this;
-  }
-  checkInResizeHand(x, y) {
-    let element = this.activeElement;
-    let hand = element.dragElement.checkPointInDragElementWhere(x, y);
-    if (hand) {
-      return {
-        element,
-        hand
-      };
-    }
-    return null;
-  }
-  checkIsResize(x, y, e) {
-    if (!this.hasActiveElement()) {
-      return false;
-    }
-    let res = this.checkInResizeHand(x, y);
-    if (res) {
-      this.isResizing = true;
-      this.resizingElement = res.element;
-      this.resizingElement.startResize(res.hand, e);
-      this.app.cursor.setResize(res.hand);
-      return true;
-    }
-    return false;
-  }
-  handleResize(...args) {
-    if (!this.isResizing) {
-      return;
-    }
-    this.resizingElement.resize(...args);
-    this.app.render.render();
-  }
-  endResize() {
-    this.isResizing = false;
-    this.resizingElement.endResize();
-    this.resizingElement = null;
-  }
-}
-class ImageEdit extends EventEmitter {
-  constructor(app) {
-    super();
-    this.app = app;
-    this.el = null;
-    this.isReady = false;
-    this.previewEl = null;
-    this.imageData = null;
-    this.maxWidth = 750;
-    this.maxHeight = 450;
-    this.maxRatio = this.maxWidth / this.maxHeight;
-    this.onImageSelectChange = this.onImageSelectChange.bind(this);
-  }
-  reset() {
-    this.el.value = "";
-    this.isReady = false;
-    document.body.removeChild(this.previewEl);
-    this.previewEl = null;
-    this.imageData = null;
-  }
-  selectImage() {
-    if (!this.el) {
-      this.el = document.createElement("input");
-      this.el.type = "file";
-      this.el.accept = "image/*";
-      this.el.style.position = "fixed";
-      this.el.style.left = "-999999px";
-      this.el.addEventListener("change", this.onImageSelectChange);
-      document.body.appendChild(this.el);
-    }
-    this.el.click();
-  }
-  updatePreviewElPos(x, y) {
-    let width = 100;
-    let height = width / this.imageData.ratio;
-    if (!this.previewEl) {
-      this.previewEl = document.createElement("div");
-      this.previewEl.style.position = "fixed";
-      this.previewEl.style.width = width + "px";
-      this.previewEl.style.height = height + "px";
-      this.previewEl.style.backgroundImage = `url('${this.imageData.url}')`;
-      this.previewEl.style.backgroundSize = "cover";
-      this.previewEl.style.pointerEvents = "none";
-      document.body.appendChild(this.previewEl);
-    }
-    let tp = this.app.coordinate.containerToWindow(x, y);
-    this.previewEl.style.left = tp.x - width / 2 + "px";
-    this.previewEl.style.top = tp.y - height / 2 + "px";
-  }
-  getImageSize(url) {
-    return __async(this, null, function* () {
-      return new Promise((resolve, reject) => {
-        let img = new Image();
-        img.setAttribute("crossOrigin", "anonymous");
-        img.onload = () => {
-          let width = img.width;
-          let height = img.height;
-          let ratio = img.width / img.height;
-          if (img.width > this.maxWidth || img.height > this.maxHeight) {
-            if (ratio > this.maxRatio) {
-              width = this.maxWidth;
-              height = this.maxWidth / ratio;
-            } else {
-              height = this.maxHeight;
-              width = this.maxHeight * ratio;
-            }
-          }
-          resolve({
-            imageObj: img,
-            size: {
-              width,
-              height
-            },
-            ratio
-          });
-        };
-        img.onerror = () => {
-          reject();
-        };
-        img.src = url;
-      });
-    });
-  }
-  onImageSelectChange(e) {
-    return __async(this, null, function* () {
-      let url = yield this.getImageUrl(e.target.files[0]);
-      let { imageObj, size, ratio } = yield this.getImageSize(url);
-      this.isReady = true;
-      this.imageData = __spreadProps(__spreadValues({
-        url
-      }, size), {
-        ratio,
-        imageObj
-      });
-      this.emit("imageSelectChange", this.imageData);
-    });
-  }
-  getImageUrl(file) {
-    return __async(this, null, function* () {
-      return new Promise((resolve, reject) => {
-        let reader = new FileReader();
-        reader.onloadend = () => {
-          resolve(reader.result);
-        };
-        reader.onerror = () => {
-          reject();
-        };
-        reader.readAsDataURL(file);
-      });
-    });
-  }
-}
-class Cursor {
-  constructor(app) {
-    this.app = app;
-    this.currentType = "default";
-  }
-  set(type = "default") {
-    this.currentType = type;
-    let style = type;
-    if (type === "eraser") {
-      style = `url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAARRJREFUOE/dlDFLxEAQhd+BVouFZ3vlQuwSyI+5a7PBRkk6k9KzTOwStJFsWv0xgaQzkNLWszim0kL2OOFc9oKRYHFTz37Lm/dmJhi5JiPzcBjAOYDz7WheADz3jalP8oIxds85P3Zd90RBqqpad133SUSXAJ5M4H3AhWVZd1EUzYQQP96VZYkkSV7btr02QY1Axtgqz/NTz/OM6qSUCMNwRURneoMJOLdt+7Gu643MfeU4zrppmgt9pibgjRBiWRRFb0R934eUcgngdrfxX4CjSwZj7C3Lsqnu8Lc05XQQBO9ENP2NKapnE5s4jme608rhNE2HxWb7qwr2A+f8SAv2BxFdDQ32rpLRVu9Pl+0wztcg6V/VPW4Vw1FsawAAAABJRU5ErkJggg==) 10 10, auto`;
-    }
-    this.app.container.style.cursor = style;
-  }
-  hide() {
-    this.set("none");
-  }
-  reset() {
-    this.set();
-  }
-  setCrosshair() {
-    this.set("crosshair");
-  }
-  setMove() {
-    this.set("move");
-  }
-  setResize(dir) {
-    let type = "";
-    switch (dir) {
-      case DRAG_ELEMENT_PARTS.BODY:
-        type = "move";
-        break;
-      case DRAG_ELEMENT_PARTS.ROTATE:
-        type = "grab";
-        break;
-      case DRAG_ELEMENT_PARTS.TOP_LEFT_BTN:
-        type = "nw-resize";
-        break;
-      case DRAG_ELEMENT_PARTS.TOP_RIGHT_BTN:
-        type = "ne-resize";
-        break;
-      case DRAG_ELEMENT_PARTS.BOTTOM_RIGHT_BTN:
-        type = "se-resize";
-        break;
-      case DRAG_ELEMENT_PARTS.BOTTOM_LEFT_BTN:
-        type = "sw-resize";
-        break;
-    }
-    this.set(type);
-  }
-  setEraser() {
-    this.set("eraser");
-  }
-}
-class TextEdit extends EventEmitter {
-  constructor(app) {
-    super();
-    this.app = app;
-    this.editable = null;
-    this.isEditing = false;
-    this.onTextInput = this.onTextInput.bind(this);
-    this.onTextBlur = this.onTextBlur.bind(this);
-  }
-  crateTextInputEl() {
-    this.editable = document.createElement("textarea");
-    this.editable.dir = "auto";
-    this.editable.tabIndex = 0;
-    this.editable.wrap = "off";
-    this.editable.className = "textInput";
-    Object.assign(this.editable.style, {
-      position: "fixed",
-      display: "block",
-      minHeight: "1em",
-      backfaceVisibility: "hidden",
-      margin: 0,
-      padding: 0,
-      border: 0,
-      outline: 0,
-      resize: "none",
-      background: "transparent",
-      overflow: "hidden",
-      whiteSpace: "pre"
-    });
-    this.editable.addEventListener("input", this.onTextInput);
-    this.editable.addEventListener("blur", this.onTextBlur);
-    document.body.appendChild(this.editable);
-  }
-  updateTextInputStyle() {
-    let activeElement = this.app.elements.activeElement;
-    if (!activeElement) {
-      return;
-    }
-    let { x, y, width, height, style, text, rotate } = activeElement;
-    let { coordinate, state } = this.app;
-    this.editable.value = text;
-    x = coordinate.subScrollX(x);
-    y = coordinate.subScrollY(y);
-    let sp = coordinate.scale(x, y);
-    let tp = coordinate.containerToWindow(sp.x, sp.y);
-    let fontSize = style.fontSize * state.scale;
-    let styles = {
-      font: getFontString(fontSize, style.fontFamily),
-      lineHeight: `${fontSize * style.lineHeightRatio}px`,
-      left: `${tp.x}px`,
-      top: `${tp.y}px`,
-      color: style.fillStyle,
-      width: Math.max(width, 100) * state.scale + "px",
-      height: height * state.scale + "px",
-      transform: `rotate(${rotate}deg)`,
-      opacity: style.globalAlpha
-    };
-    Object.assign(this.editable.style, styles);
-  }
-  onTextInput() {
-    let activeElement = this.app.elements.activeElement;
-    if (!activeElement) {
-      return;
-    }
-    activeElement.text = this.editable.value;
-    let { width, height } = getTextElementSize(activeElement);
-    activeElement.width = width;
-    activeElement.height = height;
-    this.updateTextInputStyle();
-  }
-  onTextBlur() {
-    this.editable.style.display = "none";
-    this.editable.value = "";
-    this.emit("blur");
-    this.isEditing = false;
-  }
-  showTextEdit() {
-    if (!this.editable) {
-      this.crateTextInputEl();
-    } else {
-      this.editable.style.display = "block";
-    }
-    this.updateTextInputStyle();
-    this.editable.focus();
-    this.editable.select();
-    this.isEditing = true;
-  }
-}
-class History {
-  constructor(app) {
-    this.app = app;
-    this.historyStack = [];
-    this.length = 0;
-    this.index = -1;
-  }
-  add(data) {
-    let prev = this.length > 0 ? this.historyStack[this.length - 1] : null;
-    let copyData = deepCopy(data);
-    if (copyData === prev) {
-      return;
-    }
-    this.historyStack.push(copyData);
-    this.length++;
-    this.index = this.length - 1;
-    this.emitChange();
-  }
-  undo() {
-    if (this.index <= 0) {
-      return;
-    }
-    this.index--;
-    this.shuttle();
-  }
-  redo() {
-    if (this.index >= this.length - 1) {
-      return;
-    }
-    this.index++;
-    this.shuttle();
-  }
-  shuttle() {
-    return __async(this, null, function* () {
-      let data = this.historyStack[this.index];
-      yield this.app.setData(data, true);
-      this.emitChange();
-      this.app.emit("change", data);
-    });
-  }
-  clear() {
-    this.index = -1;
-    this.length = 0;
-    this.historyStack = [];
-    this.emitChange();
-  }
-  emitChange() {
-    this.app.emit("shuttle", this.index, this.length);
-  }
-}
-class Export {
-  constructor(app) {
-    this.app = app;
-    this.openTest = false;
-    this.saveState = {
-      scale: 0,
-      scrollX: 0,
-      scrollY: 0,
-      width: 0,
-      height: 0
-    };
-  }
-  show(canvas) {
-    if (this.openTest) {
-      canvas.style.cssText = `
-        position: absolute;
-        left: 0;
-        top: 0;
-        background-color: #fff;
-      `;
-      document.body.appendChild(canvas);
-    }
-  }
-  getElementList(onlySelected = true) {
-    if (!onlySelected) {
-      return this.app.elements.elementList;
-    } else {
-      let selectedElements = [];
-      if (this.app.elements.activeElement) {
-        selectedElements.push(this.app.elements.activeElement);
-      } else if (this.app.selection.hasSelectionElements()) {
-        selectedElements = this.app.selection.getSelectionElements();
-      }
-      let res = this.app.elements.elementList.filter((element) => {
-        return selectedElements.includes(element);
-      });
-      return res;
-    }
-  }
-  exportImage({
-    type = "image/png",
-    renderBg = true,
-    useBlob = false,
-    paddingX = 10,
-    paddingY = 10,
-    onlySelected
-  } = {}) {
-    let { minx, maxx, miny, maxy } = getMultiElementRectInfo(
-      this.getElementList(onlySelected)
-    );
-    let width = maxx - minx + paddingX * 2;
-    let height = maxy - miny + paddingY * 2;
-    let { canvas, ctx } = createCanvas(width, height, {
-      noStyle: true,
-      noTranslate: true
-    });
-    this.show(canvas);
-    this.saveAppState();
-    this.changeAppState(minx - paddingX, miny - paddingY, ctx);
-    if (renderBg && this.app.state.backgroundColor) {
-      this.app.background.canvasAddBackgroundColor(
-        ctx,
-        width,
-        height,
-        this.app.state.backgroundColor
-      );
-    }
-    this.render(ctx, onlySelected);
-    this.recoveryAppState();
-    if (useBlob) {
-      return new Promise((resolve, reject) => {
-        canvas.toBlob((blob) => {
-          if (blob) {
-            resolve(blob);
-          } else {
-            reject();
-          }
-        }, type);
-      });
-    } else {
-      return canvas.toDataURL(type);
-    }
-  }
-  saveAppState() {
-    let { width, height, state, ctx } = this.app;
-    this.saveState.width = width;
-    this.saveState.height = height;
-    this.saveState.scale = state.scale;
-    this.saveState.scrollX = state.scrollX;
-    this.saveState.scrollY = state.scrollY;
-    this.saveState.ctx = ctx;
-  }
-  changeAppState(minx, miny, ctx) {
-    this.app.ctx = ctx;
-    this.app.state.scale = 1;
-    this.app.state.scrollX = 0;
-    this.app.state.scrollY = 0;
-    this.app.width = minx * 2;
-    this.app.height = miny * 2;
-  }
-  recoveryAppState() {
-    let { width, height, scale, scrollX, scrollY, ctx } = this.saveState;
-    this.app.state.scale = scale;
-    this.app.state.scrollX = scrollX;
-    this.app.state.scrollY = scrollY;
-    this.app.width = width;
-    this.app.height = height;
-    this.app.ctx = ctx;
-  }
-  render(ctx, onlySelected) {
-    ctx.save();
-    this.getElementList(onlySelected).forEach((element) => {
-      if (element.noRender) {
-        return;
-      }
-      let cacheActive = element.isActive;
-      let cacheSelected = element.isSelected;
-      element.isActive = false;
-      element.isSelected = false;
-      element.render();
-      element.isActive = cacheActive;
-      element.isSelected = cacheSelected;
-    });
-    ctx.restore();
-  }
-  exportJson() {
-    return this.app.getData();
-  }
-}
-class Background {
-  constructor(app) {
-    this.app = app;
-  }
-  set() {
-    if (this.app.state.backgroundColor) {
-      this.addBackgroundColor();
-    } else {
-      this.remove();
-    }
-  }
-  addBackgroundColor() {
-    this.app.container.style.backgroundColor = this.app.state.backgroundColor;
-  }
-  remove() {
-    this.app.container.style.backgroundColor = "";
-  }
-  canvasAddBackgroundColor(ctx, width, height, backgroundColor) {
-    ctx.save();
-    ctx.rect(0, 0, width, height);
-    ctx.fillStyle = backgroundColor;
-    ctx.fill();
-    ctx.restore();
-  }
-}
-class Canvas {
-  constructor(width, height, opt) {
-    this.width = width;
-    this.height = height;
-    let { canvas, ctx } = createCanvas(width, height, opt);
-    this.el = canvas;
-    this.ctx = ctx;
-  }
-  clearCanvas() {
-    let { width, height } = this;
-    this.ctx.clearRect(-width / 2, -height / 2, width, height);
-  }
-}
-class MultiSelectElement extends BaseElement {
-  constructor(opts = {}, app) {
-    super(opts, app);
-    this.dragElement = new DragElement(this, this.app);
-    this.selectedElementList = [];
-    this.wholeCenterPos = { x: 0, y: 0 };
-  }
-  setSelectedElementList(list) {
-    this.selectedElementList.forEach((element) => {
-      element.isSelected = false;
-    });
-    this.selectedElementList = list;
-    this.selectedElementList.forEach((element) => {
-      element.isSelected = true;
-    });
-  }
-  updateElements(elements) {
-    let exists = [];
-    this.selectedElementList.forEach((element) => {
-      if (elements.includes(element)) {
-        exists.push(element);
-      }
-    });
-    this.setSelectedElementList(exists);
-  }
-  updateRect() {
-    if (this.selectedElementList.length <= 0) {
-      super.updateRect(0, 0, 0, 0);
-      return;
-    }
-    let { minx, maxx, miny, maxy } = getMultiElementRectInfo(
-      this.selectedElementList
-    );
-    super.updateRect(minx, miny, maxx - minx, maxy - miny);
-  }
-  startResize(...args) {
-    this.selectedElementList.forEach((element) => {
-      if (args[0] === "rotate") {
-        this.wholeCenterPos = getElementCenterPoint(this);
-      }
-      element.startResize(...args);
-    });
-  }
-  resize(...args) {
-    this.selectedElementList.forEach((element) => {
-      if (element.dragElement.resizeType === "rotate") {
-        this.handleRotate(element, ...args);
-      } else {
-        element.resize(...args);
-      }
-    });
-  }
-  handleRotate(element, e, mx, my, offsetX, offsetY) {
-    let rotate = getTowPointRotate(
-      this.wholeCenterPos.x,
-      this.wholeCenterPos.y,
-      e.clientX,
-      e.clientY,
-      mx,
-      my
-    );
-    element.rotateByCenter(rotate, this.wholeCenterPos.x, this.wholeCenterPos.y);
-  }
-  endResize() {
-    this.selectedElementList.forEach((element) => {
-      element.endResize();
-    });
-  }
-  render() {
-    if (this.selectedElementList.length > 0) {
-      if (this.width <= 0 || this.height <= 0) {
-        return;
-      }
-      this.dragElement.render();
-    }
-  }
-}
-class Selection {
-  constructor(app) {
-    this.app = app;
-    this.canvas = null;
-    this.ctx = null;
-    this.creatingSelection = false;
-    this.hasSelection = false;
-    this.isResizing = false;
-    this.state = this.app.state;
-    this.width = this.app.width;
-    this.height = this.app.height;
-    this.coordinate = new Coordinate(this);
-    this.rectangle = new Rectangle(
-      {
-        type: "rectangle",
-        style: {
-          strokeStyle: "rgba(9,132,227,0.3)",
-          fillStyle: "rgba(9,132,227,0.3)"
-        }
-      },
-      this
-    );
-    this.multiSelectElement = new MultiSelectElement(
-      {
-        type: "multiSelectElement"
-      },
-      this
-    );
-    this.checkInNodes = throttle(this.checkInNodes, this, 500);
-    this.handleResize = throttle(this.handleResize, this, 16);
-    this.init();
-    this.bindEvent();
-  }
-  init() {
-    if (this.canvas) {
-      this.app.container.removeChild(this.canvas.el);
-    }
-    this.width = this.app.width;
-    this.height = this.app.height;
-    this.canvas = new Canvas(this.width, this.height, {
-      className: "selection"
-    });
-    this.ctx = this.canvas.ctx;
-    this.app.container.appendChild(this.canvas.el);
-  }
-  bindEvent() {
-    this.app.on("change", () => {
-      this.state = this.app.state;
-      this.multiSelectElement.updateElements(this.app.elements.elementList);
-      this.renderSelection();
-    });
-    this.app.on("scrollChange", () => {
-      this.renderSelection();
-    });
-    this.app.on("zoomChange", () => {
-      this.renderSelection();
-    });
-  }
-  onMousedown(e, event) {
-    if (e.originEvent.which !== 1) {
-      return;
-    }
-    this.creatingSelection = true;
-    this.rectangle.updatePos(event.mousedownPos.x, event.mousedownPos.y);
-  }
-  onMousemove(e, event) {
-    if (Math.abs(event.mouseOffset.x) <= 10 && Math.abs(event.mouseOffset.y) <= 10) {
-      return;
-    }
-    this.onMove(e, event);
-  }
-  onMouseup() {
-    this.creatingSelection = false;
-    this.rectangle.updateRect(0, 0, 0, 0);
-    this.hasSelection = this.hasSelectionElements();
-    this.multiSelectElement.updateRect();
-    this.renderSelection();
-    this.emitChange();
-  }
-  reset() {
-    this.setMultiSelectElements([]);
-    this.hasSelection = false;
-    this.renderSelection();
-    this.emitChange();
-  }
-  renderSelection() {
-    this.canvas.clearCanvas();
-    this.ctx.save();
-    this.ctx.scale(this.app.state.scale, this.app.state.scale);
-    this.rectangle.render();
-    this.multiSelectElement.render();
-    this.ctx.restore();
-  }
-  onMove(e, event) {
-    this.rectangle.updateSize(event.mouseOffset.x, event.mouseOffset.y);
-    this.renderSelection();
-    this.checkInElements(e, event);
-  }
-  checkInElements(e, event) {
-    let minx = Math.min(event.mousedownPos.x, e.clientX);
-    let miny = Math.min(event.mousedownPos.y, e.clientY);
-    let maxx = Math.max(event.mousedownPos.x, e.clientX);
-    let maxy = Math.max(event.mousedownPos.y, e.clientY);
-    let selectedElementList = [];
-    this.app.elements.elementList.forEach((element) => {
-      let _minx = Infinity;
-      let _maxx = -Infinity;
-      let _miny = Infinity;
-      let _maxy = -Infinity;
-      let endPointList = element.getEndpointList();
-      let rect = getBoundingRect(
-        endPointList.map((point) => {
-          return [point.x, point.y];
-        }),
-        true
-      );
-      rect.forEach(({ x, y }) => {
-        if (x < _minx) {
-          _minx = x;
-        }
-        if (x > _maxx) {
-          _maxx = x;
-        }
-        if (y < _miny) {
-          _miny = y;
-        }
-        if (y > _maxy) {
-          _maxy = y;
-        }
-      });
-      if (_minx >= minx && _maxx <= maxx && _miny >= miny && _maxy <= maxy) {
-        selectedElementList.push(element);
-      }
-    });
-    let finalList = [...selectedElementList];
-    selectedElementList.forEach((item) => {
-      if (item.hasGroup()) {
-        finalList.push(...this.app.group.getGroupElements(item));
-      }
-    });
-    finalList = new Set(finalList);
-    finalList = Array.from(finalList);
-    this.setMultiSelectElements(finalList, true);
-    this.app.render.render();
-  }
-  checkInResizeHand(x, y) {
-    return this.multiSelectElement.dragElement.checkPointInDragElementWhere(
-      x,
-      y
-    );
-  }
-  checkIsResize(x, y, e) {
-    if (!this.hasSelection) {
-      return false;
-    }
-    let hand = this.multiSelectElement.dragElement.checkPointInDragElementWhere(
-      x,
-      y
-    );
-    if (hand) {
-      this.isResizing = true;
-      this.multiSelectElement.startResize(hand, e);
-      this.app.cursor.setResize(hand);
-      return true;
-    }
-    return false;
-  }
-  handleResize(...args) {
-    if (!this.isResizing) {
-      return;
-    }
-    this.multiSelectElement.resize(...args);
-    this.app.render.render();
-    this.multiSelectElement.updateRect();
-    this.renderSelection();
-  }
-  endResize() {
-    this.isResizing = false;
-    this.multiSelectElement.endResize();
-  }
-  setSelectedElementStyle(style = {}) {
-    if (!this.hasSelectionElements()) {
-      return;
-    }
-    Object.keys(style).forEach((key) => {
-      this.getSelectionElements().forEach((element) => {
-        element.style[key] = style[key];
-        if (key === "fontSize" && element.type === "text") {
-          element.updateTextSize();
-          this.multiSelectElement.updateRect();
-        }
-      });
-    });
-    this.app.render.render();
-    this.app.emitChange();
-  }
-  deleteSelectedElements() {
-    this.getSelectionElements().forEach((element) => {
-      this.app.elements.deleteElement(element);
-    });
-    this.selectElements([]);
-    this.app.emitChange();
-  }
-  hasSelectionElements() {
-    return this.getSelectionElements().length > 0;
-  }
-  getSelectionElements() {
-    return this.multiSelectElement.selectedElementList;
-  }
-  copySelectionElements(pos) {
-    return __async(this, null, function* () {
-      let task = this.getSelectionElements().map((element) => {
-        return this.app.elements.copyElement(element, true);
-      });
-      this.app.group.clearCopyMap();
-      let elements = yield Promise.all(task);
-      this.setMultiSelectElements(elements);
-      if (pos) {
-        this.multiSelectElement.startResize(DRAG_ELEMENT_PARTS.BODY);
-        let ox = pos.x - this.multiSelectElement.x - this.multiSelectElement.width / 2;
-        let oy = pos.y - this.multiSelectElement.y - this.multiSelectElement.height / 2;
-        let gridAdsorbentPos = this.app.coordinate.gridAdsorbent(ox, oy);
-        this.multiSelectElement.resize(
-          null,
-          null,
-          null,
-          gridAdsorbentPos.x,
-          gridAdsorbentPos.y
-        );
-        this.multiSelectElement.endResize();
-        this.multiSelectElement.updateRect();
-      }
-      this.app.render.render();
-      this.renderSelection();
-      this.app.emitChange();
-    });
-  }
-  selectElements(elements = []) {
-    this.hasSelection = elements.length > 0;
-    this.setMultiSelectElements(elements);
-    this.app.render.render();
-    this.renderSelection();
-    this.emitChange();
-  }
-  setMultiSelectElements(elements = [], notUpdateRect) {
-    this.multiSelectElement.setSelectedElementList(elements);
-    if (!notUpdateRect) {
-      this.multiSelectElement.updateRect();
-    }
-  }
-  emitChange() {
-    this.app.emit("multiSelectChange", this.getSelectionElements());
-  }
-}
-class Grid {
-  constructor(app) {
-    this.app = app;
-    this.canvas = null;
-    this.ctx = null;
-    this.init();
-    this.app.on("zoomChange", this.renderGrid, this);
-    this.app.on("scrollChange", this.renderGrid, this);
-  }
-  init() {
-    if (this.canvas) {
-      this.app.container.removeChild(this.canvas.el);
-    }
-    let { width, height } = this.app;
-    this.canvas = new Canvas(width, height, {
-      className: "grid"
-    });
-    this.ctx = this.canvas.ctx;
-    this.app.container.insertBefore(
-      this.canvas.el,
-      this.app.container.children[0]
-    );
-  }
-  drawHorizontalLine(i) {
-    let { coordinate, width, state } = this.app;
-    let _i = coordinate.subScrollY(i);
-    this.ctx.beginPath();
-    this.ctx.moveTo(-width / state.scale / 2, _i);
-    this.ctx.lineTo(width / state.scale / 2, _i);
-    this.ctx.stroke();
-  }
-  renderHorizontalLines() {
-    let { coordinate, height, state } = this.app;
-    let { gridConfig, scale } = state;
-    let maxBottom = 0;
-    for (let i = -height / 2; i < height / 2; i += gridConfig.size) {
-      this.drawHorizontalLine(i);
-      maxBottom = i;
-    }
-    for (let i = -height / 2 - gridConfig.size; i > -coordinate.subScrollY(height / scale / 2); i -= gridConfig.size) {
-      this.drawHorizontalLine(i);
-    }
-    for (let i = maxBottom + gridConfig.size; i < coordinate.addScrollY(height / scale / 2); i += gridConfig.size) {
-      this.drawHorizontalLine(i);
-    }
-  }
-  drawVerticalLine(i) {
-    let { coordinate, height, state } = this.app;
-    let _i = coordinate.subScrollX(i);
-    this.ctx.beginPath();
-    this.ctx.moveTo(_i, -height / state.scale / 2);
-    this.ctx.lineTo(_i, height / state.scale / 2);
-    this.ctx.stroke();
-  }
-  renderVerticalLines() {
-    let { coordinate, width, state } = this.app;
-    let { gridConfig, scale } = state;
-    let maxRight = 0;
-    for (let i = -width / 2; i < width / 2; i += gridConfig.size) {
-      this.drawVerticalLine(i);
-      maxRight = i;
-    }
-    for (let i = -width / 2 - gridConfig.size; i > -coordinate.subScrollX(width / scale / 2); i -= gridConfig.size) {
-      this.drawVerticalLine(i);
-    }
-    for (let i = maxRight + gridConfig.size; i < coordinate.addScrollX(width / scale / 2); i += gridConfig.size) {
-      this.drawVerticalLine(i);
-    }
-  }
-  renderGrid() {
-    this.canvas.clearCanvas();
-    let { gridConfig, scale, showGrid } = this.app.state;
-    if (!showGrid) {
-      return;
-    }
-    this.ctx.save();
-    this.ctx.scale(scale, scale);
-    this.ctx.strokeStyle = gridConfig.strokeStyle;
-    this.ctx.lineWidth = gridConfig.lineWidth;
-    this.renderHorizontalLines();
-    this.renderVerticalLines();
-    this.ctx.restore();
-  }
-  showGrid() {
-    this.app.updateState({
-      showGrid: true
-    });
-    this.renderGrid();
-  }
-  hideGrid() {
-    this.app.updateState({
-      showGrid: false
-    });
-    this.canvas.clearCanvas();
-  }
-  updateGrid(config = {}) {
-    this.app.updateState({
-      gridConfig: __spreadValues(__spreadValues({}, this.app.state.gridConfig), config)
-    });
-    if (this.app.state.showGrid) {
-      this.hideGrid();
-      this.showGrid();
-    }
-  }
-}
-const map = {
-  Tab: 9,
-  Enter: 13,
-  Shift: 16,
-  Control: 17,
-  Alt: 18,
-  CapsLock: 20,
-  Esc: 27,
-  Space: 32,
-  PageUp: 33,
-  PageDown: 34,
-  End: 35,
-  Home: 36,
-  Insert: 45,
-  Left: 37,
-  Up: 38,
-  Right: 39,
-  Down: 40,
-  Del: 46,
-  NumLock: 144,
-  Cmd: 91,
-  CmdFF: 224,
-  F1: 112,
-  F2: 113,
-  F3: 114,
-  F4: 115,
-  F5: 116,
-  F6: 117,
-  F7: 118,
-  F8: 119,
-  F9: 120,
-  F10: 121,
-  F11: 122,
-  F12: 123,
-  "`": 192,
-  "=": 187,
-  "+": 187,
-  "-": 189,
-  "'": 222,
-  "/": 191,
-  ".": 190
-};
-for (let i = 0; i <= 9; i++) {
-  map[i] = i + 48;
-}
-"abcdefghijklmnopqrstuvwxyz".split("").forEach((n, index) => {
-  map[n] = index + 65;
-});
-const keyMap = map;
-class Mode {
-  constructor(app) {
-    this.app = app;
-    this.startScrollX = 0;
-    this.startScrollY = 0;
-    this.isDragMode = false;
-    this.onMove = throttle(this.onMove, this, 16);
-    this.bindEvent();
-  }
-  bindEvent() {
-    this.app.event.on("keydown", (e) => {
-      if (e.keyCode === keyMap.Space) {
-        this.isDragMode = true;
-        this.app.cursor.set("grab");
-      }
-    });
-    this.app.event.on("keyup", (e) => {
-      if (this.isDragMode) {
-        this.isDragMode = false;
-        this.app.cursor.set("default");
-      }
-    });
-  }
-  setEditMode() {
-    this.app.cursor.set("default");
-    this.app.updateState({
-      readonly: false
-    });
-  }
-  setReadonlyMode() {
-    this.app.cursor.set("grab");
-    this.app.updateState({
-      readonly: true
-    });
-  }
-  onStart() {
-    this.startScrollX = this.app.state.scrollX;
-    this.startScrollY = this.app.state.scrollY;
-  }
-  onMove(e, event) {
-    this.app.scrollTo(
-      this.startScrollX - event.mouseOffset.originX / this.app.state.scale,
-      this.startScrollY - event.mouseOffset.originY / this.app.state.scale
-    );
-  }
-  onEnd() {
-    this.startScrollX = 0;
-    this.startScrollY = 0;
-  }
-}
-class KeyCommand {
-  constructor(app) {
-    this.app = app;
-    this.keyMap = keyMap;
-    this.shortcutMap = {};
-    this.bindEvent();
-  }
-  bindEvent() {
-    this.app.event.on("keydown", this.onKeydown, this);
-  }
-  unBindEvent() {
-    this.app.event.off("keydown", this.onKeydown);
-  }
-  onKeydown(e) {
-    Object.keys(this.shortcutMap).forEach((key) => {
-      if (this.checkKey(e, key)) {
-        e.stopPropagation();
-        e.preventDefault();
-        this.shortcutMap[key].forEach((f) => {
-          f.fn.call(f.ctx);
-        });
-      }
-    });
-  }
-  checkKey(e, key) {
-    let o = this.getOriginEventCodeArr(e);
-    let k = this.getKeyCodeArr(key);
-    if (o.length !== k.length) {
-      return false;
-    }
-    for (let i = 0; i < o.length; i++) {
-      let index = k.findIndex((item) => {
-        return item === o[i];
-      });
-      if (index === -1) {
-        return false;
-      } else {
-        k.splice(index, 1);
-      }
-    }
-    return true;
-  }
-  getOriginEventCodeArr(e) {
-    let arr = [];
-    if (e.ctrlKey || e.metaKey) {
-      arr.push(keyMap["Control"]);
-    }
-    if (e.altKey) {
-      arr.push(keyMap["Alt"]);
-    }
-    if (e.shiftKey) {
-      arr.push(keyMap["Shift"]);
-    }
-    if (!arr.includes(e.keyCode)) {
-      arr.push(e.keyCode);
-    }
-    return arr;
-  }
-  getKeyCodeArr(key) {
-    key = key.replace(/\+\+/, "+add");
-    let keyArr = key.split(/\s*\+\s*/).map((item) => {
-      return item === "add" ? "+" : item;
-    });
-    let arr = [];
-    keyArr.forEach((item) => {
-      arr.push(keyMap[item]);
-    });
-    return arr;
-  }
-  addShortcut(key, fn, ctx) {
-    key.split(/\s*\|\s*/).forEach((item) => {
-      if (this.shortcutMap[item]) {
-        this.shortcutMap[item].push({
-          fn,
-          ctx
-        });
-      } else {
-        this.shortcutMap[item] = [
-          {
-            fn,
-            ctx
-          }
-        ];
-      }
-    });
-  }
-  removeShortcut(key, fn) {
-    key.split(/\s*\|\s*/).forEach((item) => {
-      if (this.shortcutMap[item]) {
-        if (fn) {
-          let index = this.shortcutMap[item].findIndex((f) => {
-            return f.fn === fn;
-          });
-          if (index !== -1) {
-            this.shortcutMap[item].splice(index, 1);
-          }
-        } else {
-          this.shortcutMap[item] = [];
-          delete this.shortcutMap[item];
-        }
-      }
-    });
-  }
-}
-class Render {
-  constructor(app) {
-    this.app = app;
-    this.beingCopyActiveElement = null;
-    this.beingCopySelectedElements = [];
-    this.registerShortcutKeys();
-  }
-  clearCanvas() {
-    let { width, height } = this.app;
-    this.app.ctx.clearRect(-width / 2, -height / 2, width, height);
-    return this;
-  }
-  render() {
-    let { state } = this.app;
-    this.clearCanvas();
-    this.app.ctx.save();
-    this.app.ctx.scale(state.scale, state.scale);
-    this.app.elements.elementList.forEach((element) => {
-      if (element.noRender) {
-        return;
-      }
-      element.render();
-    });
-    this.app.group.render();
-    this.app.ctx.restore();
-    return this;
-  }
-  registerShortcutKeys() {
-    this.app.keyCommand.addShortcut("Del|Backspace", () => {
-      this.deleteCurrentElements();
-    });
-    this.app.keyCommand.addShortcut("Control+c", () => {
-      this.copyCurrentElement();
-    });
-    this.app.keyCommand.addShortcut("Control+x", () => {
-      this.cutCurrentElement();
-    });
-    this.app.keyCommand.addShortcut("Control+z", () => {
-      this.app.history.undo();
-    });
-    this.app.keyCommand.addShortcut("Control+y", () => {
-      this.app.history.redo();
-    });
-    this.app.keyCommand.addShortcut("Control+v", () => {
-      this.pasteCurrentElement(true);
-    });
-    this.app.keyCommand.addShortcut("Control++", () => {
-      this.zoomIn();
-    });
-    this.app.keyCommand.addShortcut("Control+-", () => {
-      this.zoomOut();
-    });
-    this.app.keyCommand.addShortcut("Shift+1", () => {
-      this.fit();
-    });
-    this.app.keyCommand.addShortcut("Control+a", () => {
-      this.selectAll();
-    });
-    this.app.keyCommand.addShortcut("Control+0", () => {
-      this.setZoom(1);
-    });
-    this.app.keyCommand.addShortcut("Control+'", () => {
-      if (this.app.state.showGrid) {
-        this.app.grid.hideGrid();
-      } else {
-        this.app.grid.showGrid();
-      }
-    });
-  }
-  copyCurrentElement() {
-    if (this.app.elements.activeElement) {
-      this.beingCopySelectedElements = [];
-      this.beingCopyElement = this.app.elements.activeElement;
-    } else if (this.app.selection.hasSelectionElements()) {
-      this.beingCopyElement = null;
-      this.beingCopySelectedElements = this.app.selection.getSelectionElements();
-    }
-  }
-  cutCurrentElement() {
-    if (this.app.elements.activeElement) {
-      this.copyCurrentElement();
-      this.deleteCurrentElements();
-    } else if (this.app.selection.hasSelectionElements()) {
-      this.copyCurrentElement();
-      this.deleteCurrentElements();
-      this.app.selection.setMultiSelectElements(this.beingCopySelectedElements);
-      this.app.selection.emitChange();
-    }
-  }
-  pasteCurrentElement(useCurrentEventPos = false) {
-    let pos = null;
-    if (useCurrentEventPos) {
-      let x = this.app.event.lastMousePos.x;
-      let y = this.app.event.lastMousePos.y;
-      pos = {
-        x,
-        y
-      };
-    }
-    if (this.beingCopyElement) {
-      this.copyElement(this.beingCopyElement, false, pos);
-    } else if (this.beingCopySelectedElements.length > 0) {
-      this.app.selection.selectElements(this.beingCopySelectedElements);
-      this.app.selection.copySelectionElements(useCurrentEventPos ? pos : null);
-    }
-  }
-  deleteElement(element) {
-    this.app.elements.deleteElement(element);
-    this.render();
-    this.app.emitChange();
-  }
-  copyElement(element, notActive = false, pos) {
-    return __async(this, null, function* () {
-      this.app.elements.cancelActiveElement();
-      yield this.app.elements.copyElement(element, notActive, pos);
-      this.app.group.clearCopyMap();
-      this.render();
-      this.app.emitChange();
-    });
-  }
-  deleteActiveElement() {
-    if (!this.app.elements.hasActiveElement()) {
-      return;
-    }
-    this.deleteElement(this.app.elements.activeElement);
-  }
-  deleteCurrentElements() {
-    this.deleteActiveElement();
-    this.app.selection.deleteSelectedElements();
-  }
-  moveUpCurrentElement() {
-    this.moveLevelCurrentElement("up");
-  }
-  moveDownCurrentElement() {
-    this.moveLevelCurrentElement("down");
-  }
-  moveTopCurrentElement() {
-    this.moveLevelCurrentElement("top");
-  }
-  moveBottomCurrentElement() {
-    this.moveLevelCurrentElement("bottom");
-  }
-  moveLevelCurrentElement(level) {
-    let element = null;
-    if (this.app.elements.hasActiveElement()) {
-      element = this.app.elements.activeElement;
-    } else if (this.app.selection.getSelectionElements().length === 1) {
-      element = this.app.selection.getSelectionElements()[0];
-    }
-    if (!element) {
-      return;
-    }
-    let index = this.app.elements.getElementIndex(element);
-    this.app.elements.elementList.splice(index, 1);
-    if (level === "up") {
-      this.app.elements.insertElement(element, index + 1);
-    } else if (level === "down") {
-      this.app.elements.insertElement(element, index - 1);
-    } else if (level === "top") {
-      this.app.elements.addElement(element);
-    } else if (level === "bottom") {
-      this.app.elements.unshiftElement(element);
-    }
-  }
-  setActiveElementStyle(style = {}) {
-    if (!this.app.elements.hasActiveElement()) {
-      return this;
-    }
-    this.app.elements.setActiveElementStyle(style);
-    this.render();
-    if (!this.app.elements.isCreatingElement) {
-      this.app.emitChange();
-    }
-    return this;
-  }
-  setCurrentElementsStyle(style = {}) {
-    this.setActiveElementStyle(style);
-    this.app.selection.setSelectedElementStyle(style);
-  }
-  cancelActiveElement() {
-    if (!this.app.elements.hasActiveElement()) {
-      return this;
-    }
-    this.app.elements.cancelActiveElement();
-    this.render();
-    return this;
-  }
-  updateActiveElementPosition(x, y) {
-    if (!this.app.elements.hasActiveElement()) {
-      return this;
-    }
-    this.app.elements.activeElement.updatePos(x, y);
-    this.render();
-    return this;
-  }
-  updateActiveElementSize(width, height) {
-    if (!this.app.elements.hasActiveElement()) {
-      return this;
-    }
-    this.app.elements.activeElement.updateSize(width, height);
-    this.render();
-    return this;
-  }
-  updateActiveElementRotate(rotate) {
-    if (!this.app.elements.hasActiveElement()) {
-      return this;
-    }
-    this.app.elements.activeElement.updateRotate(rotate);
-    this.render();
-    return this;
-  }
-  empty() {
-    this.app.elements.deleteAllElements();
-    this.render();
-    this.app.history.clear();
-    this.app.emitChange();
-  }
-  zoomIn(num = 0.1) {
-    this.app.updateState({
-      scale: this.app.state.scale + num
-    });
-    this.render();
-    this.app.emit("zoomChange", this.app.state.scale);
-  }
-  zoomOut(num = 0.1) {
-    this.app.updateState({
-      scale: this.app.state.scale - num > 0 ? this.app.state.scale - num : 0
-    });
-    this.render();
-    this.app.emit("zoomChange", this.app.state.scale);
-  }
-  setZoom(zoom) {
-    if (zoom < 0) {
-      return;
-    }
-    this.app.updateState({
-      scale: zoom
-    });
-    this.render();
-    this.app.emit("zoomChange", this.app.state.scale);
-  }
-  fit() {
-    if (!this.app.elements.hasElements()) {
-      return;
-    }
-    this.scrollToCenter();
-    let { minx, maxx, miny, maxy } = getMultiElementRectInfo(
-      this.app.elements.elementList
-    );
-    let width = maxx - minx;
-    let height = maxy - miny;
-    let maxScale = Math.min(this.app.width / width, this.app.height / height);
-    console.log(maxScale);
-    this.setZoom(maxScale);
-  }
-  scrollTo(scrollX, scrollY) {
-    this.app.updateState({
-      scrollX,
-      scrollY
-    });
-    this.render();
-    this.app.emit(
-      "scrollChange",
-      this.app.state.scrollX,
-      this.app.state.scrollY
-    );
-  }
-  scrollToCenter() {
-    if (!this.app.elements.hasElements()) {
-      this.scrollTo(0, 0);
-      return;
-    }
-    let { minx, maxx, miny, maxy } = getMultiElementRectInfo(
-      this.app.elements.elementList
-    );
-    let width = maxx - minx;
-    let height = maxy - miny;
-    this.scrollTo(
-      minx - (this.app.width - width) / 2,
-      miny - (this.app.height - height) / 2
-    );
-  }
-  copyPasteCurrentElements() {
-    this.copyCurrentElement();
-    this.pasteCurrentElement();
-  }
-  setBackgroundColor(color) {
-    this.app.updateState({
-      backgroundColor: color
-    });
-    this.app.background.set();
-  }
-  selectAll() {
-    this.app.selection.selectElements(this.app.elements.elementList);
-  }
-}
-class Elements {
-  constructor(app) {
-    this.app = app;
-    this.elementList = [];
-    this.activeElement = null;
-    this.isCreatingElement = false;
-    this.isResizing = false;
-    this.resizingElement = null;
-    this.handleResize = throttle(this.handleResize, this, 16);
-  }
-  serialize(stringify = false) {
-    let data = this.elementList.map((element) => {
-      return element.serialize();
-    });
-    return stringify ? JSON.stringify(data) : data;
-  }
-  getElementsNum() {
-    return this.elementList.length;
-  }
-  hasElements() {
-    return this.elementList.length > 0;
-  }
-  addElement(element) {
-    this.elementList.push(element);
-    return this;
-  }
-  unshiftElement(element) {
-    this.elementList.unshift(element);
-    return this;
-  }
-  insertElement(element, index) {
-    this.elementList.splice(index, 0, element);
-  }
-  deleteElement(element) {
-    let index = this.getElementIndex(element);
-    if (index !== -1) {
-      this.elementList.splice(index, 1);
-      if (element.isActive) {
-        this.cancelActiveElement(element);
-      }
-    }
-    return this;
-  }
-  deleteAllElements() {
-    this.activeElement = null;
-    this.elementList = [];
-    this.isCreatingElement = false;
-    this.isResizing = false;
-    this.resizingElement = null;
-    return this;
-  }
-  getElementIndex(element) {
-    return this.elementList.findIndex((item) => {
-      return item === element;
-    });
-  }
-  createElementsFromData(data) {
-    data.forEach((item) => {
-      let element = this.pureCreateElement(item);
-      element.isActive = false;
-      element.isCreating = false;
-      this.addElement(element);
-    });
-    this.app.group.initIdToElementList(this.elementList);
-    return this;
-  }
-  hasActiveElement() {
-    return !!this.activeElement;
-  }
-  setActiveElement(element) {
-    this.cancelActiveElement();
-    this.activeElement = element;
-    if (element) {
-      element.isActive = true;
-    }
-    this.app.emit("activeElementChange", this.activeElement);
-    return this;
-  }
-  cancelActiveElement() {
-    if (!this.hasActiveElement()) {
-      return this;
-    }
-    this.activeElement.isActive = false;
-    this.activeElement = null;
-    this.app.emit("activeElementChange", this.activeElement);
-    return this;
-  }
-  checkIsHitElement(e) {
-    let x = e.unGridClientX;
-    let y = e.unGridClientY;
-    for (let i = this.elementList.length - 1; i >= 0; i--) {
-      let element = this.elementList[i];
-      if (element.isHit(x, y)) {
-        return element;
-      }
-    }
-    return null;
-  }
-  pureCreateElement(opts = {}) {
-    switch (opts.type) {
-      case "rectangle":
-        return new Rectangle(opts, this.app);
-      case "diamond":
-        return new Diamond(opts, this.app);
-      case "triangle":
-        return new Triangle(opts, this.app);
-      case "circle":
-        return new Circle(opts, this.app);
-      case "freedraw":
-        return new Freedraw(opts, this.app);
-      case "image":
-        return new Image$1(opts, this.app);
-      case "arrow":
-        return new Arrow(opts, this.app);
-      case "line":
-        return new Line(opts, this.app);
-      case "text":
-        return new Text(opts, this.app);
-      default:
-        return null;
-    }
-  }
-  createElement(opts = {}, callback = () => {
-  }, ctx = null, notActive) {
-    if (this.hasActiveElement() || this.isCreatingElement) {
-      return this;
-    }
-    let element = this.pureCreateElement(opts);
-    if (!element) {
-      return this;
-    }
-    this.addElement(element);
-    if (!notActive) {
-      this.setActiveElement(element);
-    }
-    this.isCreatingElement = true;
-    callback.call(ctx, element);
-    return this;
-  }
-  copyElement(element, notActive = false, pos) {
-    return new Promise((resolve) => __async(this, null, function* () {
-      if (!element) {
-        return resolve();
-      }
-      let data = this.app.group.handleCopyElementData(element.serialize());
-      if (data.type === "image") {
-        data.imageObj = yield createImageObj(data.url);
-      }
-      this.createElement(
-        data,
-        (element2) => {
-          this.app.group.handleCopyElement(element2);
-          element2.startResize(DRAG_ELEMENT_PARTS.BODY);
-          let ox = 20;
-          let oy = 20;
-          if (pos) {
-            ox = pos.x - element2.x - element2.width / 2;
-            oy = pos.y - element2.y - element2.height / 2;
-          }
-          let gridAdsorbentPos = this.app.coordinate.gridAdsorbent(ox, oy);
-          element2.resize(
-            null,
-            null,
-            null,
-            gridAdsorbentPos.x,
-            gridAdsorbentPos.y
-          );
-          element2.isCreating = false;
-          if (notActive) {
-            element2.isActive = false;
-          }
-          this.isCreatingElement = false;
-          resolve(element2);
-        },
-        this,
-        notActive
-      );
-    }));
-  }
-  creatingRectangleLikeElement(type, x, y, offsetX, offsetY) {
-    this.createElement({
-      type,
-      x,
-      y,
-      width: offsetX,
-      height: offsetY
-    });
-    this.activeElement.updateSize(offsetX, offsetY);
-  }
-  creatingCircle(x, y, e) {
-    this.createElement({
-      type: "circle",
-      x,
-      y
-    });
-    let radius = getTowPointDistance(e.clientX, e.clientY, x, y);
-    this.activeElement.updateSize(radius, radius);
-  }
-  creatingFreedraw(e, event) {
-    this.createElement({
-      type: "freedraw"
-    });
-    let element = this.activeElement;
-    let lineWidth = computedLineWidthBySpeed(
-      event.mouseSpeed,
-      element.lastLineWidth
-    );
-    element.lastLineWidth = lineWidth;
-    element.addPoint(e.clientX, e.clientY, lineWidth);
-    let { coordinate, ctx, state } = this.app;
-    let tfp = coordinate.transformToCanvasCoordinate(
-      coordinate.subScrollX(event.lastMousePos.x),
-      coordinate.subScrollY(event.lastMousePos.y)
-    );
-    let ttp = coordinate.transformToCanvasCoordinate(
-      coordinate.subScrollX(e.clientX),
-      coordinate.subScrollY(e.clientY)
-    );
-    ctx.save();
-    ctx.scale(state.scale, state.scale);
-    element.singleRender(tfp.x, tfp.y, ttp.x, ttp.y, lineWidth);
-    ctx.restore();
-  }
-  creatingImage(e, { width, height, imageObj, url, ratio }) {
-    let gp = this.app.coordinate.gridAdsorbent(
-      e.unGridClientX - width / 2,
-      e.unGridClientY - height / 2
-    );
-    this.createElement({
-      type: "image",
-      x: gp.x,
-      y: gp.y,
-      url,
-      imageObj,
-      width,
-      height,
-      ratio
-    });
-  }
-  editingText(element) {
-    if (element.type !== "text") {
-      return;
-    }
-    element.noRender = true;
-    this.setActiveElement(element);
-  }
-  completeEditingText() {
-    let element = this.activeElement;
-    if (!element || element.type !== "text") {
-      return;
-    }
-    if (!element.text.trim()) {
-      this.deleteElement(element);
-      this.setActiveElement(null);
-      return;
-    }
-    element.noRender = false;
-  }
-  completeCreateArrow(e) {
-    this.activeElement.addPoint(e.clientX, e.clientY);
-  }
-  creatingArrow(x, y, e) {
-    this.createElement(
-      {
-        type: "arrow",
-        x,
-        y
-      },
-      (element) => {
-        element.addPoint(x, y);
-      }
-    );
-    this.activeElement.updateFictitiousPoint(e.clientX, e.clientY);
-  }
-  creatingLine(x, y, e, isSingle = false, notCreate = false) {
-    if (!notCreate) {
-      this.createElement(
-        {
-          type: "line",
-          x,
-          y,
-          isSingle
-        },
-        (element2) => {
-          element2.addPoint(x, y);
-        }
-      );
-    }
-    let element = this.activeElement;
-    if (element) {
-      element.updateFictitiousPoint(e.clientX, e.clientY);
-    }
-  }
-  completeCreateLine(e, completeCallback = () => {
-  }) {
-    let element = this.activeElement;
-    let x = e.clientX;
-    let y = e.clientY;
-    if (element && element.isSingle) {
-      element.addPoint(x, y);
-      completeCallback();
-    } else {
-      this.createElement({
-        type: "line",
-        isSingle: false
-      });
-      element = this.activeElement;
-      element.addPoint(x, y);
-      element.updateFictitiousPoint(x, y);
-    }
-  }
-  completeCreateElement() {
-    this.isCreatingElement = false;
-    let element = this.activeElement;
-    if (!element) {
-      return this;
-    }
-    if (["freedraw", "arrow", "line"].includes(element.type)) {
-      element.updateMultiPointBoundingRect();
-    }
-    element.isCreating = false;
-    this.app.emitChange();
-    return this;
-  }
-  setActiveElementStyle(style = {}) {
-    if (!this.hasActiveElement()) {
-      return this;
-    }
-    Object.keys(style).forEach((key) => {
-      this.activeElement.style[key] = style[key];
-      if (key === "fontSize" && this.activeElement.type === "text") {
-        this.activeElement.updateTextSize();
-      }
-    });
-    return this;
-  }
-  checkInResizeHand(x, y) {
-    let element = this.activeElement;
-    let hand = element.dragElement.checkPointInDragElementWhere(x, y);
-    if (hand) {
-      return {
-        element,
-        hand
-      };
-    }
-    return null;
-  }
-  checkIsResize(x, y, e) {
-    if (!this.hasActiveElement()) {
-      return false;
-    }
-    let res = this.checkInResizeHand(x, y);
-    if (res) {
-      this.isResizing = true;
-      this.resizingElement = res.element;
-      this.resizingElement.startResize(res.hand, e);
-      this.app.cursor.setResize(res.hand);
-      return true;
-    }
-    return false;
-  }
-  handleResize(...args) {
-    if (!this.isResizing) {
-      return;
-    }
-    this.resizingElement.resize(...args);
-    this.app.render.render();
-  }
-  endResize() {
-    this.isResizing = false;
-    this.resizingElement.endResize();
-    this.resizingElement = null;
-  }
-}
-let getRandomValues;
-const rnds8 = new Uint8Array(16);
-function rng() {
-  if (!getRandomValues) {
-    getRandomValues = typeof crypto !== "undefined" && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);
-    if (!getRandomValues) {
-      throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
-    }
-  }
-  return getRandomValues(rnds8);
-}
-const byteToHex = [];
-for (let i = 0; i < 256; ++i) {
-  byteToHex.push((i + 256).toString(16).slice(1));
-}
-function unsafeStringify(arr, offset = 0) {
-  return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
-}
-const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
-var native = {
-  randomUUID
-};
-function v4(options, buf, offset) {
-  if (native.randomUUID && !buf && !options) {
-    return native.randomUUID();
-  }
-  options = options || {};
-  const rnds = options.random || (options.rng || rng)();
-  rnds[6] = rnds[6] & 15 | 64;
-  rnds[8] = rnds[8] & 63 | 128;
-  if (buf) {
-    offset = offset || 0;
-    for (let i = 0; i < 16; ++i) {
-      buf[offset + i] = rnds[i];
-    }
-    return buf;
-  }
-  return unsafeStringify(rnds);
-}
-class Group {
-  constructor(app) {
-    this.app = app;
-    this.groupIdToElementList = {};
-    this.newGroupIdMap = {};
-  }
-  render() {
-    Object.keys(this.groupIdToElementList).forEach((groupId) => {
-      let group = this.groupIdToElementList[groupId];
-      let selected = group[0].isSelected;
-      if (selected) {
-        let mElement = new MultiSelectElement(
-          {
-            type: "multiSelectElement"
-          },
-          this.app
-        );
-        mElement.setSelectedElementList(group);
-        mElement.updateRect();
-        mElement.dragElement.onlyShowBody();
-        mElement.render();
-      }
-    });
-  }
-  setToMap(element) {
-    let groupId = element.getGroupId();
-    if (groupId) {
-      if (!this.groupIdToElementList[groupId]) {
-        this.groupIdToElementList[groupId] = [];
-      }
-      this.groupIdToElementList[groupId].push(element);
-    }
-  }
-  initIdToElementList(elementList) {
-    this.groupIdToElementList = {};
-    elementList.forEach((element) => {
-      this.setToMap(element);
-    });
-  }
-  handleCopyElementData(data) {
-    if (data.groupId) {
-      if (this.newGroupIdMap[data.groupId]) {
-        data.groupId = this.newGroupIdMap[data.groupId];
-      } else {
-        data.groupId = this.newGroupIdMap[data.groupId] = v4();
-      }
-    }
-    return data;
-  }
-  clearCopyMap() {
-    this.newGroupIdMap = {};
-  }
-  handleCopyElement(element) {
-    this.setToMap(element);
-  }
-  dogroup() {
-    if (!this.app.selection.hasSelection || this.app.selection.multiSelectElement.selectedElementList.length <= 1) {
-      return;
-    }
-    let groupElement = this.app.selection.multiSelectElement.selectedElementList;
-    let groupId = v4();
-    this.groupIdToElementList[groupId] = groupElement;
-    groupElement.forEach((element) => {
-      element.setGroupId(groupId);
-    });
-    this.app.render.render();
-    this.app.emitChange();
-  }
-  ungroup() {
-    if (!this.app.selection.hasSelection || this.app.selection.multiSelectElement.selectedElementList.length <= 1) {
-      return;
-    }
-    let groupElement = this.app.selection.multiSelectElement.selectedElementList;
-    let groupId = groupElement[0].getGroupId();
-    this.groupIdToElementList[groupId] = [];
-    delete this.groupIdToElementList[groupId];
-    groupElement.forEach((element) => {
-      element.removeGroupId(groupId);
-    });
-    this.app.render.render();
-    this.app.emitChange();
-  }
-  setSelection(element) {
-    let groupId = element.getGroupId();
-    if (this.groupIdToElementList[groupId]) {
-      this.app.selection.selectElements(this.groupIdToElementList[groupId]);
-    }
-  }
-  getGroupElements(element) {
-    let groupId = element.getGroupId();
-    return this.groupIdToElementList[groupId] || [];
-  }
-}
-class TinyWhiteboard extends EventEmitter {
-  constructor(opts = {}) {
-    super();
-    this.opts = opts;
-    this.container = opts.container;
-    this.drawType = opts.drawType || "selection";
-    if (!this.container) {
-      throw new Error("\u7F3A\u5C11 container \u53C2\u6570\uFF01");
-    }
-    if (!["absolute", "fixed", "relative"].includes(
-      window.getComputedStyle(this.container).position
-    )) {
-      throw new Error("container\u5143\u7D20\u9700\u8981\u8BBE\u7F6E\u5B9A\u4F4D\uFF01");
-    }
-    this.width = 0;
-    this.height = 0;
-    this.left = 0;
-    this.top = 0;
-    this.canvas = null;
-    this.ctx = null;
-    this.state = __spreadValues({
-      scale: 1,
-      scrollX: 0,
-      scrollY: 0,
-      scrollStep: 50,
-      backgroundColor: "",
-      strokeStyle: "#000000",
-      fillStyle: "transparent",
-      fontFamily: "\u5FAE\u8F6F\u96C5\u9ED1, Microsoft YaHei",
-      fontSize: 18,
-      dragStrokeStyle: "#666",
-      showGrid: false,
-      readonly: false,
-      gridConfig: {
-        size: 20,
-        strokeStyle: "#dfe0e1",
-        lineWidth: 1
-      }
-    }, opts.state || {});
-    this.initCanvas();
-    this.coordinate = new Coordinate(this);
-    this.event = new Event(this);
-    this.event.on("mousedown", this.onMousedown, this);
-    this.event.on("mousemove", this.onMousemove, this);
-    this.event.on("mouseup", this.onMouseup, this);
-    this.event.on("dblclick", this.onDblclick, this);
-    this.event.on("mousewheel", this.onMousewheel, this);
-    this.event.on("contextmenu", this.onContextmenu, this);
-    this.keyCommand = new KeyCommand(this);
-    this.imageEdit = new ImageEdit(this);
-    this.imageEdit.on("imageSelectChange", this.onImageSelectChange, this);
-    this.textEdit = new TextEdit(this);
-    this.textEdit.on("blur", this.onTextInputBlur, this);
-    this.cursor = new Cursor(this);
-    this.history = new History(this);
-    this.export = new Export(this);
-    this.background = new Background(this);
-    this.selection = new Selection(this);
-    this.group = new Group(this);
-    this.grid = new Grid(this);
-    this.mode = new Mode(this);
-    this.elements = new Elements$1(this);
-    this.render = new Render(this);
-    this.proxy();
-    this.checkIsOnElement = throttle(this.checkIsOnElement, this);
-    this.emitChange();
-    this.helpUpdate();
-  }
-  proxy() {
-    ["undo", "redo"].forEach((method) => {
-      this[method] = this.history[method].bind(this.history);
-    });
-    [].forEach((method) => {
-      this[method] = this.elements[method].bind(this.elements);
-    });
-    [
-      "deleteElement",
-      "setActiveElementStyle",
-      "setCurrentElementsStyle",
-      "cancelActiveElement",
-      "deleteActiveElement",
-      "deleteCurrentElements",
-      "empty",
-      "zoomIn",
-      "zoomOut",
-      "setZoom",
-      "scrollTo",
-      "scrollToCenter",
-      "copyPasteCurrentElements",
-      "setBackgroundColor",
-      "copyElement",
-      "copyCurrentElement",
-      "cutCurrentElement",
-      "pasteCurrentElement",
-      "updateActiveElementRotate",
-      "updateActiveElementSize",
-      "updateActiveElementPosition",
-      "moveBottomCurrentElement",
-      "moveTopCurrentElement",
-      "moveUpCurrentElement",
-      "moveDownCurrentElement",
-      "selectAll",
-      "fit"
-    ].forEach((method) => {
-      this[method] = this.render[method].bind(this.render);
-    });
-    ["exportImage", "exportJson"].forEach((method) => {
-      this[method] = this.export[method].bind(this.export);
-    });
-    ["setSelectedElementStyle"].forEach((method) => {
-      this[method] = this.selection[method].bind(this.selection);
-    });
-    ["dogroup", "ungroup"].forEach((method) => {
-      this[method] = this.group[method].bind(this.group);
-    });
-    ["showGrid", "hideGrid", "updateGrid"].forEach((method) => {
-      this[method] = this.grid[method].bind(this.grid);
-    });
-    ["setEditMode", "setReadonlyMode"].forEach((method) => {
-      this[method] = this.mode[method].bind(this.mode);
-    });
-  }
-  getContainerRectInfo() {
-    let { width, height, left, top } = this.container.getBoundingClientRect();
-    this.width = width;
-    this.height = height;
-    this.left = left;
-    this.top = top;
-  }
-  helpUpdate() {
-    this.background.set();
-    if (this.state.showGrid) {
-      this.grid.showGrid();
-    }
-    if (this.state.readonly) {
-      this.setReadonlyMode();
-    }
-  }
-  setData(_0, _1) {
-    return __async(this, arguments, function* ({ state = {}, elements = [] }, noEmitChange) {
-      this.state = state;
-      for (let i = 0; i < elements.length; i++) {
-        if (elements[i].type === "image") {
-          elements[i].imageObj = yield createImageObj(elements[i].url);
-        }
-      }
-      this.helpUpdate();
-      this.elements.deleteAllElements().createElementsFromData(elements);
-      this.render.render();
-      if (!noEmitChange) {
-        this.emitChange();
-      }
-    });
-  }
-  initCanvas() {
-    this.getContainerRectInfo();
-    if (this.canvas) {
-      this.container.removeChild(this.canvas);
-    }
-    let { canvas, ctx } = createCanvas(this.width, this.height, {
-      className: "main"
-    });
-    this.canvas = canvas;
-    this.ctx = ctx;
-    this.container.appendChild(this.canvas);
-  }
-  resize() {
-    this.initCanvas();
-    this.render.render();
-    this.selection.init();
-    this.grid.init();
-    this.grid.renderGrid();
-  }
-  updateState(data = {}) {
-    this.state = __spreadValues(__spreadValues({}, this.state), data);
-    this.emitChange();
-  }
-  updateCurrentType(drawType) {
-    this.drawType = drawType;
-    if (this.drawType === "image") {
-      this.imageEdit.selectImage();
-    }
-    if (this.drawType === "eraser") {
-      this.cursor.setEraser();
-      this.cancelActiveElement();
-    } else if (this.drawType !== "selection") {
-      this.cursor.setCrosshair();
-    } else {
-      this.cursor.reset();
-    }
-    this.emit("currentTypeChange", this.drawType);
-  }
-  getData() {
-    return {
-      state: __spreadValues({}, this.state),
-      elements: this.elements.serialize()
-    };
-  }
-  onImageSelectChange() {
-    this.cursor.hide();
-  }
-  onMousedown(e, event) {
-    if (this.state.readonly || this.mode.isDragMode) {
-      this.mode.onStart();
-      return;
-    }
-    if (!this.elements.isCreatingElement && !this.textEdit.isEditing) {
-      let hitElement = this.elements.checkIsHitElement(e);
-      if (this.drawType === "selection") {
-        if (this.elements.hasActiveElement()) {
-          let isResizing = this.elements.checkIsResize(
-            event.mousedownPos.unGridClientX,
-            event.mousedownPos.unGridClientY,
-            e
-          );
-          if (!isResizing) {
-            this.elements.setActiveElement(hitElement);
-            this.render.render();
-          }
-        } else {
-          if (this.selection.hasSelection) {
-            let isResizing = this.selection.checkIsResize(
-              event.mousedownPos.unGridClientX,
-              event.mousedownPos.unGridClientY,
-              e
-            );
-            if (!isResizing) {
-              this.selection.reset();
-              this.elements.setActiveElement(hitElement);
-              this.render.render();
-            }
-          } else if (hitElement) {
-            if (hitElement.hasGroup()) {
-              this.group.setSelection(hitElement);
-              this.onMousedown(e, event);
-            } else {
-              this.elements.setActiveElement(hitElement);
-              this.render.render();
-              this.onMousedown(e, event);
-            }
-          } else {
-            this.selection.onMousedown(e, event);
-          }
-        }
-      } else if (this.drawType === "eraser") {
-        this.deleteElement(hitElement);
-      }
-    }
-  }
-  onMousemove(e, event) {
-    if (this.state.readonly || this.mode.isDragMode) {
-      if (event.isMousedown) {
-        this.mode.onMove(e, event);
-      }
-      return;
-    }
-    if (event.isMousedown) {
-      let mx = event.mousedownPos.x;
-      let my = event.mousedownPos.y;
-      let offsetX = Math.max(event.mouseOffset.x, 0);
-      let offsetY = Math.max(event.mouseOffset.y, 0);
-      if (this.drawType === "selection") {
-        if (this.selection.isResizing) {
-          this.selection.handleResize(
-            e,
-            mx,
-            my,
-            event.mouseOffset.x,
-            event.mouseOffset.y
-          );
-        } else if (this.selection.creatingSelection) {
-          this.selection.onMousemove(e, event);
-        } else {
-          this.elements.handleResize(
-            e,
-            mx,
-            my,
-            event.mouseOffset.x,
-            event.mouseOffset.y
-          );
-        }
-      } else if (["rectangle", "diamond", "triangle"].includes(this.drawType)) {
-        this.elements.creatingRectangleLikeElement(
-          this.drawType,
-          mx,
-          my,
-          offsetX,
-          offsetY
-        );
-        this.render.render();
-      } else if (this.drawType === "circle") {
-        this.elements.creatingCircle(mx, my, e);
-        this.render.render();
-      } else if (this.drawType === "freedraw") {
-        this.elements.creatingFreedraw(e, event);
-      } else if (this.drawType === "arrow") {
-        this.elements.creatingArrow(mx, my, e);
-        this.render.render();
-      } else if (this.drawType === "line") {
-        if (getTowPointDistance(mx, my, e.clientX, e.clientY) > 3) {
-          this.elements.creatingLine(mx, my, e, true);
-          this.render.render();
-        }
-      }
-    } else {
-      if (this.imageEdit.isReady) {
-        this.cursor.hide();
-        this.imageEdit.updatePreviewElPos(
-          e.originEvent.clientX,
-          e.originEvent.clientY
-        );
-      } else if (this.drawType === "selection") {
-        if (this.elements.hasActiveElement()) {
-          let handData = "";
-          if (handData = this.elements.checkInResizeHand(
-            e.unGridClientX,
-            e.unGridClientY
-          )) {
-            this.cursor.setResize(handData.hand);
-          } else {
-            this.checkIsOnElement(e);
-          }
-        } else if (this.selection.hasSelection) {
-          let hand = this.selection.checkInResizeHand(
-            e.unGridClientX,
-            e.unGridClientY
-          );
-          if (hand) {
-            this.cursor.setResize(hand);
-          } else {
-            this.checkIsOnElement(e);
-          }
-        } else {
-          this.checkIsOnElement(e);
-        }
-      } else if (this.drawType === "line") {
-        this.elements.creatingLine(null, null, e, false, true);
-        this.render.render();
-      }
-    }
-  }
-  checkIsOnElement(e) {
-    let hitElement = this.elements.checkIsHitElement(e);
-    if (hitElement) {
-      this.cursor.setMove();
-    } else {
-      this.cursor.reset();
-    }
-  }
-  resetCurrentType() {
-    if (this.drawType !== "selection") {
-      this.drawType = "selection";
-      this.emit("currentTypeChange", "selection");
-    }
-  }
-  completeCreateNewElement() {
-    this.resetCurrentType();
-    this.elements.completeCreateElement();
-    this.render.render();
-  }
-  onMouseup(e) {
-    if (this.state.readonly || this.mode.isDragMode) {
-      return;
-    }
-    if (this.drawType === "text") {
-      if (!this.textEdit.isEditing) {
-        this.createTextElement(e);
-        this.resetCurrentType();
-      }
-    } else if (this.imageEdit.isReady) {
-      this.elements.creatingImage(e, this.imageEdit.imageData);
-      this.completeCreateNewElement();
-      this.cursor.reset();
-      this.imageEdit.reset();
-    } else if (this.drawType === "arrow") {
-      this.elements.completeCreateArrow(e);
-      this.completeCreateNewElement();
-    } else if (this.drawType === "line") {
-      this.elements.completeCreateLine(e, () => {
-        this.completeCreateNewElement();
-      });
-      this.render.render();
-    } else if (this.elements.isCreatingElement) {
-      if (this.drawType === "freedraw") {
-        this.elements.completeCreateElement();
-        this.elements.setActiveElement();
-      } else {
-        this.completeCreateNewElement();
-      }
-    } else if (this.elements.isResizing) {
-      this.elements.endResize();
-      this.emitChange();
-    } else if (this.selection.creatingSelection) {
-      this.selection.onMouseup(e);
-    } else if (this.selection.isResizing) {
-      this.selection.endResize();
-      this.emitChange();
-    }
-  }
-  onDblclick(e) {
-    if (this.drawType === "line") {
-      this.completeCreateNewElement();
-    } else {
-      let hitElement = this.elements.checkIsHitElement(e);
-      if (hitElement) {
-        if (hitElement.type === "text") {
-          this.elements.editingText(hitElement);
-          this.render.render();
-          this.keyCommand.unBindEvent();
-          this.textEdit.showTextEdit();
-        }
-      } else {
-        if (!this.textEdit.isEditing) {
-          this.createTextElement(e);
-        }
-      }
-    }
-  }
-  onTextInputBlur() {
-    this.keyCommand.bindEvent();
-    this.elements.completeEditingText();
-    this.render.render();
-    this.emitChange();
-  }
-  createTextElement(e) {
-    this.elements.createElement({
-      type: "text",
-      x: e.clientX,
-      y: e.clientY
-    });
-    this.keyCommand.unBindEvent();
-    this.textEdit.showTextEdit();
-  }
-  onMousewheel(dir) {
-    let stepNum = this.state.scrollStep / this.state.scale;
-    let step = dir === "down" ? stepNum : -stepNum;
-    this.scrollTo(this.state.scrollX, this.state.scrollY + step);
-  }
-  onContextmenu(e) {
-    let elements = [];
-    if (this.elements.hasActiveElement()) {
-      elements = [this.elements.activeElement];
-    } else if (this.selection.hasSelectionElements()) {
-      elements = this.selection.getSelectionElements();
-    }
-    this.emit("contextmenu", e.originEvent, elements);
-  }
-  emitChange() {
-    let data = this.getData();
-    this.history.add(data);
-    this.emit("change", data);
-  }
-}
-TinyWhiteboard.utils = utils;
-TinyWhiteboard.checkHit = checkHit;
-TinyWhiteboard.draw = draw;
-TinyWhiteboard.elements = Elements;
-export { TinyWhiteboard as default };

Fișier diff suprimat deoarece este prea mare
+ 0 - 0
frontend/dist/tiny-whiteboard/tiny-whiteboard.umd.js


+ 0 - 137
log/app.log

@@ -1,137 +0,0 @@
-{"level":"warn","time":"2024-04-09T21:10:23.363+0800","lineNum":"file_upload/main.go:14","func":"main.init.0","message":"<nil>"}
-{"level":"warn","time":"2024-04-10T15:08:01.502+0800","lineNum":"controller/fileUpload.go:20","func":"file_upload/app/controller.FuileUpload","message":"http: no such file"}
-{"level":"warn","time":"2024-04-10T15:09:32.780+0800","lineNum":"controller/fileUpload.go:20","func":"file_upload/app/controller.FuileUpload","message":"http: no such file"}
-{"level":"warn","time":"2024-04-10T15:10:08.591+0800","lineNum":"controller/fileUpload.go:20","func":"file_upload/app/controller.FuileUpload","message":"http: no such file"}
-{"level":"warn","time":"2024-04-10T15:11:35.769+0800","lineNum":"controller/fileUpload.go:20","func":"file_upload/app/controller.FuileUpload","message":"http: no such file"}
-{"level":"warn","time":"2024-04-10T15:19:09.999+0800","lineNum":"controller/fileUpload.go:24","func":"file_upload/app/controller.FuileUpload","message":"http: no such file"}
-{"level":"warn","time":"2024-04-10T15:20:13.812+0800","lineNum":"controller/fileUpload.go:24","func":"file_upload/app/controller.FuileUpload","message":"http: no such file"}
-{"level":"warn","time":"2024-04-10T15:25:25.164+0800","lineNum":"controller/fileUpload.go:25","func":"file_upload/app/controller.FuileUpload","message":"invalid character '-' in numeric literaljson解析失败"}
-{"level":"warn","time":"2024-04-10T15:25:25.181+0800","lineNum":"controller/fileUpload.go:34","func":"file_upload/app/controller.FuileUpload","message":"http: no such file获取文件失败"}
-{"level":"warn","time":"2024-04-10T15:26:12.817+0800","lineNum":"controller/fileUpload.go:25","func":"file_upload/app/controller.FuileUpload","message":"invalid character '-' in numeric literaljson解析失败"}
-{"level":"warn","time":"2024-04-10T15:27:25.042+0800","lineNum":"controller/fileUpload.go:34","func":"file_upload/app/controller.FuileUpload","message":"http: no such file获取文件失败"}
-{"level":"warn","time":"2024-04-10T15:37:11.908+0800","lineNum":"controller/fileUpload.go:25","func":"file_upload/app/controller.FuileUpload","message":"invalid character '-' in numeric literaljson解析失败"}
-{"level":"warn","time":"2024-04-10T15:37:11.921+0800","lineNum":"controller/fileUpload.go:34","func":"file_upload/app/controller.FuileUpload","message":"http: no such file获取文件失败"}
-{"level":"warn","time":"2024-04-10T15:37:11.921+0800","lineNum":"controller/fileUpload.go:25","func":"file_upload/app/controller.FuileUpload","message":"invalid character '-' in numeric literaljson解析失败"}
-{"level":"warn","time":"2024-04-10T15:37:11.922+0800","lineNum":"controller/fileUpload.go:34","func":"file_upload/app/controller.FuileUpload","message":"http: no such file获取文件失败"}
-{"level":"warn","time":"2024-04-10T15:38:48.248+0800","lineNum":"controller/fileUpload.go:25","func":"file_upload/app/controller.FuileUpload","message":"invalid character '-' in numeric literaljson解析失败"}
-{"level":"warn","time":"2024-04-10T15:41:13.289+0800","lineNum":"controller/fileUpload.go:25","func":"file_upload/app/controller.FuileUpload","message":"invalid character '-' in numeric literaljson解析失败"}
-{"level":"warn","time":"2024-04-10T15:44:07.096+0800","lineNum":"controller/fileUpload.go:25","func":"file_upload/app/controller.FuileUpload","message":"invalid character '-' in numeric literaljson解析失败"}
-{"level":"warn","time":"2024-04-10T15:47:50.816+0800","lineNum":"controller/fileUpload.go:26","func":"file_upload/app/controller.FuileUpload","message":"invalid character '-' in numeric literaljson解析失败"}
-{"level":"warn","time":"2024-04-10T15:48:44.327+0800","lineNum":"controller/fileUpload.go:26","func":"file_upload/app/controller.FuileUpload","message":"invalid character '-' in numeric literaljson解析失败"}
-{"level":"warn","time":"2024-04-10T16:02:37.197+0800","lineNum":"controller/fileUpload.go:26","func":"file_upload/app/controller.FuileUpload","message":"invalid character '-' in numeric literaljson解析失败"}
-{"level":"warn","time":"2024-04-10T16:04:23.279+0800","lineNum":"controller/fileUpload.go:26","func":"file_upload/app/controller.FuileUpload","message":"invalid character '-' in numeric literaljson解析失败"}
-{"level":"warn","time":"2024-04-10T16:07:06.937+0800","lineNum":"controller/fileUpload.go:26","func":"file_upload/app/controller.FuileUpload","message":"invalid character '-' in numeric literaljson解析失败"}
-{"level":"warn","time":"2024-04-10T16:35:59.303+0800","lineNum":"controller/fileUpload.go:26","func":"file_upload/app/controller.FuileUpload","message":"invalid character '-' in numeric literaljson解析失败"}
-{"level":"warn","time":"2024-04-12T10:15:01.654+0800","lineNum":"global/redis.go:24","func":"file_upload/global.SetupRedisLink","message":"redis连接失败dial tcp 192.168.0.100:6379: i/o timeout"}
-{"level":"info","time":"2024-04-12T11:04:14.714+0800","lineNum":"controller/fileUpload.go:56","func":"file_upload/app/controller.SaveUsernameToLocalStorage","message":""}
-{"level":"info","time":"2024-04-12T11:04:14.719+0800","lineNum":"controller/fileUpload.go:56","func":"file_upload/app/controller.SaveUsernameToLocalStorage","message":""}
-{"level":"info","time":"2024-04-12T11:08:25.520+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:08:28.789+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:09:34.080+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:09:34.992+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:10:11.454+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:11:20.670+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:11:53.134+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:12:37.407+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:13:08.941+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:16:00.560+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:23:37.708+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:23:37.708+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:33:21.029+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:33:34.426+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:36:33.407+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:37:12.069+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:37:28.868+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:37:32.302+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:37:56.607+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:38:19.036+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:38:52.967+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:40:37.117+0800","lineNum":"controller/fileUpload.go:62","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:40:51.263+0800","lineNum":"controller/fileUpload.go:63","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:40:59.205+0800","lineNum":"controller/fileUpload.go:63","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:41:42.969+0800","lineNum":"controller/fileUpload.go:63","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:42:37.651+0800","lineNum":"controller/fileUpload.go:63","func":"file_upload/app/controller.SerializedItems","message":""}
-{"level":"info","time":"2024-04-12T11:49:22.589+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"json: cannot unmarshal array into Go value of type string"}
-{"level":"info","time":"2024-04-12T12:28:16.714+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"json: cannot unmarshal object into Go value of type []interface {}"}
-{"level":"info","time":"2024-04-12T12:32:02.472+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"json: cannot unmarshal object into Go value of type string"}
-{"level":"info","time":"2024-04-12T12:42:02.957+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"json: cannot unmarshal object into Go value of type string"}
-{"level":"info","time":"2024-04-12T12:42:04.532+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"json: cannot unmarshal object into Go value of type string"}
-{"level":"info","time":"2024-04-12T12:42:17.735+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"json: cannot unmarshal object into Go value of type string"}
-{"level":"info","time":"2024-04-12T12:44:06.073+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"json: cannot unmarshal object into Go value of type string"}
-{"level":"info","time":"2024-04-12T12:44:06.076+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"json: cannot unmarshal object into Go value of type string"}
-{"level":"info","time":"2024-04-12T12:44:17.355+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"json: cannot unmarshal object into Go value of type string"}
-{"level":"info","time":"2024-04-12T12:46:08.327+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"json: cannot unmarshal object into Go value of type string"}
-{"level":"info","time":"2024-04-12T12:46:12.343+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"json: cannot unmarshal object into Go value of type string"}
-{"level":"info","time":"2024-04-12T12:46:21.897+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"json: cannot unmarshal object into Go value of type string"}
-{"level":"info","time":"2024-04-12T12:47:42.838+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T13:56:52.390+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T13:56:54.652+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T13:57:06.361+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T13:57:38.443+0800","lineNum":"controller/fileUpload.go:64","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:00:28.155+0800","lineNum":"controller/fileUpload.go:66","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:02:07.979+0800","lineNum":"controller/fileUpload.go:69","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:02:23.405+0800","lineNum":"controller/fileUpload.go:69","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:02:39.691+0800","lineNum":"controller/fileUpload.go:69","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:03:43.246+0800","lineNum":"controller/fileUpload.go:70","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:05:44.934+0800","lineNum":"controller/fileUpload.go:70","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:06:01.615+0800","lineNum":"controller/fileUpload.go:70","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:06:48.383+0800","lineNum":"controller/fileUpload.go:70","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:06:48.383+0800","lineNum":"controller/fileUpload.go:70","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:07:00.876+0800","lineNum":"controller/fileUpload.go:70","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:12:17.525+0800","lineNum":"controller/fileUpload.go:70","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:12:38.443+0800","lineNum":"controller/fileUpload.go:70","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:14:09.847+0800","lineNum":"controller/fileUpload.go:72","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:18:26.814+0800","lineNum":"controller/fileUpload.go:72","func":"file_upload/app/controller.SerializedItems","message":"<nil>"}
-{"level":"info","time":"2024-04-12T14:19:39.683+0800","lineNum":"controller/fileUpload.go:74","func":"file_upload/app/controller.SerializedItems","message":"EOF"}
-{"level":"info","time":"2024-04-12T14:20:25.082+0800","lineNum":"controller/fileUpload.go:74","func":"file_upload/app/controller.SerializedItems","message":"EOF"}
-{"level":"info","time":"2024-04-12T14:21:06.105+0800","lineNum":"controller/fileUpload.go:67","func":"file_upload/app/controller.SerializedItems","message":"{[{\"id\":\"XOxMtR7pQmbeQJ8JFH67r\",\"status\":\"unpublished\",\"elements\":[{\"type\":\"ellipse\",\"version\":101,\"versionNonce\":478164098,\"isDeleted\":false,\"id\":\"fX6N86TfVdOIdc3PSD3KL\",\"fillStyle\":\"hachure\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"angle\":0,\"x\":540.2000122070312,\"y\":-37.400001525878906,\"strokeColor\":\"#000000\",\"backgroundColor\":\"transparent\",\"width\":272.79998779296875,\"height\":266.4000015258789,\"seed\":518248706,\"groupIds\":[],\"roundness\":{\"type\":2},\"boundElements\":[],\"updated\":1712902311981,\"link\":null,\"locked\":false},{\"type\":\"rectangle\",\"version\":146,\"versionNonce\":1953708482,\"isDeleted\":false,\"id\":\"PELjrZObO6_8JBXTADkEn\",\"fillStyle\":\"hachure\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"angle\":0,\"x\":566.5999755859375,\"y\":1.0000152587890625,\"strokeColor\":\"#000000\",\"backgroundColor\":\"transparent\",\"width\":218.40002441406253,\"height\":192.79998779296878,\"seed\":222975042,\"groupIds\":[],\"roundness\":{\"type\":3},\"boundElements\":[],\"updated\":1712902326027,\"link\":null,\"locked\":false}],\"created\":1712902332363}]}"}
-{"level":"info","time":"2024-04-12T14:21:54.360+0800","lineNum":"controller/fileUpload.go:67","func":"file_upload/app/controller.SerializedItems","message":"{[{\"id\":\"XOxMtR7pQmbeQJ8JFH67r\",\"status\":\"unpublished\",\"elements\":[{\"type\":\"ellipse\",\"version\":101,\"versionNonce\":478164098,\"isDeleted\":false,\"id\":\"fX6N86TfVdOIdc3PSD3KL\",\"fillStyle\":\"hachure\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"angle\":0,\"x\":540.2000122070312,\"y\":-37.400001525878906,\"strokeColor\":\"#000000\",\"backgroundColor\":\"transparent\",\"width\":272.79998779296875,\"height\":266.4000015258789,\"seed\":518248706,\"groupIds\":[],\"roundness\":{\"type\":2},\"boundElements\":[],\"updated\":1712902311981,\"link\":null,\"locked\":false},{\"type\":\"rectangle\",\"version\":146,\"versionNonce\":1953708482,\"isDeleted\":false,\"id\":\"PELjrZObO6_8JBXTADkEn\",\"fillStyle\":\"hachure\",\"strokeWidth\":1,\"strokeStyle\":\"solid\",\"roughness\":1,\"opacity\":100,\"angle\":0,\"x\":566.5999755859375,\"y\":1.0000152587890625,\"strokeColor\":\"#000000\",\"backgroundColor\":\"transparent\",\"width\":218.40002441406253,\"height\":192.79998779296878,\"seed\":222975042,\"groupIds\":[],\"roundness\":{\"type\":3},\"boundElements\":[],\"updated\":1712902326027,\"link\":null,\"locked\":false}],\"created\":1712902332363}]}"}
-{"level":"warn","time":"2024-04-14T15:53:08.658+0800","lineNum":"global/redis.go:24","func":"file_upload/global.SetupRedisLink","message":"redis连接失败NOAUTH Authentication required."}
-{"level":"warn","time":"2024-04-14T15:58:38.061+0800","lineNum":"global/redis.go:24","func":"file_upload/global.SetupRedisLink","message":"redis连接失败dial tcp 116.204.6.184:6379: i/o timeout"}
-{"level":"warn","time":"2024-04-16T09:11:12.268+0800","lineNum":"controller/file.go:68","func":"file_upload/app/controller.SaveFile","message":"redis: can't marshal map[string]interface {} (implement encoding.BinaryMarshaler)保存文件失败"}
-{"level":"warn","time":"2024-04-16T09:12:58.839+0800","lineNum":"controller/file.go:68","func":"file_upload/app/controller.SaveFile","message":"redis: can't marshal map[string]interface {} (implement encoding.BinaryMarshaler)保存文件失败"}
-{"level":"warn","time":"2024-04-16T11:17:36.064+0800","lineNum":"controller/file.go:136","func":"file_upload/app/controller.TemplateItem","message":"Mismatch type controller.File with value string \"at index 0: mismatched type with value\\n\\n\\t\\\"{\\\\\\\"type\\\\\\\":true,\\\\\\\"data\\\\\\\":{\\\\\\\"stat\\n\\t^...............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T11:17:54.491+0800","lineNum":"controller/file.go:136","func":"file_upload/app/controller.TemplateItem","message":"Mismatch type controller.File with value string \"at index 0: mismatched type with value\\n\\n\\t\\\"{\\\\\\\"type\\\\\\\":true,\\\\\\\"data\\\\\\\":{\\\\\\\"stat\\n\\t^...............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T11:18:33.403+0800","lineNum":"controller/file.go:136","func":"file_upload/app/controller.TemplateItem","message":"Mismatch type controller.File with value string \"at index 0: mismatched type with value\\n\\n\\t\\\"{\\\\\\\"type\\\\\\\":true,\\\\\\\"data\\\\\\\":{\\\\\\\"stat\\n\\t^...............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T11:29:34.619+0800","lineNum":"controller/file.go:136","func":"file_upload/app/controller.TemplateItem","message":"Mismatch type controller.File with value string \"at index 0: mismatched type with value\\n\\n\\t\\\"{\\\\\\\"type\\\\\\\":true,\\\\\\\"data\\\\\\\":{\\\\\\\"stat\\n\\t^...............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T11:36:41.629+0800","lineNum":"controller/file.go:136","func":"file_upload/app/controller.TemplateItem","message":"Mismatch type controller.File with value string \"at index 0: mismatched type with value\\n\\n\\t\\\"{\\\\\\\"type\\\\\\\":true,\\\\\\\"data\\\\\\\":{\\\\\\\"stat\\n\\t^...............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T11:37:41.180+0800","lineNum":"controller/file.go:137","func":"file_upload/app/controller.TemplateItem","message":"Mismatch type model.Root with value string \"at index 0: mismatched type with value\\n\\n\\t\\\"{\\\\\\\"type\\\\\\\":true,\\\\\\\"data\\\\\\\":{\\\\\\\"stat\\n\\t^...............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T11:38:54.719+0800","lineNum":"controller/file.go:133","func":"file_upload/app/controller.TemplateItem","message":"Mismatch type string with value bool \"at index 8: mismatched type with value\\n\\n\\t{\\\"type\\\":true,\\\"data\\\":{\\\"state\\\":{\\\"f\\n\\t........^.......................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T14:13:41.911+0800","lineNum":"controller/file.go:138","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T14:14:20.613+0800","lineNum":"controller/file.go:138","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T14:15:36.076+0800","lineNum":"controller/file.go:138","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T14:17:58.897+0800","lineNum":"controller/file.go:138","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T14:21:06.130+0800","lineNum":"controller/file.go:138","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T14:25:34.016+0800","lineNum":"controller/file.go:138","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T14:28:33.070+0800","lineNum":"controller/file.go:145","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T14:33:10.781+0800","lineNum":"controller/file.go:144","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T14:42:25.071+0800","lineNum":"controller/file.go:144","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T14:43:09.678+0800","lineNum":"controller/file.go:144","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-16T20:24:31.713+0800","lineNum":"global/redis.go:24","func":"file_upload/global.SetupRedisLink","message":"redis连接失败dial tcp 116.204.6.184:6379: connectex: A socket operation was attempted to an unreachable network."}
-{"level":"warn","time":"2024-04-17T09:41:59.882+0800","lineNum":"controller/file.go:65","func":"file_upload/app/controller.SaveFile","message":"invalid character 'o' looking for beginning of value获取参数失败"}
-{"level":"warn","time":"2024-04-17T09:45:20.379+0800","lineNum":"controller/file.go:65","func":"file_upload/app/controller.SaveFile","message":"invalid character 'o' looking for beginning of value获取参数失败"}
-{"level":"warn","time":"2024-04-17T10:10:49.232+0800","lineNum":"controller/file.go:163","func":"file_upload/app/controller.GetTemplate","message":"read tcp 192.168.11.29:54613->116.204.6.184:6379: i/o timeout获取文件失败"}
-{"level":"warn","time":"2024-04-17T14:30:22.609+0800","lineNum":"controller/file.go:119","func":"file_upload/app/controller.TemplateItem","message":"dial tcp 116.204.6.184:6379: connectex: A socket operation was attempted to an unreachable network.获取模板失败"}
-{"level":"warn","time":"2024-04-17T14:33:01.401+0800","lineNum":"controller/file.go:119","func":"file_upload/app/controller.TemplateItem","message":"dial tcp 116.204.6.184:6379: i/o timeout获取模板失败"}
-{"level":"warn","time":"2024-04-17T14:33:20.595+0800","lineNum":"controller/file.go:119","func":"file_upload/app/controller.TemplateItem","message":"dial tcp 116.204.6.184:6379: i/o timeout获取模板失败"}
-{"level":"warn","time":"2024-04-17T21:08:26.251+0800","lineNum":"global/redis.go:24","func":"file_upload/global.SetupRedisLink","message":"redis连接失败dial tcp 116.204.6.184:6379: i/o timeout"}
-{"level":"warn","time":"2024-04-17T21:40:56.616+0800","lineNum":"controller/file.go:112","func":"file_upload/app/controller.TemplateItem","message":"dial tcp 116.204.6.184:6379: i/o timeout获取模板失败"}
-{"level":"error","time":"2024-04-18T09:54:19.371+0800","lineNum":"controller/file.go:191","func":"file_upload/app/controller.SearchTemplate","message":"查询失败","error":"ERR wrong number of arguments for 'sinter' command"}
-{"level":"warn","time":"2024-04-18T14:12:14.471+0800","lineNum":"global/mongo.go:17","func":"file_upload/global.SetupMongo","message":"error parsing uri: scheme must be \"mongodb\" or \"mongodb+srv\"mongo 出现异常"}
-{"level":"warn","time":"2024-04-18T14:13:59.288+0800","lineNum":"global/mongo.go:22","func":"file_upload/global.SetupMongo","message":"server selection error: server selection timeout, current topology: { Type: Unknown, Servers: [{ Addr: 116.204.6.184:27017, Type: Unknown, Last error: dial tcp 116.204.6.184:27017: i/o timeout }, ] }mongo 连接失败"}
-{"level":"warn","time":"2024-04-18T14:17:04.891+0800","lineNum":"global/mongo.go:22","func":"file_upload/global.SetupMongo","message":"server selection error: server selection timeout, current topology: { Type: Unknown, Servers: [{ Addr: 116.204.6.184:27017, Type: Unknown, Last error: dial tcp 116.204.6.184:27017: i/o timeout }, ] }mongo 连接失败"}
-{"level":"warn","time":"2024-04-18T14:20:52.509+0800","lineNum":"global/mongo.go:22","func":"file_upload/global.SetupMongo","message":"server selection error: server selection timeout, current topology: { Type: Unknown, Servers: [{ Addr: 116.204.6.184:27017, Type: Unknown, Last error: dial tcp 116.204.6.184:27017: i/o timeout }, ] }mongo 连接失败"}
-{"level":"warn","time":"2024-04-18T14:31:54.505+0800","lineNum":"global/mongo.go:22","func":"file_upload/global.SetupMongo","message":"server selection error: server selection timeout, current topology: { Type: Unknown, Servers: [{ Addr: 116.204.6.184:27017, Type: Unknown, Last error: dial tcp 116.204.6.184:27017: i/o timeout }, ] }mongo 连接失败"}
-{"level":"warn","time":"2024-04-18T14:33:00.632+0800","lineNum":"global/mongo.go:22","func":"file_upload/global.SetupMongo","message":"server selection error: server selection timeout, current topology: { Type: Unknown, Servers: [{ Addr: 116.204.6.184:27017, Type: Unknown, Last error: dial tcp 116.204.6.184:27017: i/o timeout }, ] }mongo 连接失败"}
-{"level":"info","time":"2024-04-18T15:42:32.925+0800","lineNum":"controller/file.go:223","func":"file_upload/app/controller.SearchTemplate","message":"查询失败"}
-{"level":"info","time":"2024-04-18T15:47:22.746+0800","lineNum":"controller/file.go:226","func":"file_upload/app/controller.SearchTemplate","message":"查询失败"}
-{"level":"warn","time":"2024-04-18T16:21:27.323+0800","lineNum":"controller/file.go:147","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-18T16:27:58.475+0800","lineNum":"controller/file.go:147","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-18T16:28:43.954+0800","lineNum":"controller/file.go:147","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-18T16:30:16.483+0800","lineNum":"controller/file.go:184","func":"file_upload/app/controller.GetTemplate","message":"mongo: no documents in result获取文件失败"}
-{"level":"warn","time":"2024-04-18T16:33:17.251+0800","lineNum":"controller/file.go:147","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-18T16:34:05.614+0800","lineNum":"controller/file.go:147","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-18T16:35:01.965+0800","lineNum":"controller/file.go:147","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-18T16:35:27.373+0800","lineNum":"controller/file.go:147","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-18T16:42:42.296+0800","lineNum":"controller/file.go:147","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}
-{"level":"warn","time":"2024-04-18T16:42:44.482+0800","lineNum":"controller/file.go:147","func":"file_upload/app/controller.TemplateItem","message":"\"Syntax error at index 3: invalid char\\n\\n\\t\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQ\\n\\t...^............................\\n\"序列化失败"}

Fișier diff suprimat deoarece este prea mare
+ 0 - 52
upload/cec.json


Fișier diff suprimat deoarece este prea mare
+ 0 - 52
upload/sda.json


Fișier diff suprimat deoarece este prea mare
+ 0 - 52
upload/sdasadas.json


Fișier diff suprimat deoarece este prea mare
+ 0 - 52
upload/未命名sdsa.json


Fișier diff suprimat deoarece este prea mare
+ 0 - 52
upload/皮卡丘.json


Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff