From d4a1b0ec572eb1f6dc1ff044dc0c6585755ec7ac Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Sun, 19 Jan 2025 20:03:18 +0800 Subject: [PATCH 01/36] =?UTF-8?q?Update:=20=EF=BC=88=E6=AD=A5=E9=AA=A4?= =?UTF-8?q?=E5=A4=87=E4=BB=BD=EF=BC=89=E6=9B=B4=E6=96=B0=20Pear=20Admin=20?= =?UTF-8?q?=E6=A1=86=E6=9E=B6=E7=89=88=E6=9C=AC=E4=B8=8E=20Pear=20Admin=20?= =?UTF-8?q?Layui=20=E4=B8=80=E8=87=B4=EF=BC=8C=E5=B0=9D=E8=AF=95=E9=87=8D?= =?UTF-8?q?=E5=86=99=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/view/system/passport.py | 5 +- applications/view/system/rights.py | 11 +- applications/view/system/user.py | 11 +- static/system/admin/css/admin.css | 320 +- static/system/admin/css/admin.dark.css | 359 + static/system/admin/css/layout.css | 1041 + static/system/admin/css/loader.css | 105 - .../css/other/{console1.css => analysis.css} | 102 +- .../css/other/{console2.css => console.css} | 102 +- static/system/admin/css/other/department.css | 6 - static/system/admin/css/other/error.css | 76 - static/system/admin/css/other/exception.css | 28 + static/system/admin/css/other/icon.css | 531 - static/system/admin/css/other/login.css | 258 +- static/system/admin/css/other/login_old.css | 100 + static/system/admin/css/other/person.css | 80 - static/system/admin/css/other/profile.css | 77 + static/system/admin/css/other/result.css | 21 +- static/system/admin/css/other/user.css | 2 +- static/system/admin/css/reset.css | 138 + static/system/admin/css/variables.css | 9 + static/system/component/layui/css/layui.css | 2 +- static/system/component/layui/layui.js | 2 +- .../component/pear/css/module/global.css | 977 + .../component/pear/css/module/layout.css | 2 - .../system/component/pear/css/module/menu.css | 72 +- .../component/pear/css/module/menuSearch.css | 90 + .../pear/css/module/messageCenter.css | 39 + .../component/pear/css/module/nprogress.css | 8 +- .../system/component/pear/css/module/page.css | 154 + .../component/pear/css/module/tabPage.css | 314 + static/system/component/pear/css/pear.css | 35 +- static/system/component/pear/module/admin.js | 925 +- static/system/component/pear/module/button.js | 58 +- .../component/pear/module/extends/count.js | 37 + .../component/pear/module/extends/echarts.js | 95172 ++++++++++++++++ .../pear/module/extends/echartsTheme.js | 450 + .../pear/module/extends/nprogress.js | 503 + .../component/pear/module/extends/popup.js | 47 + .../component/pear/module/extends/toast.js | 1225 + .../component/pear/module/extends/yaml.js | 2057 + .../component/pear/module/fullscreen.js | 54 +- static/system/component/pear/module/menu.js | 124 +- .../component/pear/module/menuSearch.js | 233 + .../component/pear/module/messageCenter.js | 85 + static/system/component/pear/module/page.js | 119 + .../system/component/pear/module/tabPage.js | 656 + static/system/component/pear/module/tools.js | 40 + static/system/component/pear/pear.js | 60 +- templates/system/analysis/main.html | 394 + templates/system/common/footer.html | 9 +- templates/system/common/header.html | 10 +- templates/system/console/console.html | 413 - templates/system/index.html | 56 +- templates/system/login.html | 106 - templates/system/login_rename.html | 106 + templates/system/user/add.html | 35 +- templates/system/user/center.html | 5 +- templates/system/user/edit.html | 15 +- templates/system/user/edit_password.html | 10 +- templates/system/user/main.html | 16 +- 61 files changed, 105593 insertions(+), 2504 deletions(-) create mode 100644 static/system/admin/css/admin.dark.css create mode 100644 static/system/admin/css/layout.css delete mode 100644 static/system/admin/css/loader.css rename static/system/admin/css/other/{console1.css => analysis.css} (36%) rename static/system/admin/css/other/{console2.css => console.css} (44%) delete mode 100644 static/system/admin/css/other/department.css delete mode 100644 static/system/admin/css/other/error.css create mode 100644 static/system/admin/css/other/exception.css delete mode 100644 static/system/admin/css/other/icon.css create mode 100644 static/system/admin/css/other/login_old.css delete mode 100644 static/system/admin/css/other/person.css create mode 100644 static/system/admin/css/other/profile.css create mode 100644 static/system/admin/css/reset.css create mode 100644 static/system/admin/css/variables.css create mode 100644 static/system/component/pear/css/module/global.css create mode 100644 static/system/component/pear/css/module/menuSearch.css create mode 100644 static/system/component/pear/css/module/messageCenter.css create mode 100644 static/system/component/pear/css/module/page.css create mode 100644 static/system/component/pear/css/module/tabPage.css create mode 100644 static/system/component/pear/module/extends/count.js create mode 100644 static/system/component/pear/module/extends/echarts.js create mode 100644 static/system/component/pear/module/extends/echartsTheme.js create mode 100644 static/system/component/pear/module/extends/nprogress.js create mode 100644 static/system/component/pear/module/extends/popup.js create mode 100644 static/system/component/pear/module/extends/toast.js create mode 100644 static/system/component/pear/module/extends/yaml.js create mode 100644 static/system/component/pear/module/menuSearch.js create mode 100644 static/system/component/pear/module/messageCenter.js create mode 100644 static/system/component/pear/module/page.js create mode 100644 static/system/component/pear/module/tabPage.js create mode 100644 static/system/component/pear/module/tools.js create mode 100644 templates/system/analysis/main.html delete mode 100644 templates/system/console/console.html create mode 100644 templates/system/login_rename.html diff --git a/applications/view/system/passport.py b/applications/view/system/passport.py index 69e470a..503cc47 100644 --- a/applications/view/system/passport.py +++ b/applications/view/system/passport.py @@ -84,5 +84,8 @@ def login_post(): @login_required def logout(): logout_user() - session.pop('permissions') + + if 'permissions' in session: + session.pop('permissions') + return success_api(msg="注销成功") diff --git a/applications/view/system/rights.py b/applications/view/system/rights.py index dee4d2d..1491298 100644 --- a/applications/view/system/rights.py +++ b/applications/view/system/rights.py @@ -43,6 +43,8 @@ def configs(): "keepState": True, # 是否开启 Tab 记忆 "session": True, + # 预加载 + "preload": False, # 最大可打开的选项卡数量 "max": 30, "index": { @@ -117,11 +119,13 @@ def menu(): # 当前节点添加子节点 _dict['children'] = copy.deepcopy(menu_dict[_dict['id']]) _dict['children'].sort(key=lambda item: item['sort']) + # 为每个子菜单添加 "openType": "_component" + for child in _dict['children']: + child['openType'] = '_component' # 删除子节点 del menu_dict[_dict['id']] if _dict['parent_id'] not in menu_dict: - menu_dict[_dict['parent_id']] = [_dict] else: menu_dict[_dict['parent_id']].append(_dict) @@ -138,6 +142,9 @@ def menu(): # 当前节点添加子节点 _dict['children'] = copy.deepcopy(menu_dict[_dict['id']]) _dict['children'].sort(key=lambda item: item['sort']) + # 为每个子菜单添加 "openType": "_component" + for child in _dict['children']: + child['openType'] = '_component' # 删除子节点 del menu_dict[_dict['id']] @@ -151,4 +158,4 @@ def menu(): @bp.get('/welcome') @login_required def welcome(): - return render_template('system/console/console.html') + return render_template('system/analysis/main.html') diff --git a/applications/view/system/user.py b/applications/view/system/user.py index e0f9345..ee96771 100644 --- a/applications/view/system/user.py +++ b/applications/view/system/user.py @@ -57,9 +57,7 @@ def data(): } for user, dept in query.items], count=query.total) - # 用户增加 - - +# 用户增加 @bp.get('/add') @authorize("system:user:add", log=True) def add(): @@ -75,6 +73,7 @@ def save(): username = str_escape(req_json.get('username')) real_name = str_escape(req_json.get('realName')) password = str_escape(req_json.get('password')) + dept_id = str_escape(req_json.get('deptId')) role_ids = a.split(',') if not username or not real_name or not password: @@ -82,12 +81,14 @@ def save(): if bool(User.query.filter_by(username=username).count()): return fail_api(msg="用户已经存在") - user = User(username=username, realname=real_name,enable=1) + + user = User(username=username, realname=real_name, enable=1, dept_id=dept_id) user.set_password(password) db.session.add(user) roles = Role.query.filter(Role.id.in_(role_ids)).all() for r in roles: user.role.append(r) + db.session.commit() return success_api(msg="增加成功") @@ -196,7 +197,7 @@ def edit_password_put(): if res_json.get("newPassword") == '': return fail_api("新密码不得为空") if res_json.get("newPassword") != res_json.get("confirmPassword"): - return fail_api("俩次密码不一样") + return fail_api("两次密码不一样") user = current_user is_right = user.validate_password(res_json.get("oldPassword")) if not is_right: diff --git a/static/system/admin/css/admin.css b/static/system/admin/css/admin.css index 60703fe..a96ce16 100644 --- a/static/system/admin/css/admin.css +++ b/static/system/admin/css/admin.css @@ -4,16 +4,16 @@ body, height: 100%; } -.pear-admin .layui-header, .pear-admin .layui-body, .pear-admin .layui-logo, .pear-admin .layui-side, +.pear-admin .layui-header, .pear-admin .layui-header .layui-layout-left { transition: all .3s; } .pear-admin.banner-layout .layui-side { - top: 60px!important; + top: 60px !important; } .pear-admin.banner-layout .layui-side .layui-logo { @@ -25,38 +25,15 @@ body, } .pear-admin.banner-layout .layui-side .layui-side-scroll { - height: 100%!important; + height: 100% !important; } .pear-admin.banner-layout .layui-side .layui-side-scroll { - height: 100%!important; -} - -.pear-admin .layui-header.dark-theme .layui-layout-control .layui-this *{ - background-color: rgba(0,0,0,.1)!important; + height: 100% !important; } -.pear-admin.banner-layout .layui-header { - z-index: 99999; - width: 100%; - left: 0px; -} - -.pear-admin.banner-layout .layui-header .layui-layout-left { - left: 230px; -} - -.pear-admin.banner-layout .layui-header .layui-logo .title { - top: 2px; -} - -.pear-admin.banner-layout .layui-header .layui-layout-control { - display: inline-block; - left: 370px; -} - -.pear-admin.banner-layout .layui-header.dark-theme { - box-shadow: 2px 0 6px rgb(0 21 41 / 35%); +.pear-admin .layui-header.dark-theme .layui-layout-control .layui-this * { + background-color: rgba(0, 0, 0, .1) !important; } .pear-admin .layui-header .layui-logo { @@ -79,7 +56,6 @@ body, left: 230px; width: calc(100% - 230px); background-color: white; - border-bottom: 1px solid whitesmoke; } .pear-admin .layui-layout-control { @@ -92,12 +68,13 @@ body, } .pear-admin .layui-logo { - width: 230px; - height: 59px; - line-height: 59px; + height: 60px; + line-height: 60px; + border-bottom: 1px solid rgba(0, 0, 0, .12); + box-sizing: border-box; position: relative; background-color: #28333E; - border-bottom: 1px solid rgba(0, 0, 0, .12); + width: 230px; } .pear-admin .layui-logo img { @@ -108,7 +85,7 @@ body, .pear-admin .layui-logo .title { font-size: 21px; font-weight: 550; - color: #5FB878; + color: var(--global-primary-color); position: relative; top: 5px; margin-left: 5px; @@ -143,9 +120,16 @@ body, } .pear-admin .layui-body { - left: 230px; bottom: 0px; padding-bottom: 0px; + background-color: whitesmoke; + height: calc(100% - 60px); + overflow-y: auto; + left: 230px; +} + +.pear-admin .layui-body>div { + height: 100%; } .pear-admin .layui-layout-left { @@ -154,8 +138,8 @@ body, .pear-admin .layui-footer { position: absolute; - display: flex; - justify-content: space-between; + display: flex; + justify-content: space-between; left: 230px; background: #fff; border-top: 1px solid #F2F2F2; @@ -172,6 +156,64 @@ body, display: none; } +/** 通栏布局 */ + +.pear-admin.banner-layout .layui-header { + left: 0px; + z-index: 99999; + width: 100%; +} + +.pear-admin.banner-layout .layui-header.light-theme { + border-bottom: 1px solid whitesmoke; +} + +.pear-admin.banner-layout .layui-header.auto-theme, +.pear-admin.banner-layout .layui-header.dark-theme { + box-shadow: 0 1px 4px rgba(0, 0, 0, .1); +} + +.pear-admin.banner-layout .layui-header .layui-layout-left { + left: 230px; +} + +.pear-admin.banner-layout .layui-header .layui-logo .title { + top: 2px; +} + +.pear-admin.banner-layout .layui-header .layui-layout-control { + display: inline-block; + left: 370px; +} + +/** 头部主题 */ +.pear-admin .auto-theme { + background-color: var(--global-primary-color); + color: white; +} + +.pear-admin .auto-theme .layui-logo { + background-color: var(--global-primary-color); + border: none; +} + +.pear-admin .auto-theme .layui-logo .title { + color: white; +} + +.pear-admin .auto-theme .layui-nav * { + color: white !important; +} + +.pear-admin .auto-theme .layui-nav.pear-nav-control .layui-this * { + color: black !important; +} + +.pear-admin .auto-theme .layui-nav .layui-nav-child a { + color: #5f5f5f !important; + color: rgba(0, 0, 0, .8) !important; +} + /** 收缩布局 */ .pear-mini .layui-side .layui-logo .title { display: none; @@ -206,18 +248,14 @@ body, display: none; } -.pear-mini .bottom-nav li { - width: 100% !important; -} - .pear-mini .layui-side-scroll { height: calc(100% - 60px); } .pear-admin .layui-header .layui-nav .layui-nav-bar { top: 0px !important; + background-color: var(--global-primary-color); height: 2px !important; - background-color: #5FB878; } .pear-admin .layui-header .layui-nav .layui-this:after { @@ -229,18 +267,18 @@ body, } .pear-collapsed-pe { - display: none; - width: 50px; - position: absolute; - z-index: 400000; - bottom: 30px; right: 30px; - background-color: #5FB878 !important; - height: 50px; - line-height: 50px; + bottom: 30px; + z-index: 400000; + position: absolute; + background-color: var(--global-primary-color) !important; + box-shadow: 2px 0 6px rgba(0, 21, 41, .20); text-align: center; - border-radius: 50px; - box-shadow: 2px 0 6px rgba(0, 21, 41, .35); + border-radius: 4px; + line-height: 50px; + display: none; + height: 50px; + width: 50px; } .pear-collapsed-pe a { @@ -278,10 +316,6 @@ body, padding-right: 10px; } - .pear-mini .bottom-nav { - display: none; - } - .pear-mini .layui-side-scroll { height: calc(100% - 62px); } @@ -363,8 +397,8 @@ body, } .layer-anim-right { - -webkit-animation: am-horizontal-roll_show .6s ease-out; - animation: am-horizontal-roll_show .6s ease-out; + -webkit-animation: am-horizontal-roll_show .5s ease-out; + animation: am-horizontal-roll_show .5s ease-out; } @@ -390,8 +424,8 @@ body, color: whitesmoke; } -.dark-theme.layui-header li>a{ - color: whitesmoke!important; +.dark-theme.layui-header li>a { + color: whitesmoke !important; } .dark-theme.layui-header .layui-logo { @@ -445,9 +479,9 @@ body, width: 100%; height: 100%; padding: 4px; - top: -5px; - left: -5px; - border: #5FB878 2px solid; + top: -6px; + left: -6px; + border: var(--global-primary-color) 2px solid; opacity: 1; border-radius: 4px; } @@ -481,77 +515,133 @@ body, } .select-color .select-color-content .select-color-item { - background-color: gray; - width: 30px; - height: 30px; - border-radius: 3px; - float: left; - margin-left: 20px; + width: 24px; + height: 24px; color: white; - font-size: 18px; - text-align: center; + margin-left: 24px; + border-radius: 6px; + background-color: gray; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .15); - line-height: 30px; + text-align: center; + line-height: 24px; + font-size: 12px; + float: left; } .message .layui-tab-title li:not(:last-child) { border-right: 1px solid #eee; } -/* 搜索面板 */ -.menu-search-content .layui-input { - padding-left: 30px; +/** 首屏加载 */ +.loader-wrapper { + position: fixed; + width: 100%; + height: 100%; + background-color: whitesmoke; + z-index: 9999999; } -.menu-search-content { - display: flex; - flex-wrap: wrap; - justify-content: center; +.loader { + width: 50px; + height: 50px; + margin: 30px auto 40px; + margin-top: 20%; + position: relative; + z-index: 999999; + background-color: whitesmoke; } -.menu-search-input-wrapper { - width: 100%; - padding: 15px 15px; +.loader:before { + content: ""; + width: 50px; + height: 7px; + border-radius: 50%; + background: #000; + opacity: 0.1; + position: absolute; + top: 59px; + left: 0; + animation: shadow .5s linear infinite; } -.menu-search-no-data { - display: flex; - justify-content: center; - width: 100%; - height: 122px; - align-items: center; +.loader:after { + content: ""; + width: 50px; + height: 50px; + border-radius: 10px; + background-color: var(--global-primary-color); + position: absolute; + top: 0; + left: 0; + animation: loading .5s linear infinite; } -.menu-search-list { - width: 100%; - padding: 5px 15px; -} +@-webkit-keyframes loading { + 17% { + border-bottom-right-radius: 3px; + } -.menu-search-list li { - position: relative; - display: flex; - justify-content: space-between; - align-items: center; - flex-wrap: nowrap; - height: 50px; - margin-bottom: 8px; - padding: 0px 10px; - color: currentColor; - font-size: 14px; - border-radius: 4px; - box-shadow: 0 1px 3px #d4d9e1; - cursor: pointer; - background-color: #fff; + 25% { + transform: translateY(9px) rotate(22.5deg); + } + + 50% { + transform: translateY(18px) scale(1, 0.9) rotate(45deg); + border-bottom-right-radius: 40px; + } + + 75% { + transform: translateY(9px) rotate(67.5deg); + } + + 100% { + transform: translateY(0) rotate(90deg); + } } -.menu-search-list li:hover { - background-color: #5FB878; - color: white; +@keyframes loading { + 17% { + border-bottom-right-radius: 3px; + } + + 25% { + transform: translateY(9px) rotate(22.5deg); + } + + 50% { + transform: translateY(18px) scale(1, 0.9) rotate(45deg); + border-bottom-right-radius: 40px; + } + + 75% { + transform: translateY(9px) rotate(67.5deg); + } + + 100% { + transform: translateY(0) rotate(90deg); + } } -.menu-search-list li.this { - background-color: #5FB878; - color: white; +@-webkit-keyframes shadow { + + 0%, + 100% { + transform: scale(1, 1); + } + + 50% { + transform: scale(1.2, 1); + } } -/* 搜索面板结束 */ \ No newline at end of file +@keyframes shadow { + + 0%, + 100% { + transform: scale(1, 1); + } + + 50% { + transform: scale(1.2, 1); + } +} \ No newline at end of file diff --git a/static/system/admin/css/admin.dark.css b/static/system/admin/css/admin.dark.css new file mode 100644 index 0000000..cf65966 --- /dev/null +++ b/static/system/admin/css/admin.dark.css @@ -0,0 +1,359 @@ +/** loader */ +.pear-admin-dark .loader-wrapper, +.pear-admin-dark .loader-wrapper .loader { + background-color: #141414; +} + +/** layout */ +.pear-admin-dark .layui-layout { + background-color: #141414; +} + +/** header */ +.pear-admin-dark .layui-header, +.pear-admin-dark .layui-header .layui-logo { + background-color: #141414 !important; + box-shadow: none !important; + border: none !important; +} +.pear-admin-dark .layui-header.auto-theme, +.pear-admin-dark .layui-header.auto-theme .layui-logo { + background-color: var(--global-primary-color) !important; +} + +.pear-admin-dark .layui-header.auto-theme .layui-logo .title { + color: #ffffff !important; +} + +.pear-admin-dark .layui-header { + border: 1px solid rgba(0, 0, 0, .40) !important; +} + +.pear-admin-dark .layui-header .layui-nav * { + color: #ffffff !important; +} + +.pear-admin-dark .layui-header .layui-nav .layui-nav-child { + box-shadow: 0 3px 4px rgba(0, 0, 0, .6) !important; + background-color: #141414; + border-color: #141414; +} + +.pear-admin-dark .layui-header .layui-nav .layui-nav-child dd > a:hover { + background-color: #141414 !important; +} + +.pear-admin-dark .layui-header .pear-nav-control .layui-this a{ + background-color: #0c0c0c !important; +} + +.pear-admin-dark .auto-theme .layui-logo .title{ + color: var(--global-primary-color) !important; +} + +/** side */ +.pear-admin-dark .layui-side { + box-shadow: 0 3px 4px rgba(0, 0, 0, .6) !important; +} + +.pear-admin-dark .layui-logo { + border-color: rgba(0, 0, 0, .30) !important; +} + +.pear-admin-dark .layui-side .layui-logo, +.pear-admin-dark .layui-side .layui-side-scroll, +.pear-admin-dark .layui-side .layui-side-scroll .layui-nav-tree{ + background-color: #141414 !important; +} + +.pear-admin-dark .layui-side .layui-side-scroll .layui-nav-tree .layui-nav-child { + background-color: rgba(0,0,0,.3)!important; +} + +.pear-admin-dark .layui-side .layui-side-scroll .layui-nav .layui-nav-item a, +.pear-admin-dark .layui-side .layui-side-scroll .layui-nav .layui-nav-item a > .layui-nav-more { + color: rgba(255,255,255,.7) !important; +} + +.pear-admin-dark .layui-side .layui-side-scroll .layui-nav .layui-nav-child dd.layui-this a, +.pear-admin-dark .layui-side .layui-side-scroll .layui-nav .layui-nav-itemed > a, +.pear-admin-dark .layui-side .layui-side-scroll .layui-nav .layui-nav-itemed > a > .layui-nav-more, +.pear-admin-dark .layui-side .layui-side-scroll .layui-nav .layui-nav-item > a:hover { + color: #ffffff !important; +} + +/** body */ +.pear-admin-dark .layui-body, +.pear-admin-dark .layui-body .pear-tab-page-loading, +.pear-admin-dark .layui-body .pear-page-loading { + background-color: #0a0a0a !important; +} + +.pear-admin-dark .layui-body .layui-tab .layui-tab-title, +.pear-admin-dark .layui-body .layui-tab .layui-tab-title li, +.pear-admin-dark .layui-body .layui-tab .layui-tab-control li { + background-color: #141414 !important; + border-color:rgba(0, 0, 0, .30) !important; + color: #ffffff; +} + +.pear-admin-dark .layui-body .layui-tab .layui-tab-title li > span:first-child { + background-color: #434343; +} + +.pear-admin-dark .layui-body .layui-tab .layui-nav-child.layui-anim { + border-color: #141414; + background-color: #141414 !important; +} + +.pear-admin-dark .layui-body .layui-tab .layui-nav-child.layui-anim a { + color: #ffffff; +} + +.pear-admin-dark .layui-body .layui-tab .layui-nav-child.layui-anim a:hover { + background-color: #0a0a0a; +} + +.pear-admin-dark .layui-body .layui-tab .layui-tab-close:hover { + border-radius: 50%; + background-color: #0a0a0a !important; +} + +.pear-admin-dark .pear-tab-page-menu ul li { + color: #ffffff !important; +} + +.pear-admin-dark .layui-footer { + background-color: #141414; + border-top: 1px solid #141414; +} + +/** theme */ +.pear-admin-dark .set-text, +.pear-admin-dark .select-color-title, +.pear-admin-dark .color-title { + color: #ffffff; +} + +/** search */ +.pear-admin-dark .menu-search-no-data { + color: #ffffff; +} + +.pear-admin-dark .menu-search-tips * { + color: #ffffff; +} + +.pear-admin-dark .menu-search-tips kbd { + border-color: rgba(0, 0, 0, .30) !important; +} + +.pear-admin-dark .menu-search-list li{ + background-color:#141414; + box-shadow: 0 3px 4px rgba(0, 0, 0, .6) !important; + color: #ffffff; +} + +.pear-admin-dark .menu-search-list li:hover{ + background-color:var(--global-primary-color) !important; +} + + +/** message center */ +.pear-admin-dark .pear-message-center .layui-tab-title, +.pear-admin-dark .pear-message-center .message-item { + border-color: rgba(0, 0, 0, .30) !important; + color: #ffffff; +} + +/** button */ +.pear-admin-dark .layui-btn { + color: #ffffff; + border-color: #4C4D4F; +} + +/** layer */ +.pear-admin-dark .layui-layer { + background-color: #141414; +} + +.pear-admin-dark .layui-layer-msg { + border-color: #141414; +} + +.pear-admin-dark .layui-layer-msg .layui-layer-content { + color: #E5EAF3; +} + +.pear-admin-dark .layui-layer .layui-layer-setwin > span, +.pear-admin-dark .layui-layer .layui-layer-title { + color: #ffffff; +} + +/** card */ +.pear-admin-dark .layui-card { + background-color: #1d1e1f !important; +} + +.pear-admin-dark .layui-card .layui-card-header { + border-bottom-color: #414243; + color: #ffffff; +} + +.pear-admin-dark .layui-card .layui-card-body { + color: #ffffff; +} + +/** input */ +.pear-admin-dark .layui-input { + background-color: transparent; + color: #ffffff; + border-color: rgba(0, 0, 0, .30) !important; +} + +/** switch */ +.pear-admin-dark .layui-form-switch { + border-color: #484849; + background-color: rgba(255,255,255,.08); +} + +/** table */ +.pear-admin-dark .layui-table { + background-color: transparent; +} + +.pear-admin-dark .layui-table tr:hover { + background-color: #141414 !important; +} + +.pear-admin-dark .layui-table td, +.pear-admin-dark .layui-table th, +.pear-admin-dark .layui-table-view, +.pear-admin-dark .layui-table-page, +.pear-admin-dark .layui-table-tool, +.pear-admin-dark .layui-table-header { + border-color: rgba(0, 0, 0, .40) !important; +} + +.pear-admin-dark .layui-table-tool-self > div { + border-color: rgba(0, 0, 0, .40) !important; + color: #ffffff !important; + background-color: transparent; +} + +.pear-admin-dark .layui-laypage select, +.pear-admin-dark .layui-laypage button { + border-color: rgba(0, 0, 0, .40) !important; + color: #ffffff !important; + background-color: transparent; +} + +.pear-admin-dark .layui-laypage a, +.pear-admin-dark .layui-laypage-spr, +.pear-admin-dark .layui-laypage-skip, +.pear-admin-dark .layui-laypage-count { + color: #ffffff; +} + +.pear-admin-dark .layui-laypage-limits option { + background-color: #141414 !important; + color: #ffffff; +} + +/** panel */ +.pear-admin-dark .layui-panel { + background-color: #1d1e1f !important; + border-color: #1d1e1f !important; +} + +/** menu */ +.pear-admin-dark .layui-menu { + background-color: #1d1e1f !important; +} + +.pear-admin-dark .layui-menu .layui-menu-body-title, +.pear-admin-dark .layui-menu .layui-menu-body-title:hover { + color: #ffffff; + background-color: #1d1e1f !important; +} + +/** timeline */ +.pear-admin-dark .layui-timeline-axis { + background-color: rgb(29, 30, 31) !important; +} + +.pear-admin-dark .layui-timeline-item:before { + background-color: #414243 !important; +} + + +/** toast */ +.pear-admin-dark .iziToast { + background-color: #1f1f1f !important; +} + +/** console */ + +.pear-admin-dark .deputy, +.pear-admin-dark .shortcut-menu { + background-color: #141414 !important; +} + +.pear-admin-dark .deputy:hover, +.pear-admin-dark .shortcut-menu:hover { + box-shadow: 0 3px 4px rgba(0, 0, 0, .6) !important; +} + +.pear-admin-dark .message-board li { + border-bottom: 1px solid rgba(0, 0, 0, .40) !important; +} + +/** analysis */ +.pear-admin-dark .top-panel-number { + color: #ffffff !important; + border-color: #414243; +} + + +.pear-admin-dark .dynamic-status dd { + border-color: #414243; +} + +/** success failure */ +.pear-admin-dark .pear-result .content { + background-color: rgba(153, 153, 153, 0.12); + color: #E5EAF3; +} + +.pear-admin-dark .pear-result .title{ + color: #ffffff; +} + +.pear-admin-dark .pear-result .description{ + color: #8D9095; +} + +/** 403 404 500*/ +.pear-admin-dark .pear-exception .title p{ + color: #E5EAF3 !important; +} + +/** scroll */ +.pear-admin-dark *::-webkit-scrollbar-thumb { + background: #141414; + border-radius: 4px; +} + +.pear-admin-dark *::-webkit-scrollbar-thumb:hover { + background: #0a0a0a; +} + +/** profile */ +.pear-admin-dark .user-name, +.pear-admin-dark .user-desc { + color: whitesmoke; +} + +.pear-admin-dark .user-desc { + border-top: 1px solid #141414; +} \ No newline at end of file diff --git a/static/system/admin/css/layout.css b/static/system/admin/css/layout.css new file mode 100644 index 0000000..9c4d082 --- /dev/null +++ b/static/system/admin/css/layout.css @@ -0,0 +1,1041 @@ +.pear-container { + margin: 10px; + background-color: whitesmoke; + width: calc(100vw - 20px); +} + +body::-webkit-scrollbar { + width: 0px; + height: 0px; +} + +body::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +body::-webkit-scrollbar-track { + background: white; + border-radius: 2px; +} + +body::-webkit-scrollbar-thumb { + background: #E6E6E6; + border-radius: 2px; +} + +body::-webkit-scrollbar-thumb:hover { + background: #E6E6E6; +} + +body::-webkit-scrollbar-corner { + background: #f6f6f6; +} + +.mainBox::-webkit-scrollbar { + width: 0px; + height: 0px; +} + +.mainBox::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +.mainBox::-webkit-scrollbar-track { + background: white; + border-radius: 2px; +} + +.mainBox::-webkit-scrollbar-thumb { + background: #E6E6E6; + border-radius: 2px; +} + +.mainBox::-webkit-scrollbar-thumb:hover { + background: #E6E6E6; +} + +.mainBox::-webkit-scrollbar-corner { + background: #f6f6f6; +} + +.mainBox { + width: 100%; + position: absolute; + top: 0px; + left: 0px; + bottom: 50px; + overflow: auto; +} + +.bottom { + width: 100%; + position: absolute; + bottom: 0px; + left: 0px; + height: 50px; + line-height: 50px; + background-color: #F8F8F8; + border-top: 1px solid #eee; +} + +.button-container { + position: absolute; + right: 15px; +} + +.main-container { + margin: 15px; +} + +.main-container .layui-form-item { + margin-bottom: 15px !important; + margin-top: 10px !important; +} + +.pear-row::before, +.pear-row::after { + content: ""; + display: table; + clear: both; +} + +.pear-col { + float: left; + min-height: 1px; +} + +.pear-row * { + box-sizing: border-box +} + +.pear-col-md1 { + width: 4.16%; +} + +.pear-col-md2 { + width: 8.33%; +} + +.pear-col-md3 { + width: 12.5%; +} + +.pear-col-md4 { + width: 16.66%; +} + +.pear-col-md5 { + width: 20.83%; +} + +.pear-col-md6 { + width: 25%; +} + +.pear-col-md7 { + width: 29.16%; +} + +.pear-col-md8 { + width: 33.33%; +} + +.pear-col-md9 { + width: 37.5%; +} + +.pear-col-md10 { + width: 41.66%; +} + +.pear-col-md11 { + width: 45.83%; +} + +.pear-col-md12 { + width: 50%; +} + +.pear-col-md13 { + width: 54.16%; +} + +.pear-col-md14 { + width: 58.33%; +} + +.pear-col-md15 { + width: 62.5%; +} + +.pear-col-md16 { + width: 66.66%; +} + +.pear-col-md17 { + width: 70.83%; +} + +.pear-col-md18 { + width: 75%; +} + +.pear-col-md19 { + width: 79.16%; +} + +.pear-col-md20 { + width: 83.33%; +} + +.pear-col-md21 { + width: 87.5%; +} + +.pear-col-md22 { + width: 91.66%; +} + +.pear-col-md23 { + width: 95.83%; +} + +.pear-col-md24 { + width: 100%; +} + +@media all and (min-width:993px) and (max-width:1199px) { + + .pear-col-md-offset1 { + margin-left: 4.16%; + } + + .pear-col-md-offset2 { + margin-left: 8.33%; + } + + .pear-col-md-offset3 { + margin-left: 12.5%; + } + + .pear-col-md-offset4 { + margin-left: 16.66%; + } + + .pear-col-md-offset5 { + margin-left: 20.83%; + } + + .pear-col-md-offset6 { + margin-left: 25%; + } + + .pear-col-md-offset7 { + margin-left: 29.16%; + } + + .pear-col-md-offset8 { + margin-left: 33.33%; + } + + .pear-col-md-offset9 { + margin-left: 37.5%; + } + + .pear-col-md-offset10 { + margin-left: 41.66%; + } + + .pear-col-md-offset11 { + margin-left: 45.83%; + } + + .pear-col-md-offset12 { + margin-left: 50%; + } + + .pear-col-md-offset13 { + margin-left: 54.16%; + } + + .pear-col-md-offset14 { + margin-left: 58.33%; + } + + .pear-col-md-offset15 { + margin-left: 62.5%; + } + + .pear-col-md-offset16 { + margin-left: 66.66%; + } + + .pear-col-md-offset17 { + margin-left: 70.83%; + } + + .pear-col-md-offset18 { + margin-left: 75%; + } + + .pear-col-md-offset19 { + margin-left: 79.16%; + } + + .pear-col-md-offset20 { + margin-left: 83.33%; + } + + .pear-col-md-offset21 { + margin-left: 87.5%; + } + + .pear-col-md-offset22 { + margin-left: 91.66%; + } + + .pear-col-md-offset23 { + margin-left: 95.83%; + } + + .pear-col-md-offset24 { + margin-left: 100%; + } +} + + +@media all and (max-width:768px) { + .pear-col-xs1 { + width: 4.16%; + } + + .pear-col-xs2 { + width: 8.33%; + } + + .pear-col-xs3 { + width: 12.5%; + } + + .pear-col-xs4 { + width: 16.66%; + } + + .pear-col-xs5 { + width: 20.83%; + } + + .pear-col-xs6 { + width: 25%; + } + + .pear-col-xs7 { + width: 29.16%; + } + + .pear-col-xs8 { + width: 33.33%; + } + + .pear-col-xs9 { + width: 37.5%; + } + + .pear-col-xs10 { + width: 41.66%; + } + + .pear-col-xs11 { + width: 45.83%; + } + + .pear-col-xs12 { + width: 50%; + } + + .pear-col-xs13 { + width: 54.16%; + } + + .pear-col-xs14 { + width: 58.33%; + } + + .pear-col-xs15 { + width: 62.5%; + } + + .pear-col-xs16 { + width: 66.66%; + } + + .pear-col-xs17 { + width: 70.83%; + } + + .pear-col-xs18 { + width: 75%; + } + + .pear-col-xs19 { + width: 79.16%; + } + + .pear-col-xs20 { + width: 83.33%; + } + + .pear-col-xs21 { + width: 87.5%; + } + + .pear-col-xs22 { + width: 91.66%; + } + + .pear-col-xs23 { + width: 95.83%; + } + + .pear-col-xs24 { + width: 100%; + } + + .pear-col-xs-offset1 { + margin-left: 4.16%; + } + + .pear-col-xs-offset2 { + margin-left: 8.33%; + } + + .pear-col-xs-offset3 { + margin-left: 12.5%; + } + + .pear-col-xs-offset4 { + margin-left: 16.66%; + } + + .pear-col-xs-offset5 { + margin-left: 20.83%; + } + + .pear-col-xs-offset6 { + margin-left: 25%; + } + + .pear-col-xs-offset7 { + margin-left: 29.16%; + } + + .pear-col-xs-offset8 { + margin-left: 33.33%; + } + + .pear-col-xs-offset9 { + margin-left: 37.5%; + } + + .pear-col-xs-offset10 { + margin-left: 41.66%; + } + + .pear-col-xs-offset11 { + margin-left: 45.83%; + } + + .pear-col-xs-offset12 { + margin-left: 50%; + } + + .pear-col-xs-offset13 { + margin-left: 54.16%; + } + + .pear-col-xs-offset14 { + margin-left: 58.33%; + } + + .pear-col-xs-offset15 { + margin-left: 62.5%; + } + + .pear-col-xs-offset16 { + margin-left: 66.66%; + } + + .pear-col-xs-offset17 { + margin-left: 70.83%; + } + + .pear-col-xs-offset18 { + margin-left: 75%; + } + + .pear-col-xs-offset19 { + margin-left: 79.16%; + } + + .pear-col-xs-offset20 { + margin-left: 83.33%; + } + + .pear-col-xs-offset21 { + margin-left: 87.5%; + } + + .pear-col-xs-offset22 { + margin-left: 91.66%; + } + + .pear-col-xs-offset23 { + margin-left: 95.83%; + } + + .pear-col-xs-offset24 { + margin-left: 100%; + } +} + +@media all and (min-width:768px) and (max-width:992px) { + .pear-col-sm1 { + width: 4.16%; + } + + .pear-col-sm2 { + width: 8.33%; + } + + .pear-col-sm3 { + width: 12.5%; + } + + .pear-col-sm4 { + width: 16.66%; + } + + .pear-col-sm5 { + width: 20.83%; + } + + .pear-col-sm6 { + width: 25%; + } + + .pear-col-sm7 { + width: 29.16%; + } + + .pear-col-sm8 { + width: 33.33%; + } + + .pear-col-sm9 { + width: 37.5%; + } + + .pear-col-sm10 { + width: 41.66%; + } + + .pear-col-sm11 { + width: 45.83%; + } + + .pear-col-sm12 { + width: 50%; + } + + .pear-col-sm13 { + width: 54.16%; + } + + .pear-col-sm14 { + width: 58.33%; + } + + .pear-col-sm15 { + width: 62.5%; + } + + .pear-col-sm16 { + width: 66.66%; + } + + .pear-col-sm17 { + width: 70.83%; + } + + .pear-col-sm18 { + width: 75%; + } + + .pear-col-sm19 { + width: 79.16%; + } + + .pear-col-sm20 { + width: 83.33%; + } + + .pear-col-sm21 { + width: 87.5%; + } + + .pear-col-sm22 { + width: 91.66%; + } + + .pear-col-sm23 { + width: 95.83%; + } + + .pear-col-sm24 { + width: 100%; + } + + .pear-col-sm-offset1 { + margin-left: 4.16%; + } + + .pear-col-sm-offset2 { + margin-left: 8.33%; + } + + .pear-col-sm-offset3 { + margin-left: 12.5%; + } + + .pear-col-sm-offset4 { + margin-left: 16.66%; + } + + .pear-col-sm-offset5 { + margin-left: 20.83%; + } + + .pear-col-sm-offset6 { + margin-left: 25%; + } + + .pear-col-sm-offset7 { + margin-left: 29.16%; + } + + .pear-col-sm-offset8 { + margin-left: 33.33%; + } + + .pear-col-sm-offset9 { + margin-left: 37.5%; + } + + .pear-col-sm-offset10 { + margin-left: 41.66%; + } + + .pear-col-sm-offset11 { + margin-left: 45.83%; + } + + .pear-col-sm-offset12 { + margin-left: 50%; + } + + .pear-col-sm-offset13 { + margin-left: 54.16%; + } + + .pear-col-sm-offset14 { + margin-left: 58.33%; + } + + .pear-col-sm-offset15 { + margin-left: 62.5%; + } + + .pear-col-sm-offset16 { + margin-left: 66.66%; + } + + .pear-col-sm-offset17 { + margin-left: 70.83%; + } + + .pear-col-sm-offset18 { + margin-left: 75%; + } + + .pear-col-sm-offset19 { + margin-left: 79.16%; + } + + .pear-col-sm-offset20 { + margin-left: 83.33%; + } + + .pear-col-sm-offset21 { + margin-left: 87.5%; + } + + .pear-col-sm-offset22 { + margin-left: 91.66%; + } + + .pear-col-sm-offset23 { + margin-left: 95.83%; + } + + .pear-col-sm-offset24 { + margin-left: 100%; + } +} + +@media all and (min-width:1200px) { + .pear-col-lg1 { + width: 4.16%; + } + + .pear-col-lg2 { + width: 8.33%; + } + + .pear-col-lg3 { + width: 12.5%; + } + + .pear-col-lg4 { + width: 16.66%; + } + + .pear-col-lg5 { + width: 20.83%; + } + + .pear-col-lg6 { + width: 25%; + } + + .pear-col-lg7 { + width: 29.16%; + } + + .pear-col-lg8 { + width: 33.33%; + } + + .pear-col-lg9 { + width: 37.5%; + } + + .pear-col-lg10 { + width: 41.66%; + } + + .pear-col-lg11 { + width: 45.83%; + } + + .pear-col-lg12 { + width: 50%; + } + + .pear-col-lg13 { + width: 54.16%; + } + + .pear-col-lg14 { + width: 58.33%; + } + + .pear-col-lg15 { + width: 62.5%; + } + + .pear-col-lg16 { + width: 66.66%; + } + + .pear-col-lg17 { + width: 70.83%; + } + + .pear-col-lg18 { + width: 75%; + } + + .pear-col-lg19 { + width: 79.16%; + } + + .pear-col-lg20 { + width: 83.33%; + } + + .pear-col-lg21 { + width: 87.5%; + } + + .pear-col-lg22 { + width: 91.66%; + } + + .pear-col-lg23 { + width: 95.83%; + } + + .pear-col-lg24 { + width: 100%; + } + + .pear-col-lg-offset1 { + margin-left: 4.16%; + } + + .pear-col-lg-offset2 { + margin-left: 8.33%; + } + + .pear-col-lg-offset3 { + margin-left: 12.5%; + } + + .pear-col-lg-offset4 { + margin-left: 16.66%; + } + + .pear-col-lg-offset5 { + margin-left: 20.83%; + } + + .pear-col-lg-offset6 { + margin-left: 25%; + } + + .pear-col-lg-offset7 { + margin-left: 29.16%; + } + + .pear-col-lg-offset8 { + margin-left: 33.33%; + } + + .pear-col-lg-offset9 { + margin-left: 37.5%; + } + + .pear-col-lg-offset10 { + margin-left: 41.66%; + } + + .pear-col-lg-offset11 { + margin-left: 45.83%; + } + + .pear-col-lg-offset12 { + margin-left: 50%; + } + + .pear-col-lg-offset13 { + margin-left: 54.16%; + } + + .pear-col-lg-offset14 { + margin-left: 58.33%; + } + + .pear-col-lg-offset15 { + margin-left: 62.5%; + } + + .pear-col-lg-offset16 { + margin-left: 66.66%; + } + + .pear-col-lg-offset17 { + margin-left: 70.83%; + } + + .pear-col-lg-offset18 { + margin-left: 75%; + } + + .pear-col-lg-offset19 { + margin-left: 79.16%; + } + + .pear-col-lg-offset20 { + margin-left: 83.33%; + } + + .pear-col-lg-offset21 { + margin-left: 87.5%; + } + + .pear-col-lg-offset22 { + margin-left: 91.66%; + } + + .pear-col-lg-offset23 { + margin-left: 95.83%; + } + + .pear-col-lg-offset24 { + margin-left: 100%; + } +} + +.pear-col-space1 { + margin: -.5px +} + +.pear-col-space1>* { + padding: .5px +} + +.pear-col-space2 { + margin: -1px +} + +.pear-col-space2>* { + padding: 1px +} + +.pear-col-space4 { + margin: -2px +} + +.pear-col-space4>* { + padding: 2px +} + +.pear-col-space5 { + margin: -2.5px +} + +.pear-col-space5>* { + padding: 2.5px +} + +.pear-col-space6 { + margin: -3px +} + +.pear-col-space6>* { + padding: 3px +} + +.pear-col-space8 { + margin: -4px +} + +.pear-col-space8>* { + padding: 4px +} + +.pear-col-space10 { + margin: -5px +} + +.pear-col-space10>* { + padding: 5px +} + +.pear-col-space12 { + margin: -6px +} + +.pear-col-space12>* { + padding: 6px +} + +.pear-col-space14 { + margin: -7px +} + +.pear-col-space14>* { + padding: 7px +} + +.pear-col-space15 { + margin: -7.5px +} + +.pear-col-space15>* { + padding: 7.5px +} + +.pear-col-space16 { + margin: -8px +} + +.pear-col-space16>* { + padding: 8px +} + +.pear-col-space18 { + margin: -9px +} + +.pear-col-space18>* { + padding: 9px +} + +.pear-col-space20 { + margin: -10px +} + +.pear-col-space20>* { + padding: 10px +} + +.pear-col-space22 { + margin: -11px +} + +.pear-col-space22>* { + padding: 11px +} + +.pear-col-space24 { + margin: -12px +} + +.pear-col-space24>* { + padding: 12px +} + +.pear-col-space25 { + margin: -12.5px +} + +.pear-col-space25>* { + padding: 12.5px +} + +.pear-col-space26 { + margin: -13px +} + +.pear-col-space26>* { + padding: 13px +} + +.pear-col-space28 { + margin: -14px +} + +.pear-col-space28>* { + padding: 14px +} + +.pear-col-space30 { + margin: -15px +} + +.pear-col-space30>* { + padding: 15px +} diff --git a/static/system/admin/css/loader.css b/static/system/admin/css/loader.css deleted file mode 100644 index 64ee940..0000000 --- a/static/system/admin/css/loader.css +++ /dev/null @@ -1,105 +0,0 @@ -.loader-main{ - position: fixed; - width: 100%; - height: 100%; - background-color: whitesmoke; - z-index: 9999999; -} -.loader { - width: 50px; - height: 50px; - margin: 30px auto 40px; - margin-top: 20%; - position: relative; - z-index: 999999; - background-color: whitesmoke; -} -.loader:before { - content: ""; - width: 50px; - height: 7px; - border-radius: 50%; - background: #000; - opacity: 0.1; - position: absolute; - top: 59px; - left: 0; - animation: shadow .5s linear infinite; -} -.loader:after { - content: ""; - width: 50px; - height: 50px; - border-radius: 3px; - background-color: #5FB878; - position: absolute; - top: 0; - left: 0; - animation: loading .5s linear infinite; -} -@-webkit-keyframes loading { - 17% { - border-bottom-right-radius: 3px; - } - - 25% { - transform: translateY(9px) rotate(22.5deg); - } - - 50% { - transform: translateY(18px) scale(1, 0.9) rotate(45deg); - border-bottom-right-radius: 40px; - } - - 75% { - transform: translateY(9px) rotate(67.5deg); - } - - 100% { - transform: translateY(0) rotate(90deg); - } -} -@keyframes loading { - 17% { - border-bottom-right-radius: 3px; - } - - 25% { - transform: translateY(9px) rotate(22.5deg); - } - - 50% { - transform: translateY(18px) scale(1, 0.9) rotate(45deg); - border-bottom-right-radius: 40px; - } - - 75% { - transform: translateY(9px) rotate(67.5deg); - } - - 100% { - transform: translateY(0) rotate(90deg); - } -} -@-webkit-keyframes shadow { - - 0%, - 100% { - transform: scale(1, 1); - } - - 50% { - transform: scale(1.2, 1); - } -} -@keyframes shadow { - - 0%, - 100% { - transform: scale(1, 1); - } - - 50% { - transform: scale(1.2, 1); - } -} diff --git a/static/system/admin/css/other/console1.css b/static/system/admin/css/other/analysis.css similarity index 36% rename from static/system/admin/css/other/console1.css rename to static/system/admin/css/other/analysis.css index e175df8..3525a21 100644 --- a/static/system/admin/css/other/console1.css +++ b/static/system/admin/css/other/analysis.css @@ -20,105 +20,35 @@ font-size: 12px; } -.pear-container { - background-color: whitesmoke; - margin: 10px; -} - -.card { - width: 100%; - height: 160px; - background-color: whitesmoke; - border-radius: 4px; -} - -.card .header .avatar { - width: 28px; - height: 28px; - margin: 20px; - border-radius: 50px; -} - -.card .header { - color: dimgray; -} - -.card .body { - color: gray; -} - -.card .body { - margin-left: 20px; - margin-right: 20px; -} - -.card .footer { - margin-left: 20px; - margin-right: 20px; - margin-top: 20px; - font-size: 13px; - color: gray; - position: absolute; -} - -.custom-tab .layui-tab-title { - border-bottom-width: 0px; - border-bottom-style: none; -} - -.custom-tab .layui-tab-title li { - margin-left: 10px; -} - -.list .list-item { - height: 31.8px; - line-height: 31.8px; - color: gray; - padding: 5px; - padding-left: 15px; - border-radius: 4px; - margin-top: 5.2px; -} - -.list .list-item:hover { - background-color: whitesmoke; -} - -.list .list-item .title { - font-size: 13px; - width: 100%; -} - -.list .list-item .footer { - position: absolute; - right: 30px; - font-size: 12px; -} - .top-panel-tips i { font-size: 33px; } -.layuiadmin-card-status { +.top-panel-tips svg { + margin-top: -12px; + width: 50px; + height: 50px; +} + +.dynamic-status { padding: 0 10px 10px; } -.layuiadmin-card-status dd { +.dynamic-status dd { padding: 15px 0; border-bottom: 1px solid #EEE; display: -webkit-flex; display: flex; } -.layuiadmin-card-status dd div.layui-status-img, -.layuiadmin-card-team .layui-team-img { +.dynamic-status dd div.dynamic-status-img { width: 32px; height: 32px; border-radius: 50%; margin-right: 15px; } -.layuiadmin-card-status dd div.layui-status-img a { +.dynamic-status dd div.dynamic-status-img a { width: 100%; height: 100%; display: inline-block; @@ -126,16 +56,10 @@ line-height: 32px; } -.layuiadmin-card-status dd div span { +.dynamic-status dd div span { color: #BBB; } -.layuiadmin-card-status dd div a { +.dynamic-status dd div a { color: #01AAED; -} - -.top-panel-tips svg { - margin-top: -12px; - width: 50px; - height: 50px; -} +} \ No newline at end of file diff --git a/static/system/admin/css/other/console2.css b/static/system/admin/css/other/console.css similarity index 44% rename from static/system/admin/css/other/console2.css rename to static/system/admin/css/other/console.css index e29ad41..af9930b 100644 --- a/static/system/admin/css/other/console2.css +++ b/static/system/admin/css/other/console.css @@ -1,10 +1,6 @@ -.pear-container { - background-color: whitesmoke; - margin: 10px; -} -.pear-card { - width: 100%; +.shortcut-menu { + width: 100%; height: 66px; background-color: #F8F8F8; display: inline-block; @@ -13,109 +9,73 @@ margin-bottom: 3px; } -.pear-card:hover, -.pear-card2:hover { - box-shadow: 2px 0 8px 0 lightgray !important; -} - -.pear-card2 { - width: 100%; - height: 90px; - background-color: #F8F8F8; - display: inline-block; - border-radius: 5px; - text-align: center; - margin-bottom: 3px; -} - -.pear-card2 i { - font-size: 30px; - height: 90px; - line-height: 90px; -} - -.pear-card i { +.shortcut-menu i { font-size: 30px; height: 66px; line-height: 66px; } -.layui-col-md3 { - text-align: center; +.shortcut-menu:hover { + box-shadow: 2px 0 8px 0 lightgray !important; } -.pear-card-title { - margin-top: 3px; +.shortcut-menu-label { + width: 100%; + display: inline-block; + text-align: center; } -.person img { - width: 90px; +.deputy { + width: 100%; height: 90px; - border-radius: 4px; - margin-top: 8px; - margin-left: 8px; + background-color: #F8F8F8; + display: inline-block; + border-radius: 5px; + text-align: center; + margin-bottom: 3px; } -.pear-card2 .count { - color: #51A351; - font-size: 30px; - margin-top: 12px; +.deputy:hover { + box-shadow: 2px 0 8px 0 lightgray !important; } -.pear-card2 .title { +.deputy .deputy-label { color: gray; - font-size: 14px; margin-top: 14px; + font-size: 14px; +} + +.deputy .deputy-count { + margin-top: 12px; + color: var(--global-primary-color); + font-size: 30px; } -.pear-card-status { +.message-board { padding: 0 10px 10px; } -.pear-card-status li { +.message-board li { position: relative; padding: 10px 0; border-bottom: 1px solid #EEE; } -.pear-card-status li h3 { - padding-bottom: 5px; - font-weight: 700; -} - -.pear-card-status li p { +.message-board li p { padding-bottom: 10px; padding-top: 3px; } -.pear-card-status li>span { +.message-board li>span { color: #999; height: 24px; line-height: 24px; } -.pear-reply { +.message-board .message-board-reply { position: absolute; right: 20px; bottom: 12px; height: 24px; line-height: 24px; -} - -.person .title { - font-size: 17px; - font-weight: 600; - margin-left: 18px; - margin-top: 16px; - position: absolute; - display: inline-block; -} - -.person .desc { - font-size: 16px; - font-weight: 600; - margin-left: 115px; - margin-top: -30px; - position: absolute; - display: inline-block; } \ No newline at end of file diff --git a/static/system/admin/css/other/department.css b/static/system/admin/css/other/department.css deleted file mode 100644 index d6898b7..0000000 --- a/static/system/admin/css/other/department.css +++ /dev/null @@ -1,6 +0,0 @@ -.organizationTree { - width: 100% !important; - height: -webkit-calc(100vh - 130px); - height: -moz-calc(100vh - 130px); - height: calc(100vh - 130px); -} diff --git a/static/system/admin/css/other/error.css b/static/system/admin/css/other/error.css deleted file mode 100644 index 37d4c0e..0000000 --- a/static/system/admin/css/other/error.css +++ /dev/null @@ -1,76 +0,0 @@ -* { - padding: 0; - margin: 0; - font-size: 0.38rem; -} - -ul { - list-style: none; -} - -a { - text-decoration: none; - -webkit-tap-highlight-color: transparent -} - -.clearfix:after { - content: ''; - width: 0; - height: 0; - display: block; - clear: both; -} - -html { - height: 100%; - width: 100%; -} - -body { - font-size: 0.28rem; - height: 100%; - width: 100%; - display: flex; - flex-direction: column; - position: relative; - background-color: white !important; -} - -.content { - position: absolute; - top: 50%; - transform: translateY(-50%); - width: 100%; - text-align: center; -} - -.content>img { - height: 300px; - max-width: 370px; - margin-right: 180px; -} - -.content>* { - display: inline-block; -} - -.content-r { - vertical-align: top; -} - -.content-r>h1 { - font-size: 72px; - color: #434e59; - margin-bottom: 24px; - font-weight: 600; -} - -.content-r>p { - font-size: 20px; - color: rgba(0, 0, 0, .45); - margin-bottom: 16px; -} - -button { - margin-top: 20px; -} diff --git a/static/system/admin/css/other/exception.css b/static/system/admin/css/other/exception.css new file mode 100644 index 0000000..e7f2027 --- /dev/null +++ b/static/system/admin/css/other/exception.css @@ -0,0 +1,28 @@ +.pear-exception { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + text-align: center; + box-sizing: border-box; + padding: 70px 40px +} + +.pear-exception .title { + margin-top: 20px; +} + +.pear-exception .title p { + color: rgb(0, 0, 0); + font-size: 20px; +} + +.pear-exception .description { + margin-top: 10px; + color: #8D9095; + font-size: 14px; +} + +.pear-exception .extra { + margin: 30px; +} \ No newline at end of file diff --git a/static/system/admin/css/other/icon.css b/static/system/admin/css/other/icon.css deleted file mode 100644 index cd1a6ce..0000000 --- a/static/system/admin/css/other/icon.css +++ /dev/null @@ -1,531 +0,0 @@ -/* Logo 字体 */ -@font-face { - font-family: "iconfont logo"; - src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); - src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), - url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), - url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), - url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); -} - -.logo { - font-family: "iconfont logo"; - font-size: 160px; - font-style: normal; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -/* tabs */ -.nav-tabs { - position: relative; -} - -.nav-tabs .nav-more { - position: absolute; - right: 0; - bottom: 0; - height: 42px; - line-height: 42px; - color: #666; -} - -#tabs { - border-bottom: 1px solid #eee; -} - -#tabs li { - cursor: pointer; - width: 100px; - height: 40px; - line-height: 40px; - text-align: center; - font-size: 16px; - border-bottom: 2px solid transparent; - position: relative; - z-index: 1; - margin-bottom: -1px; - color: #666; -} - - -#tabs .active { - border-bottom-color: #f00; - color: #222; -} - -.tab-container .content { - display: none; -} - -/* 页面布局 */ -.main { - padding: 30px 100px; - width: 960px; - margin: 0 auto; -} - -.main .logo { - color: #333; - text-align: left; - margin-bottom: 30px; - line-height: 1; - height: 110px; - margin-top: -50px; - overflow: hidden; - *zoom: 1; -} - -.main .logo a { - font-size: 160px; - color: #333; -} - -.helps { - margin-top: 40px; -} - -.helps pre { - padding: 20px; - margin: 10px 0; - border: solid 1px #e7e1cd; - background-color: #fffdef; - overflow: auto; -} - -.icon_lists { - width: 100% !important; - overflow: hidden; - *zoom: 1; -} - -.icon_lists li { - width: 100px; - margin-bottom: 10px; - margin-right: 20px; - text-align: center; - list-style: none !important; - cursor: default; -} - -.icon_lists li .code-name { - line-height: 1.2; -} - -.icon_lists .icon { - display: block; - height: 100px; - line-height: 100px; - font-size: 42px; - margin: 10px auto; - color: #333; - -webkit-transition: font-size 0.25s linear, width 0.25s linear; - -moz-transition: font-size 0.25s linear, width 0.25s linear; - transition: font-size 0.25s linear, width 0.25s linear; -} - -.icon_lists .icon:hover { - font-size: 100px; -} - -.icon_lists .svg-icon { - /* 通过设置 font-size 来改变图标大小 */ - width: 1em; - /* 图标和文字相邻时,垂直对齐 */ - vertical-align: -0.15em; - /* 通过设置 color 来改变 SVG 的颜色/fill */ - fill: currentColor; - /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 - normalize.css 中也包含这行 */ - overflow: hidden; -} - -.icon_lists li .name, -.icon_lists li .code-name { - color: #666; -} - -/* markdown 样式 */ -.markdown { - color: #666; - font-size: 14px; - line-height: 1.8; -} - -.highlight { - line-height: 1.5; -} - -.markdown img { - vertical-align: middle; - max-width: 100%; -} - -.markdown h1 { - color: #404040; - font-weight: 500; - line-height: 40px; - margin-bottom: 24px; -} - -.markdown h2, -.markdown h3, -.markdown h4, -.markdown h5, -.markdown h6 { - color: #404040; - margin: 1.6em 0 0.6em 0; - font-weight: 500; - clear: both; -} - -.markdown h1 { - font-size: 28px; -} - -.markdown h2 { - font-size: 22px; -} - -.markdown h3 { - font-size: 16px; -} - -.markdown h4 { - font-size: 14px; -} - -.markdown h5 { - font-size: 12px; -} - -.markdown h6 { - font-size: 12px; -} - -.markdown hr { - height: 1px; - border: 0; - background: #e9e9e9; - margin: 16px 0; - clear: both; -} - -.markdown p { - margin: 1em 0; -} - -.markdown>p, -.markdown>blockquote, -.markdown>.highlight, -.markdown>ol, -.markdown>ul { - width: 80%; -} - -.markdown ul>li { - list-style: circle; -} - -.markdown>ul li, -.markdown blockquote ul>li { - margin-left: 20px; - padding-left: 4px; -} - -.markdown>ul li p, -.markdown>ol li p { - margin: 0.6em 0; -} - -.markdown ol>li { - list-style: decimal; -} - -.markdown>ol li, -.markdown blockquote ol>li { - margin-left: 20px; - padding-left: 4px; -} - -.markdown code { - margin: 0 3px; - padding: 0 5px; - background: #eee; - border-radius: 3px; -} - -.markdown strong, -.markdown b { - font-weight: 600; -} - -.markdown>table { - border-collapse: collapse; - border-spacing: 0px; - empty-cells: show; - border: 1px solid #e9e9e9; - width: 95%; - margin-bottom: 24px; -} - -.markdown>table th { - white-space: nowrap; - color: #333; - font-weight: 600; -} - -.markdown>table th, -.markdown>table td { - border: 1px solid #e9e9e9; - padding: 8px 16px; - text-align: left; -} - -.markdown>table th { - background: #F7F7F7; -} - -.markdown blockquote { - font-size: 90%; - color: #999; - border-left: 4px solid #e9e9e9; - padding-left: 0.8em; - margin: 1em 0; -} - -.markdown blockquote p { - margin: 0; -} - -.markdown .anchor { - opacity: 0; - transition: opacity 0.3s ease; - margin-left: 8px; -} - -.markdown .waiting { - color: #ccc; -} - -.markdown h1:hover .anchor, -.markdown h2:hover .anchor, -.markdown h3:hover .anchor, -.markdown h4:hover .anchor, -.markdown h5:hover .anchor, -.markdown h6:hover .anchor { - opacity: 1; - display: inline-block; -} - -.markdown>br, -.markdown>p>br { - clear: both; -} - - -.hljs { - display: block; - background: white; - padding: 0.5em; - color: #333333; - overflow-x: auto; -} - -.hljs-comment, -.hljs-meta { - color: #969896; -} - -.hljs-string, -.hljs-variable, -.hljs-template-variable, -.hljs-strong, -.hljs-emphasis, -.hljs-quote { - color: #df5000; -} - -.hljs-keyword, -.hljs-selector-tag, -.hljs-type { - color: #a71d5d; -} - -.hljs-literal, -.hljs-symbol, -.hljs-bullet, -.hljs-attribute { - color: #0086b3; -} - -.hljs-section, -.hljs-name { - color: #63a35c; -} - -.hljs-tag { - color: #333333; -} - -.hljs-title, -.hljs-attr, -.hljs-selector-id, -.hljs-selector-class, -.hljs-selector-attr, -.hljs-selector-pseudo { - color: #795da3; -} - -.hljs-addition { - color: #55a532; - background-color: #eaffea; -} - -.hljs-deletion { - color: #bd2c00; - background-color: #ffecec; -} - -.hljs-link { - text-decoration: underline; -} - -code[class*="language-"], -pre[class*="language-"] { - color: black; - background: none; - text-shadow: 0 1px white; - font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; - text-align: left; - white-space: pre; - word-spacing: normal; - word-break: normal; - word-wrap: normal; - line-height: 1.5; - - -moz-tab-size: 4; - -o-tab-size: 4; - tab-size: 4; - - -webkit-hyphens: none; - -moz-hyphens: none; - -ms-hyphens: none; - hyphens: none; -} - -pre[class*="language-"]::-moz-selection, -pre[class*="language-"] ::-moz-selection, -code[class*="language-"]::-moz-selection, -code[class*="language-"] ::-moz-selection { - text-shadow: none; - background: #b3d4fc; -} - -pre[class*="language-"]::selection, -pre[class*="language-"] ::selection, -code[class*="language-"]::selection, -code[class*="language-"] ::selection { - text-shadow: none; - background: #b3d4fc; -} - -@media print { - - code[class*="language-"], - pre[class*="language-"] { - text-shadow: none; - } -} - -/* Code blocks */ -pre[class*="language-"] { - padding: 1em; - margin: .5em 0; - overflow: auto; -} - -:not(pre)>code[class*="language-"], -pre[class*="language-"] { - background: #f5f2f0; -} - -/* Inline code */ -:not(pre)>code[class*="language-"] { - padding: .1em; - border-radius: .3em; - white-space: normal; -} - -.token.comment, -.token.prolog, -.token.doctype, -.token.cdata { - color: slategray; -} - -.token.punctuation { - color: #999; -} - -.namespace { - opacity: .7; -} - -.token.property, -.token.tag, -.token.boolean, -.token.number, -.token.constant, -.token.symbol, -.token.deleted { - color: #905; -} - -.token.selector, -.token.attr-name, -.token.string, -.token.char, -.token.builtin, -.token.inserted { - color: #690; -} - -.token.operator, -.token.entity, -.token.url, -.language-css .token.string, -.style .token.string { - color: #9a6e3a; - background: hsla(0, 0%, 100%, .5); -} - -.token.atrule, -.token.attr-value, -.token.keyword { - color: #07a; -} - -.token.function, -.token.class-name { - color: #DD4A68; -} - -.token.regex, -.token.important, -.token.variable { - color: #e90; -} - -.token.important, -.token.bold { - font-weight: bold; -} - -.token.italic { - font-style: italic; -} - -.token.entity { - cursor: help; -} diff --git a/static/system/admin/css/other/login.css b/static/system/admin/css/other/login.css index d4b6304..853e092 100644 --- a/static/system/admin/css/other/login.css +++ b/static/system/admin/css/other/login.css @@ -1,100 +1,218 @@ -.layui-form { - width: 320px !important; - margin: auto !important; - margin-top: 160px !important; +html, +body{ + height: 100%; } -.layui-form button { - width: 100% !important; - height: 44px !important; - line-height: 44px !important; - font-size: 16px !important; - background-color: #5FB878 !important; - font-weight: 550 !important; +.login-page { + width: 100%; + height: 100%; + overflow-x: hidden; + overflow-y: auto; + display: flex; + justify-content: center; + align-items: center; } -.layui-form-checked[lay-skin=primary] i { - border-color: #5FB878 !important; - background-color: #5FB878 !important; - color: #fff !important; +.layui-row { + width: 1000px; + height: 600px; + box-shadow: 2px 0 6px rgba(0, 21, 41, .20); + border: 3px solid whitesmoke; + border-radius: 15px; } -.layui-tab-content { - margin-top: 15px !important; - padding-left: 0px !important; - padding-right: 0px !important; +.login-bg { + height: 100%; + box-sizing: border-box; + background-color: rgb(250, 250, 250); + display: flex; + align-items: center; + justify-content: center; + border-bottom-left-radius: 15px; + border-top-left-radius: 15px; } -.layui-form-item { - margin-top: 20px !important; +.login-bg-img { + width: 90%; + display: inline-block; + margin: 0 auto; } -.layui-input { - height: 44px !important; - line-height: 44px !important; - padding-left: 15px !important; - border-radius: 3px !important; +.login-form { + height: 100%; + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + background-color: #fff; + border-bottom-right-radius: 15px; + border-top-right-radius: 15px; } -.layui-input:focus { - box-shadow: 0px 0px 2px 1px #5FB878 !important; +.form-center { + background: #fff; + box-sizing: border-box; + flex-flow: row wrap; + width: 100%; + display: flex; + justify-content: center; + align-items: center; + text-align: center; } -.layui-form-danger:focus{ - box-shadow: 0px 0px 2px 1px #f56c6c !important; +.form-center-box { + width: 360px; } -.logo { - width: 60px !important; - margin-top: 10px !important; - margin-bottom: 10px !important; - margin-left: 20px !important; +.top-log-title { + align-items: center; + justify-content: center; + display: flex; + margin-bottom: 30px; } -.title { - font-size: 30px !important; - font-weight: 550 !important; - margin-left: 20px !important; - color: #5FB878 !important; - display: inline-block !important; - height: 60px !important; - line-height: 60px !important; - margin-top: 10px !important; - position: absolute !important; +.top-log { + width: 50px; + border-radius: 12px; + margin-right: 20px; + height: 50px; } -.desc { - width: 100% !important; - text-align: center !important; - color: gray !important; - height: 60px !important; - line-height: 60px !important; +.top-log-title span { + font-size: 32px; + font-weight: 700; + color: var(--global-primary-color); } -body { - background-repeat:no-repeat; - background-color: whitesmoke; - background-size: 100%; - height: 100%; - } +.top-desc { + font-size: 14px; + color: #808695; + +} + +.tab-log-method { + width: 100%; + display: flex; + padding: 20px 0px; +} + +.tab-log-method-item { + flex: 1; + box-sizing: border-box; + padding: 5px 50px; + text-align: right; + color: #1f2225; + font-size: 16px; +} -.code { - float: left; - margin-right: 13px; - margin: 0px !important; - border: #e6e6e6 1px solid; - display: inline-block!important; +.tab-log-method-item:nth-child(2) { + text-align: left; } -.codeImage { - float: right; - height: 42px; - border: #e6e6e6 1px solid; +.tab-log-method-item>span { + display: inline-block; + width: 40px; + text-align: center; + height: 30px; + border-bottom: 2px solid transparent; +} + +.tab-log-method-item>span:hover { cursor: pointer; + color: #16baaa; + border-bottom: 2px solid #16baaa; } -@media (max-width:768px){ - body{ - background-position:center; +.tab-log-verification { + width: 100%; + display: flex; +} + +.verification-text { + flex: 2; + box-sizing: border-box; + margin-right: 20px; +} + +.verification-img { + flex: 1; + box-sizing: border-box; + border: 1px solid #eeeeee; + border-radius: 4px; + height: 40px; + overflow: hidden; + text-align: center; +} + +.remember-passsword { + margin: 20px 0; + width: 100%; + display: flex; + box-sizing: border-box; +} + +.remember-cehcked { + flex: 1; + text-align: left; +} + +.greenText { + color: #16baaa; + cursor: pointer; +} + + +.login-btn { + width: 100%; + box-sizing: border-box; +} + +.login-btn>.layui-btn { + width: 100%; +} + +.other-login { + width: 100%; + box-sizing: border-box; + margin: 20px 0 0; + text-align: left; + display: flex; +} + +.other-login-methods { + display: inline-block; + flex: 1; +} + +.layui-input { + border-radius: 4px; + line-height: 40px; + height: 40px; +} + +.layui-btn { + border-radius: 4px; + background-color: var(--global-primary-color); +} + +@media(min-width: 992px) and (max-width:1200px){ + .layui-row{ + width: 900px; } } +@media(min-width: 768px) and (max-width:992px){ + .layui-row{ + width: 90%; + } + .form-center{width: 90%;} +} +@media (max-width:768px){ + .layui-row{ + width: 90%; + } + .login-form { + border-bottom-left-radius: 15px; + border-top-left-radius: 15px; + } + .form-center-box{width: 95%;} +} \ No newline at end of file diff --git a/static/system/admin/css/other/login_old.css b/static/system/admin/css/other/login_old.css new file mode 100644 index 0000000..d4b6304 --- /dev/null +++ b/static/system/admin/css/other/login_old.css @@ -0,0 +1,100 @@ +.layui-form { + width: 320px !important; + margin: auto !important; + margin-top: 160px !important; +} + +.layui-form button { + width: 100% !important; + height: 44px !important; + line-height: 44px !important; + font-size: 16px !important; + background-color: #5FB878 !important; + font-weight: 550 !important; +} + +.layui-form-checked[lay-skin=primary] i { + border-color: #5FB878 !important; + background-color: #5FB878 !important; + color: #fff !important; +} + +.layui-tab-content { + margin-top: 15px !important; + padding-left: 0px !important; + padding-right: 0px !important; +} + +.layui-form-item { + margin-top: 20px !important; +} + +.layui-input { + height: 44px !important; + line-height: 44px !important; + padding-left: 15px !important; + border-radius: 3px !important; +} + +.layui-input:focus { + box-shadow: 0px 0px 2px 1px #5FB878 !important; +} + +.layui-form-danger:focus{ + box-shadow: 0px 0px 2px 1px #f56c6c !important; +} + +.logo { + width: 60px !important; + margin-top: 10px !important; + margin-bottom: 10px !important; + margin-left: 20px !important; +} + +.title { + font-size: 30px !important; + font-weight: 550 !important; + margin-left: 20px !important; + color: #5FB878 !important; + display: inline-block !important; + height: 60px !important; + line-height: 60px !important; + margin-top: 10px !important; + position: absolute !important; +} + +.desc { + width: 100% !important; + text-align: center !important; + color: gray !important; + height: 60px !important; + line-height: 60px !important; +} + +body { + background-repeat:no-repeat; + background-color: whitesmoke; + background-size: 100%; + height: 100%; + } + +.code { + float: left; + margin-right: 13px; + margin: 0px !important; + border: #e6e6e6 1px solid; + display: inline-block!important; +} + +.codeImage { + float: right; + height: 42px; + border: #e6e6e6 1px solid; + cursor: pointer; +} + +@media (max-width:768px){ + body{ + background-position:center; + } +} diff --git a/static/system/admin/css/other/person.css b/static/system/admin/css/other/person.css deleted file mode 100644 index 53c787a..0000000 --- a/static/system/admin/css/other/person.css +++ /dev/null @@ -1,80 +0,0 @@ -.pear-container { - background-color: whitesmoke; - margin: 10px; -} -.layui-body { - padding: 25px; -} -.text-center { - text-align: center; -} -.user-info-head { - width: 110px; - height: 110px; - line-height: 110px; - position: relative; - display: inline-block; - border-radius: 50%; - overflow: hidden; - cursor: pointer; - margin: 0 auto; -} -.layui-line-dash { - border-bottom: 1px dashed #ccc; - margin: 15px 0; -} -.comment { - position: absolute; - bottom: 3px; - right: 10px; - font-size: 12px; - color: dimgray; -} -.content { - padding-left: 13px; - font-size: 13px; - color: dimgray; -} -.title { - padding-left: 13.5px; -} -.layui-tab-title { - border-bottom: none; -} -.fl-item { - height: 30px; - font-size: 13.5; -} -.dot { - width: 10px; - height: 10px; - border-radius: 50px; - background-color: gray; - display: inline-block; - margin-right: 10px; -} - -.list .list-item { - height: 32px; - line-height: 32px; - color: gray; - padding: 5px; - padding-left: 15px; - border-radius: 4px; - margin-top: 5.2px; -} - -.list .list-item:hover { - background-color: whitesmoke; -} - -.list .list-item .title { - font-size: 13px; - width: 100%; -} - -.list .list-item .footer { - position: absolute; - right: 30px; - font-size: 12px; -} diff --git a/static/system/admin/css/other/profile.css b/static/system/admin/css/other/profile.css new file mode 100644 index 0000000..4c779ee --- /dev/null +++ b/static/system/admin/css/other/profile.css @@ -0,0 +1,77 @@ +.text-center { + text-align: center; +} + +.user-info { + width: 110px; + height: 110px; + line-height: 110px; + position: relative; + display: inline-block; + border-radius: 50%; + overflow: hidden; + cursor: pointer; + margin: 0 auto; +} + +.user-name { + padding-top: 20px; + font-size: 20px !important; +} + +.user-home { + padding-top: 8px; + margin-top: 10px; + font-size: 13.5px; +} + +.user-desc { + height: 45px; + border-top: 1px whitesmoke solid; + text-align: center; + line-height: 45px; + font-size: 13.5px; +} + +.blog-title { + padding-left: 13.5px; +} + +.blog-content { + padding-left: 13px; + font-size: 13px; + color: dimgray; +} + +.layui-tab-title { + border-bottom: none; +} + +.message-board { + padding: 0 10px 10px; +} + +.message-board li { + position: relative; + padding: 10px 0; + border-bottom: 1px solid #EEE; +} + +.message-board li p { + padding-bottom: 10px; + padding-top: 3px; +} + +.message-board li>span { + color: #999; + height: 24px; + line-height: 24px; +} + +.message-board .message-board-reply { + position: absolute; + right: 20px; + bottom: 12px; + height: 24px; + line-height: 24px; +} \ No newline at end of file diff --git a/static/system/admin/css/other/result.css b/static/system/admin/css/other/result.css index d5ccaa3..393c464 100644 --- a/static/system/admin/css/other/result.css +++ b/static/system/admin/css/other/result.css @@ -1,39 +1,40 @@ -.result { +.pear-result { text-align: center; } -.result .success svg { +.pear-result .success svg { color: #32C682; text-align: center; margin-top: 40px; } -.result .error svg { +.pear-result .error svg { color: #f56c6c; text-align: center; margin-top: 40px; } -.result .title { +.pear-result .title { margin-top: 25px; } -.result .desc { +.pear-result .description { margin-top: 25px; width: 60%; margin-left: 20%; color: rgba(0, 0, 0, .45); } -.result .content { +.pear-result .content { margin-top: 20px; width: 80%; - border-radius: 10px; + border-radius: 4px; background-color: whitesmoke; - height: 200px; + padding: 20px 32px; margin-left: 10%; + margin-bottom: 30px; + text-align: left; } -.result .action { +.pear-result .extra { padding-top: 10px; - border-top: 1px whitesmoke solid; margin-top: 25px; } diff --git a/static/system/admin/css/other/user.css b/static/system/admin/css/other/user.css index 63ec985..c221215 100644 --- a/static/system/admin/css/other/user.css +++ b/static/system/admin/css/other/user.css @@ -32,7 +32,7 @@ box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.15); } .button-primary{ - background-color: #5FB878; + background-color: var(--global-primary-color); color: white; } .button-default{ diff --git a/static/system/admin/css/reset.css b/static/system/admin/css/reset.css new file mode 100644 index 0000000..3ad3def --- /dev/null +++ b/static/system/admin/css/reset.css @@ -0,0 +1,138 @@ +.layui-dropdown { + border-radius: var(--global-border-radius); +} + +.layui-input { + border-radius: var(--global-border-radius); +} + +.layui-form-onswitch { + background-color: var(--global-primary-color) !important; +} + +.layui-form-onswitch { + border-color: var(--global-primary-color); +} + +.layui-form-radio:hover>*, +.layui-form-radioed>i, +.layui-form-radioed { + color: var(--global-primary-color) !important; +} + +.layui-form-checked[lay-skin=primary]>i { + border-color: var(--global-primary-color) !important; + background-color: var(--global-primary-color); + color: #fff; +} + +.layui-form-checkbox[lay-skin=primary]>.layui-icon-indeterminate, +.layui-form-checkbox[lay-skin=primary]>.layui-icon-indeterminate:hover { + border-color: var(--global-primary-color); +} + +.layui-form-checkbox[lay-skin=primary]>.layui-icon-indeterminate:before { + background-color: var(--global-primary-color); +} + +.layui-btn { + background-color: var(--global-primary-color); +} + +.layui-btn.layui-btn-primary:hover { + border: 1px solid var(--global-primary-color); +} + +.layui-btn.layui-btn-normal { + background-color: #1e9fff !important; +} + +.layui-btn.layui-btn-danger { + background-color: #ff5722 !important; +} + +.layui-btn.layui-btn-warm { + background-color: #ffb800 !important; +} + +.layui-btn.layui-btn-primary { + background-color: transparent !important; + color: #5f5f5f !important; +} + +.layui-card { + border-radius: var(--global-border-radius); +} + +.layui-timeline-axis { + color: var(--global-primary-color); +} + +.layui-table-checked { + background-color: #f8f8f8; +} + +.layui-input:focus, .layui-textarea:focus { + border-color: var(--global-primary-color) !important; + box-shadow: 0 0 0 3px rgb(from var(--global-primary-color) r g b / 8%); +} + +.layui-form-select dl dd.layui-this { + color: var(--global-primary-color); +} + +.layui-input-wrap .layui-input:focus+.layui-input-split { + border-color: var(--global-primary-color) +} + +.layui-form-checked:hover>div, .layui-form-checked>div { + background-color: var(--global-primary-color); +} + +.layui-form-checked:hover>i, .layui-form-checked>i { + color: var(--global-primary-color); +} + +.layui-laypage .layui-laypage-curr .layui-laypage-em { + background-color: var(--global-primary-color); +} + +.layui-laypage input:active { + border-color: var(--global-primary-color); +} + +.layui-laypage a:hover { + color: var(--global-primary-color); +} + +.layui-laypage input:focus, .layui-laypage select:focus { + border-color: var(--global-primary-color) !important; +} + +.layui-laydate .layui-this, .layui-laydate .layui-this>div { + background-color: var(--global-primary-color) !important; +} + +.layui-laydate-header i:hover, .layui-laydate-header span:hover { + color: var(--global-primary-color); +} + +.layui-laydate-footer span:hover { + color: var(--global-primary-color); +} + +.layui-tab-brief>.layui-tab-title .layui-this { + color: var(--global-primary-color); +} + +.layui-tab-brief>.layui-tab-more li.layui-this:after, .layui-tab-brief>.layui-tab-title .layui-this:after { + border-bottom: 2px solid var(--global-primary-color); +} + +.layui-progress-bar { + background-color: var(--global-primary-color); +} + +.layui-form-checkbox[lay-skin=primary]:hover>i { + border-color: var(--global-primary-color); +} \ No newline at end of file diff --git a/static/system/admin/css/variables.css b/static/system/admin/css/variables.css new file mode 100644 index 0000000..a0f467e --- /dev/null +++ b/static/system/admin/css/variables.css @@ -0,0 +1,9 @@ +:root { + + /* 主题颜色 */ + --global-primary-color: #16baaa; + + /** 圆角度数 */ + --global-border-radius: 4px; + +} \ No newline at end of file diff --git a/static/system/component/layui/css/layui.css b/static/system/component/layui/css/layui.css index 20e518c..4c1106a 100644 --- a/static/system/component/layui/css/layui.css +++ b/static/system/component/layui/css/layui.css @@ -1 +1 @@ -blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,li,ol,p,pre,td,textarea,th,ul{margin:0;padding:0;-webkit-tap-highlight-color:rgba(0,0,0,0)}a:active,a:hover{outline:0}img{display:inline-block;border:none;vertical-align:middle}li{list-style:none}table{border-collapse:collapse;border-spacing:0}h1,h2,h3,h4{font-weight:700}h5,h6{font-weight:500;font-size:100%}button,input,select,textarea{font-size:100%}button,input,optgroup,option,select,textarea{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;outline:0}pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}body{line-height:1.6;color:#333;color:rgba(0,0,0,.85);font:14px Helvetica Neue,Helvetica,PingFang SC,Tahoma,Arial,sans-serif}hr{height:0;line-height:0;margin:10px 0;padding:0;border:none!important;border-bottom:1px solid #eee!important;clear:both;overflow:hidden;background:0 0}a{color:#333;text-decoration:none}a:hover{color:#777}a cite{font-style:normal;*cursor:pointer}.layui-border-box,.layui-border-box *{box-sizing:border-box}.layui-box,.layui-box *{box-sizing:content-box}.layui-clear{clear:both;*zoom:1}.layui-clear:after{content:'\20';clear:both;*zoom:1;display:block;height:0}.layui-clear-space{word-spacing:-5px}.layui-inline{position:relative;display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.layui-edge{position:relative;display:inline-block;vertical-align:middle;width:0;height:0;border-width:6px;border-style:dashed;border-color:transparent;overflow:hidden}.layui-edge-top{top:-4px;border-bottom-color:#999;border-bottom-style:solid}.layui-edge-right{border-left-color:#999;border-left-style:solid}.layui-edge-bottom{top:2px;border-top-color:#999;border-top-style:solid}.layui-edge-left{border-right-color:#999;border-right-style:solid}.layui-elip{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-disabled,.layui-icon,.layui-unselect{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-disabled,.layui-disabled:hover{color:#d2d2d2!important;cursor:not-allowed!important}.layui-circle{border-radius:100%}.layui-show{display:block!important}.layui-hide{display:none!important}.layui-show-v{visibility:visible!important}.layui-hide-v{visibility:hidden!important}@font-face{font-family:layui-icon;src:url(../font/iconfont.eot?v=282);src:url(../font/iconfont.eot?v=282#iefix) format('embedded-opentype'),url(../font/iconfont.woff2?v=282) format('woff2'),url(../font/iconfont.woff?v=282) format('woff'),url(../font/iconfont.ttf?v=282) format('truetype'),url(../font/iconfont.svg?v=282#layui-icon) format('svg')}.layui-icon{font-family:layui-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-icon-leaf:before{content:"\e701"}.layui-icon-folder:before{content:"\eabe"}.layui-icon-folder-open:before{content:"\eac1"}.layui-icon-gitee:before{content:"\e69b"}.layui-icon-github:before{content:"\e6a7"}.layui-icon-disabled:before{content:"\e6cc"}.layui-icon-moon:before{content:"\e6c2"}.layui-icon-error:before{content:"\e693"}.layui-icon-success:before{content:"\e697"}.layui-icon-question:before{content:"\e699"}.layui-icon-lock:before{content:"\e69a"}.layui-icon-eye:before{content:"\e695"}.layui-icon-eye-invisible:before{content:"\e696"}.layui-icon-backspace:before{content:"\e694"}.layui-icon-tips-fill:before{content:"\eb2e"}.layui-icon-test:before{content:"\e692"}.layui-icon-clear:before{content:"\e788"}.layui-icon-heart-fill:before{content:"\e68f"}.layui-icon-light:before{content:"\e748"}.layui-icon-music:before{content:"\e690"}.layui-icon-time:before{content:"\e68d"}.layui-icon-ie:before{content:"\e7bb"}.layui-icon-firefox:before{content:"\e686"}.layui-icon-at:before{content:"\e687"}.layui-icon-bluetooth:before{content:"\e689"}.layui-icon-chrome:before{content:"\e68a"}.layui-icon-edge:before{content:"\e68b"}.layui-icon-heart:before{content:"\e68c"}.layui-icon-key:before{content:"\e683"}.layui-icon-android:before{content:"\e684"}.layui-icon-mike:before{content:"\e6dc"}.layui-icon-mute:before{content:"\e685"}.layui-icon-gift:before{content:"\e627"}.layui-icon-windows:before{content:"\e67f"}.layui-icon-ios:before{content:"\e680"}.layui-icon-logout:before{content:"\e682"}.layui-icon-wifi:before{content:"\e7e0"}.layui-icon-rss:before{content:"\e808"}.layui-icon-email:before{content:"\e618"}.layui-icon-reduce-circle:before{content:"\e616"}.layui-icon-transfer:before{content:"\e691"}.layui-icon-service:before{content:"\e626"}.layui-icon-addition:before{content:"\e624"}.layui-icon-subtraction:before{content:"\e67e"}.layui-icon-slider:before{content:"\e714"}.layui-icon-print:before{content:"\e66d"}.layui-icon-export:before{content:"\e67d"}.layui-icon-cols:before{content:"\e610"}.layui-icon-screen-full:before{content:"\e622"}.layui-icon-screen-restore:before{content:"\e758"}.layui-icon-rate-half:before{content:"\e6c9"}.layui-icon-rate-solid:before{content:"\e67a"}.layui-icon-rate:before{content:"\e67b"}.layui-icon-cellphone:before{content:"\e678"}.layui-icon-vercode:before{content:"\e679"}.layui-icon-login-weibo:before{content:"\e675"}.layui-icon-login-qq:before{content:"\e676"}.layui-icon-login-wechat:before{content:"\e677"}.layui-icon-username:before{content:"\e66f"}.layui-icon-password:before{content:"\e673"}.layui-icon-refresh-3:before{content:"\e9aa"}.layui-icon-auz:before{content:"\e672"}.layui-icon-shrink-right:before{content:"\e668"}.layui-icon-spread-left:before{content:"\e66b"}.layui-icon-snowflake:before{content:"\e6b1"}.layui-icon-tips:before{content:"\e702"}.layui-icon-note:before{content:"\e66e"}.layui-icon-senior:before{content:"\e674"}.layui-icon-refresh-1:before{content:"\e666"}.layui-icon-refresh:before{content:"\e669"}.layui-icon-flag:before{content:"\e66c"}.layui-icon-theme:before{content:"\e66a"}.layui-icon-notice:before{content:"\e667"}.layui-icon-console:before{content:"\e665"}.layui-icon-website:before{content:"\e7ae"}.layui-icon-face-surprised:before{content:"\e664"}.layui-icon-set:before{content:"\e716"}.layui-icon-template:before{content:"\e663"}.layui-icon-app:before{content:"\e653"}.layui-icon-template-1:before{content:"\e656"}.layui-icon-home:before{content:"\e68e"}.layui-icon-female:before{content:"\e661"}.layui-icon-male:before{content:"\e662"}.layui-icon-tread:before{content:"\e6c5"}.layui-icon-praise:before{content:"\e6c6"}.layui-icon-rmb:before{content:"\e65e"}.layui-icon-more:before{content:"\e65f"}.layui-icon-camera:before{content:"\e660"}.layui-icon-cart-simple:before{content:"\e698"}.layui-icon-face-cry:before{content:"\e69c"}.layui-icon-face-smile:before{content:"\e6af"}.layui-icon-survey:before{content:"\e6b2"}.layui-icon-read:before{content:"\e705"}.layui-icon-location:before{content:"\e715"}.layui-icon-dollar:before{content:"\e659"}.layui-icon-diamond:before{content:"\e735"}.layui-icon-return:before{content:"\e65c"}.layui-icon-camera-fill:before{content:"\e65d"}.layui-icon-fire:before{content:"\e756"}.layui-icon-more-vertical:before{content:"\e671"}.layui-icon-cart:before{content:"\e657"}.layui-icon-star-fill:before{content:"\e658"}.layui-icon-prev:before{content:"\e65a"}.layui-icon-next:before{content:"\e65b"}.layui-icon-upload:before{content:"\e67c"}.layui-icon-upload-drag:before{content:"\e681"}.layui-icon-user:before{content:"\e770"}.layui-icon-file-b:before{content:"\e655"}.layui-icon-component:before{content:"\e857"}.layui-icon-find-fill:before{content:"\e670"}.layui-icon-loading:before{content:"\e63d"}.layui-icon-loading-1:before{content:"\e63e"}.layui-icon-add-1:before{content:"\e654"}.layui-icon-pause:before{content:"\e651"}.layui-icon-play:before{content:"\e652"}.layui-icon-video:before{content:"\e6ed"}.layui-icon-headset:before{content:"\e6fc"}.layui-icon-voice:before{content:"\e688"}.layui-icon-speaker:before{content:"\e645"}.layui-icon-fonts-del:before{content:"\e64f"}.layui-icon-fonts-html:before{content:"\e64b"}.layui-icon-fonts-code:before{content:"\e64e"}.layui-icon-fonts-strong:before{content:"\e62b"}.layui-icon-unlink:before{content:"\e64d"}.layui-icon-picture:before{content:"\e64a"}.layui-icon-link:before{content:"\e64c"}.layui-icon-face-smile-b:before{content:"\e650"}.layui-icon-align-center:before{content:"\e647"}.layui-icon-align-right:before{content:"\e648"}.layui-icon-align-left:before{content:"\e649"}.layui-icon-fonts-u:before{content:"\e646"}.layui-icon-fonts-i:before{content:"\e644"}.layui-icon-tabs:before{content:"\e62a"}.layui-icon-circle:before{content:"\e63f"}.layui-icon-radio:before{content:"\e643"}.layui-icon-share:before{content:"\e641"}.layui-icon-edit:before{content:"\e642"}.layui-icon-delete:before{content:"\e640"}.layui-icon-engine:before{content:"\e628"}.layui-icon-chart-screen:before{content:"\e629"}.layui-icon-chart:before{content:"\e62c"}.layui-icon-table:before{content:"\e62d"}.layui-icon-tree:before{content:"\e62e"}.layui-icon-upload-circle:before{content:"\e62f"}.layui-icon-templeate-1:before{content:"\e630"}.layui-icon-util:before{content:"\e631"}.layui-icon-layouts:before{content:"\e632"}.layui-icon-prev-circle:before{content:"\e633"}.layui-icon-carousel:before{content:"\e634"}.layui-icon-code-circle:before{content:"\e635"}.layui-icon-water:before{content:"\e636"}.layui-icon-date:before{content:"\e637"}.layui-icon-layer:before{content:"\e638"}.layui-icon-fonts-clear:before{content:"\e639"}.layui-icon-dialogue:before{content:"\e63a"}.layui-icon-cellphone-fine:before{content:"\e63b"}.layui-icon-form:before{content:"\e63c"}.layui-icon-file:before{content:"\e621"}.layui-icon-triangle-r:before{content:"\e623"}.layui-icon-triangle-d:before{content:"\e625"}.layui-icon-set-sm:before{content:"\e620"}.layui-icon-add-circle:before{content:"\e61f"}.layui-icon-layim-download:before{content:"\e61e"}.layui-icon-layim-uploadfile:before{content:"\e61d"}.layui-icon-404:before{content:"\e61c"}.layui-icon-about:before{content:"\e60b"}.layui-icon-layim-theme:before{content:"\e61b"}.layui-icon-down:before{content:"\e61a"}.layui-icon-up:before{content:"\e619"}.layui-icon-circle-dot:before{content:"\e617"}.layui-icon-set-fill:before{content:"\e614"}.layui-icon-search:before{content:"\e615"}.layui-icon-friends:before{content:"\e612"}.layui-icon-group:before{content:"\e613"}.layui-icon-reply-fill:before{content:"\e611"}.layui-icon-menu-fill:before{content:"\e60f"}.layui-icon-face-smile-fine:before{content:"\e60c"}.layui-icon-picture-fine:before{content:"\e60d"}.layui-icon-log:before{content:"\e60e"}.layui-icon-list:before{content:"\e60a"}.layui-icon-release:before{content:"\e609"}.layui-icon-add-circle-fine:before{content:"\e608"}.layui-icon-ok:before{content:"\e605"}.layui-icon-help:before{content:"\e607"}.layui-icon-chat:before{content:"\e606"}.layui-icon-top:before{content:"\e604"}.layui-icon-right:before{content:"\e602"}.layui-icon-left:before{content:"\e603"}.layui-icon-star:before{content:"\e600"}.layui-icon-download-circle:before{content:"\e601"}.layui-icon-close:before{content:"\1006"}.layui-icon-close-fill:before{content:"\1007"}.layui-icon-ok-circle:before{content:"\1005"}.layui-main{position:relative;width:1160px;margin:0 auto}.layui-header{position:relative;z-index:1000;height:60px}.layui-header a:hover{transition:all .5s;-webkit-transition:all .5s}.layui-side{position:fixed;left:0;top:0;bottom:0;z-index:999;width:200px;overflow-x:hidden}.layui-side-scroll{position:relative;width:220px;height:100%;overflow-x:hidden}.layui-body{position:relative;left:200px;right:0;top:0;bottom:0;z-index:900;width:auto;box-sizing:border-box}.layui-layout-body{overflow-x:hidden}.layui-layout-admin .layui-header{position:fixed;top:0;left:0;right:0;background-color:#23292e}.layui-layout-admin .layui-side{top:60px;width:200px;overflow-x:hidden}.layui-layout-admin .layui-body{position:absolute;top:60px;padding-bottom:44px}.layui-layout-admin .layui-main{width:auto;margin:0 15px}.layui-layout-admin .layui-footer{position:fixed;left:200px;right:0;bottom:0;z-index:990;height:44px;line-height:44px;padding:0 15px;box-shadow:-1px 0 4px rgb(0 0 0 / 12%);background-color:#fafafa}.layui-layout-admin .layui-logo{position:absolute;left:0;top:0;width:200px;height:100%;line-height:60px;text-align:center;color:#16baaa;font-size:16px;box-shadow:0 1px 2px 0 rgb(0 0 0 / 15%)}.layui-layout-admin .layui-header .layui-nav{background:0 0}.layui-layout-left{position:absolute!important;left:200px;top:0}.layui-layout-right{position:absolute!important;right:0;top:0}.layui-container{position:relative;margin:0 auto;box-sizing:border-box}.layui-fluid{position:relative;margin:0 auto;padding:0 15px}.layui-row:after,.layui-row:before{content:"";display:block;clear:both}.layui-col-lg1,.layui-col-lg10,.layui-col-lg11,.layui-col-lg12,.layui-col-lg2,.layui-col-lg3,.layui-col-lg4,.layui-col-lg5,.layui-col-lg6,.layui-col-lg7,.layui-col-lg8,.layui-col-lg9,.layui-col-md1,.layui-col-md10,.layui-col-md11,.layui-col-md12,.layui-col-md2,.layui-col-md3,.layui-col-md4,.layui-col-md5,.layui-col-md6,.layui-col-md7,.layui-col-md8,.layui-col-md9,.layui-col-sm1,.layui-col-sm10,.layui-col-sm11,.layui-col-sm12,.layui-col-sm2,.layui-col-sm3,.layui-col-sm4,.layui-col-sm5,.layui-col-sm6,.layui-col-sm7,.layui-col-sm8,.layui-col-sm9,.layui-col-xl1,.layui-col-xl10,.layui-col-xl11,.layui-col-xl12,.layui-col-xl2,.layui-col-xl3,.layui-col-xl4,.layui-col-xl5,.layui-col-xl6,.layui-col-xl7,.layui-col-xl8,.layui-col-xl9,.layui-col-xs1,.layui-col-xs10,.layui-col-xs11,.layui-col-xs12,.layui-col-xs2,.layui-col-xs3,.layui-col-xs4,.layui-col-xs5,.layui-col-xs6,.layui-col-xs7,.layui-col-xs8,.layui-col-xs9{position:relative;display:block;box-sizing:border-box}.layui-col-xs1,.layui-col-xs10,.layui-col-xs11,.layui-col-xs12,.layui-col-xs2,.layui-col-xs3,.layui-col-xs4,.layui-col-xs5,.layui-col-xs6,.layui-col-xs7,.layui-col-xs8,.layui-col-xs9{float:left}.layui-col-xs1{width:8.33333333%}.layui-col-xs2{width:16.66666667%}.layui-col-xs3{width:25%}.layui-col-xs4{width:33.33333333%}.layui-col-xs5{width:41.66666667%}.layui-col-xs6{width:50%}.layui-col-xs7{width:58.33333333%}.layui-col-xs8{width:66.66666667%}.layui-col-xs9{width:75%}.layui-col-xs10{width:83.33333333%}.layui-col-xs11{width:91.66666667%}.layui-col-xs12{width:100%}.layui-col-xs-offset1{margin-left:8.33333333%}.layui-col-xs-offset2{margin-left:16.66666667%}.layui-col-xs-offset3{margin-left:25%}.layui-col-xs-offset4{margin-left:33.33333333%}.layui-col-xs-offset5{margin-left:41.66666667%}.layui-col-xs-offset6{margin-left:50%}.layui-col-xs-offset7{margin-left:58.33333333%}.layui-col-xs-offset8{margin-left:66.66666667%}.layui-col-xs-offset9{margin-left:75%}.layui-col-xs-offset10{margin-left:83.33333333%}.layui-col-xs-offset11{margin-left:91.66666667%}.layui-col-xs-offset12{margin-left:100%}@media screen and (max-width:767.98px){.layui-container{padding:0 15px}.layui-hide-xs{display:none!important}.layui-show-xs-block{display:block!important}.layui-show-xs-inline{display:inline!important}.layui-show-xs-inline-block{display:inline-block!important}}@media screen and (min-width:768px){.layui-container{width:720px}.layui-hide-sm{display:none!important}.layui-show-sm-block{display:block!important}.layui-show-sm-inline{display:inline!important}.layui-show-sm-inline-block{display:inline-block!important}.layui-col-sm1,.layui-col-sm10,.layui-col-sm11,.layui-col-sm12,.layui-col-sm2,.layui-col-sm3,.layui-col-sm4,.layui-col-sm5,.layui-col-sm6,.layui-col-sm7,.layui-col-sm8,.layui-col-sm9{float:left}.layui-col-sm1{width:8.33333333%}.layui-col-sm2{width:16.66666667%}.layui-col-sm3{width:25%}.layui-col-sm4{width:33.33333333%}.layui-col-sm5{width:41.66666667%}.layui-col-sm6{width:50%}.layui-col-sm7{width:58.33333333%}.layui-col-sm8{width:66.66666667%}.layui-col-sm9{width:75%}.layui-col-sm10{width:83.33333333%}.layui-col-sm11{width:91.66666667%}.layui-col-sm12{width:100%}.layui-col-sm-offset1{margin-left:8.33333333%}.layui-col-sm-offset2{margin-left:16.66666667%}.layui-col-sm-offset3{margin-left:25%}.layui-col-sm-offset4{margin-left:33.33333333%}.layui-col-sm-offset5{margin-left:41.66666667%}.layui-col-sm-offset6{margin-left:50%}.layui-col-sm-offset7{margin-left:58.33333333%}.layui-col-sm-offset8{margin-left:66.66666667%}.layui-col-sm-offset9{margin-left:75%}.layui-col-sm-offset10{margin-left:83.33333333%}.layui-col-sm-offset11{margin-left:91.66666667%}.layui-col-sm-offset12{margin-left:100%}}@media screen and (min-width:992px){.layui-container{width:960px}.layui-hide-md{display:none!important}.layui-show-md-block{display:block!important}.layui-show-md-inline{display:inline!important}.layui-show-md-inline-block{display:inline-block!important}.layui-col-md1,.layui-col-md10,.layui-col-md11,.layui-col-md12,.layui-col-md2,.layui-col-md3,.layui-col-md4,.layui-col-md5,.layui-col-md6,.layui-col-md7,.layui-col-md8,.layui-col-md9{float:left}.layui-col-md1{width:8.33333333%}.layui-col-md2{width:16.66666667%}.layui-col-md3{width:25%}.layui-col-md4{width:33.33333333%}.layui-col-md5{width:41.66666667%}.layui-col-md6{width:50%}.layui-col-md7{width:58.33333333%}.layui-col-md8{width:66.66666667%}.layui-col-md9{width:75%}.layui-col-md10{width:83.33333333%}.layui-col-md11{width:91.66666667%}.layui-col-md12{width:100%}.layui-col-md-offset1{margin-left:8.33333333%}.layui-col-md-offset2{margin-left:16.66666667%}.layui-col-md-offset3{margin-left:25%}.layui-col-md-offset4{margin-left:33.33333333%}.layui-col-md-offset5{margin-left:41.66666667%}.layui-col-md-offset6{margin-left:50%}.layui-col-md-offset7{margin-left:58.33333333%}.layui-col-md-offset8{margin-left:66.66666667%}.layui-col-md-offset9{margin-left:75%}.layui-col-md-offset10{margin-left:83.33333333%}.layui-col-md-offset11{margin-left:91.66666667%}.layui-col-md-offset12{margin-left:100%}}@media screen and (min-width:1200px){.layui-container{width:1150px}.layui-hide-lg{display:none!important}.layui-show-lg-block{display:block!important}.layui-show-lg-inline{display:inline!important}.layui-show-lg-inline-block{display:inline-block!important}.layui-col-lg1,.layui-col-lg10,.layui-col-lg11,.layui-col-lg12,.layui-col-lg2,.layui-col-lg3,.layui-col-lg4,.layui-col-lg5,.layui-col-lg6,.layui-col-lg7,.layui-col-lg8,.layui-col-lg9{float:left}.layui-col-lg1{width:8.33333333%}.layui-col-lg2{width:16.66666667%}.layui-col-lg3{width:25%}.layui-col-lg4{width:33.33333333%}.layui-col-lg5{width:41.66666667%}.layui-col-lg6{width:50%}.layui-col-lg7{width:58.33333333%}.layui-col-lg8{width:66.66666667%}.layui-col-lg9{width:75%}.layui-col-lg10{width:83.33333333%}.layui-col-lg11{width:91.66666667%}.layui-col-lg12{width:100%}.layui-col-lg-offset1{margin-left:8.33333333%}.layui-col-lg-offset2{margin-left:16.66666667%}.layui-col-lg-offset3{margin-left:25%}.layui-col-lg-offset4{margin-left:33.33333333%}.layui-col-lg-offset5{margin-left:41.66666667%}.layui-col-lg-offset6{margin-left:50%}.layui-col-lg-offset7{margin-left:58.33333333%}.layui-col-lg-offset8{margin-left:66.66666667%}.layui-col-lg-offset9{margin-left:75%}.layui-col-lg-offset10{margin-left:83.33333333%}.layui-col-lg-offset11{margin-left:91.66666667%}.layui-col-lg-offset12{margin-left:100%}}@media screen and (min-width:1400px){.layui-container{width:1330px}.layui-hide-xl{display:none!important}.layui-show-xl-block{display:block!important}.layui-show-xl-inline{display:inline!important}.layui-show-xl-inline-block{display:inline-block!important}.layui-col-xl1,.layui-col-xl10,.layui-col-xl11,.layui-col-xl12,.layui-col-xl2,.layui-col-xl3,.layui-col-xl4,.layui-col-xl5,.layui-col-xl6,.layui-col-xl7,.layui-col-xl8,.layui-col-xl9{float:left}.layui-col-xl1{width:8.33333333%}.layui-col-xl2{width:16.66666667%}.layui-col-xl3{width:25%}.layui-col-xl4{width:33.33333333%}.layui-col-xl5{width:41.66666667%}.layui-col-xl6{width:50%}.layui-col-xl7{width:58.33333333%}.layui-col-xl8{width:66.66666667%}.layui-col-xl9{width:75%}.layui-col-xl10{width:83.33333333%}.layui-col-xl11{width:91.66666667%}.layui-col-xl12{width:100%}.layui-col-xl-offset1{margin-left:8.33333333%}.layui-col-xl-offset2{margin-left:16.66666667%}.layui-col-xl-offset3{margin-left:25%}.layui-col-xl-offset4{margin-left:33.33333333%}.layui-col-xl-offset5{margin-left:41.66666667%}.layui-col-xl-offset6{margin-left:50%}.layui-col-xl-offset7{margin-left:58.33333333%}.layui-col-xl-offset8{margin-left:66.66666667%}.layui-col-xl-offset9{margin-left:75%}.layui-col-xl-offset10{margin-left:83.33333333%}.layui-col-xl-offset11{margin-left:91.66666667%}.layui-col-xl-offset12{margin-left:100%}}.layui-col-space1{margin:-.5px}.layui-col-space1>*{padding:.5px}.layui-col-space2{margin:-1px}.layui-col-space2>*{padding:1px}.layui-col-space4{margin:-2px}.layui-col-space4>*{padding:2px}.layui-col-space5{margin:-2.5px}.layui-col-space5>*{padding:2.5px}.layui-col-space6{margin:-3px}.layui-col-space6>*{padding:3px}.layui-col-space8{margin:-4px}.layui-col-space8>*{padding:4px}.layui-col-space10{margin:-5px}.layui-col-space10>*{padding:5px}.layui-col-space12{margin:-6px}.layui-col-space12>*{padding:6px}.layui-col-space14{margin:-7px}.layui-col-space14>*{padding:7px}.layui-col-space15{margin:-7.5px}.layui-col-space15>*{padding:7.5px}.layui-col-space16{margin:-8px}.layui-col-space16>*{padding:8px}.layui-col-space18{margin:-9px}.layui-col-space18>*{padding:9px}.layui-col-space20{margin:-10px}.layui-col-space20>*{padding:10px}.layui-col-space22{margin:-11px}.layui-col-space22>*{padding:11px}.layui-col-space24{margin:-12px}.layui-col-space24>*{padding:12px}.layui-col-space25{margin:-12.5px}.layui-col-space25>*{padding:12.5px}.layui-col-space26{margin:-13px}.layui-col-space26>*{padding:13px}.layui-col-space28{margin:-14px}.layui-col-space28>*{padding:14px}.layui-col-space30{margin:-15px}.layui-col-space30>*{padding:15px}.layui-col-space32{margin:-15px}.layui-col-space32>*{padding:15px}.layui-btn,.layui-input,.layui-select,.layui-textarea,.layui-upload-button{outline:0;-webkit-appearance:none;transition:all .3s;-webkit-transition:all .3s;box-sizing:border-box}.layui-elem-quote{margin-bottom:10px;padding:15px;line-height:1.8;border-left:5px solid #16b777;border-radius:0 2px 2px 0;background-color:#fafafa}.layui-quote-nm{border-style:solid;border-width:1px;border-left-width:5px;background:0 0}.layui-elem-field{margin-bottom:10px;padding:0;border-width:1px;border-style:solid}.layui-elem-field legend{margin-left:20px;padding:0 10px;font-size:20px}.layui-field-title{margin:16px 0;border-width:0;border-top-width:1px}.layui-field-box{padding:15px}.layui-field-title .layui-field-box{padding:10px 0}.layui-progress{position:relative;height:6px;border-radius:20px;background-color:#eee}.layui-progress-bar{position:absolute;left:0;top:0;width:0;max-width:100%;height:6px;border-radius:20px;text-align:right;background-color:#16b777;transition:all .3s;-webkit-transition:all .3s}.layui-progress-big,.layui-progress-big .layui-progress-bar{height:18px;line-height:18px}.layui-progress-text{position:relative;top:-20px;line-height:18px;font-size:12px;color:#5f5f5f}.layui-progress-big .layui-progress-text{position:static;padding:0 10px;color:#fff}.layui-collapse{border-width:1px;border-style:solid;border-radius:2px}.layui-colla-content,.layui-colla-item{border-top-width:1px;border-top-style:solid}.layui-colla-item:first-child{border-top:none}.layui-colla-title{position:relative;height:42px;line-height:42px;padding:0 15px 0 35px;color:#333;background-color:#fafafa;cursor:pointer;font-size:14px;overflow:hidden}.layui-colla-content{display:none;padding:10px 15px;line-height:1.6;color:#5f5f5f}.layui-colla-icon{position:absolute;left:15px;top:0;font-size:14px}.layui-card{margin-bottom:15px;border-radius:2px;background-color:#fff;box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.layui-card:last-child{margin-bottom:0}.layui-card-header{position:relative;height:42px;line-height:42px;padding:0 15px;border-bottom:1px solid #f8f8f8;color:#333;border-radius:2px 2px 0 0;font-size:14px}.layui-card-body{position:relative;padding:10px 15px;line-height:24px}.layui-card-body[pad15]{padding:15px}.layui-card-body[pad20]{padding:20px}.layui-card-body .layui-table{margin:5px 0}.layui-card .layui-tab{margin:0}.layui-panel{position:relative;border-width:1px;border-style:solid;border-radius:2px;box-shadow:1px 1px 4px rgb(0 0 0 / 8%);background-color:#fff;color:#5f5f5f}.layui-panel-window{position:relative;padding:15px;border-radius:0;border-top:5px solid #eee;background-color:#fff}.layui-auxiliar-moving{position:fixed;left:0;right:0;top:0;bottom:0;width:100%;height:100%;background:0 0;z-index:9999999999}.layui-scollbar-hide{overflow:hidden!important}.layui-bg-red{background-color:#ff5722!important;color:#fff!important}.layui-bg-orange{background-color:#ffb800!important;color:#fff!important}.layui-bg-green{background-color:#16baaa!important;color:#fff!important}.layui-bg-cyan{background-color:#2f4056!important;color:#fff!important}.layui-bg-blue{background-color:#1e9fff!important;color:#fff!important}.layui-bg-purple{background-color:#a233c6!important;color:#fff!important}.layui-bg-black{background-color:#2f363c!important;color:#fff!important}.layui-bg-gray{background-color:#fafafa!important;color:#5f5f5f!important}.layui-badge-rim,.layui-border,.layui-colla-content,.layui-colla-item,.layui-collapse,.layui-elem-field,.layui-form-pane .layui-form-item[pane],.layui-form-pane .layui-form-label,.layui-input,.layui-input-split,.layui-panel,.layui-quote-nm,.layui-select,.layui-tab-bar,.layui-tab-card,.layui-tab-title,.layui-tab-title .layui-this:after,.layui-textarea{border-color:#eee}.layui-border{border-width:1px;border-style:solid;color:#5f5f5f!important}.layui-border-red{border-width:1px;border-style:solid;border-color:#ff5722!important;color:#ff5722!important}.layui-border-orange{border-width:1px;border-style:solid;border-color:#ffb800!important;color:#ffb800!important}.layui-border-green{border-width:1px;border-style:solid;border-color:#16baaa!important;color:#16baaa!important}.layui-border-cyan{border-width:1px;border-style:solid;border-color:#2f4056!important;color:#2f4056!important}.layui-border-blue{border-width:1px;border-style:solid;border-color:#1e9fff!important;color:#1e9fff!important}.layui-border-purple{border-width:1px;border-style:solid;border-color:#a233c6!important;color:#a233c6!important}.layui-border-black{border-width:1px;border-style:solid;border-color:#2f363c!important;color:#2f363c!important}.layui-timeline-item:before{background-color:#eee}.layui-text{line-height:1.8;font-size:14px}.layui-text h1,.layui-text h2,.layui-text h3,.layui-text h4,.layui-text h5,.layui-text h6{color:#3a3a3a}.layui-text h1{font-size:32px}.layui-text h2{font-size:24px}.layui-text h3{font-size:18px}.layui-text h4{font-size:16px}.layui-text h5{font-size:14px}.layui-text h6{font-size:13px}.layui-text ol,.layui-text ul{padding-left:15px}.layui-text ul li{margin-top:5px;list-style-type:disc}.layui-text ol li{margin-top:5px;list-style-type:decimal}.layui-text-em,.layui-word-aux{color:#999!important;padding-left:5px!important;padding-right:5px!important}.layui-text p{margin:15px 0}.layui-text p:first-child{margin-top:0}.layui-text p:last-child{margin-bottom:0}.layui-text a:not(.layui-btn){color:#01aaed}.layui-text a:not(.layui-btn):hover{text-decoration:underline}.layui-text blockquote:not(.layui-elem-quote){padding:5px 15px;border-left:5px solid #eee}.layui-text pre>code:not(.layui-code){padding:15px;font-family:Courier New,Lucida Console,Consolas;background-color:#fafafa}.layui-font-12{font-size:12px!important}.layui-font-13{font-size:13px!important}.layui-font-14{font-size:14px!important}.layui-font-16{font-size:16px!important}.layui-font-18{font-size:18px!important}.layui-font-20{font-size:20px!important}.layui-font-22{font-size:22px!important}.layui-font-24{font-size:24px!important}.layui-font-26{font-size:26px!important}.layui-font-28{font-size:28px!important}.layui-font-30{font-size:30px!important}.layui-font-32{font-size:32px!important}.layui-font-red{color:#ff5722!important}.layui-font-orange{color:#ffb800!important}.layui-font-green{color:#16baaa!important}.layui-font-cyan{color:#2f4056!important}.layui-font-blue{color:#01aaed!important}.layui-font-purple{color:#a233c6!important}.layui-font-black{color:#000!important}.layui-font-gray{color:#c2c2c2!important}.layui-btn{display:inline-block;vertical-align:middle;height:38px;line-height:38px;border:1px solid transparent;padding:0 18px;background-color:#16baaa;color:#fff;white-space:nowrap;text-align:center;font-size:14px;border-radius:2px;cursor:pointer;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-btn:hover{opacity:.8;filter:alpha(opacity=80);color:#fff}.layui-btn:active{opacity:1;filter:alpha(opacity=100)}.layui-btn+.layui-btn{margin-left:10px}.layui-btn-container{word-spacing:-5px}.layui-btn-container .layui-btn{margin-right:10px;margin-bottom:10px;word-spacing:normal}.layui-btn-container .layui-btn+.layui-btn{margin-left:0}.layui-table .layui-btn-container .layui-btn{margin-bottom:9px}.layui-btn-radius{border-radius:100px}.layui-btn .layui-icon{padding:0 2px;vertical-align:middle\0;vertical-align:bottom}.layui-btn-primary{border-color:#d2d2d2;background:0 0;color:#5f5f5f}.layui-btn-primary:hover{border-color:#16baaa;color:#333}.layui-btn-normal{background-color:#1e9fff}.layui-btn-warm{background-color:#ffb800}.layui-btn-danger{background-color:#ff5722}.layui-btn-checked{background-color:#16b777}.layui-btn-disabled,.layui-btn-disabled:active,.layui-btn-disabled:hover{border-color:#eee!important;background-color:#fbfbfb!important;color:#d2d2d2!important;cursor:not-allowed!important;opacity:1}.layui-btn-lg{height:44px;line-height:44px;padding:0 25px;font-size:16px}.layui-btn-sm{height:30px;line-height:30px;padding:0 10px;font-size:12px}.layui-btn-xs{height:22px;line-height:22px;padding:0 5px;font-size:12px}.layui-btn-xs i{font-size:12px!important}.layui-btn-group{display:inline-block;vertical-align:middle;font-size:0}.layui-btn-group .layui-btn{margin-left:0!important;margin-right:0!important;border-left:1px solid rgba(255,255,255,.5);border-radius:0}.layui-btn-group .layui-btn-primary{border-left:none}.layui-btn-group .layui-btn-primary:hover{border-color:#d2d2d2;color:#16baaa}.layui-btn-group .layui-btn:first-child{border-left:none;border-radius:2px 0 0 2px}.layui-btn-group .layui-btn-primary:first-child{border-left:1px solid #d2d2d2}.layui-btn-group .layui-btn:last-child{border-radius:0 2px 2px 0}.layui-btn-group .layui-btn+.layui-btn{margin-left:0}.layui-btn-group+.layui-btn-group{margin-left:10px}.layui-btn-fluid{width:100%}.layui-input,.layui-select,.layui-textarea{height:38px;line-height:1.3;line-height:38px\9;border-width:1px;border-style:solid;background-color:#fff;color:rgba(0,0,0,.85);border-radius:2px}.layui-input::-webkit-input-placeholder,.layui-select::-webkit-input-placeholder,.layui-textarea::-webkit-input-placeholder{line-height:1.3}.layui-input,.layui-textarea{display:block;width:100%;padding-left:10px}.layui-input:hover,.layui-textarea:hover{border-color:#d2d2d2!important}.layui-input:focus,.layui-textarea:focus{border-color:#d2d2d2!important}.layui-textarea{position:relative;min-height:100px;height:auto;line-height:20px;padding:6px 10px;resize:vertical}.layui-select{padding:0 10px}.layui-form input[type=checkbox],.layui-form input[type=radio],.layui-form select{display:none}.layui-form [lay-ignore]{display:initial}.layui-form-item{position:relative;margin-bottom:15px;clear:both;*zoom:1}.layui-form-item:after{content:'\20';clear:both;*zoom:1;display:block;height:0}.layui-form-label{position:relative;float:left;display:block;padding:9px 15px;width:80px;font-weight:400;line-height:20px;text-align:right}.layui-form-label-col{display:block;float:none;padding:9px 0;line-height:20px;text-align:left}.layui-form-item .layui-inline{margin-bottom:5px;margin-right:10px}.layui-input-block,.layui-input-inline{position:relative}.layui-input-block{margin-left:110px;min-height:36px}.layui-input-inline{display:inline-block;vertical-align:middle}.layui-form-item .layui-input-inline{float:left;width:190px;margin-right:10px}.layui-form-text .layui-input-inline{width:auto}.layui-form-mid{position:relative;float:left;display:block;padding:9px 0!important;line-height:20px;margin-right:10px}.layui-form-danger+.layui-form-select .layui-input,.layui-form-danger:focus{border-color:#ff5722!important}.layui-input-prefix,.layui-input-split,.layui-input-suffix,.layui-input-suffix .layui-input-affix{position:absolute;right:0;top:0;padding:0 10px;width:35px;height:100%;text-align:center;transition:all .3s;box-sizing:border-box}.layui-input-prefix{left:0;border-radius:2px 0 0 2px}.layui-input-suffix{right:0;border-radius:0 2px 2px 0}.layui-input-split{border-width:1px;border-style:solid}.layui-input-prefix .layui-icon,.layui-input-split .layui-icon,.layui-input-suffix .layui-icon{position:relative;font-size:16px;color:#5f5f5f;transition:all .3s}.layui-input-group{position:relative;display:table;box-sizing:border-box}.layui-input-group>*{display:table-cell;vertical-align:middle;position:relative}.layui-input-group .layui-input{padding-right:15px}.layui-input-group .layui-input-prefix{width:auto;border-right:0}.layui-input-group .layui-input-suffix{width:auto;border-left:0}.layui-input-group .layui-input-split{white-space:nowrap}.layui-input-wrap{position:relative;line-height:38px}.layui-input-wrap .layui-input{padding-right:35px}.layui-input-wrap .layui-input::-ms-clear,.layui-input-wrap .layui-input::-ms-reveal{display:none}.layui-input-wrap .layui-input-prefix+.layui-input,.layui-input-wrap .layui-input-prefix~* .layui-input{padding-left:35px}.layui-input-wrap .layui-input-split+.layui-input,.layui-input-wrap .layui-input-split~* .layui-input{padding-left:45px}.layui-input-wrap .layui-input-prefix~.layui-form-select{position:static}.layui-input-wrap .layui-input-prefix,.layui-input-wrap .layui-input-split,.layui-input-wrap .layui-input-suffix{pointer-events:none}.layui-input-wrap .layui-input:focus+.layui-input-split{border-color:#d2d2d2}.layui-input-wrap .layui-input-prefix.layui-input-split{border-width:0;border-right-width:1px}.layui-input-affix{line-height:38px}.layui-input-suffix .layui-input-affix{right:auto;left:-35px}.layui-input-affix .layui-icon{color:rgba(0,0,0,.8);pointer-events:auto!important;cursor:pointer}.layui-input-affix .layui-icon-clear{color:rgba(0,0,0,.3)}.layui-input-affix .layui-icon:hover{color:rgba(0,0,0,.6)}.layui-form-select{position:relative;color:#5f5f5f}.layui-form-select .layui-input{padding-right:30px;cursor:pointer}.layui-form-select .layui-edge{position:absolute;right:10px;top:50%;margin-top:-3px;cursor:pointer;border-width:6px;border-top-color:#c2c2c2;border-top-style:solid;transition:all .3s;-webkit-transition:all .3s}.layui-form-select dl{display:none;position:absolute;left:0;top:42px;padding:5px 0;z-index:899;min-width:100%;border:1px solid #eee;max-height:300px;overflow-y:auto;background-color:#fff;border-radius:2px;box-shadow:1px 1px 4px rgb(0 0 0 / 8%);box-sizing:border-box}.layui-form-select dl dd,.layui-form-select dl dt{padding:0 10px;line-height:36px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.layui-form-select dl dt{font-size:12px;color:#999}.layui-form-select dl dd{cursor:pointer}.layui-form-select dl dd:hover{background-color:#f8f8f8;-webkit-transition:.5s all;transition:.5s all}.layui-form-select .layui-select-group dd{padding-left:20px}.layui-form-select dl dd.layui-select-tips{padding-left:10px!important;color:#999}.layui-form-select dl dd.layui-this{background-color:#f8f8f8;color:#16b777;font-weight:700}.layui-form-select dl dd.layui-disabled{background-color:#fff}.layui-form-selected dl{display:block}.layui-form-selected .layui-edge{margin-top:-9px;-webkit-transform:rotate(180deg);transform:rotate(180deg)}.layui-form-selected .layui-edge{margin-top:-3px\0}:root .layui-form-selected .layui-edge{margin-top:-9px\0/IE9}.layui-form-selectup dl{top:auto;bottom:42px}.layui-select-none{margin:5px 0;text-align:center;color:#999}.layui-select-disabled .layui-disabled{border-color:#eee!important}.layui-select-disabled .layui-edge{border-top-color:#d2d2d2}.layui-form-checkbox{position:relative;display:inline-block;vertical-align:middle;height:30px;line-height:30px;margin-right:10px;padding-right:30px;background-color:#fff;cursor:pointer;font-size:0;-webkit-transition:.1s linear;transition:.1s linear;box-sizing:border-box}.layui-form-checkbox>*{display:inline-block;vertical-align:middle}.layui-form-checkbox>div{padding:0 11px;font-size:14px;border-radius:2px 0 0 2px;background-color:#d2d2d2;color:#fff;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.layui-form-checkbox:hover>div{background-color:#c2c2c2}.layui-form-checkbox>i{position:absolute;right:0;top:0;width:30px;height:100%;border:1px solid #d2d2d2;border-left:none;border-radius:0 2px 2px 0;color:#fff;color:rgba(255,255,255,0);font-size:20px;text-align:center;box-sizing:border-box}.layui-form-checkbox:hover>i{border-color:#c2c2c2;color:#c2c2c2}.layui-form-checked,.layui-form-checked:hover{border-color:#16b777}.layui-form-checked:hover>div,.layui-form-checked>div{background-color:#16b777}.layui-form-checked:hover>i,.layui-form-checked>i{color:#16b777}.layui-form-item .layui-form-checkbox{margin-top:4px}.layui-form-checkbox.layui-checkbox-disabled>div{background-color:#eee!important}.layui-form [lay-checkbox]{display:none}.layui-form-checkbox[lay-skin=primary]{height:auto!important;line-height:normal!important;min-width:18px;min-height:18px;border:none!important;margin-right:0;padding-left:24px;padding-right:0;background:0 0}.layui-form-checkbox[lay-skin=primary]>div{margin-top:-1px;padding-left:0;padding-right:15px;line-height:18px;background:0 0;color:#5f5f5f}.layui-form-checkbox[lay-skin=primary]>i{right:auto;left:0;width:16px;height:16px;line-height:14px;border:1px solid #d2d2d2;font-size:12px;border-radius:2px;background-color:#fff;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-checkbox[lay-skin=primary]:hover>i{border-color:#16b777;color:#fff}.layui-form-checked[lay-skin=primary]>i{border-color:#16b777!important;background-color:#16b777;color:#fff}.layui-checkbox-disabled[lay-skin=primary]>div{background:0 0!important}.layui-form-checked.layui-checkbox-disabled[lay-skin=primary]>i{background:#eee!important;border-color:#eee!important}.layui-checkbox-disabled[lay-skin=primary]:hover>i{border-color:#d2d2d2}.layui-form-item .layui-form-checkbox[lay-skin=primary]{margin-top:10px}.layui-form-checkbox[lay-skin=primary]>.layui-icon-indeterminate{border-color:#16b777}.layui-form-checkbox[lay-skin=primary]>.layui-icon-indeterminate:before{content:'';display:inline-block;vertical-align:middle;position:relative;width:50%;height:1px;margin:-1px auto 0;background-color:#16b777}.layui-form-switch{position:relative;display:inline-block;vertical-align:middle;height:24px;line-height:22px;min-width:44px;padding:0 5px;margin-top:8px;border:1px solid #d2d2d2;border-radius:20px;cursor:pointer;box-sizing:border-box;background-color:#fff;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-switch>i{position:absolute;left:5px;top:3px;width:16px;height:16px;border-radius:20px;background-color:#d2d2d2;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-switch>div{position:relative;top:0;margin-left:21px;padding:0!important;text-align:center!important;color:#999!important;font-style:normal!important;font-size:12px}.layui-form-onswitch{border-color:#16b777;background-color:#16b777}.layui-form-onswitch>i{left:100%;margin-left:-21px;background-color:#fff}.layui-form-onswitch>div{margin-left:0;margin-right:21px;color:#fff!important}.layui-checkbox-disabled{border-color:#eee!important}.layui-checkbox-disabled>div{color:#c2c2c2!important}.layui-checkbox-disabled>i{border-color:#eee!important}.layui-checkbox-disabled:hover>i{color:#fff!important}.layui-form-radio{display:inline-block;vertical-align:middle;line-height:28px;margin:6px 10px 0 0;padding-right:10px;cursor:pointer;font-size:0}.layui-form-radio>*{display:inline-block;vertical-align:middle;font-size:14px}.layui-form-radio>i{margin-right:8px;font-size:22px;color:#c2c2c2}.layui-form-radio:hover>*,.layui-form-radioed,.layui-form-radioed>i{color:#16b777}.layui-radio-disabled>i{color:#eee!important}.layui-radio-disabled>*{color:#c2c2c2!important}.layui-form [lay-radio]{display:none}.layui-form-pane .layui-form-label{width:110px;padding:8px 15px;height:38px;line-height:20px;border-width:1px;border-style:solid;border-radius:2px 0 0 2px;text-align:center;background-color:#fafafa;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;box-sizing:border-box}.layui-form-pane .layui-input-inline{margin-left:-1px}.layui-form-pane .layui-input-block{margin-left:110px;left:-1px}.layui-form-pane .layui-input{border-radius:0 2px 2px 0}.layui-form-pane .layui-form-text .layui-form-label{float:none;width:100%;border-radius:2px;box-sizing:border-box;text-align:left}.layui-form-pane .layui-form-text .layui-input-inline{display:block;margin:0;top:-1px;clear:both}.layui-form-pane .layui-form-text .layui-input-block{margin:0;left:0;top:-1px}.layui-form-pane .layui-form-text .layui-textarea{min-height:100px;border-radius:0 0 2px 2px}.layui-form-pane .layui-form-checkbox{margin:4px 0 4px 10px}.layui-form-pane .layui-form-radio,.layui-form-pane .layui-form-switch{margin-top:6px;margin-left:10px}.layui-form-pane .layui-form-item[pane]{position:relative;border-width:1px;border-style:solid}.layui-form-pane .layui-form-item[pane] .layui-form-label{position:absolute;left:0;top:0;height:100%;border-width:0;border-right-width:1px}.layui-form-pane .layui-form-item[pane] .layui-input-inline{margin-left:110px}@media screen and (max-width:450px){.layui-form-item .layui-form-label{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-form-item .layui-inline{display:block;margin-right:0;margin-bottom:20px;clear:both}.layui-form-item .layui-inline:after{content:'\20';clear:both;display:block;height:0}.layui-form-item .layui-input-inline{display:block;float:none;left:-3px;width:auto!important;margin:0 0 10px 112px}.layui-form-item .layui-input-inline+.layui-form-mid{margin-left:110px;top:-5px;padding:0}.layui-form-item .layui-form-checkbox{margin-right:5px;margin-bottom:5px}}.layui-laypage{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;margin:10px 0;font-size:0}.layui-laypage>a:first-child,.layui-laypage>a:first-child em{border-radius:2px 0 0 2px}.layui-laypage>a:last-child,.layui-laypage>a:last-child em{border-radius:0 2px 2px 0}.layui-laypage>:first-child{margin-left:0!important}.layui-laypage>:last-child{margin-right:0!important}.layui-laypage a,.layui-laypage button,.layui-laypage input,.layui-laypage select,.layui-laypage span{border:1px solid #eee}.layui-laypage a,.layui-laypage span{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding:0 15px;height:28px;line-height:28px;margin:0 -1px 5px 0;background-color:#fff;color:#333;font-size:12px}.layui-laypage a[data-page]{color:#333}.layui-laypage a{text-decoration:none!important;cursor:pointer}.layui-laypage a:hover{color:#16baaa}.layui-laypage em{font-style:normal}.layui-laypage .layui-laypage-spr{color:#999;font-weight:700}.layui-laypage .layui-laypage-curr{position:relative}.layui-laypage .layui-laypage-curr em{position:relative;color:#fff}.layui-laypage .layui-laypage-curr .layui-laypage-em{position:absolute;left:-1px;top:-1px;padding:1px;width:100%;height:100%;background-color:#16baaa}.layui-laypage-em{border-radius:2px}.layui-laypage-next em,.layui-laypage-prev em{font-family:Sim sun;font-size:16px}.layui-laypage .layui-laypage-count,.layui-laypage .layui-laypage-limits,.layui-laypage .layui-laypage-refresh,.layui-laypage .layui-laypage-skip{margin-left:10px;margin-right:10px;padding:0;border:none}.layui-laypage .layui-laypage-limits,.layui-laypage .layui-laypage-refresh{vertical-align:top}.layui-laypage .layui-laypage-refresh i{font-size:18px;cursor:pointer}.layui-laypage select{height:22px;padding:3px;border-radius:2px;cursor:pointer}.layui-laypage .layui-laypage-skip{height:30px;line-height:30px;color:#999}.layui-laypage button,.layui-laypage input{height:30px;line-height:30px;border-radius:2px;vertical-align:top;background-color:#fff;box-sizing:border-box}.layui-laypage input{display:inline-block;width:40px;margin:0 10px;padding:0 3px;text-align:center}.layui-laypage input:focus,.layui-laypage select:focus{border-color:#16baaa!important}.layui-laypage button{margin-left:10px;padding:0 10px;cursor:pointer}.layui-flow-more{margin:10px 0;text-align:center;color:#999;font-size:14px;clear:both}.layui-flow-more a{height:32px;line-height:32px}.layui-flow-more a *{display:inline-block;vertical-align:top}.layui-flow-more a cite{padding:0 20px;border-radius:3px;background-color:#eee;color:#333;font-style:normal}.layui-flow-more a cite:hover{opacity:.8}.layui-flow-more a i{font-size:30px;color:#737383}.layui-table{width:100%;margin:10px 0;background-color:#fff;color:#5f5f5f}.layui-table tr{transition:all .3s;-webkit-transition:all .3s}.layui-table th{text-align:left;font-weight:600}.layui-table-mend{background-color:#fff}.layui-table-click,.layui-table-hover,.layui-table[lay-even] tbody tr:nth-child(even){background-color:#f8f8f8}.layui-table td,.layui-table th,.layui-table-col-set,.layui-table-fixed-r,.layui-table-grid-down,.layui-table-header,.layui-table-mend,.layui-table-page,.layui-table-tips-main,.layui-table-tool,.layui-table-total,.layui-table-view,.layui-table[lay-skin=line],.layui-table[lay-skin=row]{border-width:1px;border-style:solid;border-color:#eee}.layui-table td,.layui-table th{position:relative;padding:9px 15px;min-height:20px;line-height:20px;font-size:14px}.layui-table[lay-skin=line] td,.layui-table[lay-skin=line] th{border-width:0;border-bottom-width:1px}.layui-table[lay-skin=row] td,.layui-table[lay-skin=row] th{border-width:0;border-right-width:1px}.layui-table[lay-skin=nob] td,.layui-table[lay-skin=nob] th{border:none}.layui-table img{max-width:100px}.layui-table[lay-size=lg] td,.layui-table[lay-size=lg] th{padding-top:15px;padding-right:30px;padding-bottom:15px;padding-left:30px}.layui-table-view .layui-table[lay-size=lg] .layui-table-cell{height:50px;line-height:40px}.layui-table[lay-size=sm] td,.layui-table[lay-size=sm] th{padding-top:5px;padding-right:10px;padding-bottom:5px;padding-left:10px;font-size:12px}.layui-table-view .layui-table[lay-size=sm] .layui-table-cell{height:30px;line-height:20px;padding-top:5px;padding-left:11px;padding-right:11px}.layui-table[lay-data],.layui-table[lay-options]{display:none}.layui-table-box{position:relative;overflow:hidden}.layui-table-view{clear:both}.layui-table-view .layui-table{position:relative;width:auto;margin:0;border:0;border-collapse:separate}.layui-table-view .layui-table[lay-skin=line]{border-width:0;border-right-width:1px}.layui-table-view .layui-table[lay-skin=row]{border-width:0;border-bottom-width:1px}.layui-table-view .layui-table td,.layui-table-view .layui-table th{padding:0;border-top:none;border-left:none}.layui-table-view .layui-table th.layui-unselect .layui-table-cell span{cursor:pointer}.layui-table-view .layui-table td{cursor:default}.layui-table-view .layui-table td[data-edit]{cursor:text}.layui-table-view .layui-table td[data-edit]:hover:after{position:absolute;left:0;top:0;width:100%;height:100%;box-sizing:border-box;border:1px solid #16b777;pointer-events:none;content:""}.layui-table-view .layui-form-checkbox[lay-skin=primary] i{width:18px;height:18px;line-height:16px}.layui-table-view .layui-form-radio{line-height:0;padding:0}.layui-table-view .layui-form-radio>i{margin:0;font-size:20px}.layui-table-init{position:absolute;left:0;top:0;width:100%;height:100%;text-align:center;z-index:199}.layui-table-init .layui-icon{position:absolute;left:50%;top:50%;margin:-15px 0 0 -15px;font-size:30px;color:#c2c2c2}.layui-table-header{border-width:0;border-bottom-width:1px;overflow:hidden}.layui-table-header .layui-table{margin-bottom:-1px}.layui-table-column{position:relative;width:100%;min-height:41px;padding:8px 16px;border-width:0;border-bottom-width:1px}.layui-table-column .layui-btn-container{margin-bottom:-8px}.layui-table-column .layui-btn-container .layui-btn{margin-right:8px;margin-bottom:8px}.layui-table-tool .layui-inline[lay-event]{position:relative;width:26px;height:26px;padding:5px;line-height:16px;margin-right:10px;text-align:center;color:#333;border:1px solid #ccc;cursor:pointer;-webkit-transition:.5s all;transition:.5s all}.layui-table-tool .layui-inline[lay-event]:hover{border:1px solid #999}.layui-table-tool-temp{padding-right:120px}.layui-table-tool-self{position:absolute;right:17px;top:10px}.layui-table-tool .layui-table-tool-self .layui-inline[lay-event]{margin:0 0 0 10px}.layui-table-tool-panel{position:absolute;top:29px;left:-1px;z-index:399;padding:5px 0!important;min-width:150px;min-height:40px;border:1px solid #d2d2d2;text-align:left;overflow-y:auto;background-color:#fff;box-shadow:0 2px 4px rgba(0,0,0,.12)}.layui-table-tool-panel li{padding:0 10px;margin:0!important;line-height:30px;list-style-type:none!important;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-webkit-transition:.5s all;transition:.5s all}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary]{width:100%}.layui-table-tool-panel li:hover{background-color:#f8f8f8}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary]{padding-left:28px}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] i{position:absolute;left:0;top:0}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] span{padding:0}.layui-table-tool .layui-table-tool-self .layui-table-tool-panel{left:auto;right:-1px}.layui-table-col-set{position:absolute;right:0;top:0;width:20px;height:100%;border-width:0;border-left-width:1px;background-color:#fff}.layui-table-sort{width:10px;height:20px;margin-left:5px;cursor:pointer!important}.layui-table-sort .layui-edge{position:absolute;left:5px;border-width:5px}.layui-table-sort .layui-table-sort-asc{top:3px;border-top:none;border-bottom-style:solid;border-bottom-color:#b2b2b2}.layui-table-sort .layui-table-sort-asc:hover{border-bottom-color:#5f5f5f}.layui-table-sort .layui-table-sort-desc{bottom:5px;border-bottom:none;border-top-style:solid;border-top-color:#b2b2b2}.layui-table-sort .layui-table-sort-desc:hover{border-top-color:#5f5f5f}.layui-table-sort[lay-sort=asc] .layui-table-sort-asc{border-bottom-color:#000}.layui-table-sort[lay-sort=desc] .layui-table-sort-desc{border-top-color:#000}.layui-table-cell{height:38px;line-height:28px;padding:6px 15px;position:relative;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box}.layui-table-cell .layui-form-checkbox[lay-skin=primary]{top:-1px;padding:0}.layui-table-cell .layui-table-link{color:#01aaed}.layui-table-cell .layui-btn{vertical-align:inherit}.layui-table-cell[align=center]{-webkit-box-pack:center}.layui-table-cell[align=right]{-webkit-box-pack:end}.laytable-cell-checkbox,.laytable-cell-numbers,.laytable-cell-radio,.laytable-cell-space{text-align:center;-webkit-box-pack:center}.layui-table-body{position:relative;overflow:auto;margin-right:-1px;margin-bottom:-1px}.layui-table-body .layui-none{line-height:26px;padding:30px 15px;text-align:center;color:#999}.layui-table-fixed{position:absolute;left:0;top:0;z-index:101}.layui-table-fixed .layui-table-body{overflow:hidden}.layui-table-fixed-l{box-shadow:1px 0 8px rgba(0,0,0,.08)}.layui-table-fixed-r{left:auto;right:-1px;border-width:0;border-left-width:1px;box-shadow:-1px 0 8px rgba(0,0,0,.08)}.layui-table-fixed-r .layui-table-header{position:relative;overflow:visible}.layui-table-mend{position:absolute;right:-49px;top:0;height:100%;width:50px;border-width:0;border-left-width:1px}.layui-table-tool{position:relative;width:100%;min-height:50px;line-height:30px;padding:10px 15px;border-width:0;border-bottom-width:1px}.layui-table-tool .layui-btn-container{margin-bottom:-10px}.layui-table-total{margin-bottom:-1px;border-width:0;border-top-width:1px;overflow:hidden}.layui-table-page{border-width:0;border-top-width:1px;margin-bottom:-1px;white-space:nowrap;overflow:hidden}.layui-table-page>div{height:26px}.layui-table-page .layui-laypage{margin:0}.layui-table-page .layui-laypage a,.layui-table-page .layui-laypage span{height:26px;line-height:26px;margin-bottom:10px;border:none;background:0 0}.layui-table-page .layui-laypage a,.layui-table-page .layui-laypage span.layui-laypage-curr{padding:0 12px}.layui-table-page .layui-laypage span{margin-left:0;padding:0}.layui-table-page .layui-laypage .layui-laypage-prev{margin-left:-11px!important}.layui-table-page .layui-laypage .layui-laypage-curr .layui-laypage-em{left:0;top:0;padding:0}.layui-table-page .layui-laypage button,.layui-table-page .layui-laypage input{height:26px;line-height:26px}.layui-table-page .layui-laypage input{width:40px}.layui-table-page .layui-laypage button{padding:0 10px}.layui-table-page select{height:18px}.layui-table-pagebar{float:right;line-height:23px}.layui-table-pagebar .layui-btn-sm{margin-top:-1px}.layui-table-pagebar .layui-btn-xs{margin-top:2px}.layui-table-view select[lay-ignore]{display:inline-block}.layui-table-patch .layui-table-cell{padding:0;width:30px}.layui-table-edit{position:absolute;left:0;top:0;z-index:189;min-width:100%;min-height:100%;padding:5px 14px;border-radius:0;box-shadow:1px 1px 20px rgba(0,0,0,.15);background-color:#fff}.layui-table-edit:focus{border-color:#16b777!important}input.layui-input.layui-table-edit{height:100%}select.layui-table-edit{padding:0 0 0 10px;border-color:#d2d2d2}.layui-table-view .layui-form-checkbox,.layui-table-view .layui-form-radio,.layui-table-view .layui-form-switch{top:0;margin:0}.layui-table-view .layui-form-checkbox{top:-1px;height:26px;line-height:26px}.layui-table-view .layui-form-checkbox i{height:26px}.layui-table-grid .layui-table-cell{overflow:visible}.layui-table-grid-down{position:absolute;top:0;right:0;width:26px;height:100%;padding:5px 0;border-width:0;border-left-width:1px;text-align:center;background-color:#fff;color:#999;cursor:pointer}.layui-table-grid-down .layui-icon{position:absolute;top:50%;left:50%;margin:-8px 0 0 -8px}.layui-table-grid-down:hover{background-color:#fbfbfb}body .layui-table-tips .layui-layer-content{background:0 0;padding:0;box-shadow:0 1px 6px rgba(0,0,0,.12)}.layui-table-tips-main{margin:-49px 0 0 -1px;max-height:150px;padding:8px 15px;font-size:14px;overflow-y:scroll;background-color:#fff;color:#5f5f5f}.layui-table-tips-c{position:absolute;right:-3px;top:-13px;width:20px;height:20px;padding:3px;cursor:pointer;background-color:#5f5f5f;border-radius:50%;color:#fff}.layui-table-tips-c:hover{background-color:#777}.layui-table-tips-c:before{position:relative;right:-2px}.layui-table-tree-nodeIcon{max-width:20px}.layui-table-tree-nodeIcon>*{width:100%}.layui-table-tree-flexIcon,.layui-table-tree-nodeIcon{margin-right:2px}.layui-table-tree-flexIcon{cursor:pointer}.layui-upload-file{display:none!important;opacity:.01;filter:Alpha(opacity=1)}.layui-upload-list{margin:11px 0}.layui-upload-choose{max-width:200px;padding:0 10px;color:#999;font-size:14px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-upload-drag{position:relative;display:inline-block;padding:30px;border:1px dashed #e2e2e2;background-color:#fff;text-align:center;cursor:pointer;color:#999}.layui-upload-drag .layui-icon{font-size:50px;color:#16baaa}.layui-upload-drag[lay-over]{border-color:#16baaa}.layui-upload-form{display:inline-block}.layui-upload-iframe{position:absolute;width:0;height:0;border:0;visibility:hidden}.layui-upload-wrap{position:relative;display:inline-block;vertical-align:middle}.layui-upload-wrap .layui-upload-file{display:block!important;position:absolute;left:0;top:0;z-index:10;font-size:100px;width:100%;height:100%;opacity:.01;filter:Alpha(opacity=1);cursor:pointer}.layui-btn-container .layui-upload-choose{padding-left:0}.layui-menu{position:relative;margin:5px 0;background-color:#fff;box-sizing:border-box}.layui-menu *{box-sizing:border-box}.layui-menu li,.layui-menu-body-title,.layui-menu-body-title a{padding:5px 15px;color:initial}.layui-menu li{position:relative;margin:1px 0;line-height:26px;color:rgba(0,0,0,.8);font-size:14px;white-space:nowrap;cursor:pointer;transition:all .3s}.layui-menu li:hover{background-color:#f8f8f8}.layui-menu li.layui-disabled,.layui-menu li.layui-disabled *{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important}.layui-menu-item-parent:hover>.layui-menu-body-panel{display:block;animation-name:layui-fadein;animation-duration:.3s;animation-fill-mode:both;animation-delay:.2s}.layui-menu-item-group>.layui-menu-body-title,.layui-menu-item-parent>.layui-menu-body-title{padding-right:38px}.layui-menu .layui-menu-item-divider:hover,.layui-menu .layui-menu-item-group:hover,.layui-menu .layui-menu-item-none:hover{background:0 0;cursor:default}.layui-menu .layui-menu-item-group>ul{margin:5px 0 -5px}.layui-menu .layui-menu-item-group>.layui-menu-body-title{color:rgba(0,0,0,.35);user-select:none}.layui-menu .layui-menu-item-none{color:rgba(0,0,0,.35);cursor:default}.layui-menu .layui-menu-item-none{text-align:center}.layui-menu .layui-menu-item-divider{margin:5px 0;padding:0;height:0;line-height:0;border-bottom:1px solid #eee;overflow:hidden}.layui-menu .layui-menu-item-down:hover,.layui-menu .layui-menu-item-up:hover{cursor:pointer}.layui-menu .layui-menu-item-up>.layui-menu-body-title{color:rgba(0,0,0,.8)}.layui-menu .layui-menu-item-up>ul{visibility:hidden;height:0;overflow:hidden}.layui-menu .layui-menu-item-down:hover>.layui-menu-body-title>.layui-icon,.layui-menu .layui-menu-item-up>.layui-menu-body-title:hover>.layui-icon{color:#000}.layui-menu .layui-menu-item-down>ul{visibility:visible;height:auto}.layui-menu .layui-menu-item-checked,.layui-menu .layui-menu-item-checked2{background-color:#f8f8f8!important;color:#16b777}.layui-menu .layui-menu-item-checked a,.layui-menu .layui-menu-item-checked2 a{color:#16b777}.layui-menu .layui-menu-item-checked:after{position:absolute;right:-1px;top:0;bottom:0;border-right:3px solid #16b777;content:""}.layui-menu-body-title{position:relative;margin:-5px -15px;overflow:hidden;text-overflow:ellipsis}.layui-menu-body-title a{display:block;margin:-5px -15px;color:rgba(0,0,0,.8)}.layui-menu-body-title a:hover{transition:all .3s}.layui-menu-body-title>.layui-icon{position:absolute;right:15px;top:50%;margin-top:-6px;line-height:normal;font-size:14px}.layui-menu-body-title>.layui-icon:hover{transition:all .3s}.layui-menu-body-title>.layui-icon-right{right:14px}.layui-menu-body-panel{display:none;position:absolute;top:-7px;left:100%;z-index:1000;margin-left:13px;padding:5px 0}.layui-menu-body-panel:before{content:"";position:absolute;width:20px;left:-16px;top:0;bottom:0}.layui-menu-body-panel-left{left:auto;right:100%;margin:0 13px 0}.layui-menu-body-panel-left:before{left:auto;right:-16px}.layui-menu-lg li{line-height:32px}.layui-menu-lg .layui-menu-body-title a:hover,.layui-menu-lg li:hover{background:0 0;color:#16b777}.layui-menu-lg li .layui-menu-body-panel{margin-left:14px}.layui-menu-lg li .layui-menu-body-panel-left{margin:0 15px 0}.layui-dropdown{position:absolute;left:-999999px;top:-999999px;z-index:77777777;margin:5px 0;min-width:100px}.layui-dropdown:before{content:"";position:absolute;width:100%;height:6px;left:0;top:-6px}.layui-dropdown-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px");position:fixed;_position:absolute;pointer-events:auto}.layui-nav{position:relative;padding:0 15px;background-color:#2f363c;color:#fff;border-radius:2px;font-size:0;box-sizing:border-box}.layui-nav *{font-size:14px}.layui-nav .layui-nav-item{position:relative;display:inline-block;*display:inline;*zoom:1;margin-top:0;list-style:none;vertical-align:middle;line-height:60px}.layui-nav .layui-nav-item a{display:block;padding:0 20px;color:#fff;color:rgba(255,255,255,.7);transition:all .3s;-webkit-transition:all .3s}.layui-nav .layui-this:after,.layui-nav-bar{content:"";position:absolute;left:0;top:0;width:0;height:3px;background-color:#16b777;transition:all .2s;-webkit-transition:all .2s;pointer-events:none}.layui-nav-bar{z-index:1000}.layui-nav[lay-bar=disabled] .layui-nav-bar{display:none}.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{color:#fff;text-decoration:none}.layui-nav .layui-this:after{top:auto;bottom:0;width:100%}.layui-nav-img{width:30px;height:30px;margin-right:10px;border-radius:50%}.layui-nav .layui-nav-more{position:absolute;top:0;right:3px;left:auto!important;margin-top:0;font-size:12px;cursor:pointer;transition:all .2s;-webkit-transition:all .2s}.layui-nav .layui-nav-mored,.layui-nav-itemed>a .layui-nav-more{transform:rotate(180deg)}.layui-nav-child{display:none;position:absolute;left:0;top:65px;min-width:100%;line-height:36px;padding:5px 0;box-shadow:0 2px 4px rgba(0,0,0,.12);border:1px solid #eee;background-color:#fff;z-index:100;border-radius:2px;white-space:nowrap;box-sizing:border-box}.layui-nav .layui-nav-child a{color:#5f5f5f;color:rgba(0,0,0,.8)}.layui-nav .layui-nav-child a:hover{background-color:#f8f8f8;color:rgba(0,0,0,.8)}.layui-nav-child dd{margin:1px 0;position:relative}.layui-nav-child dd.layui-this{background-color:#f8f8f8;color:#000}.layui-nav-child dd.layui-this:after{display:none}.layui-nav-child-r{left:auto;right:0}.layui-nav-child-c{text-align:center}.layui-nav.layui-nav-tree{width:200px;padding:0}.layui-nav-tree .layui-nav-item{display:block;width:100%;line-height:40px}.layui-nav-tree .layui-nav-item a{position:relative;height:40px;line-height:40px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-nav-tree .layui-nav-item>a{padding-top:5px;padding-bottom:5px}.layui-nav-tree .layui-nav-more{right:15px}.layui-nav-tree .layui-nav-item>a .layui-nav-more{padding:5px 0}.layui-nav-tree .layui-nav-bar{width:5px;height:0}.layui-side .layui-nav-tree .layui-nav-bar{width:2px}.layui-nav-tree .layui-nav-child dd.layui-this,.layui-nav-tree .layui-nav-child dd.layui-this a,.layui-nav-tree .layui-this,.layui-nav-tree .layui-this>a,.layui-nav-tree .layui-this>a:hover{background-color:#16baaa;color:#fff}.layui-nav-tree .layui-this:after{display:none}.layui-nav-itemed>a,.layui-nav-tree .layui-nav-title a,.layui-nav-tree .layui-nav-title a:hover{color:#fff!important}.layui-nav-tree .layui-nav-bar{background-color:#16baaa}.layui-nav-tree .layui-nav-child{position:relative;z-index:0;top:0;border:none;box-shadow:none}.layui-nav-tree .layui-nav-child dd{margin:0}.layui-nav-tree .layui-nav-child a{color:#fff;color:rgba(255,255,255,.7)}.layui-nav-tree .layui-nav-child,.layui-nav-tree .layui-nav-child a:hover{background:0 0;color:#fff}.layui-nav-itemed>.layui-nav-child{display:block;background-color:rgba(0,0,0,.3)!important}.layui-nav-itemed>.layui-nav-child>.layui-this>.layui-nav-child{display:block}.layui-nav-side{position:fixed;top:0;bottom:0;left:0;overflow-x:hidden;z-index:999}.layui-nav-tree.layui-bg-gray a,.layui-nav.layui-bg-gray .layui-nav-item a{color:rgba(0,0,0,.8)}.layui-nav-tree.layui-bg-gray{padding:6px 0}.layui-nav-tree.layui-bg-gray .layui-nav-itemed>a{color:#000!important}.layui-nav.layui-bg-gray .layui-this a{color:#16b777}.layui-nav-tree.layui-bg-gray .layui-nav-itemed>.layui-nav-child{padding-left:11px;background:0 0!important}.layui-nav-tree.layui-bg-gray .layui-nav-item>a{padding-top:0;padding-bottom:0}.layui-nav-tree.layui-bg-gray .layui-nav-item>a .layui-nav-more{padding:0}.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this,.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this a,.layui-nav-tree.layui-bg-gray .layui-this,.layui-nav-tree.layui-bg-gray .layui-this>a{background:0 0!important;color:#16b777!important;font-weight:700}.layui-nav-tree.layui-bg-gray .layui-nav-bar{background-color:#16b777}.layui-breadcrumb{visibility:hidden;font-size:0}.layui-breadcrumb>*{font-size:14px}.layui-breadcrumb a{color:#999!important}.layui-breadcrumb a:hover{color:#16b777!important}.layui-breadcrumb a cite{color:#5f5f5f;font-style:normal}.layui-breadcrumb span[lay-separator]{margin:0 10px;color:#999}.layui-tab{margin:10px 0;text-align:left!important}.layui-tab[overflow]>.layui-tab-title{overflow:hidden}.layui-tab .layui-tab-title{position:relative;left:0;height:40px;white-space:nowrap;font-size:0;border-bottom-width:1px;border-bottom-style:solid;transition:all .2s;-webkit-transition:all .2s}.layui-tab .layui-tab-title li{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;font-size:14px;transition:all .2s;-webkit-transition:all .2s}.layui-tab .layui-tab-title li{position:relative;line-height:40px;min-width:65px;margin:0;padding:0 15px;text-align:center;cursor:pointer}.layui-tab .layui-tab-title li a{display:block;padding:0 15px;margin:0 -15px}.layui-tab-title .layui-this{color:#000}.layui-tab-title .layui-this:after{position:absolute;left:0;top:0;content:"";width:100%;height:41px;border-width:1px;border-style:solid;border-bottom-color:#fff;border-radius:2px 2px 0 0;box-sizing:border-box;pointer-events:none}.layui-tab-bar{position:absolute;right:0;top:0;z-index:10;width:30px;height:39px;line-height:39px;border-width:1px;border-style:solid;border-radius:2px;text-align:center;background-color:#fff;cursor:pointer}.layui-tab-bar .layui-icon{position:relative;display:inline-block;top:3px;transition:all .3s;-webkit-transition:all .3s}.layui-tab-item{display:none}.layui-tab-more{padding-right:30px;height:auto!important;white-space:normal!important}.layui-tab-more li.layui-this:after{border-bottom-color:#eee;border-radius:2px}.layui-tab-more .layui-tab-bar .layui-icon{top:-2px;top:3px\0;-webkit-transform:rotate(180deg);transform:rotate(180deg)}:root .layui-tab-more .layui-tab-bar .layui-icon{top:-2px\0/IE9}.layui-tab-content{padding:15px 0}.layui-tab-title li .layui-tab-close{position:relative;display:inline-block;width:18px;height:18px;line-height:20px;margin-left:8px;top:1px;text-align:center;font-size:14px;color:#c2c2c2;transition:all .2s;-webkit-transition:all .2s}.layui-tab-title li .layui-tab-close:hover{border-radius:2px;background-color:#ff5722;color:#fff}.layui-tab-brief>.layui-tab-title .layui-this{color:#16baaa}.layui-tab-brief>.layui-tab-more li.layui-this:after,.layui-tab-brief>.layui-tab-title .layui-this:after{border:none;border-radius:0;border-bottom:2px solid #16b777}.layui-tab-brief[overflow]>.layui-tab-title .layui-this:after{top:-1px}.layui-tab-card{border-width:1px;border-style:solid;border-radius:2px;box-shadow:0 2px 5px 0 rgba(0,0,0,.1)}.layui-tab-card>.layui-tab-title{background-color:#fafafa}.layui-tab-card>.layui-tab-title li{margin-right:-1px;margin-left:-1px}.layui-tab-card>.layui-tab-title .layui-this{background-color:#fff}.layui-tab-card>.layui-tab-title .layui-this:after{border-top:none;border-width:1px;border-bottom-color:#fff}.layui-tab-card>.layui-tab-title .layui-tab-bar{height:40px;line-height:40px;border-radius:0;border-top:none;border-right:none}.layui-tab-card>.layui-tab-more .layui-this{background:0 0;color:#16b777}.layui-tab-card>.layui-tab-more .layui-this:after{border:none}.layui-timeline{padding-left:5px}.layui-timeline-item{position:relative;padding-bottom:20px}.layui-timeline-axis{position:absolute;left:-5px;top:0;z-index:10;width:20px;height:20px;line-height:20px;background-color:#fff;color:#16b777;border-radius:50%;text-align:center;cursor:pointer}.layui-timeline-axis:hover{color:#ff5722}.layui-timeline-item:before{content:"";position:absolute;left:5px;top:0;z-index:0;width:1px;height:100%}.layui-timeline-item:first-child:before{display:block}.layui-timeline-item:last-child:before{display:none}.layui-timeline-content{padding-left:25px}.layui-timeline-title{position:relative;margin-bottom:10px;line-height:22px}.layui-badge,.layui-badge-dot,.layui-badge-rim{position:relative;display:inline-block;padding:0 6px;font-size:12px;text-align:center;background-color:#ff5722;color:#fff;border-radius:2px}.layui-badge{height:18px;line-height:18px}.layui-badge-dot{width:8px;height:8px;padding:0;border-radius:50%}.layui-badge-rim{height:18px;line-height:18px;border-width:1px;border-style:solid;background-color:#fff;color:#5f5f5f}.layui-btn .layui-badge,.layui-btn .layui-badge-dot{margin-left:5px}.layui-nav .layui-badge,.layui-nav .layui-badge-dot{position:absolute;top:50%;margin:-5px 6px 0}.layui-nav .layui-badge{margin-top:-10px}.layui-tab-title .layui-badge,.layui-tab-title .layui-badge-dot{left:5px;top:-2px}.layui-carousel{position:relative;left:0;top:0;background-color:#f8f8f8}.layui-carousel>[carousel-item]{position:relative;width:100%;height:100%;overflow:hidden}.layui-carousel>[carousel-item]:before{position:absolute;content:'\e63d';left:50%;top:50%;width:100px;line-height:20px;margin:-10px 0 0 -50px;text-align:center;color:#c2c2c2;font-family:layui-icon!important;font-size:30px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-carousel>[carousel-item]>*{display:none;position:absolute;left:0;top:0;width:100%;height:100%;background-color:#f8f8f8;transition-duration:.3s;-webkit-transition-duration:.3s}.layui-carousel-updown>*{-webkit-transition:.3s ease-in-out up;transition:.3s ease-in-out up}.layui-carousel-arrow{display:none\0;opacity:0;position:absolute;left:10px;top:50%;margin-top:-18px;width:36px;height:36px;line-height:36px;text-align:center;font-size:20px;border:none 0;border-radius:50%;background-color:rgba(0,0,0,.2);color:#fff;-webkit-transition-duration:.3s;transition-duration:.3s;cursor:pointer}.layui-carousel-arrow[lay-type=add]{left:auto!important;right:10px}.layui-carousel[lay-arrow=always] .layui-carousel-arrow{opacity:1;left:20px}.layui-carousel[lay-arrow=always] .layui-carousel-arrow[lay-type=add]{right:20px}.layui-carousel[lay-arrow=none] .layui-carousel-arrow{display:none}.layui-carousel-arrow:hover,.layui-carousel-ind ul:hover{background-color:rgba(0,0,0,.35)}.layui-carousel:hover .layui-carousel-arrow{display:block\0;opacity:1;left:20px}.layui-carousel:hover .layui-carousel-arrow[lay-type=add]{right:20px}.layui-carousel-ind{position:relative;top:-35px;width:100%;line-height:0!important;text-align:center;font-size:0}.layui-carousel[lay-indicator=outside]{margin-bottom:30px}.layui-carousel[lay-indicator=outside] .layui-carousel-ind{top:10px}.layui-carousel[lay-indicator=outside] .layui-carousel-ind ul{background-color:rgba(0,0,0,.5)}.layui-carousel[lay-indicator=none] .layui-carousel-ind{display:none}.layui-carousel-ind ul{display:inline-block;padding:5px;background-color:rgba(0,0,0,.2);border-radius:10px;-webkit-transition-duration:.3s;transition-duration:.3s}.layui-carousel-ind ul li{display:inline-block;width:10px;height:10px;margin:0 3px;font-size:14px;background-color:#eee;background-color:rgba(255,255,255,.5);border-radius:50%;cursor:pointer;-webkit-transition-duration:.3s;transition-duration:.3s}.layui-carousel-ind ul li:hover{background-color:rgba(255,255,255,.7)}.layui-carousel-ind ul li.layui-this{background-color:#fff}.layui-carousel>[carousel-item]>.layui-carousel-next,.layui-carousel>[carousel-item]>.layui-carousel-prev,.layui-carousel>[carousel-item]>.layui-this{display:block}.layui-carousel>[carousel-item]>.layui-this{left:0}.layui-carousel>[carousel-item]>.layui-carousel-prev{left:-100%}.layui-carousel>[carousel-item]>.layui-carousel-next{left:100%}.layui-carousel>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel>[carousel-item]>.layui-carousel-prev.layui-carousel-right{left:0}.layui-carousel>[carousel-item]>.layui-this.layui-carousel-left{left:-100%}.layui-carousel>[carousel-item]>.layui-this.layui-carousel-right{left:100%}.layui-carousel[lay-anim=updown] .layui-carousel-arrow{left:50%!important;top:20px;margin:0 0 0 -18px}.layui-carousel[lay-anim=updown] .layui-carousel-arrow[lay-type=add]{top:auto!important;bottom:20px}.layui-carousel[lay-anim=updown] .layui-carousel-ind{position:absolute;top:50%;right:20px;width:auto;height:auto}.layui-carousel[lay-anim=updown] .layui-carousel-ind ul{padding:3px 5px}.layui-carousel[lay-anim=updown] .layui-carousel-ind li{display:block;margin:6px 0}.layui-carousel[lay-anim=updown]>[carousel-item]>*{left:0!important}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this{top:0}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-prev{top:-100%}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-next{top:100%}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-prev.layui-carousel-right{top:0}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this.layui-carousel-left{top:-100%}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this.layui-carousel-right{top:100%}.layui-carousel[lay-anim=fade]>[carousel-item]>*{left:0!important}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-next,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-prev{opacity:0}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-prev.layui-carousel-right{opacity:1}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-this.layui-carousel-left,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-this.layui-carousel-right{opacity:0}.layui-fixbar{position:fixed;right:16px;bottom:16px;z-index:999999}.layui-fixbar li{width:50px;height:50px;line-height:50px;margin-bottom:1px;text-align:center;cursor:pointer;font-size:30px;background-color:#9f9f9f;color:#fff;border-radius:2px;opacity:.95}.layui-fixbar li:hover{opacity:.85}.layui-fixbar li:active{opacity:1}.layui-fixbar .layui-fixbar-top{display:none;font-size:40px}body .layui-util-face{border:none;background:0 0}body .layui-util-face .layui-layer-content{padding:0;background-color:#fff;color:#5f5f5f;box-shadow:none}.layui-util-face .layui-layer-TipsG{display:none}.layui-util-face ul{position:relative;width:372px;padding:10px;border:1px solid #d9d9d9;background-color:#fff;box-shadow:0 0 20px rgba(0,0,0,.2)}.layui-util-face ul li{cursor:pointer;float:left;border:1px solid #e8e8e8;height:22px;width:26px;overflow:hidden;margin:-1px 0 0 -1px;padding:4px 2px;text-align:center}.layui-util-face ul li:hover{position:relative;z-index:2;border:1px solid #eb7350;background:#fff9ec}.layui-code{position:relative;margin:10px 0;padding:15px;line-height:20px;border:1px solid #eee;border-left-width:6px;background-color:#fafafa;color:#333;font-family:Courier New,Lucida Console,Consolas;font-size:12px}.layui-transfer-box,.layui-transfer-header,.layui-transfer-search{border-width:0;border-style:solid;border-color:#eee}.layui-transfer-box{position:relative;display:inline-block;vertical-align:middle;border-width:1px;width:200px;height:360px;border-radius:2px;background-color:#fff}.layui-transfer-box .layui-form-checkbox{width:100%;margin:0!important}.layui-transfer-header{height:38px;line-height:38px;padding:0 11px;border-bottom-width:1px}.layui-transfer-search{position:relative;padding:11px;border-bottom-width:1px}.layui-transfer-search .layui-input{height:32px;padding-left:30px;font-size:12px}.layui-transfer-search .layui-icon-search{position:absolute;left:20px;top:50%;line-height:normal;margin-top:-8px;color:#5f5f5f}.layui-transfer-active{margin:0 15px;display:inline-block;vertical-align:middle}.layui-transfer-active .layui-btn{display:block;margin:0;padding:0 15px;background-color:#16b777;border-color:#16b777;color:#fff}.layui-transfer-active .layui-btn-disabled{background-color:#fbfbfb;border-color:#eee;color:#d2d2d2}.layui-transfer-active .layui-btn:first-child{margin-bottom:15px}.layui-transfer-active .layui-btn .layui-icon{margin:0;font-size:14px!important}.layui-transfer-data{padding:5px 0;overflow:auto}.layui-transfer-data li{height:32px;line-height:32px;margin-top:0!important;padding:0 11px;list-style-type:none!important}.layui-transfer-data li:hover{background-color:#f8f8f8;transition:.5s all}.layui-transfer-data .layui-none{padding:15px 11px;text-align:center;color:#999}.layui-rate,.layui-rate *{display:inline-block;vertical-align:middle}.layui-rate{padding:11px 6px 11px 0;font-size:0}.layui-rate li{margin-top:0!important}.layui-rate li i.layui-icon{font-size:20px;color:#ffb800}.layui-rate li i.layui-icon{margin-right:5px;transition:all .3s;-webkit-transition:all .3s}.layui-rate li i:hover{cursor:pointer;transform:scale(1.12);-webkit-transform:scale(1.12)}.layui-rate[readonly] li i:hover{cursor:default;transform:scale(1)}.layui-colorpicker{width:38px;height:38px;border:1px solid #eee;padding:5px;border-radius:2px;line-height:24px;display:inline-block;cursor:pointer;transition:all .3s;-webkit-transition:all .3s;box-sizing:border-box}.layui-colorpicker:hover{border-color:#d2d2d2}.layui-colorpicker.layui-colorpicker-lg{width:44px;height:44px;line-height:30px}.layui-colorpicker.layui-colorpicker-sm{width:30px;height:30px;line-height:20px;padding:3px}.layui-colorpicker.layui-colorpicker-xs{width:22px;height:22px;line-height:16px;padding:1px}.layui-colorpicker-trigger-bgcolor{display:block;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);border-radius:2px}.layui-colorpicker-trigger-span{display:block;height:100%;box-sizing:border-box;border:1px solid rgba(0,0,0,.15);border-radius:2px;text-align:center}.layui-colorpicker-trigger-i{display:inline-block;color:#fff;font-size:12px}.layui-colorpicker-trigger-i.layui-icon-close{color:#999}.layui-colorpicker-main{position:absolute;left:-999999px;top:-999999px;z-index:77777777;width:280px;margin:5px 0;padding:7px;background:#fff;border:1px solid #d2d2d2;border-radius:2px;box-shadow:0 2px 4px rgba(0,0,0,.12)}.layui-colorpicker-main-wrapper{height:180px;position:relative}.layui-colorpicker-basis{width:260px;height:100%;position:relative}.layui-colorpicker-basis-white{width:100%;height:100%;position:absolute;top:0;left:0;background:linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.layui-colorpicker-basis-black{width:100%;height:100%;position:absolute;top:0;left:0;background:linear-gradient(0deg,#000,transparent)}.layui-colorpicker-basis-cursor{width:10px;height:10px;border:1px solid #fff;border-radius:50%;position:absolute;top:-3px;right:-3px;cursor:pointer}.layui-colorpicker-side{position:absolute;top:0;right:0;width:12px;height:100%;background:linear-gradient(red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.layui-colorpicker-side-slider{width:100%;height:5px;box-shadow:0 0 1px #888;box-sizing:border-box;background:#fff;border-radius:1px;border:1px solid #f0f0f0;cursor:pointer;position:absolute;left:0}.layui-colorpicker-main-alpha{display:none;height:12px;margin-top:7px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.layui-colorpicker-alpha-bgcolor{height:100%;position:relative}.layui-colorpicker-alpha-slider{width:5px;height:100%;box-shadow:0 0 1px #888;box-sizing:border-box;background:#fff;border-radius:1px;border:1px solid #f0f0f0;cursor:pointer;position:absolute;top:0}.layui-colorpicker-main-pre{padding-top:7px;font-size:0}.layui-colorpicker-pre{width:20px;height:20px;border-radius:2px;display:inline-block;margin-left:6px;margin-bottom:7px;cursor:pointer}.layui-colorpicker-pre:nth-child(11n+1){margin-left:0}.layui-colorpicker-pre-isalpha{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.layui-colorpicker-pre.layui-this{box-shadow:0 0 3px 2px rgba(0,0,0,.15)}.layui-colorpicker-pre>div{height:100%;border-radius:2px}.layui-colorpicker-main-input{text-align:right;padding-top:7px}.layui-colorpicker-main-input .layui-btn-container .layui-btn{margin:0 0 0 10px}.layui-colorpicker-main-input div.layui-inline{float:left;margin-right:10px;font-size:14px}.layui-colorpicker-main-input input.layui-input{width:150px;height:30px;color:#5f5f5f}.layui-slider{height:4px;background:#eee;border-radius:3px;position:relative;cursor:pointer}.layui-slider-bar{border-radius:3px;position:absolute;height:100%}.layui-slider-step{position:absolute;top:0;width:4px;height:4px;border-radius:50%;background:#fff;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.layui-slider-wrap{width:36px;height:36px;position:absolute;top:-16px;-webkit-transform:translateX(-50%);transform:translateX(-50%);z-index:10;text-align:center}.layui-slider-wrap-btn{width:12px;height:12px;border-radius:50%;background:#fff;display:inline-block;vertical-align:middle;cursor:pointer;transition:.3s}.layui-slider-wrap:after{content:"";height:100%;display:inline-block;vertical-align:middle}.layui-slider-wrap-btn.layui-slider-hover,.layui-slider-wrap-btn:hover{transform:scale(1.2)}.layui-slider-wrap-btn.layui-disabled:hover{transform:scale(1)!important}.layui-slider-tips{position:absolute;top:-42px;z-index:77777777;white-space:nowrap;display:none;-webkit-transform:translateX(-50%);transform:translateX(-50%);color:#fff;background:#000;border-radius:3px;height:25px;line-height:25px;padding:0 10px}.layui-slider-tips:after{content:"";position:absolute;bottom:-12px;left:50%;margin-left:-6px;width:0;height:0;border-width:6px;border-style:solid;border-color:#000 transparent transparent transparent}.layui-slider-input{width:70px;height:32px;border:1px solid #eee;border-radius:3px;font-size:16px;line-height:32px;position:absolute;right:0;top:-14px}.layui-slider-input-btn{position:absolute;top:0;right:0;width:20px;height:100%;border-left:1px solid #eee}.layui-slider-input-btn i{cursor:pointer;position:absolute;right:0;bottom:0;width:20px;height:50%;font-size:12px;line-height:16px;text-align:center;color:#999}.layui-slider-input-btn i:first-child{top:0;border-bottom:1px solid #eee}.layui-slider-input-txt{height:100%;font-size:14px}.layui-slider-input-txt input{height:100%;border:none}.layui-slider-input-btn i:hover{color:#16baaa}.layui-slider-vertical{width:4px;margin-left:33px}.layui-slider-vertical .layui-slider-bar{width:4px}.layui-slider-vertical .layui-slider-step{top:auto;left:0;-webkit-transform:translateY(50%);transform:translateY(50%)}.layui-slider-vertical .layui-slider-wrap{top:auto;left:-16px;-webkit-transform:translateY(50%);transform:translateY(50%)}.layui-slider-vertical .layui-slider-tips{top:auto;left:2px}@media \0screen{.layui-slider-wrap-btn{margin-left:-20px}.layui-slider-vertical .layui-slider-wrap-btn{margin-left:0;margin-bottom:-20px}.layui-slider-vertical .layui-slider-tips{margin-left:-8px}.layui-slider>span{margin-left:8px}}.layui-tree{line-height:22px}.layui-tree .layui-form-checkbox{margin:0!important}.layui-tree-set{width:100%;position:relative}.layui-tree-pack{display:none;padding-left:20px;position:relative}.layui-tree-line .layui-tree-pack{padding-left:27px}.layui-tree-line .layui-tree-set .layui-tree-set:after{content:"";position:absolute;top:14px;left:-9px;width:17px;height:0;border-top:1px dotted #c0c4cc}.layui-tree-entry{position:relative;padding:3px 0;height:20px;white-space:nowrap}.layui-tree-entry:hover{background-color:#eee}.layui-tree-line .layui-tree-entry:hover{background-color:rgba(0,0,0,0)}.layui-tree-line .layui-tree-entry:hover .layui-tree-txt{color:#999;text-decoration:underline;transition:.3s}.layui-tree-main{display:inline-block;vertical-align:middle;cursor:pointer;padding-right:10px}.layui-tree-line .layui-tree-set:before{content:"";position:absolute;top:0;left:-9px;width:0;height:100%;border-left:1px dotted #c0c4cc}.layui-tree-line .layui-tree-set.layui-tree-setLineShort:before{height:13px}.layui-tree-line .layui-tree-set.layui-tree-setHide:before{height:0}.layui-tree-iconClick{display:inline-block;vertical-align:middle;position:relative;height:20px;line-height:20px;margin:0 10px;color:#c0c4cc}.layui-tree-icon{height:12px;line-height:12px;width:12px;text-align:center;border:1px solid #c0c4cc}.layui-tree-iconClick .layui-icon{font-size:18px}.layui-tree-icon .layui-icon{font-size:12px;color:#5f5f5f}.layui-tree-iconArrow{padding:0 5px}.layui-tree-iconArrow:after{content:"";position:absolute;left:4px;top:3px;z-index:100;width:0;height:0;border-width:5px;border-style:solid;border-color:transparent transparent transparent #c0c4cc;transition:.5s}.layui-tree-spread>.layui-tree-entry .layui-tree-iconClick>.layui-tree-iconArrow:after{transform:rotate(90deg) translate(3px,4px)}.layui-tree-txt{display:inline-block;vertical-align:middle;color:#555}.layui-tree-search{margin-bottom:15px;color:#5f5f5f}.layui-tree-btnGroup{visibility:hidden;display:inline-block;vertical-align:middle;position:relative}.layui-tree-btnGroup .layui-icon{display:inline-block;vertical-align:middle;padding:0 2px;cursor:pointer}.layui-tree-btnGroup .layui-icon:hover{color:#999;transition:.3s}.layui-tree-entry:hover .layui-tree-btnGroup{visibility:visible}.layui-tree-editInput{position:relative;display:inline-block;vertical-align:middle;height:20px;line-height:20px;padding:0 3px;border:none;background-color:rgba(0,0,0,.05)}.layui-tree-emptyText{text-align:center;color:#999}.layui-anim{-webkit-animation-duration:.3s;-webkit-animation-fill-mode:both;animation-duration:.3s;animation-fill-mode:both}.layui-anim.layui-icon{display:inline-block}.layui-anim-loop{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.layui-trans,.layui-trans a{transition:all .2s;-webkit-transition:all .2s}@-webkit-keyframes layui-rotate{from{-webkit-transform:rotate(0)}to{-webkit-transform:rotate(360deg)}}@keyframes layui-rotate{from{transform:rotate(0)}to{transform:rotate(360deg)}}.layui-anim-rotate{-webkit-animation-name:layui-rotate;animation-name:layui-rotate;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:linear;animation-timing-function:linear}@-webkit-keyframes layui-up{from{-webkit-transform:translate3d(0,100%,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes layui-up{from{transform:translate3d(0,100%,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-anim-up{-webkit-animation-name:layui-up;animation-name:layui-up}@-webkit-keyframes layui-upbit{from{-webkit-transform:translate3d(0,15px,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes layui-upbit{from{transform:translate3d(0,15px,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-anim-upbit{-webkit-animation-name:layui-upbit;animation-name:layui-upbit}@keyframes layui-down{0%{opacity:.3;transform:translate3d(0,-100%,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-anim-down{animation-name:layui-down}@keyframes layui-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-anim-downbit{animation-name:layui-downbit}@-webkit-keyframes layui-scale{0%{opacity:.3;-webkit-transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1)}}@keyframes layui-scale{0%{opacity:.3;-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-ms-transform:scale(1);transform:scale(1)}}.layui-anim-scale{-webkit-animation-name:layui-scale;animation-name:layui-scale}@-webkit-keyframes layui-scale-spring{0%{opacity:.5;-webkit-transform:scale(.5)}80%{opacity:.8;-webkit-transform:scale(1.1)}100%{opacity:1;-webkit-transform:scale(1)}}@keyframes layui-scale-spring{0%{opacity:.5;transform:scale(.5)}80%{opacity:.8;transform:scale(1.1)}100%{opacity:1;transform:scale(1)}}.layui-anim-scaleSpring{-webkit-animation-name:layui-scale-spring;animation-name:layui-scale-spring}@keyframes layui-scalesmall{0%{opacity:.3;transform:scale(1.5)}100%{opacity:1;transform:scale(1)}}.layui-anim-scalesmall{animation-name:layui-scalesmall}@keyframes layui-scalesmall-spring{0%{opacity:.3;transform:scale(1.5)}80%{opacity:.8;transform:scale(.9)}100%{opacity:1;transform:scale(1)}}.layui-anim-scalesmall-spring{animation-name:layui-scalesmall-spring}@-webkit-keyframes layui-fadein{0%{opacity:0}100%{opacity:1}}@keyframes layui-fadein{0%{opacity:0}100%{opacity:1}}.layui-anim-fadein{-webkit-animation-name:layui-fadein;animation-name:layui-fadein}@-webkit-keyframes layui-fadeout{0%{opacity:1}100%{opacity:0}}@keyframes layui-fadeout{0%{opacity:1}100%{opacity:0}}.layui-anim-fadeout{-webkit-animation-name:layui-fadeout;animation-name:layui-fadeout}html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-view{display:block;position:relative;margin:11px 0;padding:0;border:1px solid #eee;border-left-width:6px;background-color:#fafafa;color:#333;font-family:Courier New;font-size:13px}.layui-code-title{position:relative;padding:0 10px;height:40px;line-height:40px;border-bottom:1px solid #eee;font-size:12px}.layui-code-title>.layui-code-about{position:absolute;right:10px;top:0;color:#b7b7b7}.layui-code-about>a{padding-left:10px}.layui-code-view>.layui-code-ol,.layui-code-view>.layui-code-ul{max-height:100%;padding:0!important;position:relative;overflow:auto}.layui-code-view>.layui-code-ol>li{position:relative;margin-top:0!important;margin-left:45px!important;line-height:20px;padding:0 10px!important;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view>.layui-code-ol>li:first-child,.layui-code-view>.layui-code-ul>li:first-child{padding-top:10px!important}.layui-code-view>.layui-code-ol>li:last-child,.layui-code-view>.layui-code-ul>li:last-child{padding-bottom:10px!important}.layui-code-view>.layui-code-ul>li{position:relative;line-height:20px;padding:0 10px!important;list-style-type:none;*list-style-type:none;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-dark{border:1px solid #0c0c0c;border-left-color:#3f3f3f;background-color:#0c0c0c;color:#c2be9e}.layui-code-dark>.layui-code-title{border-bottom:none}.layui-code-dark>.layui-code-ol>li,.layui-code-dark>.layui-code-ul>li{background-color:#3f3f3f;border-left:none}.layui-code-dark>.layui-code-ul>li{margin-left:6px}.layui-code textarea{display:none}.layui-code-preview>.layui-code{margin:0}.layui-code-preview>.layui-tab{position:relative;z-index:1;margin-bottom:0}.layui-code-preview>.layui-tab>.layui-tab-title{border-bottom:none}.layui-code-preview>.layui-code>.layui-code-title{display:none}.layui-code-preview .layui-code-item{display:none}.layui-code-item-preview{position:relative;padding:16px}.layui-code-item-preview>iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:none}.layui-code-tools{position:absolute;right:11px;top:3px}.layui-code-tools>i{display:inline-block;margin-left:6px;padding:3px;cursor:pointer}.layui-code-tools>i.layui-icon-file-b{color:#999}.layui-code-tools>i:hover{color:#16b777}.layui-code-copy{position:absolute;right:6px;top:6px;cursor:pointer;display:none}.layui-code-copy .layui-icon{color:#777;transition:all .3s}.layui-code-copy:hover .layui-icon{color:#16b777}.layui-code-view:hover>.layui-code-copy{display:block}.layui-code-copy-offset{margin-right:17px}.layui-code-preview>.layui-code-view>.layui-code-copy{display:none!important}.layui-code-full{position:fixed;left:0;top:0;z-index:1111111;width:100%;height:100%;background-color:#fff}.layui-code-full .layui-code-item{width:100%!important;border-width:0!important;border-top-width:1px!important}.layui-code-full .layui-code-item,.layui-code-full .layui-code-ol,.layui-code-full .layui-code-ul{height:calc(100vh - 51px)!important;box-sizing:border-box}html #layuicss-laydate{display:none;position:absolute;width:1989px}.layui-laydate *{margin:0;padding:0}.layui-laydate,.layui-laydate *{box-sizing:border-box}.layui-laydate{position:absolute;z-index:99999999;margin:5px 0;border-radius:2px;font-size:14px;line-height:normal;-webkit-animation-duration:.2s;animation-duration:.2s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-laydate-main{width:272px}.layui-laydate-content td,.layui-laydate-header *,.layui-laydate-list li{transition-duration:.3s;-webkit-transition-duration:.3s}.layui-laydate-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px");position:fixed;_position:absolute;pointer-events:auto}@keyframes laydate-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-laydate{animation-name:laydate-downbit}.layui-laydate-static{position:relative;z-index:0;display:inline-block;margin:0;-webkit-animation:none;animation:none}.laydate-ym-show .laydate-next-m,.laydate-ym-show .laydate-prev-m{display:none!important}.laydate-ym-show .laydate-next-y,.laydate-ym-show .laydate-prev-y{display:inline-block!important}.laydate-ym-show .laydate-set-ym span[lay-type=month]{display:none!important}.laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-time-show .layui-laydate-header .layui-icon{display:none!important}.layui-laydate-header{position:relative;line-height:30px;padding:10px 70px 5px}.layui-laydate-header *{display:inline-block;vertical-align:bottom}.layui-laydate-header i{position:absolute;top:10px;padding:0 5px;color:#999;font-size:18px;cursor:pointer}.layui-laydate-header i.laydate-prev-y{left:15px}.layui-laydate-header i.laydate-prev-m{left:45px}.layui-laydate-header i.laydate-next-y{right:15px}.layui-laydate-header i.laydate-next-m{right:45px}.laydate-set-ym{width:100%;text-align:center;box-sizing:border-box;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.laydate-set-ym span{padding:0 10px;cursor:pointer}.laydate-time-text{cursor:default!important}.layui-laydate-content{position:relative;padding:10px;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content table{border-collapse:collapse;border-spacing:0}.layui-laydate-content td,.layui-laydate-content th{width:36px;height:30px;padding:0;text-align:center}.layui-laydate-content th{font-weight:400}.layui-laydate-content td{position:relative;cursor:pointer}.laydate-day-mark{position:absolute;left:0;top:0;width:100%;line-height:30px;font-size:12px;overflow:hidden}.laydate-day-mark::after{position:absolute;content:'';right:2px;top:2px;width:5px;height:5px;border-radius:50%}.laydate-day-holidays:before{position:absolute;left:0;top:0;font-size:12px;transform:scale(.7)}.laydate-day-holidays:before{content:'\4F11';color:#ff5722}.laydate-day-holidays[type=work]:before{content:'\73ED';color:inherit}.layui-laydate .layui-this .laydate-day-holidays:before{color:#fff}.layui-laydate-footer{position:relative;height:46px;line-height:26px;padding:10px}.layui-laydate-footer span{display:inline-block;vertical-align:top;height:26px;line-height:24px;padding:0 10px;border:1px solid #c9c9c9;border-radius:2px;background-color:#fff;font-size:12px;cursor:pointer;white-space:nowrap;transition:all .3s}.layui-laydate-footer span:hover{color:#16b777}.layui-laydate-footer span.layui-laydate-preview{cursor:default;border-color:transparent!important}.layui-laydate-footer span.layui-laydate-preview:hover{color:#777}.layui-laydate-footer span:first-child.layui-laydate-preview{padding-left:0}.laydate-footer-btns{position:absolute;right:10px;top:10px}.laydate-footer-btns span{margin:0 0 0 -1px;border-radius:0}.laydate-footer-btns span:first-child{border-radius:2px 0 0 2px}.laydate-footer-btns span:last-child{border-radius:0 2px 2px 0}.layui-laydate-shortcut{width:80px;padding:6px 0;display:inline-block;vertical-align:top;overflow:auto;max-height:276px;text-align:center}.layui-laydate-shortcut+.layui-laydate-main{display:inline-block;border-left:1px solid #e2e2e2}.layui-laydate-shortcut>li{padding:5px 8px;cursor:pointer;line-height:18px}.layui-laydate .layui-laydate-list{position:absolute;left:0;top:0;width:100%;height:100%;padding:10px;box-sizing:border-box;background-color:#fff}.layui-laydate .layui-laydate-list>li{position:relative;display:inline-block;width:33.3%;height:36px;line-height:36px;margin:3px 0;vertical-align:middle;text-align:center;cursor:pointer;list-style:none}.layui-laydate .laydate-month-list>li{width:25%;margin:17px 0}.layui-laydate .laydate-time-list>li{height:100%;margin:0;line-height:normal;cursor:default}.layui-laydate .laydate-time-list p{position:relative;top:-4px;margin:0;line-height:29px}.layui-laydate .laydate-time-list ol{height:181px;overflow:hidden}.layui-laydate .laydate-time-list>li:hover ol{overflow-y:auto}.layui-laydate .laydate-time-list ol li{width:130%;padding-left:33px;height:30px;line-height:30px;text-align:left;cursor:pointer}.layui-laydate-hint{position:absolute;top:115px;left:50%;width:250px;margin-left:-125px;line-height:20px;padding:15px;text-align:center;font-size:12px;color:#ff5722}.layui-laydate-range{width:546px}.layui-laydate-range .layui-laydate-main{display:inline-block;vertical-align:middle;max-width:50%}.layui-laydate-range .laydate-main-list-1 .layui-laydate-content,.layui-laydate-range .laydate-main-list-1 .layui-laydate-header{border-left:1px solid #e2e2e2}.layui-laydate-range.layui-laydate-linkage .laydate-main-list-0 .laydate-next-m,.layui-laydate-range.layui-laydate-linkage .laydate-main-list-0 .laydate-next-y,.layui-laydate-range.layui-laydate-linkage .laydate-main-list-1 .laydate-prev-m,.layui-laydate-range.layui-laydate-linkage .laydate-main-list-1 .laydate-prev-y{display:none}.layui-laydate,.layui-laydate-hint{border:1px solid #d2d2d2;box-shadow:0 2px 4px rgba(0,0,0,.12);background-color:#fff;color:#777}.layui-laydate-header{border-bottom:1px solid #e2e2e2}.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:#16b777}.layui-laydate-content{border-top:none 0;border-bottom:none 0}.layui-laydate-content th{color:#333}.layui-laydate-content td{color:#777}.layui-laydate-content td.laydate-day-now{color:#16b777}.layui-laydate-content td.laydate-day-now:after{content:'';position:absolute;width:100%;height:30px;left:0;top:0;border:1px solid #16b777;box-sizing:border-box}.layui-laydate-linkage .layui-laydate-content td.laydate-selected>div{background-color:#00f7de}.layui-laydate-linkage .laydate-selected:hover>div{background-color:#00f7de!important}.layui-laydate-content td.laydate-selected:after,.layui-laydate-content td:hover:after{content:none}.layui-laydate-content td>div:hover,.layui-laydate-list li:hover,.layui-laydate-shortcut>li:hover{background-color:#eee;color:#333}.laydate-time-list li ol{margin:0;padding:0;border:1px solid #e2e2e2;border-left-width:0}.laydate-time-list li:first-child ol{border-left-width:1px}.laydate-time-list>li:hover{background:0 0}.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color:#d2d2d2}.layui-laydate-linkage .laydate-selected.laydate-day-next>div,.layui-laydate-linkage .laydate-selected.laydate-day-prev>div{background-color:#f8f8f8!important}.layui-laydate-footer{border-top:1px solid #e2e2e2}.layui-laydate-hint{color:#ff5722}.laydate-day-mark::after{background-color:#16b777}.layui-laydate-content td.layui-this .laydate-day-mark::after{display:none}.layui-laydate-footer span[lay-type=date]{color:#16b777}.layui-laydate .layui-this,.layui-laydate .layui-this>div{background-color:#16baaa!important;color:#fff!important}.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content td>div{padding:7px 0;height:100%}.laydate-theme-molv{border:none}.laydate-theme-molv.layui-laydate-range{width:548px}.laydate-theme-molv .layui-laydate-main{width:274px}.laydate-theme-molv .layui-laydate-header{border:none;background-color:#16baaa}.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:#f6f6f6}.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color:#fff}.laydate-theme-molv .layui-laydate-content{border:1px solid #e2e2e2;border-top:none;border-bottom:none}.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content{border-left:none}.laydate-theme-molv .layui-laydate-footer{border:1px solid #e2e2e2}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead{border:1px solid #e2e2e2}.layui-laydate-linkage.laydate-theme-grid .laydate-selected,.layui-laydate-linkage.laydate-theme-grid .laydate-selected:hover{background-color:#f2f2f2!important;color:#16baaa!important}.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-next,.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-prev{color:#d2d2d2!important}.laydate-theme-grid .laydate-month-list,.laydate-theme-grid .laydate-year-list{margin:1px 0 0 1px}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li{margin:0 -1px -1px 0}.laydate-theme-grid .laydate-year-list>li{height:43px;line-height:43px}.laydate-theme-grid .laydate-month-list>li{height:71px;line-height:71px}.laydate-theme-grid .layui-laydate-content td>div{height:29px;margin-top:-1px}.laydate-theme-circle .layui-laydate-content td.layui-this>div,.laydate-theme-circle .layui-laydate-content td>div{width:28px;height:28px;line-height:28px;border-radius:14px;margin:0 4px;padding:0}.layui-laydate.laydate-theme-circle .layui-laydate-content table td.layui-this{background-color:transparent!important}.laydate-theme-grid.laydate-theme-circle .layui-laydate-content td>div{margin:0 3.5px}.laydate-theme-fullpanel .layui-laydate-main{width:526px}.laydate-theme-fullpanel .layui-laydate-list{width:252px;left:272px}.laydate-theme-fullpanel .laydate-set-ym span{display:none}.laydate-theme-fullpanel .laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-theme-fullpanel .laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-theme-fullpanel .laydate-time-show .layui-laydate-header .layui-icon{display:inline-block!important}.laydate-theme-fullpanel .laydate-btns-time{display:none}html #layuicss-layer{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px")}.layui-layer{-webkit-overflow-scrolling:touch}.layui-layer{top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;border-radius:2px;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #b2b2b2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-btn a,.layui-layer-setwin span{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layer-anim{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-00{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@keyframes layer-slide-down{from{transform:translate3d(0,-100%,0)}to{transform:translate3d(0,0,0)}}@keyframes layer-slide-down-out{from{transform:translate3d(0,0,0)}to{transform:translate3d(0,-100%,0)}}.layer-anim-slide-down{animation-name:layer-slide-down}.layer-anim-slide-down-out{animation-name:layer-slide-down-out}@keyframes layer-slide-left{from{transform:translate3d(100%,0,0)}to{transform:translate3d(0,0,0)}}@keyframes layer-slide-left-out{from{transform:translate3d(0,0,0)}to{transform:translate3d(100%,0,0)}}.layer-anim-slide-left{animation-name:layer-slide-left}.layer-anim-slide-left-out{animation-name:layer-slide-left-out}@keyframes layer-slide-up{from{transform:translate3d(0,100%,0)}to{transform:translate3d(0,0,0)}}@keyframes layer-slide-up-out{from{transform:translate3d(0,0,0)}to{transform:translate3d(0,100%,0)}}.layer-anim-slide-up{animation-name:layer-slide-up}.layer-anim-slide-up-out{animation-name:layer-slide-up-out}@keyframes layer-slide-right{from{transform:translate3d(-100%,0,0)}to{transform:translate3d(0,0,0)}}@keyframes layer-slide-right-out{from{transform:translate3d(0,0,0)}to{transform:translate3d(-100%,0,0)}}.layer-anim-slide-right{animation-name:layer-slide-right}.layer-anim-slide-right-out{animation-name:layer-slide-right-out}.layui-layer-title{padding:0 81px 0 16px;height:50px;line-height:50px;border-bottom:1px solid #f0f0f0;font-size:14px;color:#333;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:16px;font-size:0;line-height:initial}.layui-layer-setwin span{position:relative;width:16px;height:16px;line-height:18px;margin-left:10px;text-align:center;font-size:16px;cursor:pointer;color:#000;_overflow:hidden}.layui-layer-setwin .layui-layer-min:before{content:'';position:absolute;width:12px;height:1px;left:50%;top:50%;margin:-.5px 0 0 -6px;background-color:#2e2d3c;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover:before{background-color:#2d93ca}.layui-layer-setwin .layui-layer-max:after,.layui-layer-setwin .layui-layer-max:before{content:'';position:absolute;left:50%;top:50%;z-index:1;width:9px;height:9px;margin:-5px 0 0 -5px;border:1px solid #2e2d3c}.layui-layer-setwin .layui-layer-max:hover:after,.layui-layer-setwin .layui-layer-max:hover:before{border-color:#2d93ca}.layui-layer-setwin .layui-layer-min:hover:before{background-color:#2d93ca}.layui-layer-setwin .layui-layer-maxmin:after,.layui-layer-setwin .layui-layer-maxmin:before{width:7px;height:7px;margin:-3px 0 0 -3px;background-color:#fff}.layui-layer-setwin .layui-layer-maxmin:after{z-index:0;margin:-5px 0 0 -1px}.layui-layer-setwin .layui-layer-close{cursor:pointer}.layui-layer-setwin .layui-layer-close:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;color:#fff;background-color:#787878;padding:3px;border:3px solid;width:18px;height:18px;font-size:18px;font-weight:bolder;border-radius:50%;margin-left:0;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{opacity:unset;background-color:#3888f6}.layui-layer-btn{text-align:right;padding:0 15px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:5px 5px 0;padding:0 15px;border:1px solid #dedede;background-color:#fff;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#1e9fff;background-color:#1e9fff;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:240px}.layui-layer-dialog .layui-layer-content{position:relative;padding:16px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-face{position:absolute;top:18px;left:16px;color:#959595;font-size:32px;_left:-40px}.layui-layer-dialog .layui-layer-content .layui-icon-tips{color:#f39b12}.layui-layer-dialog .layui-layer-content .layui-icon-success{color:#16b777}.layui-layer-dialog .layui-layer-content .layui-icon-error{top:19px;color:#ff5722}.layui-layer-dialog .layui-layer-content .layui-icon-question{color:#ffb800}.layui-layer-dialog .layui-layer-content .layui-icon-lock{color:#787878}.layui-layer-dialog .layui-layer-content .layui-icon-face-cry{color:#ff5722}.layui-layer-dialog .layui-layer-content .layui-icon-face-smile{color:#16b777}.layui-layer-rim{border:6px solid #8d8d8d;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #d3d4d3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-close{color:#fff}.layui-layer-hui .layui-layer-content{padding:11px 24px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:18px 24px 18px 58px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:76px;height:38px;line-height:38px;text-align:center}.layui-layer-loading-icon{font-size:38px;color:#959595}.layui-layer-loading2{text-align:center}.layui-layer-loading-2{position:relative;height:38px}.layui-layer-loading-2:after,.layui-layer-loading-2:before{content:'';position:absolute;left:50%;top:50%;width:38px;height:38px;margin:-19px 0 0 -19px;border-radius:50%;border:3px solid #d2d2d2;box-sizing:border-box}.layui-layer-loading-2:after{border-color:transparent;border-left-color:#1e9fff}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:8px 15px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:5px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan .layui-layer-title{background:#4476a7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;border-top:1px solid #e9e7e7}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#e9e7e7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#c9c5c5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92b8b1}.layui-layer-lan .layui-layer-setwin .layui-icon,.layui-layer-molv .layui-layer-setwin .layui-icon{color:#fff}.layui-layer-win10{border:1px solid #aaa;box-shadow:1px 1px 6px rgba(0,0,0,.3);border-radius:none}.layui-layer-win10 .layui-layer-title{height:32px;line-height:32px;padding-left:8px;border-bottom:none;font-size:12px}.layui-layer-win10 .layui-layer-setwin{right:0;top:0}.layui-layer-win10 .layui-layer-setwin span{margin-left:0;padding:8px}.layui-layer-win10.layui-layer-page .layui-layer-setwin span{padding:8px 11px}.layui-layer-win10 .layui-layer-setwin span:hover{background-color:#e5e5e5}.layui-layer-win10 .layui-layer-setwin span.layui-icon-close:hover{background-color:#e81123;color:#fff}.layui-layer-win10.layui-layer-dialog .layui-layer-content{padding:8px 16px 32px;color:#0033bc}.layui-layer-win10.layui-layer-dialog .layui-layer-padding{padding-top:18px;padding-left:58px}.layui-layer-win10 .layui-layer-btn{padding:5px 5px 10px;border-top:1px solid #dfdfdf;background-color:#f0f0f0}.layui-layer-win10 .layui-layer-btn a{height:18px;line-height:18px;background-color:#e1e1e1;border-color:#adadad;color:#000;font-size:12px;transition:all .3s}.layui-layer-win10 .layui-layer-btn a:hover{border-color:#2a8edd;background-color:#e5f1fb}.layui-layer-win10 .layui-layer-btn .layui-layer-btn0{border-color:#0078d7}.layui-layer-prompt .layui-layer-input{display:block;width:260px;height:36px;margin:0 auto;line-height:30px;padding-left:10px;border:1px solid #e6e6e6;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px;padding:6px 10px}.layui-layer-prompt .layui-layer-content{padding:16px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;display:inline-block;vertical-align:top;border-left:1px solid transparent;border-right:1px solid transparent;min-width:80px;max-width:300px;padding:0 16px;text-align:center;cursor:default;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;cursor:pointer}.layui-layer-tab .layui-layer-title span.layui-this{height:51px;border-left-color:#eee;border-right-color:#eee;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left-color:transparent}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{background:0 0;box-shadow:none}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgnext,.layui-layer-imgprev{position:fixed;top:50%;width:52px;height:52px;line-height:52px;margin-top:-26px;cursor:pointer;font-size:52px;color:#717171}.layui-layer-imgprev{left:32px}.layui-layer-imgnext{right:32px}.layui-layer-imgnext:hover,.layui-layer-imgprev:hover{color:#959595}.layui-layer-imgbar{position:fixed;left:0;right:0;bottom:0;width:100%;height:40px;line-height:40px;background-color:#000\9;filter:Alpha(opacity=60);background-color:rgba(2,0,0,.35);color:#fff;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;padding:0 5px;font-size:12px;color:#fff}.layui-layer-imgtit h3{max-width:65%;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;font-weight:300}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}} \ No newline at end of file +blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,li,ol,p,pre,td,textarea,th,ul{margin:0;padding:0;-webkit-tap-highlight-color:rgba(0,0,0,0)}a:active,a:hover{outline:0}img{display:inline-block;border:none;vertical-align:middle}li{list-style:none}table{border-collapse:collapse;border-spacing:0}h1,h2,h3,h4{font-weight:700}h5,h6{font-weight:500;font-size:100%}button,input,select,textarea{font-size:100%}button,input,optgroup,option,select,textarea{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;outline:0}pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}body{line-height:1.6;color:#333;color:rgba(0,0,0,.85);font:14px Helvetica Neue,Helvetica,PingFang SC,Tahoma,Arial,sans-serif}hr{height:0;line-height:0;margin:10px 0;padding:0;border:none;border-bottom:1px solid #eee;clear:both;overflow:hidden;background:0 0}a{color:#333;text-decoration:none}a:hover{color:#777}a cite{font-style:normal;*cursor:pointer}.layui-border-box,.layui-border-box *{box-sizing:border-box}.layui-box,.layui-box *{box-sizing:content-box}.layui-clear{clear:both;*zoom:1}.layui-clear:after{content:'\20';clear:both;*zoom:1;display:block;height:0}.layui-clear-space{word-spacing:-5px}.layui-inline{position:relative;display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.layui-edge{position:relative;display:inline-block;vertical-align:middle;width:0;height:0;border-width:6px;border-style:dashed;border-color:transparent;overflow:hidden}.layui-edge-top{top:-4px;border-bottom-color:#999;border-bottom-style:solid}.layui-edge-right{border-left-color:#999;border-left-style:solid}.layui-edge-bottom{top:2px;border-top-color:#999;border-top-style:solid}.layui-edge-left{border-right-color:#999;border-right-style:solid}.layui-elip{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-disabled,.layui-icon,.layui-unselect{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-disabled,.layui-disabled:hover{color:#d2d2d2!important;cursor:not-allowed!important}.layui-circle{border-radius:100%}.layui-show{display:block!important}.layui-hide{display:none!important}.layui-show-v{visibility:visible!important}.layui-hide-v{visibility:hidden!important}@font-face{font-family:layui-icon;src:url(../font/iconfont.eot?v=282);src:url(../font/iconfont.eot?v=282#iefix) format('embedded-opentype'),url(../font/iconfont.woff2?v=282) format('woff2'),url(../font/iconfont.woff?v=282) format('woff'),url(../font/iconfont.ttf?v=282) format('truetype'),url(../font/iconfont.svg?v=282#layui-icon) format('svg')}.layui-icon{font-family:layui-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-icon-leaf:before{content:"\e701"}.layui-icon-folder:before{content:"\eabe"}.layui-icon-folder-open:before{content:"\eac1"}.layui-icon-gitee:before{content:"\e69b"}.layui-icon-github:before{content:"\e6a7"}.layui-icon-disabled:before{content:"\e6cc"}.layui-icon-moon:before{content:"\e6c2"}.layui-icon-error:before{content:"\e693"}.layui-icon-success:before{content:"\e697"}.layui-icon-question:before{content:"\e699"}.layui-icon-lock:before{content:"\e69a"}.layui-icon-eye:before{content:"\e695"}.layui-icon-eye-invisible:before{content:"\e696"}.layui-icon-backspace:before{content:"\e694"}.layui-icon-tips-fill:before{content:"\eb2e"}.layui-icon-test:before{content:"\e692"}.layui-icon-clear:before{content:"\e788"}.layui-icon-heart-fill:before{content:"\e68f"}.layui-icon-light:before{content:"\e748"}.layui-icon-music:before{content:"\e690"}.layui-icon-time:before{content:"\e68d"}.layui-icon-ie:before{content:"\e7bb"}.layui-icon-firefox:before{content:"\e686"}.layui-icon-at:before{content:"\e687"}.layui-icon-bluetooth:before{content:"\e689"}.layui-icon-chrome:before{content:"\e68a"}.layui-icon-edge:before{content:"\e68b"}.layui-icon-heart:before{content:"\e68c"}.layui-icon-key:before{content:"\e683"}.layui-icon-android:before{content:"\e684"}.layui-icon-mike:before{content:"\e6dc"}.layui-icon-mute:before{content:"\e685"}.layui-icon-gift:before{content:"\e627"}.layui-icon-windows:before{content:"\e67f"}.layui-icon-ios:before{content:"\e680"}.layui-icon-logout:before{content:"\e682"}.layui-icon-wifi:before{content:"\e7e0"}.layui-icon-rss:before{content:"\e808"}.layui-icon-email:before{content:"\e618"}.layui-icon-reduce-circle:before{content:"\e616"}.layui-icon-transfer:before{content:"\e691"}.layui-icon-service:before{content:"\e626"}.layui-icon-addition:before{content:"\e624"}.layui-icon-subtraction:before{content:"\e67e"}.layui-icon-slider:before{content:"\e714"}.layui-icon-print:before{content:"\e66d"}.layui-icon-export:before{content:"\e67d"}.layui-icon-cols:before{content:"\e610"}.layui-icon-screen-full:before{content:"\e622"}.layui-icon-screen-restore:before{content:"\e758"}.layui-icon-rate-half:before{content:"\e6c9"}.layui-icon-rate-solid:before{content:"\e67a"}.layui-icon-rate:before{content:"\e67b"}.layui-icon-cellphone:before{content:"\e678"}.layui-icon-vercode:before{content:"\e679"}.layui-icon-login-weibo:before{content:"\e675"}.layui-icon-login-qq:before{content:"\e676"}.layui-icon-login-wechat:before{content:"\e677"}.layui-icon-username:before{content:"\e66f"}.layui-icon-password:before{content:"\e673"}.layui-icon-refresh-3:before{content:"\e9aa"}.layui-icon-auz:before{content:"\e672"}.layui-icon-shrink-right:before{content:"\e668"}.layui-icon-spread-left:before{content:"\e66b"}.layui-icon-snowflake:before{content:"\e6b1"}.layui-icon-tips:before{content:"\e702"}.layui-icon-note:before{content:"\e66e"}.layui-icon-senior:before{content:"\e674"}.layui-icon-refresh-1:before{content:"\e666"}.layui-icon-refresh:before{content:"\e669"}.layui-icon-flag:before{content:"\e66c"}.layui-icon-theme:before{content:"\e66a"}.layui-icon-notice:before{content:"\e667"}.layui-icon-console:before{content:"\e665"}.layui-icon-website:before{content:"\e7ae"}.layui-icon-face-surprised:before{content:"\e664"}.layui-icon-set:before{content:"\e716"}.layui-icon-template:before{content:"\e663"}.layui-icon-app:before{content:"\e653"}.layui-icon-template-1:before{content:"\e656"}.layui-icon-home:before{content:"\e68e"}.layui-icon-female:before{content:"\e661"}.layui-icon-male:before{content:"\e662"}.layui-icon-tread:before{content:"\e6c5"}.layui-icon-praise:before{content:"\e6c6"}.layui-icon-rmb:before{content:"\e65e"}.layui-icon-more:before{content:"\e65f"}.layui-icon-camera:before{content:"\e660"}.layui-icon-cart-simple:before{content:"\e698"}.layui-icon-face-cry:before{content:"\e69c"}.layui-icon-face-smile:before{content:"\e6af"}.layui-icon-survey:before{content:"\e6b2"}.layui-icon-read:before{content:"\e705"}.layui-icon-location:before{content:"\e715"}.layui-icon-dollar:before{content:"\e659"}.layui-icon-diamond:before{content:"\e735"}.layui-icon-return:before{content:"\e65c"}.layui-icon-camera-fill:before{content:"\e65d"}.layui-icon-fire:before{content:"\e756"}.layui-icon-more-vertical:before{content:"\e671"}.layui-icon-cart:before{content:"\e657"}.layui-icon-star-fill:before{content:"\e658"}.layui-icon-prev:before{content:"\e65a"}.layui-icon-next:before{content:"\e65b"}.layui-icon-upload:before{content:"\e67c"}.layui-icon-upload-drag:before{content:"\e681"}.layui-icon-user:before{content:"\e770"}.layui-icon-file-b:before{content:"\e655"}.layui-icon-component:before{content:"\e857"}.layui-icon-find-fill:before{content:"\e670"}.layui-icon-loading:before{content:"\e63d"}.layui-icon-loading-1:before{content:"\e63e"}.layui-icon-add-1:before{content:"\e654"}.layui-icon-pause:before{content:"\e651"}.layui-icon-play:before{content:"\e652"}.layui-icon-video:before{content:"\e6ed"}.layui-icon-headset:before{content:"\e6fc"}.layui-icon-voice:before{content:"\e688"}.layui-icon-speaker:before{content:"\e645"}.layui-icon-fonts-del:before{content:"\e64f"}.layui-icon-fonts-html:before{content:"\e64b"}.layui-icon-fonts-code:before{content:"\e64e"}.layui-icon-fonts-strong:before{content:"\e62b"}.layui-icon-unlink:before{content:"\e64d"}.layui-icon-picture:before{content:"\e64a"}.layui-icon-link:before{content:"\e64c"}.layui-icon-face-smile-b:before{content:"\e650"}.layui-icon-align-center:before{content:"\e647"}.layui-icon-align-right:before{content:"\e648"}.layui-icon-align-left:before{content:"\e649"}.layui-icon-fonts-u:before{content:"\e646"}.layui-icon-fonts-i:before{content:"\e644"}.layui-icon-tabs:before{content:"\e62a"}.layui-icon-circle:before{content:"\e63f"}.layui-icon-radio:before{content:"\e643"}.layui-icon-share:before{content:"\e641"}.layui-icon-edit:before{content:"\e642"}.layui-icon-delete:before{content:"\e640"}.layui-icon-engine:before{content:"\e628"}.layui-icon-chart-screen:before{content:"\e629"}.layui-icon-chart:before{content:"\e62c"}.layui-icon-table:before{content:"\e62d"}.layui-icon-tree:before{content:"\e62e"}.layui-icon-upload-circle:before{content:"\e62f"}.layui-icon-templeate-1:before{content:"\e630"}.layui-icon-util:before{content:"\e631"}.layui-icon-layouts:before{content:"\e632"}.layui-icon-prev-circle:before{content:"\e633"}.layui-icon-carousel:before{content:"\e634"}.layui-icon-code-circle:before{content:"\e635"}.layui-icon-water:before{content:"\e636"}.layui-icon-date:before{content:"\e637"}.layui-icon-layer:before{content:"\e638"}.layui-icon-fonts-clear:before{content:"\e639"}.layui-icon-dialogue:before{content:"\e63a"}.layui-icon-cellphone-fine:before{content:"\e63b"}.layui-icon-form:before{content:"\e63c"}.layui-icon-file:before{content:"\e621"}.layui-icon-triangle-r:before{content:"\e623"}.layui-icon-triangle-d:before{content:"\e625"}.layui-icon-set-sm:before{content:"\e620"}.layui-icon-add-circle:before{content:"\e61f"}.layui-icon-layim-download:before{content:"\e61e"}.layui-icon-layim-uploadfile:before{content:"\e61d"}.layui-icon-404:before{content:"\e61c"}.layui-icon-about:before{content:"\e60b"}.layui-icon-layim-theme:before{content:"\e61b"}.layui-icon-down:before{content:"\e61a"}.layui-icon-up:before{content:"\e619"}.layui-icon-circle-dot:before{content:"\e617"}.layui-icon-set-fill:before{content:"\e614"}.layui-icon-search:before{content:"\e615"}.layui-icon-friends:before{content:"\e612"}.layui-icon-group:before{content:"\e613"}.layui-icon-reply-fill:before{content:"\e611"}.layui-icon-menu-fill:before{content:"\e60f"}.layui-icon-face-smile-fine:before{content:"\e60c"}.layui-icon-picture-fine:before{content:"\e60d"}.layui-icon-log:before{content:"\e60e"}.layui-icon-list:before{content:"\e60a"}.layui-icon-release:before{content:"\e609"}.layui-icon-add-circle-fine:before{content:"\e608"}.layui-icon-ok:before{content:"\e605"}.layui-icon-help:before{content:"\e607"}.layui-icon-chat:before{content:"\e606"}.layui-icon-top:before{content:"\e604"}.layui-icon-right:before{content:"\e602"}.layui-icon-left:before{content:"\e603"}.layui-icon-star:before{content:"\e600"}.layui-icon-download-circle:before{content:"\e601"}.layui-icon-close:before{content:"\1006"}.layui-icon-close-fill:before{content:"\1007"}.layui-icon-ok-circle:before{content:"\1005"}.layui-main{position:relative;width:1160px;margin:0 auto}.layui-header{position:relative;z-index:1000;height:60px}.layui-header a:hover{transition:all .5s;-webkit-transition:all .5s}.layui-side{position:fixed;left:0;top:0;bottom:0;z-index:999;width:200px;overflow-x:hidden}.layui-side-scroll{position:relative;width:220px;height:100%;overflow-x:hidden}.layui-body{position:relative;left:200px;right:0;top:0;bottom:0;z-index:900;width:auto;box-sizing:border-box}.layui-layout-body{overflow-x:hidden}.layui-layout-admin .layui-header{position:fixed;top:0;left:0;right:0;background-color:#23292e}.layui-layout-admin .layui-side{top:60px;width:200px;overflow-x:hidden}.layui-layout-admin .layui-body{position:absolute;top:60px;padding-bottom:44px}.layui-layout-admin .layui-main{width:auto;margin:0 15px}.layui-layout-admin .layui-footer{position:fixed;left:200px;right:0;bottom:0;z-index:990;height:44px;line-height:44px;padding:0 15px;box-shadow:-1px 0 4px rgb(0 0 0 / 12%);background-color:#fafafa}.layui-layout-admin .layui-logo{position:absolute;left:0;top:0;width:200px;height:100%;line-height:60px;text-align:center;color:#16baaa;font-size:16px;box-shadow:0 1px 2px 0 rgb(0 0 0 / 15%)}.layui-layout-admin .layui-header .layui-nav{background:0 0}.layui-layout-left{position:absolute!important;left:200px;top:0}.layui-layout-right{position:absolute!important;right:0;top:0}.layui-container{position:relative;margin:0 auto;box-sizing:border-box}.layui-fluid{position:relative;margin:0 auto;padding:0 15px}.layui-row:after,.layui-row:before{content:"";display:block;clear:both}.layui-col-lg1,.layui-col-lg10,.layui-col-lg11,.layui-col-lg12,.layui-col-lg2,.layui-col-lg3,.layui-col-lg4,.layui-col-lg5,.layui-col-lg6,.layui-col-lg7,.layui-col-lg8,.layui-col-lg9,.layui-col-md1,.layui-col-md10,.layui-col-md11,.layui-col-md12,.layui-col-md2,.layui-col-md3,.layui-col-md4,.layui-col-md5,.layui-col-md6,.layui-col-md7,.layui-col-md8,.layui-col-md9,.layui-col-sm1,.layui-col-sm10,.layui-col-sm11,.layui-col-sm12,.layui-col-sm2,.layui-col-sm3,.layui-col-sm4,.layui-col-sm5,.layui-col-sm6,.layui-col-sm7,.layui-col-sm8,.layui-col-sm9,.layui-col-xl1,.layui-col-xl10,.layui-col-xl11,.layui-col-xl12,.layui-col-xl2,.layui-col-xl3,.layui-col-xl4,.layui-col-xl5,.layui-col-xl6,.layui-col-xl7,.layui-col-xl8,.layui-col-xl9,.layui-col-xs1,.layui-col-xs10,.layui-col-xs11,.layui-col-xs12,.layui-col-xs2,.layui-col-xs3,.layui-col-xs4,.layui-col-xs5,.layui-col-xs6,.layui-col-xs7,.layui-col-xs8,.layui-col-xs9{position:relative;display:block;box-sizing:border-box}.layui-col-xs1,.layui-col-xs10,.layui-col-xs11,.layui-col-xs12,.layui-col-xs2,.layui-col-xs3,.layui-col-xs4,.layui-col-xs5,.layui-col-xs6,.layui-col-xs7,.layui-col-xs8,.layui-col-xs9{float:left}.layui-col-xs1{width:8.33333333%}.layui-col-xs2{width:16.66666667%}.layui-col-xs3{width:25%}.layui-col-xs4{width:33.33333333%}.layui-col-xs5{width:41.66666667%}.layui-col-xs6{width:50%}.layui-col-xs7{width:58.33333333%}.layui-col-xs8{width:66.66666667%}.layui-col-xs9{width:75%}.layui-col-xs10{width:83.33333333%}.layui-col-xs11{width:91.66666667%}.layui-col-xs12{width:100%}.layui-col-xs-offset1{margin-left:8.33333333%}.layui-col-xs-offset2{margin-left:16.66666667%}.layui-col-xs-offset3{margin-left:25%}.layui-col-xs-offset4{margin-left:33.33333333%}.layui-col-xs-offset5{margin-left:41.66666667%}.layui-col-xs-offset6{margin-left:50%}.layui-col-xs-offset7{margin-left:58.33333333%}.layui-col-xs-offset8{margin-left:66.66666667%}.layui-col-xs-offset9{margin-left:75%}.layui-col-xs-offset10{margin-left:83.33333333%}.layui-col-xs-offset11{margin-left:91.66666667%}.layui-col-xs-offset12{margin-left:100%}@media screen and (max-width:767.98px){.layui-container{padding:0 15px}.layui-hide-xs{display:none!important}.layui-show-xs-block{display:block!important}.layui-show-xs-inline{display:inline!important}.layui-show-xs-inline-block{display:inline-block!important}}@media screen and (min-width:768px){.layui-container{width:720px}.layui-hide-sm{display:none!important}.layui-show-sm-block{display:block!important}.layui-show-sm-inline{display:inline!important}.layui-show-sm-inline-block{display:inline-block!important}.layui-col-sm1,.layui-col-sm10,.layui-col-sm11,.layui-col-sm12,.layui-col-sm2,.layui-col-sm3,.layui-col-sm4,.layui-col-sm5,.layui-col-sm6,.layui-col-sm7,.layui-col-sm8,.layui-col-sm9{float:left}.layui-col-sm1{width:8.33333333%}.layui-col-sm2{width:16.66666667%}.layui-col-sm3{width:25%}.layui-col-sm4{width:33.33333333%}.layui-col-sm5{width:41.66666667%}.layui-col-sm6{width:50%}.layui-col-sm7{width:58.33333333%}.layui-col-sm8{width:66.66666667%}.layui-col-sm9{width:75%}.layui-col-sm10{width:83.33333333%}.layui-col-sm11{width:91.66666667%}.layui-col-sm12{width:100%}.layui-col-sm-offset1{margin-left:8.33333333%}.layui-col-sm-offset2{margin-left:16.66666667%}.layui-col-sm-offset3{margin-left:25%}.layui-col-sm-offset4{margin-left:33.33333333%}.layui-col-sm-offset5{margin-left:41.66666667%}.layui-col-sm-offset6{margin-left:50%}.layui-col-sm-offset7{margin-left:58.33333333%}.layui-col-sm-offset8{margin-left:66.66666667%}.layui-col-sm-offset9{margin-left:75%}.layui-col-sm-offset10{margin-left:83.33333333%}.layui-col-sm-offset11{margin-left:91.66666667%}.layui-col-sm-offset12{margin-left:100%}}@media screen and (min-width:992px){.layui-container{width:960px}.layui-hide-md{display:none!important}.layui-show-md-block{display:block!important}.layui-show-md-inline{display:inline!important}.layui-show-md-inline-block{display:inline-block!important}.layui-col-md1,.layui-col-md10,.layui-col-md11,.layui-col-md12,.layui-col-md2,.layui-col-md3,.layui-col-md4,.layui-col-md5,.layui-col-md6,.layui-col-md7,.layui-col-md8,.layui-col-md9{float:left}.layui-col-md1{width:8.33333333%}.layui-col-md2{width:16.66666667%}.layui-col-md3{width:25%}.layui-col-md4{width:33.33333333%}.layui-col-md5{width:41.66666667%}.layui-col-md6{width:50%}.layui-col-md7{width:58.33333333%}.layui-col-md8{width:66.66666667%}.layui-col-md9{width:75%}.layui-col-md10{width:83.33333333%}.layui-col-md11{width:91.66666667%}.layui-col-md12{width:100%}.layui-col-md-offset1{margin-left:8.33333333%}.layui-col-md-offset2{margin-left:16.66666667%}.layui-col-md-offset3{margin-left:25%}.layui-col-md-offset4{margin-left:33.33333333%}.layui-col-md-offset5{margin-left:41.66666667%}.layui-col-md-offset6{margin-left:50%}.layui-col-md-offset7{margin-left:58.33333333%}.layui-col-md-offset8{margin-left:66.66666667%}.layui-col-md-offset9{margin-left:75%}.layui-col-md-offset10{margin-left:83.33333333%}.layui-col-md-offset11{margin-left:91.66666667%}.layui-col-md-offset12{margin-left:100%}}@media screen and (min-width:1200px){.layui-container{width:1150px}.layui-hide-lg{display:none!important}.layui-show-lg-block{display:block!important}.layui-show-lg-inline{display:inline!important}.layui-show-lg-inline-block{display:inline-block!important}.layui-col-lg1,.layui-col-lg10,.layui-col-lg11,.layui-col-lg12,.layui-col-lg2,.layui-col-lg3,.layui-col-lg4,.layui-col-lg5,.layui-col-lg6,.layui-col-lg7,.layui-col-lg8,.layui-col-lg9{float:left}.layui-col-lg1{width:8.33333333%}.layui-col-lg2{width:16.66666667%}.layui-col-lg3{width:25%}.layui-col-lg4{width:33.33333333%}.layui-col-lg5{width:41.66666667%}.layui-col-lg6{width:50%}.layui-col-lg7{width:58.33333333%}.layui-col-lg8{width:66.66666667%}.layui-col-lg9{width:75%}.layui-col-lg10{width:83.33333333%}.layui-col-lg11{width:91.66666667%}.layui-col-lg12{width:100%}.layui-col-lg-offset1{margin-left:8.33333333%}.layui-col-lg-offset2{margin-left:16.66666667%}.layui-col-lg-offset3{margin-left:25%}.layui-col-lg-offset4{margin-left:33.33333333%}.layui-col-lg-offset5{margin-left:41.66666667%}.layui-col-lg-offset6{margin-left:50%}.layui-col-lg-offset7{margin-left:58.33333333%}.layui-col-lg-offset8{margin-left:66.66666667%}.layui-col-lg-offset9{margin-left:75%}.layui-col-lg-offset10{margin-left:83.33333333%}.layui-col-lg-offset11{margin-left:91.66666667%}.layui-col-lg-offset12{margin-left:100%}}@media screen and (min-width:1400px){.layui-container{width:1330px}.layui-hide-xl{display:none!important}.layui-show-xl-block{display:block!important}.layui-show-xl-inline{display:inline!important}.layui-show-xl-inline-block{display:inline-block!important}.layui-col-xl1,.layui-col-xl10,.layui-col-xl11,.layui-col-xl12,.layui-col-xl2,.layui-col-xl3,.layui-col-xl4,.layui-col-xl5,.layui-col-xl6,.layui-col-xl7,.layui-col-xl8,.layui-col-xl9{float:left}.layui-col-xl1{width:8.33333333%}.layui-col-xl2{width:16.66666667%}.layui-col-xl3{width:25%}.layui-col-xl4{width:33.33333333%}.layui-col-xl5{width:41.66666667%}.layui-col-xl6{width:50%}.layui-col-xl7{width:58.33333333%}.layui-col-xl8{width:66.66666667%}.layui-col-xl9{width:75%}.layui-col-xl10{width:83.33333333%}.layui-col-xl11{width:91.66666667%}.layui-col-xl12{width:100%}.layui-col-xl-offset1{margin-left:8.33333333%}.layui-col-xl-offset2{margin-left:16.66666667%}.layui-col-xl-offset3{margin-left:25%}.layui-col-xl-offset4{margin-left:33.33333333%}.layui-col-xl-offset5{margin-left:41.66666667%}.layui-col-xl-offset6{margin-left:50%}.layui-col-xl-offset7{margin-left:58.33333333%}.layui-col-xl-offset8{margin-left:66.66666667%}.layui-col-xl-offset9{margin-left:75%}.layui-col-xl-offset10{margin-left:83.33333333%}.layui-col-xl-offset11{margin-left:91.66666667%}.layui-col-xl-offset12{margin-left:100%}}.layui-col-space1{margin:-.5px}.layui-col-space1>*{padding:.5px}.layui-col-space2{margin:-1px}.layui-col-space2>*{padding:1px}.layui-col-space4{margin:-2px}.layui-col-space4>*{padding:2px}.layui-col-space5{margin:-2.5px}.layui-col-space5>*{padding:2.5px}.layui-col-space6{margin:-3px}.layui-col-space6>*{padding:3px}.layui-col-space8{margin:-4px}.layui-col-space8>*{padding:4px}.layui-col-space10{margin:-5px}.layui-col-space10>*{padding:5px}.layui-col-space12{margin:-6px}.layui-col-space12>*{padding:6px}.layui-col-space14{margin:-7px}.layui-col-space14>*{padding:7px}.layui-col-space15{margin:-7.5px}.layui-col-space15>*{padding:7.5px}.layui-col-space16{margin:-8px}.layui-col-space16>*{padding:8px}.layui-col-space18{margin:-9px}.layui-col-space18>*{padding:9px}.layui-col-space20{margin:-10px}.layui-col-space20>*{padding:10px}.layui-col-space22{margin:-11px}.layui-col-space22>*{padding:11px}.layui-col-space24{margin:-12px}.layui-col-space24>*{padding:12px}.layui-col-space25{margin:-12.5px}.layui-col-space25>*{padding:12.5px}.layui-col-space26{margin:-13px}.layui-col-space26>*{padding:13px}.layui-col-space28{margin:-14px}.layui-col-space28>*{padding:14px}.layui-col-space30{margin:-15px}.layui-col-space30>*{padding:15px}.layui-col-space32{margin:-16px}.layui-col-space32>*{padding:16px}.layui-padding-1{padding:4px!important}.layui-padding-2{padding:8px!important}.layui-padding-3{padding:16px!important}.layui-padding-4{padding:32px!important}.layui-padding-5{padding:48px!important}.layui-margin-1{margin:4px!important}.layui-margin-2{margin:8px!important}.layui-margin-3{margin:16px!important}.layui-margin-4{margin:32px!important}.layui-margin-5{margin:48px!important}.layui-btn,.layui-input,.layui-select,.layui-textarea,.layui-upload-button{outline:0;-webkit-appearance:none;transition:all .3s;-webkit-transition:all .3s;box-sizing:border-box}.layui-elem-quote{margin-bottom:10px;padding:15px;line-height:1.8;border-left:5px solid #16b777;border-radius:0 2px 2px 0;background-color:#fafafa}.layui-quote-nm{border-style:solid;border-width:1px;border-left-width:5px;background:0 0}.layui-elem-field{margin-bottom:10px;padding:0;border-width:1px;border-style:solid}.layui-elem-field legend{margin-left:20px;padding:0 10px;font-size:20px}.layui-field-title{margin:16px 0;border-width:0;border-top-width:1px}.layui-field-box{padding:15px}.layui-field-title .layui-field-box{padding:10px 0}.layui-progress{position:relative;height:6px;border-radius:20px;background-color:#eee}.layui-progress-bar{position:absolute;left:0;top:0;width:0;max-width:100%;height:6px;border-radius:20px;text-align:right;background-color:#16b777;transition:all .3s;-webkit-transition:all .3s}.layui-progress-big,.layui-progress-big .layui-progress-bar{height:18px;line-height:18px}.layui-progress-text{position:relative;top:-20px;line-height:18px;font-size:12px;color:#5f5f5f}.layui-progress-big .layui-progress-text{position:static;padding:0 10px;color:#fff}.layui-collapse{border-width:1px;border-style:solid;border-radius:2px}.layui-colla-content,.layui-colla-item{border-top-width:1px;border-top-style:solid}.layui-colla-item:first-child{border-top:none}.layui-colla-title{position:relative;height:42px;line-height:42px;padding:0 15px 0 35px;color:#333;background-color:#fafafa;cursor:pointer;font-size:14px;overflow:hidden}.layui-colla-content{display:none;padding:10px 15px;line-height:1.6;color:#5f5f5f}.layui-colla-icon{position:absolute;left:15px;top:0;font-size:14px}.layui-card{margin-bottom:15px;border-radius:2px;background-color:#fff;box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.layui-card:last-child{margin-bottom:0}.layui-card-header{position:relative;height:42px;line-height:42px;padding:0 15px;border-bottom:1px solid #f8f8f8;color:#333;border-radius:2px 2px 0 0;font-size:14px}.layui-card-body{position:relative;padding:10px 15px;line-height:24px}.layui-card-body[pad15]{padding:15px}.layui-card-body[pad20]{padding:20px}.layui-card-body .layui-table{margin:5px 0}.layui-card .layui-tab{margin:0}.layui-panel{position:relative;border-width:1px;border-style:solid;border-radius:2px;box-shadow:1px 1px 4px rgb(0 0 0 / 8%);background-color:#fff;color:#5f5f5f}.layui-panel-window{position:relative;padding:15px;border-radius:0;border-top:5px solid #eee;background-color:#fff}.layui-auxiliar-moving{position:fixed;left:0;right:0;top:0;bottom:0;width:100%;height:100%;background:0 0;z-index:9999999999;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.layui-scrollbar-hide{overflow:hidden!important}.layui-bg-red{background-color:#ff5722!important;color:#fff!important}.layui-bg-orange{background-color:#ffb800!important;color:#fff!important}.layui-bg-green{background-color:#16baaa!important;color:#fff!important}.layui-bg-cyan{background-color:#2f4056!important;color:#fff!important}.layui-bg-blue{background-color:#1e9fff!important;color:#fff!important}.layui-bg-purple{background-color:#a233c6!important;color:#fff!important}.layui-bg-black{background-color:#2f363c!important;color:#fff!important}.layui-bg-gray{background-color:#fafafa!important;color:#5f5f5f!important}.layui-badge-rim,.layui-border,.layui-colla-content,.layui-colla-item,.layui-collapse,.layui-elem-field,.layui-form-pane .layui-form-item[pane],.layui-form-pane .layui-form-label,.layui-input,.layui-input-split,.layui-panel,.layui-quote-nm,.layui-select,.layui-tab-bar,.layui-tab-card,.layui-tab-title,.layui-tab-title .layui-this:after,.layui-textarea{border-color:#eee}.layui-border{border-width:1px;border-style:solid;color:#5f5f5f!important}.layui-border-red{border-width:1px;border-style:solid;border-color:#ff5722!important;color:#ff5722!important}.layui-border-orange{border-width:1px;border-style:solid;border-color:#ffb800!important;color:#ffb800!important}.layui-border-green{border-width:1px;border-style:solid;border-color:#16baaa!important;color:#16baaa!important}.layui-border-cyan{border-width:1px;border-style:solid;border-color:#2f4056!important;color:#2f4056!important}.layui-border-blue{border-width:1px;border-style:solid;border-color:#1e9fff!important;color:#1e9fff!important}.layui-border-purple{border-width:1px;border-style:solid;border-color:#a233c6!important;color:#a233c6!important}.layui-border-black{border-width:1px;border-style:solid;border-color:#2f363c!important;color:#2f363c!important}hr.layui-border-black,hr.layui-border-blue,hr.layui-border-cyan,hr.layui-border-green,hr.layui-border-orange,hr.layui-border-purple,hr.layui-border-red{border-width:0 0 1px}.layui-timeline-item:before{background-color:#eee}.layui-text{line-height:1.8;font-size:14px}.layui-text h1,.layui-text h2,.layui-text h3,.layui-text h4,.layui-text h5,.layui-text h6{color:#3a3a3a}.layui-text h1{font-size:32px}.layui-text h2{font-size:24px}.layui-text h3{font-size:18px}.layui-text h4{font-size:16px}.layui-text h5{font-size:14px}.layui-text h6{font-size:13px}.layui-text ol,.layui-text ul{padding-left:15px}.layui-text ul li{margin-top:5px;list-style-type:disc}.layui-text ol li{margin-top:5px;list-style-type:decimal}.layui-text-em,.layui-word-aux{color:#999!important;padding-left:5px!important;padding-right:5px!important}.layui-text p{margin:15px 0}.layui-text p:first-child{margin-top:0}.layui-text p:last-child{margin-bottom:0}.layui-text a:not(.layui-btn){color:#01aaed}.layui-text a:not(.layui-btn):hover{text-decoration:underline}.layui-text blockquote:not(.layui-elem-quote){padding:5px 15px;border-left:5px solid #eee}.layui-text pre>code:not(.layui-code){padding:15px;font-family:"Courier New",Consolas,"Lucida Console"}.layui-font-12{font-size:12px!important}.layui-font-13{font-size:13px!important}.layui-font-14{font-size:14px!important}.layui-font-16{font-size:16px!important}.layui-font-18{font-size:18px!important}.layui-font-20{font-size:20px!important}.layui-font-22{font-size:22px!important}.layui-font-24{font-size:24px!important}.layui-font-26{font-size:26px!important}.layui-font-28{font-size:28px!important}.layui-font-30{font-size:30px!important}.layui-font-32{font-size:32px!important}.layui-font-red{color:#ff5722!important}.layui-font-orange{color:#ffb800!important}.layui-font-green{color:#16baaa!important}.layui-font-cyan{color:#2f4056!important}.layui-font-blue{color:#01aaed!important}.layui-font-purple{color:#a233c6!important}.layui-font-black{color:#000!important}.layui-font-gray{color:#c2c2c2!important}.layui-btn{display:inline-block;vertical-align:middle;height:38px;line-height:38px;border:1px solid transparent;padding:0 18px;background-color:#16baaa;color:#fff;white-space:nowrap;text-align:center;font-size:14px;border-radius:2px;cursor:pointer;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-btn:hover{opacity:.8;filter:alpha(opacity=80);color:#fff}.layui-btn:active{opacity:1;filter:alpha(opacity=100)}.layui-btn+.layui-btn{margin-left:10px}.layui-btn-container{word-spacing:-5px}.layui-btn-container .layui-btn{margin-right:10px;margin-bottom:10px;word-spacing:normal}.layui-btn-container .layui-btn+.layui-btn{margin-left:0}.layui-table .layui-btn-container .layui-btn{margin-bottom:9px}.layui-btn-radius{border-radius:100px}.layui-btn .layui-icon{padding:0 2px;vertical-align:middle\0;vertical-align:bottom}.layui-btn-primary{border-color:#d2d2d2;background:0 0;color:#5f5f5f}.layui-btn-primary:hover{border-color:#16baaa;color:#333}.layui-btn-normal{background-color:#1e9fff}.layui-btn-warm{background-color:#ffb800}.layui-btn-danger{background-color:#ff5722}.layui-btn-checked{background-color:#16b777}.layui-btn-disabled,.layui-btn-disabled:active,.layui-btn-disabled:hover{border-color:#eee!important;background-color:#fbfbfb!important;color:#d2d2d2!important;cursor:not-allowed!important;opacity:1}.layui-btn-lg{height:44px;line-height:44px;padding:0 25px;font-size:16px}.layui-btn-sm{height:30px;line-height:30px;padding:0 10px;font-size:12px}.layui-btn-xs{height:22px;line-height:22px;padding:0 5px;font-size:12px}.layui-btn-xs i{font-size:12px!important}.layui-btn-group{display:inline-block;vertical-align:middle;font-size:0}.layui-btn-group .layui-btn{margin-left:0!important;margin-right:0!important;border-left:1px solid rgba(255,255,255,.5);border-radius:0}.layui-btn-group .layui-btn-primary{border-left:none}.layui-btn-group .layui-btn-primary:hover{border-color:#d2d2d2;color:#16baaa}.layui-btn-group .layui-btn:first-child{border-left:none;border-radius:2px 0 0 2px}.layui-btn-group .layui-btn-primary:first-child{border-left:1px solid #d2d2d2}.layui-btn-group .layui-btn:last-child{border-radius:0 2px 2px 0}.layui-btn-group .layui-btn+.layui-btn{margin-left:0}.layui-btn-group+.layui-btn-group{margin-left:10px}.layui-btn-fluid{width:100%}.layui-input,.layui-select,.layui-textarea{height:38px;line-height:1.3;line-height:38px\9;border-width:1px;border-style:solid;background-color:#fff;color:rgba(0,0,0,.85);border-radius:2px}.layui-input::-webkit-input-placeholder,.layui-select::-webkit-input-placeholder,.layui-textarea::-webkit-input-placeholder{line-height:1.3}.layui-input,.layui-textarea{display:block;width:100%;padding-left:10px}.layui-input:hover,.layui-textarea:hover{border-color:#d2d2d2!important}.layui-input:focus,.layui-textarea:focus{border-color:#16b777!important;box-shadow:0 0 0 3px rgba(22,183,119,.08)}.layui-textarea{position:relative;min-height:100px;height:auto;line-height:20px;padding:6px 10px;resize:vertical}.layui-input[disabled],.layui-textarea[disabled]{background-color:#fafafa}.layui-select{padding:0 10px}.layui-form input[type=checkbox],.layui-form input[type=radio],.layui-form select{display:none}.layui-form [lay-ignore]{display:initial}.layui-form-item{position:relative;margin-bottom:15px;clear:both;*zoom:1}.layui-form-item:after{content:'\20';clear:both;*zoom:1;display:block;height:0}.layui-form-label{position:relative;float:left;display:block;padding:9px 15px;width:80px;font-weight:400;line-height:20px;text-align:right}.layui-form-label-col{display:block;float:none;padding:9px 0;line-height:20px;text-align:left}.layui-form-item .layui-inline{margin-bottom:5px;margin-right:10px}.layui-input-block,.layui-input-inline{position:relative}.layui-input-block{margin-left:110px;min-height:36px}.layui-input-inline{display:inline-block;vertical-align:middle}.layui-form-item .layui-input-inline{float:left;width:190px;margin-right:10px}.layui-form-text .layui-input-inline{width:auto}.layui-form-mid{position:relative;float:left;display:block;padding:9px 0!important;line-height:20px;margin-right:10px}.layui-form-danger+.layui-form-select .layui-input,.layui-form-danger:focus{border-color:#ff5722!important;box-shadow:0 0 0 3px rgba(255,87,34,.08)}.layui-input-prefix,.layui-input-split,.layui-input-suffix,.layui-input-suffix .layui-input-affix{position:absolute;right:0;top:0;padding:0 10px;width:35px;height:100%;text-align:center;transition:all .3s;box-sizing:border-box}.layui-input-prefix{left:0;border-radius:2px 0 0 2px}.layui-input-suffix{right:0;border-radius:0 2px 2px 0}.layui-input-split{border-width:1px;border-style:solid}.layui-input-prefix .layui-icon,.layui-input-split .layui-icon,.layui-input-suffix .layui-icon{position:relative;font-size:16px;color:#5f5f5f;transition:all .3s}.layui-input-group{position:relative;display:table;box-sizing:border-box}.layui-input-group>*{display:table-cell;vertical-align:middle;position:relative}.layui-input-group .layui-input{padding-right:15px}.layui-input-group>.layui-input-prefix{width:auto;border-right:0}.layui-input-group>.layui-input-suffix{width:auto;border-left:0}.layui-input-group .layui-input-split{white-space:nowrap}.layui-input-wrap{position:relative;line-height:38px}.layui-input-wrap .layui-input{padding-right:35px}.layui-input-wrap .layui-input::-ms-clear,.layui-input-wrap .layui-input::-ms-reveal{display:none}.layui-input-wrap .layui-input-prefix+.layui-input,.layui-input-wrap .layui-input-prefix~* .layui-input{padding-left:35px}.layui-input-wrap .layui-input-split+.layui-input,.layui-input-wrap .layui-input-split~* .layui-input{padding-left:45px}.layui-input-wrap .layui-input-prefix~.layui-form-select{position:static}.layui-input-wrap .layui-input-prefix,.layui-input-wrap .layui-input-split,.layui-input-wrap .layui-input-suffix{pointer-events:none}.layui-input-wrap .layui-input:hover+.layui-input-split{border-color:#d2d2d2}.layui-input-wrap .layui-input:focus+.layui-input-split{border-color:#16b777}.layui-input-wrap .layui-input.layui-form-danger:focus+.layui-input-split{border-color:#ff5722}.layui-input-wrap .layui-input-prefix.layui-input-split{border-width:0;border-right-width:1px}.layui-input-wrap .layui-input-suffix.layui-input-split{border-width:0;border-left-width:1px}.layui-input-affix{line-height:38px}.layui-input-suffix .layui-input-affix{right:auto;left:-35px}.layui-input-affix .layui-icon{color:rgba(0,0,0,.8);pointer-events:auto!important;cursor:pointer}.layui-input-affix .layui-icon-clear{color:rgba(0,0,0,.3)}.layui-input-affix .layui-icon:hover{color:rgba(0,0,0,.6)}.layui-input-wrap .layui-input-number{width:24px;padding:0}.layui-input-wrap .layui-input-number .layui-icon{position:absolute;right:0;width:100%;height:50%;line-height:normal;font-size:12px}.layui-input-wrap .layui-input-number .layui-icon:before{position:absolute;left:50%;top:50%;margin-top:-6px;margin-left:-6px}.layui-input-wrap .layui-input-number .layui-icon-up{top:0;border-bottom:1px solid #eee}.layui-input-wrap .layui-input-number .layui-icon-down{bottom:0}.layui-input-wrap .layui-input-number .layui-icon:hover{font-weight:700}.layui-input-wrap .layui-input[type=number]::-webkit-inner-spin-button,.layui-input-wrap .layui-input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none!important}.layui-input-wrap .layui-input[type=number]{-moz-appearance:textfield}.layui-input-wrap .layui-input[type=number].layui-input-number-out-of-range{color:#ff5722}.layui-form-select{position:relative;color:#5f5f5f}.layui-form-select .layui-input{padding-right:30px;cursor:pointer}.layui-form-select .layui-edge{position:absolute;right:10px;top:50%;margin-top:-3px;cursor:pointer;border-width:6px;border-top-color:#c2c2c2;border-top-style:solid;transition:all .3s;-webkit-transition:all .3s}.layui-form-select dl{display:none;position:absolute;left:0;top:42px;padding:5px 0;z-index:899;min-width:100%;border:1px solid #eee;max-height:300px;overflow-y:auto;background-color:#fff;border-radius:2px;box-shadow:1px 1px 4px rgb(0 0 0 / 8%);box-sizing:border-box}.layui-form-select dl dd,.layui-form-select dl dt{padding:0 10px;line-height:36px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.layui-form-select dl dt{font-size:12px;color:#999}.layui-form-select dl dd{cursor:pointer}.layui-form-select dl dd:hover{background-color:#f8f8f8;-webkit-transition:.5s all;transition:.5s all}.layui-form-select .layui-select-group dd{padding-left:20px}.layui-form-select dl dd.layui-select-tips{padding-left:10px!important;color:#999}.layui-form-select dl dd.layui-this{background-color:#f8f8f8;color:#16b777;font-weight:700}.layui-form-select dl dd.layui-disabled{background-color:#fff}.layui-form-selected dl{display:block}.layui-form-selected .layui-edge{margin-top:-9px;-webkit-transform:rotate(180deg);transform:rotate(180deg)}.layui-form-selected .layui-edge{margin-top:-3px\0}:root .layui-form-selected .layui-edge{margin-top:-9px\0/IE9}.layui-form-selectup dl{top:auto;bottom:42px}.layui-select-none{margin:5px 0;text-align:center;color:#999}.layui-select-disabled .layui-disabled{border-color:#eee!important}.layui-select-disabled .layui-edge{border-top-color:#d2d2d2}.layui-form-checkbox{position:relative;display:inline-block;vertical-align:middle;height:30px;line-height:30px;margin-right:10px;padding-right:30px;background-color:#fff;cursor:pointer;font-size:0;-webkit-transition:.1s linear;transition:.1s linear;box-sizing:border-box}.layui-form-checkbox>*{display:inline-block;vertical-align:middle}.layui-form-checkbox>div{padding:0 11px;font-size:14px;border-radius:2px 0 0 2px;background-color:#d2d2d2;color:#fff;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.layui-form-checkbox>div>.layui-icon{line-height:normal}.layui-form-checkbox:hover>div{background-color:#c2c2c2}.layui-form-checkbox>i{position:absolute;right:0;top:0;width:30px;height:100%;border:1px solid #d2d2d2;border-left:none;border-radius:0 2px 2px 0;color:#fff;color:rgba(255,255,255,0);font-size:20px;text-align:center;box-sizing:border-box}.layui-form-checkbox:hover>i{border-color:#c2c2c2;color:#c2c2c2}.layui-form-checked,.layui-form-checked:hover{border-color:#16b777}.layui-form-checked:hover>div,.layui-form-checked>div{background-color:#16b777}.layui-form-checked:hover>i,.layui-form-checked>i{color:#16b777}.layui-form-item .layui-form-checkbox{margin-top:4px}.layui-form-checkbox.layui-checkbox-disabled>div{background-color:#eee!important}.layui-form [lay-checkbox]{display:none}.layui-form-checkbox[lay-skin=primary]{height:auto!important;line-height:normal!important;min-width:18px;min-height:18px;border:none!important;margin-right:0;padding-left:24px;padding-right:0;background:0 0}.layui-form-checkbox[lay-skin=primary]>div{margin-top:-1px;padding-left:0;padding-right:15px;line-height:18px;background:0 0;color:#5f5f5f}.layui-form-checkbox[lay-skin=primary]>i{right:auto;left:0;width:16px;height:16px;line-height:14px;border:1px solid #d2d2d2;font-size:12px;border-radius:2px;background-color:#fff;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-checkbox[lay-skin=primary]:hover>i{border-color:#16b777;color:#fff}.layui-form-checked[lay-skin=primary]>i{border-color:#16b777!important;background-color:#16b777;color:#fff}.layui-checkbox-disabled[lay-skin=primary]>div{background:0 0!important}.layui-form-checked.layui-checkbox-disabled[lay-skin=primary]>i{background:#eee!important;border-color:#eee!important}.layui-checkbox-disabled[lay-skin=primary]:hover>i{border-color:#d2d2d2}.layui-form-item .layui-form-checkbox[lay-skin=primary]{margin-top:10px}.layui-form-checkbox[lay-skin=primary]>.layui-icon-indeterminate{border-color:#16b777}.layui-form-checkbox[lay-skin=primary]>.layui-icon-indeterminate:before{content:'';display:inline-block;vertical-align:middle;position:relative;width:50%;height:1px;margin:-1px auto 0;background-color:#16b777}.layui-form-switch{position:relative;display:inline-block;vertical-align:middle;height:24px;line-height:22px;min-width:44px;padding:0 5px;margin-top:8px;border:1px solid #d2d2d2;border-radius:20px;cursor:pointer;box-sizing:border-box;background-color:#fff;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-switch>i{position:absolute;left:5px;top:3px;width:16px;height:16px;border-radius:20px;background-color:#d2d2d2;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-switch>div{position:relative;top:0;margin-left:21px;padding:0!important;text-align:center!important;color:#999!important;font-style:normal!important;font-size:12px}.layui-form-onswitch{border-color:#16b777;background-color:#16b777}.layui-form-onswitch>i{left:100%;margin-left:-21px;background-color:#fff}.layui-form-onswitch>div{margin-left:0;margin-right:21px;color:#fff!important}.layui-form-checkbox[lay-skin=none] *,.layui-form-radio[lay-skin=none] *{box-sizing:border-box}.layui-form-checkbox[lay-skin=none],.layui-form-radio[lay-skin=none]{position:relative;min-height:20px;margin:0;padding:0;height:auto;line-height:normal}.layui-form-checkbox[lay-skin=none]>div,.layui-form-radio[lay-skin=none]>div{position:relative;top:0;left:0;cursor:pointer;z-index:10;color:inherit;background-color:inherit}.layui-form-checkbox[lay-skin=none]>i,.layui-form-radio[lay-skin=none]>i{display:none}.layui-form-checkbox[lay-skin=none].layui-checkbox-disabled>div,.layui-form-radio[lay-skin=none].layui-radio-disabled>div{cursor:not-allowed}.layui-checkbox-disabled{border-color:#eee!important}.layui-checkbox-disabled>div{color:#c2c2c2!important}.layui-checkbox-disabled>i{border-color:#eee!important}.layui-checkbox-disabled:hover>i{color:#fff!important}.layui-form-radio{display:inline-block;vertical-align:middle;line-height:28px;margin:6px 10px 0 0;padding-right:10px;cursor:pointer;font-size:0}.layui-form-radio>*{display:inline-block;vertical-align:middle;font-size:14px}.layui-form-radio>i{margin-right:8px;font-size:22px;color:#c2c2c2}.layui-form-radio:hover>*,.layui-form-radioed,.layui-form-radioed>i{color:#16b777}.layui-radio-disabled>i{color:#eee!important}.layui-radio-disabled>*{color:#c2c2c2!important}.layui-form [lay-radio]{display:none}.layui-form-pane .layui-form-label{width:110px;padding:8px 15px;height:38px;line-height:20px;border-width:1px;border-style:solid;border-radius:2px 0 0 2px;text-align:center;background-color:#fafafa;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;box-sizing:border-box}.layui-form-pane .layui-input-inline{margin-left:-1px}.layui-form-pane .layui-input-block{margin-left:110px;left:-1px}.layui-form-pane .layui-input{border-radius:0 2px 2px 0}.layui-form-pane .layui-form-text .layui-form-label{float:none;width:100%;border-radius:2px;box-sizing:border-box;text-align:left}.layui-form-pane .layui-form-text .layui-input-inline{display:block;margin:0;top:-1px;clear:both}.layui-form-pane .layui-form-text .layui-input-block{margin:0;left:0;top:-1px}.layui-form-pane .layui-form-text .layui-textarea{min-height:100px;border-radius:0 0 2px 2px}.layui-form-pane .layui-form-checkbox{margin:4px 0 4px 10px}.layui-form-pane .layui-form-radio,.layui-form-pane .layui-form-switch{margin-top:6px;margin-left:10px}.layui-form-pane .layui-form-item[pane]{position:relative;border-width:1px;border-style:solid}.layui-form-pane .layui-form-item[pane] .layui-form-label{position:absolute;left:0;top:0;height:100%;border-width:0;border-right-width:1px}.layui-form-pane .layui-form-item[pane] .layui-input-inline{margin-left:110px}@media screen and (max-width:450px){.layui-form-item .layui-form-label{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-form-item .layui-inline{display:block;margin-right:0;margin-bottom:20px;clear:both}.layui-form-item .layui-inline:after{content:'\20';clear:both;display:block;height:0}.layui-form-item .layui-input-inline{display:block;float:none;left:-3px;width:auto!important;margin:0 0 10px 112px}.layui-form-item .layui-input-inline+.layui-form-mid{margin-left:110px;top:-5px;padding:0}.layui-form-item .layui-form-checkbox{margin-right:5px;margin-bottom:5px}}.layui-laypage{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;margin:10px 0;font-size:0}.layui-laypage>a:first-child,.layui-laypage>a:first-child em{border-radius:2px 0 0 2px}.layui-laypage>a:last-child,.layui-laypage>a:last-child em{border-radius:0 2px 2px 0}.layui-laypage>:first-child{margin-left:0!important}.layui-laypage>:last-child{margin-right:0!important}.layui-laypage a,.layui-laypage button,.layui-laypage input,.layui-laypage select,.layui-laypage span{border:1px solid #eee}.layui-laypage a,.layui-laypage span{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding:0 15px;height:28px;line-height:28px;margin:0 -1px 5px 0;background-color:#fff;color:#333;font-size:12px}.layui-laypage a[data-page]{color:#333}.layui-laypage a{text-decoration:none!important;cursor:pointer}.layui-laypage a:hover{color:#16baaa}.layui-laypage em{font-style:normal}.layui-laypage .layui-laypage-spr{color:#999;font-weight:700}.layui-laypage .layui-laypage-curr{position:relative}.layui-laypage .layui-laypage-curr em{position:relative;color:#fff}.layui-laypage .layui-laypage-curr .layui-laypage-em{position:absolute;left:-1px;top:-1px;padding:1px;width:100%;height:100%;background-color:#16baaa}.layui-laypage-em{border-radius:2px}.layui-laypage-next em,.layui-laypage-prev em{font-family:Sim sun;font-size:16px}.layui-laypage .layui-laypage-count,.layui-laypage .layui-laypage-limits,.layui-laypage .layui-laypage-refresh,.layui-laypage .layui-laypage-skip{margin-left:10px;margin-right:10px;padding:0;border:none}.layui-laypage .layui-laypage-limits,.layui-laypage .layui-laypage-refresh{vertical-align:top}.layui-laypage .layui-laypage-refresh i{font-size:18px;cursor:pointer}.layui-laypage select{height:22px;padding:3px;border-radius:2px;cursor:pointer}.layui-laypage .layui-laypage-skip{height:30px;line-height:30px;color:#999}.layui-laypage button,.layui-laypage input{height:30px;line-height:30px;border-radius:2px;vertical-align:top;background-color:#fff;box-sizing:border-box}.layui-laypage input{display:inline-block;width:40px;margin:0 10px;padding:0 3px;text-align:center}.layui-laypage input:focus,.layui-laypage select:focus{border-color:#16baaa!important}.layui-laypage button{margin-left:10px;padding:0 10px;cursor:pointer}.layui-flow-more{margin:10px 0;text-align:center;color:#999;font-size:14px;clear:both}.layui-flow-more a{height:32px;line-height:32px}.layui-flow-more a *{display:inline-block;vertical-align:top}.layui-flow-more a cite{padding:0 20px;border-radius:3px;background-color:#eee;color:#333;font-style:normal}.layui-flow-more a cite:hover{opacity:.8}.layui-flow-more a i{font-size:30px;color:#737383}.layui-table{width:100%;margin:10px 0;background-color:#fff;color:#5f5f5f}.layui-table tr{transition:all .3s;-webkit-transition:all .3s}.layui-table th{text-align:left;font-weight:600}.layui-table-mend{background-color:#fff}.layui-table-click,.layui-table-hover,.layui-table[lay-even] tbody tr:nth-child(even){background-color:#f8f8f8}.layui-table-checked{background-color:#dbfbf0}.layui-table-checked.layui-table-click,.layui-table-checked.layui-table-hover{background-color:#abf8dd}.layui-table td,.layui-table th,.layui-table-col-set,.layui-table-fixed-r,.layui-table-grid-down,.layui-table-header,.layui-table-mend,.layui-table-page,.layui-table-tips-main,.layui-table-tool,.layui-table-total,.layui-table-view,.layui-table[lay-skin=line],.layui-table[lay-skin=row]{border-width:1px;border-style:solid;border-color:#eee}.layui-table td,.layui-table th{position:relative;padding:9px 15px;min-height:20px;line-height:20px;font-size:14px}.layui-table[lay-skin=line] td,.layui-table[lay-skin=line] th{border-width:0;border-bottom-width:1px}.layui-table[lay-skin=row] td,.layui-table[lay-skin=row] th{border-width:0;border-right-width:1px}.layui-table[lay-skin=nob] td,.layui-table[lay-skin=nob] th{border:none}.layui-table img{max-width:100px}.layui-table[lay-size=lg] td,.layui-table[lay-size=lg] th{padding-top:15px;padding-right:30px;padding-bottom:15px;padding-left:30px}.layui-table-view .layui-table[lay-size=lg] .layui-table-cell{height:50px;line-height:40px}.layui-table[lay-size=sm] td,.layui-table[lay-size=sm] th{padding-top:5px;padding-right:10px;padding-bottom:5px;padding-left:10px;font-size:12px}.layui-table-view .layui-table[lay-size=sm] .layui-table-cell{height:30px;line-height:20px;padding-top:5px;padding-left:11px;padding-right:11px}.layui-table[lay-data],.layui-table[lay-options]{display:none}.layui-table-box{position:relative;overflow:hidden}.layui-table-view{clear:both}.layui-table-view .layui-table{position:relative;width:auto;margin:0;border:0;border-collapse:separate}.layui-table-view .layui-table[lay-skin=line]{border-width:0;border-right-width:1px}.layui-table-view .layui-table[lay-skin=row]{border-width:0;border-bottom-width:1px}.layui-table-view .layui-table td,.layui-table-view .layui-table th{padding:0;border-top:none;border-left:none}.layui-table-view .layui-table th [lay-event],.layui-table-view .layui-table th.layui-unselect .layui-table-cell span{cursor:pointer}.layui-table-view .layui-table td,.layui-table-view .layui-table th span{cursor:default}.layui-table-view .layui-table td[data-edit]{cursor:text}.layui-table-view .layui-table td[data-edit]:hover:after{position:absolute;left:0;top:0;width:100%;height:100%;box-sizing:border-box;border:1px solid #16b777;pointer-events:none;content:""}.layui-table-view .layui-form-checkbox[lay-skin=primary] i{width:18px;height:18px;line-height:16px}.layui-table-view .layui-form-radio{line-height:0;padding:0}.layui-table-view .layui-form-radio>i{margin:0;font-size:20px}.layui-table-init{position:absolute;left:0;top:0;right:0;bottom:0;margin:0;z-index:199;transition:opacity .1s;user-select:none;opacity:1}.layui-table-init.layui-hide-v{opacity:0}.layui-table-loading-icon{position:absolute;width:100%\0;left:50%;left:auto\0;top:50%;margin-top:-15px\0;transform:translate(-50%,-50%);transform:none\0;text-align:center}.layui-table-loading-icon .layui-icon{font-size:30px;color:#c2c2c2}.layui-table-header{border-width:0;border-bottom-width:1px;overflow:hidden}.layui-table-header .layui-table{margin-bottom:-1px}.layui-table-column{position:relative;width:100%;min-height:41px;padding:8px 16px;border-width:0;border-bottom-width:1px}.layui-table-column .layui-btn-container{margin-bottom:-8px}.layui-table-column .layui-btn-container .layui-btn{margin-right:8px;margin-bottom:8px}.layui-table-tool .layui-inline[lay-event]{position:relative;width:26px;height:26px;padding:5px;line-height:16px;margin-right:10px;text-align:center;color:#333;border:1px solid #ccc;cursor:pointer;-webkit-transition:.5s all;transition:.5s all}.layui-table-tool .layui-inline[lay-event]:hover{border:1px solid #999}.layui-table-tool-temp{padding-right:120px}.layui-table-tool-self{position:absolute;right:17px;top:10px}.layui-table-tool .layui-table-tool-self .layui-inline[lay-event]{margin:0 0 0 10px}.layui-table-tool-panel{position:absolute;top:29px;left:-1px;z-index:399;padding:5px 0!important;min-width:150px;min-height:40px;border:1px solid #d2d2d2;text-align:left;overflow-y:auto;background-color:#fff;box-shadow:0 2px 4px rgba(0,0,0,.12)}.layui-table-tool-panel li{padding:0 10px;margin:0!important;line-height:30px;list-style-type:none!important;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-webkit-transition:.5s all;transition:.5s all}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary]{width:100%}.layui-table-tool-panel li:hover{background-color:#f8f8f8}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary]{padding-left:28px}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] i{position:absolute;left:0;top:0}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] span{padding:0}.layui-table-tool .layui-table-tool-self .layui-table-tool-panel{left:auto;right:-1px}.layui-table-col-set{position:absolute;right:0;top:0;width:20px;height:100%;border-width:0;border-left-width:1px;background-color:#fff}.layui-table-sort{width:10px;height:20px;margin-left:5px;cursor:pointer!important}.layui-table-sort .layui-edge{position:absolute;left:5px;border-width:5px}.layui-table-sort .layui-table-sort-asc{top:3px;border-top:none;border-bottom-style:solid;border-bottom-color:#b2b2b2}.layui-table-sort .layui-table-sort-asc:hover{border-bottom-color:#5f5f5f}.layui-table-sort .layui-table-sort-desc{bottom:5px;border-bottom:none;border-top-style:solid;border-top-color:#b2b2b2}.layui-table-sort .layui-table-sort-desc:hover{border-top-color:#5f5f5f}.layui-table-sort[lay-sort=asc] .layui-table-sort-asc{border-bottom-color:#000}.layui-table-sort[lay-sort=desc] .layui-table-sort-desc{border-top-color:#000}.layui-table-cell{height:38px;line-height:28px;padding:6px 15px;position:relative;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box}.layui-table-cell .layui-form-checkbox[lay-skin=primary]{top:-1px;padding:0}.layui-table-cell .layui-form-checkbox[lay-skin=primary]>div{padding-left:24px}.layui-table-cell .layui-table-link{color:#01aaed}.layui-table-cell .layui-btn{vertical-align:inherit}.layui-table-cell[align=center]{-webkit-box-pack:center}.layui-table-cell[align=right]{-webkit-box-pack:end}.laytable-cell-checkbox,.laytable-cell-numbers,.laytable-cell-radio,.laytable-cell-space{text-align:center;-webkit-box-pack:center}.layui-table-body{position:relative;overflow:auto;margin-right:-1px;margin-bottom:-1px}.layui-table-body .layui-none{line-height:26px;padding:30px 15px;text-align:center;color:#999}.layui-table-fixed{position:absolute;left:0;top:0;z-index:101}.layui-table-fixed .layui-table-body{overflow:hidden}.layui-table-fixed-l{box-shadow:1px 0 8px rgba(0,0,0,.08)}.layui-table-fixed-r{left:auto;right:-1px;border-width:0;border-left-width:1px;box-shadow:-1px 0 8px rgba(0,0,0,.08)}.layui-table-fixed-r .layui-table-header{position:relative;overflow:visible}.layui-table-mend{position:absolute;right:-49px;top:0;height:100%;width:50px;border-width:0;border-left-width:1px}.layui-table-tool{position:relative;width:100%;min-height:50px;line-height:30px;padding:10px 15px;border-width:0;border-bottom-width:1px}.layui-table-tool .layui-btn-container{margin-bottom:-10px}.layui-table-total{margin-bottom:-1px;border-width:0;border-top-width:1px;overflow:hidden}.layui-table-page{border-width:0;border-top-width:1px;margin-bottom:-1px;white-space:nowrap;overflow:hidden}.layui-table-page>div{height:26px}.layui-table-page .layui-laypage{margin:0}.layui-table-page .layui-laypage a,.layui-table-page .layui-laypage span{height:26px;line-height:26px;margin-bottom:10px;border:none;background:0 0}.layui-table-page .layui-laypage a,.layui-table-page .layui-laypage span.layui-laypage-curr{padding:0 12px}.layui-table-page .layui-laypage span{margin-left:0;padding:0}.layui-table-page .layui-laypage .layui-laypage-prev{margin-left:-11px!important}.layui-table-page .layui-laypage .layui-laypage-curr .layui-laypage-em{left:0;top:0;padding:0}.layui-table-page .layui-laypage button,.layui-table-page .layui-laypage input{height:26px;line-height:26px}.layui-table-page .layui-laypage input{width:40px}.layui-table-page .layui-laypage button{padding:0 10px}.layui-table-page select{height:18px}.layui-table-pagebar{float:right;line-height:23px}.layui-table-pagebar .layui-btn-sm{margin-top:-1px}.layui-table-pagebar .layui-btn-xs{margin-top:2px}.layui-table-view select[lay-ignore]{display:inline-block}.layui-table-patch .layui-table-cell{padding:0;width:30px}.layui-table-edit{position:absolute;left:0;top:0;z-index:189;min-width:100%;min-height:100%;padding:5px 14px;border-radius:0;box-shadow:1px 1px 20px rgba(0,0,0,.15);background-color:#fff}.layui-table-edit:focus{border-color:#16b777!important}input.layui-input.layui-table-edit{height:100%}select.layui-table-edit{padding:0 0 0 10px;border-color:#d2d2d2}.layui-table-view .layui-form-checkbox,.layui-table-view .layui-form-radio,.layui-table-view .layui-form-switch{top:0;margin:0}.layui-table-view .layui-form-checkbox{top:-1px;height:26px;line-height:26px}.layui-table-view .layui-form-checkbox i{height:26px}.layui-table-grid .layui-table-cell{overflow:visible}.layui-table-grid-down{position:absolute;top:0;right:0;width:24px;height:100%;padding:5px 0;border-width:0;border-left-width:1px;text-align:center;background-color:#fff;color:#999;cursor:pointer}.layui-table-grid-down .layui-icon{position:absolute;top:50%;left:50%;margin:-8px 0 0 -8px;font-size:14px}.layui-table-grid-down:hover{background-color:#fbfbfb}.layui-table-expanded{height:95px}.layui-table-expanded .layui-table-cell,.layui-table-view .layui-table[lay-size=lg] .layui-table-expanded .layui-table-cell,.layui-table-view .layui-table[lay-size=sm] .layui-table-expanded .layui-table-cell{height:auto;max-height:94px;white-space:normal;text-overflow:clip}.layui-table-cell-c{position:absolute;bottom:-10px;right:50%;margin-right:-9px;width:20px;height:20px;line-height:18px;cursor:pointer;text-align:center;background-color:#fff;border:1px solid #eee;border-radius:50%;z-index:1000;transition:.3s all;font-size:14px}.layui-table-cell-c:hover{border-color:#16b777}.layui-table-expanded td:hover .layui-table-cell{overflow:auto}.layui-table-main>.layui-table>tbody>tr:last-child>td>.layui-table-cell-c{bottom:0}body .layui-table-tips .layui-layer-content{background:0 0;padding:0;box-shadow:0 1px 6px rgba(0,0,0,.12)}.layui-table-tips-main{margin:-49px 0 0 -1px;max-height:150px;padding:8px 15px;font-size:14px;overflow-y:scroll;background-color:#fff;color:#5f5f5f}.layui-table-tips-c{position:absolute;right:-3px;top:-13px;width:20px;height:20px;padding:3px;cursor:pointer;background-color:#5f5f5f;border-radius:50%;color:#fff}.layui-table-tips-c:hover{background-color:#777}.layui-table-tips-c:before{position:relative;right:-2px}.layui-table-tree-nodeIcon{max-width:20px}.layui-table-tree-nodeIcon>*{width:100%}.layui-table-tree-flexIcon,.layui-table-tree-nodeIcon{margin-right:2px}.layui-table-tree-flexIcon{cursor:pointer}.layui-upload-file{display:none!important;opacity:.01;filter:Alpha(opacity=1)}.layui-upload-list{margin:11px 0}.layui-upload-choose{max-width:200px;padding:0 10px;color:#999;font-size:14px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-upload-drag{position:relative;display:inline-block;padding:30px;border:1px dashed #e2e2e2;background-color:#fff;text-align:center;cursor:pointer;color:#999}.layui-upload-drag .layui-icon{font-size:50px;color:#16baaa}.layui-upload-drag[lay-over]{border-color:#16baaa}.layui-upload-form{display:inline-block}.layui-upload-iframe{position:absolute;width:0;height:0;border:0;visibility:hidden}.layui-upload-wrap{position:relative;display:inline-block;vertical-align:middle}.layui-upload-wrap .layui-upload-file{display:block!important;position:absolute;left:0;top:0;z-index:10;font-size:100px;width:100%;height:100%;opacity:.01;filter:Alpha(opacity=1);cursor:pointer}.layui-btn-container .layui-upload-choose{padding-left:0}.layui-menu{position:relative;margin:5px 0;background-color:#fff;box-sizing:border-box}.layui-menu *{box-sizing:border-box}.layui-menu li,.layui-menu-body-title,.layui-menu-body-title a{padding:5px 15px;color:initial}.layui-menu li{position:relative;margin:0 0 1px;line-height:26px;color:rgba(0,0,0,.8);font-size:14px;white-space:nowrap;cursor:pointer;transition:all .3s}.layui-menu li:hover{background-color:#f8f8f8}.layui-menu li.layui-disabled,.layui-menu li.layui-disabled *{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important}.layui-menu-item-parent:hover>.layui-menu-body-panel{display:block;animation-name:layui-fadein;animation-duration:.3s;animation-fill-mode:both;animation-delay:.2s}.layui-menu-item-group>.layui-menu-body-title,.layui-menu-item-parent>.layui-menu-body-title{padding-right:38px}.layui-menu .layui-menu-item-divider:hover,.layui-menu .layui-menu-item-group:hover,.layui-menu .layui-menu-item-none:hover{background:0 0;cursor:default}.layui-menu .layui-menu-item-group>ul{margin:5px 0 -5px}.layui-menu .layui-menu-item-group>.layui-menu-body-title{color:rgba(0,0,0,.35);user-select:none}.layui-menu .layui-menu-item-none{color:rgba(0,0,0,.35);cursor:default}.layui-menu .layui-menu-item-none{text-align:center}.layui-menu .layui-menu-item-divider{margin:5px 0;padding:0;height:0;line-height:0;border-bottom:1px solid #eee;overflow:hidden}.layui-menu .layui-menu-item-down:hover,.layui-menu .layui-menu-item-up:hover{cursor:pointer}.layui-menu .layui-menu-item-up>.layui-menu-body-title{color:rgba(0,0,0,.8)}.layui-menu .layui-menu-item-up>ul{visibility:hidden;height:0;overflow:hidden}.layui-menu .layui-menu-item-down>.layui-menu-body-title>.layui-icon-down{transform:rotate(180deg)}.layui-menu .layui-menu-item-up>.layui-menu-body-title>.layui-icon-up{transform:rotate(-180deg)}.layui-menu .layui-menu-item-down:hover>.layui-menu-body-title>.layui-icon,.layui-menu .layui-menu-item-up>.layui-menu-body-title:hover>.layui-icon{color:#000}.layui-menu .layui-menu-item-down>ul{visibility:visible;height:auto}.layui-menu .layui-menu-item-checked,.layui-menu .layui-menu-item-checked2{background-color:#f8f8f8!important;color:#16b777}.layui-menu .layui-menu-item-checked a,.layui-menu .layui-menu-item-checked2 a{color:#16b777}.layui-menu .layui-menu-item-checked:after{position:absolute;right:-1px;top:0;bottom:0;border-right:3px solid #16b777;content:""}.layui-menu-body-title{position:relative;margin:-5px -15px;overflow:hidden;text-overflow:ellipsis}.layui-menu-body-title a{display:block;margin:-5px -15px;color:rgba(0,0,0,.8)}.layui-menu-body-title a:hover{transition:all .3s}.layui-menu-body-title>.layui-icon{position:absolute;right:15px;top:50%;margin-top:-6px;line-height:normal;font-size:14px;transition:all .2s;-webkit-transition:all .2s}.layui-menu-body-title>.layui-icon:hover{transition:all .3s}.layui-menu-body-title>.layui-icon-right{right:14px}.layui-menu-body-panel{display:none;position:absolute;top:-7px;left:100%;z-index:1000;margin-left:13px;padding:5px 0}.layui-menu-body-panel:before{content:"";position:absolute;width:20px;left:-16px;top:0;bottom:0}.layui-menu-body-panel-left{left:auto;right:100%;margin:0 13px 0}.layui-menu-body-panel-left:before{left:auto;right:-16px}.layui-menu-lg li{line-height:32px}.layui-menu-lg .layui-menu-body-title a:hover,.layui-menu-lg li:hover{background:0 0;color:#16b777}.layui-menu-lg li .layui-menu-body-panel{margin-left:14px}.layui-menu-lg li .layui-menu-body-panel-left{margin:0 15px 0}.layui-dropdown{position:absolute;left:-999999px;top:-999999px;z-index:77777777;margin:5px 0;min-width:100px}.layui-dropdown:before{content:"";position:absolute;width:100%;height:6px;left:0;top:-6px}.layui-dropdown-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px");position:fixed;_position:absolute;pointer-events:auto}.layui-nav{position:relative;padding:0 15px;background-color:#2f363c;color:#fff;border-radius:2px;font-size:0;box-sizing:border-box}.layui-nav *{font-size:14px}.layui-nav .layui-nav-item{position:relative;display:inline-block;*display:inline;*zoom:1;margin-top:0;list-style:none;vertical-align:middle;line-height:60px}.layui-nav .layui-nav-item a{display:block;padding:0 20px;color:#fff;color:rgba(255,255,255,.7);transition:all .3s;-webkit-transition:all .3s}.layui-nav .layui-this:after,.layui-nav-bar{content:"";position:absolute;left:0;top:0;width:0;height:3px;background-color:#16b777;transition:all .2s;-webkit-transition:all .2s;pointer-events:none}.layui-nav-bar{z-index:1000}.layui-nav[lay-bar=disabled] .layui-nav-bar{display:none}.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{color:#fff;text-decoration:none}.layui-nav .layui-this:after{top:auto;bottom:0;width:100%}.layui-nav-img{width:30px;height:30px;margin-right:10px;border-radius:50%}.layui-nav .layui-nav-more{position:absolute;top:0;right:3px;left:auto!important;margin-top:0;font-size:12px;cursor:pointer;transition:all .2s;-webkit-transition:all .2s}.layui-nav .layui-nav-mored,.layui-nav-itemed>a .layui-nav-more{transform:rotate(180deg)}.layui-nav-child{display:none;position:absolute;left:0;top:65px;min-width:100%;line-height:36px;padding:5px 0;box-shadow:0 2px 4px rgba(0,0,0,.12);border:1px solid #eee;background-color:#fff;z-index:100;border-radius:2px;white-space:nowrap;box-sizing:border-box}.layui-nav .layui-nav-child a{color:#5f5f5f;color:rgba(0,0,0,.8)}.layui-nav .layui-nav-child a:hover{background-color:#f8f8f8;color:rgba(0,0,0,.8)}.layui-nav-child dd{margin:1px 0;position:relative}.layui-nav-child dd.layui-this{background-color:#f8f8f8;color:#000}.layui-nav-child dd.layui-this:after{display:none}.layui-nav-child-r{left:auto;right:0}.layui-nav-child-c{text-align:center}.layui-nav.layui-nav-tree{width:200px;padding:0}.layui-nav-tree .layui-nav-item{display:block;width:100%;line-height:40px}.layui-nav-tree .layui-nav-item a{position:relative;height:40px;line-height:40px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-nav-tree .layui-nav-item>a{padding-top:5px;padding-bottom:5px}.layui-nav-tree .layui-nav-more{right:15px}.layui-nav-tree .layui-nav-item>a .layui-nav-more{padding:5px 0}.layui-nav-tree .layui-nav-bar{width:5px;height:0}.layui-side .layui-nav-tree .layui-nav-bar{width:2px}.layui-nav-tree .layui-nav-child dd.layui-this,.layui-nav-tree .layui-nav-child dd.layui-this a,.layui-nav-tree .layui-this,.layui-nav-tree .layui-this>a,.layui-nav-tree .layui-this>a:hover{background-color:#16baaa;color:#fff}.layui-nav-tree .layui-this:after{display:none}.layui-nav-itemed>a,.layui-nav-tree .layui-nav-title a,.layui-nav-tree .layui-nav-title a:hover{color:#fff!important}.layui-nav-tree .layui-nav-bar{background-color:#16baaa}.layui-nav-tree .layui-nav-child{position:relative;z-index:0;top:0;border:none;background:0 0;background-color:rgba(0,0,0,.3);box-shadow:none}.layui-nav-tree .layui-nav-child dd{margin:0}.layui-nav-tree .layui-nav-child a{color:#fff;color:rgba(255,255,255,.7)}.layui-nav-tree .layui-nav-child a:hover{background:0 0;color:#fff}.layui-nav-itemed>.layui-nav-child,.layui-nav-itemed>.layui-nav-child>.layui-this>.layui-nav-child{display:block}.layui-nav-side{position:fixed;top:0;bottom:0;left:0;overflow-x:hidden;z-index:999}.layui-nav-tree.layui-bg-gray a,.layui-nav.layui-bg-gray .layui-nav-item a{color:#373737;color:rgba(0,0,0,.8)}.layui-nav-tree.layui-bg-gray .layui-nav-itemed>a{color:#000!important}.layui-nav.layui-bg-gray .layui-this a{color:#16b777}.layui-nav-tree.layui-bg-gray .layui-nav-child{padding-left:11px;background:0 0}.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this,.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this a,.layui-nav-tree.layui-bg-gray .layui-this,.layui-nav-tree.layui-bg-gray .layui-this>a{background:0 0!important;color:#16b777!important;font-weight:700}.layui-nav-tree.layui-bg-gray .layui-nav-bar{background-color:#16b777}.layui-breadcrumb{visibility:hidden;font-size:0}.layui-breadcrumb>*{font-size:14px}.layui-breadcrumb a{color:#999!important}.layui-breadcrumb a:hover{color:#16b777!important}.layui-breadcrumb a cite{color:#5f5f5f;font-style:normal}.layui-breadcrumb span[lay-separator]{margin:0 10px;color:#999}.layui-tab{margin:10px 0;text-align:left!important}.layui-tab[overflow]>.layui-tab-title{overflow:hidden}.layui-tab .layui-tab-title{position:relative;left:0;height:40px;white-space:nowrap;font-size:0;border-bottom-width:1px;border-bottom-style:solid;transition:all .2s;-webkit-transition:all .2s}.layui-tab .layui-tab-title li{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;font-size:14px;transition:all .2s;-webkit-transition:all .2s}.layui-tab .layui-tab-title li{position:relative;line-height:40px;min-width:65px;margin:0;padding:0 15px;text-align:center;cursor:pointer}.layui-tab .layui-tab-title li a{display:block;padding:0 15px;margin:0 -15px}.layui-tab-title .layui-this{color:#000}.layui-tab-title .layui-this:after{position:absolute;left:0;top:0;content:"";width:100%;height:41px;border-width:1px;border-style:solid;border-bottom-color:#fff;border-radius:2px 2px 0 0;box-sizing:border-box;pointer-events:none}.layui-tab-bar{position:absolute;right:0;top:0;z-index:10;width:30px;height:39px;line-height:39px;border-width:1px;border-style:solid;border-radius:2px;text-align:center;background-color:#fff;cursor:pointer}.layui-tab-bar .layui-icon{position:relative;display:inline-block;top:3px;transition:all .3s;-webkit-transition:all .3s}.layui-tab-item{display:none}.layui-tab-more{padding-right:30px;height:auto!important;white-space:normal!important}.layui-tab-more li.layui-this:after{border-bottom-color:#eee;border-radius:2px}.layui-tab-more .layui-tab-bar .layui-icon{top:-2px;top:3px\0;-webkit-transform:rotate(180deg);transform:rotate(180deg)}:root .layui-tab-more .layui-tab-bar .layui-icon{top:-2px\0/IE9}.layui-tab-content{padding:15px 0}.layui-tab-title li .layui-tab-close{position:relative;display:inline-block;width:18px;height:18px;line-height:20px;margin-left:8px;top:1px;text-align:center;font-size:14px;color:#c2c2c2;transition:all .2s;-webkit-transition:all .2s}.layui-tab-title li .layui-tab-close:hover{border-radius:2px;background-color:#ff5722;color:#fff}.layui-tab-brief>.layui-tab-title .layui-this{color:#16baaa}.layui-tab-brief>.layui-tab-more li.layui-this:after,.layui-tab-brief>.layui-tab-title .layui-this:after{border:none;border-radius:0;border-bottom:2px solid #16b777}.layui-tab-brief[overflow]>.layui-tab-title .layui-this:after{top:-1px}.layui-tab-card{border-width:1px;border-style:solid;border-radius:2px;box-shadow:0 2px 5px 0 rgba(0,0,0,.1)}.layui-tab-card>.layui-tab-title{background-color:#fafafa}.layui-tab-card>.layui-tab-title li{margin-right:-1px;margin-left:-1px}.layui-tab-card>.layui-tab-title .layui-this{background-color:#fff}.layui-tab-card>.layui-tab-title .layui-this:after{border-top:none;border-width:1px;border-bottom-color:#fff}.layui-tab-card>.layui-tab-title .layui-tab-bar{height:40px;line-height:40px;border-radius:0;border-top:none;border-right:none}.layui-tab-card>.layui-tab-more .layui-this{background:0 0;color:#16b777}.layui-tab-card>.layui-tab-more .layui-this:after{border:none}.layui-timeline{padding-left:5px}.layui-timeline-item{position:relative;padding-bottom:20px}.layui-timeline-axis{position:absolute;left:-5px;top:0;z-index:10;width:20px;height:20px;line-height:20px;background-color:#fff;color:#16b777;border-radius:50%;text-align:center;cursor:pointer}.layui-timeline-axis:hover{color:#ff5722}.layui-timeline-item:before{content:"";position:absolute;left:5px;top:0;z-index:0;width:1px;height:100%}.layui-timeline-item:first-child:before{display:block}.layui-timeline-item:last-child:before{display:none}.layui-timeline-content{padding-left:25px}.layui-timeline-title{position:relative;margin-bottom:10px;line-height:22px}.layui-badge,.layui-badge-dot,.layui-badge-rim{position:relative;display:inline-block;padding:0 6px;font-size:12px;text-align:center;background-color:#ff5722;color:#fff;border-radius:2px}.layui-badge{height:18px;line-height:18px}.layui-badge-dot{width:8px;height:8px;padding:0;border-radius:50%}.layui-badge-rim{height:18px;line-height:18px;border-width:1px;border-style:solid;background-color:#fff;color:#5f5f5f}.layui-btn .layui-badge,.layui-btn .layui-badge-dot{margin-left:5px}.layui-nav .layui-badge,.layui-nav .layui-badge-dot{position:absolute;top:50%;margin:-5px 6px 0}.layui-nav .layui-badge{margin-top:-10px}.layui-tab-title .layui-badge,.layui-tab-title .layui-badge-dot{left:5px;top:-2px}.layui-carousel{position:relative;left:0;top:0;background-color:#f8f8f8}.layui-carousel>[carousel-item]{position:relative;width:100%;height:100%;overflow:hidden}.layui-carousel>[carousel-item]:before{position:absolute;content:'\e63d';left:50%;top:50%;width:100px;line-height:20px;margin:-10px 0 0 -50px;text-align:center;color:#c2c2c2;font-family:layui-icon!important;font-size:30px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-carousel>[carousel-item]>*{display:none;position:absolute;left:0;top:0;width:100%;height:100%;background-color:#f8f8f8;transition-duration:.3s;-webkit-transition-duration:.3s}.layui-carousel-updown>*{-webkit-transition:.3s ease-in-out up;transition:.3s ease-in-out up}.layui-carousel-arrow{display:none\0;opacity:0;position:absolute;left:10px;top:50%;margin-top:-18px;width:36px;height:36px;line-height:36px;text-align:center;font-size:20px;border:none 0;border-radius:50%;background-color:rgba(0,0,0,.2);color:#fff;-webkit-transition-duration:.3s;transition-duration:.3s;cursor:pointer}.layui-carousel-arrow[lay-type=add]{left:auto!important;right:10px}.layui-carousel[lay-arrow=always] .layui-carousel-arrow{opacity:1;left:20px}.layui-carousel[lay-arrow=always] .layui-carousel-arrow[lay-type=add]{right:20px}.layui-carousel[lay-arrow=none] .layui-carousel-arrow{display:none}.layui-carousel-arrow:hover,.layui-carousel-ind ul:hover{background-color:rgba(0,0,0,.35)}.layui-carousel:hover .layui-carousel-arrow{display:block\0;opacity:1;left:20px}.layui-carousel:hover .layui-carousel-arrow[lay-type=add]{right:20px}.layui-carousel-ind{position:relative;top:-35px;width:100%;line-height:0!important;text-align:center;font-size:0}.layui-carousel[lay-indicator=outside]{margin-bottom:30px}.layui-carousel[lay-indicator=outside] .layui-carousel-ind{top:10px}.layui-carousel[lay-indicator=outside] .layui-carousel-ind ul{background-color:rgba(0,0,0,.5)}.layui-carousel[lay-indicator=none] .layui-carousel-ind{display:none}.layui-carousel-ind ul{display:inline-block;padding:5px;background-color:rgba(0,0,0,.2);border-radius:10px;-webkit-transition-duration:.3s;transition-duration:.3s}.layui-carousel-ind ul li{display:inline-block;width:10px;height:10px;margin:0 3px;font-size:14px;background-color:#eee;background-color:rgba(255,255,255,.5);border-radius:50%;cursor:pointer;-webkit-transition-duration:.3s;transition-duration:.3s}.layui-carousel-ind ul li:hover{background-color:rgba(255,255,255,.7)}.layui-carousel-ind ul li.layui-this{background-color:#fff}.layui-carousel>[carousel-item]>.layui-carousel-next,.layui-carousel>[carousel-item]>.layui-carousel-prev,.layui-carousel>[carousel-item]>.layui-this{display:block}.layui-carousel>[carousel-item]>.layui-this{left:0}.layui-carousel>[carousel-item]>.layui-carousel-prev{left:-100%}.layui-carousel>[carousel-item]>.layui-carousel-next{left:100%}.layui-carousel>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel>[carousel-item]>.layui-carousel-prev.layui-carousel-right{left:0}.layui-carousel>[carousel-item]>.layui-this.layui-carousel-left{left:-100%}.layui-carousel>[carousel-item]>.layui-this.layui-carousel-right{left:100%}.layui-carousel[lay-anim=updown] .layui-carousel-arrow{left:50%!important;top:20px;margin:0 0 0 -18px}.layui-carousel[lay-anim=updown] .layui-carousel-arrow[lay-type=add]{top:auto!important;bottom:20px}.layui-carousel[lay-anim=updown] .layui-carousel-ind{position:absolute;top:50%;right:20px;width:auto;height:auto}.layui-carousel[lay-anim=updown] .layui-carousel-ind ul{padding:3px 5px}.layui-carousel[lay-anim=updown] .layui-carousel-ind li{display:block;margin:6px 0}.layui-carousel[lay-anim=updown]>[carousel-item]>*{left:0!important}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this{top:0}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-prev{top:-100%}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-next{top:100%}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-prev.layui-carousel-right{top:0}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this.layui-carousel-left{top:-100%}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this.layui-carousel-right{top:100%}.layui-carousel[lay-anim=fade]>[carousel-item]>*{left:0!important}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-next,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-prev{opacity:0}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-prev.layui-carousel-right{opacity:1}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-this.layui-carousel-left,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-this.layui-carousel-right{opacity:0}.layui-fixbar{position:fixed;right:16px;bottom:16px;z-index:999999}.layui-fixbar li{width:50px;height:50px;line-height:50px;margin-bottom:1px;text-align:center;cursor:pointer;font-size:30px;background-color:#9f9f9f;color:#fff;border-radius:2px;opacity:.95}.layui-fixbar li:hover{opacity:.85}.layui-fixbar li:active{opacity:1}.layui-fixbar .layui-fixbar-top{display:none;font-size:40px}body .layui-util-face{border:none;background:0 0}body .layui-util-face .layui-layer-content{padding:0;background-color:#fff;color:#5f5f5f;box-shadow:none}.layui-util-face .layui-layer-TipsG{display:none}.layui-util-face ul{position:relative;width:372px;padding:10px;border:1px solid #d9d9d9;background-color:#fff;box-shadow:0 0 20px rgba(0,0,0,.2)}.layui-util-face ul li{cursor:pointer;float:left;border:1px solid #e8e8e8;height:22px;width:26px;overflow:hidden;margin:-1px 0 0 -1px;padding:4px 2px;text-align:center}.layui-util-face ul li:hover{position:relative;z-index:2;border:1px solid #eb7350;background:#fff9ec}.layui-code{display:block;position:relative;padding:15px;line-height:20px;border:1px solid #eee;border-left-width:6px;background-color:#fff;color:#333;font-family:"Courier New",Consolas,"Lucida Console";font-size:12px}.layui-transfer-box,.layui-transfer-header,.layui-transfer-search{border-width:0;border-style:solid;border-color:#eee}.layui-transfer-box{position:relative;display:inline-block;vertical-align:middle;border-width:1px;width:200px;height:360px;border-radius:2px;background-color:#fff}.layui-transfer-box .layui-form-checkbox{width:100%;margin:0!important}.layui-transfer-header{height:38px;line-height:38px;padding:0 11px;border-bottom-width:1px}.layui-transfer-search{position:relative;padding:11px;border-bottom-width:1px}.layui-transfer-search .layui-input{height:32px;padding-left:30px;font-size:12px}.layui-transfer-search .layui-icon-search{position:absolute;left:20px;top:50%;line-height:normal;margin-top:-8px;color:#5f5f5f}.layui-transfer-active{margin:0 15px;display:inline-block;vertical-align:middle}.layui-transfer-active .layui-btn{display:block;margin:0;padding:0 15px;background-color:#16b777;border-color:#16b777;color:#fff}.layui-transfer-active .layui-btn-disabled{background-color:#fbfbfb;border-color:#eee;color:#d2d2d2}.layui-transfer-active .layui-btn:first-child{margin-bottom:15px}.layui-transfer-active .layui-btn .layui-icon{margin:0;font-size:14px!important}.layui-transfer-data{padding:5px 0;overflow:auto}.layui-transfer-data li{height:32px;line-height:32px;margin-top:0!important;padding:0 11px;list-style-type:none!important}.layui-transfer-data li:hover{background-color:#f8f8f8;transition:.5s all}.layui-transfer-data .layui-none{padding:15px 11px;text-align:center;color:#999}.layui-rate,.layui-rate *{display:inline-block;vertical-align:middle}.layui-rate{padding:11px 6px 11px 0;font-size:0}.layui-rate li{margin-top:0!important}.layui-rate li i.layui-icon{font-size:20px;color:#ffb800}.layui-rate li i.layui-icon{margin-right:5px;transition:all .3s;-webkit-transition:all .3s}.layui-rate li i:hover,.layui-rate-hover{cursor:pointer;transform:scale(1.12);-webkit-transform:scale(1.12)}.layui-rate[readonly] li i:hover{cursor:default;transform:scale(1)}.layui-colorpicker{width:38px;height:38px;border:1px solid #eee;padding:5px;border-radius:2px;line-height:24px;display:inline-block;cursor:pointer;transition:all .3s;-webkit-transition:all .3s;box-sizing:border-box}.layui-colorpicker:hover{border-color:#d2d2d2}.layui-colorpicker.layui-colorpicker-lg{width:44px;height:44px;line-height:30px}.layui-colorpicker.layui-colorpicker-sm{width:30px;height:30px;line-height:20px;padding:3px}.layui-colorpicker.layui-colorpicker-xs{width:22px;height:22px;line-height:16px;padding:1px}.layui-colorpicker-trigger-bgcolor{display:block;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);border-radius:2px}.layui-colorpicker-trigger-span{display:block;height:100%;box-sizing:border-box;border:1px solid rgba(0,0,0,.15);border-radius:2px;text-align:center}.layui-colorpicker-trigger-i{display:inline-block;color:#fff;font-size:12px}.layui-colorpicker-trigger-i.layui-icon-close{color:#999}.layui-colorpicker-main{position:absolute;left:-999999px;top:-999999px;z-index:77777777;width:280px;margin:5px 0;padding:7px;background:#fff;border:1px solid #d2d2d2;border-radius:2px;box-shadow:0 2px 4px rgba(0,0,0,.12)}.layui-colorpicker-main-wrapper{height:180px;position:relative}.layui-colorpicker-basis{width:260px;height:100%;position:relative;overflow:hidden}.layui-colorpicker-basis-white{width:100%;height:100%;position:absolute;top:0;left:0;background:linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.layui-colorpicker-basis-black{width:100%;height:100%;position:absolute;top:0;left:0;background:linear-gradient(0deg,#000,transparent)}.layui-colorpicker-basis-cursor{width:10px;height:10px;border:1px solid #fff;border-radius:50%;position:absolute;top:0;right:100%;cursor:pointer;transform:translate(-50%,-50%)}.layui-colorpicker-side{position:absolute;top:0;right:0;width:12px;height:100%;background:linear-gradient(red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.layui-colorpicker-side-slider{width:100%;height:5px;box-shadow:0 0 1px #888;box-sizing:border-box;background:#fff;border-radius:1px;border:1px solid #f0f0f0;cursor:pointer;position:absolute;left:0}.layui-colorpicker-main-alpha{display:none;height:12px;margin-top:7px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.layui-colorpicker-alpha-bgcolor{height:100%;position:relative}.layui-colorpicker-alpha-slider{width:5px;height:100%;box-shadow:0 0 1px #888;box-sizing:border-box;background:#fff;border-radius:1px;border:1px solid #f0f0f0;cursor:pointer;position:absolute;top:0}.layui-colorpicker-main-pre{padding-top:7px;font-size:0}.layui-colorpicker-pre{width:20px;height:20px;border-radius:2px;display:inline-block;margin-left:6px;margin-bottom:7px;cursor:pointer}.layui-colorpicker-pre:nth-child(11n+1){margin-left:0}.layui-colorpicker-pre-isalpha{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.layui-colorpicker-pre.layui-this{box-shadow:0 0 3px 2px rgba(0,0,0,.15)}.layui-colorpicker-pre>div{height:100%;border-radius:2px}.layui-colorpicker-main-input{text-align:right;padding-top:7px}.layui-colorpicker-main-input .layui-btn-container .layui-btn{margin:0 0 0 10px}.layui-colorpicker-main-input div.layui-inline{float:left;font-size:14px}.layui-colorpicker-main-input input.layui-input{width:168px;height:30px;color:#5f5f5f;padding-left:5px}.layui-slider{height:4px;background:#eee;border-radius:3px;position:relative;cursor:pointer}.layui-slider-bar{border-radius:3px;position:absolute;height:100%}.layui-slider-step{position:absolute;top:0;width:4px;height:4px;border-radius:50%;background:#fff;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.layui-slider-wrap{width:36px;height:36px;position:absolute;top:-16px;-webkit-transform:translateX(-50%);transform:translateX(-50%);z-index:10;text-align:center}.layui-slider-wrap-btn{width:12px;height:12px;border-radius:50%;background:#fff;display:inline-block;vertical-align:middle;cursor:pointer;transition:.3s}.layui-slider-wrap:after{content:"";height:100%;display:inline-block;vertical-align:middle}.layui-slider-wrap-btn.layui-slider-hover,.layui-slider-wrap-btn:hover{transform:scale(1.2)}.layui-slider-wrap-btn.layui-disabled:hover{transform:scale(1)!important}.layui-slider-tips{position:absolute;top:-42px;z-index:77777777;white-space:nowrap;-webkit-transform:translateX(-50%);transform:translateX(-50%);color:#fff;background:#000;border-radius:3px;height:25px;line-height:25px;padding:0 10px}.layui-slider-tips:after{content:"";position:absolute;bottom:-12px;left:50%;margin-left:-6px;width:0;height:0;border-width:6px;border-style:solid;border-color:#000 transparent transparent transparent}.layui-slider-input{width:70px;height:32px;border:1px solid #eee;border-radius:3px;font-size:16px;line-height:32px;position:absolute;right:0;top:-14px;box-sizing:border-box}.layui-slider-input-btn{position:absolute;top:0;right:0;width:20px;height:100%;border-left:1px solid #eee}.layui-slider-input-btn i{cursor:pointer;position:absolute;right:0;bottom:0;width:20px;height:50%;font-size:12px;line-height:16px;text-align:center;color:#999}.layui-slider-input-btn i:first-child{top:0;border-bottom:1px solid #eee}.layui-slider-input-txt{height:100%;font-size:14px}.layui-slider-input-txt input{height:100%;border:none;padding-right:21px}.layui-slider-input-btn i:hover{color:#16baaa}.layui-slider-vertical{width:4px;margin-left:33px}.layui-slider-vertical .layui-slider-bar{width:4px}.layui-slider-vertical .layui-slider-step{top:auto;left:0;-webkit-transform:translateY(50%);transform:translateY(50%)}.layui-slider-vertical .layui-slider-wrap{top:auto;left:-16px;-webkit-transform:translateY(50%);transform:translateY(50%)}.layui-slider-vertical .layui-slider-tips{top:auto;left:2px}@media \0screen{.layui-slider-wrap-btn{margin-left:-20px}.layui-slider-vertical .layui-slider-wrap-btn{margin-left:0;margin-bottom:-20px}.layui-slider-vertical .layui-slider-tips{margin-left:-8px}.layui-slider>span{margin-left:8px}}.layui-tree{line-height:22px}.layui-tree .layui-form-checkbox{margin:0!important}.layui-tree-set{width:100%;position:relative}.layui-tree-pack{display:none;padding-left:20px;position:relative}.layui-tree-line .layui-tree-pack{padding-left:27px}.layui-tree-line .layui-tree-set .layui-tree-set:after{content:"";position:absolute;top:14px;left:-9px;width:17px;height:0;border-top:1px dotted #c0c4cc}.layui-tree-entry{position:relative;padding:3px 0;height:26px;white-space:nowrap}.layui-tree-entry:hover{background-color:#eee}.layui-tree-line .layui-tree-entry:hover{background-color:rgba(0,0,0,0)}.layui-tree-line .layui-tree-entry:hover .layui-tree-txt{color:#999;text-decoration:underline;transition:.3s}.layui-tree-main{display:inline-block;vertical-align:middle;cursor:pointer;padding-right:10px}.layui-tree-line .layui-tree-set:before{content:"";position:absolute;top:0;left:-9px;width:0;height:100%;border-left:1px dotted #c0c4cc}.layui-tree-line .layui-tree-set.layui-tree-setLineShort:before{height:13px}.layui-tree-line .layui-tree-set.layui-tree-setHide:before{height:0}.layui-tree-iconClick{display:inline-block;vertical-align:middle;position:relative;height:20px;line-height:20px;margin:0 10px;color:#c0c4cc}.layui-tree-icon{height:14px;line-height:12px;width:14px;text-align:center;border:1px solid #c0c4cc}.layui-tree-iconClick .layui-icon{font-size:18px}.layui-tree-icon .layui-icon{font-size:12px;color:#5f5f5f}.layui-tree-iconArrow{padding:0 5px}.layui-tree-iconArrow:after{content:"";position:absolute;left:4px;top:3px;z-index:100;width:0;height:0;border-width:5px;border-style:solid;border-color:transparent transparent transparent #c0c4cc;transition:.5s}.layui-tree-spread>.layui-tree-entry .layui-tree-iconClick>.layui-tree-iconArrow:after{transform:rotate(90deg) translate(3px,4px)}.layui-tree-txt{display:inline-block;vertical-align:middle;color:#555}.layui-tree-search{margin-bottom:15px;color:#5f5f5f}.layui-tree-btnGroup{visibility:hidden;display:inline-block;vertical-align:middle;position:relative}.layui-tree-btnGroup .layui-icon{display:inline-block;vertical-align:middle;padding:0 2px;cursor:pointer}.layui-tree-btnGroup .layui-icon:hover{color:#999;transition:.3s}.layui-tree-entry:hover .layui-tree-btnGroup{visibility:visible}.layui-tree-editInput{position:relative;display:inline-block;vertical-align:middle;height:20px;line-height:20px;padding:0;border:none;background-color:rgba(0,0,0,.05)}.layui-tree-emptyText{text-align:center;color:#999}.layui-anim{-webkit-animation-duration:.3s;-webkit-animation-fill-mode:both;animation-duration:.3s;animation-fill-mode:both}.layui-anim.layui-icon{display:inline-block}.layui-anim-loop{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.layui-trans,.layui-trans a{transition:all .2s;-webkit-transition:all .2s}@-webkit-keyframes layui-rotate{from{-webkit-transform:rotate(0)}to{-webkit-transform:rotate(360deg)}}@keyframes layui-rotate{from{transform:rotate(0)}to{transform:rotate(360deg)}}.layui-anim-rotate{-webkit-animation-name:layui-rotate;animation-name:layui-rotate;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:linear;animation-timing-function:linear}@-webkit-keyframes layui-up{from{-webkit-transform:translate3d(0,100%,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes layui-up{from{transform:translate3d(0,100%,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-anim-up{-webkit-animation-name:layui-up;animation-name:layui-up}@-webkit-keyframes layui-upbit{from{-webkit-transform:translate3d(0,15px,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes layui-upbit{from{transform:translate3d(0,15px,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-anim-upbit{-webkit-animation-name:layui-upbit;animation-name:layui-upbit}@keyframes layui-down{0%{opacity:.3;transform:translate3d(0,-100%,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-anim-down{animation-name:layui-down}@keyframes layui-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-anim-downbit{animation-name:layui-downbit}@-webkit-keyframes layui-scale{0%{opacity:.3;-webkit-transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1)}}@keyframes layui-scale{0%{opacity:.3;-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-ms-transform:scale(1);transform:scale(1)}}.layui-anim-scale{-webkit-animation-name:layui-scale;animation-name:layui-scale}@-webkit-keyframes layui-scale-spring{0%{opacity:.5;-webkit-transform:scale(.5)}80%{opacity:.8;-webkit-transform:scale(1.1)}100%{opacity:1;-webkit-transform:scale(1)}}@keyframes layui-scale-spring{0%{opacity:.5;transform:scale(.5)}80%{opacity:.8;transform:scale(1.1)}100%{opacity:1;transform:scale(1)}}.layui-anim-scaleSpring{-webkit-animation-name:layui-scale-spring;animation-name:layui-scale-spring}@keyframes layui-scalesmall{0%{opacity:.3;transform:scale(1.5)}100%{opacity:1;transform:scale(1)}}.layui-anim-scalesmall{animation-name:layui-scalesmall}@keyframes layui-scalesmall-spring{0%{opacity:.3;transform:scale(1.5)}80%{opacity:.8;transform:scale(.9)}100%{opacity:1;transform:scale(1)}}.layui-anim-scalesmall-spring{animation-name:layui-scalesmall-spring}@-webkit-keyframes layui-fadein{0%{opacity:0}100%{opacity:1}}@keyframes layui-fadein{0%{opacity:0}100%{opacity:1}}.layui-anim-fadein{-webkit-animation-name:layui-fadein;animation-name:layui-fadein}@-webkit-keyframes layui-fadeout{0%{opacity:1}100%{opacity:0}}@keyframes layui-fadeout{0%{opacity:1}100%{opacity:0}}.layui-anim-fadeout{-webkit-animation-name:layui-fadeout;animation-name:layui-fadeout}html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-wrap{font-size:13px;font-family:"Courier New",Consolas,"Lucida Console"}.layui-code-view{display:block;position:relative;padding:0!important;border:1px solid #eee;border-left-width:6px;background-color:#fff;color:#333}.layui-code-view pre{margin:0!important}.layui-code-header{position:relative;z-index:3;padding:0 11px;height:40px;line-height:40px;border-bottom:1px solid #eee;background-color:#fafafa;font-size:12px}.layui-code-header>.layui-code-header-about{position:absolute;right:11px;top:0;color:#b7b7b7}.layui-code-header-about>a{padding-left:10px}.layui-code-wrap{position:relative;display:block;z-index:1;margin:0!important;padding:11px 0!important;overflow-x:hidden;overflow-y:auto}.layui-code-line{position:relative;line-height:19px;margin:0!important}.layui-code-line-number{position:absolute;left:0;top:0;padding:0 8px;min-width:45px;height:100%;text-align:right;user-select:none;white-space:nowrap;overflow:hidden}.layui-code-line-content{padding:0 11px;word-wrap:break-word;white-space:pre-wrap}.layui-code-ln-mode>.layui-code-wrap>.layui-code-line{padding-left:45px}.layui-code-ln-side{position:absolute;left:0;top:0;bottom:0;z-index:0;width:45px;border-right:1px solid #eee;border-color:rgb(126 122 122 / 15%);background-color:#fafafa;pointer-events:none}.layui-code-nowrap>.layui-code-wrap{overflow:auto}.layui-code-nowrap>.layui-code-wrap>.layui-code-line>.layui-code-line-content{white-space:pre;word-wrap:normal}.layui-code-nowrap>.layui-code-ln-side{border-right-width:0!important;background:0 0!important}.layui-code-fixbar{position:absolute;top:8px;right:11px;padding-right:45px;z-index:5}.layui-code-fixbar>span{position:absolute;right:0;top:0;padding:0 8px;color:#777;transition:all .3s}.layui-code-fixbar>span:hover{color:#16b777}.layui-code-copy{display:none;cursor:pointer}.layui-code-preview>.layui-code-view>.layui-code-fixbar .layui-code-copy{display:none!important}.layui-code-view:hover>.layui-code-fixbar .layui-code-copy{display:block}.layui-code-view:hover>.layui-code-fixbar .layui-code-lang-marker{display:none}.layui-code-theme-dark,.layui-code-theme-dark>.layui-code-header{border-color:rgb(126 122 122 / 15%);background-color:#1f1f1f}.layui-code-theme-dark{border-width:1px;color:#ccc}.layui-code-theme-dark>.layui-code-ln-side{border-right-color:#2a2a2a;background:0 0;color:#6e7681}.layui-code textarea{display:none}.layui-code-preview>.layui-code,.layui-code-preview>.layui-code-view{margin:0}.layui-code-preview>.layui-tab{position:relative;z-index:1;margin-bottom:0}.layui-code-preview>.layui-tab>.layui-tab-title{border-width:0}.layui-code-preview .layui-code-item{display:none}.layui-code-item-preview{position:relative;padding:16px}.layui-code-item-preview>iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:none}.layui-code-tools{position:absolute;right:11px;top:8px;line-height:normal}.layui-code-tools>i{display:inline-block;margin-left:6px;padding:3px;cursor:pointer}.layui-code-tools>i.layui-icon-file-b{color:#999}.layui-code-tools>i:hover{color:#16b777}.layui-code-full{position:fixed;left:0;top:0;z-index:1111111;width:100%;height:100%;background-color:#fff}.layui-code-full .layui-code-item{width:100%!important;border-width:0!important;border-top-width:1px!important}.layui-code-full .layui-code-item,.layui-code-full .layui-code-view,.layui-code-full .layui-code-wrap{height:calc(100vh - 51px)!important;box-sizing:border-box}.layui-code-full .layui-code-item-preview{overflow:auto}.layui-code-view.layui-code-hl{line-height:20px!important;border-left-width:1px}.layui-code-view.layui-code-hl>.layui-code-ln-side{background-color:transparent}.layui-code-theme-dark.layui-code-hl,.layui-code-theme-dark.layui-code-hl>.layui-code-ln-side{border-color:rgb(126 122 122 / 15%)}html #layuicss-laydate{display:none;position:absolute;width:1989px}.layui-laydate *{margin:0;padding:0}.layui-laydate,.layui-laydate *{box-sizing:border-box}.layui-laydate{position:absolute;z-index:99999999;margin:5px 0;border-radius:2px;font-size:14px;line-height:normal;-webkit-animation-duration:.2s;animation-duration:.2s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-laydate-main{width:272px}.layui-laydate-content td,.layui-laydate-header *,.layui-laydate-list li{transition-duration:.3s;-webkit-transition-duration:.3s}.layui-laydate-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px");position:fixed;_position:absolute;pointer-events:auto}@keyframes laydate-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-laydate{animation-name:laydate-downbit}.layui-laydate-static{position:relative;z-index:0;display:inline-block;margin:0;-webkit-animation:none;animation:none}.laydate-ym-show .laydate-next-m,.laydate-ym-show .laydate-prev-m{display:none!important}.laydate-ym-show .laydate-next-y,.laydate-ym-show .laydate-prev-y{display:inline-block!important}.laydate-ym-show .laydate-set-ym span[lay-type=month]{display:none!important}.laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-time-show .layui-laydate-header .layui-icon{display:none!important}.layui-laydate-header{position:relative;line-height:30px;padding:10px 70px 5px}.layui-laydate-header *{display:inline-block;vertical-align:bottom}.layui-laydate-header i{position:absolute;top:10px;padding:0 5px;color:#999;font-size:18px;cursor:pointer}.layui-laydate-header i.laydate-prev-y{left:15px}.layui-laydate-header i.laydate-prev-m{left:45px}.layui-laydate-header i.laydate-next-y{right:15px}.layui-laydate-header i.laydate-next-m{right:45px}.laydate-set-ym{width:100%;text-align:center;box-sizing:border-box;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.laydate-set-ym span{padding:0 10px;cursor:pointer}.laydate-time-text{cursor:default!important}.layui-laydate-content{position:relative;padding:10px;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content table{border-collapse:collapse;border-spacing:0}.layui-laydate-content td,.layui-laydate-content th{width:36px;height:30px;padding:0;text-align:center}.layui-laydate-content th{font-weight:400}.layui-laydate-content td{position:relative;cursor:pointer}.laydate-day-mark{position:absolute;left:0;top:0;width:100%;line-height:30px;font-size:12px;overflow:hidden}.laydate-day-mark::after{position:absolute;content:'';right:2px;top:2px;width:5px;height:5px;border-radius:50%}.laydate-day-holidays:before{position:absolute;left:0;top:0;font-size:12px;transform:scale(.7)}.laydate-day-holidays:before{content:'\4F11';color:#ff5722}.laydate-day-holidays[type=workdays]:before{content:'\73ED';color:inherit}.layui-laydate .layui-this .laydate-day-holidays:before{color:#fff}.layui-laydate-footer{position:relative;height:46px;line-height:26px;padding:10px}.layui-laydate-footer span{display:inline-block;vertical-align:top;height:26px;line-height:24px;padding:0 10px;border:1px solid #c9c9c9;border-radius:2px;background-color:#fff;font-size:12px;cursor:pointer;white-space:nowrap;transition:all .3s}.layui-laydate-footer span:hover{color:#16b777}.layui-laydate-footer span.layui-laydate-preview{cursor:default;border-color:transparent!important}.layui-laydate-footer span.layui-laydate-preview:hover{color:#777}.layui-laydate-footer span:first-child.layui-laydate-preview{padding-left:0}.laydate-footer-btns{position:absolute;right:10px;top:10px}.laydate-footer-btns span{margin:0 0 0 -1px;border-radius:0}.laydate-footer-btns span:first-child{border-radius:2px 0 0 2px}.laydate-footer-btns span:last-child{border-radius:0 2px 2px 0}.layui-laydate-shortcut{width:80px;padding:6px 0;display:inline-block;vertical-align:top;overflow:auto;max-height:276px;text-align:center}.layui-laydate-shortcut+.layui-laydate-main{display:inline-block;border-left:1px solid #e2e2e2}.layui-laydate-shortcut>li{padding:5px 8px;cursor:pointer;line-height:18px}.layui-laydate .layui-laydate-list{position:absolute;left:0;top:0;width:100%;height:100%;padding:10px;box-sizing:border-box;background-color:#fff}.layui-laydate .layui-laydate-list>li{position:relative;display:inline-block;width:33.3%;height:36px;line-height:36px;margin:3px 0;vertical-align:middle;text-align:center;cursor:pointer;list-style:none}.layui-laydate .laydate-month-list>li{width:25%;margin:17px 0}.laydate-time-list{display:table}.layui-laydate .laydate-time-list>li{display:table-cell;height:100%;margin:0;line-height:normal;cursor:default}.layui-laydate .laydate-time-list p{position:relative;top:-4px;margin:0;line-height:29px}.layui-laydate .laydate-time-list ol{height:181px;overflow:hidden}.layui-laydate .laydate-time-list>li:hover ol{overflow-y:auto}.layui-laydate .laydate-time-list ol li{width:130%;padding-left:33px;height:30px;line-height:30px;text-align:left;cursor:pointer}.layui-laydate .laydate-time-list-hide-1 ol li{padding-left:53px}.layui-laydate .laydate-time-list-hide-2 ol li{padding-left:117px}.layui-laydate-hint{position:absolute;top:115px;left:50%;width:250px;margin-left:-125px;line-height:20px;padding:15px;text-align:center;font-size:12px;color:#ff5722}.layui-laydate-range{width:546px}.layui-laydate-range .layui-laydate-main{display:inline-block;vertical-align:middle;max-width:50%}.layui-laydate-range .laydate-main-list-1 .layui-laydate-content,.layui-laydate-range .laydate-main-list-1 .layui-laydate-header{border-left:1px solid #e2e2e2}.layui-laydate-range.layui-laydate-linkage .laydate-main-list-0 .laydate-next-m,.layui-laydate-range.layui-laydate-linkage .laydate-main-list-0 .laydate-next-y,.layui-laydate-range.layui-laydate-linkage .laydate-main-list-1 .laydate-prev-m,.layui-laydate-range.layui-laydate-linkage .laydate-main-list-1 .laydate-prev-y{display:none}.layui-laydate,.layui-laydate-hint{border:1px solid #d2d2d2;box-shadow:0 2px 4px rgba(0,0,0,.12);background-color:#fff;color:#777}.layui-laydate-header{border-bottom:1px solid #e2e2e2}.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:#16b777}.layui-laydate-content{border-top:none 0;border-bottom:none 0}.layui-laydate-content th{color:#333}.layui-laydate-content td{color:#777}.layui-laydate-content td.laydate-day-now{color:#16b777}.layui-laydate-content td.laydate-day-now:after{content:'';position:absolute;width:100%;height:30px;left:0;top:0;border:1px solid #16b777;box-sizing:border-box}.layui-laydate-linkage .layui-laydate-content td.laydate-selected>div{background-color:#00f7de}.layui-laydate-linkage .laydate-selected:hover>div{background-color:#00f7de!important}.layui-laydate-content td.laydate-selected:after,.layui-laydate-content td:hover:after{content:none}.layui-laydate-content td>div:hover,.layui-laydate-list li:hover,.layui-laydate-shortcut>li:hover{background-color:#eee;color:#333}.laydate-time-list li ol{margin:0;padding:0;border:1px solid #e2e2e2;border-left-width:0}.laydate-time-list li:first-child ol{border-left-width:1px}.laydate-time-list>li:hover{background:0 0}.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color:#d2d2d2}.layui-laydate-linkage .laydate-selected.laydate-day-next>div,.layui-laydate-linkage .laydate-selected.laydate-day-prev>div{background-color:#f8f8f8!important}.layui-laydate-footer{border-top:1px solid #e2e2e2}.layui-laydate-hint{color:#ff5722}.laydate-day-mark::after{background-color:#16b777}.layui-laydate-content td.layui-this .laydate-day-mark::after{display:none}.layui-laydate-footer span[lay-type=date]{color:#16b777}.layui-laydate .layui-this,.layui-laydate .layui-this>div{background-color:#16baaa!important;color:#fff!important}.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate .layui-this.laydate-disabled,.layui-laydate .layui-this.laydate-disabled>div{background-color:#eee!important}.layui-laydate-content td>div{padding:7px 0;height:100%}.laydate-theme-molv{border:none}.laydate-theme-molv.layui-laydate-range{width:548px}.laydate-theme-molv .layui-laydate-main{width:274px}.laydate-theme-molv .layui-laydate-header{border:none;background-color:#16baaa}.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:#f6f6f6}.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color:#fff}.laydate-theme-molv .layui-laydate-content{border:1px solid #e2e2e2;border-top:none;border-bottom:none}.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content{border-left:none}.laydate-theme-molv .layui-laydate-footer{border:1px solid #e2e2e2}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead{border:1px solid #e2e2e2}.layui-laydate-linkage.laydate-theme-grid .laydate-selected,.layui-laydate-linkage.laydate-theme-grid .laydate-selected:hover{background-color:#f2f2f2!important;color:#16baaa!important}.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-next,.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-prev{color:#d2d2d2!important}.laydate-theme-grid .laydate-month-list,.laydate-theme-grid .laydate-year-list{margin:1px 0 0 1px}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li{margin:0 -1px -1px 0}.laydate-theme-grid .laydate-year-list>li{height:43px;line-height:43px}.laydate-theme-grid .laydate-month-list>li{height:71px;line-height:71px}.laydate-theme-grid .layui-laydate-content td>div{height:29px;margin-top:-1px}.laydate-theme-circle .layui-laydate-content td.layui-this>div,.laydate-theme-circle .layui-laydate-content td>div{width:28px;height:28px;line-height:28px;border-radius:14px;margin:0 4px;padding:0}.layui-laydate.laydate-theme-circle .layui-laydate-content table td.layui-this{background-color:transparent!important}.laydate-theme-grid.laydate-theme-circle .layui-laydate-content td>div{margin:0 3.5px}.laydate-theme-fullpanel .layui-laydate-main{width:526px}.laydate-theme-fullpanel .layui-laydate-list{width:252px;left:272px}.laydate-theme-fullpanel .laydate-set-ym span{display:none}.laydate-theme-fullpanel .laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-theme-fullpanel .laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-theme-fullpanel .laydate-time-show .layui-laydate-header .layui-icon{display:inline-block!important}.laydate-theme-fullpanel .laydate-btns-time{display:none}.laydate-theme-fullpanel .laydate-time-list-hide-1 ol li{padding-left:49px}.laydate-theme-fullpanel .laydate-time-list-hide-2 ol li{padding-left:107px}html #layuicss-layer{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{opacity:0;transition:opacity .35s cubic-bezier(.34,.69,.1,1);top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px")}.layui-layer{-webkit-overflow-scrolling:touch}.layui-layer{top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;border-radius:2px;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #b2b2b2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-btn a,.layui-layer-setwin span{display:inline-block;vertical-align:middle;*display:inline;*zoom:1}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layer-anim{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-00{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@keyframes layer-slide-down{from{transform:translate3d(0,-100%,0)}to{transform:translate3d(0,0,0)}}@keyframes layer-slide-down-out{from{transform:translate3d(0,0,0)}to{transform:translate3d(0,-100%,0)}}.layer-anim-slide-down{animation-name:layer-slide-down}.layer-anim-slide-down-out{animation-name:layer-slide-down-out}@keyframes layer-slide-left{from{transform:translate3d(100%,0,0)}to{transform:translate3d(0,0,0)}}@keyframes layer-slide-left-out{from{transform:translate3d(0,0,0)}to{transform:translate3d(100%,0,0)}}.layer-anim-slide-left{animation-name:layer-slide-left}.layer-anim-slide-left-out{animation-name:layer-slide-left-out}@keyframes layer-slide-up{from{transform:translate3d(0,100%,0)}to{transform:translate3d(0,0,0)}}@keyframes layer-slide-up-out{from{transform:translate3d(0,0,0)}to{transform:translate3d(0,100%,0)}}.layer-anim-slide-up{animation-name:layer-slide-up}.layer-anim-slide-up-out{animation-name:layer-slide-up-out}@keyframes layer-slide-right{from{transform:translate3d(-100%,0,0)}to{transform:translate3d(0,0,0)}}@keyframes layer-slide-right-out{from{transform:translate3d(0,0,0)}to{transform:translate3d(-100%,0,0)}}.layer-anim-slide-right{animation-name:layer-slide-right}.layer-anim-slide-right-out{animation-name:layer-slide-right-out}.layui-layer-title{padding:0 81px 0 16px;height:50px;line-height:50px;border-bottom:1px solid #f0f0f0;font-size:14px;color:#333;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:16px;font-size:0;line-height:initial}.layui-layer-setwin span{position:relative;width:16px;height:16px;line-height:18px;margin-left:10px;text-align:center;font-size:16px;cursor:pointer;color:#000;_overflow:hidden;box-sizing:border-box}.layui-layer-setwin .layui-layer-min:before{content:'';position:absolute;width:12px;border-bottom:1px solid #2e2d3c;left:50%;top:50%;margin:-.5px 0 0 -6px;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover:before{background-color:#2d93ca}.layui-layer-setwin .layui-layer-max:after,.layui-layer-setwin .layui-layer-max:before{content:'';position:absolute;left:50%;top:50%;z-index:1;width:9px;height:9px;margin:-5px 0 0 -5px;border:1px solid #2e2d3c}.layui-layer-setwin .layui-layer-max:hover:after,.layui-layer-setwin .layui-layer-max:hover:before{border-color:#2d93ca}.layui-layer-setwin .layui-layer-min:hover:before{background-color:#2d93ca}.layui-layer-setwin .layui-layer-maxmin:after,.layui-layer-setwin .layui-layer-maxmin:before{width:7px;height:7px;margin:-3px 0 0 -3px;background-color:#fff}.layui-layer-setwin .layui-layer-maxmin:after{z-index:0;margin:-5px 0 0 -1px}.layui-layer-setwin .layui-layer-close{cursor:pointer}.layui-layer-setwin .layui-layer-close:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;color:#fff;background-color:#787878;padding:3px;border:3px solid;width:28px;height:28px;font-size:16px;font-weight:bolder;border-radius:50%;margin-left:0;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{opacity:unset;background-color:#3888f6}.layui-layer-btn{text-align:right;padding:0 15px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:30px;line-height:30px;margin:5px 5px 0;padding:0 16px;border:1px solid #dedede;background-color:#fff;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none;box-sizing:border-box}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:transparent;background-color:#1e9fff;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:240px}.layui-layer-dialog .layui-layer-content{position:relative;padding:16px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-face{position:absolute;top:18px;left:16px;color:#959595;font-size:32px;_left:-40px}.layui-layer-dialog .layui-layer-content .layui-icon-tips{color:#f39b12}.layui-layer-dialog .layui-layer-content .layui-icon-success{color:#16b777}.layui-layer-dialog .layui-layer-content .layui-icon-error{top:19px;color:#ff5722}.layui-layer-dialog .layui-layer-content .layui-icon-question{color:#ffb800}.layui-layer-dialog .layui-layer-content .layui-icon-lock{color:#787878}.layui-layer-dialog .layui-layer-content .layui-icon-face-cry{color:#ff5722}.layui-layer-dialog .layui-layer-content .layui-icon-face-smile{color:#16b777}.layui-layer-rim{border:6px solid #8d8d8d;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #d3d4d3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-close{color:#fff}.layui-layer-hui .layui-layer-content{padding:11px 24px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:18px 24px 18px 58px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:76px;height:38px;line-height:38px;text-align:center}.layui-layer-loading-icon{font-size:38px;color:#959595}.layui-layer-loading2{text-align:center}.layui-layer-loading-2{position:relative;height:38px}.layui-layer-loading-2:after,.layui-layer-loading-2:before{content:'';position:absolute;left:50%;top:50%;width:38px;height:38px;margin:-19px 0 0 -19px;border-radius:50%;border:3px solid #d2d2d2;box-sizing:border-box}.layui-layer-loading-2:after{border-color:transparent;border-left-color:#1e9fff}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:8px 15px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:5px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan .layui-layer-title{background:#4476a7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;border-top:1px solid #e9e7e7}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#e9e7e7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#c9c5c5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92b8b1}.layui-layer-lan .layui-layer-setwin .layui-icon,.layui-layer-molv .layui-layer-setwin .layui-icon{color:#fff}.layui-layer-win10{border:1px solid #aaa;box-shadow:1px 1px 6px rgba(0,0,0,.3);border-radius:none}.layui-layer-win10 .layui-layer-title{height:32px;line-height:32px;padding-left:8px;border-bottom:none;font-size:12px}.layui-layer-win10 .layui-layer-setwin{right:0;top:0}.layui-layer-win10 .layui-layer-setwin span{margin-left:0;width:32px;height:32px;padding:8px}.layui-layer-win10.layui-layer-page .layui-layer-setwin span{width:38px}.layui-layer-win10 .layui-layer-setwin span:hover{background-color:#e5e5e5}.layui-layer-win10 .layui-layer-setwin span.layui-icon-close:hover{background-color:#e81123;color:#fff}.layui-layer-win10.layui-layer-dialog .layui-layer-content{padding:8px 16px 32px;color:#0033bc}.layui-layer-win10.layui-layer-dialog .layui-layer-padding{padding-top:18px;padding-left:58px}.layui-layer-win10 .layui-layer-btn{padding:5px 5px 10px;border-top:1px solid #dfdfdf;background-color:#f0f0f0}.layui-layer-win10 .layui-layer-btn a{height:20px;line-height:18px;background-color:#e1e1e1;border-color:#adadad;color:#000;font-size:12px;transition:all .3s}.layui-layer-win10 .layui-layer-btn a:hover{border-color:#2a8edd;background-color:#e5f1fb}.layui-layer-win10 .layui-layer-btn .layui-layer-btn0{border-color:#0078d7}.layui-layer-prompt .layui-layer-input{display:block;width:260px;height:36px;margin:0 auto;line-height:30px;padding-left:10px;border:1px solid #e6e6e6;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px;padding:6px 10px}.layui-layer-prompt .layui-layer-content{padding:16px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;display:inline-block;vertical-align:top;border-left:1px solid transparent;border-right:1px solid transparent;min-width:80px;max-width:300px;padding:0 16px;text-align:center;cursor:default;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;cursor:pointer}.layui-layer-tab .layui-layer-title span.layui-this{height:51px;border-left-color:#eee;border-right-color:#eee;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left-color:transparent}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{background:0 0;box-shadow:none}.layui-layer-photos .layui-layer-content{overflow:visible;text-align:center}.layui-layer-photos .layer-layer-photos-main img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-photos-next,.layui-layer-photos-prev{position:fixed;top:50%;width:52px;height:52px;line-height:52px;margin-top:-26px;cursor:pointer;font-size:52px;color:#717171}.layui-layer-photos-prev{left:32px}.layui-layer-photos-next{right:32px}.layui-layer-photos-next:hover,.layui-layer-photos-prev:hover{color:#959595}.layui-layer-photos-toolbar{position:fixed;left:0;right:0;bottom:0;width:100%;height:52px;line-height:52px;background-color:#000\9;filter:Alpha(opacity=60);background-color:rgba(0,0,0,.32);color:#fff;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;font-size:0}.layui-layer-photos-toolbar>*{display:inline-block;vertical-align:top;padding:0 16px;font-size:12px;color:#fff;*display:inline;*zoom:1}.layui-layer-photos-toolbar *{font-size:12px}.layui-layer-photos-header{top:0;bottom:auto}.layui-layer-photos-header>span{cursor:pointer}.layui-layer-photos-header>span:hover{background-color:rgba(51,51,51,.32)}.layui-layer-photos-header .layui-icon{font-size:18px}.layui-layer-photos-footer>h3{max-width:65%;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-layer-photos-footer a:hover{text-decoration:underline}.layui-layer-photos-footer em{font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s} \ No newline at end of file diff --git a/static/system/component/layui/layui.js b/static/system/component/layui/layui.js index 83af036..a0d8d67 100644 --- a/static/system/component/layui/layui.js +++ b/static/system/component/layui/layui.js @@ -1 +1 @@ -/** v2.8.6 | MIT Licensed */;!function(d){"use strict";var t,h=d.document,m={modules:{},status:{},timeout:10,event:{}},o=function(){this.v="2.8.6"},e=d.LAYUI_GLOBAL||{},v=(t=h.currentScript?h.currentScript.src:function(){for(var t,e=h.scripts,n=e.length-1,o=n;01e3*m.timeout/4?g(u+" is not a valid module","error"):void(m.status[u]?c():setTimeout(o,4))}())}function c(){e.push(layui[u]),11e3*m.timeout/4?g(u+" is not a valid module","error"):void("string"==typeof m.modules[u]&&m.status[u]?c():setTimeout(f,4))}():((p=h.createElement("script"))["async"]=!0,p.charset="utf-8",p.src=y+((i=!0===m.version?m.v||(new Date).getTime():m.version||"")?"?v="+i:""),a.appendChild(p),!p.attachEvent||p.attachEvent.toString&&p.attachEvent.toString().indexOf("[native code")<0||b?p.addEventListener("load",function(t){s(t,y)},!1):p.attachEvent("onreadystatechange",function(t){s(t,y)}),m.modules[u]=y),r},o.prototype.disuse=function(t){var n=this;return t=n.isArray(t)?t:[t],n.each(t,function(t,e){m.status[e],delete n[e],delete N[e],delete n.modules[e],delete m.status[e],delete m.modules[e]}),n},o.prototype.getStyle=function(t,e){t=t.currentStyle||d.getComputedStyle(t,null);return t[t.getPropertyValue?"getPropertyValue":"getAttribute"](e)},o.prototype.link=function(n,o,t){var r=this,e=h.getElementsByTagName("head")[0],i=h.createElement("link"),a="layuicss-"+((t="string"==typeof o?o:t)||n).replace(/\.|\//g,""),u="creating",l=0;return i.href=n+(m.debug?"?v="+(new Date).getTime():""),i.rel="stylesheet",i.id=a,i.media="all",h.getElementById(a)||e.appendChild(i),"function"!=typeof o||function s(t){var e=h.getElementById(a);return++l>1e3*m.timeout/100?g(n+" timeout"):void(1989===parseInt(r.getStyle(e,"width"))?(t===u&&e.removeAttribute("lay-status"),e.getAttribute("lay-status")===u?setTimeout(s,100):o()):(e.setAttribute("lay-status",u),setTimeout(function(){s(u)},100)))}(),r},o.prototype.addcss=function(t,e,n){return layui.link(m.dir+"css/"+t,e,n)},m.callback={},o.prototype.factory=function(t){if(layui[t])return"function"==typeof m.callback[t]?m.callback[t]:null},o.prototype.img=function(t,e,n){var o=new Image;if(o.src=t,o.complete)return e(o);o.onload=function(){o.onload=null,"function"==typeof e&&e(o)},o.onerror=function(t){o.onerror=null,"function"==typeof n&&n(t)}},o.prototype.config=function(t){for(var e in t=t||{})m[e]=t[e];return this},o.prototype.modules=function(){var t,e={};for(t in N)e[t]=N[t];return e}(),o.prototype.extend=function(t){for(var e in t=t||{})this[e]||this.modules[e]?g(e+" Module already exists","error"):this.modules[e]=t[e];return this},o.prototype.router=o.prototype.hash=function(t){var n={path:[],search:{},hash:((t=t||location.hash).match(/[^#](#.*$)/)||[])[1]||""};return/^#\//.test(t)&&(t=t.replace(/^#\//,""),n.href="/"+t,t=t.replace(/([^#])(#.*$)/,"$1").split("/")||[],this.each(t,function(t,e){/^\w+=/.test(e)?(e=e.split("="),n.search[e[0]]=e[1]):n.path.push(e)})),n},o.prototype.url=function(t){var r,e,n=this;return{pathname:(t?((t.match(/\.[^.]+?\/.+/)||[])[0]||"").replace(/^[^\/]+/,"").replace(/\?.+/,""):location.pathname).replace(/^\//,"").split("/"),search:(r={},e=(t?((t.match(/\?.+/)||[])[0]||"").replace(/\#.+/,""):location.search).replace(/^\?+/,"").split("&"),n.each(e,function(t,e){var n=e.indexOf("="),o=n<0?e.substr(0,e.length):0!==n&&e.substr(0,n);o&&(r[o]=0(s.innerHeight||l.documentElement.clientHeight)},h.position=function(t,e,n){var i,r,o,c,u,a,f;e&&(n=n||{},t!==l&&t!==h("body")[0]||(n.clickType="right"),u="right"===n.clickType?{left:(u=n.e||s.event||{}).clientX,top:u.clientY,right:u.clientX,bottom:u.clientY}:t.getBoundingClientRect(),a=e.offsetWidth,f=e.offsetHeight,i=function(t){return l.body[t=t?"scrollLeft":"scrollTop"]|l.documentElement[t]},o=u.left,c=u.bottom,"center"===n.align?o-=(a-t.offsetWidth)/2:"right"===n.align&&(o=o-a+t.offsetWidth),(o=o+a+5>(r=function(t){return l.documentElement[t?"clientWidth":"clientHeight"]})("width")?r("width")-a-5:o)<5&&(o=5),c+f+5>r()&&(u.top>f+5?c=u.top-f-10:"right"===n.clickType?(c=r()-f-10)<0&&(c=0):c=5),(a=n.position)&&(e.style.position=a),e.style.left=o+("fixed"===a?0:i(1))+"px",e.style.top=c+("fixed"===a?0:i())+"px",h.hasScrollbar()||(f=e.getBoundingClientRect(),!n.SYSTEM_RELOAD&&f.bottom+5>r()&&(n.SYSTEM_RELOAD=!0,setTimeout(function(){h.position(t,e,n)},50))))},h.options=function(t,e){if(e="object"==typeof e?e:{attr:e},t===l)return{};var t=h(t),n=e.attr||"lay-options",t=t.attr(n);try{return new Function("return "+(t||"{}"))()}catch(i){return layui.hint().error(e.errorText||[n+'="'+t+'"',"\n parseerror: "+i].join("\n"),"error"),{}}},h.isTopElem=function(n){var t=[l,h("body")[0]],i=!1;return h.each(t,function(t,e){if(e===n)return i=!0}),i},r.addStr=function(n,t){return n=n.replace(/\s+/," "),t=t.replace(/\s+/," ").split(" "),h.each(t,function(t,e){new RegExp("\\b"+e+"\\b").test(n)||(n=n+" "+e)}),n.replace(/^\s|\s$/,"")},r.removeStr=function(n,t){return n=n.replace(/\s+/," "),t=t.replace(/\s+/," ").split(" "),h.each(t,function(t,e){e=new RegExp("\\b"+e+"\\b");e.test(n)&&(n=n.replace(e,""))}),n.replace(/\s+/," ").replace(/^\s|\s$/,"")},r.fn.find=function(n){var i=[],r="object"==typeof n;return this.each(function(t,e){e=r&&e.contains(n)?n:e.querySelectorAll(n||null);h.each(e,function(t,e){i.push(e)})}),h(i)},r.fn.each=function(t){return h.each.call(this,this,t)},r.fn.addClass=function(n,i){return this.each(function(t,e){e.className=r[i?"removeStr":"addStr"](e.className,n)})},r.fn.removeClass=function(t){return this.addClass(t,!0)},r.fn.hasClass=function(n){var i=!1;return this.each(function(t,e){new RegExp("\\b"+n+"\\b").test(e.className)&&(i=!0)}),i},r.fn.css=function(e,i){var t=this,r=function(t){return isNaN(t)?t:t+"px"};return"string"!=typeof e||i!==undefined?t.each(function(t,n){"object"==typeof e?h.each(e,function(t,e){n.style[t]=r(e)}):n.style[e]=r(i)}):0]|&(?=#[a-zA-Z0-9]+)/g.test(e+="")?e.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,"""):e}},i=function(e){return new RegExp(e,"g")},u=function(e,r){var n="Laytpl Error: ";return"object"==typeof console&&console.error(n+e+"\n"+(r||"")),n+e},n=function(e,r){var n=this,e=(n.config=n.config||{},n.template=e,function(e){for(var r in e)n.config[r]=e[r]});e(c),e(r)},r=(n.prototype.tagExp=function(e,r,n){var c=this.config;return i((r||"")+c.open+["#([\\s\\S])+?","([^{#}])*?"][e||0]+c.close+(n||""))},n.prototype.parse=function(e,r){var n=this,c=n.config,t=e,o=i("^"+c.open+"#",""),p=i(c.close+"$","");if("string"!=typeof e)return e;e='"use strict";var view = "'+(e=e.replace(/\s+|\r|\t|\n/g," ").replace(i(c.open+"#"),c.open+"# ").replace(i(c.close+"}"),"} "+c.close).replace(/\\/g,"\\\\").replace(i(c.open+"!(.+?)!"+c.close),function(e){return e=e.replace(i("^"+c.open+"!"),"").replace(i("!"+c.close),"").replace(i(c.open+"|"+c.close),function(e){return e.replace(/(.)/g,"\\$1")})}).replace(/(?="|')/g,"\\").replace(n.tagExp(),function(e){return'";'+(e=e.replace(o,"").replace(p,"")).replace(/\\(.)/g,"$1")+';view+="'}).replace(n.tagExp(1),function(e){var r='"+laytpl.escape(';return e.replace(/\s/g,"")===c.open+c.close?"":(e=e.replace(i(c.open+"|"+c.close),""),/^=/.test(e)?e=e.replace(/^=/,""):/^-/.test(e)&&(e=e.replace(/^-/,""),r='"+('),r+e.replace(/\\(.)/g,"$1")+')+"')}))+'";return view;';try{return n.cache=e=new Function("d, laytpl",e),e(r,l)}catch(a){return delete n.cache,u(a,t)}},n.prototype.render=function(e,r){e=e||{};var n=this,e=n.cache?n.cache(e,l):n.parse(n.template,e);return"function"==typeof r&&r(e),e},function(e,r){return new n(e,r)});r.config=function(e){for(var r in e=e||{})c[r]=e[r]},r.v="2.0.0",e("laytpl",r)});layui.define(function(e){"use strict";var r=document,u="getElementById",c="getElementsByTagName",a="layui-disabled",t=function(e){var a=this;a.config=e||{},a.config.index=++o.index,a.render(!0)},o=(t.prototype.type=function(){var e=this.config;if("object"==typeof e.elem)return e.elem.length===undefined?2:3},t.prototype.view=function(){var t,i,n=this.config,r=n.groups="groups"in n?Number(n.groups)||0:5,u=(n.layout="object"==typeof n.layout?n.layout:["prev","page","next"],n.count=Number(n.count)||0,n.curr=Number(n.curr)||1,n.limits="object"==typeof n.limits?n.limits:[10,20,30,40,50],n.limit=Number(n.limit)||10,n.pages=Math.ceil(n.count/n.limit)||1,n.curr>n.pages?n.curr=n.pages:n.curr<1&&(n.curr=1),r<0?r=1:r>n.pages&&(r=n.pages),n.prev="prev"in n?n.prev:"上一页",n.next="next"in n?n.next:"下一页",n.pages>r?Math.ceil((n.curr+(1'+n.prev+"":"",page:function(){var e=[];if(n.count<1)return"";1'+(n.first||1)+"");var a=Math.floor((r-1)/2),t=1n.pages?n.pages:a:r;for(i-t…');t<=i;t++)t===n.curr?e.push('"+t+""):e.push(''+t+"");return n.pages>r&&n.pages>i&&!1!==n.last&&(i+1…'),0!==r&&e.push(''+(n.last||n.pages)+"")),e.join("")}(),next:n.next?''+n.next+"":"",count:'\u5171 '+n.count+" \u6761",limit:(t=['"),refresh:['','',""].join(""),skip:['到第','','页',""].join("")};return['
',(i=[],layui.each(n.layout,function(e,a){l[a]&&i.push(l[a])}),i.join("")),"
"].join("")},t.prototype.jump=function(e,a){if(e){var t=this,i=t.config,n=e.children,r=e[c]("button")[0],u=e[c]("input")[0],e=e[c]("select")[0],l=function(){var e=Number(u.value.replace(/\s|\D/g,""));e&&(i.curr=e,t.render())};if(a)return l();for(var s=0,p=n.length;si.pages||(i.curr=e,t.render())});e&&o.on(e,"change",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),r&&o.on(r,"click",function(){l()})}},t.prototype.skip=function(t){var i,e;t&&(i=this,(e=t[c]("input")[0])&&o.on(e,"keyup",function(e){var a=this.value,e=e.keyCode;/^(37|38|39|40)$/.test(e)||(/\D/.test(a)&&(this.value=a.replace(/\D/,"")),13===e&&i.jump(t,!0))}))},t.prototype.render=function(e){var a=this,t=a.config,i=a.type(),n=a.view(),i=(2===i?t.elem&&(t.elem.innerHTML=n):3===i?t.elem.html(n):r[u](t.elem)&&(r[u](t.elem).innerHTML=n),t.jump&&t.jump(t,e),r[u]("layui-laypage-"+t.index));a.jump(i),t.hash&&!e&&(location.hash="!"+t.hash+"="+t.curr),a.skip(i)},{render:function(e){return new t(e).index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(a,e,t){return a.attachEvent?a.attachEvent("on"+e,function(e){e.target=e.srcElement,t.call(a,e)}):a.addEventListener(e,t,!1),this}});e("laypage",o)});!function(i,v){"use strict";var n=i.layui&&layui.define,l={getPath:i.lay&&lay.getPath?lay.getPath:"",link:function(e,t,a){D.path&&i.lay&&lay.layui&&lay.layui.link(D.path+e,t,a)}},e=i.LAYUI_GLOBAL||{},d="layui-laydate-id",D={v:"5.5.0",config:{weekStart:0},index:i.laydate&&i.laydate.v?1e5:0,path:e.laydate_dir||l.getPath,set:function(e){var t=this;return t.config=lay.extend({},t.config,e),t},ready:function(e){var t="laydate",a=(n?"modules/":"")+"laydate.css?v="+D.v;return n?layui["layui.all"]?"function"==typeof e&&e():layui.addcss(a,e,t):l.link(a,e,t),this}},s=function(){var t=this,e=t.config.id;return(s.that[e]=t).inst={hint:function(e){t.hint.call(t,e)},reload:function(e){t.reload.call(t,e)},config:t.config}},a="laydate",x="layui-this",k="laydate-disabled",h=[100,2e5],T="layui-laydate-static",w="layui-laydate-list",o="laydate-selected",r="layui-laydate-hint",y="laydate-day-prev",m="laydate-day-next",C=".laydate-btns-confirm",M="laydate-time-text",L="laydate-btns-time",E="layui-laydate-preview",S="layui-laydate-shade",I=function(e){var t,a=this,n=(a.index=++D.index,a.config=lay.extend({},a.config,D.config,e),lay(e.elem||a.config.elem));return 1\u8bf7\u91cd\u65b0\u9009\u62e9",invalidDate:"\u4e0d\u5728\u6709\u6548\u65e5\u671f\u6216\u65f6\u95f4\u8303\u56f4\u5185",formatError:["\u65e5\u671f\u683c\u5f0f\u4e0d\u5408\u6cd5
\u5fc5\u987b\u9075\u5faa\u4e0b\u8ff0\u683c\u5f0f\uff1a
","
\u5df2\u4e3a\u4f60\u91cd\u7f6e"],preview:"\u5f53\u524d\u9009\u4e2d\u7684\u7ed3\u679c"},en:{weeks:["Su","Mo","Tu","We","Th","Fr","Sa"],time:["Hours","Minutes","Seconds"],timeTips:"Select Time",startTime:"Start Time",endTime:"End Time",dateTips:"Select Date",month:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],tools:{confirm:"Confirm",clear:"Clear",now:"Now"},timeout:"End time cannot be less than start Time
Please re-select",invalidDate:"Invalid date",formatError:["The date format error
Must be followed\uff1a
","
It has been reset"],preview:"The selected result"}};return e[this.config.lang]||e.cn},I.prototype.reload=function(e){this.config=lay.extend({},this.config,e),this.init()},I.prototype.init=function(){var r=this,o=r.config,e="static"===o.position,t={year:"yyyy",month:"yyyy-MM",date:"yyyy-MM-dd",time:"HH:mm:ss",datetime:"yyyy-MM-dd HH:mm:ss"};o.elem=lay(o.elem),o.eventElem=lay(o.eventElem),o.elem[0]&&("array"!==layui.type(o.theme)&&(o.theme=[o.theme]),o.fullPanel&&("datetime"!==o.type||o.range)&&delete o.fullPanel,r.rangeStr=o.range?"string"==typeof o.range?o.range:"-":"",r.rangeLinked=!(!o.range||!o.rangeLinked||"date"!==o.type&&"datetime"!==o.type),r.autoCalendarModel=function(){var e=r.rangeLinked;return r.rangeLinked=o.range&&("date"===o.type||"datetime"===o.type)&&(!r.startDate||!r.endDate||r.startDate&&r.endDate&&r.startDate.year===r.endDate.year&&r.startDate.month===r.endDate.month),lay(r.elem)[r.rangeLinked?"addClass":"removeClass"]("layui-laydate-linkage"),r.rangeLinked!=e},r.autoCalendarModel.auto=r.rangeLinked&&"auto"===o.rangeLinked,"array"===layui.type(o.range)&&(r.rangeElem=[lay(o.range[0]),lay(o.range[1])]),t[o.type]||(i.console&&console.error&&console.error("laydate type error:'"+o.type+"' is not supported"),o.type="date"),o.format===t.date&&(o.format=t[o.type]||t.date),r.format=s.formatArr(o.format),o.weekStart&&!/^[0-6]$/.test(o.weekStart)&&(t=r.lang(),o.weekStart=t.weeks.indexOf(o.weekStart),-1===o.weekStart&&(o.weekStart=0)),r.EXP_IF="",r.EXP_SPLIT="",lay.each(r.format,function(e,t){e=new RegExp(c).test(t)?"\\d{"+(new RegExp(c).test(r.format[0===e?e+1:e-1]||"")?/^yyyy|y$/.test(t)?4:t.length:/^yyyy$/.test(t)?"1,4":/^y$/.test(t)?"1,308":"1,2")+"}":"\\"+t;r.EXP_IF=r.EXP_IF+e,r.EXP_SPLIT=r.EXP_SPLIT+"("+e+")"}),r.EXP_IF_ONE=new RegExp("^"+r.EXP_IF+"$"),r.EXP_IF=new RegExp("^"+(o.range?r.EXP_IF+"\\s\\"+r.rangeStr+"\\s"+r.EXP_IF:r.EXP_IF)+"$"),r.EXP_SPLIT=new RegExp("^"+r.EXP_SPLIT+"$",""),r.isInput(o.elem[0])||"focus"===o.trigger&&(o.trigger="click"),o.elem.attr("lay-key",r.index),o.eventElem.attr("lay-key",r.index),o.elem.attr(d,o.id),o.mark=lay.extend({},o.calendar&&"cn"===o.lang?{"0-1-1":"\u5143\u65e6","0-2-14":"\u60c5\u4eba","0-3-8":"\u5987\u5973","0-3-12":"\u690d\u6811","0-4-1":"\u611a\u4eba","0-5-1":"\u52b3\u52a8","0-5-4":"\u9752\u5e74","0-6-1":"\u513f\u7ae5","0-9-10":"\u6559\u5e08","0-10-1":"\u56fd\u5e86","0-12-25":"\u5723\u8bde"}:{},o.mark),lay.each(["min","max"],function(e,t){var a=[],n=[];if("number"==typeof o[t])var i=o[t],l=new Date,l=r.newDate({year:l.getFullYear(),month:l.getMonth(),date:l.getDate(),hours:e?23:0,minutes:e?59:0,seconds:e?59:0}).getTime(),e=new Date(i?i<864e5?l+864e5*i:i:l),a=[e.getFullYear(),e.getMonth()+1,e.getDate()],n=[e.getHours(),e.getMinutes(),e.getSeconds()];else if("string"==typeof o[t])a=(o[t].match(/\d+-\d+-\d+/)||[""])[0].split("-"),n=(o[t].match(/\d+:\d+:\d+/)||[""])[0].split(":");else if("object"==typeof o[t])return o[t];o[t]={year:0|a[0]||(new Date).getFullYear(),month:a[1]?(0|a[1])-1:(new Date).getMonth(),date:0|a[2]||(new Date).getDate(),hours:0|n[0],minutes:0|n[1],seconds:0|n[2]}}),r.elemID="layui-laydate"+o.elem.attr("lay-key"),(o.show||e)&&r.render(),e||r.events(),o.value&&o.isInitValue&&("date"===layui.type(o.value)?r.setValue(r.parse(0,r.systemDate(o.value))):r.setValue(o.value)))},I.prototype.render=function(){var a,n,i,l,r=this,o=r.config,d=r.lang(),s="static"===o.position,y=r.elem=lay.elem("div",{id:r.elemID,"class":["layui-laydate",o.range?" layui-laydate-range":"",r.rangeLinked?" layui-laydate-linkage":"",s?" "+T:"",o.fullPanel?" laydate-theme-fullpanel":"",(a="",lay.each(o.theme,function(e,t){"default"===t||/^#/.test(t)||(a+=" laydate-theme-"+t)}),a)].join("")}),m=r.elemMain=[],c=r.elemHeader=[],u=r.elemCont=[],h=r.table=[],e=r.footer=lay.elem("div",{"class":"layui-laydate-footer"}),t=r.shortcut=lay.elem("ul",{"class":"layui-laydate-shortcut"}),f=(o.zIndex&&(y.style.zIndex=o.zIndex),lay.each(new Array(2),function(e){if(!o.range&&0'+d.timeTips+""),(o.range||"datetime"!==o.type||o.fullPanel)&&f.push(''),lay.each(o.btns,function(e,t){var a=d.tools[t]||"btn";o.range&&"now"===t||(s&&"clear"===t&&(a="cn"===o.lang?"\u91cd\u7f6e":"Reset"),n.push(''+a+""))}),f.push('"),f.join(""))),o.shortcuts&&(y.appendChild(t),lay(t).html((i=[],lay.each(o.shortcuts,function(e,t){i.push('
  • '+t.text+"
  • ")}),i.join(""))).find("li").on("click",function(e){var t=(o.shortcuts[this.dataset.index]||{}).value||[],n=(layui.isArray(t)||(t=[t]),o.type),t=(lay.each(t,function(e,t){var a=[o.dateTime,r.endDate][e];"time"===n&&"date"!==layui.type(t)?r.EXP_IF.test(t)&&(t=(t.match(r.EXP_SPLIT)||[]).slice(1),lay.extend(a,{hours:0|t[0],minutes:0|t[2],seconds:0|t[4]})):lay.extend(a,r.systemDate("date"===layui.type(t)?t:new Date(t))),"time"!==n&&"datetime"!==n||(r[["startTime","endTime"][e]]={hours:a.hours,minutes:a.minutes,seconds:a.seconds}),0===e?r.startDate=lay.extend({},a):r.endState=!0,"year"===n||"month"===n||"time"===n?r.listYM[e]=[a.year,a.month+1]:e&&r.autoCalendarModel.auto&&r.autoCalendarModel()}),r.checkDate("limit").calendar(null,null,"init"),lay(r.footer).find("."+L).removeClass(k));t&&"date"===t.attr("lay-type")&&t[0].click(),r.done(null,"change"),lay(this).addClass(x),"static"!==o.position&&r.setValue(r.parse()).done().remove()})),lay.each(m,function(e,t){y.appendChild(t)}),o.showBottom&&y.appendChild(e),lay.elem("style")),p=[],g=!0,t=(lay.each(o.theme,function(e,t){if(g&&/^#/.test(t))return g=!(l=!0),void p.push(["#{{id}} .layui-laydate-header{background-color:{{theme}};}","#{{id}} li.layui-this,#{{id}} td.layui-this>div{background-color:{{theme}} !important;}",-1!==o.theme.indexOf("circle")?"":"#{{id}} .layui-this{background-color:{{theme}} !important;}","#{{id}} .laydate-day-now{color:{{theme}} !important;}","#{{id}} .laydate-day-now:after{border-color:{{theme}} !important;}"].join("").replace(/{{id}}/g,r.elemID).replace(/{{theme}}/g,t));!g&&/^#/.test(t)&&p.push(["#{{id}} .laydate-selected>div{background-color:{{theme}} !important;}","#{{id}} .laydate-selected:hover>div{background-color:{{theme}} !important;}"].join("").replace(/{{id}}/g,r.elemID).replace(/{{theme}}/g,t))}),o.shortcuts&&o.range&&p.push("#{{id}}.layui-laydate-range{width: 628px;}".replace(/{{id}}/g,r.elemID)),p.length&&(p=p.join(""),"styleSheet"in f?(f.setAttribute("type","text/css"),f.styleSheet.cssText=p):f.innerHTML=p,l&&lay(y).addClass("laydate-theme-molv"),y.appendChild(f)),r.remove(I.thisElemDate),D.thisId=o.id,s?o.elem.append(y):(v.body.appendChild(y),r.position()),o.shade?'
    ':"");y.insertAdjacentHTML("beforebegin",t),r.checkDate().calendar(null,0,"init"),r.changeEvent(),I.thisElemDate=r.elemID,r.renderAdditional(),"function"==typeof o.ready&&o.ready(lay.extend({},o.dateTime,{month:o.dateTime.month+1})),r.preview()},I.prototype.remove=function(e){var t=this,a=t.config,n=lay("#"+(e||t.elemID));return n[0]&&(n.hasClass(T)||t.checkDate(function(){n.remove(),delete t.startDate,delete t.endDate,delete t.endState,delete t.startTime,delete t.endTime,delete D.thisId,"function"==typeof a.close&&a.close(t)}),lay("."+S).remove()),t},I.prototype.position=function(){var e=this.config;return lay.position(e.elem[0],this.elem,{position:e.position}),this},I.prototype.hint=function(e){var t=this,a=(t.config,lay.elem("div",{"class":r}));t.elem&&(a.innerHTML=(e="object"==typeof e?e||{}:{content:e}).content||"",lay(t.elem).find("."+r).remove(),t.elem.appendChild(a),clearTimeout(t.hinTimer),t.hinTimer=setTimeout(function(){lay(t.elem).find("."+r).remove()},"ms"in e?e.ms:3e3))},I.prototype.getAsYM=function(e,t,a){return a?t--:t++,t<0&&(t=11,e--),11h[1]&&(e.year=h[1],o=!0),11t&&(e.date=t,o=!0))},r=function(n,i,l){var r=["startTime","endTime"];i=(i.match(d.EXP_SPLIT)||[]).slice(1),l=l||0,s.range&&(d[r[l]]=d[r[l]]||{}),lay.each(d.format,function(e,t){var a=parseFloat(i[e]);i[e].lengthd.getDateTime(s.max)?(n=s.dateTime=lay.extend({},s.max),c=!0):d.getDateTime(n)d.getDateTime(s.max))&&(d.endDate=lay.extend({},s.max),c=!0),d.startTime={hours:s.dateTime.hours,minutes:s.dateTime.minutes,seconds:s.dateTime.seconds},d.endTime={hours:d.endDate.hours,minutes:d.endDate.minutes,seconds:d.endDate.seconds},"month"===s.type&&(s.dateTime.date=1,d.endDate.date=1)),c&&l&&(d.setValue(d.parse()),d.hint("value "+a.invalidDate+a.formatError[1])),d.startDate=d.startDate||l&&lay.extend({},s.dateTime),d.autoCalendarModel.auto&&d.autoCalendarModel(),d.endState=!s.range||!d.rangeLinked||!(!d.startDate||!d.endDate),e&&e(),d},I.prototype.mark=function(e,a){var n,t=this.config;return lay.each(t.mark,function(e,t){e=e.split("-");e[0]!=a[0]&&0!=e[0]||e[1]!=a[1]&&0!=e[1]||e[2]!=a[2]||(n=t||a[2])}),n&&e.find("div").html(''+n+""),this},I.prototype.holidays=function(n,i){var e=this.config,l=["","work"];return"array"!==layui.type(e.holidays)||lay.each(e.holidays,function(a,e){lay.each(e,function(e,t){t===n.attr("lay-ymd")&&n.find("div").html('"+i[2]+"")})}),this},I.prototype.limit=function(t){t=t||{};var i=this,e=i.config,l={},a=t.index>(t.time?0:41)?i.endDate:e.dateTime;return lay.each({now:lay.extend({},a,t.date||{}),min:e.min,max:e.max},function(e,a){var n;l[e]=i.newDate(lay.extend({year:a.year,month:"year"===t.type?0:a.month,date:"year"===t.type||"month"===t.type?1:a.date},(n={},lay.each(t.time,function(e,t){n[t]=a[t]}),n))).getTime()}),a=l.nowl.max,t.elem&&t.elem[a?"addClass":"removeClass"](k),a},I.prototype.thisDateTime=function(e){var t=this.config;return e?this.endDate:t.dateTime},I.prototype.calendar=function(e,t,a){var i,l,r,o=this,n=o.config,t=t?1:0,d=e||o.thisDateTime(t),s=new Date,y=o.lang(),m="date"!==n.type&&"datetime"!==n.type,c=lay(o.table[t]).find("td"),u=lay(o.elemHeader[t][2]).find("span");return d.yearh[1]&&(d.year=h[1],o.hint(y.invalidDate)),o.firstDate||(o.firstDate=lay.extend({},d)),s.setFullYear(d.year,d.month,1),i=(s.getDay()+(7-n.weekStart))%7,l=D.getEndDate(d.month||12,d.year),r=D.getEndDate(d.month+1,d.year),lay.each(c,function(e,t){var a=[d.year,d.month],n=0;(t=lay(t)).removeAttr("class"),e"+a[2]+""),o.mark(t,a).holidays(t,a).limit({elem:t,date:{year:a[0],month:a[1]-1,date:a[2]},index:e})}),lay(u[0]).attr("lay-ym",d.year+"-"+(d.month+1)),lay(u[1]).attr("lay-ym",d.year+"-"+(d.month+1)),"cn"===n.lang?(lay(u[0]).attr("lay-type","year").html(d.year+" \u5e74"),lay(u[1]).attr("lay-type","month").html(d.month+1+" \u6708")):(lay(u[0]).attr("lay-type","month").html(y.month[d.month]),lay(u[1]).attr("lay-type","year").html(d.year)),m&&(n.range?!e&&"init"===a||(o.listYM=[[(o.startDate||n.dateTime).year,(o.startDate||n.dateTime).month+1],[o.endDate.year,o.endDate.month+1]],o.list(n.type,0).list(n.type,1),"time"===n.type?o.setBtnStatus("\u65f6\u95f4",lay.extend({},o.systemDate(),o.startTime),lay.extend({},o.systemDate(),o.endTime)):o.setBtnStatus(!0)):(o.listYM=[[d.year,d.month+1]],o.list(n.type,0))),n.range&&"init"===a&&(o.rangeLinked?(s=o.getAsYM(d.year,d.month,t?"sub":null),o.calendar(lay.extend({},d,{year:s[0],month:s[1]}),1-t)):o.calendar(null,1-t)),n.range||(c=["hours","minutes","seconds"],o.limit({elem:lay(o.footer).find(".laydate-btns-now"),date:o.systemDate(),index:0,time:c}),o.limit({elem:lay(o.footer).find(C),index:0,time:c})),o.setBtnStatus(),lay(o.shortcut).find("li."+x).removeClass(x),n.range&&!m&&"init"!==a&&o.stampRange(),o},I.prototype.list=function(n,i){var l,r,e,o,d=this,s=d.config,y=d.rangeLinked?s.dateTime:[s.dateTime,d.endDate][i],m=d.lang(),t=s.range&&"date"!==s.type&&"datetime"!==s.type,c=lay.elem("ul",{"class":w+" "+{year:"laydate-year-list",month:"laydate-month-list",time:"laydate-time-list"}[n]}),a=d.elemHeader[i],u=lay(a[2]).find("span"),h=d.elemCont[i||0],f=lay(h).find("."+w)[0],p="cn"===s.lang,g=p?"\u5e74":"",v=d.listYM[i]||{},D=["hours","minutes","seconds"],T=["startTime","endTime"][i];return v[0]<1&&(v[0]=1),"year"===n?(e=l=v[0]-7,l<1&&(e=l=1),lay.each(new Array(15),function(e){var t=lay.elem("li",{"lay-ym":l}),a={year:l,month:0,date:1};l==v[0]&&lay(t).addClass(x),t.innerHTML=l+g,c.appendChild(t),d.limit({elem:lay(t),date:a,index:i,type:n}),l++}),lay(u[p?0:1]).attr("lay-ym",l-8+"-"+v[1]).html(e+g+" - "+(l-1)+g)):"month"===n?(lay.each(new Array(12),function(e){var t=lay.elem("li",{"lay-ym":e}),a={year:v[0],month:e,date:1};e+1==v[1]&&lay(t).addClass(x),t.innerHTML=m.month[e]+(p?"\u6708":""),c.appendChild(t),d.limit({elem:lay(t),date:a,index:i,type:n})}),lay(u[p?0:1]).attr("lay-ym",v[0]+"-"+v[1]).html(v[0]+g)):"time"===n&&(r=function(){lay(c).find("ol").each(function(a,e){lay(e).find("li").each(function(e,t){d.limit({elem:lay(t),date:[{hours:e},{hours:d[T].hours,minutes:e},{hours:d[T].hours,minutes:d[T].minutes,seconds:e}][a],index:i,time:[["hours"],["hours","minutes"],["hours","minutes","seconds"]][a]})})}),s.range||d.limit({elem:lay(d.footer).find(C),date:d[T],inedx:0,time:["hours","minutes","seconds"]})},s.range?d[T]||(d[T]="startTime"===T?y:d.endDate):d[T]=y,lay.each([24,60,60],function(t,e){var a=lay.elem("li"),n=["

    "+m.time[t]+"

      "];lay.each(new Array(e),function(e){n.push(""+lay.digit(e,2)+"")}),a.innerHTML=n.join("")+"
    ",c.appendChild(a)}),r()),f&&h.removeChild(f),h.appendChild(c),"year"===n||"month"===n?(lay(d.elemMain[i]).addClass("laydate-ym-show"),lay(c).find("li").on("click",function(){var e=0|lay(this).attr("lay-ym");lay(this).hasClass(k)||(d.rangeLinked?lay.extend(y,{year:"year"===n?e:v[0],month:"year"===n?v[1]-1:e}):y[n]=e,"year"===s.type||"month"===s.type?(lay(c).find("."+x).removeClass(x),lay(this).addClass(x),"month"===s.type&&"year"===n&&(d.listYM[i][0]=e,t&&((i?d.endDate:y).year=e),d.list("month",i))):(d.checkDate("limit").calendar(y,i,"init"),d.closeList()),d.setBtnStatus(),!s.range&&s.autoConfirm&&("month"===s.type&&"month"===n||"year"===s.type&&"year"===n)&&d.setValue(d.parse()).done().remove(),d.autoCalendarModel.auto&&!d.rangeLinked?d.choose(lay(h).find("td.layui-this"),i):d.endState&&d.done(null,"change"),lay(d.footer).find("."+L).removeClass(k))})):(e=lay.elem("span",{"class":M}),o=function(){lay(c).find("ol").each(function(e){var a=this,t=lay(a).find("li");a.scrollTop=30*(d[T][D[e]]-2),a.scrollTop<=0&&t.each(function(e,t){if(!lay(this).hasClass(k))return a.scrollTop=30*(e-2),!0})})},u=lay(a[2]).find("."+M),o(),e.innerHTML=s.range?[m.startTime,m.endTime][i]:m.timeTips,lay(d.elemMain[i]).addClass("laydate-time-show"),u[0]&&u.remove(),a[2].appendChild(e),lay(c).find("ol").each(function(t){var a=this;lay(a).find("li").on("click",function(){var e=0|this.innerHTML;lay(this).hasClass(k)||(s.range?d[T][D[t]]=e:y[D[t]]=e,lay(a).find("."+x).removeClass(x),lay(this).addClass(x),r(),o(),(d.endDate||"time"===s.type||"datetime"===s.type&&s.fullPanel)&&d.done(null,"change"),d.setBtnStatus())})})),d},I.prototype.listYM=[],I.prototype.closeList=function(){var a=this;a.config;lay.each(a.elemCont,function(e,t){lay(this).find("."+w).remove(),lay(a.elemMain[e]).removeClass("laydate-ym-show laydate-time-show")}),lay(a.elem).find("."+M).remove()},I.prototype.setBtnStatus=function(e,t,a){var n=this,i=n.config,l=n.lang(),r=lay(n.footer).find(C);i.range&&"time"!==i.type&&(t=t||(n.rangeLinked?n.startDate:i.dateTime),a=a||n.endDate,i=!n.endState||n.newDate(t).getTime()>n.newDate(a).getTime(),n.limit({date:t})||n.limit({date:a})?r.addClass(k):r[i?"addClass":"removeClass"](k),e&&i&&n.hint("string"==typeof e?l.timeout.replace(/\u65e5\u671f/g,e):l.timeout))},I.prototype.parse=function(e,t){var a=this,n=a.config,t=t||("end"==e?lay.extend({},a.endDate,a.endTime):n.range?lay.extend({},a.rangeLinked?a.startDate:n.dateTime,a.startTime):n.dateTime),t=D.parse(t,a.format,1);return n.range&&e===undefined?t+" "+a.rangeStr+" "+a.parse("end"):t},I.prototype.newDate=function(e){return e=e||{},new Date(e.year||1,e.month||0,e.date||1,e.hours||0,e.minutes||0,e.seconds||0)},I.prototype.getDateTime=function(e){return this.newDate(e).getTime()},I.prototype.setValue=function(e){var t=this,a=t.config,n=a.elem[0];return"static"===a.position||(e=e||"",t.isInput(n)?lay(n).val(e):(a=t.rangeElem)?("array"!==layui.type(e)&&(e=e.split(" "+t.rangeStr+" ")),a[0].val(e[0]||""),a[1].val(e[1]||"")):(0===lay(n).find("*").length&&lay(n).html(e),lay(n).attr("lay-date",e))),t},I.prototype.preview=function(){var e,t=this,a=t.config;a.isPreview&&(e=lay(t.elem).find("."+E),a=!a.range||(t.rangeLinked?t.endState:t.endDate)?t.parse():"",e.html(a),e.html()&&(e.css({color:"#16b777"}),setTimeout(function(){e.css({color:"#777"})},300)))},I.prototype.renderAdditional=function(){this.config.fullPanel&&this.list("time",0)},I.prototype.stampRange=function(){var n,i=this,l=i.config,r=i.rangeLinked?i.startDate:l.dateTime,e=lay(i.elem).find("td");l.range&&!i.endState&&lay(i.footer).find(C).addClass(k),r=r&&i.newDate({year:r.year,month:r.month,date:r.date}).getTime(),n=i.endState&&i.endDate&&i.newDate({year:i.endDate.year,month:i.endDate.month,date:i.endDate.date}).getTime(),lay.each(e,function(e,t){var a=lay(t).attr("lay-ymd").split("-"),a=i.newDate({year:a[0],month:a[1]-1,date:a[2]}).getTime();l.rangeLinked&&!i.startDate&&a===i.newDate(i.systemDate()).getTime()&&lay(t).addClass(lay(t).hasClass(y)||lay(t).hasClass(m)?"":"laydate-day-now"),lay(t).removeClass(o+" "+x),a!==r&&a!==n||(i.rangeLinked||!i.rangeLinked&&(e<42?a===r:a===n))&&lay(t).addClass(lay(t).hasClass(y)||lay(t).hasClass(m)?o:x),rn.getDateTime(i.max)&&(n[t]={hours:i.max.hours,minutes:i.max.minutes,seconds:i.max.seconds},lay.extend(l,n[t])))}),a||(n.startDate=lay.extend({},l)),n.endState&&!n.limit({date:n.thisDateTime(1-a)})&&(((r=n.endState&&n.autoCalendarModel.auto?n.autoCalendarModel():r)||n.rangeLinked&&n.endState)&&n.newDate(n.startDate)>n.newDate(n.endDate)&&(e=n.startDate.year===n.endDate.year&&n.startDate.month===n.endDate.month&&n.startDate.date===n.endDate.date,o=n.startDate,n.startDate=lay.extend({},n.endDate,e?{}:n.startTime),i.dateTime=lay.extend({},n.startDate),n.endDate=lay.extend({},o,e?{}:n.endTime),e&&(o=n.startTime,n.startTime=n.endTime,n.endTime=o)),r&&(i.dateTime=lay.extend({},n.startDate))),n.rangeLinked?(e=lay.extend({},l),!t||a||r||(o=n.getAsYM(l.year,l.month,"sub"),lay.extend(i.dateTime,{year:o[0],month:o[1]})),n.calendar(e,t,r?"init":null)):n.calendar(null,a,r?"init":null),n.endState&&n.done(null,"change")):"static"===i.position?n.calendar().done().done(null,"change"):"date"===i.type?i.autoConfirm?n.setValue(n.parse()).done().remove():n.calendar().done(null,"change"):"datetime"===i.type&&n.calendar().done(null,"change"))},I.prototype.tool=function(t,e){var a=this,n=a.config,i=a.lang(),l=n.dateTime,r="static"===n.position,o={datetime:function(){lay(t).hasClass(k)||(a.list("time",0),n.range&&a.list("time",1),lay(t).attr("lay-type","date").html(a.lang().dateTips))},date:function(){a.closeList(),lay(t).attr("lay-type","datetime").html(a.lang().timeTips)},clear:function(){r&&(lay.extend(l,a.firstDate),a.calendar()),n.range&&(delete n.dateTime,delete a.endDate,delete a.startTime,delete a.endTime),a.setValue(""),a.done(null,"onClear").done(["",{},{}]).remove()},now:function(){var e=new Date;if(lay(t).hasClass(k))return a.hint(i.tools.now+", "+i.invalidDate);lay.extend(l,a.systemDate(),{hours:e.getHours(),minutes:e.getMinutes(),seconds:e.getSeconds()}),a.setValue(a.parse()),r&&a.calendar(),a.done(null,"onNow").done().remove()},confirm:function(){if(n.range){if(lay(t).hasClass(k))return a.hint("time"===n.type?i.timeout.replace(/\u65e5\u671f/g,"\u65f6\u95f4"):i.timeout)}else if(lay(t).hasClass(k))return a.hint(i.invalidDate);a.setValue(a.parse()),a.done(null,"onConfirm").done().remove()}};o[e]&&o[e]()},I.prototype.change=function(n){var i=this,l=i.config,r=i.thisDateTime(n),o=l.range&&("year"===l.type||"month"===l.type),d=i.elemCont[n||0],s=i.listYM[n],e=function(e){var t=lay(d).find(".laydate-year-list")[0],a=lay(d).find(".laydate-month-list")[0];return t&&(s[0]=e?s[0]-15:s[0]+15,i.list("year",n)),a&&(e?s[0]--:s[0]++,i.list("month",n)),(t||a)&&(lay.extend(r,{year:s[0]}),o&&(r.year=s[0]),l.range||i.done(null,"change"),l.range||i.limit({elem:lay(i.footer).find(C),date:{year:s[0]}})),i.setBtnStatus(),t||a};return{prevYear:function(){e("sub")||(i.rangeLinked?(l.dateTime.year--,i.checkDate("limit").calendar(null,null,"init")):(r.year--,i.checkDate("limit").calendar(null,n),i.autoCalendarModel.auto?i.choose(lay(d).find("td.layui-this"),n):i.done(null,"change")))},prevMonth:function(){i.rangeLinked&&(r=l.dateTime);var e=i.getAsYM(r.year,r.month,"sub");lay.extend(r,{year:e[0],month:e[1]}),i.checkDate("limit").calendar(null,null,"init"),i.rangeLinked||(i.autoCalendarModel.auto?i.choose(lay(d).find("td.layui-this"),n):i.done(null,"change"))},nextMonth:function(){i.rangeLinked&&(r=l.dateTime);var e=i.getAsYM(r.year,r.month);lay.extend(r,{year:e[0],month:e[1]}),i.checkDate("limit").calendar(null,null,"init"),i.rangeLinked||(i.autoCalendarModel.auto?i.choose(lay(d).find("td.layui-this"),n):i.done(null,"change"))},nextYear:function(){e()||(i.rangeLinked?(l.dateTime.year++,i.checkDate("limit").calendar(null,0,"init")):(r.year++,i.checkDate("limit").calendar(null,n),i.autoCalendarModel.auto?i.choose(lay(d).find("td.layui-this"),n):i.done(null,"change")))}}},I.prototype.changeEvent=function(){var i=this;i.config;lay(i.elem).on("click",function(e){lay.stope(e)}).on("mousedown",function(e){lay.stope(e)}),lay.each(i.elemHeader,function(n,e){lay(e[0]).on("click",function(e){i.change(n).prevYear()}),lay(e[1]).on("click",function(e){i.change(n).prevMonth()}),lay(e[2]).find("span").on("click",function(e){var t=lay(this),a=t.attr("lay-ym"),t=t.attr("lay-type");a&&(a=a.split("-"),i.listYM[n]=[0|a[0],0|a[1]],i.list(t,n),lay(i.footer).find("."+L).addClass(k))}),lay(e[3]).on("click",function(e){i.change(n).nextMonth()}),lay(e[4]).on("click",function(e){i.change(n).nextYear()})}),lay.each(i.table,function(e,t){lay(t).find("td").on("click",function(){i.choose(lay(this),e)})}),lay(i.footer).find("span").on("click",function(){var e=lay(this).attr("lay-type");i.tool(this,e)})},I.prototype.isInput=function(e){return/input|textarea/.test(e.tagName.toLocaleLowerCase())||/INPUT|TEXTAREA/.test(e.tagName)},I.prototype.events=function(){var e,t=this,a=t.config;a.elem[0]&&!a.elem[0].eventHandler&&(a.elem.on(a.trigger,e=function(){D.thisId!==a.id&&t.render()}),a.elem[0].eventHandler=!0,a.eventElem.on(a.trigger,e),t.unbind=function(){t.remove(),a.elem.off(a.trigger,e),a.elem.removeAttr("lay-key"),a.elem.removeAttr(d),a.elem[0].eventHandler=!1,a.eventElem.off(a.trigger,e),a.eventElem.removeAttr("lay-key"),delete s.that[a.id]})},s.that={},s.getThis=function(e){var t=s.that[e];return!t&&n&&layui.hint().error(e?a+" instance with ID '"+e+"' not found":"ID argument required"),t},l.run=function(n){n(v).on("mousedown",function(e){var t,a;!D.thisId||(t=s.getThis(D.thisId))&&(a=t.config,e.target!==a.elem[0]&&e.target!==a.eventElem[0]&&e.target!==n(a.closeStop)[0]&&t.remove())}).on("keydown",function(e){var t;!D.thisId||(t=s.getThis(D.thisId))&&"static"!==t.config.position&&13===e.keyCode&&n("#"+t.elemID)[0]&&t.elemID===I.thisElemDate&&(e.preventDefault(),n(t.footer).find(C)[0].click())}),n(i).on("resize",function(){if(D.thisId){var e=s.getThis(D.thisId);if(e)return!(!e.elem||!n(".layui-laydate")[0])&&void e.position()}})},D.render=function(e){e=new I(e);return s.call(e)},D.reload=function(e,t){e=s.getThis(e);if(e)return e.reload(t)},D.getInst=function(e){e=s.getThis(e);if(e)return e.inst},D.hint=function(e,t){e=s.getThis(e);if(e)return e.hint(t)},D.unbind=function(e){e=s.getThis(e);if(e)return e.unbind()},D.close=function(e){e=s.getThis(e||D.thisId);if(e)return e.remove()},D.parse=function(a,n,i){return a=a||{},n=((n="string"==typeof n?s.formatArr(n):n)||[]).concat(),lay.each(n,function(e,t){/yyyy|y/.test(t)?n[e]=lay.digit(a.year,t.length):/MM|M/.test(t)?n[e]=lay.digit(a.month+(i||0),t.length):/dd|d/.test(t)?n[e]=lay.digit(a.date,t.length):/HH|H/.test(t)?n[e]=lay.digit(a.hours,t.length):/mm|m/.test(t)?n[e]=lay.digit(a.minutes,t.length):/ss|s/.test(t)&&(n[e]=lay.digit(a.seconds,t.length))}),n.join("")},D.getEndDate=function(e,t){var a=new Date;return a.setFullYear(t||a.getFullYear(),e||a.getMonth()+1,1),new Date(a.getTime()-864e5).getDate()},n?(D.ready(),layui.define("lay",function(e){D.path=layui.cache.dir,l.run(lay),e(a,D)})):"function"==typeof define&&define.amd?define(function(){return l.run(lay),D}):(D.ready(),l.run(i.lay),i.laydate=D)}(window,window.document);!function(e,t){"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e):function(e){if(e.document)return t(e);throw new Error("jQuery requires a window with a document")}:t(e)}("undefined"!=typeof window?window:this,function(T,M){var f=[],g=T.document,c=f.slice,O=f.concat,R=f.push,P=f.indexOf,B={},W=B.toString,m=B.hasOwnProperty,y={},e="1.12.4",C=function(e,t){return new C.fn.init(e,t)},I=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,$=/^-ms-/,z=/-([\da-z])/gi,X=function(e,t){return t.toUpperCase()};function U(e){var t=!!e&&"length"in e&&e.length,n=C.type(e);return"function"!==n&&!C.isWindow(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+a+")"+a+"*"),ee=new RegExp("="+a+"*([^\\]'\"]*?)"+a+"*\\]","g"),te=new RegExp(G),ne=new RegExp("^"+s+"$"),f={ID:new RegExp("^#("+s+")"),CLASS:new RegExp("^\\.("+s+")"),TAG:new RegExp("^("+s+"|[*])"),ATTR:new RegExp("^"+J),PSEUDO:new RegExp("^"+G),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+a+"*(even|odd|(([+-]|)(\\d*)n|)"+a+"*(?:([+-]|)"+a+"*(\\d+)|))"+a+"*\\)|)","i"),bool:new RegExp("^(?:"+Y+")$","i"),needsContext:new RegExp("^"+a+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+a+"*((?:-\\d)?\\d*)"+a+"*\\)|)(?=[^-]|$)","i")},re=/^(?:input|select|textarea|button)$/i,ie=/^h\d$/i,c=/^[^{]+\{\s*\[native \w/,oe=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ae=/[+~]/,se=/'|\\/g,d=new RegExp("\\\\([\\da-f]{1,6}"+a+"?|("+a+")|.)","ig"),p=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(65536+r):String.fromCharCode(r>>10|55296,1023&r|56320)},ue=function(){C()};try{D.apply(n=V.call(v.childNodes),v.childNodes),n[v.childNodes.length].nodeType}catch(F){D={apply:n.length?function(e,t){U.apply(e,V.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function H(e,t,n,r){var i,o,a,s,u,l,c,f,d=t&&t.ownerDocument,p=t?t.nodeType:9;if(n=n||[],"string"!=typeof e||!e||1!==p&&9!==p&&11!==p)return n;if(!r&&((t?t.ownerDocument||t:v)!==E&&C(t),t=t||E,N)){if(11!==p&&(l=oe.exec(e)))if(i=l[1]){if(9===p){if(!(a=t.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(d&&(a=d.getElementById(i))&&y(t,a)&&a.id===i)return n.push(a),n}else{if(l[2])return D.apply(n,t.getElementsByTagName(e)),n;if((i=l[3])&&g.getElementsByClassName&&t.getElementsByClassName)return D.apply(n,t.getElementsByClassName(i)),n}if(g.qsa&&!A[e+" "]&&(!m||!m.test(e))){if(1!==p)d=t,f=e;else if("object"!==t.nodeName.toLowerCase()){for((s=t.getAttribute("id"))?s=s.replace(se,"\\$&"):t.setAttribute("id",s=k),o=(c=w(e)).length,u=ne.test(s)?"#"+s:"[id='"+s+"']";o--;)c[o]=u+" "+_(c[o]);f=c.join(","),d=ae.test(e)&&de(t.parentNode)||t}if(f)try{return D.apply(n,d.querySelectorAll(f)),n}catch(h){}finally{s===k&&t.removeAttribute("id")}}}return P(e.replace(L,"$1"),t,n,r)}function le(){var n=[];function r(e,t){return n.push(e+" ")>b.cacheLength&&delete r[n.shift()],r[e+" "]=t}return r}function q(e){return e[k]=!0,e}function h(e){var t=E.createElement("div");try{return!!e(t)}catch(F){return!1}finally{t.parentNode&&t.parentNode.removeChild(t)}}function ce(e,t){for(var n=e.split("|"),r=n.length;r--;)b.attrHandle[n[r]]=t}function fe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||1<<31)-(~e.sourceIndex||1<<31);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function x(a){return q(function(o){return o=+o,q(function(e,t){for(var n,r=a([],e.length,o),i=r.length;i--;)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function de(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in g=H.support={},O=H.isXML=function(e){e=e&&(e.ownerDocument||e).documentElement;return!!e&&"HTML"!==e.nodeName},C=H.setDocument=function(e){var e=e?e.ownerDocument||e:v;return e!==E&&9===e.nodeType&&e.documentElement&&(t=(E=e).documentElement,N=!O(E),(e=E.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",ue,!1):e.attachEvent&&e.attachEvent("onunload",ue)),g.attributes=h(function(e){return e.className="i",!e.getAttribute("className")}),g.getElementsByTagName=h(function(e){return e.appendChild(E.createComment("")),!e.getElementsByTagName("*").length}),g.getElementsByClassName=c.test(E.getElementsByClassName),g.getById=h(function(e){return t.appendChild(e).id=k,!E.getElementsByName||!E.getElementsByName(k).length}),g.getById?(b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&N)return(e=t.getElementById(e))?[e]:[]},b.filter.ID=function(e){var t=e.replace(d,p);return function(e){return e.getAttribute("id")===t}}):(delete b.find.ID,b.filter.ID=function(e){var t=e.replace(d,p);return function(e){e="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return e&&e.value===t}}),b.find.TAG=g.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):g.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"!==e)return o;for(;n=o[i++];)1===n.nodeType&&r.push(n);return r},b.find.CLASS=g.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&N)return t.getElementsByClassName(e)},r=[],m=[],(g.qsa=c.test(E.querySelectorAll))&&(h(function(e){t.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&m.push("[*^$]="+a+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||m.push("\\["+a+"*(?:value|"+Y+")"),e.querySelectorAll("[id~="+k+"-]").length||m.push("~="),e.querySelectorAll(":checked").length||m.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||m.push(".#.+[+~]")}),h(function(e){var t=E.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&m.push("name"+a+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||m.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),m.push(",.*:")})),(g.matchesSelector=c.test(i=t.matches||t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.msMatchesSelector))&&h(function(e){g.disconnectedMatch=i.call(e,"div"),i.call(e,"[s!='']:x"),r.push("!=",G)}),m=m.length&&new RegExp(m.join("|")),r=r.length&&new RegExp(r.join("|")),e=c.test(t.compareDocumentPosition),y=e||c.test(t.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,t=t&&t.parentNode;return e===t||!(!t||1!==t.nodeType||!(n.contains?n.contains(t):e.compareDocumentPosition&&16&e.compareDocumentPosition(t)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},$=e?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!g.sortDetached&&t.compareDocumentPosition(e)===n?e===E||e.ownerDocument===v&&y(v,e)?-1:t===E||t.ownerDocument===v&&y(v,t)?1:u?j(u,e)-j(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===E?-1:t===E?1:i?-1:o?1:u?j(u,e)-j(u,t):0;if(i===o)return fe(e,t);for(n=e;n=n.parentNode;)a.unshift(n);for(n=t;n=n.parentNode;)s.unshift(n);for(;a[r]===s[r];)r++;return r?fe(a[r],s[r]):a[r]===v?-1:s[r]===v?1:0}),E},H.matches=function(e,t){return H(e,null,null,t)},H.matchesSelector=function(e,t){if((e.ownerDocument||e)!==E&&C(e),t=t.replace(ee,"='$1']"),g.matchesSelector&&N&&!A[t+" "]&&(!r||!r.test(t))&&(!m||!m.test(t)))try{var n=i.call(e,t);if(n||g.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(F){}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(d,p),e[3]=(e[3]||e[4]||e[5]||"").replace(d,p),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||H.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&H.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return f.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&te.test(n)&&(t=w(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(d,p).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=W[e+" "];return t||(t=new RegExp("(^|"+a+")"+e+"("+a+"|$)"))&&W(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(t,n,r){return function(e){e=H.attr(e,t);return null==e?"!="===n:!n||(e+="","="===n?e===r:"!="===n?e!==r:"^="===n?r&&0===e.indexOf(r):"*="===n?r&&-1(?:<\/\1>|)$/,G=/^.[^:#\[\.,]*$/;function K(e,n,r){if(C.isFunction(n))return C.grep(e,function(e,t){return!!n.call(e,t,e)!==r});if(n.nodeType)return C.grep(e,function(e){return e===n!==r});if("string"==typeof n){if(G.test(n))return C.filter(n,e,r);n=C.filter(n,e)}return C.grep(e,function(e){return-1)[^>]*|#([\w-]*))$/,ee=((C.fn.init=function(e,t,n){if(!e)return this;if(n=n||Q,"string"!=typeof e)return e.nodeType?(this.context=this[0]=e,this.length=1,this):C.isFunction(e)?"undefined"!=typeof n.ready?n.ready(e):e(C):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),C.makeArray(e,this));if(!(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&3<=e.length?[null,e,null]:Z.exec(e))||!r[1]&&t)return(!t||t.jquery?t||n:this.constructor(t)).find(e);if(r[1]){if(t=t instanceof C?t[0]:t,C.merge(this,C.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:g,!0)),J.test(r[1])&&C.isPlainObject(t))for(var r in t)C.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}if((n=g.getElementById(r[2]))&&n.parentNode){if(n.id!==r[2])return Q.find(e);this.length=1,this[0]=n}return this.context=g,this.selector=e,this}).prototype=C.fn,Q=C(g),/^(?:parents|prev(?:Until|All))/),te={children:!0,contents:!0,next:!0,prev:!0};function ne(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}C.fn.extend({has:function(e){var t,n=C(e,this),r=n.length;return this.filter(function(){for(t=0;t
    a",y.leadingWhitespace=3===S.firstChild.nodeType,y.tbody=!S.getElementsByTagName("tbody").length,y.htmlSerialize=!!S.getElementsByTagName("link").length,y.html5Clone="<:nav>"!==g.createElement("nav").cloneNode(!0).outerHTML,q.type="checkbox",q.checked=!0,k.appendChild(q),y.appendChecked=q.checked,S.innerHTML="",y.noCloneChecked=!!S.cloneNode(!0).lastChild.defaultValue,k.appendChild(S),(q=g.createElement("input")).setAttribute("type","radio"),q.setAttribute("checked","checked"),q.setAttribute("name","t"),S.appendChild(q),y.checkClone=S.cloneNode(!0).cloneNode(!0).lastChild.checked,y.noCloneEvent=!!S.addEventListener,S[C.expando]=1,y.attributes=!S.getAttribute(C.expando);var x={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:y.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]};function b(e,t){var n,r,i=0,o="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):undefined;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||C.nodeName(r,t)?o.push(r):C.merge(o,b(r,t));return t===undefined||t&&C.nodeName(e,t)?C.merge([e],o):o}function we(e,t){for(var n,r=0;null!=(n=e[r]);r++)C._data(n,"globalEval",!t||C._data(t[r],"globalEval"))}x.optgroup=x.option,x.tbody=x.tfoot=x.colgroup=x.caption=x.thead,x.th=x.td;var Te=/<|&#?\w+;/,Ce=/"!==f[1]||Ce.test(a)?0:u:u.firstChild)&&a.childNodes.length;o--;)C.nodeName(c=a.childNodes[o],"tbody")&&!c.childNodes.length&&a.removeChild(c);for(C.merge(h,u.childNodes),u.textContent="";u.firstChild;)u.removeChild(u.firstChild);u=p.lastChild}else h.push(t.createTextNode(a));for(u&&p.removeChild(u),y.appendChecked||C.grep(b(h,"input"),Ee),g=0;a=h[g++];)if(r&&-1]","i"),Pe=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,Be=/\s*$/g,ze=be(g).appendChild(g.createElement("div"));function Xe(e,t){return C.nodeName(e,"table")&&C.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ue(e){return e.type=(null!==C.find.attr(e,"type"))+"/"+e.type,e}function Ve(e){var t=Ie.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Ye(e,t){if(1===t.nodeType&&C.hasData(e)){var n,r,i,e=C._data(e),o=C._data(t,e),a=e.events;if(a)for(n in delete o.handle,o.events={},a)for(r=0,i=a[n].length;r")},clone:function(e,t,n){var r,i,o,a,s,u=C.contains(e.ownerDocument,e);if(y.html5Clone||C.isXMLDoc(e)||!Re.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(ze.innerHTML=e.outerHTML,ze.removeChild(o=ze.firstChild)),!(y.noCloneEvent&&y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||C.isXMLDoc(e)))for(r=b(o),s=b(e),a=0;null!=(i=s[a]);++a)if(r[a]){f=c=l=p=d=void 0;var l,c,f,d=i,p=r[a];if(1===p.nodeType){if(l=p.nodeName.toLowerCase(),!y.noCloneEvent&&p[C.expando]){for(c in(f=C._data(p)).events)C.removeEvent(p,c,f.handle);p.removeAttribute(C.expando)}"script"===l&&p.text!==d.text?(Ue(p).text=d.text,Ve(p)):"object"===l?(p.parentNode&&(p.outerHTML=d.outerHTML),y.html5Clone&&d.innerHTML&&!C.trim(p.innerHTML)&&(p.innerHTML=d.innerHTML)):"input"===l&&ge.test(d.type)?(p.defaultChecked=p.checked=d.checked,p.value!==d.value&&(p.value=d.value)):"option"===l?p.defaultSelected=p.selected=d.defaultSelected:"input"!==l&&"textarea"!==l||(p.defaultValue=d.defaultValue)}}if(t)if(n)for(s=s||b(e),r=r||b(o),a=0;null!=(i=s[a]);a++)Ye(i,r[a]);else Ye(e,o);return 0<(r=b(o,"script")).length&&we(r,!u&&b(e,"script")),r=s=i=null,o},cleanData:function(e,t){for(var n,r,i,o,a=0,s=C.expando,u=C.cache,l=y.attributes,c=C.event.special;null!=(n=e[a]);a++)if((t||v(n))&&(o=(i=n[s])&&u[i])){if(o.events)for(r in o.events)c[r]?C.event.remove(n,r):C.removeEvent(n,r,o.handle);u[i]&&(delete u[i],l||"undefined"==typeof n.removeAttribute?n[s]=undefined:n.removeAttribute(s),f.push(i))}}}),C.fn.extend({domManip:w,detach:function(e){return Je(this,e,!0)},remove:function(e){return Je(this,e)},text:function(e){return d(this,function(e){return e===undefined?C.text(this):this.empty().append((this[0]&&this[0].ownerDocument||g).createTextNode(e))},null,e,arguments.length)},append:function(){return w(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Xe(this,e).appendChild(e)})},prepend:function(){return w(this,arguments,function(e){var t;1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(t=Xe(this,e)).insertBefore(e,t.firstChild)})},before:function(){return w(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return w(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++){for(1===e.nodeType&&C.cleanData(b(e,!1));e.firstChild;)e.removeChild(e.firstChild);e.options&&C.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return C.clone(this,e,t)})},html:function(e){return d(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined)return 1===t.nodeType?t.innerHTML.replace(Oe,""):undefined;if("string"==typeof e&&!Be.test(e)&&(y.htmlSerialize||!Re.test(e))&&(y.leadingWhitespace||!ve.test(e))&&!x[(me.exec(e)||["",""])[1].toLowerCase()]){e=C.htmlPrefilter(e);try{for(;n")).appendTo(t.documentElement))[0].contentWindow||Ge[0].contentDocument).document).write(),t.close(),n=Qe(e,t),Ge.detach()),Ke[e]=n),n}var n,et,tt,nt,rt,it,ot,a,at=/^margin/,st=new RegExp("^("+e+")(?!px)[a-z%]+$","i"),ut=function(e,t,n,r){var i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.apply(e,r||[]),t)e.style[i]=o[i];return r},lt=g.documentElement;function t(){var e,t=g.documentElement;t.appendChild(ot),a.style.cssText="-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",n=tt=it=!1,et=rt=!0,T.getComputedStyle&&(e=T.getComputedStyle(a),n="1%"!==(e||{}).top,it="2px"===(e||{}).marginLeft,tt="4px"===(e||{width:"4px"}).width,a.style.marginRight="50%",et="4px"===(e||{marginRight:"4px"}).marginRight,(e=a.appendChild(g.createElement("div"))).style.cssText=a.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",e.style.marginRight=e.style.width="0",a.style.width="1px",rt=!parseFloat((T.getComputedStyle(e)||{}).marginRight),a.removeChild(e)),a.style.display="none",(nt=0===a.getClientRects().length)&&(a.style.display="",a.innerHTML="
    t
    ",a.childNodes[0].style.borderCollapse="separate",(e=a.getElementsByTagName("td"))[0].style.cssText="margin:0;border:0;padding:0;display:none",(nt=0===e[0].offsetHeight)&&(e[0].style.display="",e[1].style.display="none",nt=0===e[0].offsetHeight)),t.removeChild(ot)}ot=g.createElement("div"),(a=g.createElement("div")).style&&(a.style.cssText="float:left;opacity:.5",y.opacity="0.5"===a.style.opacity,y.cssFloat=!!a.style.cssFloat,a.style.backgroundClip="content-box",a.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===a.style.backgroundClip,(ot=g.createElement("div")).style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",a.innerHTML="",ot.appendChild(a),y.boxSizing=""===a.style.boxSizing||""===a.style.MozBoxSizing||""===a.style.WebkitBoxSizing,C.extend(y,{reliableHiddenOffsets:function(){return null==n&&t(),nt},boxSizingReliable:function(){return null==n&&t(),tt},pixelMarginRight:function(){return null==n&&t(),et},pixelPosition:function(){return null==n&&t(),n},reliableMarginRight:function(){return null==n&&t(),rt},reliableMarginLeft:function(){return null==n&&t(),it}}));var l,p,ct=/^(top|right|bottom|left)$/;function ft(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}T.getComputedStyle?(l=function(e){var t=e.ownerDocument.defaultView;return(t=t&&t.opener?t:T).getComputedStyle(e)},p=function(e,t,n){var r,i,o=e.style;return""!==(i=(n=n||l(e))?n.getPropertyValue(t)||n[t]:undefined)&&i!==undefined||C.contains(e.ownerDocument,e)||(i=C.style(e,t)),n&&!y.pixelMarginRight()&&st.test(i)&&at.test(t)&&(e=o.width,t=o.minWidth,r=o.maxWidth,o.minWidth=o.maxWidth=o.width=i,i=n.width,o.width=e,o.minWidth=t,o.maxWidth=r),i===undefined?i:i+""}):lt.currentStyle&&(l=function(e){return e.currentStyle},p=function(e,t,n){var r,i,o,a=e.style;return null==(n=(n=n||l(e))?n[t]:undefined)&&a&&a[t]&&(n=a[t]),st.test(n)&&!ct.test(t)&&(r=a.left,(o=(i=e.runtimeStyle)&&i.left)&&(i.left=e.currentStyle.left),a.left="fontSize"===t?"1em":n,n=a.pixelLeft+"px",a.left=r,o&&(i.left=o)),n===undefined?n:n+""||"auto"});var dt=/alpha\([^)]*\)/i,pt=/opacity\s*=\s*([^)]*)/i,ht=/^(none|table(?!-c[ea]).+)/,gt=new RegExp("^("+e+")(.*)$","i"),mt={position:"absolute",visibility:"hidden",display:"block"},yt={letterSpacing:"0",fontWeight:"400"},vt=["Webkit","O","Moz","ms"],xt=g.createElement("div").style;function bt(e){if(e in xt)return e;for(var t=e.charAt(0).toUpperCase()+e.slice(1),n=vt.length;n--;)if((e=vt[n]+t)in xt)return e}function wt(e,t){for(var n,r,i,o=[],a=0,s=e.length;a
    a",F=q.getElementsByTagName("a")[0],k.setAttribute("type","checkbox"),q.appendChild(k),(F=q.getElementsByTagName("a")[0]).style.cssText="top:1px",y.getSetAttribute="t"!==q.className,y.style=/top/.test(F.getAttribute("style")),y.hrefNormalized="/a"===F.getAttribute("href"),y.checkOn=!!k.value,y.optSelected=e.selected,y.enctype=!!g.createElement("form").enctype,S.disabled=!0,y.optDisabled=!e.disabled,(k=g.createElement("input")).setAttribute("value",""),y.input=""===k.getAttribute("value"),k.value="t",k.setAttribute("type","radio"),y.radioValue="t"===k.value;var Lt=/\r/g,Ht=/[\x20\t\r\n\f]+/g;C.fn.extend({val:function(t){var n,e,r,i=this[0];return arguments.length?(r=C.isFunction(t),this.each(function(e){1===this.nodeType&&(null==(e=r?t.call(this,e,C(this).val()):t)?e="":"number"==typeof e?e+="":C.isArray(e)&&(e=C.map(e,function(e){return null==e?"":e+""})),(n=C.valHooks[this.type]||C.valHooks[this.nodeName.toLowerCase()])&&"set"in n&&n.set(this,e,"value")!==undefined||(this.value=e))})):i?(n=C.valHooks[i.type]||C.valHooks[i.nodeName.toLowerCase()])&&"get"in n&&(e=n.get(i,"value"))!==undefined?e:"string"==typeof(e=i.value)?e.replace(Lt,""):null==e?"":e:void 0}}),C.extend({valHooks:{option:{get:function(e){var t=C.find.attr(e,"value");return null!=t?t:C.trim(C.text(e)).replace(Ht," ")}},select:{get:function(e){for(var t,n=e.options,r=e.selectedIndex,i="select-one"===e.type||r<0,o=i?null:[],a=i?r+1:n.length,s=r<0?a:i?r:0;s").append(C.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},C.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){C.fn[t]=function(e){return this.on(t,e)}}),C.expr.filters.animated=function(t){return C.grep(C.timers,function(e){return t===e.elem}).length},C.offset={setOffset:function(e,t,n){var r,i,o,a,s=C.css(e,"position"),u=C(e),l={};"static"===s&&(e.style.position="relative"),o=u.offset(),r=C.css(e,"top"),a=C.css(e,"left"),s=("absolute"===s||"fixed"===s)&&-1'+(s?a.title[0]:a.title)+"":"";return a.zIndex=o,t([a.shade?'
    ':"",'
    '+(e&&2!=a.type?"":s)+"'+(n=["layui-icon-tips","layui-icon-success","layui-icon-error","layui-icon-question","layui-icon-lock","layui-icon-face-cry","layui-icon-face-smile"],o="layui-anim layui-anim-rotate layui-anim-loop",0==a.type&&-1!==a.icon?'':3==a.type?(i=["layui-icon-loading","layui-icon-loading-1"],2==a.icon?'
    ':''):"")+((1!=a.type||!e)&&a.content||"")+'
    '+(n=[],l&&(n.push(''),n.push('')),a.closeBtn&&n.push(''),n.join(""))+"
    "+(a.btn?function(){var e="";"string"==typeof a.btn&&(a.btn=[a.btn]);for(var t=0,i=a.btn.length;t'+a.btn[t]+"";return'
    '+e+"
    "}():"")+(a.resize?'':"")+""],s,m('
    ')),this},t.pt.creat=function(){var e,t,i,n,a,o=this,s=o.config,l=o.index,r="object"==typeof(f=s.content),c=m("body");if(s.id&&m("."+y[0]).find("#"+s.id)[0])return e=m("#"+s.id).closest("."+y[0]),t=e.attr("times"),i=e.data("config"),n=m("#"+y.SHADE+t),void("min"===(e.data("maxminStatus")||{})?h.restore(t):i.hideOnClose&&(n.show(),e.show()));switch(s.removeFocus&&document.activeElement.blur(),"string"==typeof s.area&&(s.area="auto"===s.area?["",""]:[s.area,""]),s.shift&&(s.anim=s.shift),6==h.ie&&(s.fixed=!1),s.type){case 0:s.btn="btn"in s?s.btn:u.btn[0],h.closeAll("dialog");break;case 2:var f=s.content=r?s.content:[s.content||"","auto"];s.content='';break;case 3:delete s.title,delete s.closeBtn,-1===s.icon&&s.icon,h.closeAll("loading");break;case 4:r||(s.content=[s.content,"body"]),s.follow=s.content[1],s.content=s.content[0]+'',delete s.title,s.tips="object"==typeof s.tips?s.tips:[s.tips,!0],s.tipsMore||h.closeAll("tips")}o.vessel(r,function(e,t,i){c.append(e[0]),r?2==s.type||4==s.type?m("body").append(e[1]):f.parents("."+y[0])[0]||(f.data("display",f.css("display")).show().addClass("layui-layer-wrap").wrap(e[1]),m("#"+y[0]+l).find("."+y[5]).before(t)):c.append(e[1]),m("#"+y.MOVE)[0]||c.append(u.moveElem=i),o.layero=m("#"+y[0]+l),o.shadeo=m("#"+y.SHADE+l),s.scrollbar||y.html.css("overflow","hidden").attr("layer-full",l)}).auto(l),o.shadeo.css({"background-color":s.shade[1]||"#000",opacity:s.shade[0]||s.shade}),2==s.type&&6==h.ie&&o.layero.find("iframe").attr("src",f[0]),4==s.type?o.tips():(o.offset(),parseInt(u.getStyle(document.getElementById(y.MOVE),"z-index"))||(o.layero.css("visibility","hidden"),h.ready(function(){o.offset(),o.layero.css("visibility","visible")}))),s.fixed&&!u.events.resize[o.index]&&(u.events.resize[o.index]=function(){o.resize()},d.on("resize",u.events.resize[o.index])),s.time<=0||setTimeout(function(){h.close(o.index)},s.time),o.move().callback(),y.anim[s.anim]&&(a="layer-anim "+y.anim[s.anim],o.layero.addClass(a).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",function(){m(this).removeClass(a)})),o.layero.data("config",s)},t.pt.resize=function(){var e=this,t=e.config;e.offset(),(/^\d+%$/.test(t.area[0])||/^\d+%$/.test(t.area[1]))&&e.auto(e.index),4==t.type&&e.tips()},t.pt.auto=function(e){var t=this.config,i=m("#"+y[0]+e),n=(""===t.area[0]&&0t.maxWidth&&i.width(t.maxWidth)),[i.innerWidth(),i.innerHeight()]),a=i.find(y[1]).outerHeight()||0,o=i.find("."+y[6]).outerHeight()||0,e=function(e){(e=i.find(e)).height(n[1]-a-o-2*(0|parseFloat(e.css("padding-top"))))};return 2===t.type?e("iframe"):""===t.area[1]?0t.maxHeight?(n[1]=t.maxHeight,e("."+y[5])):t.fixed&&n[1]>=d.height()&&(n[1]=d.height(),e("."+y[5])):e("."+y[5]),this},t.pt.offset=function(){var e=this,t=e.config,i=e.layero,n=[i.outerWidth(),i.outerHeight()],a="object"==typeof t.offset;e.offsetTop=(d.height()-n[1])/2,e.offsetLeft=(d.width()-n[0])/2,a?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):"auto"!==t.offset&&("t"===t.offset?e.offsetTop=0:"r"===t.offset?e.offsetLeft=d.width()-n[0]:"b"===t.offset?e.offsetTop=d.height()-n[1]:"l"===t.offset?e.offsetLeft=0:"lt"===t.offset?(e.offsetTop=0,e.offsetLeft=0):"lb"===t.offset?(e.offsetTop=d.height()-n[1],e.offsetLeft=0):"rt"===t.offset?(e.offsetTop=0,e.offsetLeft=d.width()-n[0]):"rb"===t.offset?(e.offsetTop=d.height()-n[1],e.offsetLeft=d.width()-n[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?d.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?d.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=d.scrollTop(),e.offsetLeft+=d.scrollLeft()),"min"===i.data("maxminStatus")&&(e.offsetTop=d.height()-(i.find(y[1]).outerHeight()||0),e.offsetLeft=i.css("left")),i.css({top:e.offsetTop,left:e.offsetLeft})},t.pt.tips=function(){var e=this.config,t=this.layero,i=[t.outerWidth(),t.outerHeight()],n=m(e.follow),a={width:(n=n[0]?n:m("body")).outerWidth(),height:n.outerHeight(),top:n.offset().top,left:n.offset().left},o=t.find(".layui-layer-TipsG"),n=e.tips[0];e.tips[1]||o.remove(),a.autoLeft=function(){0d.width()&&(o=d.width()-180-(u.minStackArr.edgeIndex=u.minStackArr.edgeIndex||0,u.minStackArr.edgeIndex+=3))<0&&(o=0),t.minStack&&(l.left=o,l.top=d.height()-n,a||u.minStackIndex++,r.attr("minLeft",o)),r.attr("position",s),h.style(e,l,!0),i.hide(),"page"===r.attr("type")&&r.find(y[4]).hide(),u.rescollbar(e),c.hide())},h.restore=function(e){var t=m("#"+y[0]+e),i=m("#"+y.SHADE+e),n=t.attr("area").split(","),a=t.attr("type");t.removeData("maxminStatus"),h.style(e,{width:n[0],height:n[1],top:parseFloat(n[2]),left:parseFloat(n[3]),position:t.attr("position"),overflow:"visible"},!0),t.find(".layui-layer-max").removeClass("layui-layer-maxmin"),t.find(".layui-layer-min").show(),"page"===a&&t.find(y[4]).show(),u.rescollbar(e),i.show()},h.full=function(t){var i=m("#"+y[0]+t),e=i.data("maxminStatus");"max"!==e&&("min"===e&&h.restore(t),i.data("maxminStatus","max"),u.record(i),y.html.attr("layer-full")||y.html.css("overflow","hidden").attr("layer-full",t),clearTimeout(void 0),setTimeout(function(){var e="fixed"===i.css("position");h.style(t,{top:e?0:d.scrollTop(),left:e?0:d.scrollLeft(),width:"100%",height:"100%"},!0),i.find(".layui-layer-min").hide()},100))},h.title=function(e,t){m("#"+y[0]+(t||h.index)).find(y[1]).html(e)},h.close=function(o,s){var l,e,r=(t=m("."+y[0]).find("#"+o).closest("."+y[0]))[0]?(o=t.attr("times"),t):m("#"+y[0]+o),c=r.attr("type"),t=r.data("config")||{},f=t.id&&t.hideOnClose;r[0]&&(l={slideDown:"layer-anim-slide-down-out",slideLeft:"layer-anim-slide-left-out",slideUp:"layer-anim-slide-up-out",slideRight:"layer-anim-slide-right-out"}[t.anim]||"layer-anim-close",e=function(){var e="layui-layer-wrap";if(f)return r.removeClass("layer-anim "+l),r.hide();if(c===u.type[1]&&"object"===r.attr("conType")){r.children(":not(."+y[5]+")").remove();for(var t=r.find("."+e),i=0;i<2;i++)t.unwrap();t.css("display",t.data("display")).removeClass(e)}else{if(c===u.type[2])try{var n=m("#"+y[4]+o)[0];n.contentWindow.document.write(""),n.contentWindow.close(),r.find("."+y[5])[0].removeChild(n)}catch(a){}r[0].innerHTML="",r.remove()}"function"==typeof u.end[o]&&u.end[o](),delete u.end[o],"function"==typeof s&&s(),u.events.resize[o]&&(d.off("resize",u.events.resize[o]),delete u.events.resize[o])},m("#"+y.SHADE+o)[f?"hide":"remove"](),t.isOutAnim&&r.addClass("layer-anim "+l),6==h.ie&&u.reselect(),u.rescollbar(o),"string"==typeof r.attr("minLeft")&&(u.minStackIndex--,u.minStackArr.push(r.attr("minLeft"))),h.ie&&h.ie<10||!t.isOutAnim?e():setTimeout(function(){e()},200))},h.closeAll=function(n,a){"function"==typeof n&&(a=n,n=null);var o=m("."+y[0]);m.each(o,function(e){var t=m(this),i=n?t.attr("type")===n:1;i&&h.close(t.attr("times"),e===o.length-1?a:null)}),0===o.length&&"function"==typeof a&&a()},h.closeLast=function(e){h.close(m(".layui-layer-"+(e=e||"page")+":last").attr("times"))},h.cache||{}),g=function(e){return i.skin?" "+i.skin+" "+i.skin+"-"+e:""};h.prompt=function(i,n){var e="",t="";"function"==typeof(i=i||{})&&(n=i),i.area&&(e='style="width: '+(o=i.area)[0]+"; height: "+o[1]+';"',delete i.area),i.placeholder&&(t=' placeholder="'+i.placeholder+'"');var a,o=2==i.formType?'":'",s=i.success;return delete i.success,h.open(m.extend({type:1,btn:["确定","取消"],content:o,skin:"layui-layer-prompt"+g("prompt"),maxWidth:d.width(),success:function(e){(a=e.find(".layui-layer-input")).val(i.value||"").focus(),"function"==typeof s&&s(e)},resize:!1,yes:function(e){var t=a.val();t.length>(i.maxlength||500)?h.tips("最多输入"+(i.maxlength||500)+"个字数",a,{tips:1}):n&&n(t,e,a)}},i))},h.tab=function(n){var a=(n=n||{}).tab||{},o="layui-this",s=n.success;return delete n.success,h.open(m.extend({type:1,skin:"layui-layer-tab"+g("tab"),resize:!1,title:function(){var e=a.length,t=1,i="";if(0'+a[0].title+"";t"+a[t].title+"";return i}(),content:'
      '+function(){var e=a.length,t=1,i="";if(0'+(a[0].content||"no content")+"";t'+(a[t].content||"no content")+"";return i}()+"
    ",success:function(e){var t=e.find(".layui-layer-title").children(),i=e.find(".layui-layer-tabmain").children();t.on("mousedown",function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0;var e=m(this),t=e.index();e.addClass(o).siblings().removeClass(o),i.eq(t).show().siblings().hide(),"function"==typeof n.change&&n.change(t)}),"function"==typeof s&&s(e)}},n))},h.photos=function(n,e,a){var o={};if((n=n||{}).photos){var t=!("string"==typeof n.photos||n.photos instanceof m),i=t?n.photos:{},s=i.data||[],l=i.start||0,r=(o.imgIndex=1+(0|l),n.img=n.img||"img",n.success);if(delete n.success,t){if(0===s.length)return h.msg("没有图片")}else{var c=m(n.photos),f=function(){s=[],c.find(n.img).each(function(e){var t=m(this);t.attr("layer-index",e),s.push({alt:t.attr("alt"),pid:t.attr("layer-pid"),src:t.attr("lay-src")||t.attr("layer-src")||t.attr("src"),thumb:t.attr("src")})})};if(f(),0===s.length)return;if(e||c.on("click",n.img,function(){f();var e=m(this).attr("layer-index");h.photos(m.extend(n,{photos:{start:e,data:s,tab:n.tab},full:n.full}),!0)}),!e)return}o.imgprev=function(e){o.imgIndex--,o.imgIndex<1&&(o.imgIndex=s.length),o.tabimg(e)},o.imgnext=function(e,t){o.imgIndex++,o.imgIndex>s.length&&(o.imgIndex=1,t)||o.tabimg(e)},o.keyup=function(e){var t;o.end||(t=e.keyCode,e.preventDefault(),37===t?o.imgprev(!0):39===t?o.imgnext(!0):27===t&&h.close(o.index))},o.tabimg=function(e){if(!(s.length<=1))return i.start=o.imgIndex-1,h.close(o.index),h.photos(n,!0,e)},o.event=function(){o.bigimg.find(".layui-layer-imgprev").on("click",function(e){e.preventDefault(),o.imgprev(!0)}),o.bigimg.find(".layui-layer-imgnext").on("click",function(e){e.preventDefault(),o.imgnext(!0)}),m(document).on("keyup",o.keyup)},o.loadi=h.load(1,{shade:!("shade"in n)&&.9,scrollbar:!1});var t=s[l].src,d=function(e){h.close(o.loadi);var t,i=s[l].alt||"";a&&(n.anim=-1),o.index=h.open(m.extend({type:1,id:"layui-layer-photos",area:(e=[e.width,e.height],t=[m(p).width()-100,m(p).height()-100],!n.full&&(e[0]>t[0]||e[1]>t[1])&&((t=[e[0]/t[0],e[1]/t[1]])[1]'+i+''+(t=['
    '],1','','',"
    "].join("")),n.hideFooter||t.push(['
    ','
    ',"

    "+i+"

    ",""+o.imgIndex+" / "+s.length+"",'\u67e5\u770b\u539f\u56fe',"
    ","
    "].join("")),t.push(""),t.join(""))+"",success:function(e,t){o.bigimg=e.find(".layui-layer-phimg"),o.imgsee=e.find(".layui-layer-imgbar"),o.event(e),n.tab&&n.tab(s[l],e),"function"==typeof r&&r(e)},end:function(){o.end=!0,m(document).off("keyup",o.keyup)}},n))},u=function(){h.close(o.loadi),h.msg("当前图片地址异常
    是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){1").addClass(a));layui.each(i.bars,function(e,t){var n=s('
  • ');n.addClass(t.icon).attr({"lay-type":t.type,style:t.style||(i.bgcolor?"background-color: "+i.bgcolor:"")}).html(t.content),n.on("click",function(){var e=s(this).attr("lay-type");"top"===e&&("body"===i.target?s("html,body"):c).animate({scrollTop:0},i.duration),"function"==typeof i.click&&i.click.call(this,e)}),"object"===layui.type(i.on)&&layui.each(i.on,function(e,t){n.on(e,function(){var e=s(this).attr("lay-type");"function"==typeof t&&t.call(this,e)})}),"top"===t.type&&(n.addClass("layui-fixbar-top"),o=n),u.append(n)}),l.find("."+a).remove(),"object"==typeof i.css&&u.css(i.css),l.append(u),o&&(t=function t(){return c.scrollTop()>=i.margin?e||(o.show(),e=1):e&&(o.hide(),e=0),t}()),c.on("scroll",function(){t&&(clearTimeout(n),n=setTimeout(function(){t()},100))})},countdown:function(e,t,n){var i=this,o="function"==typeof t,a=new Date(e).getTime(),r=new Date(!t||o?(new Date).getTime():t).getTime(),a=a-r,l=[Math.floor(a/864e5),Math.floor(a/36e5)%24,Math.floor(a/6e4)%60,Math.floor(a/1e3)%60],o=(o&&(n=t),setTimeout(function(){i.countdown(e,r+1e3,n)},1e3));return n&&n(0]|&(?=#[a-zA-Z0-9]+)/g.test(e+="")?e.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,"""):e},unescape:function(e){return e!==undefined&&null!==e||(e=""),(e+="").replace(/\&/g,"&").replace(/\</g,"<").replace(/\>/g,">").replace(/\'/g,"'").replace(/\"/g,'"')},openWin:function(e){var t=(e=e||{}).window||window.open(e.url||"",e.target,e.specs);e.url||(t.document.open("text/html","replace"),t.document.write(e.content||""),t.document.close())},toVisibleArea:function(e){var t,n,i,o,a,r,l,c;(e=s.extend({margin:160,duration:200,type:"y"},e)).scrollElem[0]&&e.thisElem[0]&&(t=e.scrollElem,l=e.thisElem,i=(a="y"===e.type)?"top":"left",o=t[n=a?"scrollTop":"scrollLeft"](),a=t[a?"height":"width"](),r=t.offset()[i],c={},((l=l.offset()[i]-r)>a-e.margin||l."+h,k=function(e){var i=this;i.index=++p.index,i.config=s.extend({},i.config,p.config,e),i.init()};k.prototype.config={trigger:"click",content:"",className:"",style:"",show:!1,isAllowSpread:!0,isSpreadItem:!0,data:[],delay:300,shade:0},k.prototype.reload=function(e,i){var t=this;t.config=s.extend({},t.config,e),t.init(!0,i)},k.prototype.init=function(e,i){var t,n=this,a=n.config,l=s(a.elem);return 1');return 0No data
  • '),e},u=function(r,e){return layui.each(e,function(e,i){var t,n=i.child&&0",(t="href"in i?''+l+"":l,n?'
    '+t+("parent"===o?'':"group"===o&&d.isAllowSpread?'':"")+"
    ":'
    '+t+"
    "),""].join(""))).data("item",i),n&&(a=s('
    '),t=s("
      "),"parent"===o?(a.append(u(t,i.child)),l.append(a)):l.append(u(t,i.child))),r.append(l))}),r},a=['
      ',"
      "].join("");!(e="contextmenu"!==d.trigger&&!lay.isTopElem(d.elem[0])?e:!0)&&d.elem.data(m+"_opened")||(l.elemView=s("."+f+'[lay-id="'+d.id+'"]'),"reloadData"===i&&l.elemView.length?l.elemView.html(d.content||n()):(l.elemView=s(a),l.elemView.append(d.content||n()),d.className&&l.elemView.addClass(d.className),d.style&&l.elemView.attr("style",d.style),p.thisId=d.id,l.remove(),t.append(l.elemView),d.elem.data(m+"_opened",!0),e=d.shade?'
      ':"",l.elemView.before(e),"mouseenter"===d.trigger&&l.elemView.on("mouseenter",function(){clearTimeout(y.timer)}).on("mouseleave",function(){l.delayRemove()})),l.position(),(y.prevElem=l.elemView).data("prevElem",d.elem),l.elemView.find(".layui-menu").on(o,function(e){layui.stope(e)}),l.elemView.find(".layui-menu li").on("click",function(e){var i=s(this),t=i.data("item")||{},n=t.child&&0n.width()&&(t.addClass(V),(i=t[0].getBoundingClientRect()).left<0&&t.removeClass(V)),i.bottom>n.height()&&t.eq(0).css("margin-top",-(i.bottom-n.height()+5)))}).on("mouseleave",t,function(e){var i=s(this).children("."+C);i.removeClass(V),i.css("margin-top",0)}),p.close=function(e){e=y.getThis(e);return e?(e.remove(),y.call(e)):this},p.reload=function(e,i,t){e=y.getThis(e);return e?(e.reload(i,t),y.call(e)):this},p.reloadData=function(){var t=s.extend([],arguments),n=(t[2]="reloadData",new RegExp("^("+["data","templet","content"].join("|")+")$"));return layui.each(t[1],function(e,i){n.test(e)||delete t[1][e]}),p.reload.apply(null,t)},p.render=function(e){e=new k(e);return y.call(e)},e(r,p)});layui.define(["jquery","lay"],function(e){"use strict";var g=layui.$,c=layui.lay,m={config:{},index:layui.slider?layui.slider.index+1e4:0,set:function(e){var i=this;return i.config=g.extend({},i.config,e),i},on:function(e,i){return layui.onevent.call(this,t,e,i)}},t="slider",v="layui-disabled",x="layui-slider-bar",b="layui-slider-wrap",T="layui-slider-wrap-btn",w="layui-slider-tips",M="layui-slider-input-txt",L="layui-slider-hover",i=function(e){var i=this;i.index=++m.index,i.config=g.extend({},i.config,m.config,e),i.render()};i.prototype.config={type:"default",min:0,max:100,value:0,step:1,showstep:!1,tips:!0,input:!1,range:!1,height:200,disabled:!1,theme:"#16baaa"},i.prototype.render=function(){var a=this,n=a.config,e=g(n.elem);if(1n.min?e:n.min,n.value[1]=i>n.min?i:n.min,n.value[0]=n.value[0]>n.max?n.max:n.value[0],n.value[1]=n.value[1]>n.max?n.max:n.value[1],i=Math.floor((n.value[0]-n.min)/(n.max-n.min)*100),t=(s=Math.floor((n.value[1]-n.min)/(n.max-n.min)*100))-i+"%",i+="%",s+="%"):("object"==typeof n.value&&(n.value=Math.min.apply(null,n.value)),n.valuen.max&&(n.value=n.max),t=Math.floor((n.value-n.min)/(n.max-n.min)*100)+"%");var l,e=n.disabled?"#c2c2c2":n.theme,i='
      '+(n.tips?'
      ':"")+'
      '+(n.range?'
      ':"")+"
      ",t=g(n.elem),s=t.next(".layui-slider");if(s[0]&&s.remove(),a.elemTemp=g(i),n.range?(a.elemTemp.find("."+b).eq(0).data("value",n.value[0]),a.elemTemp.find("."+b).eq(1).data("value",n.value[1])):a.elemTemp.find("."+b).data("value",n.value),t.html(a.elemTemp),"vertical"===n.type&&a.elemTemp.height(n.height+"px"),n.showstep){for(var o=(n.max-n.min)/n.step,r="",u=1;u<1+o;u++){var d=100*u/o;d<100&&(r+='
      ')}a.elemTemp.append(r)}n.input&&!n.range&&(e=g('
      '),t.css("position","relative"),t.append(e),t.find("."+M).children("input").val(n.value),"vertical"===n.type?e.css({left:0,top:-48}):a.elemTemp.css("margin-right",e.outerWidth()+15)),n.disabled?(a.elemTemp.addClass(v),a.elemTemp.find("."+T).addClass(v)):a.slide(),a.elemTemp.find("."+T).on("mouseover",function(){var e="vertical"===n.type?n.height:a.elemTemp[0].offsetWidth,i=a.elemTemp.find("."+b),t=("vertical"===n.type?e-g(this).parent()[0].offsetTop-i.height():g(this).parent()[0].offsetLeft)/e*100,i=g(this).parent().data("value"),e=n.setTips?n.setTips(i):i;a.elemTemp.find("."+w).html(e),clearTimeout(l),l=setTimeout(function(){"vertical"===n.type?a.elemTemp.find("."+w).css({bottom:t+"%","margin-bottom":"20px",display:"inline-block"}):a.elemTemp.find("."+w).css({left:t+"%",display:"inline-block"})},300)}).on("mouseout",function(){clearTimeout(l),a.elemTemp.find("."+w).css("display","none")})},i.prototype.slide=function(e,i,t){var o=this,r=o.config,u=o.elemTemp,d=function(){return"vertical"===r.type?r.height:u[0].offsetWidth},c=u.find("."+b),m=u.next(".layui-slider-input"),v=m.children("."+M).children("input").val(),p=100/((r.max-r.min)/Math.ceil(r.step)),f=function(e,i,t){e=(e=100<(e=100a[1]&&a.reverse(),o.value=r.range?a:l,r.change&&r.change(o.value),"done"===t&&r.done&&r.done(o.value)},h=function(e){var i=e/d()*100/p,t=Math.round(i)*p;return t=e==d()?Math.ceil(i)*p:t},y=g(['
      d()?d():i)/d()*100/p;f(i,l),s.addClass(L),u.find("."+w).show(),e.preventDefault()},i=function(){s.removeClass(L),u.find("."+w).hide()},t=function(){i&&i(),y.remove(),r.done&&r.done(o.value)},g("#LAY-slider-moving")[0]||g("body").append(y),y.on("mousemove",e),y.on("mouseup",t).on("mouseleave",t)})}),u.on("click",function(e){var i=g("."+T),t=g(this);!i.is(event.target)&&0===i.has(event.target).length&&i.length&&(t=(i=(i=(i="vertical"===r.type?d()-e.clientY+t.offset().top-g(window).scrollTop():e.clientX-t.offset().left-g(window).scrollLeft())<0?0:i)>d()?d():i)/d()*100/p,i=r.range?"vertical"===r.type?Math.abs(i-parseInt(g(c[0]).css("bottom")))>Math.abs(i-parseInt(g(c[1]).css("bottom")))?1:0:Math.abs(i-c[0].offsetLeft)>Math.abs(i-c[1].offsetLeft)?1:0:0,f(t,i,"done"),e.preventDefault())}),m.children(".layui-slider-input-btn").children("i").each(function(i){g(this).on("click",function(){v=m.children("."+M).children("input").val();var e=((v=1==i?v-r.stepr.max?r.max:Number(v)+r.step)-r.min)/(r.max-r.min)*100/p;f(e,0,"done")})});var a=function(){var e=this.value,e=(e=(e=(e=isNaN(e)?0:e)r.max?r.max:e,((this.value=e)-r.min)/(r.max-r.min)*100/p);f(e,0,"done")};m.children("."+M).children("input").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),a.call(this))}).on("change",a)},i.prototype.events=function(){this.config},m.render=function(e){e=new i(e);return function(){var t=this,a=t.config;return{setValue:function(e,i){return e=(e=e>a.max?a.max:e)',"",'','',"","","
      "].join("")),r=i.elem=m(i.elem);i.size&&o.addClass("layui-colorpicker-"+i.size),r.addClass("layui-inline").html(e.elemColorBox=o),i.id="id"in i?i.id:r.attr("id")||e.index,e.color=e.elemColorBox.find("."+C)[0].style.background,e.events()},d.prototype.renderPicker=function(){var o,e=this,i=e.config,r=e.elemColorBox[0],t=e.elemPicker=m(['
      ','
      ','
      ','
      ','
      ','
      ',"
      ",'
      ','
      ',"
      ","
      ",'
      ','
      ','
      ',"
      ","
      ",i.predefine?(o=['
      '],layui.each(i.colors,function(e,i){o.push(['
      ','
      ',"
      "].join(""))}),o.push("
      "),o.join("")):"",'
      ','
      ','',"
      ",'
      ','','',"","
      "].join(""));e.elemColorBox.find("."+C)[0];m(a)[0]&&m(a).data("index")==e.index?e.removePicker(d.thisElemInd):(e.removePicker(d.thisElemInd),m("body").append(t)),n.thisId=i.id,d.thisElemInd=e.index,d.thisColor=r.style.background,e.position(),e.pickerEvents()},d.prototype.removePicker=function(e){var i=this.config,e=m("#layui-colorpicker"+(e||this.index));return e[0]&&(e.remove(),delete n.thisId,"function"==typeof i.close&&i.close(this.color)),this},d.prototype.position=function(){var e=this,i=e.config;return t.position(e.bindElem||e.elemColorBox[0],e.elemPicker[0],{position:i.position,align:"center"}),e},d.prototype.val=function(){var e,i=this,o=(i.config,i.elemColorBox.find("."+C)),r=i.elemPicker.find("."+M),t=o[0].style.backgroundColor;t?(e=Y(L(t)),o=o.attr("lay-type"),i.select(e.h,e.s,e.b),"torgb"===o?r.find("input").val(t):"rgba"===o?(o=L(t),3===(t.match(/[0-9]{1,3}/g)||[]).length?(r.find("input").val("rgba("+o.r+", "+o.g+", "+o.b+", 1)"),i.elemPicker.find("."+T).css("left",280)):(r.find("input").val(t),t=280*t.slice(t.lastIndexOf(",")+1,t.length-1),i.elemPicker.find("."+T).css("left",t)),i.elemPicker.find("."+D)[0].style.background="linear-gradient(to right, rgba("+o.r+", "+o.g+", "+o.b+", 0), rgb("+o.r+", "+o.g+", "+o.b+"))"):r.find("input").val("#"+F(e))):(i.select(0,100,100),r.find("input").val(""),i.elemPicker.find("."+D)[0].style.background="",i.elemPicker.find("."+T).css("left",280))},d.prototype.side=function(){var n=this,l=n.config,c=n.elemColorBox.find("."+C),a=c.attr("lay-type"),s=n.elemPicker.find(".layui-colorpicker-side"),e=n.elemPicker.find("."+B),d=n.elemPicker.find("."+I),r=n.elemPicker.find("."+E),f=n.elemPicker.find("."+D),u=n.elemPicker.find("."+T),g=e[0].offsetTop/180*360,p=100-(r[0].offsetTop+3)/180*100,h=(r[0].offsetLeft+3)/260*100,v=Math.round(u[0].offsetLeft/280*100)/100,b=n.elemColorBox.find("."+w),i=n.elemPicker.find(".layui-colorpicker-pre").children("div"),y=function(e,i,o,r){n.select(e,i,o);var t=j({h:e,s:i,b:o}),e=F({h:e,s:i,b:o}),i=n.elemPicker.find("."+M).find("input");b.addClass(x).removeClass(P),c[0].style.background="rgb("+t.r+", "+t.g+", "+t.b+")","torgb"===a?i.val("rgb("+t.r+", "+t.g+", "+t.b+")"):"rgba"===a?(u.css("left",280*r),i.val("rgba("+t.r+", "+t.g+", "+t.b+", "+r+")"),c[0].style.background="rgba("+t.r+", "+t.g+", "+t.b+", "+r+")",f[0].style.background="linear-gradient(to right, rgba("+t.r+", "+t.g+", "+t.b+", 0), rgb("+t.r+", "+t.g+", "+t.b+"))"):i.val("#"+e),l.change&&l.change(n.elemPicker.find("."+M).find("input").val())},o=m(['
      '].join("")),k=function(e){m("#LAY-colorpicker-moving")[0]||m("body").append(o),o.on("mousemove",e),o.on("mouseup",function(){o.remove()}).on("mouseleave",function(){o.remove()})};e.on("mousedown",function(e){var r=this.offsetTop,t=e.clientY;k(function(e){var i=r+(e.clientY-t),o=s[0].offsetHeight,o=(i=o<(i=i<0?0:i)?o:i)/180*360;y(g=o,h,p,v),e.preventDefault()}),e.preventDefault()}),s.on("click",function(e){var i=e.clientY-m(this).offset().top+H.scrollTop(),i=(i=(i=i<0?0:i)>this.offsetHeight?this.offsetHeight:i)/180*360;y(g=i,h,p,v),e.preventDefault()}),r.on("mousedown",function(e){var n=this.offsetTop,l=this.offsetLeft,c=e.clientY,a=e.clientX;layui.stope(e),k(function(e){var i=n+(e.clientY-c),o=l+(e.clientX-a),r=d[0].offsetHeight-3,t=d[0].offsetWidth-3,t=((o=t<(o=o<-3?-3:o)?t:o)+3)/260*100,o=100-((i=r<(i=i<-3?-3:i)?r:i)+3)/180*100;y(g,h=t,p=o,v),e.preventDefault()}),e.preventDefault()}),d.on("mousedown",function(e){var i=e.clientY-m(this).offset().top-3+H.scrollTop(),o=e.clientX-m(this).offset().left-3+H.scrollLeft(),o=((i=i<-3?-3:i)>this.offsetHeight-3&&(i=this.offsetHeight-3),((o=(o=o<-3?-3:o)>this.offsetWidth-3?this.offsetWidth-3:o)+3)/260*100),i=100-(i+3)/180*100;y(g,h=o,p=i,v),layui.stope(e),e.preventDefault(),r.trigger(e,"mousedown")}),u.on("mousedown",function(e){var r=this.offsetLeft,t=e.clientX;k(function(e){var i=r+(e.clientX-t),o=f[0].offsetWidth,o=(o<(i=i<0?0:i)&&(i=o),Math.round(i/280*100)/100);y(g,h,p,v=o),e.preventDefault()}),e.preventDefault()}),f.on("click",function(e){var i=e.clientX-m(this).offset().left,i=((i=i<0?0:i)>this.offsetWidth&&(i=this.offsetWidth),Math.round(i/280*100)/100);y(g,h,p,v=i),e.preventDefault()}),i.each(function(){m(this).on("click",function(){m(this).parent(".layui-colorpicker-pre").addClass("selected").siblings().removeClass("selected");var e=this.style.backgroundColor,i=Y(L(e)),o=e.slice(e.lastIndexOf(",")+1,e.length-1);g=i.h,h=i.s,p=i.b,3===(e.match(/[0-9]{1,3}/g)||[]).length&&(o=1),v=o,y(i.h,i.s,i.b,o)})})},d.prototype.select=function(e,i,o,r){this.config;var t=F({h:e,s:100,b:100}),e=(F({h:e,s:i,b:o}),e/360*180),o=180-o/100*180-3,i=i/100*260-3;this.elemPicker.find("."+B).css("top",e),this.elemPicker.find("."+I)[0].style.background="#"+t,this.elemPicker.find("."+E).css({top:o,left:i})},d.prototype.pickerEvents=function(){var c=this,a=c.config,s=c.elemColorBox.find("."+C),d=c.elemPicker.find("."+M+" input"),o={clear:function(e){s[0].style.background="",c.elemColorBox.find("."+w).removeClass(x).addClass(P),c.color="",a.done&&a.done(""),c.removePicker()},confirm:function(e,i){var o,r,t,n,l=d.val();if(-1>16,g:(65280&t)>>8,b:255&t},r=Y(n),s[0].style.background=o="#"+F(r),c.elemColorBox.find("."+w).removeClass(P).addClass(x)),"change"===i)return c.select(r.h,r.s,r.b,i),void(a.change&&a.change(o));c.color=l,a.done&&a.done(l),c.removePicker()}};c.elemPicker.on("click","*[colorpicker-events]",function(){var e=m(this),i=e.attr("colorpicker-events");o[i]&&o[i].call(this,e)}),d.on("keyup",function(e){var i=m(this);o.confirm.call(this,i,13===e.keyCode?null:"change")})},d.prototype.events=function(){var e=this;e.config;e.elemColorBox.on("click",function(){e.renderPicker(),m(a)[0]&&(e.val(),e.side())})},s.on(i,function(e){var i,o,r;!n.thisId||(i=l.getThis(n.thisId))&&(o=i.config,r=i.elemColorBox.find("."+C),m(e.target).hasClass(c)||m(e.target).parents("."+c)[0]||m(e.target).hasClass(a.replace(/\./g,""))||m(e.target).parents(a)[0]||i.elemPicker&&(i.color?(e=Y(L(i.color)),i.select(e.h,e.s,e.b)):i.elemColorBox.find("."+w).removeClass(x).addClass(P),r[0].style.background=i.color||"","function"==typeof o.cancel&&o.cancel(i.color),i.removePicker()))}),H.on("resize",function(){if(n.thisId){var e=l.getThis(n.thisId);if(e)return!(!e.elemPicker||!m(a)[0])&&void e.position()}}),l.that={},l.getThis=function(e){var i=l.that[e];return i||o.error(e?r+" instance with ID '"+e+"' not found":"ID argument required"),i},n.render=function(e){e=new d(e);return l.call(e)},e(r,n)});layui.define("jquery",function(t){"use strict";var u=layui.$,d=(layui.hint(),layui.device()),o="element",c="layui-this",h="layui-show",r=".layui-tab-title",i=function(){this.config={}},y=(i.prototype.set=function(t){return u.extend(!0,this.config,t),this},i.prototype.on=function(t,i){return layui.onevent.call(this,o,t,i)},i.prototype.tabAdd=function(t,i){var a,e=u(".layui-tab[lay-filter="+t+"]"),l=e.children(r),n=l.children(".layui-tab-bar"),e=e.children(".layui-tab-content"),s=""+(i.title||"unnaming")+"";return n[0]?n.before(s):l.append(s),e.append('
      '+(i.content||"")+"
      "),i.change&&this.tabChange(t,i.id),l.data("LAY_TAB_CHANGE",i.change),g.tabAuto(i.change?"change":null),this},i.prototype.tabDelete=function(t,i){t=u(".layui-tab[lay-filter="+t+"]").children(r).find('>li[lay-id="'+i+'"]');return g.tabDelete(null,t),this},i.prototype.tabChange=function(t,i){t=u(".layui-tab[lay-filter="+t+"]").children(r).find('>li[lay-id="'+i+'"]');return g.tabClick.call(t[0],{liElem:t}),this},i.prototype.tab=function(a){a=a||{},e.on("click",a.headerElem,function(t){var i=u(this).index();g.tabClick.call(this,{index:i,options:a})})},i.prototype.progress=function(t,i){var a="layui-progress",t=u("."+a+"[lay-filter="+t+"]").find("."+a+"-bar"),a=t.find("."+a+"-text");return t.css("width",function(){return/^.+\/.+$/.test(i)?100*new Function("return "+i)()+"%":i}).attr("lay-percent",i),a.text(i),this},".layui-nav"),f="layui-nav-item",l="layui-nav-bar",p="layui-nav-tree",b="layui-nav-child",v="layui-nav-more",m="layui-anim layui-anim-upbit",g={tabClick:function(t){var i=(t=t||{}).options||{},a=t.liElem||u(this),e=i.headerElem?a.parent():a.parents(".layui-tab").eq(0),i=i.bodyElem?u(i.bodyElem):e.children(".layui-tab-content").children(".layui-tab-item"),l=a.find("a"),l="javascript:;"!==l.attr("href")&&"_blank"===l.attr("target"),n="string"==typeof a.attr("lay-unselect"),s=e.attr("lay-filter"),t="index"in t?t.index:a.parent().children("li").index(a);l||n||(a.addClass(c).siblings().removeClass(c),i.eq(t).addClass(h).siblings().removeClass(h)),layui.event.call(this,o,"tab("+s+")",{elem:e,index:t})},tabDelete:function(t,i){var i=i||u(this).parent(),a=i.parent().children("li").index(i),e=i.closest(".layui-tab"),l=e.children(".layui-tab-content").children(".layui-tab-item"),n=e.attr("lay-filter");i.hasClass(c)&&(i.next()[0]&&i.next().is("li")?g.tabClick.call(i.next()[0],{index:a+1}):i.prev()[0]&&i.prev().is("li")&&g.tabClick.call(i.prev()[0],null,a-1)),i.remove(),l.eq(a).remove(),setTimeout(function(){g.tabAuto()},50),layui.event.call(this,o,"tabDelete("+n+")",{elem:e,index:a})},tabAuto:function(l){var n="layui-tab-more",s="layui-tab-bar",o="layui-tab-close",c=this;u(".layui-tab").each(function(){var t,i=u(this),a=i.children(".layui-tab-title"),e=(i.children(".layui-tab-content").children(".layui-tab-item"),'lay-stope="tabmore"'),e=u('');c===window&&d.ie,i.attr("lay-allowclose")&&a.find("li").each(function(){var t,i=u(this);i.find("."+o)[0]||((t=u('')).on("click",g.tabDelete),i.append(t))}),"string"!=typeof i.attr("lay-unauto")&&(a.prop("scrollWidth")>a.outerWidth()+1||a.find("li").length&&a.height()>(t=a.find("li").eq(0).height())+t/2?("change"===l&&a.data("LAY_TAB_CHANGE")&&a.addClass(n),a.find("."+s)[0]||(a.append(e),i.attr("overflow",""),e.on("click",function(t){var i=a.hasClass(n);a[i?"removeClass":"addClass"](n)}))):(a.find("."+s).remove(),i.removeAttr("overflow")))})},hideTabMore:function(t){var i=u(".layui-tab-title");!0!==t&&"tabmore"===u(t.target).attr("lay-stope")||(i.removeClass("layui-tab-more"),i.find(".layui-tab-bar").attr("title",""))},clickThis:function(){var t=u(this),i=t.parents(y),a=i.attr("lay-filter"),e=t.parent(),l=t.siblings("."+b),n="string"==typeof e.attr("lay-unselect");"javascript:;"!==t.attr("href")&&"_blank"===t.attr("target")||n||l[0]||(i.find("."+c).removeClass(c),e.addClass(c)),i.hasClass(p)&&(l.removeClass(m),l[0]&&(e["none"===l.css("display")?"addClass":"removeClass"](f+"ed"),"all"===i.attr("lay-shrink")&&e.siblings().removeClass(f+"ed"))),layui.event.call(this,o,"nav("+a+")",t)},collapse:function(){var t=u(this),i=t.find(".layui-colla-icon"),a=t.siblings(".layui-colla-content"),e=t.parents(".layui-collapse").eq(0),l=e.attr("lay-filter"),n="none"===a.css("display");"string"==typeof e.attr("lay-accordion")&&((e=e.children(".layui-colla-item").children("."+h)).siblings(".layui-colla-title").children(".layui-colla-icon").html(""),e.removeClass(h)),a[n?"addClass":"removeClass"](h),i.html(n?"":""),layui.event.call(this,o,"collapse("+l+")",{title:t,content:a,show:n})}},a=(i.prototype.render=i.prototype.init=function(t,i){var a=i?'[lay-filter="'+i+'"]':"",i={tab:function(){g.tabAuto.call({})},nav:function(){var s={},o={},c={},r="layui-nav-title";u(y+a).each(function(t){var i=u(this),a=u(''),e=i.find("."+f);i.find("."+l)[0]||(i.append(a),(i.hasClass(p)?e.find("dd,>."+r):e).on("mouseenter",function(){!function(t,i,a){var e,l=u(this),n=l.find("."+b);i.hasClass(p)?n[0]||(e=l.children("."+r),t.css({top:l.offset().top-i.offset().top,height:(e[0]?e:l).outerHeight(),opacity:1})):(n.addClass(m),n.hasClass("layui-nav-child-c")&&n.css({left:-(n.outerWidth()-l.width())/2}),n[0]?t.css({left:t.position().left+t.width()/2,width:0,opacity:0}):t.css({left:l.position().left+parseFloat(l.css("marginLeft")),top:l.position().top+l.height()-t.height()}),s[a]=setTimeout(function(){t.css({width:n[0]?0:l.width(),opacity:n[0]?0:1})},d.ie&&d.ie<10?0:200),clearTimeout(c[a]),"block"===n.css("display")&&clearTimeout(o[a]),o[a]=setTimeout(function(){n.addClass(h),l.find("."+v).addClass(v+"d")},300))}.call(this,a,i,t)}).on("mouseleave",function(){i.hasClass(p)?a.css({height:0,opacity:0}):(clearTimeout(o[t]),o[t]=setTimeout(function(){i.find("."+b).removeClass(h),i.find("."+v).removeClass(v+"d")},300))}),i.on("mouseleave",function(){clearTimeout(s[t]),c[t]=setTimeout(function(){i.hasClass(p)||a.css({width:0,left:a.position().left+a.width()/2,opacity:0})},200)})),e.find("a").each(function(){var t=u(this);t.parent();t.siblings("."+b)[0]&&!t.children("."+v)[0]&&t.append(''),t.off("click",g.clickThis).on("click",g.clickThis)})})},breadcrumb:function(){u(".layui-breadcrumb"+a).each(function(){var t=u(this),i="lay-separator",a=t.attr(i)||"/",e=t.find("a");e.next("span["+i+"]")[0]||(e.each(function(t){t!==e.length-1&&u(this).after(""+a+"")}),t.css("visibility","visible"))})},progress:function(){var e="layui-progress";u("."+e+a).each(function(){var t=u(this),i=t.find(".layui-progress-bar"),a=i.attr("lay-percent");i.css("width",function(){return/^.+\/.+$/.test(a)?100*new Function("return "+a)()+"%":a}),t.attr("lay-showpercent")&&setTimeout(function(){i.html(''+a+"")},350)})},collapse:function(){u(".layui-collapse"+a).each(function(){u(this).find(".layui-colla-item").each(function(){var t=u(this),i=t.find(".layui-colla-title"),t="none"===t.find(".layui-colla-content").css("display");i.find(".layui-colla-icon").remove(),i.append(''+(t?"":"")+""),i.off("click",g.collapse).on("click",g.collapse)})})}};return i[t]?i[t]():layui.each(i,function(t,i){i()})},new i),e=u(document);u(function(){a.render()}),e.on("click",".layui-tab-title li",g.tabClick),u(window).on("resize",g.tabAuto),t(o,a)});layui.define(["lay","layer"],function(e){"use strict";var y=layui.$,t=layui.layer,F=layui.device(),i={config:{},set:function(e){var t=this;return t.config=y.extend({},t.config,e),t},on:function(e,t){return layui.onevent.call(this,n,e,t)}},n="upload",a="layui-upload-file",o="layui-upload-form",b="layui-upload-iframe",x="layui-upload-choose",w=function(e){var t=this;t.config=y.extend({},t.config,i.config,e),t.render()};w.prototype.config={accept:"images",exts:"",auto:!0,bindAction:"",url:"",force:"",field:"file",acceptMime:"",method:"post",data:{},drag:!0,size:0,number:0,multiple:!1},w.prototype.render=function(e){var t=this;(e=t.config).elem=y(e.elem),e.bindAction=y(e.bindAction),t.file(),t.events()},w.prototype.file=function(){var e=this,t=e.config,i=e.elemFile=y(['"].join("")),n=t.elem.next();(n.hasClass(a)||n.hasClass(o))&&n.remove(),F.ie&&F.ie<10&&t.elem.wrap('
      '),e.isFile()?(e.elemFile=t.elem,t.field=t.elem[0].name):t.elem.after(i),F.ie&&F.ie<10&&e.initIE()},w.prototype.initIE=function(){var i,e=this.config,t=y(''),n=y(['
      ',"
      "].join(""));y("#"+b)[0]||y("body").append(t),e.elem.next().hasClass(o)||(this.elemFile.wrap(n),e.elem.next("."+o).append((i=[],layui.each(e.data,function(e,t){t="function"==typeof t?t():t,i.push('')}),i.join(""))))},w.prototype.msg=function(e){return t.msg(e,{icon:2,shift:6})},w.prototype.isFile=function(){var e=this.config.elem[0];if(e)return"input"===e.tagName.toLocaleLowerCase()&&"file"===e.type},w.prototype.preview=function(n){window.FileReader&&layui.each(this.chooseFiles,function(e,t){var i=new FileReader;i.readAsDataURL(t),i.onload=function(){n&&n(e,t,this.result)}})},w.prototype.upload=function(e,t){var i,n,a,o,l=this,r=l.config,u=l.elemFile[0],c=function(){return e||l.files||l.chooseFiles||u.files},s=function(){var t=0,a=0,e=c(),o=function(){r.multiple&&t+a===l.fileLength&&"function"==typeof r.allDone&&r.allDone({total:l.fileLength,successful:t,failed:a})};layui.each(e,function(i,e){var n=new FormData,e=(layui.each(r.data,function(e,t){t="function"==typeof t?t():t,n.append(e,t)}),n.append(r.field,e),{url:r.url,type:"post",data:n,contentType:!1,processData:!1,dataType:"json",headers:r.headers||{},success:function(e){t++,p(i,e),o()},error:function(e){a++,l.msg(["Upload failed, please try again.","status: "+(e.status||"")+" - "+(e.statusText||"error")].join("
      ")),d(i),o()}});"function"==typeof r.progress&&(e.xhr=function(){var e=y.ajaxSettings.xhr();return e.upload.addEventListener("progress",function(e){var t;e.lengthComputable&&(t=Math.floor(e.loaded/e.total*100),r.progress(t,(r.item||r.elem)[0],e,i))}),e}),y.ajax(e)})},f=function(){var n=y("#"+b);l.elemFile.parent().submit(),clearInterval(w.timer),w.timer=setInterval(function(){var e,t=n.contents().find("body");try{e=t.text()}catch(i){l.msg("Cross-domain requests are not supported"),clearInterval(w.timer),d()}e&&(clearInterval(w.timer),t.html(""),p(0,e))},30)},p=function(e,t){if(l.elemFile.next("."+x).remove(),u.value="","json"===r.force&&"object"!=typeof t)try{t=JSON.parse(t)}catch(i){return t={},l.msg("Please return JSON data format")}"function"==typeof r.done&&r.done(t,e||0,function(e){l.upload(e)})},d=function(e){r.auto&&(u.value=""),"function"==typeof r.error&&r.error(e||0,function(e){l.upload(e)})},m=r.exts,h=(n=[],layui.each(e||l.chooseFiles,function(e,t){n.push(t.name)}),n),g={preview:function(e){l.preview(e)},upload:function(e,t){var i={};i[e]=t,l.upload(i)},pushFile:function(){return l.files=l.files||{},layui.each(l.chooseFiles,function(e,t){l.files[e]=t}),l.files},resetFile:function(e,t,i){t=new File([t],i);l.files=l.files||{},l.files[e]=t}},v={file:"\u6587\u4ef6",images:"\u56fe\u7247",video:"\u89c6\u9891",audio:"\u97f3\u9891"}[r.accept]||"\u6587\u4ef6",h=0===h.length?u.value.match(/[^\/\\]+\..+/g)||[]||"":h;if(0!==h.length){switch(r.accept){case"file":layui.each(h,function(e,t){if(m&&!RegExp(".\\.("+m+")$","i").test(escape(t)))return i=!0});break;case"video":layui.each(h,function(e,t){if(!RegExp(".\\.("+(m||"avi|mp4|wma|rmvb|rm|flash|3gp|flv")+")$","i").test(escape(t)))return i=!0});break;case"audio":layui.each(h,function(e,t){if(!RegExp(".\\.("+(m||"mp3|wav|mid")+")$","i").test(escape(t)))return i=!0});break;default:layui.each(h,function(e,t){if(!RegExp(".\\.("+(m||"jpg|png|gif|bmp|jpeg|svg")+")$","i").test(escape(t)))return i=!0})}if(i)return l.msg("\u9009\u62e9\u7684"+v+"\u4e2d\u5305\u542b\u4e0d\u652f\u6301\u7684\u683c\u5f0f"),u.value="";if("choose"!==t&&!r.auto||(r.choose&&r.choose(g),"choose"!==t)){if(l.fileLength=(a=0,v=c(),layui.each(v,function(){a++}),a),r.number&&l.fileLength>r.number)return l.msg("\u540c\u65f6\u6700\u591a\u53ea\u80fd\u4e0a\u4f20: "+r.number+" \u4e2a\u6587\u4ef6
      \u60a8\u5f53\u524d\u5df2\u7ecf\u9009\u62e9\u4e86: "+l.fileLength+" \u4e2a\u6587\u4ef6");if(01024*r.size&&(t=1<=(t=r.size/1024)?t.toFixed(2)+"MB":r.size+"KB",u.value="",o=t)}),o)return l.msg("\u6587\u4ef6\u5927\u5c0f\u4e0d\u80fd\u8d85\u8fc7 "+o);if(!r.before||!1!==r.before(g))F.ie?(9'+e+"")},r=function(){var e=y(this);(e.attr("lay-data")||e.attr("lay-options"))&&(n.config=y.extend({},a,lay.options(this,{attr:e.attr("lay-data")?"lay-data":null})))};a.elem.off("upload.start").on("upload.start",function(){var e=y(this);r.call(this),n.config.item=e,n.elemFile[0].click()}),F.ie&&F.ie<10||a.elem.off("upload.over").on("upload.over",function(){y(this).attr("lay-over","")}).off("upload.leave").on("upload.leave",function(){y(this).removeAttr("lay-over")}).off("upload.drop").on("upload.drop",function(e,t){var i=y(this),t=t.originalEvent.dataTransfer.files||[];i.removeAttr("lay-over"),r.call(this),o(t),a.auto?n.upload():l(t)}),n.elemFile.off("upload.change").on("upload.change",function(){var e=this.files||[];r.call(this),o(e),a.auto?n.upload():l(e)}),a.bindAction.off("upload.action").on("upload.action",function(){n.upload()}),a.elem.data("haveEvents")||(n.elemFile.on("change",function(){y(this).trigger("upload.change")}),a.elem.on("click",function(){n.isFile()||y(this).trigger("upload.start")}),a.drag&&a.elem.on("dragover",function(e){e.preventDefault(),y(this).trigger("upload.over")}).on("dragleave",function(e){y(this).trigger("upload.leave")}).on("drop",function(e){e.preventDefault(),y(this).trigger("upload.drop",e)}),a.bindAction.on("click",function(){y(this).trigger("upload.action")}),a.elem.data("haveEvents",!0))},i.render=function(e){e=new w(e);return function(){var t=this;return{upload:function(e){t.upload.call(t,e)},reload:function(e){t.reload.call(t,e)},config:t.config}}.call(e)},e(n,i)});layui.define(["lay","layer","util"],function(e){"use strict";var b=layui.$,y=layui.layer,d=layui.util,l=layui.hint(),w=(layui.device(),"form"),o=".layui-form",T="layui-this",$="layui-hide",q="layui-disabled",t=function(){this.config={verify:{required:[/[\S]+/,"\u5fc5\u586b\u9879\u4e0d\u80fd\u4e3a\u7a7a"],phone:[/^1\d{10}$/,"\u8bf7\u8f93\u5165\u6b63\u786e\u7684\u624b\u673a\u53f7"],email:[/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/,"\u90ae\u7bb1\u683c\u5f0f\u4e0d\u6b63\u786e"],url:[/^(#|(http(s?)):\/\/|\/\/)[^\s]+\.[^\s]+$/,"\u94fe\u63a5\u683c\u5f0f\u4e0d\u6b63\u786e"],number:function(e){if(isNaN(e))return"\u53ea\u80fd\u586b\u5199\u6570\u5b57"},date:[/^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/,"\u65e5\u671f\u683c\u5f0f\u4e0d\u6b63\u786e"],identity:[/(^\d{15}$)|(^\d{17}(x|X|\d)$)/,"\u8bf7\u8f93\u5165\u6b63\u786e\u7684\u8eab\u4efd\u8bc1\u53f7"]},verIncludelRequired:!1,autocomplete:null}},i=(t.prototype.set=function(e){return b.extend(!0,this.config,e),this},t.prototype.verify=function(e){return b.extend(!0,this.config.verify,e),this},t.prototype.getFormElem=function(e){return b(o+(e?'[lay-filter="'+e+'"]':""))},t.prototype.on=function(e,t){return layui.onevent.call(this,w,e,t)},t.prototype.val=function(e,i){return this.getFormElem(e).each(function(e,t){var a=b(this);layui.each(i,function(e,t){var i,e=a.find('[name="'+e+'"]');e[0]&&("checkbox"===(i=e[0].type)?e[0].checked=t:"radio"===i?e.each(function(){this.checked=this.value==t}):e.val(t))})}),r.render(null,e),this.getValue(e)},t.prototype.getValue=function(e,t){t=t||this.getFormElem(e);var a={},n={},e=t.find("input,select,textarea");return layui.each(e,function(e,t){var i;b(this);t.name=(t.name||"").replace(/^\s*|\s*&/,""),t.name&&(/^.*\[\]$/.test(t.name)&&(i=t.name.match(/^(.*)\[\]$/g)[0],a[i]=0|a[i],i=t.name.replace(/^(.*)\[\]$/,"$1["+a[i]+++"]")),/^(checkbox|radio)$/.test(t.type)&&!t.checked||(n[i||t.name]=t.value))}),n},t.prototype.render=function(e,t){var i=this.config,a=b(o+(t?'[lay-filter="'+t+'"]':"")),n={input:function(e){e=e||a.find("input,textarea");i.autocomplete&&e.attr("autocomplete",i.autocomplete),a.find("input[lay-affix],textarea[lay-affix]").each(function(){var l=b(this),r=l.attr("lay-affix"),s="layui-input-suffix",o="layui-input-affix",e=l.is("[disabled]")||l.is("[readonly]"),c=function(e,t){(e=b(e))[0]&&e[b.trim(t)?"removeClass":"addClass"]($)},n=function(t){t=b.extend({},u[r]||{value:r},t,lay.options(l[0]));var i=b('
      '),e=b(''),a=(i.append(e),t.split&&i.addClass("layui-input-split"),l.next("."+o)),n=(a[0]&&a.remove(),l.next("."+s));n[0]?((a=n.find("."+o))[0]&&a.remove(),n.prepend(i),l.css("padding-right",function(){return(l.closest(".layui-input-group")[0]?0:n.outerWidth())+i.outerWidth()})):(i.addClass(s),l.after(i)),"auto"===t.show&&c(i,l.val()),l.on("input propertychange",function(){var e=this.value;"auto"===t.show&&c(i,e)}),e.on("click",function(){var e=l.attr("lay-filter");b(this).hasClass(q)||("function"==typeof t.click&&t.click.call(this,l,t),layui.event.call(this,w,"input-affix("+e+")",{elem:l[0],affix:r,options:t}))})},u={eye:{value:"eye-invisible",click:function(e,t){var i="LAY_FORM_INPUT_AFFIX_SHOW",a=e.data(i);e.attr("type",a?"password":"text").data(i,!a),n({value:a?"eye-invisible":"eye"})}},clear:{value:"clear",click:function(e){e.val("").focus(),c(b(this).parent(),null)},show:"auto",disabled:e}};n()})},select:function(e){var p,c="\u8bf7\u9009\u62e9",m="layui-form-select",g="layui-select-title",x="layui-select-none",k="",e=e||a.find("select"),C=function(e,t){b(e.target).parent().hasClass(g)&&!t||(b("."+m).removeClass(m+"ed "+m+"up"),p&&k&&p.val(k)),p=null},u=function(a,e,t){var s,r,i,n,o,l,c=b(this),u=a.find("."+g),d=u.find("input"),f=a.find("dl"),h=f.children("dd"),y=f.children("dt"),v=this.selectedIndex;e||(r=c.attr("lay-search"),i=function(){var e=a.offset().top+a.outerHeight()+5-F.scrollTop(),t=f.outerHeight();v=c[0].selectedIndex,a.addClass(m+"ed"),h.removeClass($),y.removeClass($),s=null,h.removeClass(T),0<=v&&h.eq(v).addClass(T),e+t>F.height()&&t<=e&&a.addClass(m+"up"),o()},n=function(e){a.removeClass(m+"ed "+m+"up"),d.blur(),s=null,e||l(d.val(),function(e){var t=c[0].selectedIndex;e&&(k=b(c[0].options[t]).html(),0===t&&k===d.attr("placeholder")&&(k=""),d.val(k||""))})},o=function(){var e,t,i=f.children("dd."+T);i[0]&&(e=i.position().top,t=f.height(),i=i.height(),t\u65e0\u5339\u914d\u9879

      '):f.find("."+x).remove()},"keyup"),""===t&&(c.val(""),f.find("."+T).removeClass(T),(c[0].options[0]||{}).value||f.children("dd:eq(0)").addClass(T),f.find("."+x).remove()),o()}).on("blur",function(e){var t=c[0].selectedIndex;p=d,k=b(c[0].options[t]).text(),0===t&&k===d.attr("placeholder")&&(k=""),setTimeout(function(){l(d.val(),function(e){k||d.val("")},"blur")},200)}),h.on("click",function(){var e=b(this),t=e.attr("lay-value"),i=c.attr("lay-filter");return e.hasClass(q)||(e.hasClass("layui-select-tips")?d.val(""):(d.val(e.text()),e.addClass(T)),e.siblings().removeClass(T),c.val(t).removeClass("layui-form-danger"),layui.event.call(this,w,"select("+i+")",{elem:c[0],value:t,othis:a}),n(!0)),!1}),a.find("dl>dt").on("click",function(e){return!1}),b(document).off("click",C).on("click",C))};e.each(function(e,t){var i=b(this),a=i.next("."+m),n=this.disabled,l=t.value,r=b(t.options[t.selectedIndex]),t=t.options[0];if("string"==typeof i.attr("lay-ignore"))return i.show();var s,o="string"==typeof i.attr("lay-search"),t=t&&!t.value&&t.innerHTML||c,r=b(['
      ','
      ','','
      ','
      ',(t=i.find("*"),s=[],layui.each(t,function(e,t){var i=t.tagName.toLowerCase();0!==e||t.value||"optgroup"===i?"optgroup"===i?s.push("
      "+t.label+"
      "):s.push('
      '+b.trim(t.innerHTML)+"
      "):s.push('
      '+b.trim(t.innerHTML||c)+"
      ")}),0===s.length&&s.push('
      \u6ca1\u6709\u9009\u9879
      '),s.join("")+"
      "),"
      "].join(""));a[0]&&a.remove(),i.after(r),u.call(this,r,n,o)})},checkbox:function(e){var o={checkbox:["layui-form-checkbox","layui-form-checked","checkbox"],"switch":["layui-form-switch","layui-form-onswitch","switch"],SUBTRA:"layui-icon-indeterminate"},e=e||a.find("input[type=checkbox]");e.each(function(e,t){var i=b(this),a=i.attr("lay-skin")||"primary",n=d.escape(b.trim(t.title||(t.title=i.attr("lay-text")||""))),l=this.disabled,r=o[a]||o.checkbox,s=i.next("."+r[0]);if(s[0]&&s.remove(),i.next("[lay-checkbox]")[0]&&(n=i.next().html()||""),n="switch"===a?n.split("|"):[n],"string"==typeof i.attr("lay-ignore"))return i.show();l=b(['
      ",(s={checkbox:[n[0]?"
      "+n[0]+"
      ":"primary"===a?"":"
      ",''].join(""),"switch":"
      "+((t.checked?n[0]:n[1])||"")+"
      "})[a]||s.checkbox,"
      "].join(""));i.after(l),function(a,n){var l=b(this);a.on("click",function(){var e=b(this),t=l.attr("lay-filter"),e=e.next("*[lay-checkbox]")[0]?e.next().html():l.attr("title")||"",i=l.attr("lay-skin")||"primary",e="switch"===i?e.split("|"):[e];l[0].disabled||(l[0].indeterminate&&(l[0].indeterminate=!1,a.find("."+o.SUBTRA).removeClass(o.SUBTRA).addClass("layui-icon-ok")),l[0].checked?(l[0].checked=!1,a.removeClass(n[1]),"switch"===i&&a.children("div").html(e[1])):(l[0].checked=!0,a.addClass(n[1]),"switch"===i&&a.children("div").html(e[0])),layui.event.call(l[0],w,n[2]+"("+t+")",{elem:l[0],value:l[0].value,othis:a}))})}.call(this,l,r)})},radio:function(e){var r="layui-form-radio",s=["layui-icon-radio","layui-icon-circle"],e=e||a.find("input[type=radio]");e.each(function(e,t){var i=b(this),a=i.next("."+r),n=this.disabled;if("string"==typeof i.attr("lay-ignore"))return i.show();a[0]&&a.remove();n=b(['
      ','',"
      "+(a=d.escape(t.title||""),a=i.next("[lay-radio]")[0]?i.next().html():a)+"
      ","
      "].join(""));i.after(n),function(a){var n=b(this),l="layui-anim-scaleSpring";a.on("click",function(){var e=n[0].name,t=n.parents(o),i=n.attr("lay-filter"),e=t.find("input[name="+e.replace(/(\.|#|\[|\])/g,"\\$1")+"]");n[0].disabled||(layui.each(e,function(){var e=b(this).next("."+r);this.checked=!1,e.removeClass(r+"ed"),e.find(".layui-icon").removeClass(l+" "+s[0]).addClass(s[1])}),n[0].checked=!0,a.addClass(r+"ed"),a.find(".layui-icon").addClass(l+" "+s[0]),layui.event.call(n[0],w,"radio("+i+")",{elem:n[0],value:n[0].value,othis:a}))})}.call(this,n)})}},t=function(){layui.each(n,function(e,t){t()})};return"object"===layui.type(e)?b(e).is(o)?(a=b(e),t()):e.each(function(e,t){var i=b(t);i.closest(o).length&&("SELECT"===t.tagName?n.select(i):"INPUT"===t.tagName&&("checkbox"===(t=t.type)||"radio"===t?n[t](i):n.input(i)))}):e?n[e]?n[e]():l.error('\u4e0d\u652f\u6301\u7684 "'+e+'" \u8868\u5355\u6e32\u67d3'):t(),this},t.prototype.validate=function(e){var u=null,d=this.config,f=d.verify,h="layui-form-danger";return!(e=b(e))[0]||(e.attr("lay-verify")!==undefined||!1!==this.validate(e.find("*[lay-verify]")))&&(layui.each(e,function(e,r){var s=b(this),t=(s.attr("lay-verify")||"").split("|"),o=s.attr("lay-vertype"),c=b.trim(s.val());if(s.removeClass(h),layui.each(t,function(e,t){var i="",a=f[t];if(a){var n="function"==typeof a?i=a(c,r):!a[0].test(c),l="select"===r.tagName.toLowerCase()||/^(checkbox|radio)$/.test(r.type),i=i||a[1];if("required"===t&&(i=s.attr("lay-reqtext")||i),n&&(d.verIncludelRequired||"required"===t||c&&"required"!==t))return"tips"===o?y.tips(i,"string"!=typeof s.attr("lay-ignore")&&l?s.next():s,{tips:1}):"alert"===o?y.alert(i,{title:"\u63d0\u793a",shadeClose:!0}):/\b(string|number)\b/.test(typeof i)&&y.msg(i,{icon:5,shift:6}),setTimeout(function(){(l?s.next().find("input"):r).focus()},7),s.addClass(h),u=!0}}),u)return u}),!u)},t.prototype.submit=function(e,t){var i=b(this),e="string"==typeof e?e:i.attr("lay-filter"),a=this.getFormElem?this.getFormElem(e):i.parents(o).eq(0),n=a.find("*[lay-verify]");if(!r.validate(n))return!1;n=r.getValue(null,a),a={elem:this.getFormElem?window.event&&window.event.target:this,form:(this.getFormElem?a:i.parents("form"))[0],field:n};return"function"==typeof t&&t(a),layui.event.call(this,w,"submit("+e+")",a)}),r=new t,t=b(document),F=b(window);b(function(){r.render()}),t.on("reset",o,function(){var e=b(this).attr("lay-filter");setTimeout(function(){r.render(null,e)},50)}),t.on("submit",o,i).on("click","*[lay-submit]",i),e(w,r)});layui.define(["lay","laytpl","laypage","form","util"],function(e){"use strict";var p=layui.$,c=layui.lay,m=layui.laytpl,O=layui.laypage,f=layui.layer,v=layui.form,g=layui.util,y=layui.hint(),b=layui.device(),x={config:{checkName:"LAY_CHECKED",indexName:"LAY_INDEX",numbersName:"LAY_NUM",disabledName:"LAY_DISABLED"},cache:{},index:layui.table?layui.table.index+1e4:0,set:function(e){var t=this;return t.config=p.extend({},t.config,e),t},on:function(e,t){return layui.onevent.call(this,T,e,t)}},k=function(){var a=this,e=a.config,i=e.id||e.index;return{config:e,reload:function(e,t){a.reload.call(a,e,t)},reloadData:function(e,t){x.reloadData(i,e,t)},setColsWidth:function(){a.setColsWidth.call(a)},resize:function(){a.resize.call(a)}}},C=function(e){var t=k.that[e];return t||y.error(e?"The table instance with ID '"+e+"' not found":"ID argument required"),t||null},l=function(e){var t=k.config[e];return t||y.error(e?"The table instance with ID '"+e+"' not found":"ID argument required"),t||null},w=function(e){var t=this.config||{},a=(e=e||{}).item3,i=e.content,t=(("escape"in a?a:t).escape&&(i=g.escape(i)),e.text&&a.exportTemplet||a.templet||a.toolbar);return t&&(i="function"==typeof t?t.call(a,e.tplData,e.obj):m(p(t).html()||String(i)).render(p.extend({LAY_COL:a},e.tplData))),e.text?p("
      "+i+"
      ").text():i},T="table",t=".layui-table",N="layui-hide",h="layui-hide-v",L="layui-none",R="layui-table-view",o=".layui-table-header",D=".layui-table-body",_=".layui-table-pageview",A=".layui-table-sort",E="layui-table-edit",W="layui-table-hover",j="laytable-cell-group",H="layui-table-col-special",M="layui-table-tool-panel",S="LAY_TABLE_MOVE_DICT",a=function(e){return['',"","{{# layui.each(d.data.cols, function(i1, item1){ }}","","{{# layui.each(item1, function(i2, item2){ }}",'{{# if(item2.fixed && item2.fixed !== "right"){ left = true; } }}','{{# if(item2.fixed === "right"){ right = true; } }}',(e=e||{}).fixed&&"right"!==e.fixed?'{{# if(item2.fixed && item2.fixed !== "right"){ }}':"right"===e.fixed?'{{# if(item2.fixed === "right"){ }}':"","{{# var isSort = !(item2.colGroup) && item2.sort; }}",'",e.fixed?"{{# }; }}":"","{{# }); }}","","{{# }); }}","","
      ','
      ','{{# if(item2.type === "checkbox"){ }}','',"{{# } else { }}",'{{-item2.title||""}}',"{{# if(isSort){ }}",'',"{{# } }}","{{# } }}","
      ","
      "].join("")},i=['',"","
      "].join(""),r=[,"{{# if(d.data.toolbar){ }}",'
      ','
      ','
      ',"
      ","{{# } }}",'
      ',"{{# if(d.data.loading){ }}",'
      ','',"
      ","{{# } }}","{{# var left, right; }}",'
      ',a(),"
      ",'
      ',i,"
      ","{{# if(left){ }}",'
      ','
      ',a({fixed:!0}),"
      ",'
      ',i,"
      ","
      ","{{# }; }}","{{# if(right){ }}",'
      ','
      ',a({fixed:"right"}),'
      ',"
      ",'
      ',i,"
      ","
      ","{{# }; }}","
      ","{{# if(d.data.totalRow){ }}",'
      ','','',"
      ","
      ","{{# } }}",'
      ','
      ',"
      ",""].join(""),I=p(window),F=p(document),n=function(e){this.index=++x.index,this.config=p.extend({},this.config,x.config,e),this.render()},d=(n.prototype.config={limit:10,loading:!0,escape:!0,cellMinWidth:60,cellMaxWidth:Number.MAX_VALUE,editTrigger:"click",defaultToolbar:["filter","exports","print"],defaultContextmenu:!0,autoSort:!0,text:{none:"\u65e0\u6570\u636e"},cols:[]},n.prototype.render=function(e){var t=this,a=t.config,i=(a.elem=p(a.elem),a.where=a.where||{},a.id="id"in a?a.id:a.elem.attr("id")||t.index);if(k.that[i]=t,(k.config[i]=a).request=p.extend({pageName:"page",limitName:"limit"},a.request),a.response=p.extend({statusName:"code",statusCode:0,msgName:"msg",dataName:"data",totalRowName:"totalRow",countName:"count"},a.response),null!==a.page&&"object"==typeof a.page&&(a.limit=a.page.limit||a.limit,a.limits=a.page.limits||a.limits,t.page=a.page.curr=a.page.curr||1,delete a.page.elem,delete a.page.jump),!a.elem[0])return t;if(a.elem.attr("lay-filter")||a.elem.attr("lay-filter",a.id),"reloadData"===e)return t.pullData(t.page,{type:"reloadData"});a.index=t.index,t.key=a.id||a.index,t.setInit(),a.height&&/^full-\d+$/.test(a.height)?(t.fullHeightGap=a.height.split("-")[1],a.height=I.height()-t.fullHeightGap):a.height&&/^#\w+\S*-\d+$/.test(a.height)&&(i=a.height.split("-"),t.parentHeightGap=i.pop(),t.parentDiv=i.join("-"),a.height=p(t.parentDiv).height()-t.parentHeightGap);var l,e=a.elem,i=e.next("."+R),n=t.elem=p("
      ");n.addClass((l=[R,R+"-"+t.index,"layui-form","layui-border-box"],a.className&&l.push(a.className),l.join(" "))).attr({"lay-filter":"LAY-TABLE-FORM-DF-"+t.index,"lay-id":a.id,style:(l=[],a.width&&l.push("width:"+a.width+"px;"),l.join(""))}).html(m(r,{open:"{{",close:"}}"}).render({data:a,index:t.index})),i[0]&&i.remove(),e.after(n),t.layTool=n.find(".layui-table-tool"),t.layBox=n.find(".layui-table-box"),t.layHeader=n.find(o),t.layMain=n.find(".layui-table-main"),t.layBody=n.find(D),t.layFixed=n.find(".layui-table-fixed"),t.layFixLeft=n.find(".layui-table-fixed-l"),t.layFixRight=n.find(".layui-table-fixed-r"),t.layTotal=n.find(".layui-table-total"),t.layPage=n.find(".layui-table-page"),t.renderToolbar(),t.renderPagebar(),t.fullSize(),t.pullData(t.page),t.events()},n.prototype.initOpts=function(e){this.config;e.checkbox&&(e.type="checkbox"),e.space&&(e.type="space"),e.type||(e.type="normal"),"normal"!==e.type&&(e.unresize=!0,e.width=e.width||{checkbox:50,radio:50,space:30,numbers:60}[e.type])},n.prototype.setInit=function(e){var l,a,d=this,c=d.config;if(c.clientWidth=c.width||(l=function(e){var t,a=(e=e||c.elem.parent()).width();try{t="none"===e.css("display")}catch(i){}return!e[0]||a&&!t?a:l(e.parent())})(),"width"===e)return c.clientWidth;c.height=c.maxHeight||c.height,c.css&&-1===c.css.indexOf(R)&&(a=c.css.split("}"),layui.each(a,function(e,t){t&&(a[e]="."+R+"-"+d.index+" "+t)}),c.css=a.join("}"));var r=function(a,e,i,l){var n,o;l?(l.key=[c.index,a,i].join("-"),l.colspan=l.colspan||0,l.rowspan=l.rowspan||0,d.initOpts(l),(n=a+(parseInt(l.rowspan)||1))
      ','
      ','
      '].join(""),a=this.layTool.find(".layui-table-tool-temp"),i=("default"===e.toolbar?a.html(t):"string"==typeof e.toolbar&&(t=p(e.toolbar).html()||"")&&a.html(m(t).render(e)),{filter:{title:"\u7b5b\u9009\u5217",layEvent:"LAYTABLE_COLS",icon:"layui-icon-cols"},exports:{title:"\u5bfc\u51fa",layEvent:"LAYTABLE_EXPORT",icon:"layui-icon-export"},print:{title:"\u6253\u5370",layEvent:"LAYTABLE_PRINT",icon:"layui-icon-print"}}),l=[];"object"==typeof e.defaultToolbar&&layui.each(e.defaultToolbar,function(e,t){t="string"==typeof t?i[t]:t;t&&l.push('
      ')}),this.layTool.find(".layui-table-tool-self").html(l.join(""))},n.prototype.renderPagebar=function(){var e,t=this.config,a=this.layPagebar=p('
      ');t.pagebar&&((e=p(t.pagebar).html()||"")&&a.append(m(e).render(t)),this.layPage.append(a))},n.prototype.setParentCol=function(e,t){var a=this.config,i=this.layHeader.find('th[data-key="'+t+'"]'),l=parseInt(i.attr("colspan"))||0;i[0]&&(t=t.split("-"),t=a.cols[t[1]][t[2]],e?l--:l++,i.attr("colspan",l),i[l?"removeClass":"addClass"](N),t.colspan2=l,t.hide=l<1,(a=i.data("parentkey"))&&this.setParentCol(e,a))},n.prototype.setColsPatch=function(){var a=this,e=a.config;layui.each(e.cols,function(e,t){layui.each(t,function(e,t){t.hide&&a.setParentCol(t.hide,t.parentKey)})})},n.prototype.setGroupWidth=function(i){var e,l=this;l.config.cols.length<=1||((e=l.layHeader.find((i?"th[data-key="+i.data("parentkey")+"]>":"")+"."+j)).css("width",0),layui.each(e.get().reverse(),function(){var e=p(this),t=e.parent().data("key"),a=0;l.layHeader.eq(0).find("th[data-parentkey="+t+"]").width(function(e,t){p(this).hasClass(N)||0 tr:first-child > th:last-child")).data("field")&&e.prev()[0]?t(e.prev()):e})()).data("key"),n.getCssRule(e,function(e){var t=e.style.width||a.outerWidth();e.style.width=parseFloat(t)+l+"px",0'+(e||"Error")+"
      ");a[0]&&(t.layNone.remove(),a.remove()),t.layFixed.addClass(N),t.layMain.find("tbody").html(""),t.layMain.append(t.layNone=e),t.layTotal.addClass(h),t.layPage.find(_).addClass(h),x.cache[t.key]=[],t.syncCheckAll(),t.renderForm(),t.setColsWidth()},n.prototype.page=1,n.prototype.pullData=function(t,a){var e,i,l=this,n=l.config,o=n.request,d=n.response,c=function(){"object"==typeof n.initSort&&l.sort({field:n.initSort.field,type:n.initSort.type,reloadType:a.type})},r=function(e){l.setColsWidth(),"function"==typeof n.done&&n.done(e,t,e[d.countName])};a=a||{},"function"==typeof n.before&&n.before(n),l.startTime=(new Date).getTime(),a.renderData?((e={})[d.dataName]=x.cache[l.key],e[d.countName]=n.url?"object"===layui.type(n.page)?n.page.count:e[d.dataName].length:n.data.length,"object"==typeof n.totalRow&&(e[d.totalRowName]=p.extend({},l.totalRow)),l.renderData({res:e,curr:t,count:e[d.countName],type:a.type}),c(),r(e)):n.url?(i={},n.page&&(i[o.pageName]=t,i[o.limitName]=n.limit),o=p.extend(i,n.where),n.contentType&&0==n.contentType.indexOf("application/json")&&(o=JSON.stringify(o)),l.loading(),p.ajax({type:n.method||"get",url:n.url,contentType:n.contentType,data:o,dataType:n.dataType||"json",jsonpCallback:n.jsonpCallback,headers:n.headers||{},success:function(e){(e="function"==typeof n.parseData?n.parseData(e)||e:e)[d.statusName]!=d.statusCode?l.errorView(e[d.msgName]||'\u8fd4\u56de\u7684\u6570\u636e\u4e0d\u7b26\u5408\u89c4\u8303\uff0c\u6b63\u786e\u7684\u6210\u529f\u72b6\u6001\u7801\u5e94\u4e3a\uff1a"'+d.statusName+'": '+d.statusCode):(l.totalRow=e[d.totalRowName],l.renderData({res:e,curr:t,count:e[d.countName],type:a.type}),c(),n.time=(new Date).getTime()-l.startTime+" ms"),r(e)},error:function(e,t){l.errorView("\u8bf7\u6c42\u5f02\u5e38\uff0c\u9519\u8bef\u63d0\u793a\uff1a"+t),"function"==typeof n.error&&n.error(e,t)}})):"array"===layui.type(n.data)&&(e={},i=t*n.limit-n.limit,o=n.data.concat(),e[d.dataName]=n.page?o.splice(i,n.limit):o,e[d.countName]=n.data.length,"object"==typeof n.totalRow&&(e[d.totalRowName]=p.extend({},n.totalRow)),l.totalRow=e[d.totalRowName],l.renderData({res:e,curr:t,count:e[d.countName],type:a.type}),c(),r(e))},n.prototype.eachCols=function(e){return x.eachCols(null,e,this.config.cols),this},n.prototype.col=function(e){try{return e=e.split("-"),this.config.cols[e[1]][e[2]]||{}}catch(t){return y.error(t),{}}},n.prototype.getTrHtml=function(t,a,l,e){var u=this,y=u.config,n=e&&e.trs||[],h=e&&e.trs_fixed||[],f=e&&e.trs_fixed_r||[];return l=l||1,layui.each(t,function(o,d){var i=[],c=[],r=[],s=o+y.limit*(l-1)+1;if("object"!=typeof d){t[o]=d={LAY_KEY:d};try{x.cache[u.key][o]=d}catch(e){}}"array"===layui.type(d)&&0===d.length||(d[x.config.numbersName]=s,a||(d[x.config.indexName]=o),u.eachCols(function(e,l){var t,e=l.field||e,a=l.key,n=d[e];n!==undefined&&null!==n||(n=""),l.colGroup||(t=['','
      "+function(){var e,t=p.extend(!0,{LAY_COL:l},d),a=x.config.checkName,i=x.config.disabledName;switch(l.type){case"checkbox":return'';case"radio":return t[a]&&(u.thisCheckedRowIndex=o),'';case"numbers":return s}return l.toolbar?m(p(l.toolbar).html()||"").render(t):w.call(u,{item3:l,content:n,tplData:t})}(),"
      "].join(""),i.push(t),l.fixed&&"right"!==l.fixed&&c.push(t),"right"===l.fixed&&r.push(t))}),n.push(''+i.join("")+""),h.push(''+c.join("")+""),f.push(''+r.join("")+""))}),{trs:n,trs_fixed:h,trs_fixed_r:f}},x.getTrHtml=function(e,t){e=C(e);return e.getTrHtml(t,null,e.page)},n.prototype.renderData=function(e){var a=this,i=a.config,t=e.res,l=e.curr,n=a.count=e.count,o=e.sort,d=t[i.response.dataName]||[],t=t[i.response.totalRowName],c=[],r=[],s=[],u=function(){if(i.HAS_SET_COLS_PATCH||a.setColsPatch(),i.HAS_SET_COLS_PATCH=!0,a.thisCheckedRowIndex="",!o&&a.sortKey)return a.sort({field:a.sortKey.field,type:a.sortKey.sort,pull:!0,reloadType:e.type});a.getTrHtml(d,o,l,{trs:c,trs_fixed:r,trs_fixed_r:s}),"fixed"===i.scrollPos&&"reloadData"===e.type||a.layBody.scrollTop(0),"reset"===i.scrollPos&&a.layBody.scrollLeft(0),a.layMain.find("."+L).remove(),a.layMain.find("tbody").html(c.join("")),a.layFixLeft.find("tbody").html(r.join("")),a.layFixRight.find("tbody").html(s.join("")),a.renderForm(),"number"==typeof a.thisCheckedRowIndex&&a.setRowChecked({type:"radio",index:a.thisCheckedRowIndex},!0),a.syncCheckAll(),a.fullSize(),a.haveInit?a.scrollPatch():setTimeout(function(){a.scrollPatch()},50),a.haveInit=!0,f.close(a.tipsIndex)};return x.cache[a.key]=d,a.layTotal[0==d.length?"addClass":"removeClass"](h),a.layPage[i.page||i.pagebar?"removeClass":"addClass"](N),a.layPage.find(_)[!i.page||0==n||0===d.length&&1==l?"addClass":"removeClass"](h),0===d.length?a.errorView(i.text.none):(a.layFixLeft.removeClass(N),o?u():(u(),a.renderTotal(d,t),a.layTotal&&a.layTotal.removeClass(N),void(i.page&&(i.page=p.extend({elem:"layui-table-page"+i.index,count:n,limit:i.limit,limits:i.limits||[10,20,30,40,50,60,70,80,90],groups:3,layout:["prev","page","next","skip","count","limit"],prev:'',next:'',jump:function(e,t){t||(a.page=e.curr,i.limit=e.limit,a.pullData(e.curr))}},i.page),i.page.count=n,O.render(i.page)))))},x.renderData=function(e){e=C(e);e&&e.pullData(e.page,{renderData:!0,type:"reloadData"})},n.prototype.renderTotal=function(e,o){var d,c=this,r=c.config,s={};r.totalRow&&(layui.each(e,function(e,i){"array"===layui.type(i)&&0===i.length||c.eachCols(function(e,t){var e=t.field||e,a=i[e];t.totalRow&&(s[e]=(s[e]||0)+(parseFloat(a)||0))})}),c.dataTotal=[],d=[],c.eachCols(function(e,t){var a,e=t.field||e,i=o&&o[t.field],l="totalRowDecimals"in t?t.totalRowDecimals:2,l=s[e]?parseFloat(s[e]||0).toFixed(l):"",l=(a=t.totalRowText||"",(n={LAY_COL:t})[e]=l,n=t.totalRow&&w.call(c,{item3:t,content:l,tplData:n})||a,i||n),n=(t.field&&c.dataTotal.push({field:t.field,total:p("
      "+l+"
      ").text()}),['','
      "+("string"==typeof(a=t.totalRow||r.totalRow)?m(a).render(p.extend({TOTAL_NUMS:i||s[e],TOTAL_ROW:o||{},LAY_COL:t},t)):l),"
      "].join(""));d.push(n)}),e=c.layTotal.find(".layui-table-patch"),c.layTotal.find("tbody").html(""+d.join("")+(e.length?e.get(0).outerHTML:"")+""))},n.prototype.getColElem=function(e,t){this.config;return e.eq(0).find(".laytable-cell-"+t+":eq(0)")},n.prototype.renderForm=function(e){this.config;var t=this.elem.attr("lay-filter");v.render(e,t)},n.prototype.setRowChecked=function(a,e){var t,i,l=this,n=l.config,o="layui-table-click",d=l.layBody.find("tr"+("all"===a.index?"":'[data-index="'+a.index+'"]'));"all"!==(a=p.extend({type:"checkbox"},a)).index&&d.addClass(o).siblings("tr").removeClass(o),a.selectedStyle||e||(o=x.cache[l.key],t="checked"in a,i=function(e){return"radio"===a.type||(t?a.checked:!e)},layui.each(o,function(e,t){a.index===e||"all"===a.index?t[n.checkName]=i(t[n.checkName]):"radio"===a.type&&delete t[n.checkName]}),(e=d.find('input[lay-type="'+({radio:"layTableRadio",checkbox:"layTableCheckbox"}[a.type]||"checkbox")+'"]')).prop("checked",i(e.last().prop("checked"))),l.syncCheckAll(),l.renderForm(a.type))},n.prototype.sort=function(l){var e,t=this,a={},i=t.config,n=i.elem.attr("lay-filter"),o=x.cache[t.key];"string"==typeof(l=l||{}).field&&(d=l.field,t.layHeader.find("th").each(function(e,t){var a=p(this),i=a.data("field");if(i===l.field)return l.field=a,d=i,!1}));try{var d=d||l.field.data("field"),c=l.field.data("key");if(t.sortKey&&!l.pull&&d===t.sortKey.field&&l.type===t.sortKey.sort)return;var r=t.layHeader.find("th .laytable-cell-"+c).find(A);t.layHeader.find("th").find(A).removeAttr("lay-sort"),r.attr("lay-sort",l.type||null),t.layFixed.find("th")}catch(s){y.error("Table modules: sort field '"+d+"' not matched")}t.sortKey={field:d,sort:l.type},i.autoSort&&("asc"===l.type?e=layui.sort(o,d,null,!0):"desc"===l.type?e=layui.sort(o,d,!0,!0):(e=layui.sort(o,x.config.indexName,null,!0),delete t.sortKey,delete i.initSort)),a[i.response.dataName]=e||o,t.renderData({res:a,curr:t.page,count:t.count,sort:!0,type:l.reloadType}),l.fromEvent&&(i.initSort={field:d,type:l.type},layui.event.call(l.field,T,"sort("+n+")",p.extend({config:i},i.initSort)))},n.prototype.loading=function(e){var t=this;t.config.loading&&(e?(t.layInit&&t.layInit.remove(),delete t.layInit,t.layBox.find(".layui-table-init").remove()):(t.layInit=p(['
      ','',"
      "].join("")),t.layBox.append(t.layInit)))},n.prototype.setCheckData=function(a,i,l){var n=this.config,e=x.cache[this.key];e[a]&&"array"!==layui.type(e[a])&&layui.each(e,function(e,t){a===e?t[n.checkName]=i:l&&delete t[n.checkName]})},n.prototype.syncCheckAll=function(){var e=this,i=e.config,t=e.layHeader.find('input[name="layTableCheckbox"]'),a=function(a){return e.eachCols(function(e,t){"checkbox"===t.type&&(t[i.checkName]=a)}),a};t[0]&&(x.checkStatus(e.key).isAll?(t[0].checked||(t.prop("checked",!0),e.renderForm("checkbox")),a(!0)):(t[0].checked&&(t.prop("checked",!1),e.renderForm("checkbox")),a(!1)))},n.prototype.getCssRule=function(a,i){var e=this.elem.find("style")[0],e=e.sheet||e.styleSheet||{},e=e.cssRules||e.rules;layui.each(e,function(e,t){if(t.selectorText===".laytable-cell-"+a)return i(t),!0})},n.prototype.fullSize=function(){var e,a,i=this,t=i.config,l=t.height;i.fullHeightGap?(l=I.height()-i.fullHeightGap)<135&&(l=135):i.parentDiv&&i.parentHeightGap&&(l=p(i.parentDiv).height()-i.parentHeightGap)<135&&(l=135),1
      ')).find("div").css({width:a}),e.find("tr").append(t)):e.find(".layui-table-patch").remove()};n(e.layHeader),n(e.layTotal);n=e.layMain.height()-i;e.layFixed.find(D).css("height",t.height()>=n?n:"auto"),e.layFixRight[x.cache[e.key]&&x.cache[e.key].length&&0');a.html(t),u.height&&a.css("max-height",u.height-(s.layTool.outerHeight()||50)),i.find("."+M)[0]||i.append(a),s.renderForm(),a.on("click",function(e){layui.stope(e)}),e.done&&e.done(a,t)};switch(layui.stope(e),F.trigger("table.tool.panel.remove"),f.close(s.tipsIndex),t){case"LAYTABLE_COLS":l({list:(a=[],s.eachCols(function(e,t){t.field&&"normal"==t.type&&a.push('
    • "+(t.fieldTitle||t.title||t.field)+"
    • ").text())+'" lay-filter="LAY_TABLE_TOOL_COLS">')}),a.join("")),done:function(){v.on("checkbox(LAY_TABLE_TOOL_COLS)",function(e){var e=p(e.elem),t=this.checked,a=e.data("key"),i=s.col(a),l=i.hide,e=e.data("parentkey");i.key&&(i.hide=!t,s.elem.find('*[data-key="'+a+'"]')[t?"removeClass":"addClass"](N),l!=i.hide&&s.setParentCol(!t,e),s.resize(),layui.event.call(this,T,"colToggled("+c+")",{col:i,config:u}))})}});break;case"LAYTABLE_EXPORT":b.ie?f.tips("\u5bfc\u51fa\u529f\u80fd\u4e0d\u652f\u6301 IE\uff0c\u8bf7\u7528 Chrome \u7b49\u9ad8\u7ea7\u6d4f\u89c8\u5668\u5bfc\u51fa",this,{tips:3}):l({list:['
    • \u5bfc\u51fa csv \u683c\u5f0f\u6587\u4ef6
    • ','
    • \u5bfc\u51fa xls \u683c\u5f0f\u6587\u4ef6
    • '].join(""),done:function(e,t){t.on("click",function(){var e=p(this).data("type");x.exportFile.call(s,u.id,null,e)})}});break;case"LAYTABLE_PRINT":var n=window.open("about:blank","_blank"),o=[""].join(""),d=p(s.layHeader.html());d.append(s.layMain.find("table").html()),d.append(s.layTotal.find("table").html()),d.find("th.layui-table-patch").remove(),d.find("thead>tr>th."+H).filter(function(e,t){return!p(t).children("."+j).length}).remove(),d.find("tbody>tr>td."+H).remove(),n.document.write(o+d.prop("outerHTML")),n.document.close(),layui.device("edg").edg?(n.onafterprint=n.close,n.print()):(n.print(),n.close())}layui.event.call(this,T,"toolbar("+c+")",p.extend({event:t,config:u},{}))}),s.layPagebar.on("click","*[lay-event]",function(e){var t=p(this).attr("lay-event");layui.event.call(this,T,"pagebar("+c+")",p.extend({event:t,config:u},{}))}),e.on("mousemove",function(e){var t=p(this),a=t.offset().left,e=e.clientX-a;t.data("unresize")||k.eventMoveElem||(d.allowResize=t.width()-e<=10,o.css("cursor",d.allowResize?"col-resize":""))}).on("mouseleave",function(){p(this);k.eventMoveElem||o.css("cursor","")}).on("mousedown",function(e){var t,a=p(this);d.allowResize&&(t=a.data("key"),e.preventDefault(),d.offset=[e.clientX,e.clientY],s.getCssRule(t,function(e){var t=e.style.width||a.outerWidth();d.rule=e,d.ruleWidth=parseFloat(t),d.minWidth=a.data("minwidth")||u.cellMinWidth,d.maxWidth=a.data("maxwidth")||u.cellMaxWidth}),a.data(S,d),k.eventMoveElem=a)}),k.docEvent||F.on("mousemove",function(e){var t,a;k.eventMoveElem&&(t=k.eventMoveElem.data(S)||{},k.eventMoveElem.data("resizing",1),e.preventDefault(),t.rule&&(e=t.ruleWidth+e.clientX-t.offset[0],a=k.eventMoveElem.closest("."+R).attr("lay-id"),(a=C(a))&&((e=et.maxWidth&&(e=t.maxWidth),t.rule.style.width=e+"px",a.setGroupWidth(k.eventMoveElem),f.close(s.tipsIndex))))}).on("mouseup",function(e){var t,a,i,l,n;k.eventMoveElem&&(i=(t=k.eventMoveElem).closest("."+R).attr("lay-id"),(a=C(i))&&(i=t.data("key"),l=a.col(i),n=a.config.elem.attr("lay-filter"),d={},o.css("cursor",""),a.scrollPatch(),t.removeData(S),delete k.eventMoveElem,a.getCssRule(i,function(e){l.width=parseFloat(e.style.width),layui.event.call(t[0],T,"colResized("+n+")",{col:l,config:a.config})})))}),k.docEvent=!0,e.on("click",function(e){var t=p(this),a=t.find(A),i=a.attr("lay-sort");if(!a[0]||1===t.data("resizing"))return t.removeData("resizing");s.sort({field:t,type:"asc"===i?"desc":"desc"===i?null:"asc",fromEvent:!0})}).find(A+" .layui-edge ").on("click",function(e){var t=p(this),a=t.index(),t=t.parents("th").eq(0).data("field");layui.stope(e),0===a?s.sort({field:t,type:"asc",fromEvent:!0}):s.sort({field:t,type:"desc",fromEvent:!0})}),s.commonMember=function(e){var t=p(this).parents("tr").eq(0).data("index"),c=s.layBody.find('tr[data-index="'+t+'"]'),r=(r=x.cache[s.key]||[])[t]||{},a={tr:c,config:u,data:x.clearCacheKey(r),index:t,del:function(){x.cache[s.key][t]=[],c.remove(),s.scrollPatch()},update:function(e,d){e=e||{},layui.each(e,function(i,l){var n=c.children('td[data-field="'+i+'"]'),o=n.children(y);r[i]=a.data[i]=l,s.eachCols(function(e,t){var a;t.field==i?(o.html(w.call(s,{item3:t,content:l,tplData:p.extend({LAY_COL:t},r)})),n.data("content",l)):d&&(t.templet||t.toolbar)&&(e=c.children('td[data-field="'+(t.field||e)+'"]'),a=r[t.field],e.children(y).html(w.call(s,{item3:t,content:a,tplData:p.extend({LAY_COL:t},r)})),e.data("content",a))})}),s.renderForm()},setRowChecked:function(e){s.setRowChecked(p.extend({index:t},e))}};return p.extend(a,e)}),i=(s.elem.on("click",'input[name="layTableCheckbox"]+',function(e){var t=p(this),a=t.closest("td"),t=t.prev(),i=s.layBody.find('input[name="layTableCheckbox"]'),l=t.parents("tr").eq(0).data("index"),n=t[0].checked,o="layTableAllChoose"===t.attr("lay-filter");t[0].disabled||(o?(i.each(function(e,t){t.checked=n,s.setCheckData(e,n)}),s.syncCheckAll(),s.renderForm("checkbox")):(s.setCheckData(l,n),s.syncCheckAll(),layui.stope(e)),layui.event.call(t[0],T,"checkbox("+c+")",r.call(t[0],{checked:n,type:o?"all":"one",getCol:function(){return s.col(a.data("key"))}})))}),s.elem.on("click",'input[lay-type="layTableRadio"]+',function(e){var t=p(this),a=t.closest("td"),t=t.prev(),i=t[0].checked,l=t.parents("tr").eq(0).data("index");if(layui.stope(e),t[0].disabled)return!1;s.setCheckData(l,i,"radio"),s.setRowChecked({type:"radio",index:l},!0),layui.event.call(t[0],T,"radio("+c+")",r.call(t[0],{checked:i,getCol:function(){return s.col(a.data("key"))}}))}),s.layBody.on("mouseenter","tr",function(){var e=p(this),t=e.index();e.data("off")||s.layBody.find("tr:eq("+t+")").addClass(W)}).on("mouseleave","tr",function(){var e=p(this),t=e.index();e.data("off")||s.layBody.find("tr:eq("+t+")").removeClass(W)}).on("click","tr",function(e){var t=".layui-form-checkbox,.layui-form-radio,[lay-unrow]",a=p(this).find(t);p(e.target).is(t)||a[0]&&p.contains(a[0],e.target)||i.call(this,"row")}).on("dblclick","tr",function(){i.call(this,"rowDouble")}).on("contextmenu","tr",function(e){u.defaultContextmenu||e.preventDefault(),i.call(this,"rowContextmenu")}),function(e){var t=p(this);t.data("off")||layui.event.call(this,T,e+"("+c+")",r.call(t.children("td")[0]))}),n=function(e,t){var a,i,l,n;(e=p(e)).data("off")||(a=e.data("field"),n=e.data("key"),n=s.col(n),i=e.closest("tr").data("index"),i=x.cache[s.key][i],l=e.children(y),(n="function"==typeof n.edit?n.edit(i):n.edit)&&((n=p("textarea"===n?'':''))[0].value=e.data("content")||i[a]||l.text(),e.find("."+E)[0]||e.append(n),n.focus(),t&&layui.stope(t)))},l=(s.layBody.on("change","."+E,function(){var e=p(this),t=e.parent(),a=this.value,i=e.parent().data("field"),e=e.closest("tr").data("index"),e=x.cache[s.key][e],l=r.call(t[0],{value:a,field:i,oldValue:e[i],td:t,reedit:function(){setTimeout(function(){n(l.td);var e={};e[i]=l.oldValue,l.update(e)})},getCol:function(){return s.col(t.data("key"))}}),e={};e[i]=a,l.update(e),layui.event.call(t[0],T,"edit("+c+")",l)}).on("blur","."+E,function(){p(this).remove()}),s.layBody.on(u.editTrigger,"td",function(e){n(this,e)}).on("mouseenter","td",function(){t.call(this)}).on("mouseleave","td",function(){t.call(this,"hide")}),s.layTotal.on("mouseenter","td",function(){t.call(this)}).on("mouseleave","td",function(){t.call(this,"hide")}),"layui-table-grid-down"),t=function(e){var t=p(this),a=t.children(y);t.data("off")||(e?t.find(".layui-table-grid-down").remove():!(a.prop("scrollWidth")>a.outerWidth()||0'))},a=function(e){var t=p(this).parent().children(y);s.tipsIndex=f.tips(['
      ',t.html(),"
      ",''].join(""),t[0],{tips:[3,""],time:-1,anim:-1,maxWidth:b.ios||b.android?300:s.elem.width()/2,isOutAnim:!1,skin:"layui-table-tips",success:function(e,t){e.find(".layui-table-tips-c").on("click",function(){f.close(t)})}}),layui.stope(e)},h=(s.layBody.on("click","."+l,function(e){a.call(this,e)}),s.layTotal.on("click","."+l,function(e){a.call(this,e)}),function(e){var t=p(this),a=t.closest("td"),i=t.parents("tr").eq(0).data("index");layui.event.call(this,T,(e||"tool")+"("+c+")",r.call(this,{event:t.attr("lay-event"),getCol:function(){return s.col(a.data("key"))}})),s.setRowChecked({type:"radio",index:i},!0)});s.layBody.on("click","*[lay-event]",function(e){h.call(this),layui.stope(e)}).on("dblclick","*[lay-event]",function(e){h.call(this,"toolDouble"),layui.stope(e)}),s.layMain.on("scroll",function(){var e=p(this),t=e.scrollLeft(),e=e.scrollTop();s.layHeader.scrollLeft(t),s.layTotal.scrollLeft(t),s.layFixed.find(D).scrollTop(e),f.close(s.tipsIndex)}),I.on("resize",function(){s.resize()})},F.on("click",function(){F.trigger("table.remove.tool.panel")}),F.on("table.remove.tool.panel",function(){p("."+M).remove()}),x.init=function(i,o){o=o||{};var e="object"==typeof i?i:p("string"==typeof i?'table[lay-filter="'+i+'"]':t+"[lay-data], "+t+"[lay-options]"),d="Table element property lay-data configuration item has a syntax error: ";return e.each(function(){var l,e=p(this),t=e.attr("lay-data"),t=c.options(this,{attr:t?"lay-data":null,errorText:d+(t||e.attr("lay-options"))}),n=p.extend({elem:this,cols:[],data:[],skin:e.attr("lay-skin"),size:e.attr("lay-size"),even:"string"==typeof e.attr("lay-even")},x.config,o,t),a=(i&&e.hide(),e.find("thead>tr").each(function(i){n.cols[i]=[],p(this).children().each(function(e){var t=p(this),a=t.attr("lay-data"),a=c.options(this,{attr:a?"lay-data":null,errorText:d+(a||t.attr("lay-options"))}),t=p.extend({title:t.text(),colspan:parseInt(t.attr("colspan"))||0,rowspan:parseInt(t.attr("rowspan"))||0},a);n.cols[i].push(t)})}),e.find("tbody>tr")),t=x.render(n);!a.length||o.data||t.config.url||(l=0,x.eachCols(t.config.id,function(e,i){a.each(function(e){n.data[e]=n.data[e]||{};var t=p(this),a=i.field;n.data[e][a]=t.children("td").eq(l).html()}),l++}),t.reloadData({data:n.data}))}),this},k.that={},k.config={},function(a,i,e,l){var n,o;l.colGroup&&(n=0,a++,l.CHILD_COLS=[],o=e+(parseInt(l.rowspan)||1),layui.each(i[o],function(e,t){t.parentKey?t.parentKey===l.key&&(t.PARENT_COL_INDEX=a,l.CHILD_COLS.push(t),d(a,i,o,t)):t.PARENT_COL_INDEX||1<=n&&n==(l.colspan||1)||(t.PARENT_COL_INDEX=a,l.CHILD_COLS.push(t),n+=parseInt(1td').filter('[data-field="'+e+'"]')}}})).replace(/"/g,'""'),n.push(a='"'+a+'"')))}),d.push(n.join(","))}),r&&layui.each(r.dataTotal,function(e,t){c[t.field]||i.push(t.total+"\t")}),o.join(",")+"\r\n"+d.join("\r\n")+"\r\n"+i.join(","))),u.download=(a.title||n.title||"table_"+(n.index||""))+"."+l,document.body.appendChild(u),u.click(),document.body.removeChild(u)},x.getOptions=l,x.hideCol=function(e,l){var n=C(e);n&&("boolean"===layui.type(l)?n.eachCols(function(e,t){var a=t.key,i=n.col(a),t=t.parentKey;i.hide!=l&&(i=i.hide=l,n.elem.find('*[data-key="'+a+'"]')[i?"addClass":"removeClass"](N),n.setParentCol(i,t))}):(l=layui.isArray(l)?l:[l],layui.each(l,function(e,l){n.eachCols(function(e,t){var a,i;l.field===t.field&&(a=t.key,i=n.col(a),t=t.parentKey,"hide"in l&&i.hide!=l.hide&&(i=i.hide=!!l.hide,n.elem.find('*[data-key="'+a+'"]')[i?"addClass":"removeClass"](N),n.setParentCol(i,t)))})})),p("."+M).remove(),n.resize())},x.reload=function(e,t,a,i){if(l(e))return e=C(e),e.reload(t,a,i),k.call(e)},x.reloadData=function(){var a=p.extend([],arguments),i=(a[3]="reloadData",new RegExp("^("+["elem","id","cols","width","height","maxHeight","toolbar","defaultToolbar","className","css","totalRow","pagebar"].join("|")+")$"));return layui.each(a[1],function(e,t){i.test(e)&&delete a[1][e]}),x.reload.apply(null,a)},x.render=function(e){e=new n(e);return k.call(e)},x.clearCacheKey=function(e){return delete(e=p.extend({},e))[x.config.checkName],delete e[x.config.indexName],delete e[x.config.numbersName],delete e[x.config.disabledName],e},p(function(){x.init()}),e(T,x)});layui.define(["table"],function(e){"use strict";var B=layui.$,x=layui.form,j=layui.table,y=layui.hint(),P={config:{},on:j.on,eachCols:j.eachCols,index:j.index,set:function(e){var t=this;return t.config=B.extend({},t.config,e),t},resize:j.resize,getOptions:j.getOptions,hideCol:j.hideCol,renderData:j.renderData},i=function(){var a=this,e=a.config,n=e.id||e.index;return{config:e,reload:function(e,t){a.reload.call(a,e,t)},reloadData:function(e,t){P.reloadData(n,e,t)}}},F=function(e){var t=i.that[e];return t||y.error(e?"The treeTable instance with ID '"+e+"' not found":"ID argument required"),t||null},q="layui-hide",L=".layui-table-main",Y=".layui-table-fixed-l",R=".layui-table-fixed-r",h="layui-table-tree",H="LAY_DATA_INDEX",m="LAY_DATA_INDEX_HISTORY",f="LAY_PARENT_INDEX",b="LAY_CHECKBOX_HALF",X="LAY_EXPAND",z="LAY_HAS_EXPANDED",V="LAY_ASYNC_STATUS",t=function(e){var t=this;t.index=++P.index,t.config=B.extend(!0,{},t.config,P.config,e),t.init(),t.render()},u=function(n,i,e){var l=j.cache[n];layui.each(e||l,function(e,t){var a=t[H];-1!==a.indexOf("-")&&(l[a]=t),t[i]&&u(n,i,t[i])})},l=function(i,a,e){var l=F(i),t=("reloadData"!==e&&(l.status={expand:{}}),B.extend(!0,{},l.getOptions(),a)),n=t.tree,r=n.customName.children,d=n.customName.id,o=(delete a.hasNumberCol,delete a.hasChecboxCol,delete a.hasRadioCol,j.eachCols(null,function(e,t){"numbers"===t.type?a.hasNumberCol=!0:"checkbox"===t.type?a.hasChecboxCol=!0:"radio"===t.type&&(a.hasRadioCol=!0)},t.cols),a.parseData),c=a.done;t.url?e&&(!o||o.mod)||(a.parseData=function(){var e=this,t=arguments,a=t[0],t=("function"===layui.type(o)&&(a=o.apply(e,t)||t[0]),e.response.dataName);return n.data.isSimpleData&&!n["async"].enable&&(a[t]=l.flatToTree(a[t])),s(a[t],function(e){e[X]=X in e?e[X]:e[d]!==undefined&&l.status.expand[e[d]]},r),e.autoSort&&e.initSort&&e.initSort.type&&layui.sort(a[t],e.initSort.field,"desc"===e.initSort.type,!0),l.initData(a[t]),a},a.parseData.mod=!0):(a.data=a.data||[],n.data.isSimpleData&&(a.data=l.flatToTree(a.data)),a.initSort&&a.initSort.type&&layui.sort(a.data,a.initSort.field,"desc"===a.initSort.type,!0),l.initData(a.data)),e&&(!c||c.mod)||(a.done=function(){var e,t=arguments,a=this.elem.next(),n=(l.updateStatus(null,{LAY_HAS_EXPANDED:!1}),u(i,r),a.find('[name="layTableCheckbox"][lay-filter="layTableAllChoose"]'));if(n.length&&(e=P.checkStatus(i),n.prop({checked:e.isAll&&e.data.length,indeterminate:!e.isAll&&e.data.length})),l.renderTreeTable(a),"function"===layui.type(c))return c.apply(this,t)},a.done.mod=!0)};t.prototype.init=function(){var e=this.config,t=j.render(B.extend({},e,{data:[],url:"",done:null})),a=t.config.id;(i.that[a]=this).tableIns=t,l(a,e)},t.prototype.config={tree:{customName:{children:"children",isParent:"isParent",name:"name",id:"id",pid:"parentId",icon:"icon"},view:{indent:14,flexIconClose:'',flexIconOpen:'',showIcon:!0,icon:"",iconClose:'',iconOpen:'',iconLeaf:'',showFlexIconIfNotParent:!1,dblClickExpand:!0},data:{isSimpleData:!1,rootPid:null},"async":{enable:!1,url:"",type:null,contentType:null,headers:null,where:null,autoParam:[]},callback:{beforeExpand:null,onExpand:null}}},t.prototype.getOptions=function(){return this.tableIns?j.getOptions(this.tableIns.config.id):this.config},t.prototype.flatToTree=function(e){var a,n,i,t,l,r,d,o=this.getOptions(),c=o.tree,u=c.customName,o=o.id;return e=e||j.cache[o],o=e,a=u.id,n=u.pid,i=u.children,t=c.data.rootPid,a=a||"id",n=n||"parentId",i=i||"children",d={},layui.each(o,function(e,t){l=a+t[a],d[l]=B.extend({},t),d[l][i]=[]}),layui.each(d,function(e,t){(r=a+t[n])&&d[r]&&d[r][i].push(t)}),Object.values(d).filter(function(e){return t?e[n]===t:!e[n]})},t.prototype.treeToFlat=function(e,n,i){var l=this,r=l.getOptions().tree.customName,d=r.children,o=r.pid,c=[];return layui.each(e,function(e,t){var e=(i?i+"-":"")+e,a=B.extend({},t);a[d]=null,a[o]=t[o]||n,c.push(a),c=c.concat(l.treeToFlat(t[d],t[r.id],e))}),c},t.prototype.getTreeNode=function(e){var t=this;if(!e)return y.error("\u627e\u4e0d\u5230\u8282\u70b9\u6570\u636e");var a=t.getOptions(),n=a.tree;a.id,n.customName;return{data:e,dataIndex:e[H],getParentNode:function(){return t.getNodeByIndex(e[f])}}},t.prototype.getNodeByIndex=function(t){var e=this,a=e.getNodeDataByIndex(t);if(!a)return y.error("\u627e\u4e0d\u5230\u8282\u70b9\u6570\u636e");var n=e.getOptions(),i=(n.tree.customName.parent,n.id),n={data:a,dataIndex:a[H],getParentNode:function(){return e.getNodeByIndex(a[f])},update:function(e){return P.updateNode(i,t,e)},remove:function(){return P.removeNode(i,t)},expand:function(e){return P.expandNode(i,B.extend({},e,{index:t}))},setChecked:function(e){return P.setRowChecked(i,B.extend({},e,{index:t}))}};return n.dataIndex=t,n},t.prototype.getNodeById=function(a){var e=this.getOptions(),n=e.tree.customName.id,i="",e=P.getData(e.id,!0);if(layui.each(e,function(e,t){if(t[n]===a)return i=t[H],!0}),i)return this.getNodeByIndex(i)},t.prototype.getNodeDataByIndex=function(a,e,t){var n=this.getOptions(),i=n.tree,l=n.id,r=j.cache[l][a];if("delete"!==t&&r)return B.extend(r,t),e?B.extend({},r):r;for(var r=this.getTableData(),d=(a+="").split("-"),o=r,c=n.url||1');var D=function(e){y[V]="success",y[f.children]=e,c.initData(y[f.children],y[H]),J(t,!0,!p&&n,i,l)},T=b.format;if("function"===layui.type(T))return T(y,o,D),h;var _=B.extend({},b.where||o.where),T=b.autoParam,T=(layui.each(T,function(e,t){t=t.split("=");_[t[0].trim()]=y[(t[1]||t[0]).trim()]}),b.contentType||o.contentType),k=(T&&0==T.indexOf("application/json")&&(_=JSON.stringify(_)),b.method||o.method),S=b.dataType||o.dataType,O=b.jsonpCallback||o.jsonpCallback,w=b.headers||o.headers,A=b.parseData||o.parseData,E=b.response||o.response;return B.ajax({type:k||"get",url:C,contentType:T,data:_,dataType:S||"json",jsonpCallback:O,headers:w||{},success:function(e){(e="function"==typeof A?A.call(o,e)||e:e)[E.statusName]!=E.statusCode?(y[V]="error",g.html('')):D(e[E.dataName])},error:function(e,t){y[V]="error","function"==typeof o.error&&o.error(e,t)}}),h}m=y[z]=!0,v.length&&(!o.initSort||o.url&&!o.autoSort||((b=o.initSort).type?layui.sort(v,b.field,"desc"===b.type,!0):layui.sort(v,j.config.indexName,null,!0)),c.initData(y[f.children],y[H]),k=j.getTrHtml(d,v,null,null,e),N={trs:B(k.trs.join("")),trs_fixed:B(k.trs_fixed.join("")),trs_fixed_r:B(k.trs_fixed_r.join(""))},I=(e.split("-").length-1||0)+1,layui.each(v,function(e,t){N.trs.eq(e).attr({"data-index":t[H],"lay-data-index":t[H],"data-level":I}),N.trs_fixed.eq(e).attr({"data-index":t[H],"lay-data-index":t[H],"data-level":I}),N.trs_fixed_r.eq(e).attr({"data-index":t[H],"lay-data-index":t[H],"data-level":I})}),r.find(L).find('tbody tr[lay-data-index="'+e+'"]').after(N.trs),r.find(Y).find('tbody tr[lay-data-index="'+e+'"]').after(N.trs_fixed),r.find(R).find('tbody tr[lay-data-index="'+e+'"]').after(N.trs_fixed_r),c.renderTreeTable(N.trs,I),n&&!p&&layui.each(v,function(e,t){J({dataIndex:t[H],trElem:r.find('tr[lay-data-index="'+t[H]+'"]').first(),tableViewElem:r,tableId:d,options:o},a,n,i,l)}))}else n&&!p?(layui.each(v,function(e,t){J({dataIndex:t[H],trElem:r.find('tr[lay-data-index="'+t[H]+'"]').first(),tableViewElem:r,tableId:d,options:o},a,n,i,l)}),r.find(v.map(function(e,t,a){return'tr[lay-data-index="'+e[H]+'"]'}).join(",")).addClass(q)):(C=c.treeToFlat(v,y[f.id],e),r.find(C.map(function(e,t,a){return'tr[lay-data-index="'+e[H]+'"]'}).join(",")).addClass(q));return U("resize-"+d,function(){P.resize(d)},0)(),l&&"loading"!==y[V]&&(T=u.callback.onExpand,"function"===layui.type(T)&&T(d,y,x)),h},g=(P.expandNode=function(e,t){var a,n,i,e=F(e);if(e)return a=(t=t||{}).index,n=t.expandFlag,i=t.inherit,t=t.callbackFlag,e=e.getOptions().elem.next(),J({trElem:e.find('tr[lay-data-index="'+a+'"]').first()},n,i,null,t)},P.expandAll=function(a,e){if("boolean"!==layui.type(e))return y.error("expandAll \u7684\u5c55\u5f00\u72b6\u6001\u53c2\u6570\u53ea\u63a5\u6536true/false");var t=F(a);if(t){var n=t.getOptions(),i=n.tree,l=n.elem.next(),r=i.customName.isParent,d=i.customName.id,o=i.view.showFlexIconIfNotParent;if(e){e=P.getData(a,!0);if(i["async"].enable){var c=!0;if(layui.each(e,function(e,t){if(t[r]&&!t[V])return!(c=!1)}),!c)return void layui.each(P.getData(a),function(e,t){P.expandNode(a,{index:t[H],expandFlag:!0,inherit:!0})})}var u=!0;if(layui.each(e,function(e,t){if(t[r]&&!t[z])return!(u=!1)}),u)t.updateStatus(null,function(e){(e[r]||o)&&(e[X]=!0,e[d]!==undefined&&(t.status.expand[e[d]]=!0))}),l.find('tbody tr[data-level!="0"]').removeClass(q),l.find(".layui-table-tree-flexIcon").html(i.view.flexIconOpen),i.view.showIcon&&l.find(".layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)").html(i.view.iconOpen);else{if(t.updateStatus(null,function(e){(e[r]||o)&&(e[X]=!0,e[z]=!0,e[d]!==undefined&&(t.status.expand[e[d]]=!0))}),n.initSort&&n.initSort.type&&(!n.url||n.autoSort))return P.sort(a);var f,n=j.getTrHtml(a,e),s={trs:B(n.trs.join("")),trs_fixed:B(n.trs_fixed.join("")),trs_fixed_r:B(n.trs_fixed_r.join(""))};layui.each(e,function(e,t){var a=t[H].split("-").length-1;f={"data-index":t[H],"lay-data-index":t[H],"data-level":a},s.trs.eq(e).attr(f),s.trs_fixed.eq(e).attr(f),s.trs_fixed_r.eq(e).attr(f)}),layui.each(["main","fixed-l","fixed-r"],function(e,t){l.find(".layui-table-"+t+" tbody").html(s[["trs","trs_fixed","trs_fixed_r"][e]])}),t.renderTreeTable(l,0,!1)}}else t.updateStatus(null,function(e){(e[r]||o)&&(e[X]=!1,e[d]!==undefined&&(t.status.expand[e[d]]=!1))}),l.find('.layui-table-box tbody tr[data-level!="0"]').addClass(q),l.find(".layui-table-tree-flexIcon").html(i.view.flexIconClose),i.view.showIcon&&l.find(".layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)").html(i.view.iconClose);P.resize(a)}},t.prototype.renderTreeTable=function(e,t,a){var n=this,i=n.getOptions(),l=i.elem.next(),r=(l.hasClass(h)||l.addClass(h),i.id),d=i.tree||{},o=(d.data,d.view||{}),c=d.customName||{},u=c.isParent,f=(l.attr("lay-filter"),n),s=((t=t||0)||(l.find(".layui-table-body tr:not([data-level])").attr("data-level",t),layui.each(j.cache[r],function(e,t){l.find('.layui-table-main tbody tr[data-level="0"]:eq('+e+")").attr("lay-data-index",t[H]),l.find('.layui-table-fixed-l tbody tr[data-level="0"]:eq('+e+")").attr("lay-data-index",t[H]),l.find('.layui-table-fixed-r tbody tr[data-level="0"]:eq('+e+")").attr("lay-data-index",t[H])})),null),y=c.name,p=o.indent||14;layui.each(e.find('td[data-field="'+y+'"]'),function(e,t){var a,n,i=(t=B(t)).closest("tr"),t=t.children(".layui-table-cell");t.hasClass("layui-table-tree-item")||(n=i.attr("lay-data-index"))&&(i=l.find('tr[lay-data-index="'+n+'"]'),(a=f.getNodeDataByIndex(n))[X]&&a[u]&&((s=s||{})[n]=!0),a[b]&&i.find('input[type="checkbox"][name="layTableCheckbox"]').prop("indeterminate",!0),n=t.html(),(t=i.find('td[data-field="'+y+'"]>div.layui-table-cell')).addClass("layui-table-tree-item"),t.html(['
      ',a[X]?o.flexIconOpen:o.flexIconClose,"
      ",o.showIcon?'
      '+(a[c.icon]||o.icon||(a[u]?a[X]?o.iconOpen:o.iconClose:o.iconLeaf)||"")+"
      ":"",n].join("")).find(".layui-table-tree-flexIcon").on("click",function(e){layui.stope(e),J({trElem:i},null,null,null,!0)}))}),!1!==a&&s?layui.each(s,function(e,t){e=l.find('tr[lay-data-index="'+e+'"]');e.find(".layui-table-tree-flexIcon").html(o.flexIconOpen),J({trElem:e.first()},!0)}):U("renderTreeTable-"+r,function(){i.hasNumberCol&&g(n),x.render(B('.layui-table-tree[lay-id="'+r+'"]'))},0)()},function(a){var e=a.getOptions(),t=e.elem.next(),n=0,i=t.find(".layui-table-main tbody tr"),l=t.find(".layui-table-fixed-l tbody tr"),r=t.find(".layui-table-fixed-r tbody tr");layui.each(a.treeToFlat(j.cache[e.id]),function(e,t){a.getNodeDataByIndex(t[H]).LAY_NUM=++n,i.eq(e).find(".laytable-cell-numbers").html(n),l.eq(e).find(".laytable-cell-numbers").html(n),r.eq(e).find(".laytable-cell-numbers").html(n)})}),s=(t.prototype.render=function(e){var t=this;t.tableIns=j["reloadData"===e?"reloadData":"reload"](t.tableIns.config.id,B.extend(!0,{},t.config)),t.config=t.tableIns.config},t.prototype.reload=function(e,t,a){var n=this;e=e||{},delete n.haveInit,layui.each(e,function(e,t){"array"===layui.type(t)&&delete n.config[e]}),l(n.config.id,e,a||!0),n.config=B.extend(t,{},n.config,e),n.render(a)},P.reloadData=function(){var e=B.extend(!0,[],arguments);return e[3]="reloadData",P.reload.apply(null,e)},function(e,a,n){var i=[];return layui.each(e,function(e,t){"function"===layui.type(a)?a(t):B.extend(t,a),i.push(B.extend({},t)),i=i.concat(s(t[n],a,n))}),i}),r=(t.prototype.updateStatus=function(e,t){var a=this.getOptions(),n=a.tree;return e=e||j.cache[a.id],s(e,t,n.customName.children)},t.prototype.getTableData=function(){var e=this.getOptions();return e.url?j.cache[e.id]:e.data},P.updateStatus=function(e,t,a){var e=F(e),n=e.getOptions();return a=a||(n.url?j.cache[n.id]:n.data),e.updateStatus(a,t)},P.sort=function(e){var t,a,n,i,l=F(e);l&&(a=(t=l.getOptions()).initSort,t.url?t.autoSort&&(n=l.initData(),(i={})[t.response.dataName]=n,"function"==typeof t.done&&t.done(i,l.page,l.count)):(a.type?layui.sort(t.data,a.field,"desc"===a.type,!0):layui.sort(t.data,j.config.indexName,null,!0),l.initData(t.data),P.reloadData(e)))},function(n){var t=n.config.id,i=F(t),a=n.data=P.getNodeDataByIndex(t,n.index),l=a[H],r=(n.dataIndex=l,n.update);n.update=function(){var e=arguments,t=(B.extend(i.getNodeDataByIndex(l),e[0]),r.apply(this,e)),a=n.config.tree.customName.name;return a in e[0]&&n.tr.find('td[data-field="'+a+'"]').children("div.layui-table-cell").removeClass("layui-table-tree-item"),i.renderTreeTable(n.tr,n.tr.attr("data-level"),!1),t},n.del=function(){P.removeNode(t,a)},n.setRowChecked=function(e){P.setRowChecked(t,{index:a,checked:e})}}),o=(P.updateNode=function(e,a,t){var n,i,l,r,d,o=F(e);o&&((r=o.getOptions()).tree,r=(n=r.elem.next()).find('tr[lay-data-index="'+a+'"]'),i=r.attr("data-index"),l=r.attr("data-level"),t&&(r=o.getNodeDataByIndex(a,!1,t),d=j.getTrHtml(e,[r]),layui.each(["main","fixed-l","fixed-r"],function(e,t){n.find(".layui-table-"+t+' tbody tr[lay-data-index="'+a+'"]').replaceWith(B(d[["trs","trs_fixed","trs_fixed_r"][e]].join("")).attr({"data-index":i,"lay-data-index":a,"data-level":l}))}),o.renderTreeTable(n.find('tr[lay-data-index="'+a+'"]'),l)))},P.removeNode=function(e,t){var a,n,i,l,r,d=F(e);d&&(r=(a=d.getOptions()).tree,n=a.elem.next(),i=[],t=d.getNodeDataByIndex("string"===layui.type(t)?t:t[H],!1,"delete"),l=d.getNodeDataByIndex(t[f]),d.updateCheckStatus(l),l=d.treeToFlat([t],t[r.customName.pid],t[f]),layui.each(l,function(e,t){i.push('tr[lay-data-index="'+t[H]+'"]')}),n.find(i.join(",")).remove(),r=d.initData(),layui.each(d.treeToFlat(r),function(e,t){t[m]&&t[m]!==t[H]&&n.find('tr[lay-data-index="'+t[m]+'"]').attr({"data-index":t[H],"lay-data-index":t[H]})}),layui.each(j.cache[e],function(e,t){n.find('tr[data-level="0"][lay-data-index="'+t[H]+'"]').attr("data-index",e)}),a.hasNumberCol&&g(d))},P.addNodes=function(e,t){var a=F(e);if(a){var n=a.getOptions(),i=n.tree,l=n.elem.next(),r=(t=t||{}).parentIndex,d=t.index,o=t.data,t=t.focus,c=(r="number"===layui.type(r)?r.toString():r)?a.getNodeDataByIndex(r):null,d="number"===layui.type(d)?d:-1,o=B.extend(!0,[],layui.isArray(o)?o:[o]);a.getTableData();if(c){var u=i.customName.isParent,f=i.customName.children;c[u]=!0;var s=(s=c[f])?(y=s.splice(-1===d?s.length:d),c[f]=s.concat(o,y)):c[f]=o,f=(a.updateStatus(s,function(e){(e[u]||i.view.showFlexIconIfNotParent)&&(e[z]=!1)}),a.treeToFlat(s));l.find(f.map(function(e){return'tr[lay-data-index="'+e[H]+'"]'}).join(",")).remove(),a.initData(),c[z]=!1,c[V]="local",J({trElem:l.find('tr[lay-data-index="'+r+'"]')},!0)}else{var y=j.cache[e].splice(-1===d?j.cache[e].length:d);if(j.cache[e]=j.cache[e].concat(o,y),n.url||(n.page?(s=n.page,n.data.splice.apply(n.data,[s.limit*(s.curr-1),s.limit].concat(j.cache[e]))):n.data=j.cache[e]),a.initData(),l.find(".layui-none").length)return j.renderData(e),o;var p,f=j.getTrHtml(e,o),x={trs:B(f.trs.join("")),trs_fixed:B(f.trs_fixed.join("")),trs_fixed_r:B(f.trs_fixed_r.join(""))},r=(layui.each(o,function(e,t){p={"data-index":t[H],"lay-data-index":t[H],"data-level":"0"},x.trs.eq(e).attr(p),x.trs_fixed.eq(e).attr(p),x.trs_fixed_r.eq(e).attr(p)}),parseInt(o[0][H])-1),s=l.find(L),n=l.find(Y),f=l.find(R);-1==r?(s.find('tr[data-level="0"][data-index="0"]').before(x.trs),n.find('tr[data-level="0"][data-index="0"]').before(x.trs_fixed),f.find('tr[data-level="0"][data-index="0"]').before(x.trs_fixed_r)):-1===d?(s.find("tbody").append(x.trs),n.find("tbody").append(x.trs_fixed),f.find("tbody").append(x.trs_fixed_r)):(r=y[0][m],s.find('tr[data-level="0"][data-index="'+r+'"]').before(x.trs),n.find('tr[data-level="0"][data-index="'+r+'"]').before(x.trs_fixed),f.find('tr[data-level="0"][data-index="'+r+'"]').before(x.trs_fixed_r)),layui.each(j.cache[e],function(e,t){l.find('tr[data-level="0"][lay-data-index="'+t[H]+'"]').attr("data-index",e)}),a.renderTreeTable(l.find(o.map(function(e,t,a){return'tr[lay-data-index="'+e[H]+'"]'}).join(",")))}return a.updateCheckStatus(c),P.resize(e),t&&l.find(L).find('tr[lay-data-index="'+o[0][H]+'"]').get(0).scrollIntoViewIfNeeded(),o}},P.checkStatus=function(e,n){var i,t,a;if(F(e))return i=j.config.checkName,t=P.getData(e,!0).filter(function(e,t,a){return e[i]||n&&e[b]}),a=!0,layui.each(j.cache[e],function(e,t){if(!t[i])return!(a=!1)}),{data:t,isAll:a}},P.on("sort",function(e){var e=e.config,t=e.elem.next(),e=e.id;t.hasClass(h)&&P.sort(e)}),P.on("row",function(e){e.config.elem.next().hasClass(h)&&r(e)}),P.on("rowDouble",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(h)&&(r(e),(t.tree||{}).view.dblClickExpand&&J({trElem:e.tr.first()},null,null,null,!0))}),P.on("rowContextmenu",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(h)&&r(e)}),P.on("tool",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(h)&&r(e)}),P.on("edit",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(h)&&(r(e),e.field===t.tree.customName.name&&((a={})[e.field]=e.value,e.update(a)))}),P.on("radio",function(e){var t=e.config,a=t.elem.next(),t=t.id;a.hasClass(h)&&(a=F(t),r(e),o.call(a,e.tr,e.checked))}),t.prototype.updateCheckStatus=function(e,t){var a=this.getOptions(),n=(a.tree,a.id),i=a.elem.next(),l=j.config.checkName,r=(e&&(a=this.updateParentCheckStatus(e,"boolean"===layui.type(t)?t:null),layui.each(a,function(e,t){x.render(i.find('tr[lay-data-index="'+t[H]+'"] input[name="layTableCheckbox"]:not(:disabled)').prop({checked:t[l],indeterminate:t[b]}))})),!0),d=!1;return layui.each(j.cache[n],function(e,t){(t[l]||t[b])&&(d=!0),t[l]||(r=!1)}),d=d&&!r,x.render(i.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop({checked:r,indeterminate:d})),r},t.prototype.updateParentCheckStatus=function(a,n){var i,e=this.getOptions(),t=e.tree,e=e.id,l=j.config.checkName,t=t.customName.children,r=[];return!(a[b]=!1)===n?a[t].length?layui.each(a[t],function(e,t){if(!t[l])return n=!1,a[b]=!0}):n=!1:!1===n?layui.each(a[t],function(e,t){if(t[l]||t[b])return a[b]=!0}):(n=!1,i=0,layui.each(a[t],function(e,t){t[l]&&i++}),n=a[t].length?a[t].length===i:a[l],a[b]=!n&&0')),a=(e.tree(n),i.elem=u(i.elem));if(a[0]){if(e.key=i.id||e.index,e.elem=n,e.elemNone=u('
      '+i.text.none+"
      "),a.html(e.elem),0==e.elem.find(".layui-tree-set").length)return e.elem.append(e.elemNone);i.showCheckbox&&e.renderForm("checkbox"),e.elem.find(".layui-tree-set").each(function(){var e=u(this);e.parent(".layui-tree-pack")[0]||e.addClass("layui-tree-setHide"),!e.next()[0]&&e.parents(".layui-tree-pack").eq(1).hasClass("layui-tree-lineExtend")&&e.addClass(N),e.next()[0]||e.parents(".layui-tree-set").eq(0).next()[0]||e.addClass(N)}),e.events()}},l.prototype.renderForm=function(e){i.render(e,"LAY-tree-"+this.index)},l.prototype.tree=function(l,e){var r=this,c=r.config,e=e||c.data;layui.each(e,function(e,i){var n=i.children&&0"),t=u(['
      ','
      ','
      ',c.showLine?n?'':'':'',c.showCheckbox?'':"",c.isJump&&i.href?''+(i.title||i.label||c.text.defaultNodeName)+"":''+(i.title||i.label||c.text.defaultNodeName)+"","
      ",function(){if(!c.edit)return"";var n={add:'',update:'',del:''},a=['
      '];return!0===c.edit&&(c.edit=["update","del"]),"object"==typeof c.edit?(layui.each(c.edit,function(e,i){a.push(n[i]||"")}),a.join("")+"
      "):void 0}(),"
      "].join(""));n&&(t.append(a),r.tree(a,i.children)),l.append(t),t.prev("."+f)[0]&&t.prev().children(".layui-tree-pack").addClass("layui-tree-showLine"),n||t.parent(".layui-tree-pack").addClass("layui-tree-lineExtend"),r.spread(t,i),c.showCheckbox&&(i.checked&&r.checkids.push(i.id),r.checkClick(t,i)),c.edit&&r.operate(t,i)})},l.prototype.spread=function(a,e){var t=this.config,i=a.children("."+m),n=i.children("."+x),l=i.find("."+C),i=i.find("."+b),r=t.onlyIconControl?l:n,c="";r.on("click",function(e){var i=a.children("."+g),n=(r.children(".layui-icon")[0]?r:r.find(".layui-tree-icon")).children(".layui-icon");i[0]?a.hasClass(w)?(a.removeClass(w),i.slideUp(200),n.removeClass(v).addClass(k)):(a.addClass(w),i.slideDown(200),n.addClass(v).removeClass(k),t.accordion&&((i=a.siblings("."+f)).removeClass(w),i.children("."+g).slideUp(200),i.find(".layui-tree-icon").children(".layui-icon").removeClass(v).addClass(k))):c="normal"}),i.on("click",function(){u(this).hasClass(d)||(c=a.hasClass(w)?t.onlyIconControl?"open":"close":t.onlyIconControl?"close":"open",t.click&&t.click({elem:a,state:c,data:e}))})},l.prototype.setCheckbox=function(e,i,n){this.config;var t,l=n.prop("checked");n.prop("disabled")||("object"!=typeof i.children&&!e.find("."+g)[0]||e.find("."+g).find('input[same="layuiTreeCheck"]').each(function(){this.disabled||(this.checked=l)}),(t=function(e){var i,n,a;e.parents("."+f)[0]&&(n=(e=e.parent("."+g)).parent(),a=e.prev().find('input[same="layuiTreeCheck"]'),l?a.prop("checked",l):(e.find('input[same="layuiTreeCheck"]').each(function(){this.checked&&(i=!0)}),i||a.prop("checked",!1)),t(n))})(e),this.renderForm("checkbox"))},l.prototype.checkClick=function(n,a){var t=this,l=t.config;n.children("."+m).children("."+x).on("click",'input[same="layuiTreeCheck"]+',function(e){layui.stope(e);var e=u(this).prev(),i=e.prop("checked");e.prop("disabled")||(t.setCheckbox(n,a,e),l.oncheck&&l.oncheck({elem:n,checked:i,data:a}))})},l.prototype.operate=function(c,d){var s=this,o=s.config,e=c.children("."+m),h=e.children("."+x);e.children(".layui-tree-btnGroup").on("click",".layui-icon",function(e){layui.stope(e);var i,e=u(this).data("type"),a=c.children("."+g),t={data:d,type:e,elem:c};if("add"==e){a[0]||(o.showLine?(h.find("."+C).addClass("layui-tree-icon"),h.find("."+C).children(".layui-icon").addClass(k).removeClass("layui-icon-file")):h.find(".layui-tree-iconArrow").removeClass(y),c.append('
      '));var n,l=o.operate&&o.operate(t),r={};if(r.title=o.text.defaultNodeName,r.id=l,s.tree(c.children("."+g),[r]),o.showLine&&(a[0]?(a.hasClass(L)||a.addClass(L),c.find("."+g).each(function(){u(this).children("."+f).last().addClass(N)}),(a.children("."+f).last().prev().hasClass(N)?a.children("."+f).last().prev():a.children("."+f).last()).removeClass(N),!c.parent("."+g)[0]&&c.next()[0]&&a.children("."+f).last().removeClass(N)):(l=c.siblings("."+f),n=1,r=c.parent("."+g),layui.each(l,function(e,i){u(i).children("."+g)[0]||(n=0)}),1==n?(l.children("."+g).addClass(T),l.children("."+g).children("."+f).removeClass(N),c.children("."+g).addClass(T),r.removeClass(L),r.children("."+f).last().children("."+g).children("."+f).last().addClass(N)):c.children("."+g).children("."+f).addClass(N))),!o.showCheckbox)return;h.find('input[same="layuiTreeCheck"]')[0].checked&&(c.children("."+g).children("."+f).last().find('input[same="layuiTreeCheck"]')[0].checked=!0),s.renderForm("checkbox")}else"update"==e?(l=h.children("."+b).html(),h.children("."+b).html(""),h.append(''),h.children(".layui-tree-editInput").val(l).focus(),i=function(e){var i=(i=e.val().trim())||o.text.defaultNodeName;e.remove(),h.children("."+b).html(i),t.data.title=i,o.operate&&o.operate(t)},h.children(".layui-tree-editInput").blur(function(){i(u(this))}),h.children(".layui-tree-editInput").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),i(u(this)))})):p.confirm('\u786e\u8ba4\u5220\u9664\u8be5\u8282\u70b9 "'+(d.title||"")+'" \u5417\uff1f',function(e){if(o.operate&&o.operate(t),t.status="remove",p.close(e),!c.prev("."+f)[0]&&!c.next("."+f)[0]&&!c.parent("."+g)[0])return c.remove(),void s.elem.append(s.elemNone);var l,n,i;c.siblings("."+f).children("."+m)[0]?(o.showCheckbox&&(l=function(e){var i,n,a,t;e.parents("."+f)[0]&&(i=e.siblings("."+f).children("."+m),n=(e=e.parent("."+g).prev()).find('input[same="layuiTreeCheck"]')[0],a=1,(t=0)==n.checked&&(i.each(function(e,i){i=u(i).find('input[same="layuiTreeCheck"]')[0];0!=i.checked||i.disabled||(a=0),i.disabled||(t=1)}),1==a&&1==t&&(n.checked=!0,s.renderForm("checkbox"),l(e.parent("."+f)))))})(c),o.showLine&&(e=c.siblings("."+f),n=1,i=c.parent("."+g),layui.each(e,function(e,i){u(i).children("."+g)[0]||(n=0)}),1==n?(a[0]||(i.removeClass(L),e.children("."+g).addClass(T),e.children("."+g).children("."+f).removeClass(N)),(c.next()[0]?i.children("."+f).last():c.prev()).children("."+g).children("."+f).last().addClass(N),c.next()[0]||c.parents("."+f)[1]||c.parents("."+f).eq(0).next()[0]||c.prev("."+f).addClass(N)):!c.next()[0]&&c.hasClass(N)&&c.prev().addClass(N))):(e=c.parent("."+g).prev(),o.showLine?(e.find("."+C).removeClass("layui-tree-icon"),e.find("."+C).children(".layui-icon").removeClass(v).addClass("layui-icon-file"),(i=e.parents("."+g).eq(0)).addClass(L),i.children("."+f).each(function(){u(this).children("."+g).children("."+f).last().addClass(N)})):e.find(".layui-tree-iconArrow").addClass(y),c.parents("."+f).eq(0).removeClass(w),c.parent("."+g).remove()),c.remove()})})},l.prototype.events=function(){var i=this,t=i.config;i.elem.find(".layui-tree-checkedFirst");i.setChecked(i.checkids),i.elem.find(".layui-tree-search").on("keyup",function(){var e=u(this),n=e.val(),e=e.nextAll(),a=[];e.find("."+b).each(function(){var i,e=u(this).parents("."+m);-1!=u(this).html().indexOf(n)&&(a.push(u(this).parent()),(i=function(e){e.addClass("layui-tree-searchShow"),e.parent("."+g)[0]&&i(e.parent("."+g).parent("."+f))})(e.parent("."+f)))}),e.find("."+m).each(function(){var e=u(this).parent("."+f);e.hasClass("layui-tree-searchShow")||e.addClass(y)}),0==e.find(".layui-tree-searchShow").length&&i.elem.append(i.elemNone),t.onsearch&&t.onsearch({elem:a})}),i.elem.find(".layui-tree-search").on("keydown",function(){u(this).nextAll().find("."+m).each(function(){u(this).parent("."+f).removeClass("layui-tree-searchShow "+y)}),u(".layui-tree-emptyText")[0]&&u(".layui-tree-emptyText").remove()})},l.prototype.getChecked=function(){var e=this.config,i=[],n=[],t=(this.elem.find(".layui-form-checked").each(function(){i.push(u(this).prev()[0].value)}),function(e,a){layui.each(e,function(e,n){layui.each(i,function(e,i){if(n.id==i)return delete(i=u.extend({},n)).children,a.push(i),n.children&&(i.children=[],t(n.children,i.children)),!0})})});return t(u.extend({},e.data),n),n},l.prototype.setChecked=function(l){this.config;this.elem.find("."+f).each(function(e,i){var n=u(this).data("id"),a=u(i).children("."+m).find('input[same="layuiTreeCheck"]'),t=a.next();if("number"==typeof l){if(n.toString()==l.toString())return a[0].checked||t.click(),!1}else"object"==typeof l&&layui.each(l,function(e,i){if(i.toString()==n.toString()&&!a[0].checked)return t.click(),!0})})},t.that={},t.config={},a.reload=function(e,i){e=t.that[e];return e.reload(i),t.call(e)},a.getChecked=function(e){return t.that[e].getChecked()},a.setChecked=function(e,i){return t.that[e].setChecked(i)},a.render=function(e){e=new l(e);return t.call(e)},e(n,a)});layui.define(["laytpl","form"],function(e){"use strict";var s=layui.$,n=layui.laytpl,t=layui.form,a="transfer",i={config:{},index:layui[a]?layui[a].index+1e4:0,set:function(e){var t=this;return t.config=s.extend({},t.config,e),t},on:function(e,t){return layui.onevent.call(this,a,e,t)}},l=function(){var t=this,e=t.config,a=e.id||t.index;return l.that[a]=t,{config:l.config[a]=e,reload:function(e){t.reload.call(t,e)},getData:function(){return t.getData.call(t)}}},d="layui-hide",h="layui-btn-disabled",r="layui-none",c="layui-transfer-box",u="layui-transfer-header",o="layui-transfer-search",f="layui-transfer-data",y=function(e){return['
      ','
      ','","
      ","{{# if(d.data.showSearch){ }}",'","{{# } }}",'
        ',"
        "].join("")},p=['
        ',y({index:0,checkAllName:"layTransferLeftCheckAll"}),'
        ','",'","
        ",y({index:1,checkAllName:"layTransferRightCheckAll"}),"
        "].join(""),v=function(e){var t=this;t.index=++i.index,t.config=s.extend({},t.config,i.config,e),t.render()};v.prototype.config={title:["\u5217\u8868\u4e00","\u5217\u8868\u4e8c"],width:200,height:360,data:[],value:[],showSearch:!1,id:"",text:{none:"\u65e0\u6570\u636e",searchNone:"\u65e0\u5339\u914d\u6570\u636e"}},v.prototype.reload=function(e){var t=this;t.config=s.extend({},t.config,e),t.render()},v.prototype.render=function(){var e=this,t=e.config,a=e.elem=s(n(p,{open:"{{",close:"}}"}).render({data:t,index:e.index})),i=t.elem=s(t.elem);i[0]&&(t.data=t.data||[],t.value=t.value||[],t.id="id"in t?t.id:elem.attr("id")||e.index,e.key=t.id,i.html(e.elem),e.layBox=e.elem.find("."+c),e.layHeader=e.elem.find("."+u),e.laySearch=e.elem.find("."+o),e.layData=a.find("."+f),e.layBtn=a.find(".layui-transfer-active .layui-btn"),e.layBox.css({width:t.width,height:t.height}),e.layData.css({height:(i=t.height-e.layHeader.outerHeight(),t.showSearch&&(i-=e.laySearch.outerHeight()),i-2)}),e.renderData(),e.events())},v.prototype.renderData=function(){var e=this,t=e.config,l=[{checkName:"layTransferLeftCheck",views:[]},{checkName:"layTransferRightCheck",views:[]}];e.parseData(function(a){var i=a.selected?1:0,n=["
      • ",'',"
      • "].join("");i?layui.each(t.value,function(e,t){t==a.value&&a.selected&&(l[i].views[e]=n)}):l[i].views.push(n),delete a.selected}),e.layData.eq(0).html(l[0].views.join("")),e.layData.eq(1).html(l[1].views.join("")),e.renderCheckBtn()},v.prototype.renderForm=function(e){t.render(e,"LAY-transfer-"+this.index)},v.prototype.renderCheckBtn=function(r){var c=this,o=c.config;r=r||{},c.layBox.each(function(e){var t=s(this),a=t.find("."+f),t=t.find("."+u).find('input[type="checkbox"]'),i=a.find('input[type="checkbox"]'),n=0,l=!1;i.each(function(){var e=s(this).data("hide");(this.checked||this.disabled||e)&&n++,this.checked&&!e&&(l=!0)}),t.prop("checked",l&&n===i.length),c.layBtn.eq(e)[l?"removeClass":"addClass"](h),r.stopNone||(i=a.children("li:not(."+d+")").length,c.noneView(a,i?"":o.text.none))}),c.renderForm("checkbox")},v.prototype.noneView=function(e,t){var a=s('

        '+(t||"")+"

        ");e.find("."+r)[0]&&e.find("."+r).remove(),t.replace(/\s/g,"")&&e.append(a)},v.prototype.setValue=function(){var e=this.config,t=[];return this.layBox.eq(1).find("."+f+' input[type="checkbox"]').each(function(){s(this).data("hide")||t.push(this.value)}),e.value=t,this},v.prototype.parseData=function(t){var i=this.config,n=[];return layui.each(i.data,function(e,a){a=("function"==typeof i.parseData?i.parseData(a):a)||a,n.push(a=s.extend({},a)),layui.each(i.value,function(e,t){t==a.value&&(a.selected=!0)}),t&&t(a)}),i.data=n,this},v.prototype.getData=function(e){var t=this.config,i=[];return this.setValue(),layui.each(e||t.value,function(e,a){layui.each(t.data,function(e,t){delete t.selected,a==t.value&&i.push(t)})}),i},v.prototype.transfer=function(e,t){var a,i=this,n=i.config,l=i.layBox.eq(e),r=[],t=(t?((a=(t=t).find('input[type="checkbox"]'))[0].checked=!1,l.siblings("."+c).find("."+f).append(t.clone()),t.remove(),r.push(a[0].value),i.setValue()):l.each(function(e){s(this).find("."+f).children("li").each(function(){var e=s(this),t=e.find('input[type="checkbox"]'),a=t.data("hide");t[0].checked&&!a&&(t[0].checked=!1,l.siblings("."+c).find("."+f).append(e.clone()),e.remove(),r.push(t[0].value)),i.setValue()})}),i.renderCheckBtn(),l.siblings("."+c).find("."+o+" input"));""!==t.val()&&t.trigger("keyup"),n.onchange&&n.onchange(i.getData(r),e)},v.prototype.events=function(){var n=this,l=n.config;n.elem.on("click",'input[lay-filter="layTransferCheckbox"]+',function(){var e=s(this).prev(),t=e[0].checked,a=e.parents("."+c).eq(0).find("."+f);e[0].disabled||("all"===e.attr("lay-type")&&a.find('input[type="checkbox"]').each(function(){this.disabled||(this.checked=t)}),setTimeout(function(){n.renderCheckBtn({stopNone:!0})},0))}),n.elem.on("dblclick","."+f+">li",function(e){var t=s(this),a=t.children('input[type="checkbox"]'),i=t.parent().parent();a[0].disabled||n.transfer(i.data("index"),t)}),n.layBtn.on("click",function(){var e=s(this),t=e.data("index");e.hasClass(h)||n.transfer(t)}),n.laySearch.find("input").on("keyup",function(){var i=this.value,e=s(this).parents("."+o).eq(0).siblings("."+f),t=e.children("li"),t=(t.each(function(){var e=s(this),t=e.find('input[type="checkbox"]'),a=t[0].title,a=("cs"!==l.showSearch&&(a=a.toLowerCase(),i=i.toLowerCase()),-1!==a.indexOf(i));e[a?"removeClass":"addClass"](d),t.data("hide",!a)}),n.renderCheckBtn(),t.length===e.children("li."+d).length);n.noneView(e,t?l.text.searchNone:"")})},l.that={},l.config={},i.reload=function(e,t){e=l.that[e];return e.reload(t),l.call(e)},i.getData=function(e){return l.that[e].getData()},i.render=function(e){e=new v(e);return l.call(e)},e(a,i)});layui.define(["jquery","lay"],function(e){"use strict";var a=layui.$,t=layui.lay,o=(layui.hint(),layui.device(),{config:{},set:function(e){var i=this;return i.config=a.extend({},i.config,e),i},on:function(e,i){return layui.onevent.call(this,r,e,i)}}),r="carousel",d="layui-this",s="layui-carousel-left",u="layui-carousel-right",c="layui-carousel-prev",m="layui-carousel-next",l="layui-carousel-arrow",f="layui-carousel-ind",i=function(e){var i=this;i.config=a.extend({},i.config,o.config,e),i.render()};i.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},i.prototype.render=function(){var e=this,i=e.config,n=a(i.elem);if(1*[carousel-item]>*"),i.index<0&&(i.index=0),i.index>=e.elemItem.length&&(i.index=e.elemItem.length-1),i.interval<800&&(i.interval=800),i.full?i.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):i.elem.css({width:i.width,height:i.height}),i.elem.attr("lay-anim",i.anim),e.elemItem.eq(i.index).addClass(d),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},i.prototype.reload=function(e){var i=this;clearInterval(i.timer),i.config=a.extend({},i.config,e),i.render()},i.prototype.prevIndex=function(){var e=this.config.index-1;return e=e<0?this.elemItem.length-1:e},i.prototype.nextIndex=function(){var e=this.config.index+1;return e=e>=this.elemItem.length?0:e},i.prototype.addIndex=function(e){var i=this.config;i.index=i.index+(e=e||1),i.index>=this.elemItem.length&&(i.index=0)},i.prototype.subIndex=function(e){var i=this.config;i.index=i.index-(e=e||1),i.index<0&&(i.index=this.elemItem.length-1)},i.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(clearInterval(e.timer),e.timer=setInterval(function(){e.slide()},i.interval))},i.prototype.arrow=function(){var i=this,e=i.config,n=a(['",'"].join(""));e.elem.attr("lay-arrow",e.arrow),e.elem.find("."+l)[0]&&e.elem.find("."+l).remove(),e.elem.append(n),n.on("click",function(){var e=a(this).attr("lay-type");i.slide(e)})},i.prototype["goto"]=function(e){var i=this,n=i.config;e>n.index?i.slide("add",e-n.index):e
          ',(i=[],layui.each(e.elemItem,function(e){i.push("")}),i.join("")),"
        "].join(""));n.elem.attr("lay-indicator",n.indicator),n.elem.find("."+f)[0]&&n.elem.find("."+f).remove(),n.elem.append(t),"updown"===n.anim&&t.css("margin-top",-t.height()/2),t.find("li").on("hover"===n.trigger?"mouseover":n.trigger,function(){e["goto"](a(this).index())})},i.prototype.slide=function(e,i){var n=this,t=n.elemItem,a=n.config,o=a.index,l=a.elem.attr("lay-filter");n.haveSlide||("sub"===e?(n.subIndex(i),t.eq(a.index).addClass(c),setTimeout(function(){t.eq(o).addClass(u),t.eq(a.index).addClass(u)},50)):(n.addIndex(i),t.eq(a.index).addClass(m),setTimeout(function(){t.eq(o).addClass(s),t.eq(a.index).addClass(s)},50)),setTimeout(function(){t.removeClass(d+" "+c+" "+m+" "+s+" "+u),t.eq(a.index).addClass(d),n.haveSlide=!1},300),n.elemInd.find("li").eq(a.index).addClass(d).siblings().removeClass(d),n.haveSlide=!0,e={index:a.index,prevIndex:o,item:t.eq(a.index)},"function"==typeof a.change&&a.change(e),layui.event.call(this,r,"change("+l+")",e))},i.prototype.events=function(){var e=this,i=e.config;i.elem.data("haveEvents")||(i.elem.on("mouseenter",function(){"always"!==e.config.autoplay&&clearInterval(e.timer)}).on("mouseleave",function(){"always"!==e.config.autoplay&&e.autoplay()}),i.elem.data("haveEvents",!0))},o.render=function(e){return new i(e)},e(r,o)});layui.define(["jquery","lay"],function(e){"use strict";var s=layui.jquery,r=layui.lay,c={config:{},index:layui.rate?layui.rate.index+1e4:0,set:function(e){var a=this;return a.config=s.extend({},a.config,e),a},on:function(e,a){return layui.onevent.call(this,l,e,a)}},l="rate",f="layui-icon-rate",h="layui-icon-rate-solid",o="layui-icon-rate-half",u="layui-icon-rate-solid layui-icon-rate-half",v="layui-icon-rate layui-icon-rate-half",a=function(e){var a=this;a.index=++c.index,a.config=s.extend({},a.config,c.config,e),a.render()};a.prototype.config={length:5,text:!1,readonly:!1,half:!1,value:0,theme:""},a.prototype.render=function(){var e=this,a=e.config,l=s(a.elem);if(1a.length&&(a.value=a.length),parseInt(a.value)===a.value||a.half||(a.value=Math.ceil(a.value)-a.value<.5?Math.ceil(a.value):Math.floor(a.value)),'
          "),t=1;t<=a.length;t++){var o='
        • ";a.half&&parseInt(a.value)!==a.value&&t==Math.ceil(a.value)?n=n+'
        • ":n+=o}n+="
        "+(a.text?''+a.value+"\u661f":"")+"";var l=a.elem,u=l.next(".layui-rate");u[0]&&u.remove(),e.elemTemp=s(n),a.span=e.elemTemp.next("span"),a.setText&&a.setText(a.value),l.html(e.elemTemp),l.addClass("layui-inline"),a.readonly||e.action()},a.prototype.setvalue=function(e){this.config.value=e,this.render()},a.prototype.action=function(){var i=this.config,n=this.elemTemp,t=n.find("i").width();n.children("li").each(function(e){var a=e+1,l=s(this);l.on("click",function(e){i.value=a,i.half&&e.pageX-s(this).offset().left<=t/2&&(i.value=i.value-.5),i.text&&n.next("span").text(i.value+"\u661f"),i.choose&&i.choose(i.value),i.setText&&i.setText(i.value)}),l.on("mousemove",function(e){n.find("i").each(function(){s(this).addClass(f).removeClass(u)}),n.find("i:lt("+a+")").each(function(){s(this).addClass(h).removeClass(v)}),i.half&&e.pageX-s(this).offset().left<=t/2&&l.children("i").addClass(o).removeClass(h)}),l.on("mouseleave",function(){n.find("i").each(function(){s(this).addClass(f).removeClass(u)}),n.find("i:lt("+Math.floor(i.value)+")").each(function(){s(this).addClass(h).removeClass(v)}),i.half&&parseInt(i.value)!==i.value&&n.children("li:eq("+Math.floor(i.value)+")").children("i").addClass(o).removeClass("layui-icon-rate-solid layui-icon-rate")})})},a.prototype.events=function(){this.config},c.render=function(e){e=new a(e);return function(){var a=this;return{setvalue:function(e){a.setvalue.call(a,e)},config:a.config}}.call(e)},e(l,c)});layui.define("jquery",function(l){"use strict";var g=layui.$,e=function(l){};e.prototype.load=function(l){var t,i,n,e,r,o,a,c,m,s,u,f,y,d=this,p=0,h=g((l=l||{}).elem);if(h[0])return e=g(l.scrollElem||document),r=l.mb||50,o=!("isAuto"in l)||l.isAuto,a=l.end||"\u6ca1\u6709\u66f4\u591a\u4e86",c=l.scrollElem&&l.scrollElem!==document,m="\u52a0\u8f7d\u66f4\u591a",s=g('"),h.find(".layui-flow-more")[0]||h.append(s),u=function(l,e){l=g(l),s.before(l),(e=0==e||null)?s.html(a):s.find("a").html(m),i=e,t=null,y&&y()},f=function(){t=!0,s.find("a").html(''),"function"==typeof l.done&&l.done(++p,u)},f(),s.find("a").on("click",function(){g(this);i||t||f()}),l.isLazyimg&&(y=d.lazyimg({elem:l.elem+" img",scrollElem:l.scrollElem})),o&&e.on("scroll",function(){var e=g(this),o=e.scrollTop();n&&clearTimeout(n),!i&&h.width()&&(n=setTimeout(function(){var l=(c?e:g(window)).height();(c?e.prop("scrollHeight"):document.documentElement.scrollHeight)-o-l<=r&&(t||f())},100))}),d},e.prototype.lazyimg=function(l){var e,c=this,m=0,s=g((l=l||{}).scrollElem||document),u=l.elem||"img",f=l.scrollElem&&l.scrollElem!==document,y=function(e,l){var o,t=s.scrollTop(),l=t+l,i=f?e.offset().top-s.offset().top+t:e.offset().top;t<=i&&i<=l&&e.attr("lay-src")&&(o=e.attr("lay-src"),layui.img(o,function(){var l=c.lazyimg.elem.eq(m);e.attr("src",o).removeAttr("lay-src"),l[0]&&n(l),m++},function(){c.lazyimg.elem.eq(m);e.removeAttr("lay-src")}))},n=function(l,e){var o=(f?e||s:g(window)).height(),t=s.scrollTop(),i=t+o;if(c.lazyimg.elem=g(u),l)y(l,o);else for(var n=0;n"),preview:"Preview"}},x=function(e){return _.trim(e).replace(/^\n|\n$/,"")};e("code",function(e){var M=e=_.extend(!0,{},a,e);e.elem=_(e.elem),e.elem[0]&&layui.each(e.elem.get().reverse(),function(e,a){var t,l,i,o,n,s,c,d,r,u,y=_(a),E=_.extend(!0,{},M,lay.options(a),(t={},layui.each(["title","height","encode","skin","about"],function(e,a){var i=y.attr("lay-"+a);"string"==typeof i&&(t[a]=i)}),t)),p=y.data("code")||(i=[],y.children("textarea").each(function(){i.push(x(this.value))}),0===i.length&&i.push(x(y.html())),i),f=(y.data("code",p),{copy:{className:"file-b",title:["\u590d\u5236\u4ee3\u7801"],event:function(e,a){if("function"==typeof E.onCopy)E.onCopy(l);else try{navigator.clipboard.writeText(C.unescape(l)).then(function(){g.msg("\u5df2\u590d\u5236",{icon:1})})}catch(i){g.msg("\u590d\u5236\u5931\u8d25",{icon:2})}}}}),v=(E.preview&&(a="LAY-CODE-DF-"+e,r=E.layout||["code","preview"],o="iframe"===E.preview,L=_('
        '),d=_('
        '),n=_('
        '),u=_('
        '),s=_('
        '),m=y.parent("."+T.ELEM_PREVIEW),v=y.prev("."+T.ELEM_TAB),h=y.next("."+T.ELEM_ITEM+"-preview"),E.id&&L.attr("id",E.id),L.addClass(E.className),d.attr("lay-filter",a),E.encode=!0,layui.each(r,function(e,a){var i=_('
      • ');0===e&&i.addClass("layui-this"),i.html(E.text[a]),n.append(i)}),_.extend(f,{full:{className:"screen-full",title:["\u6700\u5927\u5316\u663e\u793a","\u8fd8\u539f\u663e\u793a"],event:function(e,a){var i=e.closest("."+T.ELEM_PREVIEW),t="layui-icon-"+this.className,l="layui-icon-screen-restore",o=this.title,n=_("html,body"),s="layui-scollbar-hide";e.hasClass(t)?(i.addClass(T.ELEM_FULL),e.removeClass(t).addClass(l),e.attr("title",o[1]),n.addClass(s)):(i.removeClass(T.ELEM_FULL),e.removeClass(l).addClass(t),e.attr("title",o[0]),n.removeClass(s))}},window:{className:"release",title:["\u5728\u65b0\u7a97\u53e3\u9884\u89c8"],event:function(e,a){C.openWin({content:l})}}}),E.copy&&("array"===layui.type(E.tools)?-1===E.tools.indexOf("copy")&&E.tools.unshift("copy"):E.tools=["copy"]),s.on("click",">i",function(){var e=_(this),a=e.data("type");"function"==typeof f[a].event&&f[a].event(e,a),"function"==typeof E.toolsEvent&&E.toolsEvent(e,a)}),layui.each(E.tools,function(e,a){var i=f[a]&&f[a].className||a,t=f[a].title||[""];s.append('')}),v[0]&&v.remove(),h[0]&&h.remove(),m[0]&&y.unwrap(),d.append(n),E.tools&&d.append(s),y.wrap(L).addClass(T.ELEM_ITEM).before(d),o&&u.html(''),c=function(e){var a=e.children("iframe")[0],i=(o&&a?a.srcdoc=p.join(""):e.html(p.join("")),{container:e,render:function(){b.render(e.find(".layui-form")),w.render()}});setTimeout(function(){"function"==typeof E.done&&E.done(i)},3)},"preview"===r[0]?(u.addClass(T.ELEM_SHOW),y.before(u),c(u)):y.addClass(T.ELEM_SHOW).after(u),E.codeStyle=[E.style,E.codeStyle].join(""),E.previewStyle=[E.style,E.previewStyle].join(""),u.attr("style",E.previewStyle),w.on("tab("+a+")",function(e){var a=_(this),i=_(e.elem).closest("."+T.ELEM_PREVIEW).find("."+T.ELEM_ITEM),e=i.eq(e.index);i.removeClass(T.ELEM_SHOW),e.addClass(T.ELEM_SHOW),"preview"===a.attr("lay-id")&&c(e)})),E.ln?"ol":"ul"),h=_("<"+v+' class="layui-code-'+v+'">'),m=_('
        '),L=(y.addClass("layui-code-view layui-box"),E.skin&&("notepad"===E.skin&&(E.skin="dark"),y.removeClass("layui-code-dark layui-code-light"),y.addClass("layui-code-"+E.skin)),l=p.join(""));"function"==typeof E.codeParse&&(L=l=E.codeParse(L)),L=(L=E.encode?C.escape(L):L).replace(/[\r\t\n]+/g,"
      • "),y.html(h.html("
      • "+L+"
      • ")),E.header&&!y.children("."+T.ELEM_TITLE)[0]&&(m.html((E.title||E.text.code)+(E.about?'
        '+E.about+"
        ":"")),y.prepend(m)),E.elem.length===e+1&&"function"==typeof E.allDone&&E.allDone(),0<(d=Math.floor(h.find("li").length/100))&&h.css("margin-left",d+"px"),E.height&&h.css("max-height",E.height),h.attr("style",E.codeStyle),E.copy&&!E.preview&&(r=_(['','',""].join("")),u=y.children("."+T.ELEM_COPY),(h[0].style.height||h[0].style.maxHeight)&&r.addClass(T.ELEM_COPY+"-offset"),u[0]&&u.remove(),y.append(r),r.on("click",function(){f.copy.event()}))})})}),layui["layui.all"]||layui.addcss("modules/code.css?v=3","skincodecss"); \ No newline at end of file +/** v2.9.10 | MIT Licensed */;!function(d){"use strict";var t,h=d.document,m={modules:{},status:{},timeout:10,event:{}},n=function(){this.v="2.9.10"},e=d.LAYUI_GLOBAL||{},v=(t=h.currentScript?h.currentScript.src:function(){for(var t,e=h.scripts,o=e.length-1,n=o;01e3*m.timeout/4?g(s+" is not a valid module","error"):void(m.status[s]?y():setTimeout(n,4))}())}function y(){e.push(layui[s]),11e3*m.timeout/4?g(s+" is not a valid module","error"):void("string"==typeof m.modules[s]&&m.status[s]?y():setTimeout(f,4))}():((r=h.createElement("script"))["async"]=!0,r.charset="utf-8",r.src=i+((u=!0===m.version?m.v||(new Date).getTime():m.version||"")?"?v="+u:""),l.appendChild(r),!r.attachEvent||r.attachEvent.toString&&r.attachEvent.toString().indexOf("[native code")<0||b?r.addEventListener("load",function(t){p(t,i)},!1):r.attachEvent("onreadystatechange",function(t){p(t,i)}),m.modules[s]=i)),a},n.prototype.disuse=function(t){var o=this;return t=o.isArray(t)?t:[t],o.each(t,function(t,e){m.status[e],delete o[e],delete N[e],delete o.modules[e],delete m.status[e],delete m.modules[e]}),o},n.prototype.getStyle=function(t,e){t=t.currentStyle||d.getComputedStyle(t,null);return t[t.getPropertyValue?"getPropertyValue":"getAttribute"](e)},n.prototype.link=function(o,n,t){var r=this,e=h.getElementsByTagName("head")[0],i=h.createElement("link"),a="layuicss-"+((t="string"==typeof n?n:t)||o).replace(/\.|\//g,""),u="creating",l=0;return i.href=o+(m.debug?"?v="+(new Date).getTime():""),i.rel="stylesheet",i.id=a,i.media="all",h.getElementById(a)||e.appendChild(i),"function"==typeof n&&function s(t){var e=h.getElementById(a);return++l>1e3*m.timeout/100?g(o+" timeout"):void(1989===parseInt(r.getStyle(e,"width"))?(t===u&&e.removeAttribute("lay-status"),e.getAttribute("lay-status")===u?setTimeout(s,100):n()):(e.setAttribute("lay-status",u),setTimeout(function(){s(u)},100)))}(),r},n.prototype.addcss=function(t,e,o){return layui.link(m.dir+"css/"+t,e,o)},m.callback={},n.prototype.factory=function(t){if(layui[t])return"function"==typeof m.callback[t]?m.callback[t]:null},n.prototype.img=function(t,e,o){var n=new Image;if(n.src=t,n.complete)return e(n);n.onload=function(){n.onload=null,"function"==typeof e&&e(n)},n.onerror=function(t){n.onerror=null,"function"==typeof o&&o(t)}},n.prototype.config=function(t){for(var e in t=t||{})m[e]=t[e];return this},n.prototype.modules=function(){var t,e={};for(t in N)e[t]=N[t];return e}(),n.prototype.extend=function(t){for(var e in t=t||{})this[e]||this.modules[e]?g(e+" Module already exists","error"):this.modules[e]=t[e];return this},n.prototype.router=n.prototype.hash=function(t){var o={path:[],search:{},hash:((t=t||location.hash).match(/[^#](#.*$)/)||[])[1]||""};return/^#\//.test(t)&&(t=t.replace(/^#\//,""),o.href="/"+t,t=t.replace(/([^#])(#.*$)/,"$1").split("/")||[],this.each(t,function(t,e){/^\w+=/.test(e)?(e=e.split("="),o.search[e[0]]=e[1]):o.path.push(e)})),o},n.prototype.url=function(t){var r,e,o=this;return{pathname:(t?((t.match(/\.[^.]+?\/.+/)||[])[0]||"").replace(/^[^\/]+/,"").replace(/\?.+/,""):location.pathname).replace(/^\//,"").split("/"),search:(r={},e=(t?((t.match(/\?.+/)||[])[0]||"").replace(/\#.+/,""):location.search).replace(/^\?+/,"").split("&"),o.each(e,function(t,e){var o=e.indexOf("="),n=o<0?e.substr(0,e.length):0!==o&&e.substr(0,o);n&&(r[n]=0(l.innerHeight||h.documentElement.clientHeight)},d.getStyleRules=function(t,n){if(t)return t=(t=t.sheet||t.styleSheet||{}).cssRules||t.rules,"function"==typeof n&&layui.each(t,function(t,e){if(n(e,t))return!0}),t},d.style=function(t){t=t||{};var e=d.elem("style"),n=t.text||"",i=t.target;if(n)return"styleSheet"in e?(e.setAttribute("type","text/css"),e.styleSheet.cssText=n):e.innerHTML=n,e.id="LAY-STYLE-"+(t.id||(n=d.style.index||0,d.style.index++,"DF-"+n)),i&&((t=d(i).find("#"+e.id))[0]&&t.remove(),d(i).append(e)),e},d.position=function(t,e,n){var i,o,r,c,u,a,s,f;e&&(n=n||{},t!==h&&t!==d("body")[0]||(n.clickType="right"),i="right"===n.clickType?{left:(i=n.e||l.event||{}).clientX,top:i.clientY,right:i.clientX,bottom:i.clientY}:t.getBoundingClientRect(),s=e.offsetWidth,f=e.offsetHeight,o=function(t){return h.body[t=t?"scrollLeft":"scrollTop"]|h.documentElement[t]},r=function(t){return h.documentElement[t?"clientWidth":"clientHeight"]},c="margin"in n?n.margin:5,u=i.left,a=i.bottom,"center"===n.align?u-=(s-t.offsetWidth)/2:"right"===n.align&&(u=u-s+t.offsetWidth),(u=u+s+c>r("width")?r("width")-s-c:u)r()&&(i.top>f+c&&i.top<=r()?a=i.top-f-2*c:n.allowBottomOut||(a=r()-f-2*c)<0&&(a=0)),(s=n.position)&&(e.style.position=s),e.style.left=u+("fixed"===s?0:o(1))+"px",e.style.top=a+("fixed"===s?0:o())+"px",d.hasScrollbar()||(f=e.getBoundingClientRect(),!n.SYSTEM_RELOAD&&f.bottom+c>r()&&(n.SYSTEM_RELOAD=!0,setTimeout(function(){d.position(t,e,n)},50))))},d.options=function(t,e){if(e="object"==typeof e?e:{attr:e},t===h)return{};var t=d(t),n=e.attr||"lay-options",t=t.attr(n);try{return new Function("return "+(t||"{}"))()}catch(i){return layui.hint().error(e.errorText||[n+'="'+t+'"',"\n parseerror: "+i].join("\n"),"error"),{}}},d.isTopElem=function(n){var t=[h,d("body")[0]],i=!1;return d.each(t,function(t,e){if(e===n)return i=!0}),i},d.clipboard={writeText:function(n){var i=String(n.text);function t(){var t=h.createElement("textarea");t.value=i,t.style.position="fixed",t.style.opacity="0",t.style.top="0px",t.style.left="0px",h.body.appendChild(t),t.select();try{h.execCommand("copy"),"function"==typeof n.done&&n.done()}catch(e){"function"==typeof n.error&&n.error(e)}finally{t.remove?t.remove():h.body.removeChild(t)}}navigator&&"clipboard"in navigator?navigator.clipboard.writeText(i).then(n.done,function(){t()}):t()}},d.passiveSupported=function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){t=!0}});l.addEventListener("test",null,e),l.removeEventListener("test",null,e)}catch(n){}return t}(),d.touchEventsSupported=function(){return"ontouchstart"in l},d.touchSwipe=function(t,e){var n,i,o,r=e,c=d(t)[0];c&&d.touchEventsSupported()&&(n={pointerStart:{x:0,y:0},pointerEnd:{x:0,y:0},distanceX:0,distanceY:0,direction:"none",timeStart:null},e=function(t){1===t.touches.length&&(c.addEventListener("touchmove",i,!!d.passiveSupported&&{passive:!1}),c.addEventListener("touchend",o),c.addEventListener("touchcancel",o),n.timeStart=Date.now(),n.pointerStart.x=n.pointerEnd.x=t.touches[0].clientX,n.pointerStart.y=n.pointerEnd.y=t.touches[0].clientY,n.distanceX=n.distanceY=0,n.direction="none",r.onTouchStart)&&r.onTouchStart(t,n)},i=function(t){t.preventDefault(),n.pointerEnd.x=t.touches[0].clientX,n.pointerEnd.y=t.touches[0].clientY,n.distanceX=n.pointerStart.x-n.pointerEnd.x,n.distanceY=n.pointerStart.y-n.pointerEnd.y,Math.abs(n.distanceX)>Math.abs(n.distanceY)?n.direction=0]|&(?=#[a-zA-Z0-9]+)/g.test(e+="")?e.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,"""):e}},i=function(e){return new RegExp(e,"g")},u=function(e,r){var n="Laytpl Error: ";return"object"==typeof console&&console.error(n+e+"\n"+(r||"")),n+e},n=function(e,r){var n=this,e=(n.config=n.config||{},n.template=e,function(e){for(var r in e)n.config[r]=e[r]});e(c),e(r)},r=(n.prototype.tagExp=function(e,r,n){var c=this.config;return i((r||"")+c.open+["#([\\s\\S])+?","([^{#}])*?"][e||0]+c.close+(n||""))},n.prototype.parse=function(e,r){var n=this,c=n.config,t=e,o=i("^"+c.open+"#",""),p=i(c.close+"$","");if("string"!=typeof e)return e;e='"use strict";var view = "'+(e=e.replace(/\s+|\r|\t|\n/g," ").replace(i(c.open+"#"),c.open+"# ").replace(i(c.close+"}"),"} "+c.close).replace(/\\/g,"\\\\").replace(i(c.open+"!(.+?)!"+c.close),function(e){return e=e.replace(i("^"+c.open+"!"),"").replace(i("!"+c.close),"").replace(i(c.open+"|"+c.close),function(e){return e.replace(/(.)/g,"\\$1")})}).replace(/(?="|')/g,"\\").replace(n.tagExp(),function(e){return'";'+(e=e.replace(o,"").replace(p,"")).replace(/\\(.)/g,"$1")+';view+="'}).replace(n.tagExp(1),function(e){var r='"+laytpl.escape(';return e.replace(/\s/g,"")===c.open+c.close?"":(e=e.replace(i(c.open+"|"+c.close),""),/^=/.test(e)?e=e.replace(/^=/,""):/^-/.test(e)&&(e=e.replace(/^-/,""),r='"+('),r+e.replace(/\\(.)/g,"$1")+')+"')}))+'";return view;';try{return n.cache=e=new Function("d, laytpl",e),e(r,l)}catch(a){return delete n.cache,u(a,t)}},n.prototype.render=function(e,r){e=e||{};var n=this,e=n.cache?n.cache(e,l):n.parse(n.template,e);return"function"==typeof r&&r(e),e},function(e,r){return new n(e,r)});r.config=function(e){for(var r in e=e||{})c[r]=e[r]},r.v="2.0.0",e("laytpl",r)});layui.define(function(e){"use strict";var r=document,u="getElementById",c="getElementsByTagName",a="layui-disabled",t=function(e){var a=this;a.config=e||{},a.config.index=++o.index,a.render(!0)},o=(t.prototype.type=function(){var e=this.config;if("object"==typeof e.elem)return e.elem.length===undefined?2:3},t.prototype.view=function(){var i,e,t,n=this.config,r=n.groups="groups"in n?Number(n.groups)||0:5,u=(n.layout="object"==typeof n.layout?n.layout:["prev","page","next"],n.count=Number(n.count)||0,n.curr=Number(n.curr)||1,n.limits="object"==typeof n.limits?n.limits:[10,20,30,40,50],n.limit=Number(n.limit)||10,n.pages=Math.ceil(n.count/n.limit)||1,n.curr>n.pages?n.curr=n.pages:n.curr<1&&(n.curr=1),r<0?r=1:r>n.pages&&(r=n.pages),n.prev="prev"in n?n.prev:"\u4e0a\u4e00\u9875",n.next="next"in n?n.next:"\u4e0b\u4e00\u9875",n.pages>r?Math.ceil((n.curr+(1'+n.prev+"":"",page:function(){var e=[];if(n.count<1)return"";1'+(n.first||1)+"");var a=Math.floor((r-1)/2),t=1n.pages?n.pages:a:r;for(i-t...');t<=i;t++)t===n.curr?e.push('"+t+""):e.push(''+t+"");return n.pages>r&&n.pages>i&&!1!==n.last&&(i+1...'),0!==r)&&e.push(''+(n.last||n.pages)+""),e.join("")}(),next:n.next?''+n.next+"":"",count:''+(e="object"==typeof n.countText?n.countText:["\u5171 "," \u6761"])[0]+n.count+e[1]+"",limit:(i=['"),refresh:['','',""].join(""),skip:[''+(e="object"==typeof n.skipText?n.skipText:["\u5230\u7b2c","\u9875","\u786e\u5b9a"])[0],'',e[1]+'",""].join("")};return['
        ',(t=[],layui.each(n.layout,function(e,a){l[a]&&t.push(l[a])}),t.join("")),"
        "].join("")},t.prototype.jump=function(e,a){if(e){var t=this,i=t.config,n=e.children,r=e[c]("button")[0],u=e[c]("input")[0],e=e[c]("select")[0],l=function(){var e=Number(u.value.replace(/\s|\D/g,""));e&&(i.curr=e,t.render())};if(a)return l();for(var s=0,p=n.length;si.pages||(i.curr=e,t.render())});e&&o.on(e,"change",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),r&&o.on(r,"click",function(){l()})}},t.prototype.skip=function(t){var i,e;t&&(i=this,e=t[c]("input")[0])&&o.on(e,"keyup",function(e){var a=this.value,e=e.keyCode;/^(37|38|39|40)$/.test(e)||(/\D/.test(a)&&(this.value=a.replace(/\D/,"")),13===e&&i.jump(t,!0))})},t.prototype.render=function(e){var a=this,t=a.config,i=a.type(),n=a.view(),i=(2===i?t.elem&&(t.elem.innerHTML=n):3===i?t.elem.html(n):r[u](t.elem)&&(r[u](t.elem).innerHTML=n),t.jump&&t.jump(t,e),r[u]("layui-laypage-"+t.index));a.jump(i),t.hash&&!e&&(location.hash="!"+t.hash+"="+t.curr),a.skip(i)},{render:function(e){return new t(e).index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(a,e,t){return a.attachEvent?a.attachEvent("on"+e,function(e){e.target=e.srcElement,t.call(a,e)}):a.addEventListener(e,t,!1),this}});e("laypage",o)});!function(i,D){"use strict";var n=i.layui&&layui.define,l={getPath:i.lay&&lay.getPath?lay.getPath:"",link:function(e,t,a){T.path&&i.lay&&lay.layui&&lay.layui.link(T.path+e,t,a)}},e=i.LAYUI_GLOBAL||{},a="laydate",d="lay-"+a+"-id",T={v:"5.6.0",config:{weekStart:0},index:i.laydate&&i.laydate.v?1e5:0,path:e.laydate_dir||l.getPath,set:function(e){var t=this;return t.config=lay.extend({},t.config,e),t},ready:function(e){var t="laydate",a=(n?"modules/":"")+"laydate.css?v="+T.v;return n?layui["layui.all"]?"function"==typeof e&&e():layui.addcss(a,e,t):l.link(a,e,t),this}},s=function(){var t=this,e=t.config.id;return(s.that[e]=t).inst={hint:function(e){t.hint.call(t,e)},reload:function(e){t.reload.call(t,e)},config:t.config}},C="layui-this",M="laydate-disabled",h=[100,2e5],v="layui-laydate-static",b="layui-laydate-list",o="laydate-selected",r="layui-laydate-hint",y="laydate-day-prev",m="laydate-day-next",L=".laydate-btns-confirm",E="laydate-time-text",I="laydate-btns-time",x="layui-laydate-preview",w="layui-laydate-shade",k=function(e){var t,a=this,n=(a.index=++T.index,a.config=lay.extend({},a.config,T.config,e),lay(e.elem||a.config.elem));return 1\u8bf7\u91cd\u65b0\u9009\u62e9",invalidDate:"\u4e0d\u5728\u6709\u6548\u65e5\u671f\u6216\u65f6\u95f4\u8303\u56f4\u5185",formatError:["\u65e5\u671f\u683c\u5f0f\u4e0d\u5408\u6cd5
        \u5fc5\u987b\u9075\u5faa\u4e0b\u8ff0\u683c\u5f0f\uff1a
        ","
        \u5df2\u4e3a\u4f60\u91cd\u7f6e"],preview:"\u5f53\u524d\u9009\u4e2d\u7684\u7ed3\u679c"},en:{weeks:["Su","Mo","Tu","We","Th","Fr","Sa"],time:["Hours","Minutes","Seconds"],timeTips:"Select Time",startTime:"Start Time",endTime:"End Time",dateTips:"Select Date",month:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],tools:{confirm:"Confirm",clear:"Clear",now:"Now"},timeout:"End time cannot be less than start Time
        Please re-select",invalidDate:"Invalid date",formatError:["The date format error
        Must be followed\uff1a
        ","
        It has been reset"],preview:"The selected result"}};return e[this.config.lang]||e.cn},k.prototype.markerOfChineseFestivals={"0-1-1":"\u5143\u65e6","0-2-14":"\u60c5\u4eba","0-3-8":"\u5987\u5973","0-3-12":"\u690d\u6811","0-4-1":"\u611a\u4eba","0-5-1":"\u52b3\u52a8","0-5-4":"\u9752\u5e74","0-6-1":"\u513f\u7ae5","0-9-10":"\u6559\u5e08","0-10-1":"\u56fd\u5e86","0-12-25":"\u5723\u8bde"},k.prototype.reload=function(e){this.config=lay.extend({},this.config,e),this.init()},k.prototype.init=function(){var r=this,o=r.config,e="static"===o.position,t={year:"yyyy",month:"yyyy-MM",date:"yyyy-MM-dd",time:"HH:mm:ss",datetime:"yyyy-MM-dd HH:mm:ss"};o.elem=lay(o.elem),o.eventElem=lay(o.eventElem),o.elem[0]&&("array"!==layui.type(o.theme)&&(o.theme=[o.theme]),o.fullPanel&&("datetime"!==o.type||o.range)&&delete o.fullPanel,r.rangeStr=o.range?"string"==typeof o.range?o.range:"-":"",r.rangeLinked=!(!o.range||!o.rangeLinked||"date"!==o.type&&"datetime"!==o.type),r.autoCalendarModel=function(){var e=r.rangeLinked;return r.rangeLinked=o.range&&("date"===o.type||"datetime"===o.type)&&(!r.startDate||!r.endDate||r.startDate&&r.endDate&&r.startDate.year===r.endDate.year&&r.startDate.month===r.endDate.month),lay(r.elem)[r.rangeLinked?"addClass":"removeClass"]("layui-laydate-linkage"),r.rangeLinked!=e},r.autoCalendarModel.auto=r.rangeLinked&&"auto"===o.rangeLinked,"array"===layui.type(o.range)&&(r.rangeElem=[lay(o.range[0]),lay(o.range[1])]),t[o.type]||(i.console&&console.error&&console.error("laydate type error:'"+o.type+"' is not supported"),o.type="date"),o.format===t.date&&(o.format=t[o.type]||t.date),r.format=s.formatArr(o.format),o.weekStart&&!/^[0-6]$/.test(o.weekStart)&&(t=r.lang(),o.weekStart=t.weeks.indexOf(o.weekStart),-1===o.weekStart)&&(o.weekStart=0),r.EXP_IF="",r.EXP_SPLIT="",lay.each(r.format,function(e,t){e=new RegExp(u).test(t)?"\\d{"+(new RegExp(u).test(r.format[0===e?e+1:e-1]||"")?/^yyyy|y$/.test(t)?4:t.length:/^yyyy$/.test(t)?"1,4":/^y$/.test(t)?"1,308":"1,2")+"}":"\\"+t;r.EXP_IF=r.EXP_IF+e,r.EXP_SPLIT=r.EXP_SPLIT+"("+e+")"}),r.EXP_IF_ONE=new RegExp("^"+r.EXP_IF+"$"),r.EXP_IF=new RegExp("^"+(o.range?r.EXP_IF+"\\s\\"+r.rangeStr+"\\s"+r.EXP_IF:r.EXP_IF)+"$"),r.EXP_SPLIT=new RegExp("^"+r.EXP_SPLIT+"$",""),r.isInput(o.elem[0])||"focus"===o.trigger&&(o.trigger="click"),o.elem.attr("lay-key",r.index),o.eventElem.attr("lay-key",r.index),o.elem.attr(d,o.id),lay.each(["min","max"],function(e,t){var a=[],n=[];if("number"==typeof o[t])var i=o[t],l=new Date,l=r.newDate({year:l.getFullYear(),month:l.getMonth(),date:l.getDate(),hours:e?23:0,minutes:e?59:0,seconds:e?59:0}).getTime(),e=new Date(i?i<864e5?l+864e5*i:i:l),a=[e.getFullYear(),e.getMonth()+1,e.getDate()],n=[e.getHours(),e.getMinutes(),e.getSeconds()];else if("string"==typeof o[t])a=(o[t].match(/\d+-\d+-\d+/)||[""])[0].split("-"),n=(o[t].match(/\d+:\d+:\d+/)||[""])[0].split(":");else if("object"==typeof o[t])return o[t];o[t]={year:0|a[0]||(new Date).getFullYear(),month:a[1]?(0|a[1])-1:(new Date).getMonth(),date:0|a[2]||(new Date).getDate(),hours:0|n[0],minutes:0|n[1],seconds:0|n[2]}}),r.elemID="layui-laydate"+o.elem.attr("lay-key"),(o.show||e)&&r.render(),e||r.events(),"function"==typeof o.formatToDisplay&&(r.isInput(o.elem[0])?r.formatToDisplay(o.elem[0],o.formatToDisplay):(t=r.rangeElem)&&(r.formatToDisplay(t[0][0],o.formatToDisplay),r.formatToDisplay(t[1][0],o.formatToDisplay))),o.value)&&o.isInitValue&&("date"===layui.type(o.value)?r.setValue(r.parse(0,r.systemDate(o.value))):r.setValue(o.value))},k.prototype.render=function(){var a,n,i,l,r=this,o=r.config,d=r.lang(),s="static"===o.position,y=r.elem=lay.elem("div",{id:r.elemID,"class":["layui-laydate",o.range?" layui-laydate-range":"",r.rangeLinked?" layui-laydate-linkage":"",s?" "+v:"",o.fullPanel?" laydate-theme-fullpanel":"",(a="",lay.each(o.theme,function(e,t){"default"===t||/^#/.test(t)||(a+=" laydate-theme-"+t)}),a)].join("")}),m=r.elemMain=[],u=r.elemHeader=[],c=r.elemCont=[],h=r.table=[],e=r.footer=lay.elem("div",{"class":"layui-laydate-footer"}),t=r.shortcut=lay.elem("ul",{"class":"layui-laydate-shortcut"}),p=(o.zIndex&&(y.style.zIndex=o.zIndex),lay.each(new Array(2),function(e){if(!o.range&&0'+d.timeTips+""),(o.range||"datetime"!==o.type||o.fullPanel)&&p.push(''),lay.each(o.btns,function(e,t){var a=d.tools[t]||"btn";o.range&&"now"===t||(s&&"clear"===t&&(a="cn"===o.lang?"\u91cd\u7f6e":"Reset"),n.push(''+a+""))}),p.push('"),p.join(""))),o.shortcuts&&(y.appendChild(t),lay(t).html((i=[],lay.each(o.shortcuts,function(e,t){i.push('
      • '+t.text+"
      • ")}),i.join(""))).find("li").on("click",function(e){var t=o.shortcuts[this.dataset.index]||{},t=("function"==typeof t.value?t.value():t.value)||[],n=(layui.isArray(t)||(t=[t]),o.type),t=(lay.each(t,function(e,t){var a=[o.dateTime,r.endDate][e];"time"===n&&"date"!==layui.type(t)?r.EXP_IF.test(t)&&(t=(t.match(r.EXP_SPLIT)||[]).slice(1),lay.extend(a,{hours:0|t[0],minutes:0|t[2],seconds:0|t[4]})):lay.extend(a,r.systemDate("date"===layui.type(t)?t:new Date(t))),"time"!==n&&"datetime"!==n||(r[["startTime","endTime"][e]]={hours:a.hours,minutes:a.minutes,seconds:a.seconds}),0===e?r.startDate=lay.extend({},a):r.endState=!0,"year"===n||"month"===n||"time"===n?r.listYM[e]=[a.year,a.month+1]:e&&r.autoCalendarModel.auto&&r.autoCalendarModel()}),r.checkDate("limit").calendar(null,null,"init"),lay(r.footer).find("."+I).removeClass(M));t&&"date"===t.attr("lay-type")&&t[0].click(),r.done(null,"change"),lay(this).addClass(C),"static"!==o.position&&r.setValue(r.parse()).done().remove()})),lay.each(m,function(e,t){y.appendChild(t)}),o.showBottom&&y.appendChild(e),lay.elem("style")),f=[],g=!0,t=(lay.each(o.theme,function(e,t){g&&/^#/.test(t)?(g=!(l=!0),f.push(["#{{id}} .layui-laydate-header{background-color:{{theme}};}","#{{id}} li.layui-this,#{{id}} td.layui-this>div{background-color:{{theme}} !important;}",-1!==o.theme.indexOf("circle")?"":"#{{id}} .layui-this{background-color:{{theme}} !important;}","#{{id}} .laydate-day-now{color:{{theme}} !important;}","#{{id}} .laydate-day-now:after{border-color:{{theme}} !important;}"].join("").replace(/{{id}}/g,r.elemID).replace(/{{theme}}/g,t))):!g&&/^#/.test(t)&&f.push(["#{{id}} .laydate-selected>div{background-color:{{theme}} !important;}","#{{id}} .laydate-selected:hover>div{background-color:{{theme}} !important;}"].join("").replace(/{{id}}/g,r.elemID).replace(/{{theme}}/g,t))}),o.shortcuts&&o.range&&f.push("#{{id}}.layui-laydate-range{width: 628px;}".replace(/{{id}}/g,r.elemID)),f.length&&(f=f.join(""),"styleSheet"in p?(p.setAttribute("type","text/css"),p.styleSheet.cssText=f):p.innerHTML=f,l&&lay(y).addClass("laydate-theme-molv"),y.appendChild(p)),r.remove(k.thisElemDate),T.thisId=o.id,s?o.elem.append(y):(D.body.appendChild(y),r.position()),o.shade?'
        ':"");y.insertAdjacentHTML("beforebegin",t),r.checkDate().calendar(null,0,"init"),r.changeEvent(),k.thisElemDate=r.elemID,r.renderAdditional(),"function"==typeof o.ready&&o.ready(lay.extend({},o.dateTime,{month:o.dateTime.month+1})),r.preview()},k.prototype.remove=function(e){var t=this,a=t.config,n=lay("#"+(e||t.elemID));return n[0]&&(n.hasClass(v)||t.checkDate(function(){n.remove(),delete t.startDate,delete t.endDate,delete t.endState,delete t.startTime,delete t.endTime,delete T.thisId,"function"==typeof a.close&&a.close(t)}),lay("."+w).remove()),t},k.prototype.position=function(){var e=this.config;return lay.position(e.elem[0],this.elem,{position:e.position}),this},k.prototype.hint=function(e){var t=this,a=(t.config,lay.elem("div",{"class":r}));t.elem&&(a.innerHTML=(e="object"==typeof e?e||{}:{content:e}).content||"",lay(t.elem).find("."+r).remove(),t.elem.appendChild(a),clearTimeout(t.hinTimer),t.hinTimer=setTimeout(function(){lay(t.elem).find("."+r).remove()},"ms"in e?e.ms:3e3))},k.prototype.getAsYM=function(e,t,a){return a?t--:t++,t<0&&(t=11,e--),11h[1]&&(e.year=h[1],o=!0),11t)&&(e.date=t,o=!0)},c=function(n,i,l){var r=["startTime","endTime"];i=(i.match(d.EXP_SPLIT)||[]).slice(1),l=l||0,s.range&&(d[r[l]]=d[r[l]]||{}),lay.each(d.format,function(e,t){var a=parseFloat(i[e]);i[e].lengthd.getDateTime(s.max)?(r=s.dateTime=lay.extend({},s.max),i=!0):d.getDateTime(r)d.getDateTime(s.max))&&(d.endDate=lay.extend({},s.max),i=!0),d.startTime={hours:s.dateTime.hours,minutes:s.dateTime.minutes,seconds:s.dateTime.seconds},d.endTime={hours:d.endDate.hours,minutes:d.endDate.minutes,seconds:d.endDate.seconds},"month"===s.type)&&(s.dateTime.date=1,d.endDate.date=1),i&&m&&(d.setValue(d.parse()),d.hint("value "+l.invalidDate+l.formatError[1])),d.startDate=d.startDate||m&&lay.extend({},s.dateTime),d.autoCalendarModel.auto&&d.autoCalendarModel(),d.endState=!s.range||!d.rangeLinked||!(!d.startDate||!d.endDate),e&&e()),d},k.prototype.markRender=function(e,a,t){var n;"object"==typeof t?lay.each(t||{},function(e,t){e=e.split("-");e[0]!=a[0]&&0!=e[0]||e[1]!=a[1]&&0!=e[1]||e[2]!=a[2]||(n=t||a[2])}):"string"==typeof t&&(n=t||a[2]),n&&e.find("div").html(''+n+"")},k.prototype.mark=function(t,a){var n=this,e=n.config,i=function(e){n.markRender(t,a,e)};return e.calendar&&"cn"===e.lang&&i(n.markerOfChineseFestivals),"function"==typeof e.mark?e.mark({year:a[0],month:a[1],date:a[2]},i):"object"==typeof e.mark&&i(e.mark),n},k.prototype.holidaysRender=function(r,o,e){var d=["holidays","workdays"],s=function(e,t,a){e.find("div").html(["",a,""].join(""))};"array"===layui.type(e)?lay.each(e,function(l,e){lay.each(e,function(e,t){var a,n,i;t=t,a=r.attr("lay-ymd"),n=t.split("-"),i=a.split("-"),lay.each(n,function(e,t){n[e]=parseInt(t,10)}),lay.each(i,function(e,t){i[e]=parseInt(t,10)}),n.join("-")===i.join("-")&&s(r,d[l],o[2])})}):"string"==typeof e&&-1!==d.indexOf(e)&&s(r,e,o[2])},k.prototype.holidays=function(t,a){var n=this,e=n.config,i=function(e){n.holidaysRender(t,a,e)};return"function"==typeof e.holidays?e.holidays({year:a[0],month:a[1],date:a[2]},i):"array"===layui.type(e.holidays)&&i(e.holidays),n},k.prototype.cellRender=function(t,e,a){var n=this.config;return"function"==typeof n.cellRender&&n.cellRender(e,function(e){"string"==typeof e?lay(t).html(e):"object"==typeof e&&lay(t).html("").append(lay(e)[0])},{originElem:t,type:a}),this},k.prototype.startOfYear=function(e){e=new Date(e);return e.setFullYear(e.getFullYear(),0,1),e.setHours(0,0,0,0),e},k.prototype.endOfYear=function(e){var e=new Date(e),t=e.getFullYear();return e.setFullYear(t+1,0,0),e.setHours(23,59,59,999),e},k.prototype.startOfMonth=function(e){e=new Date(e);return e.setDate(1),e.setHours(0,0,0,0),e},k.prototype.endOfMonth=function(e){var e=new Date(e),t=e.getMonth();return e.setFullYear(e.getFullYear(),t+1,0),e.setHours(23,59,59,999),e},k.prototype.addDays=function(e,t){e=new Date(e);return t&&e.setDate(e.getDate()+t),e},k.prototype.isDisabledYearOrMonth=function(e,t,a){for(var n=this,i=n.config,l="year"===t?n.startOfYear(e):n.startOfMonth(e),t="year"===t?n.endOfYear(e):n.endOfMonth(e),r=Math.floor((t.getTime()-l.getTime())/864e5)+1,o=0,d=0;d(t.time?0:41)?i.endDate:e.dateTime;return lay.each({now:lay.extend({},a,t.date||{}),min:e.min,max:e.max},function(e,a){var n;l[e]=i.newDate(lay.extend({year:a.year,month:"year"===t.type?0:a.month,date:"year"===t.type||"month"===t.type?1:a.date},(n={},lay.each(t.time,function(e,t){n[t]=a[t]}),n))).getTime()}),a=l.nowh[1]&&(s.year=h[1],d.hint(y.invalidDate)),d.firstDate||(d.firstDate=lay.extend({},s)),n.setFullYear(s.year,s.month,1),l=(n.getDay()+(7-a.weekStart))%7,r=T.getEndDate(s.month||12,s.year),o=T.getEndDate(s.month+1,s.year),lay.each(u,function(e,t){var a,n=[s.year,s.month];(t=lay(t)).removeAttr("class"),e"+n[2]+"
        "),d.mark(t,n).holidays(t,n).limit({elem:t,date:{year:n[0],month:n[1]-1,date:n[2]},index:e,rangeType:i,disabledType:"date"}),d.cellRender(t,{year:n[0],month:n[1],date:n[2]},"date")}),lay(c[0]).attr("lay-ym",s.year+"-"+(s.month+1)),lay(c[1]).attr("lay-ym",s.year+"-"+(s.month+1)),"cn"===a.lang?(lay(c[0]).attr("lay-type","year").html(s.year+" \u5e74"),lay(c[1]).attr("lay-type","month").html(s.month+1+" \u6708")):(lay(c[0]).attr("lay-type","month").html(y.month[s.month]),lay(c[1]).attr("lay-type","year").html(s.year)),m&&(a.range?!e&&"init"===t||(d.listYM=[[(d.startDate||a.dateTime).year,(d.startDate||a.dateTime).month+1],[d.endDate.year,d.endDate.month+1]],d.list(a.type,0).list(a.type,1),"time"===a.type?d.setBtnStatus("\u65f6\u95f4",lay.extend({},d.systemDate(),d.startTime),lay.extend({},d.systemDate(),d.endTime)):d.setBtnStatus(!0)):(d.listYM=[[s.year,s.month+1]],d.list(a.type,0))),a.range&&"init"===t&&(d.rangeLinked?(n=d.getAsYM(s.year,s.month,i?"sub":null),d.calendar(lay.extend({},s,{year:n[0],month:n[1]}),1-i)):d.calendar(null,1-i)),a.range||(u=["hours","minutes","seconds"],d.limit({elem:lay(d.footer).find(".laydate-btns-now"),date:d.systemDate(/^(datetime|time)$/.test(a.type)?new Date:null),index:0,time:u,disabledType:"datetime"}),d.limit({elem:lay(d.footer).find(L),index:0,time:u,disabledType:"datetime"})),d.setBtnStatus(),lay(d.shortcut).find("li."+C).removeClass(C),a.range&&!m&&"init"!==t&&d.stampRange(),d},k.prototype.list=function(n,i){var l,r,e,a,o,d,t,s=this,y=s.config,m=s.rangeLinked?y.dateTime:[y.dateTime,s.endDate][i],u=s.lang(),c=y.range&&"date"!==y.type&&"datetime"!==y.type,h=lay.elem("ul",{"class":b+" "+{year:"laydate-year-list",month:"laydate-month-list",time:"laydate-time-list"}[n]}),p=s.elemHeader[i],f=lay(p[2]).find("span"),g=s.elemCont[i||0],D=lay(g).find("."+b)[0],T="cn"===y.lang,v=T?"\u5e74":"",x=s.listYM[i]||{},w=["hours","minutes","seconds"],k=["startTime","endTime"][i];return x[0]<1&&(x[0]=1),"year"===n?(e=l=x[0]-7,l<1&&(e=l=1),lay.each(new Array(15),function(e){var t=lay.elem("li",{"lay-ym":l}),a={year:l,month:0,date:1};l==x[0]&&lay(t).addClass(C),t.innerHTML=l+v,h.appendChild(t),s.limit({elem:lay(t),date:a,index:i,type:n,rangeType:i,disabledType:"date"}),s.cellRender(t,{year:l,month:1,date:1},"year"),l++}),lay(f[T?0:1]).attr("lay-ym",l-8+"-"+x[1]).html(e+v+" - "+(l-1)+v)):"month"===n?(lay.each(new Array(12),function(e){var t=lay.elem("li",{"lay-ym":e}),a={year:x[0],month:e,date:1};e+1==x[1]&&lay(t).addClass(C),t.innerHTML=u.month[e]+(T?"\u6708":""),h.appendChild(t),s.limit({elem:lay(t),date:a,index:i,type:n,rangeType:i,disabledType:"date"}),s.cellRender(t,{year:x[0],month:e+1,date:1},"month")}),lay(f[T?0:1]).attr("lay-ym",x[0]+"-"+x[1]).html(x[0]+v)):"time"===n&&(r=function(){lay(h).find("ol").each(function(a,e){lay(e).find("li").each(function(e,t){s.limit({elem:lay(t),date:[{hours:e},{hours:s[k].hours,minutes:e},{hours:s[k].hours,minutes:s[k].minutes,seconds:e}][a],index:i,rangeType:i,disabledType:"time",time:[["hours"],["hours","minutes"],["hours","minutes","seconds"]][a]})})}),y.range||s.limit({elem:lay(s.footer).find(L),date:s[k],index:0,time:["hours","minutes","seconds"],disabledType:"datetime"})},y.range?s[k]||(s[k]="startTime"===k?m:s.endDate):s[k]=m,lay.each([24,60,60],function(t,e){var a=lay.elem("li"),n=["

        "+u.time[t]+"

          "];lay.each(new Array(e),function(e){n.push(""+lay.digit(e,2)+"")}),a.innerHTML=n.join("")+"
        ",h.appendChild(a)}),r(),e=-1!==y.format.indexOf("H"),f=-1!==y.format.indexOf("m"),t=-1!==y.format.indexOf("s"),a=h.children,o=0,lay.each([e,f,t],function(e,t){t||(a[e].className+=" layui-hide",o++)}),h.className+=" laydate-time-list-hide-"+o),D&&g.removeChild(D),g.appendChild(h),"year"===n||"month"===n?(lay(s.elemMain[i]).addClass("laydate-ym-show"),lay(h).find("li").on("click",function(){var e=0|lay(this).attr("lay-ym");lay(this).hasClass(M)||(s.rangeLinked?lay.extend(m,{year:"year"===n?e:x[0],month:"year"===n?x[1]-1:e}):m[n]=e,"year"===y.type||"month"===y.type?(lay(h).find("."+C).removeClass(C),lay(this).addClass(C),"month"===y.type&&"year"===n&&(s.listYM[i][0]=e,c&&((i?s.endDate:m).year=e),s.list("month",i))):(s.checkDate("limit").calendar(m,i,"init"),s.closeList()),s.setBtnStatus(),!y.range&&y.autoConfirm&&("month"===y.type&&"month"===n||"year"===y.type&&"year"===n)&&s.setValue(s.parse()).done().remove(),s.autoCalendarModel.auto&&!s.rangeLinked?s.choose(lay(g).find("td.layui-this"),i):s.endState&&s.done(null,"change"),lay(s.footer).find("."+I).removeClass(M))})):(f=lay.elem("span",{"class":E}),d=function(){lay(h).find("ol").each(function(e){var a=this,t=lay(a).find("li");a.scrollTop=30*(s[k][w[e]]-2),a.scrollTop<=0&&t.each(function(e,t){if(!lay(this).hasClass(M))return a.scrollTop=30*(e-2),!0})})},t=lay(p[2]).find("."+E),d(),f.innerHTML=y.range?[u.startTime,u.endTime][i]:u.timeTips,lay(s.elemMain[i]).addClass("laydate-time-show"),t[0]&&t.remove(),p[2].appendChild(f),(D=lay(h).find("ol")).each(function(t){var a=this;lay(a).find("li").on("click",function(){var e=0|this.innerHTML;lay(this).hasClass(M)||(y.range?s[k][w[t]]=e:m[w[t]]=e,lay(a).find("."+C).removeClass(C),lay(this).addClass(C),r(),d(),!s.endDate&&"time"!==y.type&&"datetime"!==y.type||s.done(null,"change"),s.setBtnStatus())})}),layui.device().mobile&&D.css({overflowY:"auto",touchAction:"pan-y"})),s},k.prototype.listYM=[],k.prototype.closeList=function(){var a=this;a.config;lay.each(a.elemCont,function(e,t){lay(this).find("."+b).remove(),lay(a.elemMain[e]).removeClass("laydate-ym-show laydate-time-show")}),lay(a.elem).find("."+E).remove()},k.prototype.setBtnStatus=function(e,t,a){var n=this,i=n.config,l=n.lang(),r=lay(n.footer).find(L),o="datetime"===i.type||"time"===i.type?["hours","minutes","seconds"]:undefined;i.range&&(t=t||(n.rangeLinked?n.startDate:i.dateTime),a=a||n.endDate,i=!n.endState||n.newDate(t).getTime()>n.newDate(a).getTime(),n.limit({date:t,disabledType:"datetime",time:o,rangeType:0})||n.limit({date:a,disabledType:"datetime",time:o,rangeType:1})?r.addClass(M):r[i?"addClass":"removeClass"](M),e)&&i&&n.hint("string"==typeof e?l.timeout.replace(/\u65e5\u671f/g,e):l.timeout)},k.prototype.parse=function(e,t){var a=this,n=a.config,i=a.rangeLinked?a.startDate:n.dateTime,t=t||("end"==e?lay.extend({},a.endDate,a.endTime):n.range?lay.extend({},i||n.dateTime,a.startTime):n.dateTime),i=T.parse(t,a.format,1);return n.range&&e===undefined?i+" "+a.rangeStr+" "+a.parse("end"):i},k.prototype.newDate=function(e){return e=e||{},new Date(e.year||1,e.month||0,e.date||1,e.hours||0,e.minutes||0,e.seconds||0)},k.prototype.getDateTime=function(e){return this.newDate(e).getTime()},k.prototype.formatToDisplay=function(e,t){var a=this,n=Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,"value");Object.defineProperty(e,"value",lay.extend({},n,{get:function(){return this.getAttribute("lay-date")},set:function(e){n.set.call(this,t.call(a,e)),this.setAttribute("lay-date",e)}}))},k.prototype.setValue=function(e){var t,a=this,n=a.config,i=n.elem[0];return"static"!==n.position&&(e=e||"",a.isInput(i)?lay(i).val(e):(t=a.rangeElem)?("array"!==layui.type(e)&&(e=e.split(" "+a.rangeStr+" ")),t[0].val(e[0]||""),t[1].val(e[1]||"")):(0===lay(i).find("*").length&&(t="function"==typeof n.formatToDisplay?n.formatToDisplay(e):e,lay(i).html(t)),lay(i).attr("lay-date",e))),a},k.prototype.preview=function(){var e,t=this,a=t.config;a.isPreview&&(e=lay(t.elem).find("."+x),a=!a.range||(t.rangeLinked?t.endState:t.endDate)?t.parse():"",e.html(a),e.html())&&(e.css({color:"#16b777"}),setTimeout(function(){e.css({color:"#777"})},300))},k.prototype.renderAdditional=function(){this.config.fullPanel&&this.list("time",0)},k.prototype.stampRange=function(){var n,i=this,l=i.config,r=i.rangeLinked?i.startDate:l.dateTime,e=lay(i.elem).find("td");l.range&&!i.endState&&lay(i.footer).find(L).addClass(M),r=r&&i.newDate({year:r.year,month:r.month,date:r.date}).getTime(),n=i.endState&&i.endDate&&i.newDate({year:i.endDate.year,month:i.endDate.month,date:i.endDate.date}).getTime(),lay.each(e,function(e,t){var a=lay(t).attr("lay-ymd").split("-"),a=i.newDate({year:a[0],month:a[1]-1,date:a[2]}).getTime();l.rangeLinked&&!i.startDate&&a===i.newDate(i.systemDate()).getTime()&&lay(t).addClass(lay(t).hasClass(y)||lay(t).hasClass(m)?"":"laydate-day-now"),lay(t).removeClass(o+" "+C),a!==r&&a!==n||(i.rangeLinked||!i.rangeLinked&&(e<42?a===r:a===n))&&lay(t).addClass(lay(t).hasClass(y)||lay(t).hasClass(m)?o:C),rn.getDateTime(i.max)&&(n[t]={hours:i.max.hours,minutes:i.max.minutes,seconds:i.max.seconds},lay.extend(l,n[t])))}),a||(n.startDate=lay.extend({},l)),n.endState&&!n.limit({date:n.rangeLinked?n.startDate:n.thisDateTime(1-a),disabledType:"date"})&&(((r=n.endState&&n.autoCalendarModel.auto?n.autoCalendarModel():r)||n.rangeLinked&&n.endState)&&n.newDate(n.startDate)>n.newDate(n.endDate)&&(n.startDate.year===n.endDate.year&&n.startDate.month===n.endDate.month&&n.startDate.date===n.endDate.date&&(o=n.startTime,n.startTime=n.endTime,n.endTime=o),o=n.startDate,n.startDate=lay.extend({},n.endDate,n.startTime),i.dateTime=lay.extend({},n.startDate),n.endDate=lay.extend({},o,n.endTime)),r)&&(i.dateTime=lay.extend({},n.startDate)),n.rangeLinked?(e=lay.extend({},l),!t||a||r||(o=n.getAsYM(l.year,l.month,"sub"),lay.extend(i.dateTime,{year:o[0],month:o[1]})),n.calendar(e,t,r?"init":null)):n.calendar(null,a,r?"init":null),n.endState&&n.done(null,"change")):"static"===i.position?n.calendar().done().done(null,"change"):"date"===i.type?i.autoConfirm?n.setValue(n.parse()).done().remove():n.calendar().done(null,"change"):"datetime"===i.type&&n.calendar().done(null,"change"))},k.prototype.tool=function(t,e){var a=this,n=a.config,i=a.lang(),l=n.dateTime,r="static"===n.position,o={datetime:function(){lay(t).hasClass(M)||(a.list("time",0),n.range&&a.list("time",1),lay(t).attr("lay-type","date").html(a.lang().dateTips))},date:function(){a.closeList(),lay(t).attr("lay-type","datetime").html(a.lang().timeTips)},clear:function(){r&&(lay.extend(l,a.firstDate),a.calendar()),n.range&&(delete n.dateTime,delete a.endDate,delete a.startTime,delete a.endTime),a.setValue(""),a.done(null,"onClear").done(["",{},{}]).remove()},now:function(){var e=new Date;if(lay(t).hasClass(M))return a.hint(i.tools.now+", "+i.invalidDate);lay.extend(l,a.systemDate(),{hours:e.getHours(),minutes:e.getMinutes(),seconds:e.getSeconds()}),a.setValue(a.parse()),r&&a.calendar(),a.done(null,"onNow").done().remove()},confirm:function(){if(n.range){if(lay(t).hasClass(M))return("time"===n.type?a.startTime&&a.endTime&&a.newDate(a.startTime)>a.newDate(a.endTime):a.startDate&&a.endDate&&a.newDate(lay.extend({},a.startDate,a.startTime||{}))>a.newDate(lay.extend({},a.endDate,a.endTime||{})))?a.hint("time"===n.type?i.timeout.replace(/\u65e5\u671f/g,"\u65f6\u95f4"):i.timeout):a.hint(i.invalidDate)}else if(lay(t).hasClass(M))return a.hint(i.invalidDate);a.setValue(a.parse()),a.done(null,"onConfirm").done().remove()}};o[e]&&o[e]()},k.prototype.change=function(n){var i=this,l=i.config,r=i.thisDateTime(n),o=l.range&&("year"===l.type||"month"===l.type),d=i.elemCont[n||0],s=i.listYM[n],e=function(e){var t=lay(d).find(".laydate-year-list")[0],a=lay(d).find(".laydate-month-list")[0];return t&&(s[0]=e?s[0]-15:s[0]+15,i.list("year",n)),a&&(e?s[0]--:s[0]++,i.list("month",n)),(t||a)&&(lay.extend(r,{year:s[0]}),o&&(r.year=s[0]),l.range||i.done(null,"change"),l.range||i.limit({elem:lay(i.footer).find(L),date:{year:s[0]},disabledType:"datetime"})),i.setBtnStatus(),t||a};return{prevYear:function(){e("sub")||(i.rangeLinked?(l.dateTime.year--,i.checkDate("limit").calendar(null,null,"init")):(r.year--,i.checkDate("limit").calendar(null,n),i.autoCalendarModel.auto?i.choose(lay(d).find("td.layui-this"),n):i.done(null,"change")))},prevMonth:function(){i.rangeLinked&&(r=l.dateTime);var e=i.getAsYM(r.year,r.month,"sub");lay.extend(r,{year:e[0],month:e[1]}),i.checkDate("limit").calendar(null,null,"init"),i.rangeLinked||(i.autoCalendarModel.auto?i.choose(lay(d).find("td.layui-this"),n):i.done(null,"change"))},nextMonth:function(){i.rangeLinked&&(r=l.dateTime);var e=i.getAsYM(r.year,r.month);lay.extend(r,{year:e[0],month:e[1]}),i.checkDate("limit").calendar(null,null,"init"),i.rangeLinked||(i.autoCalendarModel.auto?i.choose(lay(d).find("td.layui-this"),n):i.done(null,"change"))},nextYear:function(){e()||(i.rangeLinked?(l.dateTime.year++,i.checkDate("limit").calendar(null,0,"init")):(r.year++,i.checkDate("limit").calendar(null,n),i.autoCalendarModel.auto?i.choose(lay(d).find("td.layui-this"),n):i.done(null,"change")))}}},k.prototype.changeEvent=function(){var i=this;i.config;lay(i.elem).on("click",function(e){lay.stope(e)}).on("mousedown",function(e){lay.stope(e)}),lay.each(i.elemHeader,function(n,e){lay(e[0]).on("click",function(e){i.change(n).prevYear()}),lay(e[1]).on("click",function(e){i.change(n).prevMonth()}),lay(e[2]).find("span").on("click",function(e){var t=lay(this),a=t.attr("lay-ym"),t=t.attr("lay-type");a&&(a=a.split("-"),i.listYM[n]=[0|a[0],0|a[1]],i.list(t,n),lay(i.footer).find("."+I).addClass(M))}),lay(e[3]).on("click",function(e){i.change(n).nextMonth()}),lay(e[4]).on("click",function(e){i.change(n).nextYear()})}),lay.each(i.table,function(e,t){lay(t).find("td").on("click",function(){i.choose(lay(this),e)})}),lay(i.footer).find("span").on("click",function(){var e=lay(this).attr("lay-type");i.tool(this,e)})},k.prototype.isInput=function(e){return/input|textarea/.test(e.tagName.toLocaleLowerCase())||/INPUT|TEXTAREA/.test(e.tagName)},k.prototype.events=function(){var e,t=this,a=t.config;a.elem[0]&&!a.elem[0].eventHandler&&(a.elem.on(a.trigger,e=function(){T.thisId!==a.id&&t.render()}),a.elem[0].eventHandler=!0,a.eventElem.on(a.trigger,e),t.unbind=function(){t.remove(),a.elem.off(a.trigger,e),a.elem.removeAttr("lay-key"),a.elem.removeAttr(d),a.elem[0].eventHandler=!1,a.eventElem.off(a.trigger,e),a.eventElem.removeAttr("lay-key"),delete s.that[a.id]})},s.that={},s.getThis=function(e){var t=s.that[e];return!t&&n&&layui.hint().error(e?a+" instance with ID '"+e+"' not found":"ID argument required"),t},l.run=function(n){n(D).on("mousedown",function(e){var t,a;T.thisId&&(t=s.getThis(T.thisId))&&(a=t.config,e.target===a.elem[0]||e.target===a.eventElem[0]||e.target===n(a.closeStop)[0]||a.elem[0]&&a.elem[0].contains(e.target)||t.remove())}).on("keydown",function(e){var t;T.thisId&&(t=s.getThis(T.thisId))&&"static"!==t.config.position&&13===e.keyCode&&n("#"+t.elemID)[0]&&t.elemID===k.thisElemDate&&(e.preventDefault(),n(t.footer).find(L)[0].click())}),n(i).on("resize",function(){if(T.thisId){var e=s.getThis(T.thisId);if(e)return!(!e.elem||!n(".layui-laydate")[0])&&void e.position()}})},T.render=function(e){e=new k(e);return s.call(e)},T.reload=function(e,t){e=s.getThis(e);if(e)return e.reload(t)},T.getInst=function(e){e=s.getThis(e);if(e)return e.inst},T.hint=function(e,t){e=s.getThis(e);if(e)return e.hint(t)},T.unbind=function(e){e=s.getThis(e);if(e)return e.unbind()},T.close=function(e){e=s.getThis(e||T.thisId);if(e)return e.remove()},T.parse=function(a,n,i){return a=a||{},n=((n="string"==typeof n?s.formatArr(n):n)||[]).concat(),lay.each(n,function(e,t){/yyyy|y/.test(t)?n[e]=lay.digit(a.year,t.length):/MM|M/.test(t)?n[e]=lay.digit(a.month+(i||0),t.length):/dd|d/.test(t)?n[e]=lay.digit(a.date,t.length):/HH|H/.test(t)?n[e]=lay.digit(a.hours,t.length):/mm|m/.test(t)?n[e]=lay.digit(a.minutes,t.length):/ss|s/.test(t)&&(n[e]=lay.digit(a.seconds,t.length))}),n.join("")},T.getEndDate=function(e,t){var a=new Date;return a.setFullYear(t||a.getFullYear(),e||a.getMonth()+1,1),new Date(a.getTime()-864e5).getDate()},n?(T.ready(),layui.define("lay",function(e){T.path=layui.cache.dir,l.run(lay),e(a,T)})):"function"==typeof define&&define.amd?define(function(){return l.run(lay),T}):(T.ready(),l.run(i.lay),i.laydate=T)}(window,window.document);!function(e,t){"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e):function(e){if(e.document)return t(e);throw new Error("jQuery requires a window with a document")}:t(e)}("undefined"!=typeof window?window:this,function(T,M){var f=[],g=T.document,c=f.slice,O=f.concat,R=f.push,P=f.indexOf,B={},W=B.toString,m=B.hasOwnProperty,y={},e="1.12.4",C=function(e,t){return new C.fn.init(e,t)},I=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,$=/^-ms-/,z=/-([\da-z])/gi,X=function(e,t){return t.toUpperCase()};function U(e){var t=!!e&&"length"in e&&e.length,n=C.type(e);return"function"!==n&&!C.isWindow(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+a+")"+a+"*"),ee=new RegExp("="+a+"*([^\\]'\"]*?)"+a+"*\\]","g"),te=new RegExp(G),ne=new RegExp("^"+s+"$"),f={ID:new RegExp("^#("+s+")"),CLASS:new RegExp("^\\.("+s+")"),TAG:new RegExp("^("+s+"|[*])"),ATTR:new RegExp("^"+J),PSEUDO:new RegExp("^"+G),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+a+"*(even|odd|(([+-]|)(\\d*)n|)"+a+"*(?:([+-]|)"+a+"*(\\d+)|))"+a+"*\\)|)","i"),bool:new RegExp("^(?:"+Y+")$","i"),needsContext:new RegExp("^"+a+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+a+"*((?:-\\d)?\\d*)"+a+"*\\)|)(?=[^-]|$)","i")},re=/^(?:input|select|textarea|button)$/i,ie=/^h\d$/i,c=/^[^{]+\{\s*\[native \w/,oe=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ae=/[+~]/,se=/'|\\/g,d=new RegExp("\\\\([\\da-f]{1,6}"+a+"?|("+a+")|.)","ig"),p=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(65536+r):String.fromCharCode(r>>10|55296,1023&r|56320)},ue=function(){C()};try{D.apply(n=V.call(v.childNodes),v.childNodes),n[v.childNodes.length].nodeType}catch(F){D={apply:n.length?function(e,t){U.apply(e,V.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function H(e,t,n,r){var i,o,a,s,u,l,c,f,d=t&&t.ownerDocument,p=t?t.nodeType:9;if(n=n||[],"string"!=typeof e||!e||1!==p&&9!==p&&11!==p)return n;if(!r&&((t?t.ownerDocument||t:v)!==E&&C(t),t=t||E,N)){if(11!==p&&(l=oe.exec(e)))if(i=l[1]){if(9===p){if(!(a=t.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(d&&(a=d.getElementById(i))&&y(t,a)&&a.id===i)return n.push(a),n}else{if(l[2])return D.apply(n,t.getElementsByTagName(e)),n;if((i=l[3])&&g.getElementsByClassName&&t.getElementsByClassName)return D.apply(n,t.getElementsByClassName(i)),n}if(g.qsa&&!A[e+" "]&&(!m||!m.test(e))){if(1!==p)d=t,f=e;else if("object"!==t.nodeName.toLowerCase()){for((s=t.getAttribute("id"))?s=s.replace(se,"\\$&"):t.setAttribute("id",s=k),o=(c=w(e)).length,u=ne.test(s)?"#"+s:"[id='"+s+"']";o--;)c[o]=u+" "+_(c[o]);f=c.join(","),d=ae.test(e)&&de(t.parentNode)||t}if(f)try{return D.apply(n,d.querySelectorAll(f)),n}catch(h){}finally{s===k&&t.removeAttribute("id")}}}return P(e.replace(L,"$1"),t,n,r)}function le(){var n=[];function r(e,t){return n.push(e+" ")>b.cacheLength&&delete r[n.shift()],r[e+" "]=t}return r}function q(e){return e[k]=!0,e}function h(e){var t=E.createElement("div");try{return!!e(t)}catch(F){return!1}finally{t.parentNode&&t.parentNode.removeChild(t)}}function ce(e,t){for(var n=e.split("|"),r=n.length;r--;)b.attrHandle[n[r]]=t}function fe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||1<<31)-(~e.sourceIndex||1<<31);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function x(a){return q(function(o){return o=+o,q(function(e,t){for(var n,r=a([],e.length,o),i=r.length;i--;)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function de(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in g=H.support={},O=H.isXML=function(e){e=e&&(e.ownerDocument||e).documentElement;return!!e&&"HTML"!==e.nodeName},C=H.setDocument=function(e){var e=e?e.ownerDocument||e:v;return e!==E&&9===e.nodeType&&e.documentElement&&(t=(E=e).documentElement,N=!O(E),(e=E.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",ue,!1):e.attachEvent&&e.attachEvent("onunload",ue)),g.attributes=h(function(e){return e.className="i",!e.getAttribute("className")}),g.getElementsByTagName=h(function(e){return e.appendChild(E.createComment("")),!e.getElementsByTagName("*").length}),g.getElementsByClassName=c.test(E.getElementsByClassName),g.getById=h(function(e){return t.appendChild(e).id=k,!E.getElementsByName||!E.getElementsByName(k).length}),g.getById?(b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&N)return(e=t.getElementById(e))?[e]:[]},b.filter.ID=function(e){var t=e.replace(d,p);return function(e){return e.getAttribute("id")===t}}):(delete b.find.ID,b.filter.ID=function(e){var t=e.replace(d,p);return function(e){e="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return e&&e.value===t}}),b.find.TAG=g.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):g.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"!==e)return o;for(;n=o[i++];)1===n.nodeType&&r.push(n);return r},b.find.CLASS=g.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&N)return t.getElementsByClassName(e)},r=[],m=[],(g.qsa=c.test(E.querySelectorAll))&&(h(function(e){t.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&m.push("[*^$]="+a+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||m.push("\\["+a+"*(?:value|"+Y+")"),e.querySelectorAll("[id~="+k+"-]").length||m.push("~="),e.querySelectorAll(":checked").length||m.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||m.push(".#.+[+~]")}),h(function(e){var t=E.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&m.push("name"+a+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||m.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),m.push(",.*:")})),(g.matchesSelector=c.test(i=t.matches||t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.msMatchesSelector))&&h(function(e){g.disconnectedMatch=i.call(e,"div"),i.call(e,"[s!='']:x"),r.push("!=",G)}),m=m.length&&new RegExp(m.join("|")),r=r.length&&new RegExp(r.join("|")),e=c.test(t.compareDocumentPosition),y=e||c.test(t.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,t=t&&t.parentNode;return e===t||!(!t||1!==t.nodeType||!(n.contains?n.contains(t):e.compareDocumentPosition&&16&e.compareDocumentPosition(t)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},$=e?function(e,t){var n;return e===t?(l=!0,0):(n=!e.compareDocumentPosition-!t.compareDocumentPosition)||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!g.sortDetached&&t.compareDocumentPosition(e)===n?e===E||e.ownerDocument===v&&y(v,e)?-1:t===E||t.ownerDocument===v&&y(v,t)?1:u?j(u,e)-j(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===E?-1:t===E?1:i?-1:o?1:u?j(u,e)-j(u,t):0;if(i===o)return fe(e,t);for(n=e;n=n.parentNode;)a.unshift(n);for(n=t;n=n.parentNode;)s.unshift(n);for(;a[r]===s[r];)r++;return r?fe(a[r],s[r]):a[r]===v?-1:s[r]===v?1:0}),E},H.matches=function(e,t){return H(e,null,null,t)},H.matchesSelector=function(e,t){if((e.ownerDocument||e)!==E&&C(e),t=t.replace(ee,"='$1']"),g.matchesSelector&&N&&!A[t+" "]&&(!r||!r.test(t))&&(!m||!m.test(t)))try{var n=i.call(e,t);if(n||g.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(F){}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(d,p),e[3]=(e[3]||e[4]||e[5]||"").replace(d,p),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||H.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&H.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return f.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&te.test(n)&&(t=(t=w(n,!0))&&n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(d,p).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=W[e+" "];return t||(t=new RegExp("(^|"+a+")"+e+"("+a+"|$)"))&&W(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(t,n,r){return function(e){e=H.attr(e,t);return null==e?"!="===n:!n||(e+="","="===n?e===r:"!="===n?e!==r:"^="===n?r&&0===e.indexOf(r):"*="===n?r&&-1(?:<\/\1>|)$/,G=/^.[^:#\[\.,]*$/;function K(e,n,r){if(C.isFunction(n))return C.grep(e,function(e,t){return!!n.call(e,t,e)!==r});if(n.nodeType)return C.grep(e,function(e){return e===n!==r});if("string"==typeof n){if(G.test(n))return C.filter(n,e,r);n=C.filter(n,e)}return C.grep(e,function(e){return-1)[^>]*|#([\w-]*))$/,ee=((C.fn.init=function(e,t,n){if(e){if(n=n||Q,"string"!=typeof e)return e.nodeType?(this.context=this[0]=e,this.length=1,this):C.isFunction(e)?"undefined"!=typeof n.ready?n.ready(e):e(C):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),C.makeArray(e,this));if(!(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&3<=e.length?[null,e,null]:Z.exec(e))||!r[1]&&t)return(!t||t.jquery?t||n:this.constructor(t)).find(e);if(r[1]){if(t=t instanceof C?t[0]:t,C.merge(this,C.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:g,!0)),J.test(r[1])&&C.isPlainObject(t))for(var r in t)C.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r])}else{if((n=g.getElementById(r[2]))&&n.parentNode){if(n.id!==r[2])return Q.find(e);this.length=1,this[0]=n}this.context=g,this.selector=e}}return this}).prototype=C.fn,Q=C(g),/^(?:parents|prev(?:Until|All))/),te={children:!0,contents:!0,next:!0,prev:!0};function ne(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}C.fn.extend({has:function(e){var t,n=C(e,this),r=n.length;return this.filter(function(){for(t=0;t
        a",y.leadingWhitespace=3===S.firstChild.nodeType,y.tbody=!S.getElementsByTagName("tbody").length,y.htmlSerialize=!!S.getElementsByTagName("link").length,y.html5Clone="<:nav>"!==g.createElement("nav").cloneNode(!0).outerHTML,q.type="checkbox",q.checked=!0,k.appendChild(q),y.appendChecked=q.checked,S.innerHTML="",y.noCloneChecked=!!S.cloneNode(!0).lastChild.defaultValue,k.appendChild(S),(q=g.createElement("input")).setAttribute("type","radio"),q.setAttribute("checked","checked"),q.setAttribute("name","t"),S.appendChild(q),y.checkClone=S.cloneNode(!0).cloneNode(!0).lastChild.checked,y.noCloneEvent=!!S.addEventListener,S[C.expando]=1,y.attributes=!S.getAttribute(C.expando);var x={option:[1,""],legend:[1,"
        ","
        "],area:[1,"",""],param:[1,"",""],thead:[1,"","
        "],tr:[2,"","
        "],col:[2,"","
        "],td:[3,"","
        "],_default:y.htmlSerialize?[0,"",""]:[1,"X
        ","
        "]};function b(e,t){var n,r,i=0,o="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):undefined;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||C.nodeName(r,t)?o.push(r):C.merge(o,b(r,t));return t===undefined||t&&C.nodeName(e,t)?C.merge([e],o):o}function we(e,t){for(var n,r=0;null!=(n=e[r]);r++)C._data(n,"globalEval",!t||C._data(t[r],"globalEval"))}x.optgroup=x.option,x.tbody=x.tfoot=x.colgroup=x.caption=x.thead,x.th=x.td;var Te=/<|&#?\w+;/,Ce=/"!==f[1]||Ce.test(a)?0:u:u.firstChild)&&a.childNodes.length;o--;)C.nodeName(c=a.childNodes[o],"tbody")&&!c.childNodes.length&&a.removeChild(c);for(C.merge(h,u.childNodes),u.textContent="";u.firstChild;)u.removeChild(u.firstChild);u=p.lastChild}else h.push(t.createTextNode(a));for(u&&p.removeChild(u),y.appendChecked||C.grep(b(h,"input"),Ee),g=0;a=h[g++];)if(r&&-1]","i"),Pe=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,Be=/\s*$/g,ze=be(g).appendChild(g.createElement("div"));function Xe(e,t){return C.nodeName(e,"table")&&C.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ue(e){return e.type=(null!==C.find.attr(e,"type"))+"/"+e.type,e}function Ve(e){var t=Ie.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Ye(e,t){if(1===t.nodeType&&C.hasData(e)){var n,r,i,e=C._data(e),o=C._data(t,e),a=e.events;if(a)for(n in delete o.handle,o.events={},a)for(r=0,i=a[n].length;r")},clone:function(e,t,n){var r,i,o,a,s,u=C.contains(e.ownerDocument,e);if(y.html5Clone||C.isXMLDoc(e)||!Re.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(ze.innerHTML=e.outerHTML,ze.removeChild(o=ze.firstChild)),!(y.noCloneEvent&&y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||C.isXMLDoc(e)))for(r=b(o),s=b(e),a=0;null!=(i=s[a]);++a)if(r[a]){f=c=l=p=d=void 0;var l,c,f,d=i,p=r[a];if(1===p.nodeType){if(l=p.nodeName.toLowerCase(),!y.noCloneEvent&&p[C.expando]){for(c in(f=C._data(p)).events)C.removeEvent(p,c,f.handle);p.removeAttribute(C.expando)}"script"===l&&p.text!==d.text?(Ue(p).text=d.text,Ve(p)):"object"===l?(p.parentNode&&(p.outerHTML=d.outerHTML),y.html5Clone&&d.innerHTML&&!C.trim(p.innerHTML)&&(p.innerHTML=d.innerHTML)):"input"===l&&ge.test(d.type)?(p.defaultChecked=p.checked=d.checked,p.value!==d.value&&(p.value=d.value)):"option"===l?p.defaultSelected=p.selected=d.defaultSelected:"input"!==l&&"textarea"!==l||(p.defaultValue=d.defaultValue)}}if(t)if(n)for(s=s||b(e),r=r||b(o),a=0;null!=(i=s[a]);a++)Ye(i,r[a]);else Ye(e,o);return 0<(r=b(o,"script")).length&&we(r,!u&&b(e,"script")),r=s=i=null,o},cleanData:function(e,t){for(var n,r,i,o,a=0,s=C.expando,u=C.cache,l=y.attributes,c=C.event.special;null!=(n=e[a]);a++)if((t||v(n))&&(o=(i=n[s])&&u[i])){if(o.events)for(r in o.events)c[r]?C.event.remove(n,r):C.removeEvent(n,r,o.handle);u[i]&&(delete u[i],l||"undefined"==typeof n.removeAttribute?n[s]=undefined:n.removeAttribute(s),f.push(i))}}}),C.fn.extend({domManip:w,detach:function(e){return Je(this,e,!0)},remove:function(e){return Je(this,e)},text:function(e){return d(this,function(e){return e===undefined?C.text(this):this.empty().append((this[0]&&this[0].ownerDocument||g).createTextNode(e))},null,e,arguments.length)},append:function(){return w(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Xe(this,e).appendChild(e)})},prepend:function(){return w(this,arguments,function(e){var t;1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(t=Xe(this,e)).insertBefore(e,t.firstChild)})},before:function(){return w(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return w(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++){for(1===e.nodeType&&C.cleanData(b(e,!1));e.firstChild;)e.removeChild(e.firstChild);e.options&&C.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return C.clone(this,e,t)})},html:function(e){return d(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined)return 1===t.nodeType?t.innerHTML.replace(Oe,""):undefined;if("string"==typeof e&&!Be.test(e)&&(y.htmlSerialize||!Re.test(e))&&(y.leadingWhitespace||!ve.test(e))&&!x[(me.exec(e)||["",""])[1].toLowerCase()]){e=C.htmlPrefilter(e);try{for(;n")).appendTo(t.documentElement))[0].contentWindow||Ge[0].contentDocument).document).write(),t.close(),n=Qe(e,t),Ge.detach()),Ke[e]=n),n}var n,et,tt,nt,rt,it,ot,a,at=/^margin/,st=new RegExp("^("+e+")(?!px)[a-z%]+$","i"),ut=function(e,t,n,r){var i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.apply(e,r||[]),t)e.style[i]=o[i];return r},lt=g.documentElement;function t(){var e,t=g.documentElement;t.appendChild(ot),a.style.cssText="-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",n=tt=it=!1,et=rt=!0,T.getComputedStyle&&(e=T.getComputedStyle(a),n="1%"!==(e||{}).top,it="2px"===(e||{}).marginLeft,tt="4px"===(e||{width:"4px"}).width,a.style.marginRight="50%",et="4px"===(e||{marginRight:"4px"}).marginRight,(e=a.appendChild(g.createElement("div"))).style.cssText=a.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",e.style.marginRight=e.style.width="0",a.style.width="1px",rt=!parseFloat((T.getComputedStyle(e)||{}).marginRight),a.removeChild(e)),a.style.display="none",(nt=0===a.getClientRects().length)&&(a.style.display="",a.innerHTML="
        t
        ",a.childNodes[0].style.borderCollapse="separate",(e=a.getElementsByTagName("td"))[0].style.cssText="margin:0;border:0;padding:0;display:none",nt=0===e[0].offsetHeight)&&(e[0].style.display="",e[1].style.display="none",nt=0===e[0].offsetHeight),t.removeChild(ot)}ot=g.createElement("div"),(a=g.createElement("div")).style&&(a.style.cssText="float:left;opacity:.5",y.opacity="0.5"===a.style.opacity,y.cssFloat=!!a.style.cssFloat,a.style.backgroundClip="content-box",a.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===a.style.backgroundClip,(ot=g.createElement("div")).style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",a.innerHTML="",ot.appendChild(a),y.boxSizing=""===a.style.boxSizing||""===a.style.MozBoxSizing||""===a.style.WebkitBoxSizing,C.extend(y,{reliableHiddenOffsets:function(){return null==n&&t(),nt},boxSizingReliable:function(){return null==n&&t(),tt},pixelMarginRight:function(){return null==n&&t(),et},pixelPosition:function(){return null==n&&t(),n},reliableMarginRight:function(){return null==n&&t(),rt},reliableMarginLeft:function(){return null==n&&t(),it}}));var l,p,ct=/^(top|right|bottom|left)$/;function ft(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}T.getComputedStyle?(l=function(e){var t=e.ownerDocument.defaultView;return(t=t&&t.opener?t:T).getComputedStyle(e)},p=function(e,t,n){var r,i,o=e.style;return""!==(i=(n=n||l(e))?n.getPropertyValue(t)||n[t]:undefined)&&i!==undefined||C.contains(e.ownerDocument,e)||(i=C.style(e,t)),n&&!y.pixelMarginRight()&&st.test(i)&&at.test(t)&&(e=o.width,t=o.minWidth,r=o.maxWidth,o.minWidth=o.maxWidth=o.width=i,i=n.width,o.width=e,o.minWidth=t,o.maxWidth=r),i===undefined?i:i+""}):lt.currentStyle&&(l=function(e){return e.currentStyle},p=function(e,t,n){var r,i,o,a=e.style;return null==(n=(n=n||l(e))?n[t]:undefined)&&a&&a[t]&&(n=a[t]),st.test(n)&&!ct.test(t)&&(r=a.left,(o=(i=e.runtimeStyle)&&i.left)&&(i.left=e.currentStyle.left),a.left="fontSize"===t?"1em":n,n=a.pixelLeft+"px",a.left=r,o)&&(i.left=o),n===undefined?n:n+""||"auto"});var dt=/alpha\([^)]*\)/i,pt=/opacity\s*=\s*([^)]*)/i,ht=/^(none|table(?!-c[ea]).+)/,gt=new RegExp("^("+e+")(.*)$","i"),mt={position:"absolute",visibility:"hidden",display:"block"},yt={letterSpacing:"0",fontWeight:"400"},vt=["Webkit","O","Moz","ms"],xt=g.createElement("div").style;function bt(e){if(e in xt)return e;for(var t=e.charAt(0).toUpperCase()+e.slice(1),n=vt.length;n--;)if((e=vt[n]+t)in xt)return e}function wt(e,t){for(var n,r,i,o=[],a=0,s=e.length;a
        a",F=q.getElementsByTagName("a")[0],k.setAttribute("type","checkbox"),q.appendChild(k),(F=q.getElementsByTagName("a")[0]).style.cssText="top:1px",y.getSetAttribute="t"!==q.className,y.style=/top/.test(F.getAttribute("style")),y.hrefNormalized="/a"===F.getAttribute("href"),y.checkOn=!!k.value,y.optSelected=e.selected,y.enctype=!!g.createElement("form").enctype,S.disabled=!0,y.optDisabled=!e.disabled,(k=g.createElement("input")).setAttribute("value",""),y.input=""===k.getAttribute("value"),k.value="t",k.setAttribute("type","radio"),y.radioValue="t"===k.value;var Lt=/\r/g,Ht=/[\x20\t\r\n\f]+/g;C.fn.extend({val:function(t){var n,e,r,i=this[0];return arguments.length?(r=C.isFunction(t),this.each(function(e){1!==this.nodeType||(null==(e=r?t.call(this,e,C(this).val()):t)?e="":"number"==typeof e?e+="":C.isArray(e)&&(e=C.map(e,function(e){return null==e?"":e+""})),(n=C.valHooks[this.type]||C.valHooks[this.nodeName.toLowerCase()])&&"set"in n&&n.set(this,e,"value")!==undefined)||(this.value=e)})):i?(n=C.valHooks[i.type]||C.valHooks[i.nodeName.toLowerCase()])&&"get"in n&&(e=n.get(i,"value"))!==undefined?e:"string"==typeof(e=i.value)?e.replace(Lt,""):null==e?"":e:void 0}}),C.extend({valHooks:{option:{get:function(e){var t=C.find.attr(e,"value");return null!=t?t:C.trim(C.text(e)).replace(Ht," ")}},select:{get:function(e){for(var t,n=e.options,r=e.selectedIndex,i="select-one"===e.type||r<0,o=i?null:[],a=i?r+1:n.length,s=r<0?a:i?r:0;s").append(C.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this)},C.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){C.fn[t]=function(e){return this.on(t,e)}}),C.expr.filters.animated=function(t){return C.grep(C.timers,function(e){return t===e.elem}).length},C.offset={setOffset:function(e,t,n){var r,i,o,a,s=C.css(e,"position"),u=C(e),l={};"static"===s&&(e.style.position="relative"),o=u.offset(),r=C.css(e,"top"),a=C.css(e,"left"),s=("absolute"===s||"fixed"===s)&&-1'+(s?a.title[0]:a.title)+"
        ":"";return a.zIndex=o,t([a.shade?'
        ':"",'
        '+(e&&2!=a.type?"":s)+"'+(n=["layui-icon-tips","layui-icon-success","layui-icon-error","layui-icon-question","layui-icon-lock","layui-icon-face-cry","layui-icon-face-smile"],o="layui-anim layui-anim-rotate layui-anim-loop",0==a.type&&-1!==a.icon?'':3==a.type?(i=["layui-icon-loading","layui-icon-loading-1"],2==a.icon?'
        ':''):"")+((1!=a.type||!e)&&a.content||"")+'
        '+(n=[],r&&(n.push(''),n.push('')),a.closeBtn&&n.push(''),n.join(""))+"
        "+(a.btn?function(){var e="";"string"==typeof a.btn&&(a.btn=[a.btn]);for(var t,i=0,n=a.btn.length;i'+a.btn[i]+"";return'
        '+e+"
        "}():"")+(a.resize?'':"")+"
        "],s,m('
        ')),this},t.pt.creat=function(){var e,t,i,n,a=this,o=a.config,s=a.index,r="object"==typeof(f=o.content),l=m("body"),c=function(e){var t;o.shift&&(o.anim=o.shift),u.anim[o.anim]&&(t="layer-anim "+u.anim[o.anim],e.addClass(t).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",function(){m(this).removeClass(t)}))};if(o.id&&m("."+u[0]).find("#"+o.id)[0])e=m("#"+o.id).closest("."+u[0]),t=e.attr("times"),i=e.data("config"),n=m("#"+u.SHADE+t),"min"===(e.data("maxminStatus")||{})?v.restore(t):i.hideOnClose&&(n.show(),e.show(),c(e),setTimeout(function(){n.css({opacity:n.data(y)})},10));else{switch(o.removeFocus&&document.activeElement.blur(),"string"==typeof o.area&&(o.area="auto"===o.area?["",""]:[o.area,""]),6==v.ie&&(o.fixed=!1),o.type){case 0:o.btn="btn"in o?o.btn:d.btn[0],v.closeAll("dialog");break;case 2:var f=o.content=r?o.content:[o.content||"","auto"];o.content='';break;case 3:delete o.title,delete o.closeBtn,-1===o.icon&&o.icon,v.closeAll("loading");break;case 4:r||(o.content=[o.content,"body"]),o.follow=o.content[1],o.content=o.content[0]+'',delete o.title,o.tips="object"==typeof o.tips?o.tips:[o.tips,!0],o.tipsMore||v.closeAll("tips")}a.vessel(r,function(e,t,i){l.append(e[0]),r?2==o.type||4==o.type?m("body").append(e[1]):f.parents("."+u[0])[0]||(f.data("display",f.css("display")).show().addClass("layui-layer-wrap").wrap(e[1]),m("#"+u[0]+s).find("."+u[5]).before(t)):l.append(e[1]),m("#"+u.MOVE)[0]||l.append(d.moveElem=i),a.layero=m("#"+u[0]+s),a.shadeo=m("#"+u.SHADE+s),o.scrollbar||d.setScrollbar(s)}).auto(s),a.shadeo.css({"background-color":o.shade[1]||"#000",opacity:o.shade[0]||o.shade,transition:o.shade[2]||""}),a.shadeo.data(y,o.shade[0]||o.shade),2==o.type&&6==v.ie&&a.layero.find("iframe").attr("src",f[0]),4==o.type?a.tips():(a.offset(),parseInt(d.getStyle(document.getElementById(u.MOVE),"z-index"))||(a.layero.css("visibility","hidden"),v.ready(function(){a.offset(),a.layero.css("visibility","visible")}))),!o.fixed||d.events.resize[a.index]||(d.events.resize[a.index]=function(){a.resize()},g.on("resize",d.events.resize[a.index])),o.time<=0||setTimeout(function(){v.close(a.index)},o.time),a.move().callback(),c(a.layero),a.layero.data("config",o)}},t.pt.resize=function(){var e=this,t=e.config;e.offset(),(/^\d+%$/.test(t.area[0])||/^\d+%$/.test(t.area[1]))&&e.auto(e.index),4==t.type&&e.tips()},t.pt.auto=function(e){var t=this.config,i=m("#"+u[0]+e),n=(""===t.area[0]&&0t.maxWidth)&&i.width(t.maxWidth),[i.innerWidth(),i.innerHeight()]),a=i.find(u[1]).outerHeight()||0,o=i.find("."+u[6]).outerHeight()||0,e=function(e){(e=i.find(e)).height(n[1]-a-o-2*(0|parseFloat(e.css("padding-top"))))};return 2===t.type?e("iframe"):""===t.area[1]?0t.maxHeight?(n[1]=t.maxHeight,e("."+u[5])):t.fixed&&n[1]>=g.height()&&(n[1]=g.height(),e("."+u[5])):e("."+u[5]),this},t.pt.offset=function(){var e=this,t=e.config,i=e.layero,n=[i.outerWidth(),i.outerHeight()],a="object"==typeof t.offset;e.offsetTop=(g.height()-n[1])/2,e.offsetLeft=(g.width()-n[0])/2,a?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):"auto"!==t.offset&&("t"===t.offset?e.offsetTop=0:"r"===t.offset?e.offsetLeft=g.width()-n[0]:"b"===t.offset?e.offsetTop=g.height()-n[1]:"l"===t.offset?e.offsetLeft=0:"lt"===t.offset?(e.offsetTop=0,e.offsetLeft=0):"lb"===t.offset?(e.offsetTop=g.height()-n[1],e.offsetLeft=0):"rt"===t.offset?(e.offsetTop=0,e.offsetLeft=g.width()-n[0]):"rb"===t.offset?(e.offsetTop=g.height()-n[1],e.offsetLeft=g.width()-n[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?g.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?g.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=g.scrollTop(),e.offsetLeft+=g.scrollLeft()),"min"===i.data("maxminStatus")&&(e.offsetTop=g.height()-(i.find(u[1]).outerHeight()||0),e.offsetLeft=i.css("left")),i.css({top:e.offsetTop,left:e.offsetLeft})},t.pt.tips=function(){var e=this.config,t=this.layero,i=[t.outerWidth(),t.outerHeight()],n=m(e.follow),a={width:(n=n[0]?n:m("body")).outerWidth(),height:n.outerHeight(),top:n.offset().top,left:n.offset().left},o=t.find(".layui-layer-TipsG"),n=e.tips[0];e.tips[1]||o.remove(),a.autoLeft=function(){0g.width()&&(o=g.width()-180-(d.minStackArr.edgeIndex=d.minStackArr.edgeIndex||0,d.minStackArr.edgeIndex+=3))<0&&(o=0),t.minStack&&(r.left=o,r.top=g.height()-n,a||d.minStackIndex++,l.attr("minLeft",o)),l.attr("position",s),v.style(e,r,!0),i.hide(),"page"===l.attr("type")&&l.find(u[4]).hide(),d.restScrollbar(e),c.hide())},v.restore=function(e){var t=m("#"+u[0]+e),i=m("#"+u.SHADE+e),n=t.find(".layui-layer-content"),a=t.attr("area").split(","),o=t.attr("type"),s=t.data("config")||{},r=n.data(l);t.removeData("maxminStatus"),v.style(e,{width:a[0],height:a[1],top:parseFloat(a[2]),left:parseFloat(a[3]),position:t.attr("position"),overflow:"visible"},!0),t.find(".layui-layer-max").removeClass("layui-layer-maxmin"),t.find(".layui-layer-min").show(),"page"===o&&t.find(u[4]).show(),s.scrollbar?d.restScrollbar(e):d.setScrollbar(e),r!==h&&(n.removeData(l),(o===d.type[2]?n.children("iframe"):n).css({height:r})),i.show()},v.full=function(t){var i=m("#"+u[0]+t),e=i.data("maxminStatus");"max"!==e&&("min"===e&&v.restore(t),i.data("maxminStatus","max"),d.record(i),u.html.attr("layer-full")||d.setScrollbar(t),setTimeout(function(){var e="fixed"===i.css("position");v.style(t,{top:e?0:g.scrollTop(),left:e?0:g.scrollLeft(),width:"100%",height:"100%"},!0),i.find(".layui-layer-min").hide()},100))},v.title=function(e,t){m("#"+u[0]+(t||v.index)).find(u[1]).html(e)},v.close=function(o,s){var r,e,t,l=(i=m("."+u[0]).children("#"+o).closest("."+u[0]))[0]?(o=i.attr("times"),i):m("#"+u[0]+o),c=l.attr("type"),i=l.data("config")||{},f=i.id&&i.hideOnClose;l[0]&&(r={slideDown:"layer-anim-slide-down-out",slideLeft:"layer-anim-slide-left-out",slideUp:"layer-anim-slide-up-out",slideRight:"layer-anim-slide-right-out"}[i.anim]||"layer-anim-close",e=function(){var e="layui-layer-wrap";if(f)return l.removeClass("layer-anim "+r),l.hide();if(c===d.type[1]&&"object"===l.attr("conType")){l.children(":not(."+u[5]+")").remove();for(var t=l.find("."+e),i=0;i<2;i++)t.unwrap();t.css("display",t.data("display")).removeClass(e)}else{if(c===d.type[2])try{var n=m("#"+u[4]+o)[0];n.contentWindow.document.write(""),n.contentWindow.close(),l.find("."+u[5])[0].removeChild(n)}catch(a){}l[0].innerHTML="",l.remove()}"function"==typeof d.end[o]&&d.end[o](),delete d.end[o],"function"==typeof s&&s(),d.events.resize[o]&&(g.off("resize",d.events.resize[o]),delete d.events.resize[o])},t=m("#"+u.SHADE+o),v.ie&&v.ie<10||!i.isOutAnim?t[f?"hide":"remove"]():(t.css({opacity:0}),setTimeout(function(){t[f?"hide":"remove"]()},350)),i.isOutAnim&&l.addClass("layer-anim "+r),6==v.ie&&d.reselect(),d.restScrollbar(o),"string"==typeof l.attr("minLeft")&&(d.minStackIndex--,d.minStackArr.push(l.attr("minLeft"))),v.ie&&v.ie<10||!i.isOutAnim?e():setTimeout(function(){e()},200))},v.closeAll=function(n,a){"function"==typeof n&&(a=n,n=null);var o=m("."+u[0]);m.each(o,function(e){var t=m(this),i=n?t.attr("type")===n:1;i&&v.close(t.attr("times"),e===o.length-1?a:null)}),0===o.length&&"function"==typeof a&&a()},v.closeLast=function(i,e){var t,n=[],a=m.isArray(i);m("string"==typeof i?".layui-layer-"+i:".layui-layer").each(function(e,t){t=m(t);if(a&&-1===i.indexOf(t.attr("type"))||"none"===t.css("display"))return!0;n.push(Number(t.attr("times")))}),0":'",s=i.success;return delete i.success,v.open(m.extend({type:1,btn:["\u786e\u5b9a","\u53d6\u6d88"],content:o,skin:"layui-layer-prompt"+x("prompt"),maxWidth:g.width(),success:function(e){(a=e.find(".layui-layer-input")).val(i.value||"").focus(),"function"==typeof s&&s(e)},resize:!1,yes:function(e){var t=a.val();t.length>(i.maxlength||500)?v.tips("\u6700\u591a\u8f93\u5165"+(i.maxlength||500)+"\u4e2a\u5b57\u7b26",a,{tips:1}):n&&n(t,e,a)}},i))},v.tab=function(n){var a=(n=n||{}).tab||{},o="layui-this",s=n.success;return delete n.success,v.open(m.extend({type:1,skin:"layui-layer-tab"+x("tab"),resize:!1,title:function(){var e=a.length,t=1,i="";if(0'+a[0].title+"";t"+a[t].title+"";return i}(),content:'
          '+function(){var e=a.length,t=1,i="";if(0'+(a[0].content||"no content")+"";t'+(a[t].content||"no content")+"";return i}()+"
        ",success:function(e){var t=e.find(".layui-layer-title").children(),i=e.find(".layui-layer-tabmain").children();t.on("mousedown",function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0;var e=m(this),t=e.index();e.addClass(o).siblings().removeClass(o),i.eq(t).show().siblings().hide(),"function"==typeof n.change&&n.change(t)}),"function"==typeof s&&s(e)}},n))},v.photos=function(n,e,a){var s={};if((n=m.extend(!0,{toolbar:!0,footer:!0},n)).photos){var t=!("string"==typeof n.photos||n.photos instanceof m),i=t?n.photos:{},o=i.data||[],r=i.start||0,l=n.success;if(s.imgIndex=1+(0|r),n.img=n.img||"img",delete n.success,t){if(0===o.length)return v.msg("\u6ca1\u6709\u56fe\u7247")}else{var c=m(n.photos),f=function(){o=[],c.find(n.img).each(function(e){var t=m(this);t.attr("layer-index",e),o.push({alt:t.attr("alt"),pid:t.attr("layer-pid"),src:t.attr("lay-src")||t.attr("layer-src")||t.attr("src"),thumb:t.attr("src")})})};if(f(),0===o.length)return;if(e||c.on("click",n.img,function(){f();var e=m(this).attr("layer-index");v.photos(m.extend(n,{photos:{start:e,data:o,tab:n.tab},full:n.full}),!0)}),!e)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=o.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>o.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){var t;s.end||(t=e.keyCode,e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&v.close(s.index))},s.tabimg=function(e){if(!(o.length<=1))return i.start=s.imgIndex-1,v.close(s.index),v.photos(n,!0,e)},s.isNumber=function(e){return"number"==typeof e&&!isNaN(e)},s.image={},s.getTransform=function(e){var t=[],i=e.rotate,n=e.scaleX,e=e.scale;return s.isNumber(i)&&0!==i&&t.push("rotate("+i+"deg)"),s.isNumber(n)&&1!==n&&t.push("scaleX("+n+")"),s.isNumber(e)&&t.push("scale("+e+")"),t.length?t.join(" "):"none"},s.event=function(e,i,n){var a,o;s.main.find(".layui-layer-photos-prev").on("click",function(e){e.preventDefault(),s.imgprev(!0)}),s.main.find(".layui-layer-photos-next").on("click",function(e){e.preventDefault(),s.imgnext(!0)}),m(document).on("keyup",s.keyup),e.off("click").on("click","*[toolbar-event]",function(){var e=m(this);switch(e.attr("toolbar-event")){case"rotate":s.image.rotate=((s.image.rotate||0)+Number(e.attr("data-option")))%360,s.imgElem.css({transform:s.getTransform(s.image)});break;case"scalex":s.image.scaleX=-1===s.image.scaleX?1:-1,s.imgElem.css({transform:s.getTransform(s.image)});break;case"zoom":var t=Number(e.attr("data-option"));s.image.scale=(s.image.scale||1)+t,t<0&&s.image.scale<0-t&&(s.image.scale=0-t),s.imgElem.css({transform:s.getTransform(s.image)});break;case"reset":s.image.scaleX=1,s.image.scale=1,s.image.rotate=0,s.imgElem.css({transform:"none"});break;case"close":v.close(i)}n.offset(),n.auto(i)}),s.main.on("mousewheel DOMMouseScroll",function(e){var t=e.originalEvent.wheelDelta||-e.originalEvent.detail,i=s.main.find('[toolbar-event="zoom"]');(0n)&&("left"===t.direction?s.imgnext(!0):"right"===t.direction&&s.imgprev(!0))},m.each([n.shadeo,s.main],function(e,t){a.touchSwipe(t,{onTouchEnd:o})}))},s.loadi=v.load(1,{shade:!("shade"in n)&&[.9,h,"unset"],scrollbar:!1});var t=o[r].src,d=function(e){v.close(s.loadi);var t,i=o[r].alt||"";a&&(n.anim=-1),s.index=v.open(m.extend({type:1,id:"layui-layer-photos",area:(e=[e.width,e.height],t=[m(p).width()-100,m(p).height()-100],!n.full&&(t[0]'+i+''+(t=['
        '],1','','',"
        "].join("")),n.toolbar&&t.push(['
        ','','','','','','',"
        "].join("")),n.footer&&t.push(['"].join("")),t.push("
        "),t.join(""))+"",success:function(e,t,i){s.main=e.find(".layer-layer-photos-main"),s.footer=e.find(".layui-layer-photos-footer"),s.imgElem=s.main.children("img"),s.event(e,t,i),n.tab&&n.tab(o[r],e),"function"==typeof l&&l(e)},end:function(){s.end=!0,m(document).off("keyup",s.keyup)}},n))},u=function(){v.close(s.loadi),v.msg("\u5f53\u524d\u56fe\u7247\u5730\u5740\u5f02\u5e38\uff0c
        \u662f\u5426\u7ee7\u7eed\u67e5\u770b\u4e0b\u4e00\u5f20\uff1f",{time:3e4,btn:["\u4e0b\u4e00\u5f20","\u4e0d\u770b\u4e86"],yes:function(){1").addClass(r));layui.each(i.bars,function(t,e){var n=s('
      • ');n.addClass(e.icon).attr({"lay-type":e.type,style:e.style||(i.bgcolor?"background-color: "+i.bgcolor:"")}).html(e.content),n.on("click",function(){var t=s(this).attr("lay-type");"top"===t&&("body"===i.target?s("html,body"):u).animate({scrollTop:0},i.duration),"function"==typeof i.click&&i.click.call(this,t)}),"object"===layui.type(i.on)&&layui.each(i.on,function(t,e){n.on(t,function(){var t=s(this).attr("lay-type");"function"==typeof e&&e.call(this,t)})}),"top"===e.type&&(n.addClass("layui-fixbar-top"),o=n),l.append(n)}),c.find("."+r).remove(),"object"==typeof i.css&&l.css(i.css),c.append(l),o&&(e=function e(){return u.scrollTop()>=i.margin?t||(o.show(),t=1):t&&(o.hide(),t=0),e}()),u.on("scroll",function(){e&&(clearTimeout(n),n=setTimeout(function(){e()},100))})},countdown:function(i){i=s.extend(!0,{date:new Date,now:new Date},i);var o=arguments,r=(1]|&(?=#[a-zA-Z0-9]+)/g.test(t+="")?t.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,"""):t},unescape:function(t){return t!==undefined&&null!==t||(t=""),(t+="").replace(/\&/g,"&").replace(/\</g,"<").replace(/\>/g,">").replace(/\'/g,"'").replace(/\"/g,'"')},openWin:function(t){var e=(t=t||{}).window||window.open(t.url||"",t.target,t.specs);t.url||(e.document.open("text/html","replace"),e.document.write(t.content||""),e.document.close())},toVisibleArea:function(t){var e,n,i,o,r,a,c,u;(t=s.extend({margin:160,duration:200,type:"y"},t)).scrollElem[0]&&t.thisElem[0]&&(e=t.scrollElem,c=t.thisElem,i=(r="y"===t.type)?"top":"left",o=e[n=r?"scrollTop":"scrollLeft"](),r=e[r?"height":"width"](),a=e.offset()[i],u={},(c=c.offset()[i]-a)>r-t.margin||c."+w,E=function(e){var i=this;i.index=++h.index,i.config=c.extend({},i.config,h.config,e),i.init()};E.prototype.config={trigger:"click",content:"",className:"",style:"",show:!1,isAllowSpread:!0,isSpreadItem:!0,data:[],delay:[200,300],shade:0,accordion:!1},E.prototype.reload=function(e,i){var t=this;t.config=c.extend({},t.config,e),t.init(!0,i)},E.prototype.init=function(e,i){var t,n=this,l=n.config,a=c(l.elem);return 1');return 0\u6682\u65e0\u6570\u636e
      • '),e},u=function(r,e){return layui.each(e,function(e,i){var t,n=i[s.children]&&0",(t="href"in i?''+a+"":a,n?'
        '+t+("parent"===o?'':"group"===o&&d.isAllowSpread?'':"")+"
        ":'
        '+t+"
        "),""].join(""))).data("item",i),n&&(l=c('
        '),t=c("
          "),"parent"===o?(l.append(u(t,i[s.children])),a.append(l)):a.append(u(t,i[s.children]))),r.append(a))}),r},l=['
          ',"
          "].join("");!(e="contextmenu"!==d.trigger&&!lay.isTopElem(d.elem[0])?e:!0)&&d.elem.data(y+"_opened")||(a.elemView=c("."+v+"["+f+'="'+d.id+'"]'),"reloadData"===i&&a.elemView.length?a.elemView.html(d.content||n()):(a.elemView=c(l),a.elemView.append(d.content||n()),d.className&&a.elemView.addClass(d.className),d.style&&a.elemView.attr("style",d.style),h.thisId=d.id,a.remove(),t.append(a.elemView),d.elem.data(y+"_opened",!0),e=d.shade?'
          ':"",a.elemView.before(e),"mouseenter"===d.trigger&&a.elemView.on("mouseenter",function(){clearTimeout(g.timer)}).on("mouseleave",function(){a.delayRemove()})),a.position(),(g.prevElem=a.elemView).data("prevElem",d.elem),a.elemView.find(".layui-menu").on(o,function(e){layui.stope(e)}),a.elemView.find(".layui-menu li").on("click",function(e){var i=c(this),t=i.data("item")||{},n=t[s.children]&&0n.width()&&(t.addClass(b),(i=t[0].getBoundingClientRect()).left<0)&&t.removeClass(b),i.bottom>n.height())&&t.eq(0).css("margin-top",-(i.bottom-n.height()+5))}).on("mouseleave",t,function(e){var i=c(this).children("."+x);i.removeClass(b),i.css("margin-top",0)}),h.close=function(e){e=g.getThis(e);return e?(e.remove(),g.call(e)):this},h.open=function(e){e=g.getThis(e);return e?(e.render(),g.call(e)):this},h.reload=function(e,i,t){e=g.getThis(e);return e?(e.reload(i,t),g.call(e)):this},h.reloadData=function(){var t=c.extend([],arguments),n=(t[2]="reloadData",new RegExp("^("+["data","templet","content"].join("|")+")$"));return layui.each(t[1],function(e,i){n.test(e)||delete t[1][e]}),h.reload.apply(null,t)},h.render=function(e){e=new E(e);return g.call(e)},e(r,h)});layui.define(["jquery","lay"],function(e){"use strict";var x=layui.$,b=layui.lay,m={config:{},index:layui.slider?layui.slider.index+1e4:0,set:function(e){var t=this;return t.config=x.extend({},t.config,e),t},on:function(e,t){return layui.onevent.call(this,i,e,t)}},i="slider",f="layui-disabled",T="layui-slider-bar",w="layui-slider-wrap",M="layui-slider-wrap-btn",L="layui-slider-tips",E="layui-slider-input-txt",Y="layui-slider-hover",t=function(e){var t=this;t.index=++m.index,t.config=x.extend({},t.config,m.config,e),t.render()};t.prototype.config={type:"default",min:0,max:100,value:0,step:1,showstep:!1,tips:!0,tipsAlways:!1,input:!1,range:!1,height:200,disabled:!1,theme:"#16baaa"},t.prototype.precision=function(){var e=this.config,e=x.map([e.min,e.max,e.step],function(e,t){e=String(e).split(".");return e[1]?e[1].length:0});return Math.max.apply(null,e)},t.prototype.render=function(){var n=this,a=n.config,e=x(a.elem);if(1a.max&&(a.value=a.max),l=(a.value-a.min)/(a.max-a.min)*100+"%");var t,e=a.disabled?"#c2c2c2":a.theme,i='
          '+(a.tips?'
          ":"")+'
          '+(a.range?'
          ':"")+"
          ",l=x(a.elem),s=l.next(".layui-slider");if(s[0]&&s.remove(),n.elemTemp=x(i),a.range?(n.elemTemp.find("."+w).eq(0).data("value",a.value[0]),n.elemTemp.find("."+w).eq(1).data("value",a.value[1])):n.elemTemp.find("."+w).data("value",a.value),l.html(n.elemTemp),"vertical"===a.type&&n.elemTemp.height(a.height+"px"),a.showstep){for(var o=(a.max-a.min)/a.step,r="",u=1;u<1+o;u++){var c=100*u/o;c<100&&(r+='
          ')}n.elemTemp.append(r)}function d(e){e=e.parent().data("value"),e=a.setTips?a.setTips(e):e;n.elemTemp.find("."+L).html(e)}function p(e){var t="vertical"===a.type?a.height:n.elemTemp[0].offsetWidth,i=n.elemTemp.find("."+w);return("vertical"===a.type?t-e.parent()[0].offsetTop-i.height():e.parent()[0].offsetLeft)/t*100}function v(e){"vertical"===a.type?n.elemTemp.find("."+L).css({bottom:e+"%","margin-bottom":"20px",display:"inline-block"}):n.elemTemp.find("."+L).css({left:e+"%",display:"inline-block"})}a.input&&!a.range&&(e=x('
          '),l.css("position","relative"),l.append(e),l.find("."+E).children("input").val(a.value),"vertical"===a.type?e.css({left:0,top:-48}):n.elemTemp.css("margin-right",e.outerWidth()+15)),a.disabled?(n.elemTemp.addClass(f),n.elemTemp.find("."+M).addClass(f)):n.slide(),a.tips&&(a.tipsAlways?(d(s=n.elemTemp.find("."+M)),v(p(s))):n.elemTemp.find("."+M).on("mouseover",function(){d(x(this));var e=p(x(this));clearTimeout(t),t=setTimeout(function(){v(e)},300)}).on("mouseout",function(){clearTimeout(t),a.tipsAlways||n.elemTemp.find("."+L).css("display","none")}))},t.prototype.slide=function(e,t,i){var u=this,c=u.config,d=u.elemTemp,p=function(){return"vertical"===c.type?c.height:d[0].offsetWidth},v=d.find("."+w),o=d.next(".layui-slider-input"),r=o.children("."+E).children("input").val(),m=100/((c.max-c.min)/c.step),f=u.precision(),h=function(e,t,i){e=(e=100<(e=100n[1]&&n.reverse(),u.value=c.range?n:l,c.change&&c.change(u.value),"done"===i&&c.done&&c.done(u.value)},y=function(e){var t=e/p()*100/m,i=Math.round(t)*m;return i=e==p()?Math.ceil(t)*m:i},g=x(['
          p()?p():t)/p()*100/m;h(t,o),r.addClass(Y),d.find("."+L).show(),e.preventDefault()},n=function(e){r.removeClass(Y),c.tipsAlways||setTimeout(function(){d.find("."+L).hide()},e)},a=function(){n&&n(b.touchEventsSupported()?1e3:0),g.remove(),c.done&&c.done(u.value),b.touchEventsSupported()&&(t[0].removeEventListener("touchmove",i,!!b.passiveSupported&&{passive:!1}),t[0].removeEventListener("touchend",a),t[0].removeEventListener("touchcancel",a))},x("#LAY-slider-moving")[0]||x("body").append(g),g.on("mousemove",i),g.on("mouseup",a).on("mouseleave",a),b.touchEventsSupported()&&(t[0].addEventListener("touchmove",i,!!b.passiveSupported&&{passive:!1}),t[0].addEventListener("touchend",a),t[0].addEventListener("touchcancel",a))})}),d.on("click",function(e){var t=x("."+M),i=x(this);!t.is(event.target)&&0===t.has(event.target).length&&t.length&&(i=(t=(t=(t="vertical"===c.type?p()-e.clientY+i.offset().top-x(window).scrollTop():e.clientX-i.offset().left-x(window).scrollLeft())<0?0:t)>p()?p():t)/p()*100/m,t=c.range?"vertical"===c.type?Math.abs(t-parseInt(x(v[0]).css("bottom")))>Math.abs(t-parseInt(x(v[1]).css("bottom")))?1:0:Math.abs(t-v[0].offsetLeft)>Math.abs(t-v[1].offsetLeft)?1:0:0,h(i,t,"done"),e.preventDefault())}),o.children(".layui-slider-input-btn").children("i").each(function(t){x(this).on("click",function(){r=o.children("."+E).children("input").val();var e=((r=1==t?r-c.stepc.max?c.max:Number(r)+c.step)-c.min)/(c.max-c.min)*100/m;h(e,0,"done")})});var n=function(){var e=this.value,e=(e=(e=(e=isNaN(e)?0:e)c.max?c.max:e,((this.value=e)-c.min)/(c.max-c.min)*100/m);h(e,0,"done")};o.children("."+E).children("input").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),n.call(this))}).on("change",n)},t.prototype.events=function(){this.config},m.render=function(e){e=new t(e);return function(){var i=this,n=i.config;return{setValue:function(e,t){return e=(e=e>n.max?n.max:e)',"",'','',"","","
          "].join("")),t=i.elem=k(i.elem);i.size&&o.addClass("layui-colorpicker-"+i.size),t.addClass("layui-inline").html(e.elemColorBox=o),i.id="id"in i?i.id:t.attr("id")||e.index,e.color=e.elemColorBox.find("."+C)[0].style.background,e.events()},d.prototype.renderPicker=function(){var o,e=this,i=e.config,t=e.elemColorBox[0],r=e.elemPicker=k(['
          ','
          ','
          ','
          ','
          ','
          ',"
          ",'
          ','
          ',"
          ","
          ",'
          ','
          ','
          ',"
          ","
          ",i.predefine?(o=['
          '],layui.each(i.colors,function(e,i){o.push(['
          ','
          ',"
          "].join(""))}),o.push("
          "),o.join("")):"",'
          ','
          ','',"
          ",'
          ','','',"","
          "].join(""));e.elemColorBox.find("."+C)[0];k(a)[0]&&k(a).data("index")==e.index?e.removePicker(d.thisElemInd):(e.removePicker(d.thisElemInd),k("body").append(r)),n.thisId=i.id,d.thisElemInd=e.index,d.thisColor=t.style.background,e.position(),e.pickerEvents()},d.prototype.removePicker=function(e){var i=this.config,e=k("#layui-colorpicker"+(e||this.index));return e[0]&&(e.remove(),delete n.thisId,"function"==typeof i.close)&&i.close(this.color),this},d.prototype.position=function(){var e=this,i=e.config;return r.position(e.bindElem||e.elemColorBox[0],e.elemPicker[0],{position:i.position,align:"center"}),e},d.prototype.val=function(){var e,i=this,o=(i.config,i.elemColorBox.find("."+C)),t=i.elemPicker.find("."+M),r=o[0].style.backgroundColor;r?(e=Y(F(r)),o=o.attr("lay-type"),i.select(e.h,e.s,e.b),"torgb"===o?t.find("input").val(r):"rgba"===o?(o=F(r),3===(r.match(/[0-9]{1,3}/g)||[]).length?(t.find("input").val("rgba("+o.r+", "+o.g+", "+o.b+", 1)"),i.elemPicker.find("."+D).css("left",280)):(t.find("input").val(r),r=280*r.slice(r.lastIndexOf(",")+1,r.length-1),i.elemPicker.find("."+D).css("left",r)),i.elemPicker.find("."+T)[0].style.background="linear-gradient(to right, rgba("+o.r+", "+o.g+", "+o.b+", 0), rgb("+o.r+", "+o.g+", "+o.b+"))"):t.find("input").val("#"+j(e))):(i.select(0,100,100),t.find("input").val(""),i.elemPicker.find("."+T)[0].style.background="",i.elemPicker.find("."+D).css("left",280))},d.prototype.side=function(){var n=this,l=n.config,c=n.elemColorBox.find("."+C),a=c.attr("lay-type"),s=n.elemPicker.find(".layui-colorpicker-side"),e=n.elemPicker.find("."+B),d=n.elemPicker.find("."+I),t=n.elemPicker.find("."+E),u=n.elemPicker.find("."+T),f=n.elemPicker.find("."+D),p=e[0].offsetTop/180*360,h=100-(t[0].offsetTop+3)/180*100,g=(t[0].offsetLeft+3)/260*100,v=Math.round(f[0].offsetLeft/280*100)/100,y=n.elemColorBox.find("."+w),i=n.elemPicker.find(".layui-colorpicker-pre").children("div"),m=function(e,i,o,t){n.select(e,i,o);var r=X({h:e,s:i,b:o}),e=j({h:e,s:i,b:o}),i=n.elemPicker.find("."+M).find("input");y.addClass(x).removeClass(P),c[0].style.background="rgb("+r.r+", "+r.g+", "+r.b+")","torgb"===a?i.val("rgb("+r.r+", "+r.g+", "+r.b+")"):"rgba"===a?(f.css("left",280*t),i.val("rgba("+r.r+", "+r.g+", "+r.b+", "+t+")"),c[0].style.background="rgba("+r.r+", "+r.g+", "+r.b+", "+t+")",u[0].style.background="linear-gradient(to right, rgba("+r.r+", "+r.g+", "+r.b+", 0), rgb("+r.r+", "+r.g+", "+r.b+"))"):i.val("#"+e),l.change&&l.change(k.trim(n.elemPicker.find("."+M).find("input").val()))},o=k(['
          '].join("")),b=function(e){k("#LAY-colorpicker-moving")[0]||k("body").append(o),o.on("mousemove",e),o.on("mouseup",function(){o.remove()}).on("mouseleave",function(){o.remove()})};e.on("mousedown",function(e){var t=this.offsetTop,r=e.clientY;b(function(e){var i=t+(e.clientY-r),o=s[0].offsetHeight,o=(i=o<(i=i<0?0:i)?o:i)/180*360;m(p=o,g,h,v),e.preventDefault()}),e.preventDefault()}),s.on("click",function(e){var i=e.clientY-k(this).offset().top+H.scrollTop(),i=(i=(i=i<0?0:i)>this.offsetHeight?this.offsetHeight:i)/180*360;m(p=i,g,h,v),e.preventDefault()}),t.on("mousedown",function(e){var n=this.offsetTop,l=this.offsetLeft,c=e.clientY,a=e.clientX;layui.stope(e),b(function(e){var i=n+(e.clientY-c),o=l+(e.clientX-a),t=d[0].offsetHeight,r=d[0].offsetWidth,r=(o=r<(o=o<0?0:o)?r:o)/260*100,o=100-(i=t<(i=i<0?0:i)?t:i)/180*100;m(p,g=r,h=o,v),e.preventDefault()}),e.preventDefault()}),d.on("mousedown",function(e){var i=e.clientY-k(this).offset().top+H.scrollTop(),o=e.clientX-k(this).offset().left+H.scrollLeft(),o=((i=i<0?0:i)>this.offsetHeight&&(i=this.offsetHeight),(o=(o=o<0?0:o)>this.offsetWidth?this.offsetWidth:o)/260*100),i=100-i/180*100;m(p,g=o,h=i,v),layui.stope(e),e.preventDefault(),t.trigger(e,"mousedown")}),f.on("mousedown",function(e){var t=this.offsetLeft,r=e.clientX;b(function(e){var i=t+(e.clientX-r),o=u[0].offsetWidth,o=(o<(i=i<0?0:i)&&(i=o),Math.round(i/280*100)/100);m(p,g,h,v=o),e.preventDefault()}),e.preventDefault()}),u.on("click",function(e){var i=e.clientX-k(this).offset().left,i=((i=i<0?0:i)>this.offsetWidth&&(i=this.offsetWidth),Math.round(i/280*100)/100);m(p,g,h,v=i),e.preventDefault()}),i.each(function(){k(this).on("click",function(){k(this).parent(".layui-colorpicker-pre").addClass("selected").siblings().removeClass("selected");var e=this.style.backgroundColor,i=Y(F(e)),o=e.slice(e.lastIndexOf(",")+1,e.length-1);p=i.h,g=i.s,h=i.b,3===(e.match(/[0-9]{1,3}/g)||[]).length&&(o=1),v=o,m(i.h,i.s,i.b,o)})}),r.touchEventsSupported()&&layui.each([{elem:s,eventType:"click"},{elem:u,eventType:"click"},{elem:d,eventType:"mousedown"}],function(e,t){r.touchSwipe(t.elem,{onTouchMove:function(e){var i,o;e=e,i=t.eventType,e=e.touches[0],(o=document.createEvent("MouseEvent")).initMouseEvent(i,!0,!0,window,1,e.screenX,e.screenY,e.clientX,e.clientY,!1,!1,!1,!1,0,null),e.target.dispatchEvent(o)}})})},d.prototype.select=function(e,i,o,t){this.config;var r=j({h:e,s:100,b:100}),e=(j({h:e,s:i,b:o}),e/360*180),o=180-o/100*180,i=i/100*260,n=this.elemPicker.find("."+I)[0];this.elemPicker.find("."+B).css("top",e),n.style.background="#"+r,this.elemPicker.find("."+E).css({top:o/n.offsetHeight*100+"%",left:i/n.offsetWidth*100+"%"})},d.prototype.pickerEvents=function(){var c=this,a=c.config,s=c.elemColorBox.find("."+C),d=c.elemPicker.find("."+M+" input"),o={clear:function(e){s[0].style.background="",c.elemColorBox.find("."+w).removeClass(x).addClass(P),c.color="",a.done&&a.done(""),c.removePicker()},confirm:function(e,i){var o,t,r,n,l=k.trim(d.val());-1>16,g:(65280&r)>>8,b:255&r},t=Y(n),s[0].style.background=o="#"+j(t),c.elemColorBox.find("."+w).removeClass(P).addClass(x)),"change"===i?(c.select(t.h,t.s,t.b,i),a.change&&a.change(o)):(c.color=l,a.done&&a.done(l),c.removePicker())}};c.elemPicker.on("click","*[colorpicker-events]",function(){var e=k(this),i=e.attr("colorpicker-events");o[i]&&o[i].call(this,e)}),d.on("keyup",function(e){var i=k(this);o.confirm.call(this,i,13===e.keyCode?null:"change")})},d.prototype.events=function(){var e=this;e.config;e.elemColorBox.on("click",function(){e.renderPicker(),k(a)[0]&&(e.val(),e.side())})},s.on(i,function(e){var i,o,t;n.thisId&&(i=l.getThis(n.thisId))&&(o=i.config,t=i.elemColorBox.find("."+C),k(e.target).hasClass(c)||k(e.target).parents("."+c)[0]||k(e.target).hasClass(a.replace(/\./g,""))||k(e.target).parents(a)[0]||i.elemPicker&&(i.color?(e=Y(F(i.color)),i.select(e.h,e.s,e.b)):i.elemColorBox.find("."+w).removeClass(x).addClass(P),t[0].style.background=i.color||"","function"==typeof o.cancel&&o.cancel(i.color),i.removePicker()))}),H.on("resize",function(){if(n.thisId){var e=l.getThis(n.thisId);if(e)return!(!e.elemPicker||!k(a)[0])&&void e.position()}}),l.that={},l.getThis=function(e){var i=l.that[e];return i||o.error(e?t+" instance with ID '"+e+"' not found":"ID argument required"),i},n.render=function(e){e=new d(e);return l.call(e)},e(t,n)});layui.define("jquery",function(t){"use strict";var u=layui.$,d=(layui.hint(),layui.device()),c="element",r="layui-this",h="layui-show",o=".layui-tab-title",i=function(){this.config={}},y=(i.prototype.set=function(t){return u.extend(!0,this.config,t),this},i.prototype.on=function(t,i){return layui.onevent.call(this,c,t,i)},i.prototype.tabAdd=function(t,i){var a,e=u(".layui-tab[lay-filter="+t+"]"),l=e.children(o),n=l.children(".layui-tab-bar"),e=e.children(".layui-tab-content"),s=""+(i.title||"unnaming")+"";return n[0]?n.before(s):l.append(s),e.append('
          '+(i.content||"")+"
          "),i.change&&this.tabChange(t,i.id),l.data("LAY_TAB_CHANGE",i.change),C.tabAuto(i.change?"change":null),this},i.prototype.tabDelete=function(t,i){t=u(".layui-tab[lay-filter="+t+"]").children(o).find('>li[lay-id="'+i+'"]');return C.tabDelete(null,t),this},i.prototype.tabChange=function(t,i){t=u(".layui-tab[lay-filter="+t+"]").children(o).find('>li[lay-id="'+i+'"]');return C.tabClick.call(t[0],{liElem:t}),this},i.prototype.tab=function(a){a=a||{},e.on("click",a.headerElem,function(t){var i=u(a.headerElem).index(u(this));C.tabClick.call(this,{index:i,options:a})})},i.prototype.progress=function(t,i){var a="layui-progress",t=u("."+a+"[lay-filter="+t+"]").find("."+a+"-bar"),a=t.find("."+a+"-text");return t.css("width",function(){return/^.+\/.+$/.test(i)?100*new Function("return "+i)()+"%":i}).attr("lay-percent",i),a.text(i),this},".layui-nav"),f="layui-nav-item",p="layui-nav-bar",b="layui-nav-tree",v="layui-nav-child",m="layui-nav-more",g="layui-anim layui-anim-upbit",C={tabClick:function(t){var i=(t=t||{}).options||{},a=t.liElem||u(this),e=i.headerElem?a.parent():a.parents(".layui-tab").eq(0),i=i.bodyElem?u(i.bodyElem):e.children(".layui-tab-content").children(".layui-tab-item"),l=a.find("a"),l="javascript:;"!==l.attr("href")&&"_blank"===l.attr("target"),n="string"==typeof a.attr("lay-unselect"),s=e.attr("lay-filter"),t="index"in t?t.index:a.parent().children("li").index(a);l||n||(a.addClass(r).siblings().removeClass(r),i.eq(t).addClass(h).siblings().removeClass(h)),layui.event.call(this,c,"tab("+s+")",{elem:e,index:t})},tabDelete:function(t,i){var i=i||u(this).parent(),a=i.parent().children("li").index(i),e=i.closest(".layui-tab"),l=e.children(".layui-tab-content").children(".layui-tab-item"),n=e.attr("lay-filter");i.hasClass(r)&&(i.next()[0]&&i.next().is("li")?C.tabClick.call(i.next()[0],{index:a+1}):i.prev()[0]&&i.prev().is("li")&&C.tabClick.call(i.prev()[0],null,a-1)),i.remove(),l.eq(a).remove(),setTimeout(function(){C.tabAuto()},50),layui.event.call(this,c,"tabDelete("+n+")",{elem:e,index:a})},tabAuto:function(l){var n="layui-tab-more",s="layui-tab-bar",o="layui-tab-close",c=this;u(".layui-tab").each(function(){var t,i=u(this),a=i.children(".layui-tab-title"),e=(i.children(".layui-tab-content").children(".layui-tab-item"),'lay-stope="tabmore"'),e=u('');c===window&&d.ie,i.attr("lay-allowclose")&&a.find("li").each(function(){var t,i=u(this);i.find("."+o)[0]||((t=u('')).on("click",C.tabDelete),i.append(t))}),"string"!=typeof i.attr("lay-unauto")&&(a.prop("scrollWidth")>a.outerWidth()+1||a.find("li").length&&a.height()>(t=a.find("li").eq(0).height())+t/2?("change"===l&&a.data("LAY_TAB_CHANGE")&&a.addClass(n),a.find("."+s)[0]||(a.append(e),i.attr("overflow",""),e.on("click",function(t){var i=a.hasClass(n);a[i?"removeClass":"addClass"](n)}))):(a.find("."+s).remove(),i.removeAttr("overflow")))})},hideTabMore:function(t){var i=u(".layui-tab-title");!0!==t&&"tabmore"===u(t.target).attr("lay-stope")||(i.removeClass("layui-tab-more"),i.find(".layui-tab-bar").attr("title",""))},clickThis:function(){var t=u(this),i=t.closest(y),a=i.attr("lay-filter"),e=t.parent(),l=t.siblings("."+v),n="string"==typeof e.attr("lay-unselect");if("javascript:;"!==t.attr("href")&&"_blank"===t.attr("target")||n||l[0]||(i.find("."+r).removeClass(r),e.addClass(r)),i.hasClass(b)){var n=f+"ed",s=!e.hasClass(n),o=function(){u(this).css({display:""}),i.children("."+p).css({opacity:0})};if(l.is(":animated"))return;l.removeClass(g),l[0]&&(s?(l.slideDown(200,o),e.addClass(n)):(e.removeClass(n),l.show().slideUp(200,o)),"string"!=typeof i.attr("lay-accordion")&&"all"!==i.attr("lay-shrink")||((s=e.siblings("."+n)).removeClass(n),s.children("."+v).show().stop().slideUp(200,o)))}layui.event.call(this,c,"nav("+a+")",t)},collapse:function(){var t=u(this),i=t.find(".layui-colla-icon"),a=t.siblings(".layui-colla-content"),e=t.parents(".layui-collapse").eq(0),l=e.attr("lay-filter"),n="none"===a.css("display");"string"==typeof e.attr("lay-accordion")&&((e=e.children(".layui-colla-item").children("."+h)).siblings(".layui-colla-title").children(".layui-colla-icon").html(""),e.removeClass(h)),a[n?"addClass":"removeClass"](h),i.html(n?"":""),layui.event.call(this,c,"collapse("+l+")",{title:t,content:a,show:n})}},a=(i.prototype.render=i.prototype.init=function(t,i){var a=i?'[lay-filter="'+i+'"]':"",i={tab:function(){C.tabAuto.call({})},nav:function(){var s={},o={},c={},r="layui-nav-title";u(y+a).each(function(t){var i=u(this),a=u(''),e=i.find("."+f);i.find("."+p)[0]||(i.append(a),(i.hasClass(b)?e.find("dd,>."+r):e).on("mouseenter",function(){!function(t,i,a){var e,l=u(this),n=l.find("."+v);i.hasClass(b)?n[0]||(e=l.children("."+r),t.css({top:l.offset().top-i.offset().top,height:(e[0]?e:l).outerHeight(),opacity:1})):(n.addClass(g),n.hasClass("layui-nav-child-c")&&n.css({left:-(n.outerWidth()-l.width())/2}),n[0]?t.css({left:t.position().left+t.width()/2,width:0,opacity:0}):t.css({left:l.position().left+parseFloat(l.css("marginLeft")),top:l.position().top+l.height()-t.height()}),s[a]=setTimeout(function(){t.css({width:n[0]?0:l.width(),opacity:n[0]?0:1})},d.ie&&d.ie<10?0:200),clearTimeout(c[a]),"block"===n.css("display")&&clearTimeout(o[a]),o[a]=setTimeout(function(){n.addClass(h),l.find("."+m).addClass(m+"d")},300))}.call(this,a,i,t)}).on("mouseleave",function(){i.hasClass(b)?a.css({height:0,opacity:0}):(clearTimeout(o[t]),o[t]=setTimeout(function(){i.find("."+v).removeClass(h),i.find("."+m).removeClass(m+"d")},300))}),i.on("mouseleave",function(){clearTimeout(s[t]),c[t]=setTimeout(function(){i.hasClass(b)||a.css({width:0,left:a.position().left+a.width()/2,opacity:0})},200)})),e.find("a").each(function(){var t=u(this);t.parent();t.siblings("."+v)[0]&&!t.children("."+m)[0]&&t.append(''),t.off("click",C.clickThis).on("click",C.clickThis)})})},breadcrumb:function(){u(".layui-breadcrumb"+a).each(function(){var t=u(this),i="lay-separator",a=t.attr(i)||"/",e=t.find("a");e.next("span["+i+"]")[0]||(e.each(function(t){t!==e.length-1&&u(this).after(""+a+"")}),t.css("visibility","visible"))})},progress:function(){var e="layui-progress";u("."+e+a).each(function(){var t=u(this),i=t.find(".layui-progress-bar"),a=i.attr("lay-percent");i.css("width",function(){return/^.+\/.+$/.test(a)?100*new Function("return "+a)()+"%":a}),t.attr("lay-showpercent")&&setTimeout(function(){i.html(''+a+"")},350)})},collapse:function(){u(".layui-collapse"+a).each(function(){u(this).find(".layui-colla-item").each(function(){var t=u(this),i=t.find(".layui-colla-title"),t="none"===t.find(".layui-colla-content").css("display");i.find(".layui-colla-icon").remove(),i.append(''+(t?"":"")+""),i.off("click",C.collapse).on("click",C.collapse)})})}};return i[t]?i[t]():layui.each(i,function(t,i){i()})},new i),e=u(document);u(function(){a.render()}),e.on("click",".layui-tab-title li",C.tabClick),u(window).on("resize",C.tabAuto),t(c,a)});layui.define(["lay","layer"],function(e){"use strict";var x=layui.$,a=layui.lay,i=layui.layer,b=layui.device(),t="upload",c="layui_"+t+"_index",s={config:{},index:layui[t]?layui[t].index+1e4:0,set:function(e){var i=this;return i.config=x.extend({},i.config,e),i},on:function(e,i){return layui.onevent.call(this,t,e,i)}},o=function(){var i=this,e=i.config.id;return{upload:function(e){i.upload.call(i,e)},reload:function(e){i.reload.call(i,e)},config:(o.that[e]=i).config}},l="layui-upload-file",r="layui-upload-form",F="layui-upload-iframe",w="layui-upload-choose",L="UPLOADING",z=function(e){var i=this;i.index=++s.index,i.config=x.extend({},i.config,s.config,e),i.render()};z.prototype.config={accept:"images",exts:"",auto:!0,bindAction:"",url:"",force:"",field:"file",acceptMime:"",method:"post",data:{},drag:!0,size:0,number:0,multiple:!1,text:{"cross-domain":"Cross-domain requests are not supported","data-format-error":"Please return JSON data format","check-error":"",error:"","limit-number":null,"limit-size":null}},z.prototype.reload=function(e){var i=this;i.config=x.extend({},i.config,e),i.render(!0)},z.prototype.render=function(e){var i=this,t=i.config,n=x(t.elem);return 1"].join("")),n=i.elem.next();(n.hasClass(l)||n.hasClass(r))&&n.remove(),b.ie&&b.ie<10&&i.elem.wrap('
          '),e.isFile()?(e.elemFile=i.elem,i.field=i.elem[0].name):i.elem.after(t),b.ie&&b.ie<10&&e.initIE()},z.prototype.initIE=function(){var t,e=this.config,i=x(''),n=x(['
          ',"
          "].join(""));x("#"+F)[0]||x("body").append(i),e.elem.next().hasClass(r)||(this.elemFile.wrap(n),e.elem.next("."+r).append((t=[],layui.each(e.data,function(e,i){i="function"==typeof i?i():i,t.push('')}),t.join(""))))},z.prototype.msg=function(e){return i.msg(e,{icon:2,shift:6})},z.prototype.isFile=function(){var e=this.config.elem[0];if(e)return"input"===e.tagName.toLocaleLowerCase()&&"file"===e.type},z.prototype.preview=function(n){window.FileReader&&layui.each(this.chooseFiles,function(e,i){var t=new FileReader;t.readAsDataURL(i),t.onload=function(){n&&n(e,i,this.result)}})},z.prototype.upload=function(e,i){var t,n,a,o,u=this,f=u.config,c=f.text||{},l=u.elemFile[0],s=function(){return e||u.files||u.chooseFiles||l.files},r=function(){var a=0,o=0,l=s(),r=function(){f.multiple&&a+o===u.fileLength&&"function"==typeof f.allDone&&f.allDone({total:u.fileLength,successful:a,failed:o})},t=function(t){var n=new FormData,i=function(e){t.unified?layui.each(l,function(e,i){delete i[L]}):delete e[L]};if(layui.each(f.data,function(e,i){i="function"==typeof i?t.unified?i():i(t.index,t.file):i,n.append(e,i)}),t.unified)layui.each(l,function(e,i){i[L]||(i[L]=!0,n.append(f.field,i))});else{if(t.file[L])return;n.append(f.field,t.file),t.file[L]=!0}var e={url:f.url,type:"post",data:n,dataType:f.dataType||"json",contentType:!1,processData:!1,headers:f.headers||{},success:function(e){f.unified?a+=u.fileLength:a++,p(t.index,e),r(t.index),i(t.file)},error:function(e){f.unified?o+=u.fileLength:o++,u.msg(c.error||["Upload failed, please try again.","status: "+(e.status||"")+" - "+(e.statusText||"error")].join("
          ")),m(t.index),r(t.index),i(t.file)}};"function"==typeof f.progress&&(e.xhr=function(){var e=x.ajaxSettings.xhr();return e.upload.addEventListener("progress",function(e){var i;e.lengthComputable&&(i=Math.floor(e.loaded/e.total*100),f.progress(i,(f.item||f.elem)[0],e,t.index))}),e}),x.ajax(e)};f.unified?t({unified:!0,index:0}):layui.each(l,function(e,i){t({index:e,file:i})})},d=function(){var n=x("#"+F);u.elemFile.parent().submit(),clearInterval(z.timer),z.timer=setInterval(function(){var e,i=n.contents().find("body");try{e=i.text()}catch(t){u.msg(c["cross-domain"]),clearInterval(z.timer),m()}e&&(clearInterval(z.timer),i.html(""),p(0,e))},30)},p=function(e,i){if(u.elemFile.next("."+w).remove(),l.value="","json"===f.force&&"object"!=typeof i)try{i=JSON.parse(i)}catch(t){return i={},u.msg(c["data-format-error"])}"function"==typeof f.done&&f.done(i,e||0,function(e){u.upload(e)})},m=function(e){f.auto&&(l.value=""),"function"==typeof f.error&&f.error(e||0,function(e){u.upload(e)})},h=f.exts,g=(n=[],layui.each(e||u.chooseFiles,function(e,i){n.push(i.name)}),n),v={preview:function(e){u.preview(e)},upload:function(e,i){var t={};t[e]=i,u.upload(t)},pushFile:function(){return u.files=u.files||{},layui.each(u.chooseFiles,function(e,i){u.files[e]=i}),u.files},resetFile:function(e,i,t){i=new File([i],t);u.files=u.files||{},u.files[e]=i},getChooseFiles:function(){return u.chooseFiles}},y={file:"\u6587\u4ef6",images:"\u56fe\u7247",video:"\u89c6\u9891",audio:"\u97f3\u9891"}[f.accept]||"\u6587\u4ef6",g=0===g.length?l.value.match(/[^\/\\]+\..+/g)||[]:g;if(0!==g.length){switch(f.accept){case"file":layui.each(g,function(e,i){if(h&&!RegExp(".\\.("+h+")$","i").test(escape(i)))return t=!0});break;case"video":layui.each(g,function(e,i){if(!RegExp(".\\.("+(h||"avi|mp4|wma|rmvb|rm|flash|3gp|flv")+")$","i").test(escape(i)))return t=!0});break;case"audio":layui.each(g,function(e,i){if(!RegExp(".\\.("+(h||"mp3|wav|mid")+")$","i").test(escape(i)))return t=!0});break;default:layui.each(g,function(e,i){if(!RegExp(".\\.("+(h||"jpg|png|gif|bmp|jpeg|svg|webp")+")$","i").test(escape(i)))return t=!0})}if(t)return u.msg(c["check-error"]||"\u9009\u62e9\u7684"+y+"\u4e2d\u5305\u542b\u4e0d\u652f\u6301\u7684\u683c\u5f0f"),l.value="";if("choose"!==i&&!f.auto||(f.choose&&f.choose(v),"choose"!==i)){if(u.fileLength=(a=0,y=s(),layui.each(y,function(){a++}),a),f.number&&u.fileLength>f.number)return u.msg("function"==typeof c["limit-number"]?c["limit-number"](f,u.fileLength):"\u540c\u65f6\u6700\u591a\u53ea\u80fd\u4e0a\u4f20: "+f.number+" \u4e2a\u6587\u4ef6
          \u60a8\u5f53\u524d\u5df2\u7ecf\u9009\u62e9\u4e86: "+u.fileLength+" \u4e2a\u6587\u4ef6");if(01024*f.size&&(i=1<=(i=f.size/1024)?i.toFixed(2)+"MB":f.size+"KB",l.value="",o=i)}),o)return u.msg("function"==typeof c["limit-size"]?c["limit-size"](f,o):"\u6587\u4ef6\u5927\u5c0f\u4e0d\u80fd\u8d85\u8fc7 "+o);if(!f.before||!1!==f.before(v))b.ie?(9'+e+"")},r=function(t){var n=!0;return layui.each(a.files,function(e,i){if(!(n=!(i.name===t.name)))return!0}),n},u=function(e){var t=function(e){e.ext=e.name.substr(e.name.lastIndexOf(".")+1).toLowerCase(),e.sizes=s.util.parseSize(e.size)};return e instanceof FileList?layui.each(e,function(e,i){t(i)}):t(e),e},f=function(e){var t;return(e=e||[]).length?a.files?(t=[],layui.each(e,function(e,i){r(i)&&t.push(u(i))}),t):u(e):[]};n.elem.off("upload.start").on("upload.start",function(){var e=x(this);a.config.item=e,a.elemFile[0].click()}),b.ie&&b.ie<10||n.elem.off("upload.over").on("upload.over",function(){x(this).attr("lay-over","")}).off("upload.leave").on("upload.leave",function(){x(this).removeAttr("lay-over")}).off("upload.drop").on("upload.drop",function(e,i){var t=x(this),i=f(i.originalEvent.dataTransfer.files);t.removeAttr("lay-over"),o(i),n.auto?a.upload():l(i)}),a.elemFile.on("change",function(){var e=f(this.files);0!==e.length&&(o(e),n.auto?a.upload():l(e))}),n.bindAction.off("upload.action").on("upload.action",function(){a.upload()}),n.elem.data(c)||(n.elem.on("click",function(){a.isFile()||x(this).trigger("upload.start")}),n.drag&&n.elem.on("dragover",function(e){e.preventDefault(),x(this).trigger("upload.over")}).on("dragleave",function(e){x(this).trigger("upload.leave")}).on("drop",function(e){e.preventDefault(),x(this).trigger("upload.drop",e)}),n.bindAction.on("click",function(){x(this).trigger("upload.action")}),n.elem.data(c,n.id))},s.util={parseSize:function(e,i){var t,n;return i=i||2,null!=e&&e?(t="string"==typeof e?parseFloat(e):e,n=Math.floor(Math.log(t)/Math.log(1024)),(e=(e=t/Math.pow(1024,n))%1==0?e:parseFloat(e.toFixed(i)))+["Bytes","Kb","Mb","Gb","Tb","Pb","Eb","Zb","Yb"][n]):"0"}},o.that={},o.getThis=function(e){var i=o.that[e];return i||hint.error(e?t+" instance with ID '"+e+"' not found":"ID argument required"),i},s.render=function(e){e=new z(e);return o.call(e)},e(t,s)});layui.define(["lay","layer","util"],function(e){"use strict";var T=layui.$,h=layui.layer,N=layui.util,l=layui.hint(),$=(layui.device(),"form"),u=".layui-form",_="layui-this",F="layui-hide",A="layui-disabled",t=function(){this.config={verify:{required:function(e){if(!/[\S]+/.test(e))return"\u5fc5\u586b\u9879\u4e0d\u80fd\u4e3a\u7a7a"},phone:function(e){if(e&&!/^1\d{10}$/.test(e))return"\u624b\u673a\u53f7\u683c\u5f0f\u4e0d\u6b63\u786e"},email:function(e){if(e&&!/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/.test(e))return"\u90ae\u7bb1\u683c\u5f0f\u4e0d\u6b63\u786e"},url:function(e){if(e&&!/^(#|(http(s?)):\/\/|\/\/)[^\s]+\.[^\s]+$/.test(e))return"\u94fe\u63a5\u683c\u5f0f\u4e0d\u6b63\u786e"},number:function(e){if(e&&isNaN(e))return"\u53ea\u80fd\u586b\u5199\u6570\u5b57"},date:function(e){if(e&&!/^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/.test(e))return"\u65e5\u671f\u683c\u5f0f\u4e0d\u6b63\u786e"},identity:function(e){if(e&&!/(^\d{15}$)|(^\d{17}(x|X|\d)$)/.test(e))return"\u8eab\u4efd\u8bc1\u53f7\u683c\u5f0f\u4e0d\u6b63\u786e"}},autocomplete:null}},i=(t.prototype.set=function(e){return T.extend(!0,this.config,e),this},t.prototype.verify=function(e){return T.extend(!0,this.config.verify,e),this},t.prototype.getFormElem=function(e){return T(u+(e?'[lay-filter="'+e+'"]':""))},t.prototype.on=function(e,t){return layui.onevent.call(this,$,e,t)},t.prototype.val=function(e,i){return this.getFormElem(e).each(function(e,t){var a=T(this);layui.each(i,function(e,t){var i,e=a.find('[name="'+e+'"]');e[0]&&("checkbox"===(i=e[0].type)?e[0].checked=t:"radio"===i?e.each(function(){this.checked=this.value==t+""}):e.val(t))})}),r.render(null,e),this.getValue(e)},t.prototype.getValue=function(e,t){t=t||this.getFormElem(e);var a={},n={},e=t.find("input,select,textarea");return layui.each(e,function(e,t){var i;T(this);t.name=(t.name||"").replace(/^\s*|\s*&/,""),t.name&&(/^.*\[\]$/.test(t.name)&&(i=t.name.match(/^(.*)\[\]$/g)[0],a[i]=0|a[i],i=t.name.replace(/^(.*)\[\]$/,"$1["+a[i]+++"]")),/^(checkbox|radio)$/.test(t.type)&&!t.checked||(n[i||t.name]=t.value))}),n},t.prototype.render=function(e,t){var i=this.config,a=T(u+(t?'[lay-filter="'+t+'"]':"")),n={input:function(e){var e=e||a.find("input,textarea"),t=(i.autocomplete&&e.attr("autocomplete",i.autocomplete),function(e,t){var i=e.val(),a=Number(i),n=Number(e.attr("step"))||1,l=Number(e.attr("min")),r=Number(e.attr("max")),s=Number(e.attr("lay-precision")),o="click"!==t&&""===i,c="init"===t;isNaN(a)||("click"===t&&(a=!!T(this).index()?a-n:a+n),t=function(e){return((e.toString().match(/\.(\d+$)/)||[])[1]||"").length},s=0<=s?s:Math.max(t(n),t(i)),o||(c||r<=(a=a<=l?l:a)&&(a=r),0===s?a=parseInt(a):0'),e=layui.isArray(i.value)?i.value:[i.value],e=T((a=[],layui.each(e,function(e,t){a.push('')}),a.join(""))),n=(t.append(e),i.split&&t.addClass("layui-input-split"),i.className&&t.addClass(i.className),r.next("."+u)),l=(n[0]&&n.remove(),r.parent().hasClass(o)||r.wrap('
          '),r.next("."+c));l[0]?((n=l.find("."+u))[0]&&n.remove(),l.prepend(t),r.css("padding-right",function(){return(r.closest(".layui-input-group")[0]?0:l.outerWidth())+t.outerWidth()})):(t.addClass(c),r.after(t)),"auto"===i.show&&d(t,r.val()),"function"==typeof i.init&&i.init.call(this,r,i),r.on("input propertychange",function(){var e=this.value;"auto"===i.show&&d(t,e)}),r.on("blur",function(){"function"==typeof i.blur&&i.blur.call(this,r,i)}),e.on("click",function(){var e=r.attr("lay-filter");T(this).hasClass(A)||("function"==typeof i.click&&i.click.call(this,r,i),layui.event.call(this,$,"input-affix("+e+")",{elem:r[0],affix:s,options:i}))})},f={eye:{value:"eye-invisible",click:function(e,t){var i="LAY_FORM_INPUT_AFFIX_SHOW",a=e.data(i);e.attr("type",a?"password":"text").data(i,!a),n({value:a?"eye-invisible":"eye"})}},clear:{value:"clear",click:function(e){e.val("").focus(),d(T(this).parent(),null)},show:"auto",disabled:e},number:{value:["up","down"],split:!0,className:"layui-input-number",disabled:r.is("[disabled]"),init:function(e){t.call(this,e,"init")},click:function(e){t.call(this,e,"click")},blur:function(e){t.call(this,e,"blur")}}};n()})},select:function(e){var m,u="\u8bf7\u9009\u62e9",g="layui-form-select",b="layui-select-title",x="layui-select-none",k="layui-select-create-option",C="",e=e||a.find("select"),w=function(e,t){T(e.target).parent().hasClass(b)&&!t||((e=T("."+g)).removeClass(g+"ed "+g+"up"),e.hasClass("layui-select-creatable")&&e.children("dl").children("."+k).remove(),m&&C&&m.val(C)),m=null},d=function(n,e,t,c){var s,u,a,i,o,d,l,r=T(this),f=n.find("."+b),h=f.find("input"),y=n.find("dl"),p=(y.children("dd"),y.children("dt")),v=this.selectedIndex;e||(u=r.attr("lay-search"),a=!(!lay.ie||"10"!==lay.ie&&"11"!==lay.ie||!h.attr("placeholder")),i=function(){var e=n.offset().top+n.outerHeight()+5-j.scrollTop(),t=y.outerHeight(),i=y.children("dd");v=r[0].selectedIndex,n.addClass(g+"ed"),i.removeClass(F),p.removeClass(F),s=null,i.removeClass(_),0<=v&&i.eq(v).addClass(_),e+t>j.height()&&t<=e&&n.addClass(g+"up"),d(),a&&y.off("mousedown.select.ieph").on("mousedown.select.ieph",function(){h[0].__ieph=!0,setTimeout(function(){h[0].__ieph=!1},60)})},o=function(e){n.removeClass(g+"ed "+g+"up"),h.blur(),s=null,c&&y.children("."+k).remove(),e||l(h.val(),function(e){var t=r[0].selectedIndex;e&&(C=T(r[0].options[t]).html(),0===t&&C===h.attr("placeholder")&&(C=""),h.val(C||""))})},d=function(){var e,t,i=y.children("dd."+_);i[0]&&(e=i.position().top,t=y.height(),i=i.height(),t")).addClass(k).attr("lay-value",i).html(N.escape(i)),y.append(t)):e?y.find("."+x)[0]||y.append('

          \u65e0\u5339\u914d\u9879

          '):y.find("."+x).remove()},"keyup"),""===i&&(r.val(""),y.find("."+_).removeClass(_),(r[0].options[0]||{}).value||y.children("dd:eq(0)").addClass(_),y.find("."+x).remove(),c)&&y.children("."+k).remove(),void d()))},50)).on("blur",function(e){var t=r[0].selectedIndex;m=h,C=T(r[0].options[t]).text(),0===t&&C===h.attr("placeholder")&&(C=""),setTimeout(function(){l(h.val(),function(e){C||h.val("")},"blur")},200)}),y.on("click","dd",function(){var e,t=T(this),i=t.attr("lay-value"),a=r.attr("lay-filter");return t.hasClass(A)||(t.hasClass("layui-select-tips")?h.val(""):(h.val(t.text()),t.addClass(_)),c&&t.hasClass(k)&&(t.removeClass(k),(e=T("
          "].join(""));i.after(l),function(a,n){var l=T(this);a.on("click",function(){var e=T(this),t=l.attr("lay-filter"),e=e.next("*[lay-checkbox]")[0]?e.next().html():l.attr("title")||"",i=l.attr("lay-skin")||"primary",e="switch"===i?e.split("|"):[e];l[0].disabled||(l[0].indeterminate&&(l[0].indeterminate=!1,a.find("."+c.SUBTRA).removeClass(c.SUBTRA).addClass("layui-icon-ok")),l[0].checked?(l[0].checked=!1,a.removeClass(n[1]),"switch"===i&&a.children("div").html(e[1])):(l[0].checked=!0,a.addClass(n[1]),"switch"===i&&a.children("div").html(e[0])),layui.event.call(l[0],$,n[2]+"("+t+")",{elem:l[0],value:l[0].value,othis:a}))})}.call(this,l,r)})},radio:function(e){var o="layui-form-radio",c=["layui-icon-radio","layui-icon-circle"],e=e||a.find("input[type=radio]");e.each(function(e,t){var i=T(this),a=i.next("."+o),n=this.disabled,l=i.attr("lay-skin");if("string"==typeof i.attr("lay-ignore"))return i.show();a[0]&&a.remove();var a=N.escape(t.title||""),r=[],s=(i.next("[lay-radio]")[0]&&(a=(s=i.next()).html()||"",1",'',"
          "+a+"
          ","
          "].join("")));i.after(s),function(a){var n=T(this),l="layui-anim-scaleSpring";a.on("click",function(){var e=n[0].name,t=n.parents(u),i=n.attr("lay-filter"),e=t.find("input[name="+e.replace(/(\.|#|\[|\])/g,"\\$1")+"]");n[0].disabled||(layui.each(e,function(){var e=T(this).next("."+o);this.checked=!1,e.removeClass(o+"ed"),e.children(".layui-icon").removeClass(l+" "+c[0]).addClass(c[1])}),n[0].checked=!0,a.addClass(o+"ed"),a.children(".layui-icon").addClass(l+" "+c[0]),layui.event.call(n[0],$,"radio("+i+")",{elem:n[0],value:n[0].value,othis:a}))})}.call(this,s)})}},t=function(){layui.each(n,function(e,t){t()})};return"object"===layui.type(e)?T(e).is(u)?(a=T(e),t()):e.each(function(e,t){var i=T(t);i.closest(u).length&&("SELECT"===t.tagName?n.select(i):"INPUT"===t.tagName&&("checkbox"===(t=t.type)||"radio"===t?n[t](i):n.input(i)))}):e?n[e]?n[e]():l.error('\u4e0d\u652f\u6301\u7684 "'+e+'" \u8868\u5355\u6e32\u67d3'):t(),this},t.prototype.validate=function(e){var u,d=this.config.verify,f="layui-form-danger";return!(e=T(e))[0]||(e.attr("lay-verify")!==undefined||!1!==this.validate(e.find("*[lay-verify]")))&&(layui.each(e,function(e,r){var s=T(this),t=(s.attr("lay-verify")||"").split("|"),o=s.attr("lay-vertype"),c=T.trim(s.val());if(s.removeClass(f),layui.each(t,function(e,t){var i="",a=d[t];if(a){var n="function"==typeof a?i=a(c,r):!a[0].test(c),l="select"===r.tagName.toLowerCase()||/^(checkbox|radio)$/.test(r.type),i=i||a[1];if("required"===t&&(i=s.attr("lay-reqtext")||i),n)return"tips"===o?h.tips(i,"string"!=typeof s.attr("lay-ignore")&&l?s.next():s,{tips:1}):"alert"===o?h.alert(i,{title:"\u63d0\u793a",shadeClose:!0}):/\b(string|number)\b/.test(typeof i)&&h.msg(i,{icon:5,shift:6}),setTimeout(function(){(l?s.next().find("input"):r).focus()},7),s.addClass(f),u=!0}}),u)return u}),!u)},t.prototype.submit=function(e,t){var i={},a=T(this),e="string"==typeof e?e:a.attr("lay-filter"),n=this.getFormElem?this.getFormElem(e):a.parents(u).eq(0),l=n.find("*[lay-verify]");return!!r.validate(l)&&(i=r.getValue(null,n),l={elem:this.getFormElem?window.event&&window.event.target:this,form:(this.getFormElem?n:a.parents("form"))[0],field:i},"function"==typeof t&&t(l),layui.event.call(this,$,"submit("+e+")",l))}),r=new t,t=T(document),j=T(window);T(function(){r.render()}),t.on("reset",u,function(){var e=T(this).attr("lay-filter");setTimeout(function(){r.render(null,e)},50)}),t.on("submit",u,i).on("click","*[lay-submit]",i),e($,r)});layui.define(["lay","laytpl","laypage","form","util"],function(n){"use strict";var f=layui.$,d=layui.lay,m=layui.laytpl,O=layui.laypage,p=layui.layer,v=layui.form,g=layui.util,b=layui.hint(),x=layui.device(),k={config:{checkName:"LAY_CHECKED",indexName:"LAY_INDEX",numbersName:"LAY_NUM",disabledName:"LAY_DISABLED"},cache:{},index:layui.table?layui.table.index+1e4:0,set:function(e){return this.config=f.extend({},this.config,e),this},on:function(e,t){return layui.onevent.call(this,N,e,t)}},w=function(){var a=this,e=a.config,i=e.id||e.index;return{config:e,reload:function(e,t){a.reload.call(a,e,t)},reloadData:function(e,t){k.reloadData(i,e,t)},setColsWidth:function(){a.setColsWidth.call(a)},resize:function(){a.resize.call(a)}}},C=function(e){var t=w.that[e];return t||b.error(e?"The table instance with ID '"+e+"' not found":"ID argument required"),t||null},l=function(e){var t=w.config[e];return t||b.error(e?"The table instance with ID '"+e+"' not found":"ID argument required"),t||null},T=function(e){var t=this.config||{},a=(e=e||{}).item3,i=e.content;"numbers"===a.type&&(i=e.tplData[k.config.numbersName]);("escape"in a?a:t).escape&&(i=g.escape(i));t=e.text&&a.exportTemplet||a.templet||a.toolbar;return t&&(i="function"==typeof t?t.call(a,e.tplData,e.obj):m(function(e){try{return d(e).html()}catch(t){return e}}(t)||String(i)).render(f.extend({LAY_COL:a},e.tplData))),e.text?f("
          "+i+"
          ").text():i},N="table",R="lay-"+N+"-id",t=".layui-table",D="layui-hide",y="layui-hide-v",h="layui-none",L="layui-table-view",o=".layui-table-header",E=".layui-table-body",u=".layui-table-fixed-r",P=".layui-table-pageview",A=".layui-table-sort",_="layui-table-checked",M="layui-table-edit",W="layui-table-hover",I="laytable-cell-group",H="layui-table-col-special",j="layui-table-tool-panel",S="layui-table-expanded",F="LAY_TABLE_MOVE_DICT",e=function(e){return['',"","{{# layui.each(d.data.cols, function(i1, item1){ }}","","{{# layui.each(item1, function(i2, item2){ }}",'{{# if(item2.fixed && item2.fixed !== "right"){ left = true; } }}','{{# if(item2.fixed === "right"){ right = true; } }}',(e=e||{}).fixed&&"right"!==e.fixed?'{{# if(item2.fixed && item2.fixed !== "right"){ }}':"right"===e.fixed?'{{# if(item2.fixed === "right"){ }}':"","{{# var isSort = !(item2.colGroup) && item2.sort; }}",'",e.fixed?"{{# }; }}":"","{{# }); }}","","{{# }); }}","","
          ','
          ','{{# if(item2.type === "checkbox"){ }}','',"{{# } else { }}",'{{-item2.title||""}}',"{{# if(isSort){ }}",'',"{{# } }}","{{# } }}","
          ","
          "].join("")},a=['',"","
          "].join(""),s=[,"{{# if(d.data.toolbar){ }}",'
          ','
          ','
          ',"
          ","{{# } }}",'
          ',"{{# if(d.data.loading){ }}",'
          ','
          ','{{# if(typeof d.data.loading === "string"){ }}',"{{- d.data.loading}}","{{# } else{ }}",'',"{{# } }}","
          ","
          ","{{# } }}","{{# var left, right; }}",'
          ',e(),"
          ",'
          ',a,"
          ","{{# if(left){ }}",'
          ','
          ',e({fixed:!0}),"
          ",'
          ',a,"
          ","
          ","{{# }; }}","{{# if(right){ }}",'
          ','
          ',e({fixed:"right"}),'
          ',"
          ",'
          ',a,"
          ","
          ","{{# }; }}","
          ","{{# if(d.data.totalRow){ }}",'
          ','','',"
          ","
          ","{{# } }}",'
          ','
          ',"
          "].join(""),r=f(window),z=f(document),i=function(e){this.index=++k.index,this.config=f.extend({},this.config,k.config,e),this.render()},c=(i.prototype.config={limit:10,loading:!0,escape:!0,cellMinWidth:60,cellMaxWidth:Number.MAX_VALUE,editTrigger:"click",defaultToolbar:["filter","exports","print"],defaultContextmenu:!0,autoSort:!0,text:{none:"\u65e0\u6570\u636e"},cols:[]},i.prototype.render=function(e){var t=this,a=t.config,i=(a.elem=f(a.elem),a.where=a.where||{},a.id="id"in a?a.id:a.elem.attr("id")||t.index);if(w.that[i]=t,(w.config[i]=a).request=f.extend({pageName:"page",limitName:"limit"},a.request),a.response=f.extend({statusName:"code",statusCode:0,msgName:"msg",dataName:"data",totalRowName:"totalRow",countName:"count"},a.response),null!==a.page&&"object"==typeof a.page&&(a.limit=a.page.limit||a.limit,a.limits=a.page.limits||a.limits,t.page=a.page.curr=a.page.curr||1,delete a.page.elem,delete a.page.jump),!a.elem[0])return t;if(a.elem.attr("lay-filter")||a.elem.attr("lay-filter",a.id),"reloadData"===e)return t.pullData(t.page,{type:"reloadData"});a.index=t.index,t.key=a.id||a.index,t.setInit(),a.height&&/^full-.+$/.test(a.height)?(t.fullHeightGap=a.height.split("-")[1],a.height=r.height()-(parseFloat(t.fullHeightGap)||0)):a.height&&/^#\w+\S*-.+$/.test(a.height)?(i=a.height.split("-"),t.parentHeightGap=i.pop(),t.parentDiv=i.join("-"),a.height=f(t.parentDiv).height()-(parseFloat(t.parentHeightGap)||0)):"function"==typeof a.height&&(t.customHeightFunc=a.height,a.height=t.customHeightFunc());var l,e=a.elem,i=e.next("."+L),n=t.elem=f("
          ");n.addClass((l=[L,L+"-"+t.index,"layui-form","layui-border-box"],a.className&&l.push(a.className),l.join(" "))).attr(((l={"lay-filter":"LAY-TABLE-FORM-DF-"+t.index,style:(l=[],a.width&&l.push("width:"+a.width+"px;"),l.join(""))})[R]=a.id,l)).html(m(s,{open:"{{",close:"}}"}).render({data:a,index:t.index})),t.renderStyle(),i[0]&&(t.resizeObserver&&t.resizeObserver.unobserve(t.elem[0]),i.remove()),e.after(n),t.layTool=n.find(".layui-table-tool"),t.layBox=n.find(".layui-table-box"),t.layHeader=n.find(o),t.layMain=n.find(".layui-table-main"),t.layBody=n.find(E),t.layFixed=n.find(".layui-table-fixed"),t.layFixLeft=n.find(".layui-table-fixed-l"),t.layFixRight=n.find(u),t.layTotal=n.find(".layui-table-total"),t.layPage=n.find(".layui-table-page"),t.renderToolbar(),t.renderPagebar(),t.fullSize(),t.pullData(t.page),t.events()},i.prototype.initOpts=function(e){this.config;e.checkbox&&(e.type="checkbox"),e.space&&(e.type="space"),e.type||(e.type="normal"),"normal"!==e.type&&(e.unresize=!0,e.width=e.width||{checkbox:50,radio:50,space:30,numbers:60}[e.type])},i.prototype.setInit=function(e){var l,a,r=this,d=r.config;if(d.clientWidth=d.width||(l=function(e){var t,a=(e=e||d.elem.parent()).width();try{t="none"===e.css("display")}catch(i){}return!e[0]||a&&!t?a:l(e.parent())})(),"width"===e)return d.clientWidth;d.height=d.maxHeight||d.height,d.css&&-1===d.css.indexOf(L)&&(a=d.css.split("}"),layui.each(a,function(e,t){t&&(a[e]="."+L+"-"+r.index+" "+t)}),d.css=a.join("}"));var c=function(a,e,i,l){var n,o;l?(l.key=[d.index,a,i].join("-"),l.colspan=l.colspan||0,l.rowspan=l.rowspan||0,r.initOpts(l),(n=a+(parseInt(l.rowspan)||1)) td:hover > .layui-table-cell{overflow: auto;}"].concat(x.ie?[".layui-table-edit{height: "+i+";}","td[data-edit]:hover:after{height: "+i+";}"]:[]),function(e,t){t&&o.push(a+" "+t)})),l.css&&o.push(l.css),d.style({target:this.elem[0],text:o.join(""),id:"DF-table-"+n})},i.prototype.renderToolbar=function(){var e=this.config,t=['
          ','
          ','
          '].join(""),a=this.layTool.find(".layui-table-tool-temp"),i=("default"===e.toolbar?a.html(t):"string"==typeof e.toolbar&&(t=f(e.toolbar).html()||"")&&a.html(m(t).render(e)),{filter:{title:"\u7b5b\u9009\u5217",layEvent:"LAYTABLE_COLS",icon:"layui-icon-cols"},exports:{title:"\u5bfc\u51fa",layEvent:"LAYTABLE_EXPORT",icon:"layui-icon-export"},print:{title:"\u6253\u5370",layEvent:"LAYTABLE_PRINT",icon:"layui-icon-print"}}),l=[];"object"==typeof e.defaultToolbar&&layui.each(e.defaultToolbar,function(e,t){t="string"==typeof t?i[t]:t;t&&l.push('
          ')}),this.layTool.find(".layui-table-tool-self").html(l.join(""))},i.prototype.renderPagebar=function(){var e,t=this.config,a=this.layPagebar=f('
          ');t.pagebar&&((e=f(t.pagebar).html()||"")&&a.append(m(e).render(t)),this.layPage.append(a))},i.prototype.setParentCol=function(e,t){var a=this.config,i=this.layHeader.find('th[data-key="'+t+'"]'),l=parseInt(i.attr("colspan"))||0;i[0]&&(t=t.split("-"),t=a.cols[t[1]][t[2]],e?l--:l++,i.attr("colspan",l),i[l?"removeClass":"addClass"](D),t.colspan2=l,t.hide=l<1,a=i.data("parentkey"))&&this.setParentCol(e,a)},i.prototype.setColsPatch=function(){var a=this,e=a.config;layui.each(e.cols,function(e,t){layui.each(t,function(e,t){t.hide&&a.setParentCol(t.hide,t.parentKey)})})},i.prototype.setGroupWidth=function(i){var e,l=this;l.config.cols.length<=1||((e=l.layHeader.find((i?"th[data-key="+i.data("parentkey")+"]>":"")+"."+I)).css("width",0),layui.each(e.get().reverse(),function(){var e=f(this),t=e.parent().data("key"),a=0;l.layHeader.eq(0).find("th[data-parentkey="+t+"]").width(function(e,t){f(this).hasClass(D)||0 tr:first-child > th:last-child")).data("field")&&e.prev()[0]?t(e.prev()):e})()).data("key"),n.cssRules(e,function(e){var t=e.style.width||a.outerWidth();e.style.width=parseFloat(t)+l+"px",0'+(e||"Error")+"");a[0]&&(t.layNone.remove(),a.remove()),t.layFixed.addClass(D),t.layMain.find("tbody").html(""),t.layMain.append(t.layNone=e),t.layTotal.addClass(y),t.layPage.find(P).addClass(y),k.cache[t.key]=[],t.syncCheckAll(),t.renderForm(),t.setColsWidth(),t.loading(!1)},i.prototype.page=1,i.prototype.pullData=function(a,t){var e,i,l=this,n=l.config,o=(n.HAS_SET_COLS_PATCH||l.setColsPatch(),n.HAS_SET_COLS_PATCH=!0,n.request),r=n.response,d=function(){"object"==typeof n.initSort&&l.sort({field:n.initSort.field,type:n.initSort.type,reloadType:t.type})},c=function(e,t){l.setColsWidth(),l.loading(!1),"function"==typeof n.done&&n.done(e,a,e[r.countName],t)};t=t||{},"function"==typeof n.before&&n.before(n),l.startTime=(new Date).getTime(),t.renderData?((e={})[r.dataName]=k.cache[l.key],e[r.countName]=n.url?"object"===layui.type(n.page)?n.page.count:e[r.dataName].length:n.data.length,"object"==typeof n.totalRow&&(e[r.totalRowName]=f.extend({},l.totalRow)),l.renderData({res:e,curr:a,count:e[r.countName],type:t.type,sort:!0}),c(e,"renderData")):n.url?(i={},n.page&&(i[o.pageName]=a,i[o.limitName]=n.limit),o=f.extend(i,n.where),n.contentType&&0==n.contentType.indexOf("application/json")&&(o=JSON.stringify(o)),l.loading(!0),f.ajax({type:n.method||"get",url:n.url,contentType:n.contentType,data:o,dataType:n.dataType||"json",jsonpCallback:n.jsonpCallback,headers:n.headers||{},complete:"function"==typeof n.complete?n.complete:undefined,success:function(e){(e="function"==typeof n.parseData?n.parseData(e)||e:e)[r.statusName]!=r.statusCode?l.errorView(e[r.msgName]||'\u8fd4\u56de\u7684\u6570\u636e\u4e0d\u7b26\u5408\u89c4\u8303\uff0c\u6b63\u786e\u7684\u6210\u529f\u72b6\u6001\u7801\u5e94\u4e3a\uff1a"'+r.statusName+'": '+r.statusCode):(l.totalRow=e[r.totalRowName],l.renderData({res:e,curr:a,count:e[r.countName],type:t.type}),d(),n.time=(new Date).getTime()-l.startTime+" ms"),c(e,t.type)},error:function(e,t){l.errorView("\u8bf7\u6c42\u5f02\u5e38\uff0c\u9519\u8bef\u63d0\u793a\uff1a"+t),"function"==typeof n.error&&n.error(e,t)}})):"array"===layui.type(n.data)&&(e={},i=a*n.limit-n.limit,o=n.data.concat(),e[r.dataName]=n.page?o.splice(i,n.limit):o,e[r.countName]=n.data.length,"object"==typeof n.totalRow&&(e[r.totalRowName]=f.extend({},n.totalRow)),l.totalRow=e[r.totalRowName],l.renderData({res:e,curr:a,count:e[r.countName],type:t.type}),d(),c(e,t.type))},i.prototype.eachCols=function(e){return k.eachCols(null,e,this.config.cols),this},i.prototype.col=function(e){try{return e=e.split("-"),this.config.cols[e[1]][e[2]]||{}}catch(t){return b.error(t),{}}},i.prototype.getTrHtml=function(a,l,n,e){var s=this,u=s.config,y=e&&e.trs||[],h=e&&e.trs_fixed||[],p=e&&e.trs_fixed_r||[];return n=n||1,layui.each(a,function(e,o){var i=[],r=[],d=[],c=e+u.limit*(n-1)+1;if("object"!=typeof o){a[e]=o={LAY_KEY:o};try{k.cache[s.key][e]=o}catch(t){}}"array"===layui.type(o)&&0===o.length||(o[k.config.numbersName]=c,l||(o[k.config.indexName]=e),s.eachCols(function(e,l){var t,e=l.field||e,a=l.key,n=o[e];n!==undefined&&null!==n||(n=""),l.colGroup||(e=['','
          "+function(){var e,t=f.extend(!0,{LAY_COL:l},o),a=k.config.checkName,i=k.config.disabledName;switch(l.type){case"checkbox":return'';case"radio":return'';case"numbers":return c}return l.toolbar?m(f(l.toolbar).html()||"").render(t):T.call(s,{item3:l,content:n,tplData:t})}(),"
          "].join(""),i.push(e),l.fixed&&"right"!==l.fixed&&r.push(e),"right"===l.fixed&&d.push(e))}),e=['data-index="'+e+'"'],o[k.config.checkName]&&e.push('class="'+_+'"'),e=e.join(" "),y.push(""+i.join("")+""),h.push(""+r.join("")+""),p.push(""+d.join("")+""))}),{trs:y,trs_fixed:h,trs_fixed_r:p}},k.getTrHtml=function(e,t){e=C(e);return e.getTrHtml(t,null,e.page)},i.prototype.renderData=function(e){var a=this,i=a.config,t=e.res,l=e.curr,n=a.count=e.count,o=e.sort,r=t[i.response.dataName]||[],t=t[i.response.totalRowName],d=[],c=[],s=[],u=function(){if(!o&&a.sortKey)return a.sort({field:a.sortKey.field,type:a.sortKey.sort,pull:!0,reloadType:e.type});a.getTrHtml(r,o,l,{trs:d,trs_fixed:c,trs_fixed_r:s}),"fixed"===i.scrollPos&&"reloadData"===e.type||a.layBody.scrollTop(0),"reset"===i.scrollPos&&a.layBody.scrollLeft(0),a.layMain.find("."+h).remove(),a.layMain.find("tbody").html(d.join("")),a.layFixLeft.find("tbody").html(c.join("")),a.layFixRight.find("tbody").html(s.join("")),a.syncCheckAll(),a.renderForm(),a.fullSize(),a.haveInit?a.scrollPatch():setTimeout(function(){a.scrollPatch()},50),a.haveInit=!0,p.close(a.tipsIndex)};return k.cache[a.key]=r,a.layTotal[0==r.length?"addClass":"removeClass"](y),a.layPage[i.page||i.pagebar?"removeClass":"addClass"](D),a.layPage.find(P)[!i.page||0==n||0===r.length&&1==l?"addClass":"removeClass"](y),0===r.length?a.errorView(i.text.none):(a.layFixLeft.removeClass(D),o?u():(u(),a.renderTotal(r,t),a.layTotal&&a.layTotal.removeClass(D),void(i.page&&(i.page=f.extend({elem:"layui-table-page"+i.index,count:n,limit:i.limit,limits:i.limits||[10,20,30,40,50,60,70,80,90],groups:3,layout:["prev","page","next","skip","count","limit"],prev:'',next:'',jump:function(e,t){t||(a.page=e.curr,i.limit=e.limit,a.pullData(e.curr))}},i.page),i.page.count=n,O.render(i.page)))))},k.renderData=function(e){e=C(e);e&&e.pullData(e.page,{renderData:!0,type:"reloadData"})},i.prototype.renderTotal=function(e,o){var r,d=this,c=d.config,s={};c.totalRow&&(layui.each(e,function(e,i){"array"===layui.type(i)&&0===i.length||d.eachCols(function(e,t){var e=t.field||e,a=i[e];t.totalRow&&(s[e]=(s[e]||0)+(parseFloat(a)||0))})}),d.dataTotal=[],r=[],d.eachCols(function(e,t){var a,e=t.field||e,i=o&&o[t.field],l="totalRowDecimals"in t?t.totalRowDecimals:2,l=s[e]?parseFloat(s[e]||0).toFixed(l):"",l=(a=t.totalRowText||"",(n={LAY_COL:t})[e]=l,n=t.totalRow&&T.call(d,{item3:t,content:l,tplData:n})||a,i||n),n=(t.field&&d.dataTotal.push({field:t.field,total:f("
          "+l+"
          ").text()}),['','
          "+("string"==typeof(a=t.totalRow||c.totalRow)?m(a).render(f.extend({TOTAL_NUMS:i||s[e],TOTAL_ROW:o||{},LAY_COL:t},t)):l),"
          "].join(""));r.push(n)}),e=d.layTotal.find(".layui-table-patch"),d.layTotal.find("tbody").html(""+r.join("")+(e.length?e.get(0).outerHTML:"")+""))},i.prototype.getColElem=function(e,t){return e.eq(0).find(".laytable-cell-"+t+":eq(0)")},i.prototype.renderForm=function(e){this.config;var t=this.elem.attr("lay-filter");v.render(e,t)},i.prototype.renderFormByElem=function(a){layui.each(["input","select"],function(e,t){v.render(a.find(t))})},i.prototype.syncCheckAll=function(){var a,e=this,i=e.config,t=e.layHeader.find('input[name="layTableCheckbox"]'),l=k.checkStatus(e.key);t[0]&&(a=l.isAll,e.eachCols(function(e,t){"checkbox"===t.type&&(t[i.checkName]=a)}),t.prop({checked:l.isAll,indeterminate:!l.isAll&&l.data.length}),v.render(t))},i.prototype.setRowActive=function(e,t,a){this.config;e=this.layBody.find('tr[data-index="'+e+'"]');if(t=t||"layui-table-click",a)return e.removeClass(t);e.addClass(t),e.siblings("tr").removeClass(t)},i.prototype.setRowChecked=function(i){var e=this,l=e.config,n="all"===i.index,o="array"===layui.type(i.index),r=(t=e.layBody.find("tr"),n?t:t.filter(o?function(){var e=f(this).data("index");return-1!==i.index.indexOf(e)}:'[data-index="'+i.index+'"]')),t=(i=f.extend({type:"checkbox"},i),k.cache[e.key]),a="checked"in i,d=function(e){return"radio"===i.type||(a?i.checked:!e)},t=(layui.each(t,function(e,t){var a;"array"===layui.type(t)||t[l.disabledName]||(n||(o?-1!==i.index.indexOf(e):Number(i.index)===e)?(a=t[l.checkName]=d(t[l.checkName]),(e=r.filter('[data-index="'+e+'"]'))[a?"addClass":"removeClass"](_),"radio"===i.type&&e.siblings().removeClass(_)):"radio"===i.type&&delete t[l.checkName])}),r.find('input[lay-type="'+({radio:"layTableRadio",checkbox:"layTableCheckbox"}[i.type]||"checkbox")+'"]:not(:disabled)')),c=t.last(),s=c.closest(u);("radio"===i.type&&s.hasClass(D)?t.first():t).prop("checked",d(c.prop("checked"))),e.syncCheckAll(),e.renderForm(i.type)},i.prototype.sort=function(l){var e,t=this,a={},i=t.config,n=i.elem.attr("lay-filter"),o=k.cache[t.key];"string"==typeof(l=l||{}).field&&(r=l.field,t.layHeader.find("th").each(function(e,t){var a=f(this),i=a.data("field");if(i===l.field)return l.field=a,r=i,!1}));try{var r=r||l.field.data("field"),d=l.field.data("key");if(t.sortKey&&!l.pull&&r===t.sortKey.field&&l.type===t.sortKey.sort)return;var c=t.layHeader.find("th .laytable-cell-"+d).find(A);t.layHeader.find("th").find(A).removeAttr("lay-sort"),c.attr("lay-sort",l.type||null),t.layFixed.find("th")}catch(s){b.error("Table modules: sort field '"+r+"' not matched")}t.sortKey={field:r,sort:l.type},i.autoSort&&("asc"===l.type?e=layui.sort(o,r,null,!0):"desc"===l.type?e=layui.sort(o,r,!0,!0):(e=layui.sort(o,k.config.indexName,null,!0),delete t.sortKey,delete i.initSort)),a[i.response.dataName]=e||o,t.renderData({res:a,curr:t.page,count:t.count,sort:!0,type:l.reloadType}),l.fromEvent&&(i.initSort={field:r,type:l.type},layui.event.call(l.field,N,"sort("+n+")",f.extend({config:i},i.initSort)))},i.prototype.loading=function(e){this.config.loading&&this.layBox.find(".layui-table-init").toggleClass(y,!e)},i.prototype.cssRules=function(t,a){var e=this.elem.children("style")[0];d.getStyleRules(e,function(e){if(e.selectorText===".laytable-cell-"+t)return a(e),!0})},i.prototype.fullSize=function(){var e,a,i=this,t=i.config,l=t.height;i.fullHeightGap?(l=r.height()-i.fullHeightGap)<135&&(l=135):i.parentDiv&&i.parentHeightGap?(l=f(i.parentDiv).height()-i.parentHeightGap)<135&&(l=135):i.customHeightFunc&&(l=i.customHeightFunc())<135&&(l=135),1
          ')).find("div").css({width:a}),e.find("tr").append(t)):e.find(".layui-table-patch").remove()};n(e.layHeader),n(e.layTotal);n=e.layMain.height()-i;e.layFixed.find(E).css("height",t.height()>=n?n:"auto").scrollTop(e.layMain.scrollTop()),e.layFixRight[k.cache[e.key]&&k.cache[e.key].length&&0');a.html(t),s.height&&a.css("max-height",s.height-(c.layTool.outerHeight()||50)),i.find("."+j)[0]||i.append(a),c.renderForm(),a.on("click",function(e){layui.stope(e)}),e.done&&e.done(a,t)};switch(layui.stope(e),z.trigger("table.tool.panel.remove"),p.close(c.tipsIndex),t){case"LAYTABLE_COLS":n({list:(a=[],c.eachCols(function(e,t){t.field&&"normal"==t.type&&a.push('
        • "+(t.fieldTitle||t.title||t.field)+"").text())+'" lay-filter="LAY_TABLE_TOOL_COLS">
        • ')}),a.join("")),done:function(){v.on("checkbox(LAY_TABLE_TOOL_COLS)",function(e){var e=f(e.elem),t=this.checked,a=e.data("key"),i=c.col(a),l=i.hide,e=e.data("parentkey");i.key&&(i.hide=!t,c.elem.find('*[data-key="'+a+'"]')[t?"removeClass":"addClass"](D),l!=i.hide&&c.setParentCol(!t,e),c.resize(),layui.event.call(this,N,"colToggled("+u+")",{col:i,config:s}))})}});break;case"LAYTABLE_EXPORT":if(!l.length)return p.tips("\u5f53\u524d\u8868\u683c\u65e0\u6570\u636e",this,{tips:3});x.ie?p.tips("\u5bfc\u51fa\u529f\u80fd\u4e0d\u652f\u6301 IE\uff0c\u8bf7\u7528 Chrome \u7b49\u9ad8\u7ea7\u6d4f\u89c8\u5668\u5bfc\u51fa",this,{tips:3}):n({list:['
        • \u5bfc\u51fa csv \u683c\u5f0f\u6587\u4ef6
        • ','
        • \u5bfc\u51fa xls \u683c\u5f0f\u6587\u4ef6
        • '].join(""),done:function(e,t){t.on("click",function(){var e=f(this).data("type");k.exportFile.call(c,s.id,null,e)})}});break;case"LAYTABLE_PRINT":if(!l.length)return p.tips("\u5f53\u524d\u8868\u683c\u65e0\u6570\u636e",this,{tips:3});var o=window.open("about:blank","_blank"),r=[""].join(""),d=f(c.layHeader.html());d.append(c.layMain.find("table").html()),d.append(c.layTotal.find("table").html()),d.find("th.layui-table-patch").remove(),d.find("thead>tr>th."+H).filter(function(e,t){return!f(t).children("."+I).length}).remove(),d.find("tbody>tr>td."+H).remove(),o.document.write(r+d.prop("outerHTML")),o.document.close(),layui.device("edg").edg?(o.onafterprint=o.close,o.print()):(o.print(),o.close())}layui.event.call(this,N,"toolbar("+u+")",f.extend({event:t,config:s},{}))}),c.layHeader.on("click","*[lay-event]",function(e){var t=f(this),a=t.attr("lay-event"),t=t.closest("th").data("key"),t=c.col(t);layui.event.call(this,N,"colTool("+u+")",f.extend({event:a,config:s,col:t},{}))}),c.layPagebar.on("click","*[lay-event]",function(e){var t=f(this).attr("lay-event");layui.event.call(this,N,"pagebar("+u+")",f.extend({event:t,config:s},{}))}),e.on("mousemove",function(e){var t=f(this),a=t.offset().left,e=e.clientX-a;t.data("unresize")||w.eventMoveElem||(r.allowResize=t.width()-e<=10,o.css("cursor",r.allowResize?"col-resize":""))}).on("mouseleave",function(){f(this);w.eventMoveElem||(r.allowResize=!1,o.css("cursor",""))}).on("mousedown",function(e){var t,a=f(this);r.allowResize&&(t=a.data("key"),e.preventDefault(),r.offset=[e.clientX,e.clientY],c.cssRules(t,function(e){var t=e.style.width||a.outerWidth();r.rule=e,r.ruleWidth=parseFloat(t),r.minWidth=a.data("minwidth")||s.cellMinWidth,r.maxWidth=a.data("maxwidth")||s.cellMaxWidth}),a.data(F,r),w.eventMoveElem=a)}),w.docEvent||z.on("mousemove",function(e){var t,a;w.eventMoveElem&&(t=w.eventMoveElem.data(F)||{},w.eventMoveElem.data("resizing",1),e.preventDefault(),t.rule)&&(e=t.ruleWidth+e.clientX-t.offset[0],a=w.eventMoveElem.closest("."+L).attr(R),a=C(a))&&((e=et.maxWidth&&(e=t.maxWidth),t.rule.style.width=e+"px",a.setGroupWidth(w.eventMoveElem),p.close(c.tipsIndex))}).on("mouseup",function(e){var t,a,i,l,n;w.eventMoveElem&&(i=(t=w.eventMoveElem).closest("."+L).attr(R),a=C(i))&&(i=t.data("key"),l=a.col(i),n=a.config.elem.attr("lay-filter"),r={},o.css("cursor",""),a.scrollPatch(),t.removeData(F),delete w.eventMoveElem,a.cssRules(i,function(e){l.width=parseFloat(e.style.width),layui.event.call(t[0],N,"colResized("+n+")",{col:l,config:a.config})}))}),w.docEvent=!0,e.on("click",function(e){var t=f(this),a=t.find(A),i=a.attr("lay-sort");if(!a[0]||1===t.data("resizing"))return t.removeData("resizing");c.sort({field:t,type:"asc"===i?"desc":"desc"===i?null:"asc",fromEvent:!0})}).find(A+" .layui-edge ").on("click",function(e){var t=f(this),a=t.index(),t=t.parents("th").eq(0).data("field");layui.stope(e),0===a?c.sort({field:t,type:"asc",fromEvent:!0}):c.sort({field:t,type:"desc",fromEvent:!0})}),c.commonMember=function(e){var a=f(this).parents("tr").eq(0).data("index"),t=c.layBody.find('tr[data-index="'+a+'"]'),i=(k.cache[c.key]||[])[a]||{},l={tr:t,config:s,data:k.clearCacheKey(i),dataCache:i,index:a,del:function(){k.cache[c.key][a]=[],t.remove(),c.scrollPatch()},update:function(e,t){c.updateRow({index:a,data:e=e||{},related:t},function(e,t){l.data[e]=t})},setRowChecked:function(e){c.setRowChecked(f.extend({index:a},e))}};return f.extend(l,e)}),a=(c.elem.on("click",'input[name="layTableCheckbox"]+',function(e){var t=f(this),a=t.closest("td"),t=t.prev(),i=(c.layBody.find('input[name="layTableCheckbox"]'),t.parents("tr").eq(0).data("index")),l=t[0].checked,n="layTableAllChoose"===t.attr("lay-filter");t[0].disabled||(n?c.setRowChecked({index:"all",checked:l}):(c.setRowChecked({index:i,checked:l}),layui.stope(e)),layui.event.call(t[0],N,"checkbox("+u+")",d.call(t[0],{checked:l,type:n?"all":"one",getCol:function(){return c.col(a.data("key"))}})))}),c.elem.on("click",'input[lay-type="layTableRadio"]+',function(e){var t=f(this),a=t.closest("td"),t=t.prev(),i=t[0].checked,l=t.parents("tr").eq(0).data("index");if(layui.stope(e),t[0].disabled)return!1;c.setRowChecked({type:"radio",index:l}),layui.event.call(t[0],N,"radio("+u+")",d.call(t[0],{checked:i,getCol:function(){return c.col(a.data("key"))}}))}),c.layBody.on("mouseenter","tr",function(){var e=f(this),t=e.index();e.data("off")||c.layBody.find("tr:eq("+t+")").addClass(W)}).on("mouseleave","tr",function(){var e=f(this),t=e.index();e.data("off")||c.layBody.find("tr:eq("+t+")").removeClass(W)}).on("click","tr",function(e){var t=[".layui-form-checkbox",".layui-form-switch",".layui-form-radio","[lay-unrow]"].join(",");f(e.target).is(t)||f(e.target).closest(t)[0]||a.call(this,"row")}).on("dblclick","tr",function(){a.call(this,"rowDouble")}).on("contextmenu","tr",function(e){s.defaultContextmenu||e.preventDefault(),a.call(this,"rowContextmenu")}),function(e){var t=f(this);t.data("off")||layui.event.call(this,N,e+"("+u+")",d.call(t.children("td")[0]))}),n=function(e,t){var a,i,l;(e=f(e)).data("off")||(l=e.data("field"),i=e.data("key"),i=c.col(i),a=e.closest("tr").data("index"),a=k.cache[c.key][a],e.children(y),(i="function"==typeof i.edit?i.edit(a):i.edit)&&((i=f("textarea"===i?'':''))[0].value=(l=e.data("content")||a[l])===undefined||null===l?"":l,e.find("."+M)[0]||e.append(i),i.focus(),t)&&layui.stope(t))},i=(c.layBody.on("change","."+M,function(){var e=f(this),t=e.parent(),a=this.value,i=e.parent().data("field"),e=e.closest("tr").data("index"),e=k.cache[c.key][e],l=d.call(t[0],{value:a,field:i,oldValue:e[i],td:t,reedit:function(){setTimeout(function(){n(l.td);var e={};e[i]=l.oldValue,l.update(e)})},getCol:function(){return c.col(t.data("key"))}}),e={};e[i]=a,l.update(e),layui.event.call(t[0],N,"edit("+u+")",l)}).on("blur","."+M,function(){f(this).remove()}),c.layBody.on(s.editTrigger,"td",function(e){n(this,e)}).on("mouseenter","td",function(){t.call(this)}).on("mouseleave","td",function(){t.call(this,"hide")}),c.layTotal.on("mouseenter","td",function(){t.call(this)}).on("mouseleave","td",function(){t.call(this,"hide")}),"layui-table-grid-down"),t=function(e){var t=f(this),a=t.children(y);t.data("off")||t.parent().hasClass(S)||(e?t.find(".layui-table-grid-down").remove():!(a.prop("scrollWidth")>a.prop("clientWidth")||0'))},l=function(e,t){var a=f(this),i=a.parent(),l=i.data("key"),n=c.col(l),o=i.parent().data("index"),r=i.children(y),i="layui-table-cell-c",d=f('');"tips"===(t=t||n.expandedMode||s.cellExpandedMode)?c.tipsIndex=p.tips(['
          ',r.html(),"
          ",''].join(""),r[0],{tips:[3,""],time:-1,anim:-1,maxWidth:x.ios||x.android?300:c.elem.width()/2,isOutAnim:!1,skin:"layui-table-tips",success:function(e,t){e.find(".layui-table-tips-c").on("click",function(){p.close(t)})}}):(c.elem.find("."+i).trigger("click"),c.cssRules(l,function(e){var t=e.style.width,a=n.expandedWidth||s.cellExpandedWidth;atr").each(function(i){n.cols[i]=[],f(this).children().each(function(e){var t=f(this),a=t.attr("lay-data"),a=d.options(this,{attr:a?"lay-data":null,errorText:r+(a||t.attr("lay-options"))}),t=f.extend({title:t.text(),colspan:parseInt(t.attr("colspan"))||1,rowspan:parseInt(t.attr("rowspan"))||1},a);n.cols[i].push(t)})}),e.find("tbody>tr")),t=k.render(n);!a.length||o.data||t.config.url||(l=0,k.eachCols(t.config.id,function(e,i){a.each(function(e){n.data[e]=n.data[e]||{};var t=f(this),a=i.field;n.data[e][a]=t.children("td").eq(l).html()}),l++}),t.reloadData({data:n.data}))}),this},w.that={},w.config={},function(a,i,e,l){var n,o;l.colGroup&&(n=0,a++,l.CHILD_COLS=[],o=e+(parseInt(l.rowspan)||1),layui.each(i[o],function(e,t){t.parentKey?t.parentKey===l.key&&(t.PARENT_COL_INDEX=a,l.CHILD_COLS.push(t),c(a,i,o,t)):t.PARENT_COL_INDEX||1<=n&&n==(l.colspan||1)||(t.PARENT_COL_INDEX=a,l.CHILD_COLS.push(t),n+=parseInt(1td').filter('[data-field="'+e+'"]')}}})).replace(/"/g,'""'),n.push(a='"'+a+'"')):t.field&&"normal"!==t.type&&0==i&&(d[t.field]=!0)}),r.push(n.join(","))}),c&&layui.each(c.dataTotal,function(e,t){d[t.field]||i.push('"'+(t.total||"")+'"')}),o.join(",")+"\r\n"+r.join("\r\n")+"\r\n"+i.join(","))),u.download=(a.title||n.title||"table_"+(n.index||""))+"."+l,document.body.appendChild(u),u.click(),document.body.removeChild(u)},k.getOptions=l,k.hideCol=function(e,l){var n=C(e);n&&("boolean"===layui.type(l)?n.eachCols(function(e,t){var a=t.key,i=n.col(a),t=t.parentKey;i.hide!=l&&(i=i.hide=l,n.elem.find('*[data-key="'+a+'"]')[i?"addClass":"removeClass"](D),n.setParentCol(i,t))}):(l=layui.isArray(l)?l:[l],layui.each(l,function(e,l){n.eachCols(function(e,t){var a,i;l.field===t.field&&(a=t.key,i=n.col(a),t=t.parentKey,"hide"in l)&&i.hide!=l.hide&&(i=i.hide=!!l.hide,n.elem.find('*[data-key="'+a+'"]')[i?"addClass":"removeClass"](D),n.setParentCol(i,t))})})),f("."+j).remove(),n.resize())},k.reload=function(e,t,a,i){if(l(e))return(e=C(e)).reload(t,a,i),w.call(e)},k.reloadData=function(){var a=f.extend([],arguments),i=(a[3]="reloadData",new RegExp("^("+["elem","id","cols","width","height","maxHeight","toolbar","defaultToolbar","className","css","pagebar"].join("|")+")$"));return layui.each(a[1],function(e,t){i.test(e)&&delete a[1][e]}),k.reload.apply(null,a)},k.render=function(e){e=new i(e);return w.call(e)},k.clearCacheKey=function(e){return delete(e=f.extend({},e))[k.config.checkName],delete e[k.config.indexName],delete e[k.config.numbersName],delete e[k.config.disabledName],e},f(function(){k.init()}),n(N,k)});layui.define(["table"],function(e){"use strict";var A=layui.$,x=layui.form,P=layui.table,y=layui.hint(),B={config:{},on:P.on,eachCols:P.eachCols,index:P.index,set:function(e){var t=this;return t.config=A.extend({},t.config,e),t},resize:P.resize,getOptions:P.getOptions,hideCol:P.hideCol,renderData:P.renderData},i=function(){var a=this,e=a.config,n=e.id||e.index;return{config:e,reload:function(e,t){a.reload.call(a,e,t)},reloadData:function(e,t){B.reloadData(n,e,t)}}},j=function(e){var t=i.that[e];return t||y.error(e?"The treeTable instance with ID '"+e+"' not found":"ID argument required"),t||null},F="lay-table-id",L="layui-hide",s=".layui-table-body",q=".layui-table-main",R=".layui-table-fixed-l",Y=".layui-table-fixed-r",l="layui-table-checked",h="layui-table-tree",z="LAY_DATA_INDEX",m="LAY_DATA_INDEX_HISTORY",f="LAY_PARENT_INDEX",b="LAY_CHECKBOX_HALF",H="LAY_EXPAND",X="LAY_HAS_EXPANDED",V="LAY_ASYNC_STATUS",n=["all","parent","children","none"],t=/<[^>]+?>/,p=["flexIconClose","flexIconOpen","iconClose","iconOpen","iconLeaf","icon"],a=function(e){var t=this;t.index=++B.index,t.config=A.extend(!0,{},t.config,B.config,e),t.init(),t.render()},g=function(n,i,e){var l=P.cache[n];layui.each(e||l,function(e,t){var a=t[z]||"";-1!==a.indexOf("-")&&(l[a]=t),t[i]&&g(n,i,t[i])})},d=function(d,a,e){var r=j(d),o=("reloadData"!==e&&(r.status={expand:{}}),A.extend(!0,{},r.getOptions(),a)),n=o.tree,c=n.customName.children,i=n.customName.id,l=(delete a.hasNumberCol,delete a.hasChecboxCol,delete a.hasRadioCol,P.eachCols(null,function(e,t){"numbers"===t.type?a.hasNumberCol=!0:"checkbox"===t.type?a.hasChecboxCol=!0:"radio"===t.type&&(a.hasRadioCol=!0)},o.cols),a.parseData),u=a.done;"reloadData"===e&&"fixed"===o.scrollPos&&(r.scrollTopCache=r.config.elem.next().find(s).scrollTop()),o.url?e&&(!l||l.mod)||(a.parseData=function(){var e=this,t=arguments,a=t[0],t=("function"===layui.type(l)&&(a=l.apply(e,t)||t[0]),e.response.dataName);return n.data.isSimpleData&&!n["async"].enable&&(a[t]=r.flatToTree(a[t])),N(a[t],function(e){e[H]=H in e?e[H]:e[i]!==undefined&&r.status.expand[e[i]]},c),e.autoSort&&e.initSort&&e.initSort.type&&layui.sort(a[t],e.initSort.field,"desc"===e.initSort.type,!0),r.initData(a[t]),a},a.parseData.mod=!0):(a.data=a.data||[],n.data.isSimpleData&&(a.data=r.flatToTree(a.data)),r.initData(a.data)),e&&(!u||u.mod)||(a.done=function(){var e,t=arguments,a=t[3],n="renderData"===a,i=(n||delete r.isExpandAll,this.elem.next()),l=(r.updateStatus(null,{LAY_HAS_EXPANDED:!1}),g(d,c),i.find('[name="layTableCheckbox"][lay-filter="layTableAllChoose"]'));if(l.length&&(e=B.checkStatus(d),l.prop({checked:e.isAll&&e.data.length,indeterminate:!e.isAll&&e.data.length})),!n&&o.autoSort&&o.initSort&&o.initSort.type&&B.sort(d),r.renderTreeTable(i),"reloadData"===a&&"fixed"===this.scrollPos&&i.find(s).scrollTop(r.scrollTopCache),"function"===layui.type(u))return u.apply(this,t)},a.done.mod=!0),a&&a.tree&&a.tree.view&&layui.each(p,function(e,t){a.tree.view[t]!==undefined&&(a.tree.view[t]=r.normalizedIcon(a.tree.view[t]))})};a.prototype.init=function(){var e=this.config,t=e.tree.data.cascade,t=(-1===n.indexOf(t)&&(e.tree.data.cascade="all"),P.render(A.extend({},e,{data:[],url:"",done:null}))),a=t.config.id;(i.that[a]=this).tableIns=t,d(a,e)},a.prototype.config={tree:{customName:{children:"children",isParent:"isParent",name:"name",id:"id",pid:"parentId",icon:"icon"},view:{indent:14,flexIconClose:'',flexIconOpen:'',showIcon:!0,icon:"",iconClose:'',iconOpen:'',iconLeaf:'',showFlexIconIfNotParent:!1,dblClickExpand:!0,expandAllDefault:!1},data:{isSimpleData:!1,rootPid:null,cascade:"all"},"async":{enable:!1,url:"",type:null,contentType:null,headers:null,where:null,autoParam:[]},callback:{beforeExpand:null,onExpand:null}}},a.prototype.normalizedIcon=function(e){return e?t.test(e)?e:'':""},a.prototype.getOptions=function(){return this.tableIns?P.getOptions(this.tableIns.config.id):this.config},a.prototype.flatToTree=function(e){var n,i,l,d,r,o,c,u,t=this.getOptions(),a=t.tree,s=a.customName,t=t.id;return e=e||P.cache[t],t=e,n=s.id,i=s.pid,l=s.children,d=a.data.rootPid,n=n||"id",i=i||"parentId",l=l||"children",c={},u=[],layui.each(t,function(e,t){r=n+t[n],o=n+t[i],c[r]||(c[r]={},c[r][l]=[]);var a={};a[l]=c[r][l],c[r]=A.extend({},t,a),((d?c[r][i]===d:!c[r][i])?u:(c[o]||(c[o]={},c[o][l]=[]),c[o][l])).push(c[r])}),u},a.prototype.treeToFlat=function(e,n,i){var l=this,d=l.getOptions().tree.customName,r=d.children,o=d.pid,c=[];return layui.each(e,function(e,t){var e=(i?i+"-":"")+e,a=A.extend({},t);a[o]=t[o]||n,c.push(a),c=c.concat(l.treeToFlat(t[r],t[d.id],e))}),c},a.prototype.getTreeNode=function(e){var t,a,n=this;return e?(a=(t=n.getOptions()).tree,t.id,a.customName,{data:e,dataIndex:e[z],getParentNode:function(){return n.getNodeByIndex(e[f])}}):y.error("\u627e\u4e0d\u5230\u8282\u70b9\u6570\u636e")},a.prototype.getNodeByIndex=function(t){var a,e,n=this,i=n.getNodeDataByIndex(t);return i?((e=n.getOptions()).tree.customName.parent,a=e.id,(e={data:i,dataIndex:i[z],getParentNode:function(){return n.getNodeByIndex(i[f])},update:function(e){return B.updateNode(a,t,e)},remove:function(){return B.removeNode(a,t)},expand:function(e){return B.expandNode(a,A.extend({},e,{index:t}))},setChecked:function(e){return B.setRowChecked(a,A.extend({},e,{index:t}))}}).dataIndex=t,e):y.error("\u627e\u4e0d\u5230\u8282\u70b9\u6570\u636e")},a.prototype.getNodeById=function(a){var e=this.getOptions(),n=e.tree.customName.id,i="",e=B.getData(e.id,!0);if(layui.each(e,function(e,t){if(t[n]===a)return i=t[z],!0}),i)return this.getNodeByIndex(i)},a.prototype.getNodeDataByIndex=function(e,t,a){var n=this.getOptions(),i=n.tree,n=n.id,n=P.cache[n],l=n[e];if("delete"!==a&&l)return A.extend(l,a),t?A.extend({},l):l;for(var d=n,r=String(e).split("-"),o=0,c=i.customName.children;o
          '),N=function(e){y[V]="success",y[s.children]=e,c.initData(y[s.children],y[z]),J(t,!0,!p&&n,i,l)},C=m.format,"function"===layui.type(C)?C(y,o,N):(I=A.extend({},m.where||o.where),C=m.autoParam,layui.each(C,function(e,t){t=t.split("=");I[t[0].trim()]=y[(t[1]||t[0]).trim()]}),(C=m.contentType||o.contentType)&&0==C.indexOf("application/json")&&(I=JSON.stringify(I)),O=m.method||o.method,D=m.dataType||o.dataType,T=m.jsonpCallback||o.jsonpCallback,_=m.headers||o.headers,k=m.parseData||o.parseData,w=m.response||o.response,A.ajax({type:O||"get",url:b,contentType:C,data:I,dataType:D||"json",jsonpCallback:T,headers:_||{},success:function(e){(e="function"==typeof k?k.call(o,e)||e:e)[w.statusName]!=w.statusCode?(y[V]="error",g.html('')):N(e[w.dataName])},error:function(e,t){y[V]="error","function"==typeof o.error&&o.error(e,t)}})),h;y[X]=!0,v.length&&(!o.initSort||o.url&&!o.autoSort||((m=o.initSort).type?layui.sort(v,m.field,"desc"===m.type,!0):layui.sort(v,P.config.indexName,null,!0)),c.initData(y[s.children],y[z]),O=P.getTrHtml(r,v,null,null,e),S={trs:A(O.trs.join("")),trs_fixed:A(O.trs_fixed.join("")),trs_fixed_r:A(O.trs_fixed_r.join(""))},E=(e.split("-").length-1||0)+1,layui.each(v,function(e,t){S.trs.eq(e).attr({"data-index":t[z],"lay-data-index":t[z],"data-level":E}).data("index",t[z]),S.trs_fixed.eq(e).attr({"data-index":t[z],"lay-data-index":t[z],"data-level":E}).data("index",t[z]),S.trs_fixed_r.eq(e).attr({"data-index":t[z],"lay-data-index":t[z],"data-level":E}).data("index",t[z])}),d.find(q).find('tbody tr[lay-data-index="'+e+'"]').after(S.trs),d.find(R).find('tbody tr[lay-data-index="'+e+'"]').after(S.trs_fixed),d.find(Y).find('tbody tr[lay-data-index="'+e+'"]').after(S.trs_fixed_r),c.renderTreeTable(S.trs,E),n)&&!p&&layui.each(v,function(e,t){J({dataIndex:t[z],trElem:d.find('tr[lay-data-index="'+t[z]+'"]').first(),tableViewElem:d,tableId:r,options:o},a,n,i,l)})}else c.isExpandAll=!1,(n&&!p?(layui.each(v,function(e,t){J({dataIndex:t[z],trElem:d.find('tr[lay-data-index="'+t[z]+'"]').first(),tableViewElem:d,tableId:r,options:o},a,n,i,l)}),d.find(v.map(function(e,t,a){return'tr[lay-data-index="'+e[z]+'"]'}).join(","))):(b=c.treeToFlat(v,y[s.id],e),d.find(b.map(function(e,t,a){return'tr[lay-data-index="'+e[z]+'"]'}).join(",")))).addClass(L);U("resize-"+r,function(){B.resize(r)},0)(),l&&"loading"!==y[V]&&(C=u.callback.onExpand,"function"===layui.type(C))&&C(r,y,x)}return h},v=(B.expandNode=function(e,t){var a,n,i,e=j(e);if(e)return a=(t=t||{}).index,n=t.expandFlag,i=t.inherit,t=t.callbackFlag,e=e.getOptions().elem.next(),J({trElem:e.find('tr[lay-data-index="'+a+'"]').first()},n,i,null,t)},B.expandAll=function(a,e){if("boolean"!==layui.type(e))return y.error("expandAll \u7684\u5c55\u5f00\u72b6\u6001\u53c2\u6570\u53ea\u63a5\u6536true/false");var t=j(a);if(t){t.isExpandAll=e;var n=t.getOptions(),i=n.tree,l=n.elem.next(),d=i.customName.isParent,r=i.customName.id,o=i.view.showFlexIconIfNotParent;if(e){e=B.getData(a,!0);if(i["async"].enable){var c=!0;if(layui.each(e,function(e,t){if(t[d]&&!t[V])return!(c=!1)}),!c)return void layui.each(B.getData(a),function(e,t){B.expandNode(a,{index:t[z],expandFlag:!0,inherit:!0})})}var u=!0;if(layui.each(e,function(e,t){if(t[d]&&!t[X])return!(u=!1)}),u)t.updateStatus(null,function(e){(e[d]||o)&&(e[H]=!0,e[r]!==undefined)&&(t.status.expand[e[r]]=!0)}),l.find('tbody tr[data-level!="0"]').removeClass(L),l.find(".layui-table-tree-flexIcon").html(i.view.flexIconOpen),i.view.showIcon&&l.find(".layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)").html(i.view.iconOpen);else{if(t.updateStatus(null,function(e){(e[d]||o)&&(e[H]=!0,e[X]=!0,e[r]!==undefined)&&(t.status.expand[e[r]]=!0)}),n.initSort&&n.initSort.type&&n.autoSort)return B.sort(a);var s,n=P.getTrHtml(a,e),f={trs:A(n.trs.join("")),trs_fixed:A(n.trs_fixed.join("")),trs_fixed_r:A(n.trs_fixed_r.join(""))};layui.each(e,function(e,t){var a=t[z].split("-").length-1;s={"data-index":t[z],"lay-data-index":t[z],"data-level":a},f.trs.eq(e).attr(s).data("index",t[z]),f.trs_fixed.eq(e).attr(s).data("index",t[z]),f.trs_fixed_r.eq(e).attr(s).data("index",t[z])}),layui.each(["main","fixed-l","fixed-r"],function(e,t){l.find(".layui-table-"+t+" tbody").html(f[["trs","trs_fixed","trs_fixed_r"][e]])}),t.renderTreeTable(l,0,!1)}}else t.updateStatus(null,function(e){(e[d]||o)&&(e[H]=!1,e[r]!==undefined)&&(t.status.expand[e[r]]=!1)}),l.find('.layui-table-box tbody tr[data-level!="0"]').addClass(L),l.find(".layui-table-tree-flexIcon").html(i.view.flexIconClose),i.view.showIcon&&l.find(".layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)").html(i.view.iconClose);B.resize(a)}},a.prototype.updateNodeIcon=function(e){var t=this.getOptions().tree||{},a=e.scopeEl,n=e.isExpand,e=e.isParent;a.find(".layui-table-tree-flexIcon").css("visibility",e||t.view.showFlexIconIfNotParent?"visible":"hidden").html(n?t.view.flexIconOpen:t.view.flexIconClose),t.view.showIcon&&(a=a.find(".layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom)"),n=e?n?t.view.iconOpen:t.view.iconClose:t.view.iconLeaf,a.toggleClass("layui-table-tree-iconLeaf",!e).html(n))},a.prototype.renderTreeTable=function(e,t,a){var l=this,n=l.getOptions(),d=n.elem.next(),i=(d.hasClass(h)||d.addClass(h),n.id),r=n.tree||{},o=(r.data,r.view||{}),c=r.customName||{},u=c.isParent,s=(d.attr("lay-filter"),l),f=((t=t||0)||(d.find(".layui-table-body tr:not([data-level])").attr("data-level",t),layui.each(P.cache[i],function(e,t){d.find('.layui-table-main tbody tr[data-level="0"]:eq('+e+")").attr("lay-data-index",t[z]),d.find('.layui-table-fixed-l tbody tr[data-level="0"]:eq('+e+")").attr("lay-data-index",t[z]),d.find('.layui-table-fixed-r tbody tr[data-level="0"]:eq('+e+")").attr("lay-data-index",t[z])})),null),y=c.name,p=o.indent||14;if(layui.each(e.find('td[data-field="'+y+'"]'),function(e,t){var a,n,i=(t=A(t)).closest("tr"),t=t.children(".layui-table-cell");t.hasClass("layui-table-tree-item")||(n=i.attr("lay-data-index"))&&(i=d.find('tr[lay-data-index="'+n+'"]'),(a=s.getNodeDataByIndex(n))[H]&&a[u]&&((f=f||{})[n]=!0),a[b]&&i.find('input[type="checkbox"][name="layTableCheckbox"]').prop("indeterminate",!0),n=t.html(),(t=i.find('td[data-field="'+y+'"]>div.layui-table-cell')).addClass("layui-table-tree-item"),t.html(['
          ',a[H]?o.flexIconOpen:o.flexIconClose,"
          ",o.showIcon?'
          '+(l.normalizedIcon(a[c.icon])||o.icon||(a[u]?a[H]?o.iconOpen:o.iconClose:o.iconLeaf)||"")+"
          ":"",n].join("")).find(".layui-table-tree-flexIcon").on("click",function(e){layui.stope(e),J({trElem:i},null,null,null,!0)}))}),!t&&r.view.expandAllDefault&&l.isExpandAll===undefined)return B.expandAll(i,!0);(!1!==a&&f?(layui.each(f,function(e,t){e=d.find('tr[lay-data-index="'+e+'"]');e.find(".layui-table-tree-flexIcon").html(o.flexIconOpen),J({trElem:e.first()},!0)}),U("renderTreeTable2-"+i,function(){x.render(A(".layui-table-tree["+F+'="'+i+'"]'))},0)):U("renderTreeTable-"+i,function(){n.hasNumberCol&&v(l),x.render(A(".layui-table-tree["+F+'="'+i+'"]'))},0))()},function(a){var e=a.getOptions(),t=e.elem.next(),n=0,i=t.find(".layui-table-main tbody tr"),l=t.find(".layui-table-fixed-l tbody tr"),d=t.find(".layui-table-fixed-r tbody tr");layui.each(a.treeToFlat(P.cache[e.id]),function(e,t){t.LAY_HIDE||(a.getNodeDataByIndex(t[z]).LAY_NUM=++n,i.eq(e).find(".laytable-cell-numbers").html(n),l.eq(e).find(".laytable-cell-numbers").html(n),d.eq(e).find(".laytable-cell-numbers").html(n))})}),N=(a.prototype.render=function(e){var t=this;t.tableIns=P["reloadData"===e?"reloadData":"reload"](t.tableIns.config.id,A.extend(!0,{},t.config)),t.config=t.tableIns.config},a.prototype.reload=function(e,t,a){var n=this;e=e||{},delete n.haveInit,layui.each(e,function(e,t){"array"===layui.type(t)&&delete n.config[e]}),d(n.getOptions().id,e,a||!0),n.config=A.extend(t,{},n.config,e),n.render(a)},B.reloadData=function(){var e=A.extend(!0,[],arguments);return e[3]="reloadData",B.reload.apply(null,e)},function(e,a,n,i){var l=[];return layui.each(e,function(e,t){"function"===layui.type(a)?a(t):A.extend(t,a),l.push(A.extend({},t)),i||(l=l.concat(N(t[n],a,n,i)))}),l}),o=(a.prototype.updateStatus=function(e,t,a){var n=this.getOptions(),i=n.tree;return e=e||P.cache[n.id],N(e,t,i.customName.children,a)},a.prototype.getTableData=function(){var e=this.getOptions();return P.cache[e.id]},B.updateStatus=function(e,t,a){var e=j(e),n=e.getOptions();return a=a||(n.url?P.cache[n.id]:n.data),e.updateStatus(a,t)},B.sort=function(e){var t,a,i,l,n,d=j(e);d&&(n=(t=d.getOptions()).tree,a=B.getData(e),i=n.customName.children,l=function(e,a,n){layui.sort(e,a,n,!0),layui.each(e,function(e,t){l(t[i]||[],a,n)})},t.autoSort)&&((n=t.initSort).type?l(a,n.field,"desc"===n.type):l(a,P.config.indexName,null),P.cache[e]=a,d.initData(a),B.renderData(e))},function(n){var t=n.config.id,i=j(t),a=n.data=B.getNodeDataByIndex(t,n.index),l=a[z],d=(n.dataIndex=l,n.update);n.update=function(){var e=arguments,t=(A.extend(i.getNodeDataByIndex(l),e[0]),d.apply(this,e)),a=n.config.tree.customName.name;return a in e[0]&&n.tr.find('td[data-field="'+a+'"]').children("div.layui-table-cell").removeClass("layui-table-tree-item"),i.renderTreeTable(n.tr,n.tr.attr("data-level"),!1),t},n.del=function(){B.removeNode(t,a)},n.setRowChecked=function(e){B.setRowChecked(t,{index:a,checked:e})}}),u=(B.updateNode=function(e,a,t){var n,i,l,d,r,o=j(e);o&&((d=o.getOptions()).tree,d=(n=d.elem.next()).find('tr[lay-data-index="'+a+'"]'),i=d.attr("data-index"),l=d.attr("data-level"),t)&&(d=o.getNodeDataByIndex(a,!1,t),r=P.getTrHtml(e,[d]),layui.each(["main","fixed-l","fixed-r"],function(e,t){n.find(".layui-table-"+t+' tbody tr[lay-data-index="'+a+'"]').replaceWith(A(r[["trs","trs_fixed","trs_fixed_r"][e]].join("")).attr({"data-index":i,"lay-data-index":a,"data-level":l}).data("index",i))}),o.renderTreeTable(n.find('tr[lay-data-index="'+a+'"]'),l))},B.removeNode=function(e,t){var a=j(e);if(a){var n,i=a.getOptions(),l=i.tree,d=l.customName.isParent,r=l.customName.children,o=i.elem.next(),c=[],u=P.cache[e],t=a.getNodeDataByIndex("string"===layui.type(t)?t:t[z],!1,"delete"),s=a.getNodeDataByIndex(t[f]),l=(a.updateCheckStatus(s),a.treeToFlat([t],t[l.customName.pid],t[f])),t=(layui.each(l,function(e,t){t=t[z];c.push('tr[lay-data-index="'+t+'"]'),-1!==t.indexOf("-")&&delete u[t]}),o.find(c.join(",")).remove(),a.initData());for(n in u)-1!==n.indexOf("-")&&n!==u[n][z]&&delete u[n];layui.each(a.treeToFlat(t),function(e,t){t[m]&&t[m]!==t[z]&&o.find('tr[lay-data-index="'+t[m]+'"]').attr({"data-index":t[z],"lay-data-index":t[z]}).data("index",t[z])}),layui.each(u,function(e,t){o.find('tr[data-level="0"][lay-data-index="'+t[z]+'"]').attr("data-index",e).data("index",e)}),i.hasNumberCol&&v(a),s&&(l=o.find('tr[lay-data-index="'+s[z]+'"]'),s[d]=!(!s[r]||!s[r].length),a.updateNodeIcon({scopeEl:l,isExpand:s[H],isParent:s[d]})),B.resize(e)}},B.addNodes=function(e,t){var a=j(e);if(a){var n=a.getOptions(),i=n.tree,l=n.elem.next(),d=P.config.checkName,r=(t=t||{}).parentIndex,o=t.index,c=t.data,t=t.focus,u=(r="number"===layui.type(r)?r.toString():r)?a.getNodeDataByIndex(r):null,o="number"===layui.type(o)?o:-1,c=A.extend(!0,[],layui.isArray(c)?c:[c]);layui.each(c,function(e,t){d in t||!u||(t[d]=u[d])}),a.getTableData();if(u){var s=i.customName.isParent,f=i.customName.children;u[s]=!0;var y=(y=u[f])?(p=y.splice(-1===o?y.length:o),u[f]=y.concat(c,p)):u[f]=c,f=(a.updateStatus(y,function(e){(e[s]||i.view.showFlexIconIfNotParent)&&(e[X]=!1)}),a.treeToFlat(y));l.find(f.map(function(e){return'tr[lay-data-index="'+e[z]+'"]'}).join(",")).remove(),a.initData(),u[X]=!1,u[V]="local",J({trElem:l.find('tr[lay-data-index="'+r+'"]')},!0)}else{var p=P.cache[e].splice(-1===o?P.cache[e].length:o);if(P.cache[e]=P.cache[e].concat(c,p),n.url||(n.page?(y=n.page,n.data.splice.apply(n.data,[y.limit*(y.curr-1),y.limit].concat(P.cache[e]))):n.data=P.cache[e]),a.initData(),l.find(".layui-none").length)return P.renderData(e),c;var x,f=P.getTrHtml(e,c),h={trs:A(f.trs.join("")),trs_fixed:A(f.trs_fixed.join("")),trs_fixed_r:A(f.trs_fixed_r.join(""))},r=(layui.each(c,function(e,t){x={"data-index":t[z],"lay-data-index":t[z],"data-level":"0"},h.trs.eq(e).attr(x).data("index",t[z]),h.trs_fixed.eq(e).attr(x).data("index",t[z]),h.trs_fixed_r.eq(e).attr(x).data("index",t[z])}),parseInt(c[0][z])-1),y=l.find(q),n=l.find(R),f=l.find(Y);-1==r?y.find('tr[data-level="0"][data-index="0"]')[0]?(y.find('tr[data-level="0"][data-index="0"]').before(h.trs),n.find('tr[data-level="0"][data-index="0"]').before(h.trs_fixed),f.find('tr[data-level="0"][data-index="0"]').before(h.trs_fixed_r)):(y.find("tbody").prepend(h.trs),n.find("tbody").prepend(h.trs_fixed),f.find("tbody").prepend(h.trs_fixed_r)):-1===o?(y.find("tbody").append(h.trs),n.find("tbody").append(h.trs_fixed),f.find("tbody").append(h.trs_fixed_r)):(r=p[0][m],y.find('tr[data-level="0"][data-index="'+r+'"]').before(h.trs),n.find('tr[data-level="0"][data-index="'+r+'"]').before(h.trs_fixed),f.find('tr[data-level="0"][data-index="'+r+'"]').before(h.trs_fixed_r)),layui.each(P.cache[e],function(e,t){l.find('tr[data-level="0"][lay-data-index="'+t[z]+'"]').attr("data-index",e).data("index",e)}),a.renderTreeTable(l.find(c.map(function(e,t,a){return'tr[lay-data-index="'+e[z]+'"]'}).join(",")))}return a.updateCheckStatus(u),u&&(o=l.find('tr[lay-data-index="'+u[z]+'"]'),a.updateNodeIcon({scopeEl:o,isExpand:u[H],isParent:u[s]})),B.resize(e),t&&l.find(q).find('tr[lay-data-index="'+c[0][z]+'"]').get(0).scrollIntoViewIfNeeded(),c}},B.checkStatus=function(e,n){var i,t,a,l=j(e);if(l)return l=l.getOptions().tree,i=P.config.checkName,t=B.getData(e,!0).filter(function(e,t,a){return e[i]||n&&e[b]}),a=!0,layui.each("all"===l.data.cascade?P.cache[e]:B.getData(e,!0),function(e,t){if(!t[i])return!(a=!1)}),{data:t,isAll:a}},B.on("sort",function(e){var e=e.config,t=e.elem.next(),e=e.id;t.hasClass(h)&&B.sort(e)}),B.on("row",function(e){e.config.elem.next().hasClass(h)&&o(e)}),B.on("rowDouble",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(h)&&(o(e),(t.tree||{}).view.dblClickExpand)&&J({trElem:e.tr.first()},null,null,null,!0)}),B.on("rowContextmenu",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(h)&&o(e)}),B.on("tool",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(h)&&o(e)}),B.on("edit",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(h)&&(o(e),e.field===t.tree.customName.name)&&((a={})[e.field]=e.value,e.update(a))}),B.on("radio",function(e){var t=e.config,a=t.elem.next(),t=t.id;a.hasClass(h)&&(a=j(t),o(e),u.call(a,e.tr,e.checked))}),a.prototype.setRowCheckedClass=function(e,t){var a=this.getOptions(),n=(e.data("index"),a.elem.next());e[t?"addClass":"removeClass"](l),e.each(function(){var e=A(this).data("index");n.find('.layui-table-fixed-r tbody tr[data-index="'+e+'"]')[t?"addClass":"removeClass"](l)})},a.prototype.updateCheckStatus=function(e,t){var a,n,i,l,d,r,o,c=this,u=c.getOptions();return!!u.hasChecboxCol&&(a=u.tree,n=u.id,i=u.elem.next(),l=P.config.checkName,"all"!==(d=a.data.cascade)&&"parent"!==d||!e||(d=c.updateParentCheckStatus(e,"boolean"===layui.type(t)?t:null),layui.each(d,function(e,t){var a=i.find('tr[lay-data-index="'+t[z]+'"] input[name="layTableCheckbox"]:not(:disabled)'),n=t[l];c.setRowCheckedClass(a.closest("tr"),n),x.render(a.prop({checked:n,indeterminate:t[b]}))})),o=!(r=!0),0<(e=(e="all"===a.data.cascade?P.cache[n]:B.getData(n,!0)).filter(function(e){return!e[u.disabledName]})).length?layui.each(e,function(e,t){if((t[l]||t[b])&&(o=!0),t[l]||(r=!1),o&&!r)return!0}):r=!1,o=o&&!r,x.render(i.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop({checked:r,indeterminate:o})),r)},a.prototype.updateParentCheckStatus=function(a,n){var i,e=this.getOptions(),t=e.tree,e=e.id,l=P.config.checkName,t=t.customName.children,d=[];return!(a[b]=!1)===n?a[t].length?layui.each(a[t],function(e,t){if(!t[l])return n=!1,a[b]=!0}):n=!1:!1===n?layui.each(a[t],function(e,t){if(t[l]||t[b])return a[b]=!0}):(n=!1,i=0,layui.each(a[t],function(e,t){t[l]&&i++}),n=a[t].length?a[t].length===i:a[l],a[b]=!n&&0')),n=(e.tree(a),i.elem=p(i.elem));if(n[0]){if(e.key=i.id||e.index,e.elem=a,e.elemNone=p('
          '+i.text.none+"
          "),n.html(e.elem),0==e.elem.find(".layui-tree-set").length)return e.elem.append(e.elemNone);i.showCheckbox&&e.renderForm("checkbox"),e.elem.find(".layui-tree-set").each(function(){var e=p(this);e.parent(".layui-tree-pack")[0]||e.addClass("layui-tree-setHide"),!e.next()[0]&&e.parents(".layui-tree-pack").eq(1).hasClass("layui-tree-lineExtend")&&e.addClass(T),e.next()[0]||e.parents(".layui-tree-set").eq(0).next()[0]||e.addClass(T)}),e.events()}},l.prototype.renderForm=function(e){i.render(e,"LAY-tree-"+this.index)},l.prototype.tree=function(r,e){var d=this,s=d.config,o=s.customName,e=e||s.data;layui.each(e,function(e,i){var a,n,t=i[o.children]&&0"),c=p(['
          ','
          ','
          ',s.showLine?t?'':'':'',s.showCheckbox?'':"",s.isJump&&i.href?''+(i[o.title]||i.label||s.text.defaultNodeName)+"":''+(i[o.title]||i.label||s.text.defaultNodeName)+"","
          ",s.edit?(a={add:'',update:'',del:''},n=['
          '],!0===s.edit&&(s.edit=["update","del"]),"object"==typeof s.edit?(layui.each(s.edit,function(e,i){n.push(a[i]||"")}),n.join("")+"
          "):void 0):"","
          "].join(""));t&&(c.append(l),d.tree(l,i[o.children])),r.append(c),c.prev("."+k)[0]&&c.prev().children(".layui-tree-pack").addClass("layui-tree-showLine"),t||c.parent(".layui-tree-pack").addClass("layui-tree-lineExtend"),d.spread(c,i),s.showCheckbox&&(i.checked&&d.checkids.push(i[o.id]),d.checkClick(c,i)),s.edit&&d.operate(c,i)})},l.prototype.spread=function(n,t){var l=this,c=l.config,e=n.children("."+b),i=e.children("."+g),a=i.find('input[same="layuiTreeCheck"]'),r=e.find("."+C),e=e.find("."+w),d=c.onlyIconControl?r:i,s="";d.on("click",function(e){var i=n.children("."+N),a=(d.children(".layui-icon")[0]?d:d.find(".layui-tree-icon")).children(".layui-icon");i[0]?n.hasClass(F)?(n.removeClass(F),i.slideUp(200),a.removeClass(x).addClass(v),l.updateFieldValue(t,"spread",!1)):(n.addClass(F),i.slideDown(200),a.addClass(x).removeClass(v),l.updateFieldValue(t,"spread",!0),c.accordion&&((i=n.siblings("."+k)).removeClass(F),i.children("."+N).slideUp(200),i.find(".layui-tree-icon").children(".layui-icon").removeClass(x).addClass(v))):s="normal"}),e.on("click",function(){p(this).hasClass(u)||(s=n.hasClass(F)?c.onlyIconControl?"open":"close":c.onlyIconControl?"close":"open",a[0]&&l.updateFieldValue(t,"checked",a.prop("checked")),c.click&&c.click({elem:n,state:s,data:t}))})},l.prototype.updateFieldValue=function(e,i,a){i in e&&(e[i]=a)},l.prototype.setCheckbox=function(e,i,a){var t,n=this,l=n.config.customName,c=a.prop("checked");a.prop("disabled")||("object"!=typeof i[l.children]&&!e.find("."+N)[0]||e.find("."+N).find('input[same="layuiTreeCheck"]').each(function(e){this.disabled||((e=i[l.children][e])&&n.updateFieldValue(e,"checked",c),n.updateFieldValue(this,"checked",c))}),(t=function(e){var i,a,n;e.parents("."+k)[0]&&(a=(e=e.parent("."+N)).parent(),n=e.prev().find('input[same="layuiTreeCheck"]'),c?n.prop("checked",c):(e.find('input[same="layuiTreeCheck"]').each(function(){this.checked&&(i=!0)}),i||n.prop("checked",!1)),t(a))})(e),n.renderForm("checkbox"))},l.prototype.checkClick=function(a,n){var t=this,l=t.config;a.children("."+b).children("."+g).on("click",'input[same="layuiTreeCheck"]+',function(e){layui.stope(e);var e=p(this).prev(),i=e.prop("checked");e.prop("disabled")||(t.setCheckbox(a,n,e),t.updateFieldValue(n,"checked",i),l.oncheck&&l.oncheck({elem:a,checked:i,data:n}))})},l.prototype.operate=function(r,d){var s=this,o=s.config,u=o.customName,e=r.children("."+b),h=e.children("."+g);e.children(".layui-tree-btnGroup").on("click",".layui-icon",function(e){layui.stope(e);var i,e=p(this).data("type"),n=r.children("."+N),t={data:d,type:e,elem:r};if("add"==e){n[0]||(o.showLine?(h.find("."+C).addClass("layui-tree-icon"),h.find("."+C).children(".layui-icon").addClass(v).removeClass("layui-icon-file")):h.find(".layui-tree-iconArrow").removeClass(m),r.append('
          '));var a,l=o.operate&&o.operate(t),c={};if(c[u.title]=o.text.defaultNodeName,c[u.id]=l,s.tree(r.children("."+N),[c]),o.showLine&&(n[0]?(n.hasClass(S)||n.addClass(S),r.find("."+N).each(function(){p(this).children("."+k).last().addClass(T)}),(n.children("."+k).last().prev().hasClass(T)?n.children("."+k).last().prev():n.children("."+k).last()).removeClass(T),!r.parent("."+N)[0]&&r.next()[0]&&n.children("."+k).last().removeClass(T)):(l=r.siblings("."+k),a=1,c=r.parent("."+N),layui.each(l,function(e,i){p(i).children("."+N)[0]||(a=0)}),(1==a?(l.children("."+N).addClass(L),l.children("."+N).children("."+k).removeClass(T),r.children("."+N).addClass(L),c.removeClass(S),c.children("."+k).last().children("."+N).children("."+k).last()):r.children("."+N).children("."+k)).addClass(T))),!o.showCheckbox)return;h.find('input[same="layuiTreeCheck"]')[0].checked&&(r.children("."+N).children("."+k).last().find('input[same="layuiTreeCheck"]')[0].checked=!0),s.renderForm("checkbox")}else"update"==e?(l=h.children("."+w).html(),h.children("."+w).html(""),h.append(''),h.children(".layui-tree-editInput").val(f.unescape(l)).focus(),i=function(e){var i=f.escape(e.val().trim())||o.text.defaultNodeName;e.remove(),h.children("."+w).html(i),t.data[u.title]=i,o.operate&&o.operate(t)},h.children(".layui-tree-editInput").blur(function(){i(p(this))}),h.children(".layui-tree-editInput").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),i(p(this)))})):y.confirm('\u786e\u8ba4\u5220\u9664\u8be5\u8282\u70b9 "'+(d[u.title]||"")+'" \u5417\uff1f',function(e){var l,a,i;o.operate&&o.operate(t),t.status="remove",y.close(e),r.prev("."+k)[0]||r.next("."+k)[0]||r.parent("."+N)[0]?(r.siblings("."+k).children("."+b)[0]?(o.showCheckbox&&(l=function(e){var i,a,n,t;e.parents("."+k)[0]&&(i=e.siblings("."+k).children("."+b),a=(e=e.parent("."+N).prev()).find('input[same="layuiTreeCheck"]')[0],n=1,(t=0)==a.checked)&&(i.each(function(e,i){i=p(i).find('input[same="layuiTreeCheck"]')[0];0!=i.checked||i.disabled||(n=0),i.disabled||(t=1)}),1==n)&&1==t&&(a.checked=!0,s.renderForm("checkbox"),l(e.parent("."+k)))})(r),o.showLine&&(e=r.siblings("."+k),a=1,i=r.parent("."+N),layui.each(e,function(e,i){p(i).children("."+N)[0]||(a=0)}),1==a?(n[0]||(i.removeClass(S),e.children("."+N).addClass(L),e.children("."+N).children("."+k).removeClass(T)),(r.next()[0]?i.children("."+k).last():r.prev()).children("."+N).children("."+k).last().addClass(T),r.next()[0]||r.parents("."+k)[1]||r.parents("."+k).eq(0).next()[0]||r.prev("."+k).addClass(T)):!r.next()[0]&&r.hasClass(T)&&r.prev().addClass(T))):(e=r.parent("."+N).prev(),o.showLine?(e.find("."+C).removeClass("layui-tree-icon"),e.find("."+C).children(".layui-icon").removeClass(x).addClass("layui-icon-file"),(i=e.parents("."+N).eq(0)).addClass(S),i.children("."+k).each(function(){p(this).children("."+N).children("."+k).last().addClass(T)})):e.find(".layui-tree-iconArrow").addClass(m),r.parents("."+k).eq(0).removeClass(F),r.parent("."+N).remove()),r.remove()):(r.remove(),s.elem.append(s.elemNone))})})},l.prototype.events=function(){var i=this,t=i.config;i.elem.find(".layui-tree-checkedFirst");i.setChecked(i.checkids),i.elem.find(".layui-tree-search").on("keyup",function(){var e=p(this),a=e.val(),e=e.nextAll(),n=[];e.find("."+w).each(function(){var i,e=p(this).parents("."+b);-1!=p(this).html().indexOf(a)&&(n.push(p(this).parent()),(i=function(e){e.addClass("layui-tree-searchShow"),e.parent("."+N)[0]&&i(e.parent("."+N).parent("."+k))})(e.parent("."+k)))}),e.find("."+b).each(function(){var e=p(this).parent("."+k);e.hasClass("layui-tree-searchShow")||e.addClass(m)}),0==e.find(".layui-tree-searchShow").length&&i.elem.append(i.elemNone),t.onsearch&&t.onsearch({elem:n})}),i.elem.find(".layui-tree-search").on("keydown",function(){p(this).nextAll().find("."+b).each(function(){p(this).parent("."+k).removeClass("layui-tree-searchShow "+m)}),p(".layui-tree-emptyText")[0]&&p(".layui-tree-emptyText").remove()})},l.prototype.getChecked=function(){var t=this,e=t.config,l=e.customName,i=[],a=[],c=(t.elem.find(".layui-form-checked").each(function(){i.push(p(this).prev()[0].value)}),function(e,n){layui.each(e,function(e,a){layui.each(i,function(e,i){if(a[l.id]==i)return t.updateFieldValue(a,"checked",!0),delete(i=p.extend({},a))[l.children],n.push(i),a[l.children]&&(i[l.children]=[],c(a[l.children],i[l.children])),!0})})});return c(p.extend({},e.data),a),a},l.prototype.setChecked=function(l){this.config;this.elem.find("."+k).each(function(e,i){var a=p(this).data("id"),n=p(i).children("."+b).find('input[same="layuiTreeCheck"]'),t=n.next();if("number"==typeof l){if(a.toString()==l.toString())return n[0].checked||t.click(),!1}else"object"==typeof l&&layui.each(l,function(e,i){if(i.toString()==a.toString()&&!n[0].checked)return t.click(),!0})})},n.that={},n.config={},t.reload=function(e,i){e=n.that[e];return e.reload(i),n.call(e)},t.getChecked=function(e){return n.that[e].getChecked()},t.setChecked=function(e,i){return n.that[e].setChecked(i)},t.render=function(e){e=new l(e);return n.call(e)},e(a,t)});layui.define(["laytpl","form"],function(e){"use strict";var d=layui.$,n=layui.laytpl,t=layui.form,a="transfer",i={config:{},index:layui[a]?layui[a].index+1e4:0,set:function(e){var t=this;return t.config=d.extend({},t.config,e),t},on:function(e,t){return layui.onevent.call(this,a,e,t)}},l=function(){var t=this,e=t.config,a=e.id||t.index;return l.that[a]=t,{config:l.config[a]=e,reload:function(e){t.reload.call(t,e)},getData:function(){return t.getData.call(t)}}},s="layui-hide",u="layui-btn-disabled",c="layui-none",r="layui-transfer-box",h="layui-transfer-header",o="layui-transfer-search",f="layui-transfer-data",y=function(e){return['
          ','
          ','","
          ","{{# if(d.data.showSearch){ }}",'","{{# } }}",'
            ',"
            "].join("")},p=['
            ',y({index:0,checkAllName:"layTransferLeftCheckAll"}),'
            ','",'","
            ",y({index:1,checkAllName:"layTransferRightCheckAll"}),"
            "].join(""),v=function(e){var t=this;t.index=++i.index,t.config=d.extend({},t.config,i.config,e),t.render()};v.prototype.config={title:["\u5217\u8868\u4e00","\u5217\u8868\u4e8c"],width:200,height:360,data:[],value:[],showSearch:!1,id:"",text:{none:"\u65e0\u6570\u636e",searchNone:"\u65e0\u5339\u914d\u6570\u636e"}},v.prototype.reload=function(e){var t=this;t.config=d.extend({},t.config,e),t.render()},v.prototype.render=function(){var e=this,t=e.config,a=e.elem=d(n(p,{open:"{{",close:"}}"}).render({data:t,index:e.index})),i=t.elem=d(t.elem);i[0]&&(t.data=t.data||[],t.value=t.value||[],t.id="id"in t?t.id:elem.attr("id")||e.index,e.key=t.id,i.html(e.elem),e.layBox=e.elem.find("."+r),e.layHeader=e.elem.find("."+h),e.laySearch=e.elem.find("."+o),e.layData=a.find("."+f),e.layBtn=a.find(".layui-transfer-active .layui-btn"),e.layBox.css({width:t.width,height:t.height}),e.layData.css({height:(i=t.height-e.layHeader.outerHeight(),t.showSearch&&(i-=e.laySearch.outerHeight()),i-2)}),e.renderData(),e.events())},v.prototype.renderData=function(){var e=this,t=e.config,l=[{checkName:"layTransferLeftCheck",views:[]},{checkName:"layTransferRightCheck",views:[]}];e.parseData(function(a){var i=a.selected?1:0,n=["
          • ",'',"
          • "].join("");i?layui.each(t.value,function(e,t){t==a.value&&a.selected&&(l[i].views[e]=n)}):l[i].views.push(n),delete a.selected}),e.layData.eq(0).html(l[0].views.join("")),e.layData.eq(1).html(l[1].views.join("")),e.renderCheckBtn()},v.prototype.renderForm=function(e){t.render(e,"LAY-transfer-"+this.index)},v.prototype.renderCheckBtn=function(c){var r=this,o=r.config;c=c||{},r.layBox.each(function(e){var t=d(this),a=t.find("."+f),t=t.find("."+h).find('input[type="checkbox"]'),i=a.find('input[type="checkbox"]'),n=0,l=!1;i.each(function(){var e=d(this).data("hide");(this.checked||this.disabled||e)&&n++,this.checked&&!e&&(l=!0)}),t.prop("checked",l&&n===i.length),r.layBtn.eq(e)[l?"removeClass":"addClass"](u),c.stopNone||(i=a.children("li:not(."+s+")").length,r.noneView(a,i?"":o.text.none))}),r.renderForm("checkbox")},v.prototype.noneView=function(e,t){var a=d('

            '+(t||"")+"

            ");e.find("."+c)[0]&&e.find("."+c).remove(),t.replace(/\s/g,"")&&e.append(a)},v.prototype.setValue=function(){var e=this.config,t=[];return this.layBox.eq(1).find("."+f+' input[type="checkbox"]').each(function(){d(this).data("hide")||t.push(this.value)}),e.value=t,this},v.prototype.parseData=function(t){var i=this.config,n=[];return layui.each(i.data,function(e,a){a=("function"==typeof i.parseData?i.parseData(a):a)||a,n.push(a=d.extend({},a)),layui.each(i.value,function(e,t){t==a.value&&(a.selected=!0)}),t&&t(a)}),i.data=n,this},v.prototype.getData=function(e){var t=this.config,i=[];return this.setValue(),layui.each(e||t.value,function(e,a){layui.each(t.data,function(e,t){delete t.selected,a==t.value&&i.push(t)})}),i},v.prototype.transfer=function(e,t){var a,i=this,n=i.config,l=i.layBox.eq(e),c=[],t=(t?((a=(t=t).find('input[type="checkbox"]'))[0].checked=!1,l.siblings("."+r).find("."+f).append(t.clone()),t.remove(),c.push(a[0].value),i.setValue()):l.each(function(e){d(this).find("."+f).children("li").each(function(){var e=d(this),t=e.find('input[type="checkbox"]'),a=t.data("hide");t[0].checked&&!a&&(t[0].checked=!1,l.siblings("."+r).find("."+f).append(e.clone()),e.remove(),c.push(t[0].value)),i.setValue()})}),i.renderCheckBtn(),l.siblings("."+r).find("."+o+" input"));""!==t.val()&&t.trigger("keyup"),n.onchange&&n.onchange(i.getData(c),e)},v.prototype.events=function(){var n=this,l=n.config;n.elem.on("click",'input[lay-filter="layTransferCheckbox"]+',function(){var e=d(this).prev(),t=e[0].checked,a=e.parents("."+r).eq(0).find("."+f);e[0].disabled||("all"===e.attr("lay-type")&&a.find('input[type="checkbox"]').each(function(){this.disabled||(this.checked=t)}),setTimeout(function(){n.renderCheckBtn({stopNone:!0})},0))}),n.elem.on("dblclick","."+f+">li",function(e){var t=d(this),a=t.children('input[type="checkbox"]'),i=t.parent().parent().data("index");a[0].disabled||!1!==("function"==typeof l.dblclick?l.dblclick({elem:t,data:n.getData([a[0].value])[0],index:i}):null)&&n.transfer(i,t)}),n.layBtn.on("click",function(){var e=d(this),t=e.data("index");e.hasClass(u)||n.transfer(t)}),n.laySearch.find("input").on("keyup",function(){var i=this.value,e=d(this).parents("."+o).eq(0).siblings("."+f),t=e.children("li"),t=(t.each(function(){var e=d(this),t=e.find('input[type="checkbox"]'),a=t[0].title,a=("cs"!==l.showSearch&&(a=a.toLowerCase(),i=i.toLowerCase()),-1!==a.indexOf(i));e[a?"removeClass":"addClass"](s),t.data("hide",!a)}),n.renderCheckBtn(),t.length===e.children("li."+s).length);n.noneView(e,t?l.text.searchNone:"")})},l.that={},l.config={},i.reload=function(e,t){e=l.that[e];return e.reload(t),l.call(e)},i.getData=function(e){return l.that[e].getData()},i.render=function(e){e=new v(e);return l.call(e)},e(a,i)});layui.define(["jquery","lay"],function(e){"use strict";var a=layui.$,l=layui.lay,t=(layui.hint(),layui.device(),{config:{},set:function(e){var i=this;return i.config=a.extend({},i.config,e),i},on:function(e,i){return layui.onevent.call(this,d,e,i)}}),d="carousel",r="layui-this",s="layui-carousel-left",u="layui-carousel-right",c="layui-carousel-prev",h="layui-carousel-next",o="layui-carousel-arrow",m="layui-carousel-ind",i=function(e){var i=this;i.config=a.extend({},i.config,t.config,e),i.render()};i.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},i.prototype.render=function(){var e=this,i=e.config,n=a(i.elem);if(1*[carousel-item]>*"),i.index<0&&(i.index=0),i.index>=e.elemItem.length&&(i.index=e.elemItem.length-1),i.interval<800&&(i.interval=800),i.full?i.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):i.elem.css({width:i.width,height:i.height}),i.elem.attr("lay-anim",i.anim),e.elemItem.eq(i.index).addClass(r),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},i.prototype.reload=function(e){var i=this;clearInterval(i.timer),i.config=a.extend({},i.config,e),i.render()},i.prototype.prevIndex=function(){var e=this.config.index-1;return e=e<0?this.elemItem.length-1:e},i.prototype.nextIndex=function(){var e=this.config.index+1;return e=e>=this.elemItem.length?0:e},i.prototype.addIndex=function(e){var i=this.config;i.index=i.index+(e=e||1),i.index>=this.elemItem.length&&(i.index=0)},i.prototype.subIndex=function(e){var i=this.config;i.index=i.index-(e=e||1),i.index<0&&(i.index=this.elemItem.length-1)},i.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(clearInterval(e.timer),e.timer=setInterval(function(){e.slide()},i.interval))},i.prototype.arrow=function(){var i=this,e=i.config,n=a(['",'"].join(""));e.elem.attr("lay-arrow",e.arrow),e.elem.find("."+o)[0]&&e.elem.find("."+o).remove(),e.elem.append(n),n.on("click",function(){var e=a(this).attr("lay-type");i.slide(e)})},i.prototype["goto"]=function(e){var i=this,n=i.config;e>n.index?i.slide("add",e-n.index):e
              ',(i=[],layui.each(e.elemItem,function(e){i.push("")}),i.join("")),"
            "].join(""));n.elem.attr("lay-indicator",n.indicator),n.elem.find("."+m)[0]&&n.elem.find("."+m).remove(),n.elem.append(t),"updown"===n.anim&&t.css("margin-top",-t.height()/2),t.find("li").on("hover"===n.trigger?"mouseover":n.trigger,function(){e["goto"](a(this).index())})},i.prototype.slide=function(e,i){var n=this,t=n.elemItem,a=n.config,o=a.index,l=a.elem.attr("lay-filter");n.haveSlide||("sub"===e?(n.subIndex(i),t.eq(a.index).addClass(c),setTimeout(function(){t.eq(o).addClass(u),t.eq(a.index).addClass(u)},50)):(n.addIndex(i),t.eq(a.index).addClass(h),setTimeout(function(){t.eq(o).addClass(s),t.eq(a.index).addClass(s)},50)),setTimeout(function(){t.removeClass(r+" "+c+" "+h+" "+s+" "+u),t.eq(a.index).addClass(r),n.haveSlide=!1},350),n.elemInd.find("li").eq(a.index).addClass(r).siblings().removeClass(r),n.haveSlide=!0,e={index:a.index,prevIndex:o,item:t.eq(a.index)},"function"==typeof a.change&&a.change(e),layui.event.call(this,d,"change("+l+")",e))},i.prototype.events=function(){var t,a,o=this,e=o.config;e.elem.data("haveEvents")||(e.elem.on("mouseenter touchstart",function(){"always"!==o.config.autoplay&&clearInterval(o.timer)}).on("mouseleave touchend",function(){"always"!==o.config.autoplay&&o.autoplay()}),t=e.elem,a="updown"===e.anim,l.touchSwipe(t,{onTouchEnd:function(e,i){var n=Date.now()-i.timeStart,i=a?i.distanceY:i.distanceX;(.25t[a?"height":"width"]()/3)&&o.slide(0a.length&&(a.value=a.length),parseInt(a.value)===a.value||a.half||(a.value=Math.ceil(a.value)-a.value<.5?Math.ceil(a.value):Math.floor(a.value)),'
              "),n=1;n<=a.length;n++){var o='
            • ";a.half&&parseInt(a.value)!==a.value&&n==Math.ceil(a.value)?i=i+'
            • ":i+=o}i+="
            "+(a.text?''+a.value+"\u661f":"")+"";var l=a.elem,s=l.next(".layui-rate");s[0]&&s.remove(),e.elemTemp=u(i),a.span=e.elemTemp.next("span"),a.setText&&a.setText(a.value),l.html(e.elemTemp),l.addClass("layui-inline"),a.readonly||e.action()},a.prototype.setvalue=function(e){this.config.value=e,this.render()},a.prototype.action=function(){var n=this.config,t=this.elemTemp,i=t.find("i").width(),l=t.children("li");l.each(function(e){var a=e+1,l=u(this);l.on("click",function(e){n.value=a,n.half&&e.pageX-u(this).offset().left<=i/2&&(n.value=n.value-.5),n.text&&t.next("span").text(n.value+"\u661f"),n.choose&&n.choose(n.value),n.setText&&n.setText(n.value)}),l.on("mousemove",function(e){t.find("i").each(function(){u(this).addClass(h).removeClass(s)}),t.find("i:lt("+a+")").each(function(){u(this).addClass(f).removeClass(v)}),n.half&&e.pageX-u(this).offset().left<=i/2&&l.children("i").addClass(o).removeClass(f)}),l.on("mouseleave",function(){t.find("i").each(function(){u(this).addClass(h).removeClass(s)}),t.find("i:lt("+Math.floor(n.value)+")").each(function(){u(this).addClass(f).removeClass(v)}),n.half&&parseInt(n.value)!==n.value&&t.children("li:eq("+Math.floor(n.value)+")").children("i").addClass(o).removeClass("layui-icon-rate-solid layui-icon-rate")})}),r.touchSwipe(t,{onTouchMove:function(e,a){var i;Date.now()-a.timeStart<=200||(a=e.touches[0].pageX,e=t.width()/n.length,a=(a-t.offset().left)/e,(i=(i=(e=a%1)<=.5&&n.half?.5+(a-e):Math.ceil(a))>n.length?n.length:i)<0&&(i=0),l.each(function(e){var a=u(this).children("i"),l=Math.ceil(i)-e==1,t=Math.ceil(i)>e,e=i-e==.5;t?(a.addClass(f).removeClass(v),n.half&&e&&a.addClass(o).removeClass(f)):a.addClass(h).removeClass(s),a.toggleClass("layui-rate-hover",l)}),n.value=i,n.text&&t.next("span").text(n.value+"\u661f"),n.setText&&n.setText(n.value))},onTouchEnd:function(e,a){Date.now()-a.timeStart<=200||(t.find("i").removeClass("layui-rate-hover"),n.choose&&n.choose(n.value),n.setText&&n.setText(n.value))}})},a.prototype.events=function(){},c.render=function(e){e=new a(e);return function(){var a=this;return{setvalue:function(e){a.setvalue.call(a,e)},config:a.config}}.call(e)},e(l,c)});layui.define("jquery",function(o){"use strict";var v=layui.$,l=function(o){};l.prototype.load=function(o){var i,n,r,l,c,m,e,a,f,s,u,p,t,d,y=this,h=0,g=v((o=o||{}).elem);if(g[0])return c=v(o.scrollElem||document),m="mb"in o?o.mb:50,e=!("isAuto"in o)||o.isAuto,a=o.end||"\u6ca1\u6709\u66f4\u591a\u4e86",f="top"===(o.direction||"bottom"),y._cleanup(g,c),s=o.scrollElem&&o.scrollElem!==document,p=v('"),g.find(".layui-flow-more")[0]||g[f?"prepend":"append"](p),t=function(o,l){var e=s?c.prop("scrollHeight"):document.documentElement.scrollHeight,t=c.scrollTop();o=v(o),p[f?"after":"before"](o),(l=0==l||null)?p.html(a):p.find("a").html(u),n=l,i=null,r&&r(),f&&(o=s?c.prop("scrollHeight"):document.documentElement.scrollHeight,1===h?c.scrollTop(o):1'),"function"==typeof o.done&&o.done(++h,t)})(),p.find("a").on("click.flow",function(){v(this);n||i||d()}),o.isLazyimg&&(r=y.lazyimg({elem:o.elem+" img",scrollElem:o.scrollElem,direction:o.direction})),e&&c.on("scroll.flow",function(){var e=v(this),t=e.scrollTop();l&&clearTimeout(l),!n&&g.width()&&(l=setTimeout(function(){var o=(s?e:v(window)).height(),l=s?e.prop("scrollHeight"):document.documentElement.scrollHeight;(f?t<=m:l-t-o<=m)&&!i&&d()},100))}),y},l.prototype.lazyimg=function(o){var l,m=this,a=0,f=v((o=o||{}).scrollElem||document),s=o.elem||"img",n="top"===(o.direction||"bottom"),u=o.scrollElem&&o.scrollElem!==document,p=function(l,o){var e,t=f.scrollTop(),o=t+o,i=u?l.offset().top-f.offset().top+t:l.offset().top;(n?i+l.height():i)>=t&&i<=o&&l.attr("lay-src")&&(e=l.attr("lay-src"),layui.img(e,function(){var o=m.lazyimg.elem.eq(a);l.attr("src",e).removeAttr("lay-src"),o[0]&&r(o),a++},function(){m.lazyimg.elem.eq(a);l.removeAttr("lay-src")}))},r=function(o,l){var e=(u?l||f:v(window)).height(),t=f.scrollTop(),i=t+e;if(m.lazyimg.elem=v(s),o)p(o,e);else for(var n=0;n"),preview:"Preview"},wordWrap:!0,lang:"text",highlighter:!1,langMarker:!1},W=layui.code?layui.code.index+1e4:0,R=function(e){return String(e).replace(/\s+$/,"").replace(/^\n|\n$/,"")};e("code",function(l,e){var o,i,t,a,n,d,c,s,r,u,y,p,E,f,h,v,m,L,_,M,C,g={config:l=x.extend(!0,{},T,l),reload:function(e){layui.code(this.updateOptions(e))},updateOptions:function(e){return delete(e=e||{}).elem,x.extend(!0,l,e)},reloadCode:function(e){layui.code(this.updateOptions(e),"reloadCode")}},w=x(l.elem);return 1',l.ln?['
            ',D.digit(t+1)+".","
            "].join(""):"",'
            ',e||" ","
            ",""].join("")})}},a=l.code,n=function(e){return"function"==typeof l.codeParse?l.codeParse(e,l):e},"reloadCode"===e?o.children(".layui-code-wrap").html(w(n(a)).html):(d=layui.code.index=++W,o.attr("lay-code-index",d),(M=A.CDDE_DATA_CLASS in o.data())&&o.attr("class",o.data(A.CDDE_DATA_CLASS)||""),M||o.data(A.CDDE_DATA_CLASS,o.attr("class")),c={copy:{className:"file-b",title:["\u590d\u5236\u4ee3\u7801"],event:function(e){var t=D.unescape(n(l.code));lay.clipboard.writeText({text:t,done:function(){N.msg("\u5df2\u590d\u5236",{icon:1})},error:function(){N.msg("\u590d\u5236\u5931\u8d25",{icon:2})}}),"function"==typeof l.onCopy&&l.onCopy(t)}}},function b(){var e=o.parent("."+A.ELEM_PREVIEW),t=e.children("."+A.ELEM_TAB),a=e.children("."+A.ELEM_ITEM+"-preview");return t.remove(),a.remove(),e[0]&&o.unwrap(),b}(),l.preview&&(M="LAY-CODE-DF-"+d,f=l.layout||["code","preview"],s="iframe"===l.preview,E=x('
            '),C=x('
            '),r=x('
            '),_=x('
            '),u=x('
            '),l.id&&E.attr("id",l.id),E.addClass(l.className),C.attr("lay-filter",M),layui.each(f,function(e,t){var a=x('
          • ');0===e&&a.addClass("layui-this"),a.html(l.text[t]),r.append(a)}),x.extend(c,{full:{className:"screen-full",title:["\u6700\u5927\u5316\u663e\u793a","\u8fd8\u539f\u663e\u793a"],event:function(e){var e=e.elem,t=e.closest("."+A.ELEM_PREVIEW),a="layui-icon-"+this.className,i="layui-icon-screen-restore",l=this.title,o=x("html,body"),n="layui-scrollbar-hide";e.hasClass(a)?(t.addClass(A.ELEM_FULL),e.removeClass(a).addClass(i),e.attr("title",l[1]),o.addClass(n)):(t.removeClass(A.ELEM_FULL),e.removeClass(i).addClass(a),e.attr("title",l[0]),o.removeClass(n))}},window:{className:"release",title:["\u5728\u65b0\u7a97\u53e3\u9884\u89c8"],event:function(e){D.openWin({content:n(l.code)})}}}),l.copy&&("array"===layui.type(l.tools)?-1===l.tools.indexOf("copy")&&l.tools.unshift("copy"):l.tools=["copy"]),u.on("click",">i",function(){var e=x(this),t=e.data("type"),e={elem:e,type:t,options:l,rawCode:l.code,finalCode:D.unescape(n(l.code))};c[t]&&"function"==typeof c[t].event&&c[t].event(e),"function"==typeof l.toolsEvent&&l.toolsEvent(e)}),l.addTools&&l.tools&&(l.tools=[].concat(l.tools,l.addTools)),layui.each(l.tools,function(e,t){var a="object"==typeof t,i=a?t:c[t]||{className:t,title:[t]},l=i.className||i.type,o=i.title||[""],a=a?i.type||l:t;a&&(c[a]||((t={})[a]=i,x.extend(c,t)),u.append(''))}),o.addClass(A.ELEM_ITEM).wrap(E),C.append(r),l.tools&&C.append(u),o.before(C),s&&_.html(''),y=function(e){var t=e.children("iframe")[0];s&&t?t.srcdoc=n(l.code):e.html(l.code),setTimeout(function(){"function"==typeof l.done&&l.done({container:e,options:l,render:function(){I.render(e.find(".layui-form")),S.render()}})},3)},"preview"===f[0]?(_.addClass(A.ELEM_SHOW),o.before(_),y(_)):o.addClass(A.ELEM_SHOW).after(_),l.previewStyle=[l.style,l.previewStyle].join(""),_.attr("style",l.previewStyle),S.on("tab("+M+")",function(e){var t=x(this),a=x(e.elem).closest("."+A.ELEM_PREVIEW).find("."+A.ELEM_ITEM),e=a.eq(e.index);a.removeClass(A.ELEM_SHOW),e.addClass(A.ELEM_SHOW),"preview"===t.attr("lay-id")&&y(e),L()})),p=x(''),o.addClass((E=["layui-code-view layui-border-box"],l.wordWrap||E.push("layui-code-nowrap"),E.join(" "))),(C=l.theme||l.skin)&&(o.removeClass("layui-code-theme-dark layui-code-theme-light"),o.addClass("layui-code-theme-"+C)),l.highlighter&&o.addClass([l.highlighter,"language-"+l.lang,"layui-code-hl"].join(" ")),f=w(l.encode?D.escape(n(a)):a),h=f.lines,o.html(p.html(f.html)),l.ln&&o.append('
            '),l.height&&p.css("max-height",l.height),l.codeStyle=[l.style,l.codeStyle].join(""),l.codeStyle&&p.attr("style",function(e,t){return(t||"")+l.codeStyle}),v=[{selector:">.layui-code-wrap>.layui-code-line{}",setValue:function(e,t){e.style["padding-left"]=t+"px"}},{selector:">.layui-code-wrap>.layui-code-line>.layui-code-line-number{}",setValue:function(e,t){e.style.width=t+"px"}},{selector:">.layui-code-ln-side{}",setValue:function(e,t){e.style.width=t+"px"}}],m=lay.style({target:o[0],id:"DF-code-"+d,text:x.map(x.map(v,function(e){return e.selector}),function(e,t){return['.layui-code-view[lay-code-index="'+d+'"]',e].join(" ")}).join("")}),L=function b(){var e,i;return l.ln&&(e=Math.floor(h.length/100),i=p.children("."+A.ELEM_LINE).last().children("."+A.ELEM_LINE_NUM).outerWidth(),o.addClass(A.ELEM_LN_MODE),e)&&A.LINE_RAW_WIDTH
          • ')).html(l.title||l.text.code),o.prepend(_)),M=x('
            '),l.copy&&!l.preview&&((C=x(['','',""].join(""))).on("click",function(){c.copy.event()}),M.append(C)),l.langMarker&&M.append(''+l.lang+""),l.about&&M.append(l.about),o.append(M),l.preview||setTimeout(function(){"function"==typeof l.done&&l.done({})},3),l.elem.length===1+d&&"function"==typeof l.allDone&&l.allDone())),g})}),layui["layui.all"]||layui.addcss("modules/code.css?v=6","skincodecss"); \ No newline at end of file diff --git a/static/system/component/pear/css/module/global.css b/static/system/component/pear/css/module/global.css new file mode 100644 index 0000000..94d57c7 --- /dev/null +++ b/static/system/component/pear/css/module/global.css @@ -0,0 +1,977 @@ +.pear-container { + padding: 10px; + margin: 0px; + box-sizing: border-box; + background-color: transparent; + width: 100%; +} + +*::-webkit-scrollbar { + width: 0px; + height: 0px; +} + +*::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +*::-webkit-scrollbar-track { + background: transparent; +} + +*::-webkit-scrollbar-thumb { + background: #E6E6E6; + border-radius: 4px; +} + +*::-webkit-scrollbar-thumb:hover { + background: #E6E6E6; +} + +*::-webkit-scrollbar-corner { + background: #f6f6f6; +} + +.pear-row::after, +.pear-row::before { + content: ""; + display: table; + clear: both; +} + +.pear-col { + float: left; + min-height: 1px; +} + +.pear-row * { + box-sizing: border-box +} + +.pear-col-md1 { + width: 4.16%; +} + +.pear-col-md2 { + width: 8.33%; +} + +.pear-col-md3 { + width: 12.5%; +} + +.pear-col-md4 { + width: 16.66%; +} + +.pear-col-md5 { + width: 20.83%; +} + +.pear-col-md6 { + width: 25%; +} + +.pear-col-md7 { + width: 29.16%; +} + +.pear-col-md8 { + width: 33.33%; +} + +.pear-col-md9 { + width: 37.5%; +} + +.pear-col-md10 { + width: 41.66%; +} + +.pear-col-md11 { + width: 45.83%; +} + +.pear-col-md12 { + width: 50%; +} + +.pear-col-md13 { + width: 54.16%; +} + +.pear-col-md14 { + width: 58.33%; +} + +.pear-col-md15 { + width: 62.5%; +} + +.pear-col-md16 { + width: 66.66%; +} + +.pear-col-md17 { + width: 70.83%; +} + +.pear-col-md18 { + width: 75%; +} + +.pear-col-md19 { + width: 79.16%; +} + +.pear-col-md20 { + width: 83.33%; +} + +.pear-col-md21 { + width: 87.5%; +} + +.pear-col-md22 { + width: 91.66%; +} + +.pear-col-md23 { + width: 95.83%; +} + +.pear-col-md24 { + width: 100%; +} + +.pear-col-md-offset1 { + margin-left: 4.16%; +} + +.pear-col-md-offset2 { + margin-left: 8.33%; +} + +.pear-col-md-offset3 { + margin-left: 12.5%; +} + +.pear-col-md-offset4 { + margin-left: 16.66%; +} + +.pear-col-md-offset5 { + margin-left: 20.83%; +} + +.pear-col-md-offset6 { + margin-left: 25%; +} + +.pear-col-md-offset7 { + margin-left: 29.16%; +} + +.pear-col-md-offset8 { + margin-left: 33.33%; +} + +.pear-col-md-offset9 { + margin-left: 37.5%; +} + +.pear-col-md-offset10 { + margin-left: 41.66%; +} + +.pear-col-md-offset11 { + margin-left: 45.83%; +} + +.pear-col-md-offset12 { + margin-left: 50%; +} + +.pear-col-md-offset13 { + margin-left: 54.16%; +} + +.pear-col-md-offset14 { + margin-left: 58.33%; +} + +.pear-col-md-offset15 { + margin-left: 62.5%; +} + +.pear-col-md-offset16 { + margin-left: 66.66%; +} + +.pear-col-md-offset17 { + margin-left: 70.83%; +} + +.pear-col-md-offset18 { + margin-left: 75%; +} + +.pear-col-md-offset19 { + margin-left: 79.16%; +} + +.pear-col-md-offset20 { + margin-left: 83.33%; +} + +.pear-col-md-offset21 { + margin-left: 87.5%; +} + +.pear-col-md-offset22 { + margin-left: 91.66%; +} + +.pear-col-md-offset23 { + margin-left: 95.83%; +} + +.pear-col-md-offset24 { + margin-left: 100%; +} + + +@media all and (max-width:768px) { + .pear-col-xs1 { + width: 4.16%; + } + + .pear-col-xs2 { + width: 8.33%; + } + + .pear-col-xs3 { + width: 12.5%; + } + + .pear-col-xs4 { + width: 16.66%; + } + + .pear-col-xs5 { + width: 20.83%; + } + + .pear-col-xs6 { + width: 25%; + } + + .pear-col-xs7 { + width: 29.16%; + } + + .pear-col-xs8 { + width: 33.33%; + } + + .pear-col-xs9 { + width: 37.5%; + } + + .pear-col-xs10 { + width: 41.66%; + } + + .pear-col-xs11 { + width: 45.83%; + } + + .pear-col-xs12 { + width: 50%; + } + + .pear-col-xs13 { + width: 54.16%; + } + + .pear-col-xs14 { + width: 58.33%; + } + + .pear-col-xs15 { + width: 62.5%; + } + + .pear-col-xs16 { + width: 66.66%; + } + + .pear-col-xs17 { + width: 70.83%; + } + + .pear-col-xs18 { + width: 75%; + } + + .pear-col-xs19 { + width: 79.16%; + } + + .pear-col-xs20 { + width: 83.33%; + } + + .pear-col-xs21 { + width: 87.5%; + } + + .pear-col-xs22 { + width: 91.66%; + } + + .pear-col-xs23 { + width: 95.83%; + } + + .pear-col-xs24 { + width: 100%; + } + + .pear-col-xs-offset1 { + margin-left: 4.16%; + } + + .pear-col-xs-offset2 { + margin-left: 8.33%; + } + + .pear-col-xs-offset3 { + margin-left: 12.5%; + } + + .pear-col-xs-offset4 { + margin-left: 16.66%; + } + + .pear-col-xs-offset5 { + margin-left: 20.83%; + } + + .pear-col-xs-offset6 { + margin-left: 25%; + } + + .pear-col-xs-offset7 { + margin-left: 29.16%; + } + + .pear-col-xs-offset8 { + margin-left: 33.33%; + } + + .pear-col-xs-offset9 { + margin-left: 37.5%; + } + + .pear-col-xs-offset10 { + margin-left: 41.66%; + } + + .pear-col-xs-offset11 { + margin-left: 45.83%; + } + + .pear-col-xs-offset12 { + margin-left: 50%; + } + + .pear-col-xs-offset13 { + margin-left: 54.16%; + } + + .pear-col-xs-offset14 { + margin-left: 58.33%; + } + + .pear-col-xs-offset15 { + margin-left: 62.5%; + } + + .pear-col-xs-offset16 { + margin-left: 66.66%; + } + + .pear-col-xs-offset17 { + margin-left: 70.83%; + } + + .pear-col-xs-offset18 { + margin-left: 75%; + } + + .pear-col-xs-offset19 { + margin-left: 79.16%; + } + + .pear-col-xs-offset20 { + margin-left: 83.33%; + } + + .pear-col-xs-offset21 { + margin-left: 87.5%; + } + + .pear-col-xs-offset22 { + margin-left: 91.66%; + } + + .pear-col-xs-offset23 { + margin-left: 95.83%; + } + + .pear-col-xs-offset24 { + margin-left: 100%; + } +} + +@media all and (min-width:768px) and (max-width:992px) { + .pear-col-sm1 { + width: 4.16%; + } + + .pear-col-sm2 { + width: 8.33%; + } + + .pear-col-sm3 { + width: 12.5%; + } + + .pear-col-sm4 { + width: 16.66%; + } + + .pear-col-sm5 { + width: 20.83%; + } + + .pear-col-sm6 { + width: 25%; + } + + .pear-col-sm7 { + width: 29.16%; + } + + .pear-col-sm8 { + width: 33.33%; + } + + .pear-col-sm9 { + width: 37.5%; + } + + .pear-col-sm10 { + width: 41.66%; + } + + .pear-col-sm11 { + width: 45.83%; + } + + .pear-col-sm12 { + width: 50%; + } + + .pear-col-sm13 { + width: 54.16%; + } + + .pear-col-sm14 { + width: 58.33%; + } + + .pear-col-sm15 { + width: 62.5%; + } + + .pear-col-sm16 { + width: 66.66%; + } + + .pear-col-sm17 { + width: 70.83%; + } + + .pear-col-sm18 { + width: 75%; + } + + .pear-col-sm19 { + width: 79.16%; + } + + .pear-col-sm20 { + width: 83.33%; + } + + .pear-col-sm21 { + width: 87.5%; + } + + .pear-col-sm22 { + width: 91.66%; + } + + .pear-col-sm23 { + width: 95.83%; + } + + .pear-col-sm24 { + width: 100%; + } + + .pear-col-sm-offset1 { + margin-left: 4.16%; + } + + .pear-col-sm-offset2 { + margin-left: 8.33%; + } + + .pear-col-sm-offset3 { + margin-left: 12.5%; + } + + .pear-col-sm-offset4 { + margin-left: 16.66%; + } + + .pear-col-sm-offset5 { + margin-left: 20.83%; + } + + .pear-col-sm-offset6 { + margin-left: 25%; + } + + .pear-col-sm-offset7 { + margin-left: 29.16%; + } + + .pear-col-sm-offset8 { + margin-left: 33.33%; + } + + .pear-col-sm-offset9 { + margin-left: 37.5%; + } + + .pear-col-sm-offset10 { + margin-left: 41.66%; + } + + .pear-col-sm-offset11 { + margin-left: 45.83%; + } + + .pear-col-sm-offset12 { + margin-left: 50%; + } + + .pear-col-sm-offset13 { + margin-left: 54.16%; + } + + .pear-col-sm-offset14 { + margin-left: 58.33%; + } + + .pear-col-sm-offset15 { + margin-left: 62.5%; + } + + .pear-col-sm-offset16 { + margin-left: 66.66%; + } + + .pear-col-sm-offset17 { + margin-left: 70.83%; + } + + .pear-col-sm-offset18 { + margin-left: 75%; + } + + .pear-col-sm-offset19 { + margin-left: 79.16%; + } + + .pear-col-sm-offset20 { + margin-left: 83.33%; + } + + .pear-col-sm-offset21 { + margin-left: 87.5%; + } + + .pear-col-sm-offset22 { + margin-left: 91.66%; + } + + .pear-col-sm-offset23 { + margin-left: 95.83%; + } + + .pear-col-sm-offset24 { + margin-left: 100%; + } +} + +@media all and (min-width:1200px) { + .pear-col-lg1 { + width: 4.16%; + } + + .pear-col-lg2 { + width: 8.33%; + } + + .pear-col-lg3 { + width: 12.5%; + } + + .pear-col-lg4 { + width: 16.66%; + } + + .pear-col-lg5 { + width: 20.83%; + } + + .pear-col-lg6 { + width: 25%; + } + + .pear-col-lg7 { + width: 29.16%; + } + + .pear-col-lg8 { + width: 33.33%; + } + + .pear-col-lg9 { + width: 37.5%; + } + + .pear-col-lg10 { + width: 41.66%; + } + + .pear-col-lg11 { + width: 45.83%; + } + + .pear-col-lg12 { + width: 50%; + } + + .pear-col-lg13 { + width: 54.16%; + } + + .pear-col-lg14 { + width: 58.33%; + } + + .pear-col-lg15 { + width: 62.5%; + } + + .pear-col-lg16 { + width: 66.66%; + } + + .pear-col-lg17 { + width: 70.83%; + } + + .pear-col-lg18 { + width: 75%; + } + + .pear-col-lg19 { + width: 79.16%; + } + + .pear-col-lg20 { + width: 83.33%; + } + + .pear-col-lg21 { + width: 87.5%; + } + + .pear-col-lg22 { + width: 91.66%; + } + + .pear-col-lg23 { + width: 95.83%; + } + + .pear-col-lg24 { + width: 100%; + } + + .pear-col-lg-offset1 { + margin-left: 4.16%; + } + + .pear-col-lg-offset2 { + margin-left: 8.33%; + } + + .pear-col-lg-offset3 { + margin-left: 12.5%; + } + + .pear-col-lg-offset4 { + margin-left: 16.66%; + } + + .pear-col-lg-offset5 { + margin-left: 20.83%; + } + + .pear-col-lg-offset6 { + margin-left: 25%; + } + + .pear-col-lg-offset7 { + margin-left: 29.16%; + } + + .pear-col-lg-offset8 { + margin-left: 33.33%; + } + + .pear-col-lg-offset9 { + margin-left: 37.5%; + } + + .pear-col-lg-offset10 { + margin-left: 41.66%; + } + + .pear-col-lg-offset11 { + margin-left: 45.83%; + } + + .pear-col-lg-offset12 { + margin-left: 50%; + } + + .pear-col-lg-offset13 { + margin-left: 54.16%; + } + + .pear-col-lg-offset14 { + margin-left: 58.33%; + } + + .pear-col-lg-offset15 { + margin-left: 62.5%; + } + + .pear-col-lg-offset16 { + margin-left: 66.66%; + } + + .pear-col-lg-offset17 { + margin-left: 70.83%; + } + + .pear-col-lg-offset18 { + margin-left: 75%; + } + + .pear-col-lg-offset19 { + margin-left: 79.16%; + } + + .pear-col-lg-offset20 { + margin-left: 83.33%; + } + + .pear-col-lg-offset21 { + margin-left: 87.5%; + } + + .pear-col-lg-offset22 { + margin-left: 91.66%; + } + + .pear-col-lg-offset23 { + margin-left: 95.83%; + } + + .pear-col-lg-offset24 { + margin-left: 100%; + } +} + +.pear-col-space1 { + margin: -.5px +} + +.pear-col-space1>* { + padding: .5px +} + +.pear-col-space2 { + margin: -1px +} + +.pear-col-space2>* { + padding: 1px +} + +.pear-col-space4 { + margin: -2px +} + +.pear-col-space4>* { + padding: 2px +} + +.pear-col-space5 { + margin: -2.5px +} + +.pear-col-space5>* { + padding: 2.5px +} + +.pear-col-space6 { + margin: -3px +} + +.pear-col-space6>* { + padding: 3px +} + +.pear-col-space8 { + margin: -4px +} + +.pear-col-space8>* { + padding: 4px +} + +.pear-col-space10 { + margin: -5px +} + +.pear-col-space10>* { + padding: 5px +} + +.pear-col-space12 { + margin: -6px +} + +.pear-col-space12>* { + padding: 6px +} + +.pear-col-space14 { + margin: -7px +} + +.pear-col-space14>* { + padding: 7px +} + +.pear-col-space15 { + margin: -7.5px +} + +.pear-col-space15>* { + padding: 7.5px +} + +.pear-col-space16 { + margin: -8px +} + +.pear-col-space16>* { + padding: 8px +} + +.pear-col-space18 { + margin: -9px +} + +.pear-col-space18>* { + padding: 9px +} + +.pear-col-space20 { + margin: -10px +} + +.pear-col-space20>* { + padding: 10px +} + +.pear-col-space22 { + margin: -11px +} + +.pear-col-space22>* { + padding: 11px +} + +.pear-col-space24 { + margin: -12px +} + +.pear-col-space24>* { + padding: 12px +} + +.pear-col-space25 { + margin: -12.5px +} + +.pear-col-space25>* { + padding: 12.5px +} + +.pear-col-space26 { + margin: -13px +} + +.pear-col-space26>* { + padding: 13px +} + +.pear-col-space28 { + margin: -14px +} + +.pear-col-space28>* { + padding: 14px +} + +.pear-col-space30 { + margin: -15px +} + +.pear-col-space30>* { + padding: 15px +} \ No newline at end of file diff --git a/static/system/component/pear/css/module/layout.css b/static/system/component/pear/css/module/layout.css index 9c4d082..ae55bba 100644 --- a/static/system/component/pear/css/module/layout.css +++ b/static/system/component/pear/css/module/layout.css @@ -1,7 +1,5 @@ .pear-container { - margin: 10px; background-color: whitesmoke; - width: calc(100vw - 20px); } body::-webkit-scrollbar { diff --git a/static/system/component/pear/css/module/menu.css b/static/system/component/pear/css/module/menu.css index 938f987..9c59c64 100644 --- a/static/system/component/pear/css/module/menu.css +++ b/static/system/component/pear/css/module/menu.css @@ -16,7 +16,7 @@ line-height: 48px; } -.pear-nav-tree .layui-nav-item>a .layui-nav-more { +.pear-nav-tree .layui-nav-item>a .layui-nav-more { padding: 0px; } @@ -24,7 +24,8 @@ width: 0px; height: 0px; } -.pear-side-scroll{ + +.pear-side-scroll { width: 230px; } @@ -33,7 +34,7 @@ .layui-nav-tree .layui-this, .layui-nav-tree .layui-this>a, .layui-nav-tree .layui-this>a:hover { - background-color: #5FB878; + background-color: var(--global-primary-color); } .pear-nav-tree .toast { @@ -100,7 +101,7 @@ font-size: 14px; } -.pear-nav-control.pc li{ +.pear-nav-control.pc li { display: inline-block; } @@ -112,15 +113,15 @@ background-color: whitesmoke; } -.pear-nav-control.pc *{ - color: darkslategray!important; +.pear-nav-control.pc * { + color: darkslategray !important; } -.pear-nav-control.pc .layui-nav-bar{ - display: none!important; +.pear-nav-control.pc .layui-nav-bar { + display: none !important; } -.pear-nav-control .layui-nav-child{ +.pear-nav-control .layui-nav-child { border: 1px solid whitesmoke; border-radius: 6px; width: 150px; @@ -134,6 +135,7 @@ display: block !important; background: transparent !important; } + .pear-nav-tree .layui-nav-hover:before { content: ''; position: absolute; @@ -147,66 +149,73 @@ display: block; box-shadow: 0px 0px 3px lightgray; } + .pear-nav-tree .layui-nav-hover a span { display: inline-block !important; } + .pear-nav-tree .layui-nav-hover a i { display: none; } + .pear-nav-tree .layui-nav-child dd a span { margin-left: 26px !important; } + .pear-nav-tree .layui-nav-child dd a i { display: none; } + .pear-nav-tree .layui-nav-hover dd a span { margin-left: 0px !important; } + .pear-nav-tree dl { padding-top: 0; padding-bottom: 0; } + /** 亮 样 式*/ -.dark-theme .layui-nav-tree{ - background-color: #28333E!important; +.dark-theme .layui-nav-tree { + background-color: #28333E !important; } -.light-theme{ - background-color: white!important; +.light-theme { + background-color: white !important; } .light-theme .pear-nav-tree, .light-theme .pear-nav-tree .layui-nav-hover:before, -.light-theme .pear-nav-tree .layui-nav-child{ - background-color: white!important; +.light-theme .pear-nav-tree .layui-nav-child { + background-color: white !important; } .light-theme .pear-nav-tree a, -.light-theme .pear-nav-tree .layui-nav-more{ - color: dimgray!important; +.light-theme .pear-nav-tree .layui-nav-more { + color: dimgray !important; border-top-color: dimgray; } -.light-theme .pear-nav-tree .layui-nav-itemed>a>.layui-nav-more{ - border-top-color: white!important; - border-bottom-color: dimgray!important; +.light-theme .pear-nav-tree .layui-nav-itemed>a>.layui-nav-more { + border-top-color: white !important; + border-bottom-color: dimgray !important; } .light-theme .pear-nav-tree .layui-this a, -.light-theme .pear-nav-tree .layui-this{ - color: white!important; - background-color: #5FB878!important; - +.light-theme .pear-nav-tree .layui-this { + color: white !important; + background-color: var(--global-primary-color) !important; + } -.light-theme .pear-nav-tree .layui-this a:hover{ - background-color: #5FB878!important; - +.light-theme .pear-nav-tree .layui-this a:hover { + background-color: var(--global-primary-color) !important; + } - -.light-theme .pear-nav-tree .layui-nav-bar{ + +.light-theme .pear-nav-tree .layui-nav-bar { display: none; - + } /** 下 拉 图 标 */ @@ -247,6 +256,7 @@ width: 12px; text-align: center; } + .pear-nav-tree.arrow .layui-nav-child.layui-nav-hover>dd>a>.layui-nav-more { display: inline-block !important; transform: rotate(270deg); @@ -264,4 +274,4 @@ content: '\e61a'; display: inline-block; vertical-align: middle; -} +} \ No newline at end of file diff --git a/static/system/component/pear/css/module/menuSearch.css b/static/system/component/pear/css/module/menuSearch.css new file mode 100644 index 0000000..e4f5b54 --- /dev/null +++ b/static/system/component/pear/css/module/menuSearch.css @@ -0,0 +1,90 @@ +/* 搜索面板 */ +.menu-search-content .layui-input { + padding-left: 30px; +} + +.menu-search-content .layui-input:focus { + border: 1px solid var(--global-primary-color)!important; + box-shadow: none; +} + +.menu-search-content { + display: flex; + flex-wrap: wrap; + justify-content: center; +} + +.menu-search-input-wrapper { + width: 100%; + padding: 15px 15px; +} + +.menu-search-no-data { + display: flex; + justify-content: center; + width: 100%; + height: 122px; + align-items: center; +} + +.menu-search-list { + width: 100%; + padding: 5px 15px; +} + +.menu-search-list li { + position: relative; + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: nowrap; + height: 50px; + margin-bottom: 8px; + padding: 0px 10px; + color: currentColor; + font-size: 14px; + border-radius: 4px; + box-shadow: 0 1px 3px #d4d9e1; + cursor: pointer; + background-color: #fff; +} + +.menu-search-list li.this, +.menu-search-list li:hover { + background-color: var(--global-primary-color); + color: white; +} +.menu-search-tips { + margin-bottom: 15px; + padding: 0 15px; + width: 100% +} + +.menu-search-tips>div { + display: flex; + align-items: center; + justify-content: flex-end; + font-size: 12px; +} + +.menu-search-tips .mr-1 { + margin-right: 4px; +} + +.menu-search-tips .mr-5 { + margin-right: 20px; +} + +.menu-search-tips .w-5 { + width: 14px; +} + +.menu-search-tips kbd { + line-height: 1.5; + border: 1px solid #e5e7eb; + font-size: 10px; + text-align: center; + padding: 2px 6px; + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace; + border-radius: 5px; +} \ No newline at end of file diff --git a/static/system/component/pear/css/module/messageCenter.css b/static/system/component/pear/css/module/messageCenter.css new file mode 100644 index 0000000..0ab9ef3 --- /dev/null +++ b/static/system/component/pear/css/module/messageCenter.css @@ -0,0 +1,39 @@ +.pear-message-center { + width: 360px; + height: 100%; +} + +.pear-message-center .layui-tab .layui-tab-title{ + display: flex; +} + +.pear-message-center .layui-tab .layui-tab-title .layui-this::after { + display: none; +} + +.pear-message-center .layui-tab .layui-tab-title li { + flex: 1; +} + +.pear-message-center .message-item img { + margin-left: 8px; + width: 33px !important; + height: 33px !important; + border-radius: 50px; + margin-right: 15px; +} + +.pear-message-center .message-item { + height: 64px !important; + line-height: 45px !important; + padding-right: 20px; + padding-left: 20px; + border-bottom: 1px solid whitesmoke; + padding-top: 10px; + padding-bottom: 15px; +} + +.pear-message-center .message-item .extra { + float: right; + right: 10px; +} \ No newline at end of file diff --git a/static/system/component/pear/css/module/nprogress.css b/static/system/component/pear/css/module/nprogress.css index 24c5cf1..a78f1c9 100644 --- a/static/system/component/pear/css/module/nprogress.css +++ b/static/system/component/pear/css/module/nprogress.css @@ -4,7 +4,7 @@ } #nprogress .bar { - background: #29d; + background: var(--global-primary-color); position: fixed; z-index: 999999; @@ -22,7 +22,7 @@ right: 0px; width: 100px; height: 100%; - box-shadow: 0 0 10px #29d, 0 0 5px #29d; + box-shadow: 0 0 10px var(--global-primary-color), 0 0 5px var(--global-primary-color); opacity: 1.0; -webkit-transform: rotate(3deg) translate(0px, -4px); @@ -45,8 +45,8 @@ box-sizing: border-box; border: solid 2px transparent; - border-top-color: #29d; - border-left-color: #29d; + border-top-color: var(--global-primary-color); + border-left-color: var(--global-primary-color); border-radius: 50%; -webkit-animation: nprogress-spinner 400ms linear infinite; diff --git a/static/system/component/pear/css/module/page.css b/static/system/component/pear/css/module/page.css new file mode 100644 index 0000000..2131056 --- /dev/null +++ b/static/system/component/pear/css/module/page.css @@ -0,0 +1,154 @@ +.pear-page { + width: 100%; + position: relative; + overflow-y: auto; + height: 100%; +} + +.pear-page .dot { + width: 5px; + height: 24px; + background-color: #5FB878; + margin-top: 8px; + margin-left: 15px; + border-radius: 2px; + display: inline-block; +} + +.pear-page .pear-page-title { + height: 40px; + line-height: 40px; + background-color: white; + border: whitesmoke 1px solid; +} + +.pear-page .pear-page-content, +.pear-page .pear-page-content iframe { + width: 100%; + height: calc(100% - 0px) !important; +} + +.pear-page .pear-page-content iframe { + height: calc(100% - 4px) !important; +} + +.pear-page-loading { + position: absolute; + display: none; + width: 100%; + height: calc(100% - 0px) !important; + background-color: #fff; + top: 0px; + z-index: 19; +} + +.pear-page-loading.close { + animation: close 1s; + -webkit-animation: close 1s; + animation-fill-mode: forwards; +} + +.ball-loader { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%) +} + +.ball-loader>span, +.signal-loader>span { + background-color: #4aca85; + display: inline-block +} + +.ball-loader>span:nth-child(1), +.ball-loader.sm>span:nth-child(1), +.signal-loader>span:nth-child(1), +.signal-loader.sm>span:nth-child(1) { + -webkit-animation-delay: 0s; + animation-delay: 0s +} + +.ball-loader>span:nth-child(2), +.ball-loader.sm>span:nth-child(2), +.signal-loader>span:nth-child(2), +.signal-loader.sm>span:nth-child(2) { + -webkit-animation-delay: .1s; + animation-delay: .1s +} + +.ball-loader>span:nth-child(3), +.ball-loader.sm>span:nth-child(3), +.signal-loader>span:nth-child(3), +.signal-loader.sm>span:nth-child(3) { + -webkit-animation-delay: .15s; + animation-delay: .15s +} + +.ball-loader>span:nth-child(4), +.ball-loader.sm>span:nth-child(4), +.signal-loader>span:nth-child(4), +.signal-loader.sm>span:nth-child(4) { + -webkit-animation-delay: .2s; + animation-delay: .2s +} + +.ball-loader>span { + width: 20px; + height: 20px; + margin: 0 3px; + border-radius: 50%; + transform: scale(0); + -ms-transform: scale(0); + -webkit-transform: scale(0); + animation: ball-load 1s ease-in-out infinite; + -webkit-animation: 1s ball-load ease-in-out infinite +} + +@-webkit-keyframes ball-load { + 0% { + transform: scale(0); + -webkit-transform: scale(0) + } + + 50% { + transform: scale(1); + -webkit-transform: scale(1) + } + + 100% { + transform: scale(0); + -webkit-transform: scale(0) + } +} + +@keyframes ball-load { + 0% { + transform: scale(0); + -webkit-transform: scale(0) + } + + 50% { + transform: scale(1); + -webkit-transform: scale(1) + } + + 100% { + transform: scale(0); + -webkit-transform: scale(0) + } +} + +@-webkit-keyframes close { + 0% { + opacity: 1; + /*display: block;*/ + } + + 100% { + opacity: 0; + /*display: none;*/ + } +} diff --git a/static/system/component/pear/css/module/tabPage.css b/static/system/component/pear/css/module/tabPage.css new file mode 100644 index 0000000..589aea6 --- /dev/null +++ b/static/system/component/pear/css/module/tabPage.css @@ -0,0 +1,314 @@ +.pear-tab-page { + margin: 0px; + overflow: hidden; + height: 100% !important; +} + +.pear-tab-page .layui-tab-content { + height: calc(100% - 42px) !important; +} + +.pear-tab-page .layui-tab-content .layui-tab-item { + overflow-y: auto; + height: 100%; +} + +.pear-tab-page-menu{ + box-shadow: none; + border-radius: 4px!important; + overflow: hidden; + box-shadow: 2px 0 6px rgba(0, 21, 41, .10); +} + +.pear-tab-page-menu .item{ + height: 20px; + padding-left: 18px; + padding-top: 7px; + padding-bottom: 7px; + color: #333; + font-size: 13.5px; + line-height: 20px; + cursor:pointer; +} +.pear-tab-page-menu .item:hover{ + background: var(--global-primary-color); + color: white; +} + +.pear-tab-page .layui-tab-content { + padding: 0px; +} + +.pear-tab-page > .layui-tab-title { + border: none; + border: 1px solid whitesmoke; + background-color: white; +} + +.pear-tab-page > .layui-tab-title li { + border-right: 1px solid whitesmoke; + color: dimgray; + font-size: 13.5px; +} + +.pear-tab-page > .layui-tab-title .layui-tab-bar { + display: none; +} + +.pear-tab-page .layui-nav-more { + display: none; +} + +.pear-tab-page > .layui-tab-title .layui-this:after { + display: none; +} + +.pear-tab-page > .layui-tab-title .pear-tab-page-active { + display: inline-block; + background-color: lightgray; + width: 8px; + height: 8px; + border-radius: 30px; + margin-right: 12px; +} + +.pear-tab-page > .layui-tab-title .layui-this .pear-tab-page-active { + background-color: var(--global-primary-color) !important; +} + +.pear-tab-page > .layui-tab-title .layui-tab-close:hover { + background-color: white; + line-height: 19px; + color: gray; +} + +.pear-tab-page > .layui-tab-title .disable-close+.layui-tab-close { + display: none; +} + +.pear-tab-page > .layui-tab-title .able-close+.layui-tab-close { + display: inline-block; +} + +.pear-tab-page .layui-tab-close{ + font-size: 13px; +} + +.pear-tab-page .layui-tab-control>li { + position: absolute; + top: 0px; + height: 40px; + line-height: 40px; + width: 40px; + background-color: white; + border-top: whitesmoke 1px solid; + border-bottom: whitesmoke 1px solid; + text-align: center; +} + +.pear-tab-page .layui-tab-prev { + left: 0px; + border-right: whitesmoke 1px solid; +} + +.pear-tab-page .layui-tab-next { + right: 40px; + border-left: 1px solid whitesmoke; +} + +.pear-tab-page .layui-tab-tool { + right: 0px; + border-left: 1px solid whitesmoke; +} + +.pear-tab-page .layui-tab-control .layui-tab-tool, +.pear-tab-page .layui-tab-control .layui-tab-prev, +.pear-tab-page .layui-tab-control .layui-tab-next { + display: none; +} + +.pear-tab-page.layui-tab-roll .layui-tab-control .layui-tab-prev, +.pear-tab-page.layui-tab-roll .layui-tab-control .layui-tab-next { + display: block; +} + +.pear-tab-page.layui-tab-roll .layui-tab-control .layui-tab-next { + right: 0px; + border-right: 1px solid whitesmoke; +} + +.pear-tab-page.layui-tab-roll .layui-tab-title { + padding-left: 40px; + padding-right: 40px; +} + +.pear-tab-page.layui-tab-tool .layui-tab-control .layui-tab-tool { + display: block; +} + +.pear-tab-page.layui-tab-tool .layui-tab-title { + padding-left: 0px; + padding-right: 40px; +} + +.pear-tab-page.layui-tab-rollTool > .layui-tab-title { + padding-left: 40px; + padding-right: 80px; +} + +.pear-tab-page.layui-tab-rollTool .layui-tab-control .layui-tab-prev, +.pear-tab-page.layui-tab-rollTool .layui-tab-control .layui-tab-next, +.pear-tab-page.layui-tab-rollTool .layui-tab-control .layui-tab-tool { + display: block; +} + +.pear-tab-page .layui-tab-tool .layui-nav { + position: absolute; + height: 43px !important; + top: 0; + width: 100%; + height: 100%; + padding: 0; + background: 0 0; +} + +.pear-tab-page .layui-tab-tool .layui-nav-item { + height: 40px; +} + +.pear-tab-page .layui-tab-tool .layui-nav-bar { + display: none; +} + +.pear-tab-page .layui-tab-tool .layui-nav-child { + left: auto; + top: 45px; + right: 3px; + width: 120px; + border: 1px solid whitesmoke; +} + +.pear-tab-page .layui-tab-tool .layui-this a { + background-color: #009688; +} + +.pear-tab-page-loading { + position: absolute; + display: none; + width: 100%; + height: calc(100% - 42px); + top: 42px; + z-index: 19; + background-color: #fff +} + +.pear-tab-page-loading.close { + animation: close 1s; + -webkit-animation: close 1s; + animation-fill-mode: forwards; +} + +.ball-loader { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%) +} + +.ball-loader>span, +.signal-loader>span { + background-color: var(--global-primary-color) !important; + display: inline-block +} + +.ball-loader>span:nth-child(1), +.ball-loader.sm>span:nth-child(1), +.signal-loader>span:nth-child(1), +.signal-loader.sm>span:nth-child(1) { + -webkit-animation-delay: 0s; + animation-delay: 0s +} + +.ball-loader>span:nth-child(2), +.ball-loader.sm>span:nth-child(2), +.signal-loader>span:nth-child(2), +.signal-loader.sm>span:nth-child(2) { + -webkit-animation-delay: .1s; + animation-delay: .1s +} + +.ball-loader>span:nth-child(3), +.ball-loader.sm>span:nth-child(3), +.signal-loader>span:nth-child(3), +.signal-loader.sm>span:nth-child(3) { + -webkit-animation-delay: .15s; + animation-delay: .15s +} + +.ball-loader>span:nth-child(4), +.ball-loader.sm>span:nth-child(4), +.signal-loader>span:nth-child(4), +.signal-loader.sm>span:nth-child(4) { + -webkit-animation-delay: .2s; + animation-delay: .2s +} + +.ball-loader>span { + width: 20px; + height: 20px; + margin: 0 3px; + border-radius: 50%; + transform: scale(0); + -ms-transform: scale(0); + -webkit-transform: scale(0); + animation: ball-load 1s ease-in-out infinite; + -webkit-animation: 1s ball-load ease-in-out infinite +} + +@-webkit-keyframes ball-load { + 0% { + transform: scale(0); + -webkit-transform: scale(0) + } + + 50% { + transform: scale(1); + -webkit-transform: scale(1) + } + + 100% { + transform: scale(0); + -webkit-transform: scale(0) + } +} + +@keyframes ball-load { + 0% { + transform: scale(0); + -webkit-transform: scale(0) + } + + 50% { + transform: scale(1); + -webkit-transform: scale(1) + } + + 100% { + transform: scale(0); + -webkit-transform: scale(0) + } +} + +@-webkit-keyframes close { + 0% { + opacity: 1; + /*display: block;*/ + } + + 100% { + opacity: 0; + /*display: none;*/ + } +} diff --git a/static/system/component/pear/css/pear.css b/static/system/component/pear/css/pear.css index c43e364..e35a690 100644 --- a/static/system/component/pear/css/pear.css +++ b/static/system/component/pear/css/pear.css @@ -1,30 +1,17 @@ +/* Pear Admin layui */ @import url("../../layui/css/layui.css"); @import url("../font/iconfont.css"); +@import url("module/nprogress.css"); +@import url("module/messageCenter.css"); +@import url("module/global.css"); +@import url("module/menu.css"); +@import url("module/menuSearch.css"); +@import url("module/page.css"); +@import url("module/tabPage.css"); +@import url("module/toast.css"); +/* Pear Admin Flask */ @import url("module/dtree/font/dtreefont.css"); @import url("module/dtree/dtree.css"); -@import url("module/iconPicker.css"); -@import url("module/treetable.css"); -@import url("module/nprogress.css"); -@import url("module/message.css"); -@import url("module/cropper.css"); -@import url("module/loading.css"); -@import url("module/topBar.css"); -@import url("module/select.css"); -@import url("module/layout.css"); -@import url("module/notice.css"); -@import url("module/button.css"); -@import url("module/table.css"); -@import url("module/frame.css"); @import url("module/layer.css"); -@import url("module/toast.css"); -@import url("module/menu.css"); -@import url("module/form.css"); -@import url("module/link.css"); -@import url("module/code.css"); -@import url("module/step.css"); -@import url("module/card.css"); -@import url("module/tab.css"); -@import url("module/tag.css"); -@import url("module/fullscreen.css"); -@import url("module/popover.min.css"); \ No newline at end of file +@import url("module/layout.css"); diff --git a/static/system/component/pear/module/admin.js b/static/system/component/pear/module/admin.js index b829933..78c8285 100644 --- a/static/system/component/pear/module/admin.js +++ b/static/system/component/pear/module/admin.js @@ -1,124 +1,229 @@ -layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'menu', 'frame', 'theme', 'convert','fullscreen'], - function(exports) { +layui.define(['jquery', 'tools', 'element', 'yaml', 'form', 'tabPage', 'menu', 'page', 'fullscreen', 'messageCenter', 'menuSearch'], + function (exports) { "use strict"; var $ = layui.jquery, form = layui.form, - element = layui.element, yaml = layui.yaml, - pearTab = layui.tab, - convert = layui.convert, - pearMenu = layui.menu, - pearFrame = layui.frame, - pearTheme = layui.theme, - message = layui.message, - fullscreen=layui.fullscreen; - - var bodyFrame; - var sideMenu; - var bodyTab; - var config; - var logout = function() {}; - var msgInstance; - var body = $('body'); + page = layui.page, + menu = layui.menu, + tabPage = layui.tabPage, + messageCenter = layui.messageCenter, + menuSearch = layui.menuSearch, + fullscreen = layui.fullscreen, + tools = layui.tools; - var pearAdmin = new function() { + var configurationCache; - var configType = 'yml'; - var configPath = 'pear.config.yml'; + var logout = function () { }; - this.setConfigPath = function(path) { - configPath = path; - } + var body = $('body'); - this.setConfigType = function(type) { - configType = type; + var pearAdmin = new function () { + + this.configuration = {}; + + this.configurationPath = "pear.config.yml"; + + this.instances = {}; + + /** + * @since Pear Admin 4.0 + * + * 获取 pear.config 实现 [ default ] + */ + this.configurationProvider = () => { + return new Promise((resolve) => { + if (this.configurationPath.indexOf("yml") == -1) { + $.ajax({ + type: 'get', + url: this.configurationPath, + dataType: 'json', + async: false, + success: (result) => { + resolve(result); + } + }); + } else { + resolve(yaml.load(this.configurationPath)); + } + }) } - this.render = function(initConfig) { - if (initConfig !== undefined) { - applyConfig(initConfig); + /** + * @since Pear Admin 4.0 + * + * 配置 pear.config 路径 + */ + this.setConfigurationPath = (path) => { + this.configurationPath = path; + } + + /** + * @since Pear Admin 4.0 + * + * 获取 pear.config 实现 [ implement ] + */ + this.setConfigurationProvider = (provider) => { + this.configurationProvider = provider; + } + + /** + * @since Pear Admin 4.0 + * + * 获取 pear.config 配置 + */ + this.getConfiguration = () => { + return this.configuration; + } + + /** + * @since Pear Admin 4.0 + * + * Core Function. + * + * @param {*} options + */ + this.render = (options) => { + if (options !== undefined) { + pearAdmin.apply(options); } else { - applyConfig(pearAdmin.readConfig()); + this.configurationProvider().then((result) => { + pearAdmin.apply(result); + }) } } - this.readConfig = function() { - if (configType === "yml") { - return yaml.load(configPath); - } else { - var data; - $.ajax({ - url: configPath, - type: 'get', - dataType: 'json', - async: false, - success: function(result) { - data = result; + /** + * @since Pear Admin 4.0 + * + * 启动构建 + */ + this.apply = function (configuration) { + configurationCache = configuration; + pearAdmin.logoRender(configuration); + pearAdmin.menuRender(configuration); + pearAdmin.menuSearchRender(configuration); + pearAdmin.bodyRender(configuration); + pearAdmin.messageCenterRender(configuration); + pearAdmin.themeRender(configuration); + pearAdmin.keepLoad(configuration); + window.PearAdmin = pearAdmin; + } + + /** + * @since Pear Admin 4.0 + * + * 菜单搜索 + */ + this.menuSearchRender = function (options) { + menuSearch.render({ + elem: ".menuSearch", + dataProvider: () => pearAdmin.instances.menu.cache(), + select: (node) => { + if (node.type == "1") { + pearAdmin.instances.menu.selectItem(node.id); + if (node.openType === "_layer") { + layer.open({ + type: 2, + title: data.title, + content: data.url, + area: ['80%', '80%'], + maxmin: true + }) + } else { + if (isMuiltTab(options) === "true" || + isMuiltTab(options) === true) { + pearAdmin.instances.tabPage.changePage({ + id: node.id, + title: node.title, + type: node.openType, + url: node.url, + close: true + }); + } else { + pearAdmin.instances.page.changePage({ + href: node.url, + type: node.openType + }); + } + } } - }) - return data; - } + } + }) } - this.messageRender = function(option) { - var option = { + /** + * @since Pear Admin 4.0 + * + * 消息中心 + */ + this.messageCenterRender = function (options) { + messageCenter.render({ elem: '.message', - url: option.header.message, + url: options.header.message, height: '250px' - }; - msgInstance = message.render(option); + }); } - this.logoRender = function(param) { + this.logoRender = function (param) { $(".layui-logo .logo").attr("src", param.logo.image); $(".layui-logo .title").html(param.logo.title); } - this.menuRender = function(param) { - sideMenu = pearMenu.render({ - elem: 'sideMenu', - async: param.menu.async !== undefined ? param.menu.async : true, - theme: "dark-theme", - height: '100%', + /** + * @since Pear Admin 4.0 + * + * 侧边菜单 + */ + this.menuRender = function (param) { + pearAdmin.instances.menu = menu.render({ + elem: 'side', + async: param.menu.async, method: param.menu.method, - control: isControl(param) === 'true' || isControl(param) === true ? 'control' : false, // control + control: isControl(param) === 'true' || isControl(param) === true ? 'control' : false, controlWidth: param.menu.controlWidth, - defaultMenu: 0, accordion: param.menu.accordion, - url: param.menu.data, data: param.menu.data, + url: param.menu.data, parseData: false, - change: function() { + defaultMenu: 0, + change: function () { compatible(); }, - done: function() { - sideMenu.isCollapse = param.menu.collapse; - sideMenu.selectItem(param.menu.select); - pearAdmin.collapse(param); + done: function () { + pearAdmin.instances.menu.isCollapse = param.menu.collapse; + pearAdmin.instances.menu.selectItem(param.menu.select); + if (param.menu.collapse) { + if ($(window).width() >= 768) { + collapse() + } + } } }); } - this.bodyRender = function(param) { + /** + * @since Pear Admin 4.0 + * + * 视图容器 + */ + this.bodyRender = function (param) { - body.on("click", ".refresh", function() { - refresh(); + body.on("click", ".refresh", function () { + pearAdmin.refresh(); }) if (isMuiltTab(param) === "true" || isMuiltTab(param) === true) { - bodyTab = pearTab.render({ + + pearAdmin.instances.tabPage = tabPage.render({ elem: 'content', - roll: true, - tool: true, - width: '100%', - height: '100%', session: param.tab.session, index: 0, tabMax: param.tab.max, preload: param.tab.preload, - closeEvent: function(id) { - sideMenu.selectItem(id); + closeEvent: function (id) { + pearAdmin.instances.menu.selectItem(id); }, data: [{ id: param.tab.index.id, @@ -126,58 +231,92 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm title: param.tab.index.title, close: false }], - success: function(id) { + success: function (id) { if (param.tab.session) { - setTimeout(function() { - sideMenu.selectItem(id); - bodyTab.positionTab(); + setTimeout(function () { + pearAdmin.instances.menu.selectItem(id); + pearAdmin.instances.tabPage.positionTab(); }, 500) } } }); - bodyTab.click(function(id) { + pearAdmin.instances.tabPage.click(function (id) { if (!param.tab.keepState) { - bodyTab.refresh(false); + pearAdmin.instances.tabPage.refresh(false); } - bodyTab.positionTab(); - sideMenu.selectItem(id); + pearAdmin.instances.tabPage.positionTab(); + pearAdmin.instances.menu.selectItem(id); }) - sideMenu.click(function(dom, data) { - bodyTab.addTabOnly({ - id: data.menuId, - title: data.menuTitle, - url: data.menuUrl, - icon: data.menuIcon, - close: true - }, 300); + pearAdmin.instances.menu.click(function (dom, data) { + if (data.menuOpenType === "_layer") { + layer.open({ type: 2, title: data.menuTitle, content: data.menuUrl, area: ['80%', '80%'], maxmin: true }) + } else { + pearAdmin.instances.tabPage.changePage({ + id: data.menuId, + title: data.menuTitle, + type: data.menuOpenType, + url: data.menuUrl, + close: true + }); + } compatible(); }) + } else { - bodyFrame = pearFrame.render({ + + pearAdmin.instances.page = page.render({ elem: 'content', title: '首页', - url: param.tab.index.href, - width: '100%', - height: '100%' + url: param.tab.index.href }); - sideMenu.click(function(dom, data) { - bodyFrame.changePage(data.menuUrl, true); + pearAdmin.instances.menu.click(function (dom, data) { + if (data.menuOpenType === "_layer") { + layer.open({ type: 2, title: data.menuTitle, content: data.menuUrl, area: ['80%', '80%'], maxmin: true }) + } else { + pearAdmin.instances.page.changePage({ href: data.menuUrl, type: data.menuOpenType }); + } compatible() }) } } - this.keepLoad = function(param) { + this.keepLoad = function (param) { compatible() - setTimeout(function() { - $(".loader-main").fadeOut(200); + setTimeout(function () { + $(".loader-wrapper").fadeOut(200); }, param.other.keepLoad) } - this.themeRender = function(option) { + /*** + * @since Pear Admin 4.0 + * + * 切换主题色 + */ + this.changeTheme = function () { + const variableKey = "--global-primary-color"; + const variableVal = localStorage.getItem("theme-color-color"); + document.documentElement.style.setProperty(variableKey, variableVal); + + /* 遍历所有 iframe 更改主题色 */ + const iframes = document.querySelectorAll('iframe'); + iframes.forEach(function(iframe) { + try { + const iframeDocument = iframe.contentDocument || iframe.contentWindow.document; + // 设置 iframe 中的主题色 + iframeDocument.documentElement.style.setProperty(variableKey, variableVal); + } catch (e) {} + }); + } + + /** + * @since Pear Admin 4.0 + * + * 主题配置 + */ + this.themeRender = function (option) { if (option.theme.allowCustom === false) { $(".setting").remove(); } @@ -186,7 +325,7 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm localStorage.setItem("theme-color", currentColor.id); localStorage.setItem("theme-color-color", currentColor.color); localStorage.setItem("theme-color-second", currentColor.second); - pearTheme.changeTheme(window, isAutoHead(config)); + pearAdmin.changeTheme(); var menu = localStorage.getItem("theme-menu"); if (menu === null) { @@ -243,40 +382,51 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm } var footer = localStorage.getItem("footer"); - if( footer === null) { + if (footer === null) { footer = option.other.footer; - }else{ + } else { if (option.theme.allowCustom === false) { footer = option.other.footer; } } + var dark = localStorage.getItem("dark"); + if (dark === null) { + dark = option.theme.dark; + } else { + if (option.theme.allowCustom === false) { + dark = option.theme.dark; + } + } + localStorage.setItem("muilt-tab", muiltTab); localStorage.setItem("theme-banner", banner); localStorage.setItem("theme-menu", menu); + localStorage.setItem("footer", footer); + localStorage.setItem("control", control); localStorage.setItem("theme-header", header); localStorage.setItem("auto-head", autoHead); - localStorage.setItem("control", control); - localStorage.setItem("footer", footer); + localStorage.setItem("dark", dark); this.menuSkin(menu); this.headerSkin(header); this.bannerSkin(banner); + this.switchTheme(dark); this.footer(footer); } - this.footer = function(footer){ + this.footer = function (footer) { var bodyDOM = $(".pear-admin .layui-body"); var footerDOM = $(".pear-admin .layui-footer"); if (footer === true || footer === "true") { footerDOM.removeClass("close"); - bodyDOM.css("bottom", footerDOM.outerHeight()); + bodyDOM.css("height", "calc(100% - 105px)"); } else { footerDOM.addClass("close"); - bodyDOM.css("bottom", ""); + bodyDOM.css("height", "calc(100% - 60px)"); } } - this.bannerSkin = function(theme) { + this.bannerSkin = function (theme) { var pearAdmin = $(".pear-admin"); pearAdmin.removeClass("banner-layout"); if (theme === true || theme === "true") { @@ -284,158 +434,81 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm } } - this.collapse = function(param) { - if (param.menu.collapse) { - if ($(window).width() >= 768) { - collapse() - } + this.switchTheme = function (checked) { + var $pearAdmin = $(".pear-admin"); + $pearAdmin.removeClass("pear-admin-dark"); + if (checked === true || checked === "true") { + $pearAdmin.addClass("pear-admin-dark"); } } - this.menuSkin = function(theme) { + this.menuSkin = function (theme) { var pearAdmin = $(".pear-admin .layui-side"); pearAdmin.removeClass("light-theme"); pearAdmin.removeClass("dark-theme"); pearAdmin.addClass(theme); } - this.headerSkin = function(theme) { + this.headerSkin = function (theme) { var pearAdmin = $(".pear-admin .layui-header"); - pearAdmin.removeClass("light-theme"); pearAdmin.removeClass("dark-theme"); + pearAdmin.removeClass("light-theme"); + pearAdmin.removeClass("auto-theme"); pearAdmin.addClass(theme); } - this.logout = function(callback) { - logout = callback; - } - - this.message = function(callback) { - if (callback != null) { - msgInstance.click(callback); - } - } - - this.collapseSide = function() { - collapse() - } - - this.refreshThis = function() { - refresh() - } - - this.refresh = function(id) { - $("iframe[id='"+ id +"']").attr('src', $("iframe[id='"+ id +"']").attr('src')); - } - - this.addTab = function(id, title, url) { - if (isMuiltTab(config) === "true" || isMuiltTab(config) === true) { - bodyTab.addTabOnly({ - id: id, - title: title, - url: url, - icon: null, - close: true - }, 400); - } else { - return; + /** + * 设置注销逻辑 + * + * @param callback 实现 + */ + this.logout = function (callback) { + if (callback != undefined) { + logout = callback; } } - this.closeTab = function(id) { - if (isMuiltTab(config) === "true" || isMuiltTab(config) === true) { - pearTab.delTabByElem('content', id, function(currentId){ - sideMenu.selectItem(currentId); - }); + /** + * @since Pear Admin 4.0.3 + * + * 刷新当前页面 + */ + this.refresh = function () { + var refreshBtn = $(".refresh a"); + refreshBtn.addClass("layui-anim layui-anim-rotate layui-anim-loop layui-icon-loading"); + refreshBtn.removeClass("layui-icon-refresh-1"); + if (isMuiltTab(configurationCache) === "true" || isMuiltTab(configurationCache) === true) pearAdmin.instances.tabPage.refresh(true); + else pearAdmin.instances.page.refresh(true); + setTimeout(function () { + refreshBtn.removeClass("layui-anim layui-anim-rotate layui-anim-loop layui-icon-loading"); + refreshBtn.addClass("layui-icon-refresh-1"); + }, 600) + } + + /** + * @since Pear Admin 4.0.3 + * + * 切换内容页面 + * + * PS: tabPages 模式下,如果页面不存在则新增,反则仅做切换。 + */ + this.changePage = function (data) { + if (isMuiltTab(configurationCache) === "true" || isMuiltTab(configurationCache) === true) { + pearAdmin.instances.tabPage.changePage({ id: data.id, title: data.title, url: data.url, type: data.type, close: true }); } else { - return; + pearAdmin.instances.page.changePage({ href: data.url, type: data.type }); } } - this.closeCurrentTab = function() { - if (isMuiltTab(config) === "true" || isMuiltTab(config) === true) { - pearTab.delCurrentTabByElem('content', function(id){ - sideMenu.selectItem(id); - }); - } else { - return; - } - } - - this.closeOtherTab = function() { - if (isMuiltTab(config) === "true" || isMuiltTab(config) === true) { - pearTab.delOtherTabByElem('content', function(id){ - sideMenu.selectItem(id); - }); - } else { - return; - } - } - - this.closeAllTab = function() { - if (isMuiltTab(config) === "true" || isMuiltTab(config) === true) { - pearTab.delAllTabByElem('content', function(id){ - sideMenu.selectItem(id); - }); - } else { - return; - } - } - - this.changeTabTitle = function(id, title) { - pearTab.changeTabTitleById('content', id ,title); - } - - this.changeIframe = function(id, title, url) { - if (isMuiltTab(config) === "true" || isMuiltTab(config) === true) { - return; - } else { - sideMenu.selectItem(id); - bodyFrame.changePage(url, true); - } - } - - this.jump = function(id, title, url) { - if (isMuiltTab(config) === "true" || isMuiltTab(config) === true) { - pearAdmin.addTab(id, title, url) - } else { - pearAdmin.changeIframe(id, title, url) - } - } - - this.fullScreen = function() { - if ($(".fullScreen").hasClass("layui-icon-screen-restore")) { - screenFun(2).then(function() { - $(".fullScreen").eq(0).removeClass("layui-icon-screen-restore"); - }); - } else { - screenFun(1).then(function() { - $(".fullScreen").eq(0).addClass("layui-icon-screen-restore"); - }); - } - } }; - function refresh() { - var refreshA = $(".refresh a"); - refreshA.removeClass("layui-icon-refresh-1"); - refreshA.addClass("layui-anim"); - refreshA.addClass("layui-anim-rotate"); - refreshA.addClass("layui-anim-loop"); - refreshA.addClass("layui-icon-loading"); - if (isMuiltTab(config) === "true" || isMuiltTab(config) === true) bodyTab.refresh(true); - else bodyFrame.refresh(true); - setTimeout(function() { - refreshA.addClass("layui-icon-refresh-1"); - refreshA.removeClass("layui-anim"); - refreshA.removeClass("layui-anim-rotate"); - refreshA.removeClass("layui-anim-loop"); - refreshA.removeClass("layui-icon-loading"); - }, 600) - } - + /** + * @since Pear Admin 4.0 + * + * 菜单折叠 + */ function collapse() { - sideMenu.collapse(); + pearAdmin.instances.menu.collapse(); var admin = $(".pear-admin"); var left = $(".layui-icon-spread-left") var right = $(".layui-icon-shrink-right") @@ -443,246 +516,74 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm left.addClass("layui-icon-shrink-right") left.removeClass("layui-icon-spread-left") admin.removeClass("pear-mini"); - sideMenu.isCollapse = false; + pearAdmin.instances.menu.isCollapse = false; } else { right.addClass("layui-icon-spread-left") right.removeClass("layui-icon-shrink-right") admin.addClass("pear-mini"); - sideMenu.isCollapse = true; + pearAdmin.instances.menu.isCollapse = true; } } - body.on("click", ".logout", function() { - if (logout() && bodyTab) { - bodyTab.clear(); - } - }) - - body.on("click", ".collapse,.pear-cover", function() { - collapse(); - }); - - body.on("click", ".menuSearch", function () { - // 过滤菜单 - var filterHandle = function (filterData, val) { - if (!val) return []; - var filteredMenus = []; - filterData = $.extend(true, {}, filterData); - $.each(filterData, function (index, item) { - if (item.children && item.children.length) { - var children = filterHandle(item.children, val) - var obj = $.extend({}, item, { children: children }); - if (children && children.length) { - filteredMenus.push(obj); - } else if (item.title.indexOf(val) >= 0) { - item.children = []; // 父级匹配但子级不匹配,就去除子级 - filteredMenus.push($.extend({}, item)); + /** + * @since Pear Admin 4.0 + * + * 使用 admin.logout(Function) 实现注销 + * + * Promise 作为返回值类型时,泛型内容为 true 时视为注销成功,则清除 pearAdmin.instances.tabPage 缓存 + * + * 否则视为注销失败,不做任何处置。 + */ + body.on("click", ".logout", function () { + var promise = logout(); + if (promise != undefined) { + promise.then((asyncResult) => { + if (asyncResult) { + if (pearAdmin.instances.tabPage != undefined) { + pearAdmin.instances.tabPage.clear(); } - } else if (item.title.indexOf(val) >= 0) { - filteredMenus.push(item); } }) - return filteredMenus; - } - - // 树转路径 - var tiledHandle = function (data) { - var tiledMenus = []; - var treeTiled = function (data, content) { - var path = ""; - var separator = " / "; - // 上级路径 - if (!content) content = ""; - $.each(data, function (index, item) { - if (item.children && item.children.length) { - path += content + item.title + separator; - var childPath = treeTiled(item.children, path); - path += childPath; - if (!childPath) path = ""; // 重置路径 - } else { - path += content + item.title - tiledMenus.push({ path: path, info: item }); - path = ""; //重置路径 - } - }) - return path; - }; - treeTiled(data); - - return tiledMenus; + } else { + if (pearAdmin.instances.tabPage != undefined) { + pearAdmin.instances.tabPage.clear(); + } } + }) - // 创建搜索列表 - var createList = function (data) { - var _listHtml = ''; - $.each(data, function (index, item) { - _listHtml += '
          • '; - _listHtml += ' ' + item.path + ''; - _listHtml += ' '; - _listHtml += '
          • ' - }) - return _listHtml; - } - - var _html = [ - '' - ].join(''); - - layer.open({ - type: 1, - offset: "10%", - area: ['600px'], - title: false, - closeBtn: 0, - shadeClose: true, - anim: 0, - move: false, - content: _html, - success: function(layero,layeridx){ - var $layer = layero; - var $content = $(layero).children('.layui-layer-content'); - var $input = $(".menu-search-input-wrapper input"); - var $noData = $(".menu-search-no-data"); - var $list = $(".menu-search-list"); - var menuData = sideMenu.option.data; - - - $layer.css("border-radius", "6px"); - $input.off("focus").focus(); - // 搜索菜单 - $input.off("input").on("input", debounce(function(){ - var keywords = $input.val().trim(); - var filteredMenus = filterHandle(menuData, keywords); - - if(filteredMenus.length){ - var tiledMenus = tiledHandle(filteredMenus); - var listHtml = createList(tiledMenus); - $noData.css("display", "none"); - $list.html("").append(listHtml).children(":first").addClass("this") - }else{ - $list.html(""); - $noData.css("display", "flex"); - } - var currentHeight = $(".menu-search-content").outerHeight() - $layer.css("height", currentHeight); - $content.css("height", currentHeight); - }, 500) - ) - // 搜索列表点击事件 - $list.off("click").on("click", "li", function () { - var menuId = $(this).attr("smenu-id"); - var menuUrl = $(this).attr("smenu-url"); - var menuIcon = $(this).attr("smenu-icon"); - var menuTitle = $(this).attr("smenu-title"); - var menuType = $(this).attr("smenu-type"); - var openableWindow = menuType === "1" || menuType === 1; - - if(sideMenu.isCollapse){ - collapse(); - } - if (openableWindow) { - pearAdmin.jump(menuId, menuTitle, menuUrl) - } else { - sideMenu.selectItem(menuId); - } - compatible(); - layer.close(layeridx); - }) - - $list.off('mouseenter').on("mouseenter", "li", function () { - $(".menu-search-list li.this").removeClass("this"); - $(this).addClass("this"); - }).off("mouseleave").on("mouseleave", "li", function(){ - $(this).removeClass("this"); - }) - - // 监听键盘事件 - // Enter:13 Spacebar:32 UpArrow:38 DownArrow:40 Esc:27 - $(document).off("keydown").keydown(function (e) { - if (e.keyCode === 13 || e.keyCode === 32) { - e.preventDefault(); - var menuId = $(".menu-search-list li.this").attr("smenu-id"); - var menuUrl = $(".menu-search-list li.this").attr("smenu-url"); - var menuTitle = $(".menu-search-list li.this").attr("smenu-title"); - var menuType = $(".menu-search-list li.this").attr("smenu-type"); - var openableWindow = menuType === "1" || menuType === 1; - if (sideMenu.isCollapse) { - collapse(); - } - if (openableWindow) { - pearAdmin.jump(menuId, menuTitle, menuUrl) - } else { - sideMenu.selectItem(menuId); - } - compatible(); - layer.close(layeridx); - }else if(e.keyCode === 38){ - e.preventDefault(); - var prevEl = $(".menu-search-list li.this").prev(); - $(".menu-search-list li.this").removeClass("this"); - if(prevEl.length !== 0){ - prevEl.addClass("this"); - }else{ - $list.children().last().addClass("this"); - } - }else if(e.keyCode === 40){ - e.preventDefault(); - var nextEl = $(".menu-search-list li.this").next(); - $(".menu-search-list li.this").removeClass("this"); - if(nextEl.length !== 0){ - nextEl.addClass("this"); - }else{ - $list.children().first().addClass("this"); - } - }else if(e.keyCode === 27){ - e.preventDefault(); - layer.close(layeridx); - } - }) - } - }) + body.on("click", ".collapse,.pear-cover", function () { + collapse(); }); - - body.on("click", ".fullScreen", function() { + body.on("click", ".fullScreen", function () { if ($(this).hasClass("layui-icon-screen-restore")) { - fullscreen.fullClose().then(function() { + fullscreen.fullClose().then(function () { $(".fullScreen").eq(0).removeClass("layui-icon-screen-restore"); }); } else { - fullscreen.fullScreen().then(function() { + fullscreen.fullScreen().then(function () { $(".fullScreen").eq(0).addClass("layui-icon-screen-restore"); }); } }); - body.on("click", '[user-menu-id]', function() { - if (isMuiltTab(config) === "true" || isMuiltTab(config) === true) { - bodyTab.addTabOnly({ + body.on("click", '[user-menu-id]', function () { + if (isMuiltTab(configurationCache) === "true" || isMuiltTab(configurationCache) === true) { + pearAdmin.instances.tabPage.changePage({ id: $(this).attr("user-menu-id"), title: $(this).attr("user-menu-title"), url: $(this).attr("user-menu-url"), - icon: "", close: true }, 300); } else { - bodyFrame.changePage($(this).attr("user-menu-url"), true); + pearAdmin.instances.page.changePage({ + href: $(this).attr("user-menu-url"), + type: "_component" + }, true); } }); - body.on("click", ".setting", function() { + body.on("click", ".setting", function () { var menuItem = '
          • ' + @@ -724,28 +625,36 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm '' + '
          • '; + headItem += + '
          • ' + + '' + + '
            ' + + '
            ' + + '
            ' + + '
          • '; + var headHtml = '
            \n' + - '
            顶部风格
            \n' + + '
            顶栏风格
            \n' + '
            \n' + '
              \n' + headItem + '
            \n' + '
            \n' + '
            '; var moreItem = - '
            菜单
            '; + '
            菜单分割
            '; moreItem += - '
            视图
            '; + '
            多选项卡
            '; moreItem += - '
            通栏
            '; + '
            通栏布局
            '; moreItem += - '
            通色
            '; + '
            开启页脚
            '; moreItem += - '
            页脚
            '; + '
            夜间模式
            '; var moreHtml = '
            \n' + '
            更多设置
            \n' + @@ -766,7 +675,7 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm skin: 'layer-anim-right', move: false, content: menuHtml + headHtml + buildColorHtml() + moreHtml, - success: function(layero, index) { + success: function (layero, index) { form.render(); @@ -789,31 +698,31 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm $("[data-select-header='" + header + "']").addClass("layui-this"); } - $('#layui-layer-shade' + index).click(function() { + $('#layui-layer-shade' + index).click(function () { var $layero = $('#layui-layer' + index); $layero.animate({ left: $layero.offset().left + $layero.width() - }, 200, function() { + }, 200, function () { layer.close(index); }); }) - form.on('switch(control)', function(data) { + form.on('switch(control)', function (data) { localStorage.setItem("control", this.checked); window.location.reload(); }) - form.on('switch(muilt-tab)', function(data) { + form.on('switch(muilt-tab)', function (data) { localStorage.setItem("muilt-tab", this.checked); window.location.reload(); }) - form.on('switch(auto-head)', function(data) { + form.on('switch(auto-head)', function (data) { localStorage.setItem("auto-head", this.checked); - pearTheme.changeTheme(window, this.checked); + pearAdmin.changeTheme(); }) - form.on('switch(banner)', function(data) { + form.on('switch(banner)', function (data) { localStorage.setItem("theme-banner", this.checked); pearAdmin.bannerSkin(this.checked); }) @@ -823,6 +732,11 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm pearAdmin.footer(this.checked); }) + form.on('switch(dark)', function (data) { + localStorage.setItem("dark", this.checked); + pearAdmin.switchTheme(this.checked); + }) + if (localStorage.getItem('theme-banner') === 'true') { $('input[name="banner"]').attr('checked', 'checked') } else { @@ -841,24 +755,24 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm $('input[name="muilt-tab"]').removeAttr('checked') } - if (localStorage.getItem('auto-head') === 'true') { - $('input[name="auto-head"]').attr('checked', 'checked') - } else { - $('input[name="auto-head"]').removeAttr('checked') - } - if (localStorage.getItem('footer') === 'true') { $('input[name="footer"]').attr('checked', 'checked') } else { $('input[name="footer"]').removeAttr('checked') } + if (localStorage.getItem('dark') === 'true') { + $('input[name="dark"]').attr('checked', 'checked') + } else { + $('input[name="dark"]').removeAttr('checked') + } + form.render('checkbox'); } }); }); - body.on('click', '[data-select-bgcolor]', function() { + body.on('click', '[data-select-bgcolor]', function () { var theme = $(this).attr('data-select-bgcolor'); $('[data-select-bgcolor]').removeClass("layui-this"); $(this).addClass("layui-this"); @@ -866,15 +780,22 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm pearAdmin.menuSkin(theme); }); - body.on('click', '[data-select-header]', function() { - var theme = $(this).attr('data-select-header'); + body.on('click', '[data-select-header]', function () { + var headerColor = $(this).attr('data-select-header'); $('[data-select-header]').removeClass("layui-this"); $(this).addClass("layui-this"); - localStorage.setItem("theme-header", theme); - pearAdmin.headerSkin(theme); + localStorage.setItem("theme-header", headerColor); + if (headerColor == "auto-theme") { + localStorage.setItem("auto-head", true); + pearAdmin.changeTheme(); + } else { + localStorage.setItem("auto-head", false); + pearAdmin.changeTheme(); + } + pearAdmin.headerSkin(headerColor); }); - body.on('click', '.select-color-item', function() { + body.on('click', '.select-color-item', function () { $(".select-color-item").removeClass("layui-icon").removeClass("layui-icon-ok"); $(this).addClass("layui-icon").addClass("layui-icon-ok"); var colorId = $(".select-color-item.layui-icon-ok").attr("color-id"); @@ -882,33 +803,21 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm localStorage.setItem("theme-color", currentColor.id); localStorage.setItem("theme-color-color", currentColor.color); localStorage.setItem("theme-color-second", currentColor.second); - pearTheme.changeTheme(window, isAutoHead(config)); + pearAdmin.changeTheme(); }); - function applyConfig(param) { - config = param; - pearAdmin.logoRender(param); - pearAdmin.menuRender(param); - pearAdmin.bodyRender(param); - pearAdmin.themeRender(param); - pearAdmin.keepLoad(param); - if (param.header.message != false) { - pearAdmin.messageRender(param); - } - } - function getColorById(id) { var color; var flag = false; - $.each(config.colors, function(i, value) { + $.each(configurationCache.colors, function (i, value) { if (value.id === id) { color = value; flag = true; } }) - if (flag === false || config.theme.allowCustom === false) { - $.each(config.colors, function(i, value) { - if (value.id === config.theme.defaultColor) { + if (flag === false || configurationCache.theme.allowCustom === false) { + $.each(configurationCache.colors, function (i, value) { + if (value.id === configurationCache.theme.defaultColor) { color = value; } }) @@ -918,11 +827,11 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm function buildColorHtml() { var colors = ""; - $.each(config.colors, function(i, value) { + $.each(configurationCache.colors, function (i, value) { colors += ""; }) - return "
            主题配色
            " + + return "
            主题颜色
            " + colors + "
            " } @@ -944,18 +853,6 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm } } - function isAutoHead(option) { - if (option.theme.allowCustom) { - if (localStorage.getItem("auto-head") != null) { - return localStorage.getItem("auto-head"); - } else { - return option.other.autoHead; - } - } else { - return option.other.autoHead; - } - } - function isMuiltTab(option) { if (option.theme.allowCustom) { if (localStorage.getItem("muilt-tab") != null) { @@ -968,29 +865,17 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm } } - window.onresize = function() { + window.onresize = function () { if (!fullscreen.isFullscreen()) { $(".fullScreen").eq(0).removeClass("layui-icon-screen-restore"); } } - $(window).on('resize', debounce(function () { - if (sideMenu && !sideMenu.isCollapse && $(window).width() <= 768) { + $(window).on('resize', tools.debounce(function () { + if (pearAdmin.instances.menu && !pearAdmin.instances.menu.isCollapse && $(window).width() <= 768) { collapse(); } - },50)); + }, 50)); - function debounce(fn, awaitTime) { - var timerID = null - return function () { - var arg = arguments[0] - if (timerID) { - clearTimeout(timerID) - } - timerID = setTimeout(function () { - fn(arg) - }, awaitTime) - } - } exports('admin', pearAdmin); - }) + }) \ No newline at end of file diff --git a/static/system/component/pear/module/button.js b/static/system/component/pear/module/button.js index d77c18d..29555cf 100644 --- a/static/system/component/pear/module/button.js +++ b/static/system/component/pear/module/button.js @@ -1,53 +1,59 @@ -layui.define(['jquery'], function(exports) { +layui.define(['jquery'], function (exports) { "use strict"; /** + * @since Pear Admin 4.0 + * * Button component * */ var MOD_NAME = 'button', $ = layui.jquery; - var button = function(opt) { + var button = function (opt) { this.option = opt; }; - /** + /** + * @since Pear Admin 4.0 + * * Button start loading * */ - button.prototype.load = function(opt) { - - var option = { + button.prototype.load = function (opt) { + + var options = { elem: opt.elem, time: opt.time ? opt.time : false, - done: opt.done ? opt.done : function(){} + done: opt.done ? opt.done : function () { } } - var text = $(option.elem).html(); - - $(option.elem).html(""); - - $(option.elem).attr("disabled", "disabled"); - - var buttons = $(option.elem); - - if (option.time != "" || option.time !=false) { - setTimeout(function() { - $(option.elem).attr("disabled", false); - buttons.html(text); - option.done(); - }, option.time); + + var text = $(options.elem).html(); + + $(options.elem).html(""); + $(options.elem).attr("disabled", "disabled"); + + var $button = $(options.elem); + + if (options.time != "" || options.time != false) { + setTimeout(function () { + $button.attr("disabled", false); + $button.html(text); + options.done(); + }, options.time); } - option.text = text; - return new button(option); + options.text = text; + return new button(options); } - + /** + * @since Pear Admin 4.0 + * * Button stop loaded * */ - button.prototype.stop = function(success) { + button.prototype.stop = function (success) { $(this.option.elem).attr("disabled", false); $(this.option.elem).html(this.option.text); success && success(); - } + } exports(MOD_NAME, new button()); }); diff --git a/static/system/component/pear/module/extends/count.js b/static/system/component/pear/module/extends/count.js new file mode 100644 index 0000000..fed5893 --- /dev/null +++ b/static/system/component/pear/module/extends/count.js @@ -0,0 +1,37 @@ +layui.define(['jquery', 'element'], function(exports) { + "use strict"; + + var MOD_NAME = 'count', + $ = layui.jquery, + element = layui.element; + + var count = new function() { + + this.up = function(targetEle, options) { + + options = options || {}; + + var $this = document.getElementById(targetEle), + time = options.time, + finalNum = options.num, + regulator = options.regulator, + step = finalNum / (time / regulator), + count = 0.00, + initial = 0; + + var timer = setInterval(function() { + count = count + step; + if (count >= finalNum) { + clearInterval(timer); + count = finalNum; + } + var t = count.toFixed(options.bit?options.bit:0);; + if (t == initial) return; + initial = t; + $this.innerHTML = initial; + }, 30); + } + + } + exports(MOD_NAME, count); +}); \ No newline at end of file diff --git a/static/system/component/pear/module/extends/echarts.js b/static/system/component/pear/module/extends/echarts.js new file mode 100644 index 0000000..e97eb7b --- /dev/null +++ b/static/system/component/pear/module/extends/echarts.js @@ -0,0 +1,95172 @@ + +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.echarts = {})); +}(this, (function (exports) { 'use strict'; + + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + ***************************************************************************** */ + /* global Reflect, Promise */ + + var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + + function __extends(d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + } + + var Browser = (function () { + function Browser() { + this.firefox = false; + this.ie = false; + this.edge = false; + this.newEdge = false; + this.weChat = false; + } + return Browser; + }()); + var Env = (function () { + function Env() { + this.browser = new Browser(); + this.node = false; + this.wxa = false; + this.worker = false; + this.svgSupported = false; + this.touchEventsSupported = false; + this.pointerEventsSupported = false; + this.domSupported = false; + this.transformSupported = false; + this.transform3dSupported = false; + this.hasGlobalWindow = typeof window !== 'undefined'; + } + return Env; + }()); + var env = new Env(); + if (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') { + env.wxa = true; + env.touchEventsSupported = true; + } + else if (typeof document === 'undefined' && typeof self !== 'undefined') { + env.worker = true; + } + else if (typeof navigator === 'undefined') { + env.node = true; + env.svgSupported = true; + } + else { + detect(navigator.userAgent, env); + } + function detect(ua, env) { + var browser = env.browser; + var firefox = ua.match(/Firefox\/([\d.]+)/); + var ie = ua.match(/MSIE\s([\d.]+)/) + || ua.match(/Trident\/.+?rv:(([\d.]+))/); + var edge = ua.match(/Edge?\/([\d.]+)/); + var weChat = (/micromessenger/i).test(ua); + if (firefox) { + browser.firefox = true; + browser.version = firefox[1]; + } + if (ie) { + browser.ie = true; + browser.version = ie[1]; + } + if (edge) { + browser.edge = true; + browser.version = edge[1]; + browser.newEdge = +edge[1].split('.')[0] > 18; + } + if (weChat) { + browser.weChat = true; + } + env.svgSupported = typeof SVGRect !== 'undefined'; + env.touchEventsSupported = 'ontouchstart' in window && !browser.ie && !browser.edge; + env.pointerEventsSupported = 'onpointerdown' in window + && (browser.edge || (browser.ie && +browser.version >= 11)); + env.domSupported = typeof document !== 'undefined'; + var style = document.documentElement.style; + env.transform3dSupported = ((browser.ie && 'transition' in style) + || browser.edge + || (('WebKitCSSMatrix' in window) && ('m11' in new WebKitCSSMatrix())) + || 'MozPerspective' in style) + && !('OTransition' in style); + env.transformSupported = env.transform3dSupported + || (browser.ie && +browser.version >= 9); + } + + var DEFAULT_FONT_SIZE = 12; + var DEFAULT_FONT_FAMILY = 'sans-serif'; + var DEFAULT_FONT = DEFAULT_FONT_SIZE + "px " + DEFAULT_FONT_FAMILY; + var OFFSET = 20; + var SCALE = 100; + var defaultWidthMapStr = "007LLmW'55;N0500LLLLLLLLLL00NNNLzWW\\\\WQb\\0FWLg\\bWb\\WQ\\WrWWQ000CL5LLFLL0LL**F*gLLLL5F0LF\\FFF5.5N"; + function getTextWidthMap(mapStr) { + var map = {}; + if (typeof JSON === 'undefined') { + return map; + } + for (var i = 0; i < mapStr.length; i++) { + var char = String.fromCharCode(i + 32); + var size = (mapStr.charCodeAt(i) - OFFSET) / SCALE; + map[char] = size; + } + return map; + } + var DEFAULT_TEXT_WIDTH_MAP = getTextWidthMap(defaultWidthMapStr); + var platformApi = { + createCanvas: function () { + return typeof document !== 'undefined' + && document.createElement('canvas'); + }, + measureText: (function () { + var _ctx; + var _cachedFont; + return function (text, font) { + if (!_ctx) { + var canvas = platformApi.createCanvas(); + _ctx = canvas && canvas.getContext('2d'); + } + if (_ctx) { + if (_cachedFont !== font) { + _cachedFont = _ctx.font = font || DEFAULT_FONT; + } + return _ctx.measureText(text); + } + else { + text = text || ''; + font = font || DEFAULT_FONT; + var res = /^([0-9]*?)px$/.exec(font); + var fontSize = +(res && res[1]) || DEFAULT_FONT_SIZE; + var width = 0; + if (font.indexOf('mono') >= 0) { + width = fontSize * text.length; + } + else { + for (var i = 0; i < text.length; i++) { + var preCalcWidth = DEFAULT_TEXT_WIDTH_MAP[text[i]]; + width += preCalcWidth == null ? fontSize : (preCalcWidth * fontSize); + } + } + return { width: width }; + } + }; + })(), + loadImage: function (src, onload, onerror) { + var image = new Image(); + image.onload = onload; + image.onerror = onerror; + image.src = src; + return image; + } + }; + function setPlatformAPI(newPlatformApis) { + for (var key in platformApi) { + if (newPlatformApis[key]) { + platformApi[key] = newPlatformApis[key]; + } + } + } + + var BUILTIN_OBJECT = reduce([ + 'Function', + 'RegExp', + 'Date', + 'Error', + 'CanvasGradient', + 'CanvasPattern', + 'Image', + 'Canvas' + ], function (obj, val) { + obj['[object ' + val + ']'] = true; + return obj; + }, {}); + var TYPED_ARRAY = reduce([ + 'Int8', + 'Uint8', + 'Uint8Clamped', + 'Int16', + 'Uint16', + 'Int32', + 'Uint32', + 'Float32', + 'Float64' + ], function (obj, val) { + obj['[object ' + val + 'Array]'] = true; + return obj; + }, {}); + var objToString = Object.prototype.toString; + var arrayProto = Array.prototype; + var nativeForEach = arrayProto.forEach; + var nativeFilter = arrayProto.filter; + var nativeSlice = arrayProto.slice; + var nativeMap = arrayProto.map; + var ctorFunction = function () { }.constructor; + var protoFunction = ctorFunction ? ctorFunction.prototype : null; + var protoKey = '__proto__'; + var idStart = 0x0907; + function guid() { + return idStart++; + } + function logError() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + if (typeof console !== 'undefined') { + console.error.apply(console, args); + } + } + function clone(source) { + if (source == null || typeof source !== 'object') { + return source; + } + var result = source; + var typeStr = objToString.call(source); + if (typeStr === '[object Array]') { + if (!isPrimitive(source)) { + result = []; + for (var i = 0, len = source.length; i < len; i++) { + result[i] = clone(source[i]); + } + } + } + else if (TYPED_ARRAY[typeStr]) { + if (!isPrimitive(source)) { + var Ctor = source.constructor; + if (Ctor.from) { + result = Ctor.from(source); + } + else { + result = new Ctor(source.length); + for (var i = 0, len = source.length; i < len; i++) { + result[i] = source[i]; + } + } + } + } + else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) { + result = {}; + for (var key in source) { + if (source.hasOwnProperty(key) && key !== protoKey) { + result[key] = clone(source[key]); + } + } + } + return result; + } + function merge(target, source, overwrite) { + if (!isObject(source) || !isObject(target)) { + return overwrite ? clone(source) : target; + } + for (var key in source) { + if (source.hasOwnProperty(key) && key !== protoKey) { + var targetProp = target[key]; + var sourceProp = source[key]; + if (isObject(sourceProp) + && isObject(targetProp) + && !isArray(sourceProp) + && !isArray(targetProp) + && !isDom(sourceProp) + && !isDom(targetProp) + && !isBuiltInObject(sourceProp) + && !isBuiltInObject(targetProp) + && !isPrimitive(sourceProp) + && !isPrimitive(targetProp)) { + merge(targetProp, sourceProp, overwrite); + } + else if (overwrite || !(key in target)) { + target[key] = clone(source[key]); + } + } + } + return target; + } + function mergeAll(targetAndSources, overwrite) { + var result = targetAndSources[0]; + for (var i = 1, len = targetAndSources.length; i < len; i++) { + result = merge(result, targetAndSources[i], overwrite); + } + return result; + } + function extend(target, source) { + if (Object.assign) { + Object.assign(target, source); + } + else { + for (var key in source) { + if (source.hasOwnProperty(key) && key !== protoKey) { + target[key] = source[key]; + } + } + } + return target; + } + function defaults(target, source, overlay) { + var keysArr = keys(source); + for (var i = 0; i < keysArr.length; i++) { + var key = keysArr[i]; + if ((overlay ? source[key] != null : target[key] == null)) { + target[key] = source[key]; + } + } + return target; + } + var createCanvas = platformApi.createCanvas; + function indexOf(array, value) { + if (array) { + if (array.indexOf) { + return array.indexOf(value); + } + for (var i = 0, len = array.length; i < len; i++) { + if (array[i] === value) { + return i; + } + } + } + return -1; + } + function inherits(clazz, baseClazz) { + var clazzPrototype = clazz.prototype; + function F() { } + F.prototype = baseClazz.prototype; + clazz.prototype = new F(); + for (var prop in clazzPrototype) { + if (clazzPrototype.hasOwnProperty(prop)) { + clazz.prototype[prop] = clazzPrototype[prop]; + } + } + clazz.prototype.constructor = clazz; + clazz.superClass = baseClazz; + } + function mixin(target, source, override) { + target = 'prototype' in target ? target.prototype : target; + source = 'prototype' in source ? source.prototype : source; + if (Object.getOwnPropertyNames) { + var keyList = Object.getOwnPropertyNames(source); + for (var i = 0; i < keyList.length; i++) { + var key = keyList[i]; + if (key !== 'constructor') { + if ((override ? source[key] != null : target[key] == null)) { + target[key] = source[key]; + } + } + } + } + else { + defaults(target, source, override); + } + } + function isArrayLike(data) { + if (!data) { + return false; + } + if (typeof data === 'string') { + return false; + } + return typeof data.length === 'number'; + } + function each(arr, cb, context) { + if (!(arr && cb)) { + return; + } + if (arr.forEach && arr.forEach === nativeForEach) { + arr.forEach(cb, context); + } + else if (arr.length === +arr.length) { + for (var i = 0, len = arr.length; i < len; i++) { + cb.call(context, arr[i], i, arr); + } + } + else { + for (var key in arr) { + if (arr.hasOwnProperty(key)) { + cb.call(context, arr[key], key, arr); + } + } + } + } + function map(arr, cb, context) { + if (!arr) { + return []; + } + if (!cb) { + return slice(arr); + } + if (arr.map && arr.map === nativeMap) { + return arr.map(cb, context); + } + else { + var result = []; + for (var i = 0, len = arr.length; i < len; i++) { + result.push(cb.call(context, arr[i], i, arr)); + } + return result; + } + } + function reduce(arr, cb, memo, context) { + if (!(arr && cb)) { + return; + } + for (var i = 0, len = arr.length; i < len; i++) { + memo = cb.call(context, memo, arr[i], i, arr); + } + return memo; + } + function filter(arr, cb, context) { + if (!arr) { + return []; + } + if (!cb) { + return slice(arr); + } + if (arr.filter && arr.filter === nativeFilter) { + return arr.filter(cb, context); + } + else { + var result = []; + for (var i = 0, len = arr.length; i < len; i++) { + if (cb.call(context, arr[i], i, arr)) { + result.push(arr[i]); + } + } + return result; + } + } + function find(arr, cb, context) { + if (!(arr && cb)) { + return; + } + for (var i = 0, len = arr.length; i < len; i++) { + if (cb.call(context, arr[i], i, arr)) { + return arr[i]; + } + } + } + function keys(obj) { + if (!obj) { + return []; + } + if (Object.keys) { + return Object.keys(obj); + } + var keyList = []; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + keyList.push(key); + } + } + return keyList; + } + function bindPolyfill(func, context) { + var args = []; + for (var _i = 2; _i < arguments.length; _i++) { + args[_i - 2] = arguments[_i]; + } + return function () { + return func.apply(context, args.concat(nativeSlice.call(arguments))); + }; + } + var bind = (protoFunction && isFunction(protoFunction.bind)) + ? protoFunction.call.bind(protoFunction.bind) + : bindPolyfill; + function curry(func) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + return function () { + return func.apply(this, args.concat(nativeSlice.call(arguments))); + }; + } + function isArray(value) { + if (Array.isArray) { + return Array.isArray(value); + } + return objToString.call(value) === '[object Array]'; + } + function isFunction(value) { + return typeof value === 'function'; + } + function isString(value) { + return typeof value === 'string'; + } + function isStringSafe(value) { + return objToString.call(value) === '[object String]'; + } + function isNumber(value) { + return typeof value === 'number'; + } + function isObject(value) { + var type = typeof value; + return type === 'function' || (!!value && type === 'object'); + } + function isBuiltInObject(value) { + return !!BUILTIN_OBJECT[objToString.call(value)]; + } + function isTypedArray(value) { + return !!TYPED_ARRAY[objToString.call(value)]; + } + function isDom(value) { + return typeof value === 'object' + && typeof value.nodeType === 'number' + && typeof value.ownerDocument === 'object'; + } + function isGradientObject(value) { + return value.colorStops != null; + } + function isImagePatternObject(value) { + return value.image != null; + } + function isRegExp(value) { + return objToString.call(value) === '[object RegExp]'; + } + function eqNaN(value) { + return value !== value; + } + function retrieve() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + for (var i = 0, len = args.length; i < len; i++) { + if (args[i] != null) { + return args[i]; + } + } + } + function retrieve2(value0, value1) { + return value0 != null + ? value0 + : value1; + } + function retrieve3(value0, value1, value2) { + return value0 != null + ? value0 + : value1 != null + ? value1 + : value2; + } + function slice(arr) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + return nativeSlice.apply(arr, args); + } + function normalizeCssArray(val) { + if (typeof (val) === 'number') { + return [val, val, val, val]; + } + var len = val.length; + if (len === 2) { + return [val[0], val[1], val[0], val[1]]; + } + else if (len === 3) { + return [val[0], val[1], val[2], val[1]]; + } + return val; + } + function assert(condition, message) { + if (!condition) { + throw new Error(message); + } + } + function trim(str) { + if (str == null) { + return null; + } + else if (typeof str.trim === 'function') { + return str.trim(); + } + else { + return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); + } + } + var primitiveKey = '__ec_primitive__'; + function setAsPrimitive(obj) { + obj[primitiveKey] = true; + } + function isPrimitive(obj) { + return obj[primitiveKey]; + } + var HashMap = (function () { + function HashMap(obj) { + this.data = {}; + var isArr = isArray(obj); + this.data = {}; + var thisMap = this; + (obj instanceof HashMap) + ? obj.each(visit) + : (obj && each(obj, visit)); + function visit(value, key) { + isArr ? thisMap.set(value, key) : thisMap.set(key, value); + } + } + HashMap.prototype.get = function (key) { + return this.data.hasOwnProperty(key) ? this.data[key] : null; + }; + HashMap.prototype.set = function (key, value) { + return (this.data[key] = value); + }; + HashMap.prototype.each = function (cb, context) { + for (var key in this.data) { + if (this.data.hasOwnProperty(key)) { + cb.call(context, this.data[key], key); + } + } + }; + HashMap.prototype.keys = function () { + return keys(this.data); + }; + HashMap.prototype.removeKey = function (key) { + delete this.data[key]; + }; + return HashMap; + }()); + function createHashMap(obj) { + return new HashMap(obj); + } + function concatArray(a, b) { + var newArray = new a.constructor(a.length + b.length); + for (var i = 0; i < a.length; i++) { + newArray[i] = a[i]; + } + var offset = a.length; + for (var i = 0; i < b.length; i++) { + newArray[i + offset] = b[i]; + } + return newArray; + } + function createObject(proto, properties) { + var obj; + if (Object.create) { + obj = Object.create(proto); + } + else { + var StyleCtor = function () { }; + StyleCtor.prototype = proto; + obj = new StyleCtor(); + } + if (properties) { + extend(obj, properties); + } + return obj; + } + function disableUserSelect(dom) { + var domStyle = dom.style; + domStyle.webkitUserSelect = 'none'; + domStyle.userSelect = 'none'; + domStyle.webkitTapHighlightColor = 'rgba(0,0,0,0)'; + domStyle['-webkit-touch-callout'] = 'none'; + } + function hasOwn(own, prop) { + return own.hasOwnProperty(prop); + } + function noop() { } + var RADIAN_TO_DEGREE = 180 / Math.PI; + + var util = /*#__PURE__*/Object.freeze({ + __proto__: null, + guid: guid, + logError: logError, + clone: clone, + merge: merge, + mergeAll: mergeAll, + extend: extend, + defaults: defaults, + createCanvas: createCanvas, + indexOf: indexOf, + inherits: inherits, + mixin: mixin, + isArrayLike: isArrayLike, + each: each, + map: map, + reduce: reduce, + filter: filter, + find: find, + keys: keys, + bind: bind, + curry: curry, + isArray: isArray, + isFunction: isFunction, + isString: isString, + isStringSafe: isStringSafe, + isNumber: isNumber, + isObject: isObject, + isBuiltInObject: isBuiltInObject, + isTypedArray: isTypedArray, + isDom: isDom, + isGradientObject: isGradientObject, + isImagePatternObject: isImagePatternObject, + isRegExp: isRegExp, + eqNaN: eqNaN, + retrieve: retrieve, + retrieve2: retrieve2, + retrieve3: retrieve3, + slice: slice, + normalizeCssArray: normalizeCssArray, + assert: assert, + trim: trim, + setAsPrimitive: setAsPrimitive, + isPrimitive: isPrimitive, + HashMap: HashMap, + createHashMap: createHashMap, + concatArray: concatArray, + createObject: createObject, + disableUserSelect: disableUserSelect, + hasOwn: hasOwn, + noop: noop, + RADIAN_TO_DEGREE: RADIAN_TO_DEGREE + }); + + function create(x, y) { + if (x == null) { + x = 0; + } + if (y == null) { + y = 0; + } + return [x, y]; + } + function copy(out, v) { + out[0] = v[0]; + out[1] = v[1]; + return out; + } + function clone$1(v) { + return [v[0], v[1]]; + } + function set(out, a, b) { + out[0] = a; + out[1] = b; + return out; + } + function add(out, v1, v2) { + out[0] = v1[0] + v2[0]; + out[1] = v1[1] + v2[1]; + return out; + } + function scaleAndAdd(out, v1, v2, a) { + out[0] = v1[0] + v2[0] * a; + out[1] = v1[1] + v2[1] * a; + return out; + } + function sub(out, v1, v2) { + out[0] = v1[0] - v2[0]; + out[1] = v1[1] - v2[1]; + return out; + } + function len(v) { + return Math.sqrt(lenSquare(v)); + } + var length = len; + function lenSquare(v) { + return v[0] * v[0] + v[1] * v[1]; + } + var lengthSquare = lenSquare; + function mul(out, v1, v2) { + out[0] = v1[0] * v2[0]; + out[1] = v1[1] * v2[1]; + return out; + } + function div(out, v1, v2) { + out[0] = v1[0] / v2[0]; + out[1] = v1[1] / v2[1]; + return out; + } + function dot(v1, v2) { + return v1[0] * v2[0] + v1[1] * v2[1]; + } + function scale(out, v, s) { + out[0] = v[0] * s; + out[1] = v[1] * s; + return out; + } + function normalize(out, v) { + var d = len(v); + if (d === 0) { + out[0] = 0; + out[1] = 0; + } + else { + out[0] = v[0] / d; + out[1] = v[1] / d; + } + return out; + } + function distance(v1, v2) { + return Math.sqrt((v1[0] - v2[0]) * (v1[0] - v2[0]) + + (v1[1] - v2[1]) * (v1[1] - v2[1])); + } + var dist = distance; + function distanceSquare(v1, v2) { + return (v1[0] - v2[0]) * (v1[0] - v2[0]) + + (v1[1] - v2[1]) * (v1[1] - v2[1]); + } + var distSquare = distanceSquare; + function negate(out, v) { + out[0] = -v[0]; + out[1] = -v[1]; + return out; + } + function lerp(out, v1, v2, t) { + out[0] = v1[0] + t * (v2[0] - v1[0]); + out[1] = v1[1] + t * (v2[1] - v1[1]); + return out; + } + function applyTransform(out, v, m) { + var x = v[0]; + var y = v[1]; + out[0] = m[0] * x + m[2] * y + m[4]; + out[1] = m[1] * x + m[3] * y + m[5]; + return out; + } + function min(out, v1, v2) { + out[0] = Math.min(v1[0], v2[0]); + out[1] = Math.min(v1[1], v2[1]); + return out; + } + function max(out, v1, v2) { + out[0] = Math.max(v1[0], v2[0]); + out[1] = Math.max(v1[1], v2[1]); + return out; + } + + var vector = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create, + copy: copy, + clone: clone$1, + set: set, + add: add, + scaleAndAdd: scaleAndAdd, + sub: sub, + len: len, + length: length, + lenSquare: lenSquare, + lengthSquare: lengthSquare, + mul: mul, + div: div, + dot: dot, + scale: scale, + normalize: normalize, + distance: distance, + dist: dist, + distanceSquare: distanceSquare, + distSquare: distSquare, + negate: negate, + lerp: lerp, + applyTransform: applyTransform, + min: min, + max: max + }); + + var Param = (function () { + function Param(target, e) { + this.target = target; + this.topTarget = e && e.topTarget; + } + return Param; + }()); + var Draggable = (function () { + function Draggable(handler) { + this.handler = handler; + handler.on('mousedown', this._dragStart, this); + handler.on('mousemove', this._drag, this); + handler.on('mouseup', this._dragEnd, this); + } + Draggable.prototype._dragStart = function (e) { + var draggingTarget = e.target; + while (draggingTarget && !draggingTarget.draggable) { + draggingTarget = draggingTarget.parent || draggingTarget.__hostTarget; + } + if (draggingTarget) { + this._draggingTarget = draggingTarget; + draggingTarget.dragging = true; + this._x = e.offsetX; + this._y = e.offsetY; + this.handler.dispatchToElement(new Param(draggingTarget, e), 'dragstart', e.event); + } + }; + Draggable.prototype._drag = function (e) { + var draggingTarget = this._draggingTarget; + if (draggingTarget) { + var x = e.offsetX; + var y = e.offsetY; + var dx = x - this._x; + var dy = y - this._y; + this._x = x; + this._y = y; + draggingTarget.drift(dx, dy, e); + this.handler.dispatchToElement(new Param(draggingTarget, e), 'drag', e.event); + var dropTarget = this.handler.findHover(x, y, draggingTarget).target; + var lastDropTarget = this._dropTarget; + this._dropTarget = dropTarget; + if (draggingTarget !== dropTarget) { + if (lastDropTarget && dropTarget !== lastDropTarget) { + this.handler.dispatchToElement(new Param(lastDropTarget, e), 'dragleave', e.event); + } + if (dropTarget && dropTarget !== lastDropTarget) { + this.handler.dispatchToElement(new Param(dropTarget, e), 'dragenter', e.event); + } + } + } + }; + Draggable.prototype._dragEnd = function (e) { + var draggingTarget = this._draggingTarget; + if (draggingTarget) { + draggingTarget.dragging = false; + } + this.handler.dispatchToElement(new Param(draggingTarget, e), 'dragend', e.event); + if (this._dropTarget) { + this.handler.dispatchToElement(new Param(this._dropTarget, e), 'drop', e.event); + } + this._draggingTarget = null; + this._dropTarget = null; + }; + return Draggable; + }()); + + var Eventful = (function () { + function Eventful(eventProcessors) { + if (eventProcessors) { + this._$eventProcessor = eventProcessors; + } + } + Eventful.prototype.on = function (event, query, handler, context) { + if (!this._$handlers) { + this._$handlers = {}; + } + var _h = this._$handlers; + if (typeof query === 'function') { + context = handler; + handler = query; + query = null; + } + if (!handler || !event) { + return this; + } + var eventProcessor = this._$eventProcessor; + if (query != null && eventProcessor && eventProcessor.normalizeQuery) { + query = eventProcessor.normalizeQuery(query); + } + if (!_h[event]) { + _h[event] = []; + } + for (var i = 0; i < _h[event].length; i++) { + if (_h[event][i].h === handler) { + return this; + } + } + var wrap = { + h: handler, + query: query, + ctx: (context || this), + callAtLast: handler.zrEventfulCallAtLast + }; + var lastIndex = _h[event].length - 1; + var lastWrap = _h[event][lastIndex]; + (lastWrap && lastWrap.callAtLast) + ? _h[event].splice(lastIndex, 0, wrap) + : _h[event].push(wrap); + return this; + }; + Eventful.prototype.isSilent = function (eventName) { + var _h = this._$handlers; + return !_h || !_h[eventName] || !_h[eventName].length; + }; + Eventful.prototype.off = function (eventType, handler) { + var _h = this._$handlers; + if (!_h) { + return this; + } + if (!eventType) { + this._$handlers = {}; + return this; + } + if (handler) { + if (_h[eventType]) { + var newList = []; + for (var i = 0, l = _h[eventType].length; i < l; i++) { + if (_h[eventType][i].h !== handler) { + newList.push(_h[eventType][i]); + } + } + _h[eventType] = newList; + } + if (_h[eventType] && _h[eventType].length === 0) { + delete _h[eventType]; + } + } + else { + delete _h[eventType]; + } + return this; + }; + Eventful.prototype.trigger = function (eventType) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + if (!this._$handlers) { + return this; + } + var _h = this._$handlers[eventType]; + var eventProcessor = this._$eventProcessor; + if (_h) { + var argLen = args.length; + var len = _h.length; + for (var i = 0; i < len; i++) { + var hItem = _h[i]; + if (eventProcessor + && eventProcessor.filter + && hItem.query != null + && !eventProcessor.filter(eventType, hItem.query)) { + continue; + } + switch (argLen) { + case 0: + hItem.h.call(hItem.ctx); + break; + case 1: + hItem.h.call(hItem.ctx, args[0]); + break; + case 2: + hItem.h.call(hItem.ctx, args[0], args[1]); + break; + default: + hItem.h.apply(hItem.ctx, args); + break; + } + } + } + eventProcessor && eventProcessor.afterTrigger + && eventProcessor.afterTrigger(eventType); + return this; + }; + Eventful.prototype.triggerWithContext = function (type) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + if (!this._$handlers) { + return this; + } + var _h = this._$handlers[type]; + var eventProcessor = this._$eventProcessor; + if (_h) { + var argLen = args.length; + var ctx = args[argLen - 1]; + var len = _h.length; + for (var i = 0; i < len; i++) { + var hItem = _h[i]; + if (eventProcessor + && eventProcessor.filter + && hItem.query != null + && !eventProcessor.filter(type, hItem.query)) { + continue; + } + switch (argLen) { + case 0: + hItem.h.call(ctx); + break; + case 1: + hItem.h.call(ctx, args[0]); + break; + case 2: + hItem.h.call(ctx, args[0], args[1]); + break; + default: + hItem.h.apply(ctx, args.slice(1, argLen - 1)); + break; + } + } + } + eventProcessor && eventProcessor.afterTrigger + && eventProcessor.afterTrigger(type); + return this; + }; + return Eventful; + }()); + + var LN2 = Math.log(2); + function determinant(rows, rank, rowStart, rowMask, colMask, detCache) { + var cacheKey = rowMask + '-' + colMask; + var fullRank = rows.length; + if (detCache.hasOwnProperty(cacheKey)) { + return detCache[cacheKey]; + } + if (rank === 1) { + var colStart = Math.round(Math.log(((1 << fullRank) - 1) & ~colMask) / LN2); + return rows[rowStart][colStart]; + } + var subRowMask = rowMask | (1 << rowStart); + var subRowStart = rowStart + 1; + while (rowMask & (1 << subRowStart)) { + subRowStart++; + } + var sum = 0; + for (var j = 0, colLocalIdx = 0; j < fullRank; j++) { + var colTag = 1 << j; + if (!(colTag & colMask)) { + sum += (colLocalIdx % 2 ? -1 : 1) * rows[rowStart][j] + * determinant(rows, rank - 1, subRowStart, subRowMask, colMask | colTag, detCache); + colLocalIdx++; + } + } + detCache[cacheKey] = sum; + return sum; + } + function buildTransformer(src, dest) { + var mA = [ + [src[0], src[1], 1, 0, 0, 0, -dest[0] * src[0], -dest[0] * src[1]], + [0, 0, 0, src[0], src[1], 1, -dest[1] * src[0], -dest[1] * src[1]], + [src[2], src[3], 1, 0, 0, 0, -dest[2] * src[2], -dest[2] * src[3]], + [0, 0, 0, src[2], src[3], 1, -dest[3] * src[2], -dest[3] * src[3]], + [src[4], src[5], 1, 0, 0, 0, -dest[4] * src[4], -dest[4] * src[5]], + [0, 0, 0, src[4], src[5], 1, -dest[5] * src[4], -dest[5] * src[5]], + [src[6], src[7], 1, 0, 0, 0, -dest[6] * src[6], -dest[6] * src[7]], + [0, 0, 0, src[6], src[7], 1, -dest[7] * src[6], -dest[7] * src[7]] + ]; + var detCache = {}; + var det = determinant(mA, 8, 0, 0, 0, detCache); + if (det === 0) { + return; + } + var vh = []; + for (var i = 0; i < 8; i++) { + for (var j = 0; j < 8; j++) { + vh[j] == null && (vh[j] = 0); + vh[j] += ((i + j) % 2 ? -1 : 1) + * determinant(mA, 7, i === 0 ? 1 : 0, 1 << i, 1 << j, detCache) + / det * dest[i]; + } + } + return function (out, srcPointX, srcPointY) { + var pk = srcPointX * vh[6] + srcPointY * vh[7] + 1; + out[0] = (srcPointX * vh[0] + srcPointY * vh[1] + vh[2]) / pk; + out[1] = (srcPointX * vh[3] + srcPointY * vh[4] + vh[5]) / pk; + }; + } + + var EVENT_SAVED_PROP = '___zrEVENTSAVED'; + var _calcOut = []; + function transformLocalCoord(out, elFrom, elTarget, inX, inY) { + return transformCoordWithViewport(_calcOut, elFrom, inX, inY, true) + && transformCoordWithViewport(out, elTarget, _calcOut[0], _calcOut[1]); + } + function transformCoordWithViewport(out, el, inX, inY, inverse) { + if (el.getBoundingClientRect && env.domSupported && !isCanvasEl(el)) { + var saved = el[EVENT_SAVED_PROP] || (el[EVENT_SAVED_PROP] = {}); + var markers = prepareCoordMarkers(el, saved); + var transformer = preparePointerTransformer(markers, saved, inverse); + if (transformer) { + transformer(out, inX, inY); + return true; + } + } + return false; + } + function prepareCoordMarkers(el, saved) { + var markers = saved.markers; + if (markers) { + return markers; + } + markers = saved.markers = []; + var propLR = ['left', 'right']; + var propTB = ['top', 'bottom']; + for (var i = 0; i < 4; i++) { + var marker = document.createElement('div'); + var stl = marker.style; + var idxLR = i % 2; + var idxTB = (i >> 1) % 2; + stl.cssText = [ + 'position: absolute', + 'visibility: hidden', + 'padding: 0', + 'margin: 0', + 'border-width: 0', + 'user-select: none', + 'width:0', + 'height:0', + propLR[idxLR] + ':0', + propTB[idxTB] + ':0', + propLR[1 - idxLR] + ':auto', + propTB[1 - idxTB] + ':auto', + '' + ].join('!important;'); + el.appendChild(marker); + markers.push(marker); + } + return markers; + } + function preparePointerTransformer(markers, saved, inverse) { + var transformerName = inverse ? 'invTrans' : 'trans'; + var transformer = saved[transformerName]; + var oldSrcCoords = saved.srcCoords; + var srcCoords = []; + var destCoords = []; + var oldCoordTheSame = true; + for (var i = 0; i < 4; i++) { + var rect = markers[i].getBoundingClientRect(); + var ii = 2 * i; + var x = rect.left; + var y = rect.top; + srcCoords.push(x, y); + oldCoordTheSame = oldCoordTheSame && oldSrcCoords && x === oldSrcCoords[ii] && y === oldSrcCoords[ii + 1]; + destCoords.push(markers[i].offsetLeft, markers[i].offsetTop); + } + return (oldCoordTheSame && transformer) + ? transformer + : (saved.srcCoords = srcCoords, + saved[transformerName] = inverse + ? buildTransformer(destCoords, srcCoords) + : buildTransformer(srcCoords, destCoords)); + } + function isCanvasEl(el) { + return el.nodeName.toUpperCase() === 'CANVAS'; + } + + var MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/; + var _calcOut$1 = []; + var firefoxNotSupportOffsetXY = env.browser.firefox + && +env.browser.version.split('.')[0] < 39; + function clientToLocal(el, e, out, calculate) { + out = out || {}; + if (calculate) { + calculateZrXY(el, e, out); + } + else if (firefoxNotSupportOffsetXY + && e.layerX != null + && e.layerX !== e.offsetX) { + out.zrX = e.layerX; + out.zrY = e.layerY; + } + else if (e.offsetX != null) { + out.zrX = e.offsetX; + out.zrY = e.offsetY; + } + else { + calculateZrXY(el, e, out); + } + return out; + } + function calculateZrXY(el, e, out) { + if (env.domSupported && el.getBoundingClientRect) { + var ex = e.clientX; + var ey = e.clientY; + if (isCanvasEl(el)) { + var box = el.getBoundingClientRect(); + out.zrX = ex - box.left; + out.zrY = ey - box.top; + return; + } + else { + if (transformCoordWithViewport(_calcOut$1, el, ex, ey)) { + out.zrX = _calcOut$1[0]; + out.zrY = _calcOut$1[1]; + return; + } + } + } + out.zrX = out.zrY = 0; + } + function getNativeEvent(e) { + return e + || window.event; + } + function normalizeEvent(el, e, calculate) { + e = getNativeEvent(e); + if (e.zrX != null) { + return e; + } + var eventType = e.type; + var isTouch = eventType && eventType.indexOf('touch') >= 0; + if (!isTouch) { + clientToLocal(el, e, e, calculate); + var wheelDelta = getWheelDeltaMayPolyfill(e); + e.zrDelta = wheelDelta ? wheelDelta / 120 : -(e.detail || 0) / 3; + } + else { + var touch = eventType !== 'touchend' + ? e.targetTouches[0] + : e.changedTouches[0]; + touch && clientToLocal(el, touch, e, calculate); + } + var button = e.button; + if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) { + e.which = (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0))); + } + return e; + } + function getWheelDeltaMayPolyfill(e) { + var rawWheelDelta = e.wheelDelta; + if (rawWheelDelta) { + return rawWheelDelta; + } + var deltaX = e.deltaX; + var deltaY = e.deltaY; + if (deltaX == null || deltaY == null) { + return rawWheelDelta; + } + var delta = deltaY !== 0 ? Math.abs(deltaY) : Math.abs(deltaX); + var sign = deltaY > 0 ? -1 + : deltaY < 0 ? 1 + : deltaX > 0 ? -1 + : 1; + return 3 * delta * sign; + } + function addEventListener(el, name, handler, opt) { + el.addEventListener(name, handler, opt); + } + function removeEventListener(el, name, handler, opt) { + el.removeEventListener(name, handler, opt); + } + var stop = function (e) { + e.preventDefault(); + e.stopPropagation(); + e.cancelBubble = true; + }; + function isMiddleOrRightButtonOnMouseUpDown(e) { + return e.which === 2 || e.which === 3; + } + + var GestureMgr = (function () { + function GestureMgr() { + this._track = []; + } + GestureMgr.prototype.recognize = function (event, target, root) { + this._doTrack(event, target, root); + return this._recognize(event); + }; + GestureMgr.prototype.clear = function () { + this._track.length = 0; + return this; + }; + GestureMgr.prototype._doTrack = function (event, target, root) { + var touches = event.touches; + if (!touches) { + return; + } + var trackItem = { + points: [], + touches: [], + target: target, + event: event + }; + for (var i = 0, len = touches.length; i < len; i++) { + var touch = touches[i]; + var pos = clientToLocal(root, touch, {}); + trackItem.points.push([pos.zrX, pos.zrY]); + trackItem.touches.push(touch); + } + this._track.push(trackItem); + }; + GestureMgr.prototype._recognize = function (event) { + for (var eventName in recognizers) { + if (recognizers.hasOwnProperty(eventName)) { + var gestureInfo = recognizers[eventName](this._track, event); + if (gestureInfo) { + return gestureInfo; + } + } + } + }; + return GestureMgr; + }()); + function dist$1(pointPair) { + var dx = pointPair[1][0] - pointPair[0][0]; + var dy = pointPair[1][1] - pointPair[0][1]; + return Math.sqrt(dx * dx + dy * dy); + } + function center(pointPair) { + return [ + (pointPair[0][0] + pointPair[1][0]) / 2, + (pointPair[0][1] + pointPair[1][1]) / 2 + ]; + } + var recognizers = { + pinch: function (tracks, event) { + var trackLen = tracks.length; + if (!trackLen) { + return; + } + var pinchEnd = (tracks[trackLen - 1] || {}).points; + var pinchPre = (tracks[trackLen - 2] || {}).points || pinchEnd; + if (pinchPre + && pinchPre.length > 1 + && pinchEnd + && pinchEnd.length > 1) { + var pinchScale = dist$1(pinchEnd) / dist$1(pinchPre); + !isFinite(pinchScale) && (pinchScale = 1); + event.pinchScale = pinchScale; + var pinchCenter = center(pinchEnd); + event.pinchX = pinchCenter[0]; + event.pinchY = pinchCenter[1]; + return { + type: 'pinch', + target: tracks[0].target, + event: event + }; + } + } + }; + + var SILENT = 'silent'; + function makeEventPacket(eveType, targetInfo, event) { + return { + type: eveType, + event: event, + target: targetInfo.target, + topTarget: targetInfo.topTarget, + cancelBubble: false, + offsetX: event.zrX, + offsetY: event.zrY, + gestureEvent: event.gestureEvent, + pinchX: event.pinchX, + pinchY: event.pinchY, + pinchScale: event.pinchScale, + wheelDelta: event.zrDelta, + zrByTouch: event.zrByTouch, + which: event.which, + stop: stopEvent + }; + } + function stopEvent() { + stop(this.event); + } + var EmptyProxy = (function (_super) { + __extends(EmptyProxy, _super); + function EmptyProxy() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.handler = null; + return _this; + } + EmptyProxy.prototype.dispose = function () { }; + EmptyProxy.prototype.setCursor = function () { }; + return EmptyProxy; + }(Eventful)); + var HoveredResult = (function () { + function HoveredResult(x, y) { + this.x = x; + this.y = y; + } + return HoveredResult; + }()); + var handlerNames = [ + 'click', 'dblclick', 'mousewheel', 'mouseout', + 'mouseup', 'mousedown', 'mousemove', 'contextmenu' + ]; + var Handler = (function (_super) { + __extends(Handler, _super); + function Handler(storage, painter, proxy, painterRoot) { + var _this = _super.call(this) || this; + _this._hovered = new HoveredResult(0, 0); + _this.storage = storage; + _this.painter = painter; + _this.painterRoot = painterRoot; + proxy = proxy || new EmptyProxy(); + _this.proxy = null; + _this.setHandlerProxy(proxy); + _this._draggingMgr = new Draggable(_this); + return _this; + } + Handler.prototype.setHandlerProxy = function (proxy) { + if (this.proxy) { + this.proxy.dispose(); + } + if (proxy) { + each(handlerNames, function (name) { + proxy.on && proxy.on(name, this[name], this); + }, this); + proxy.handler = this; + } + this.proxy = proxy; + }; + Handler.prototype.mousemove = function (event) { + var x = event.zrX; + var y = event.zrY; + var isOutside = isOutsideBoundary(this, x, y); + var lastHovered = this._hovered; + var lastHoveredTarget = lastHovered.target; + if (lastHoveredTarget && !lastHoveredTarget.__zr) { + lastHovered = this.findHover(lastHovered.x, lastHovered.y); + lastHoveredTarget = lastHovered.target; + } + var hovered = this._hovered = isOutside ? new HoveredResult(x, y) : this.findHover(x, y); + var hoveredTarget = hovered.target; + var proxy = this.proxy; + proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default'); + if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) { + this.dispatchToElement(lastHovered, 'mouseout', event); + } + this.dispatchToElement(hovered, 'mousemove', event); + if (hoveredTarget && hoveredTarget !== lastHoveredTarget) { + this.dispatchToElement(hovered, 'mouseover', event); + } + }; + Handler.prototype.mouseout = function (event) { + var eventControl = event.zrEventControl; + if (eventControl !== 'only_globalout') { + this.dispatchToElement(this._hovered, 'mouseout', event); + } + if (eventControl !== 'no_globalout') { + this.trigger('globalout', { type: 'globalout', event: event }); + } + }; + Handler.prototype.resize = function () { + this._hovered = new HoveredResult(0, 0); + }; + Handler.prototype.dispatch = function (eventName, eventArgs) { + var handler = this[eventName]; + handler && handler.call(this, eventArgs); + }; + Handler.prototype.dispose = function () { + this.proxy.dispose(); + this.storage = null; + this.proxy = null; + this.painter = null; + }; + Handler.prototype.setCursorStyle = function (cursorStyle) { + var proxy = this.proxy; + proxy.setCursor && proxy.setCursor(cursorStyle); + }; + Handler.prototype.dispatchToElement = function (targetInfo, eventName, event) { + targetInfo = targetInfo || {}; + var el = targetInfo.target; + if (el && el.silent) { + return; + } + var eventKey = ('on' + eventName); + var eventPacket = makeEventPacket(eventName, targetInfo, event); + while (el) { + el[eventKey] + && (eventPacket.cancelBubble = !!el[eventKey].call(el, eventPacket)); + el.trigger(eventName, eventPacket); + el = el.__hostTarget ? el.__hostTarget : el.parent; + if (eventPacket.cancelBubble) { + break; + } + } + if (!eventPacket.cancelBubble) { + this.trigger(eventName, eventPacket); + if (this.painter && this.painter.eachOtherLayer) { + this.painter.eachOtherLayer(function (layer) { + if (typeof (layer[eventKey]) === 'function') { + layer[eventKey].call(layer, eventPacket); + } + if (layer.trigger) { + layer.trigger(eventName, eventPacket); + } + }); + } + } + }; + Handler.prototype.findHover = function (x, y, exclude) { + var list = this.storage.getDisplayList(); + var out = new HoveredResult(x, y); + for (var i = list.length - 1; i >= 0; i--) { + var hoverCheckResult = void 0; + if (list[i] !== exclude + && !list[i].ignore + && (hoverCheckResult = isHover(list[i], x, y))) { + !out.topTarget && (out.topTarget = list[i]); + if (hoverCheckResult !== SILENT) { + out.target = list[i]; + break; + } + } + } + return out; + }; + Handler.prototype.processGesture = function (event, stage) { + if (!this._gestureMgr) { + this._gestureMgr = new GestureMgr(); + } + var gestureMgr = this._gestureMgr; + stage === 'start' && gestureMgr.clear(); + var gestureInfo = gestureMgr.recognize(event, this.findHover(event.zrX, event.zrY, null).target, this.proxy.dom); + stage === 'end' && gestureMgr.clear(); + if (gestureInfo) { + var type = gestureInfo.type; + event.gestureEvent = type; + var res = new HoveredResult(); + res.target = gestureInfo.target; + this.dispatchToElement(res, type, gestureInfo.event); + } + }; + return Handler; + }(Eventful)); + each(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) { + Handler.prototype[name] = function (event) { + var x = event.zrX; + var y = event.zrY; + var isOutside = isOutsideBoundary(this, x, y); + var hovered; + var hoveredTarget; + if (name !== 'mouseup' || !isOutside) { + hovered = this.findHover(x, y); + hoveredTarget = hovered.target; + } + if (name === 'mousedown') { + this._downEl = hoveredTarget; + this._downPoint = [event.zrX, event.zrY]; + this._upEl = hoveredTarget; + } + else if (name === 'mouseup') { + this._upEl = hoveredTarget; + } + else if (name === 'click') { + if (this._downEl !== this._upEl + || !this._downPoint + || dist(this._downPoint, [event.zrX, event.zrY]) > 4) { + return; + } + this._downPoint = null; + } + this.dispatchToElement(hovered, name, event); + }; + }); + function isHover(displayable, x, y) { + if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) { + var el = displayable; + var isSilent = void 0; + var ignoreClip = false; + while (el) { + if (el.ignoreClip) { + ignoreClip = true; + } + if (!ignoreClip) { + var clipPath = el.getClipPath(); + if (clipPath && !clipPath.contain(x, y)) { + return false; + } + if (el.silent) { + isSilent = true; + } + } + var hostEl = el.__hostTarget; + el = hostEl ? hostEl : el.parent; + } + return isSilent ? SILENT : true; + } + return false; + } + function isOutsideBoundary(handlerInstance, x, y) { + var painter = handlerInstance.painter; + return x < 0 || x > painter.getWidth() || y < 0 || y > painter.getHeight(); + } + + var DEFAULT_MIN_MERGE = 32; + var DEFAULT_MIN_GALLOPING = 7; + function minRunLength(n) { + var r = 0; + while (n >= DEFAULT_MIN_MERGE) { + r |= n & 1; + n >>= 1; + } + return n + r; + } + function makeAscendingRun(array, lo, hi, compare) { + var runHi = lo + 1; + if (runHi === hi) { + return 1; + } + if (compare(array[runHi++], array[lo]) < 0) { + while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) { + runHi++; + } + reverseRun(array, lo, runHi); + } + else { + while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) { + runHi++; + } + } + return runHi - lo; + } + function reverseRun(array, lo, hi) { + hi--; + while (lo < hi) { + var t = array[lo]; + array[lo++] = array[hi]; + array[hi--] = t; + } + } + function binaryInsertionSort(array, lo, hi, start, compare) { + if (start === lo) { + start++; + } + for (; start < hi; start++) { + var pivot = array[start]; + var left = lo; + var right = start; + var mid; + while (left < right) { + mid = left + right >>> 1; + if (compare(pivot, array[mid]) < 0) { + right = mid; + } + else { + left = mid + 1; + } + } + var n = start - left; + switch (n) { + case 3: + array[left + 3] = array[left + 2]; + case 2: + array[left + 2] = array[left + 1]; + case 1: + array[left + 1] = array[left]; + break; + default: + while (n > 0) { + array[left + n] = array[left + n - 1]; + n--; + } + } + array[left] = pivot; + } + } + function gallopLeft(value, array, start, length, hint, compare) { + var lastOffset = 0; + var maxOffset = 0; + var offset = 1; + if (compare(value, array[start + hint]) > 0) { + maxOffset = length - hint; + while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) { + lastOffset = offset; + offset = (offset << 1) + 1; + if (offset <= 0) { + offset = maxOffset; + } + } + if (offset > maxOffset) { + offset = maxOffset; + } + lastOffset += hint; + offset += hint; + } + else { + maxOffset = hint + 1; + while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) { + lastOffset = offset; + offset = (offset << 1) + 1; + if (offset <= 0) { + offset = maxOffset; + } + } + if (offset > maxOffset) { + offset = maxOffset; + } + var tmp = lastOffset; + lastOffset = hint - offset; + offset = hint - tmp; + } + lastOffset++; + while (lastOffset < offset) { + var m = lastOffset + (offset - lastOffset >>> 1); + if (compare(value, array[start + m]) > 0) { + lastOffset = m + 1; + } + else { + offset = m; + } + } + return offset; + } + function gallopRight(value, array, start, length, hint, compare) { + var lastOffset = 0; + var maxOffset = 0; + var offset = 1; + if (compare(value, array[start + hint]) < 0) { + maxOffset = hint + 1; + while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) { + lastOffset = offset; + offset = (offset << 1) + 1; + if (offset <= 0) { + offset = maxOffset; + } + } + if (offset > maxOffset) { + offset = maxOffset; + } + var tmp = lastOffset; + lastOffset = hint - offset; + offset = hint - tmp; + } + else { + maxOffset = length - hint; + while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) { + lastOffset = offset; + offset = (offset << 1) + 1; + if (offset <= 0) { + offset = maxOffset; + } + } + if (offset > maxOffset) { + offset = maxOffset; + } + lastOffset += hint; + offset += hint; + } + lastOffset++; + while (lastOffset < offset) { + var m = lastOffset + (offset - lastOffset >>> 1); + if (compare(value, array[start + m]) < 0) { + offset = m; + } + else { + lastOffset = m + 1; + } + } + return offset; + } + function TimSort(array, compare) { + var minGallop = DEFAULT_MIN_GALLOPING; + var length = 0; + var runStart; + var runLength; + var stackSize = 0; + length = array.length; + var tmp = []; + runStart = []; + runLength = []; + function pushRun(_runStart, _runLength) { + runStart[stackSize] = _runStart; + runLength[stackSize] = _runLength; + stackSize += 1; + } + function mergeRuns() { + while (stackSize > 1) { + var n = stackSize - 2; + if ((n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1]) + || (n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1])) { + if (runLength[n - 1] < runLength[n + 1]) { + n--; + } + } + else if (runLength[n] > runLength[n + 1]) { + break; + } + mergeAt(n); + } + } + function forceMergeRuns() { + while (stackSize > 1) { + var n = stackSize - 2; + if (n > 0 && runLength[n - 1] < runLength[n + 1]) { + n--; + } + mergeAt(n); + } + } + function mergeAt(i) { + var start1 = runStart[i]; + var length1 = runLength[i]; + var start2 = runStart[i + 1]; + var length2 = runLength[i + 1]; + runLength[i] = length1 + length2; + if (i === stackSize - 3) { + runStart[i + 1] = runStart[i + 2]; + runLength[i + 1] = runLength[i + 2]; + } + stackSize--; + var k = gallopRight(array[start2], array, start1, length1, 0, compare); + start1 += k; + length1 -= k; + if (length1 === 0) { + return; + } + length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare); + if (length2 === 0) { + return; + } + if (length1 <= length2) { + mergeLow(start1, length1, start2, length2); + } + else { + mergeHigh(start1, length1, start2, length2); + } + } + function mergeLow(start1, length1, start2, length2) { + var i = 0; + for (i = 0; i < length1; i++) { + tmp[i] = array[start1 + i]; + } + var cursor1 = 0; + var cursor2 = start2; + var dest = start1; + array[dest++] = array[cursor2++]; + if (--length2 === 0) { + for (i = 0; i < length1; i++) { + array[dest + i] = tmp[cursor1 + i]; + } + return; + } + if (length1 === 1) { + for (i = 0; i < length2; i++) { + array[dest + i] = array[cursor2 + i]; + } + array[dest + length2] = tmp[cursor1]; + return; + } + var _minGallop = minGallop; + var count1; + var count2; + var exit; + while (1) { + count1 = 0; + count2 = 0; + exit = false; + do { + if (compare(array[cursor2], tmp[cursor1]) < 0) { + array[dest++] = array[cursor2++]; + count2++; + count1 = 0; + if (--length2 === 0) { + exit = true; + break; + } + } + else { + array[dest++] = tmp[cursor1++]; + count1++; + count2 = 0; + if (--length1 === 1) { + exit = true; + break; + } + } + } while ((count1 | count2) < _minGallop); + if (exit) { + break; + } + do { + count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare); + if (count1 !== 0) { + for (i = 0; i < count1; i++) { + array[dest + i] = tmp[cursor1 + i]; + } + dest += count1; + cursor1 += count1; + length1 -= count1; + if (length1 <= 1) { + exit = true; + break; + } + } + array[dest++] = array[cursor2++]; + if (--length2 === 0) { + exit = true; + break; + } + count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare); + if (count2 !== 0) { + for (i = 0; i < count2; i++) { + array[dest + i] = array[cursor2 + i]; + } + dest += count2; + cursor2 += count2; + length2 -= count2; + if (length2 === 0) { + exit = true; + break; + } + } + array[dest++] = tmp[cursor1++]; + if (--length1 === 1) { + exit = true; + break; + } + _minGallop--; + } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING); + if (exit) { + break; + } + if (_minGallop < 0) { + _minGallop = 0; + } + _minGallop += 2; + } + minGallop = _minGallop; + minGallop < 1 && (minGallop = 1); + if (length1 === 1) { + for (i = 0; i < length2; i++) { + array[dest + i] = array[cursor2 + i]; + } + array[dest + length2] = tmp[cursor1]; + } + else if (length1 === 0) { + throw new Error(); + } + else { + for (i = 0; i < length1; i++) { + array[dest + i] = tmp[cursor1 + i]; + } + } + } + function mergeHigh(start1, length1, start2, length2) { + var i = 0; + for (i = 0; i < length2; i++) { + tmp[i] = array[start2 + i]; + } + var cursor1 = start1 + length1 - 1; + var cursor2 = length2 - 1; + var dest = start2 + length2 - 1; + var customCursor = 0; + var customDest = 0; + array[dest--] = array[cursor1--]; + if (--length1 === 0) { + customCursor = dest - (length2 - 1); + for (i = 0; i < length2; i++) { + array[customCursor + i] = tmp[i]; + } + return; + } + if (length2 === 1) { + dest -= length1; + cursor1 -= length1; + customDest = dest + 1; + customCursor = cursor1 + 1; + for (i = length1 - 1; i >= 0; i--) { + array[customDest + i] = array[customCursor + i]; + } + array[dest] = tmp[cursor2]; + return; + } + var _minGallop = minGallop; + while (true) { + var count1 = 0; + var count2 = 0; + var exit = false; + do { + if (compare(tmp[cursor2], array[cursor1]) < 0) { + array[dest--] = array[cursor1--]; + count1++; + count2 = 0; + if (--length1 === 0) { + exit = true; + break; + } + } + else { + array[dest--] = tmp[cursor2--]; + count2++; + count1 = 0; + if (--length2 === 1) { + exit = true; + break; + } + } + } while ((count1 | count2) < _minGallop); + if (exit) { + break; + } + do { + count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare); + if (count1 !== 0) { + dest -= count1; + cursor1 -= count1; + length1 -= count1; + customDest = dest + 1; + customCursor = cursor1 + 1; + for (i = count1 - 1; i >= 0; i--) { + array[customDest + i] = array[customCursor + i]; + } + if (length1 === 0) { + exit = true; + break; + } + } + array[dest--] = tmp[cursor2--]; + if (--length2 === 1) { + exit = true; + break; + } + count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare); + if (count2 !== 0) { + dest -= count2; + cursor2 -= count2; + length2 -= count2; + customDest = dest + 1; + customCursor = cursor2 + 1; + for (i = 0; i < count2; i++) { + array[customDest + i] = tmp[customCursor + i]; + } + if (length2 <= 1) { + exit = true; + break; + } + } + array[dest--] = array[cursor1--]; + if (--length1 === 0) { + exit = true; + break; + } + _minGallop--; + } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING); + if (exit) { + break; + } + if (_minGallop < 0) { + _minGallop = 0; + } + _minGallop += 2; + } + minGallop = _minGallop; + if (minGallop < 1) { + minGallop = 1; + } + if (length2 === 1) { + dest -= length1; + cursor1 -= length1; + customDest = dest + 1; + customCursor = cursor1 + 1; + for (i = length1 - 1; i >= 0; i--) { + array[customDest + i] = array[customCursor + i]; + } + array[dest] = tmp[cursor2]; + } + else if (length2 === 0) { + throw new Error(); + } + else { + customCursor = dest - (length2 - 1); + for (i = 0; i < length2; i++) { + array[customCursor + i] = tmp[i]; + } + } + } + return { + mergeRuns: mergeRuns, + forceMergeRuns: forceMergeRuns, + pushRun: pushRun + }; + } + function sort(array, compare, lo, hi) { + if (!lo) { + lo = 0; + } + if (!hi) { + hi = array.length; + } + var remaining = hi - lo; + if (remaining < 2) { + return; + } + var runLength = 0; + if (remaining < DEFAULT_MIN_MERGE) { + runLength = makeAscendingRun(array, lo, hi, compare); + binaryInsertionSort(array, lo, hi, lo + runLength, compare); + return; + } + var ts = TimSort(array, compare); + var minRun = minRunLength(remaining); + do { + runLength = makeAscendingRun(array, lo, hi, compare); + if (runLength < minRun) { + var force = remaining; + if (force > minRun) { + force = minRun; + } + binaryInsertionSort(array, lo, lo + force, lo + runLength, compare); + runLength = force; + } + ts.pushRun(lo, runLength); + ts.mergeRuns(); + remaining -= runLength; + lo += runLength; + } while (remaining !== 0); + ts.forceMergeRuns(); + } + + var REDRAW_BIT = 1; + var STYLE_CHANGED_BIT = 2; + var SHAPE_CHANGED_BIT = 4; + + var invalidZErrorLogged = false; + function logInvalidZError() { + if (invalidZErrorLogged) { + return; + } + invalidZErrorLogged = true; + console.warn('z / z2 / zlevel of displayable is invalid, which may cause unexpected errors'); + } + function shapeCompareFunc(a, b) { + if (a.zlevel === b.zlevel) { + if (a.z === b.z) { + return a.z2 - b.z2; + } + return a.z - b.z; + } + return a.zlevel - b.zlevel; + } + var Storage = (function () { + function Storage() { + this._roots = []; + this._displayList = []; + this._displayListLen = 0; + this.displayableSortFunc = shapeCompareFunc; + } + Storage.prototype.traverse = function (cb, context) { + for (var i = 0; i < this._roots.length; i++) { + this._roots[i].traverse(cb, context); + } + }; + Storage.prototype.getDisplayList = function (update, includeIgnore) { + includeIgnore = includeIgnore || false; + var displayList = this._displayList; + if (update || !displayList.length) { + this.updateDisplayList(includeIgnore); + } + return displayList; + }; + Storage.prototype.updateDisplayList = function (includeIgnore) { + this._displayListLen = 0; + var roots = this._roots; + var displayList = this._displayList; + for (var i = 0, len = roots.length; i < len; i++) { + this._updateAndAddDisplayable(roots[i], null, includeIgnore); + } + displayList.length = this._displayListLen; + sort(displayList, shapeCompareFunc); + }; + Storage.prototype._updateAndAddDisplayable = function (el, clipPaths, includeIgnore) { + if (el.ignore && !includeIgnore) { + return; + } + el.beforeUpdate(); + el.update(); + el.afterUpdate(); + var userSetClipPath = el.getClipPath(); + if (el.ignoreClip) { + clipPaths = null; + } + else if (userSetClipPath) { + if (clipPaths) { + clipPaths = clipPaths.slice(); + } + else { + clipPaths = []; + } + var currentClipPath = userSetClipPath; + var parentClipPath = el; + while (currentClipPath) { + currentClipPath.parent = parentClipPath; + currentClipPath.updateTransform(); + clipPaths.push(currentClipPath); + parentClipPath = currentClipPath; + currentClipPath = currentClipPath.getClipPath(); + } + } + if (el.childrenRef) { + var children = el.childrenRef(); + for (var i = 0; i < children.length; i++) { + var child = children[i]; + if (el.__dirty) { + child.__dirty |= REDRAW_BIT; + } + this._updateAndAddDisplayable(child, clipPaths, includeIgnore); + } + el.__dirty = 0; + } + else { + var disp = el; + if (clipPaths && clipPaths.length) { + disp.__clipPaths = clipPaths; + } + else if (disp.__clipPaths && disp.__clipPaths.length > 0) { + disp.__clipPaths = []; + } + if (isNaN(disp.z)) { + logInvalidZError(); + disp.z = 0; + } + if (isNaN(disp.z2)) { + logInvalidZError(); + disp.z2 = 0; + } + if (isNaN(disp.zlevel)) { + logInvalidZError(); + disp.zlevel = 0; + } + this._displayList[this._displayListLen++] = disp; + } + var decalEl = el.getDecalElement && el.getDecalElement(); + if (decalEl) { + this._updateAndAddDisplayable(decalEl, clipPaths, includeIgnore); + } + var textGuide = el.getTextGuideLine(); + if (textGuide) { + this._updateAndAddDisplayable(textGuide, clipPaths, includeIgnore); + } + var textEl = el.getTextContent(); + if (textEl) { + this._updateAndAddDisplayable(textEl, clipPaths, includeIgnore); + } + }; + Storage.prototype.addRoot = function (el) { + if (el.__zr && el.__zr.storage === this) { + return; + } + this._roots.push(el); + }; + Storage.prototype.delRoot = function (el) { + if (el instanceof Array) { + for (var i = 0, l = el.length; i < l; i++) { + this.delRoot(el[i]); + } + return; + } + var idx = indexOf(this._roots, el); + if (idx >= 0) { + this._roots.splice(idx, 1); + } + }; + Storage.prototype.delAllRoots = function () { + this._roots = []; + this._displayList = []; + this._displayListLen = 0; + return; + }; + Storage.prototype.getRoots = function () { + return this._roots; + }; + Storage.prototype.dispose = function () { + this._displayList = null; + this._roots = null; + }; + return Storage; + }()); + + var requestAnimationFrame; + requestAnimationFrame = (env.hasGlobalWindow + && ((window.requestAnimationFrame && window.requestAnimationFrame.bind(window)) + || (window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window)) + || window.mozRequestAnimationFrame + || window.webkitRequestAnimationFrame)) || function (func) { + return setTimeout(func, 16); + }; + var requestAnimationFrame$1 = requestAnimationFrame; + + var easingFuncs = { + linear: function (k) { + return k; + }, + quadraticIn: function (k) { + return k * k; + }, + quadraticOut: function (k) { + return k * (2 - k); + }, + quadraticInOut: function (k) { + if ((k *= 2) < 1) { + return 0.5 * k * k; + } + return -0.5 * (--k * (k - 2) - 1); + }, + cubicIn: function (k) { + return k * k * k; + }, + cubicOut: function (k) { + return --k * k * k + 1; + }, + cubicInOut: function (k) { + if ((k *= 2) < 1) { + return 0.5 * k * k * k; + } + return 0.5 * ((k -= 2) * k * k + 2); + }, + quarticIn: function (k) { + return k * k * k * k; + }, + quarticOut: function (k) { + return 1 - (--k * k * k * k); + }, + quarticInOut: function (k) { + if ((k *= 2) < 1) { + return 0.5 * k * k * k * k; + } + return -0.5 * ((k -= 2) * k * k * k - 2); + }, + quinticIn: function (k) { + return k * k * k * k * k; + }, + quinticOut: function (k) { + return --k * k * k * k * k + 1; + }, + quinticInOut: function (k) { + if ((k *= 2) < 1) { + return 0.5 * k * k * k * k * k; + } + return 0.5 * ((k -= 2) * k * k * k * k + 2); + }, + sinusoidalIn: function (k) { + return 1 - Math.cos(k * Math.PI / 2); + }, + sinusoidalOut: function (k) { + return Math.sin(k * Math.PI / 2); + }, + sinusoidalInOut: function (k) { + return 0.5 * (1 - Math.cos(Math.PI * k)); + }, + exponentialIn: function (k) { + return k === 0 ? 0 : Math.pow(1024, k - 1); + }, + exponentialOut: function (k) { + return k === 1 ? 1 : 1 - Math.pow(2, -10 * k); + }, + exponentialInOut: function (k) { + if (k === 0) { + return 0; + } + if (k === 1) { + return 1; + } + if ((k *= 2) < 1) { + return 0.5 * Math.pow(1024, k - 1); + } + return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2); + }, + circularIn: function (k) { + return 1 - Math.sqrt(1 - k * k); + }, + circularOut: function (k) { + return Math.sqrt(1 - (--k * k)); + }, + circularInOut: function (k) { + if ((k *= 2) < 1) { + return -0.5 * (Math.sqrt(1 - k * k) - 1); + } + return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1); + }, + elasticIn: function (k) { + var s; + var a = 0.1; + var p = 0.4; + if (k === 0) { + return 0; + } + if (k === 1) { + return 1; + } + if (!a || a < 1) { + a = 1; + s = p / 4; + } + else { + s = p * Math.asin(1 / a) / (2 * Math.PI); + } + return -(a * Math.pow(2, 10 * (k -= 1)) + * Math.sin((k - s) * (2 * Math.PI) / p)); + }, + elasticOut: function (k) { + var s; + var a = 0.1; + var p = 0.4; + if (k === 0) { + return 0; + } + if (k === 1) { + return 1; + } + if (!a || a < 1) { + a = 1; + s = p / 4; + } + else { + s = p * Math.asin(1 / a) / (2 * Math.PI); + } + return (a * Math.pow(2, -10 * k) + * Math.sin((k - s) * (2 * Math.PI) / p) + 1); + }, + elasticInOut: function (k) { + var s; + var a = 0.1; + var p = 0.4; + if (k === 0) { + return 0; + } + if (k === 1) { + return 1; + } + if (!a || a < 1) { + a = 1; + s = p / 4; + } + else { + s = p * Math.asin(1 / a) / (2 * Math.PI); + } + if ((k *= 2) < 1) { + return -0.5 * (a * Math.pow(2, 10 * (k -= 1)) + * Math.sin((k - s) * (2 * Math.PI) / p)); + } + return a * Math.pow(2, -10 * (k -= 1)) + * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1; + }, + backIn: function (k) { + var s = 1.70158; + return k * k * ((s + 1) * k - s); + }, + backOut: function (k) { + var s = 1.70158; + return --k * k * ((s + 1) * k + s) + 1; + }, + backInOut: function (k) { + var s = 1.70158 * 1.525; + if ((k *= 2) < 1) { + return 0.5 * (k * k * ((s + 1) * k - s)); + } + return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2); + }, + bounceIn: function (k) { + return 1 - easingFuncs.bounceOut(1 - k); + }, + bounceOut: function (k) { + if (k < (1 / 2.75)) { + return 7.5625 * k * k; + } + else if (k < (2 / 2.75)) { + return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; + } + else if (k < (2.5 / 2.75)) { + return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; + } + else { + return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; + } + }, + bounceInOut: function (k) { + if (k < 0.5) { + return easingFuncs.bounceIn(k * 2) * 0.5; + } + return easingFuncs.bounceOut(k * 2 - 1) * 0.5 + 0.5; + } + }; + + var mathPow = Math.pow; + var mathSqrt = Math.sqrt; + var EPSILON = 1e-8; + var EPSILON_NUMERIC = 1e-4; + var THREE_SQRT = mathSqrt(3); + var ONE_THIRD = 1 / 3; + var _v0 = create(); + var _v1 = create(); + var _v2 = create(); + function isAroundZero(val) { + return val > -EPSILON && val < EPSILON; + } + function isNotAroundZero(val) { + return val > EPSILON || val < -EPSILON; + } + function cubicAt(p0, p1, p2, p3, t) { + var onet = 1 - t; + return onet * onet * (onet * p0 + 3 * t * p1) + + t * t * (t * p3 + 3 * onet * p2); + } + function cubicDerivativeAt(p0, p1, p2, p3, t) { + var onet = 1 - t; + return 3 * (((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet + + (p3 - p2) * t * t); + } + function cubicRootAt(p0, p1, p2, p3, val, roots) { + var a = p3 + 3 * (p1 - p2) - p0; + var b = 3 * (p2 - p1 * 2 + p0); + var c = 3 * (p1 - p0); + var d = p0 - val; + var A = b * b - 3 * a * c; + var B = b * c - 9 * a * d; + var C = c * c - 3 * b * d; + var n = 0; + if (isAroundZero(A) && isAroundZero(B)) { + if (isAroundZero(b)) { + roots[0] = 0; + } + else { + var t1 = -c / b; + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + } + } + else { + var disc = B * B - 4 * A * C; + if (isAroundZero(disc)) { + var K = B / A; + var t1 = -b / a + K; + var t2 = -K / 2; + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + if (t2 >= 0 && t2 <= 1) { + roots[n++] = t2; + } + } + else if (disc > 0) { + var discSqrt = mathSqrt(disc); + var Y1 = A * b + 1.5 * a * (-B + discSqrt); + var Y2 = A * b + 1.5 * a * (-B - discSqrt); + if (Y1 < 0) { + Y1 = -mathPow(-Y1, ONE_THIRD); + } + else { + Y1 = mathPow(Y1, ONE_THIRD); + } + if (Y2 < 0) { + Y2 = -mathPow(-Y2, ONE_THIRD); + } + else { + Y2 = mathPow(Y2, ONE_THIRD); + } + var t1 = (-b - (Y1 + Y2)) / (3 * a); + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + } + else { + var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt(A * A * A)); + var theta = Math.acos(T) / 3; + var ASqrt = mathSqrt(A); + var tmp = Math.cos(theta); + var t1 = (-b - 2 * ASqrt * tmp) / (3 * a); + var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a); + var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a); + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + if (t2 >= 0 && t2 <= 1) { + roots[n++] = t2; + } + if (t3 >= 0 && t3 <= 1) { + roots[n++] = t3; + } + } + } + return n; + } + function cubicExtrema(p0, p1, p2, p3, extrema) { + var b = 6 * p2 - 12 * p1 + 6 * p0; + var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2; + var c = 3 * p1 - 3 * p0; + var n = 0; + if (isAroundZero(a)) { + if (isNotAroundZero(b)) { + var t1 = -c / b; + if (t1 >= 0 && t1 <= 1) { + extrema[n++] = t1; + } + } + } + else { + var disc = b * b - 4 * a * c; + if (isAroundZero(disc)) { + extrema[0] = -b / (2 * a); + } + else if (disc > 0) { + var discSqrt = mathSqrt(disc); + var t1 = (-b + discSqrt) / (2 * a); + var t2 = (-b - discSqrt) / (2 * a); + if (t1 >= 0 && t1 <= 1) { + extrema[n++] = t1; + } + if (t2 >= 0 && t2 <= 1) { + extrema[n++] = t2; + } + } + } + return n; + } + function cubicSubdivide(p0, p1, p2, p3, t, out) { + var p01 = (p1 - p0) * t + p0; + var p12 = (p2 - p1) * t + p1; + var p23 = (p3 - p2) * t + p2; + var p012 = (p12 - p01) * t + p01; + var p123 = (p23 - p12) * t + p12; + var p0123 = (p123 - p012) * t + p012; + out[0] = p0; + out[1] = p01; + out[2] = p012; + out[3] = p0123; + out[4] = p0123; + out[5] = p123; + out[6] = p23; + out[7] = p3; + } + function cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, out) { + var t; + var interval = 0.005; + var d = Infinity; + var prev; + var next; + var d1; + var d2; + _v0[0] = x; + _v0[1] = y; + for (var _t = 0; _t < 1; _t += 0.05) { + _v1[0] = cubicAt(x0, x1, x2, x3, _t); + _v1[1] = cubicAt(y0, y1, y2, y3, _t); + d1 = distSquare(_v0, _v1); + if (d1 < d) { + t = _t; + d = d1; + } + } + d = Infinity; + for (var i = 0; i < 32; i++) { + if (interval < EPSILON_NUMERIC) { + break; + } + prev = t - interval; + next = t + interval; + _v1[0] = cubicAt(x0, x1, x2, x3, prev); + _v1[1] = cubicAt(y0, y1, y2, y3, prev); + d1 = distSquare(_v1, _v0); + if (prev >= 0 && d1 < d) { + t = prev; + d = d1; + } + else { + _v2[0] = cubicAt(x0, x1, x2, x3, next); + _v2[1] = cubicAt(y0, y1, y2, y3, next); + d2 = distSquare(_v2, _v0); + if (next <= 1 && d2 < d) { + t = next; + d = d2; + } + else { + interval *= 0.5; + } + } + } + if (out) { + out[0] = cubicAt(x0, x1, x2, x3, t); + out[1] = cubicAt(y0, y1, y2, y3, t); + } + return mathSqrt(d); + } + function cubicLength(x0, y0, x1, y1, x2, y2, x3, y3, iteration) { + var px = x0; + var py = y0; + var d = 0; + var step = 1 / iteration; + for (var i = 1; i <= iteration; i++) { + var t = i * step; + var x = cubicAt(x0, x1, x2, x3, t); + var y = cubicAt(y0, y1, y2, y3, t); + var dx = x - px; + var dy = y - py; + d += Math.sqrt(dx * dx + dy * dy); + px = x; + py = y; + } + return d; + } + function quadraticAt(p0, p1, p2, t) { + var onet = 1 - t; + return onet * (onet * p0 + 2 * t * p1) + t * t * p2; + } + function quadraticDerivativeAt(p0, p1, p2, t) { + return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1)); + } + function quadraticRootAt(p0, p1, p2, val, roots) { + var a = p0 - 2 * p1 + p2; + var b = 2 * (p1 - p0); + var c = p0 - val; + var n = 0; + if (isAroundZero(a)) { + if (isNotAroundZero(b)) { + var t1 = -c / b; + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + } + } + else { + var disc = b * b - 4 * a * c; + if (isAroundZero(disc)) { + var t1 = -b / (2 * a); + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + } + else if (disc > 0) { + var discSqrt = mathSqrt(disc); + var t1 = (-b + discSqrt) / (2 * a); + var t2 = (-b - discSqrt) / (2 * a); + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + if (t2 >= 0 && t2 <= 1) { + roots[n++] = t2; + } + } + } + return n; + } + function quadraticExtremum(p0, p1, p2) { + var divider = p0 + p2 - 2 * p1; + if (divider === 0) { + return 0.5; + } + else { + return (p0 - p1) / divider; + } + } + function quadraticSubdivide(p0, p1, p2, t, out) { + var p01 = (p1 - p0) * t + p0; + var p12 = (p2 - p1) * t + p1; + var p012 = (p12 - p01) * t + p01; + out[0] = p0; + out[1] = p01; + out[2] = p012; + out[3] = p012; + out[4] = p12; + out[5] = p2; + } + function quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, out) { + var t; + var interval = 0.005; + var d = Infinity; + _v0[0] = x; + _v0[1] = y; + for (var _t = 0; _t < 1; _t += 0.05) { + _v1[0] = quadraticAt(x0, x1, x2, _t); + _v1[1] = quadraticAt(y0, y1, y2, _t); + var d1 = distSquare(_v0, _v1); + if (d1 < d) { + t = _t; + d = d1; + } + } + d = Infinity; + for (var i = 0; i < 32; i++) { + if (interval < EPSILON_NUMERIC) { + break; + } + var prev = t - interval; + var next = t + interval; + _v1[0] = quadraticAt(x0, x1, x2, prev); + _v1[1] = quadraticAt(y0, y1, y2, prev); + var d1 = distSquare(_v1, _v0); + if (prev >= 0 && d1 < d) { + t = prev; + d = d1; + } + else { + _v2[0] = quadraticAt(x0, x1, x2, next); + _v2[1] = quadraticAt(y0, y1, y2, next); + var d2 = distSquare(_v2, _v0); + if (next <= 1 && d2 < d) { + t = next; + d = d2; + } + else { + interval *= 0.5; + } + } + } + if (out) { + out[0] = quadraticAt(x0, x1, x2, t); + out[1] = quadraticAt(y0, y1, y2, t); + } + return mathSqrt(d); + } + function quadraticLength(x0, y0, x1, y1, x2, y2, iteration) { + var px = x0; + var py = y0; + var d = 0; + var step = 1 / iteration; + for (var i = 1; i <= iteration; i++) { + var t = i * step; + var x = quadraticAt(x0, x1, x2, t); + var y = quadraticAt(y0, y1, y2, t); + var dx = x - px; + var dy = y - py; + d += Math.sqrt(dx * dx + dy * dy); + px = x; + py = y; + } + return d; + } + + var regexp = /cubic-bezier\(([0-9,\.e ]+)\)/; + function createCubicEasingFunc(cubicEasingStr) { + var cubic = cubicEasingStr && regexp.exec(cubicEasingStr); + if (cubic) { + var points = cubic[1].split(','); + var a_1 = +trim(points[0]); + var b_1 = +trim(points[1]); + var c_1 = +trim(points[2]); + var d_1 = +trim(points[3]); + if (isNaN(a_1 + b_1 + c_1 + d_1)) { + return; + } + var roots_1 = []; + return function (p) { + return p <= 0 + ? 0 : p >= 1 + ? 1 + : cubicRootAt(0, a_1, c_1, 1, p, roots_1) && cubicAt(0, b_1, d_1, 1, roots_1[0]); + }; + } + } + + var Clip = (function () { + function Clip(opts) { + this._inited = false; + this._startTime = 0; + this._pausedTime = 0; + this._paused = false; + this._life = opts.life || 1000; + this._delay = opts.delay || 0; + this.loop = opts.loop || false; + this.onframe = opts.onframe || noop; + this.ondestroy = opts.ondestroy || noop; + this.onrestart = opts.onrestart || noop; + opts.easing && this.setEasing(opts.easing); + } + Clip.prototype.step = function (globalTime, deltaTime) { + if (!this._inited) { + this._startTime = globalTime + this._delay; + this._inited = true; + } + if (this._paused) { + this._pausedTime += deltaTime; + return; + } + var life = this._life; + var elapsedTime = globalTime - this._startTime - this._pausedTime; + var percent = elapsedTime / life; + if (percent < 0) { + percent = 0; + } + percent = Math.min(percent, 1); + var easingFunc = this.easingFunc; + var schedule = easingFunc ? easingFunc(percent) : percent; + this.onframe(schedule); + if (percent === 1) { + if (this.loop) { + var remainder = elapsedTime % life; + this._startTime = globalTime - remainder; + this._pausedTime = 0; + this.onrestart(); + } + else { + return true; + } + } + return false; + }; + Clip.prototype.pause = function () { + this._paused = true; + }; + Clip.prototype.resume = function () { + this._paused = false; + }; + Clip.prototype.setEasing = function (easing) { + this.easing = easing; + this.easingFunc = isFunction(easing) + ? easing + : easingFuncs[easing] || createCubicEasingFunc(easing); + }; + return Clip; + }()); + + var Entry = (function () { + function Entry(val) { + this.value = val; + } + return Entry; + }()); + var LinkedList = (function () { + function LinkedList() { + this._len = 0; + } + LinkedList.prototype.insert = function (val) { + var entry = new Entry(val); + this.insertEntry(entry); + return entry; + }; + LinkedList.prototype.insertEntry = function (entry) { + if (!this.head) { + this.head = this.tail = entry; + } + else { + this.tail.next = entry; + entry.prev = this.tail; + entry.next = null; + this.tail = entry; + } + this._len++; + }; + LinkedList.prototype.remove = function (entry) { + var prev = entry.prev; + var next = entry.next; + if (prev) { + prev.next = next; + } + else { + this.head = next; + } + if (next) { + next.prev = prev; + } + else { + this.tail = prev; + } + entry.next = entry.prev = null; + this._len--; + }; + LinkedList.prototype.len = function () { + return this._len; + }; + LinkedList.prototype.clear = function () { + this.head = this.tail = null; + this._len = 0; + }; + return LinkedList; + }()); + var LRU = (function () { + function LRU(maxSize) { + this._list = new LinkedList(); + this._maxSize = 10; + this._map = {}; + this._maxSize = maxSize; + } + LRU.prototype.put = function (key, value) { + var list = this._list; + var map = this._map; + var removed = null; + if (map[key] == null) { + var len = list.len(); + var entry = this._lastRemovedEntry; + if (len >= this._maxSize && len > 0) { + var leastUsedEntry = list.head; + list.remove(leastUsedEntry); + delete map[leastUsedEntry.key]; + removed = leastUsedEntry.value; + this._lastRemovedEntry = leastUsedEntry; + } + if (entry) { + entry.value = value; + } + else { + entry = new Entry(value); + } + entry.key = key; + list.insertEntry(entry); + map[key] = entry; + } + return removed; + }; + LRU.prototype.get = function (key) { + var entry = this._map[key]; + var list = this._list; + if (entry != null) { + if (entry !== list.tail) { + list.remove(entry); + list.insertEntry(entry); + } + return entry.value; + } + }; + LRU.prototype.clear = function () { + this._list.clear(); + this._map = {}; + }; + LRU.prototype.len = function () { + return this._list.len(); + }; + return LRU; + }()); + + var kCSSColorTable = { + 'transparent': [0, 0, 0, 0], 'aliceblue': [240, 248, 255, 1], + 'antiquewhite': [250, 235, 215, 1], 'aqua': [0, 255, 255, 1], + 'aquamarine': [127, 255, 212, 1], 'azure': [240, 255, 255, 1], + 'beige': [245, 245, 220, 1], 'bisque': [255, 228, 196, 1], + 'black': [0, 0, 0, 1], 'blanchedalmond': [255, 235, 205, 1], + 'blue': [0, 0, 255, 1], 'blueviolet': [138, 43, 226, 1], + 'brown': [165, 42, 42, 1], 'burlywood': [222, 184, 135, 1], + 'cadetblue': [95, 158, 160, 1], 'chartreuse': [127, 255, 0, 1], + 'chocolate': [210, 105, 30, 1], 'coral': [255, 127, 80, 1], + 'cornflowerblue': [100, 149, 237, 1], 'cornsilk': [255, 248, 220, 1], + 'crimson': [220, 20, 60, 1], 'cyan': [0, 255, 255, 1], + 'darkblue': [0, 0, 139, 1], 'darkcyan': [0, 139, 139, 1], + 'darkgoldenrod': [184, 134, 11, 1], 'darkgray': [169, 169, 169, 1], + 'darkgreen': [0, 100, 0, 1], 'darkgrey': [169, 169, 169, 1], + 'darkkhaki': [189, 183, 107, 1], 'darkmagenta': [139, 0, 139, 1], + 'darkolivegreen': [85, 107, 47, 1], 'darkorange': [255, 140, 0, 1], + 'darkorchid': [153, 50, 204, 1], 'darkred': [139, 0, 0, 1], + 'darksalmon': [233, 150, 122, 1], 'darkseagreen': [143, 188, 143, 1], + 'darkslateblue': [72, 61, 139, 1], 'darkslategray': [47, 79, 79, 1], + 'darkslategrey': [47, 79, 79, 1], 'darkturquoise': [0, 206, 209, 1], + 'darkviolet': [148, 0, 211, 1], 'deeppink': [255, 20, 147, 1], + 'deepskyblue': [0, 191, 255, 1], 'dimgray': [105, 105, 105, 1], + 'dimgrey': [105, 105, 105, 1], 'dodgerblue': [30, 144, 255, 1], + 'firebrick': [178, 34, 34, 1], 'floralwhite': [255, 250, 240, 1], + 'forestgreen': [34, 139, 34, 1], 'fuchsia': [255, 0, 255, 1], + 'gainsboro': [220, 220, 220, 1], 'ghostwhite': [248, 248, 255, 1], + 'gold': [255, 215, 0, 1], 'goldenrod': [218, 165, 32, 1], + 'gray': [128, 128, 128, 1], 'green': [0, 128, 0, 1], + 'greenyellow': [173, 255, 47, 1], 'grey': [128, 128, 128, 1], + 'honeydew': [240, 255, 240, 1], 'hotpink': [255, 105, 180, 1], + 'indianred': [205, 92, 92, 1], 'indigo': [75, 0, 130, 1], + 'ivory': [255, 255, 240, 1], 'khaki': [240, 230, 140, 1], + 'lavender': [230, 230, 250, 1], 'lavenderblush': [255, 240, 245, 1], + 'lawngreen': [124, 252, 0, 1], 'lemonchiffon': [255, 250, 205, 1], + 'lightblue': [173, 216, 230, 1], 'lightcoral': [240, 128, 128, 1], + 'lightcyan': [224, 255, 255, 1], 'lightgoldenrodyellow': [250, 250, 210, 1], + 'lightgray': [211, 211, 211, 1], 'lightgreen': [144, 238, 144, 1], + 'lightgrey': [211, 211, 211, 1], 'lightpink': [255, 182, 193, 1], + 'lightsalmon': [255, 160, 122, 1], 'lightseagreen': [32, 178, 170, 1], + 'lightskyblue': [135, 206, 250, 1], 'lightslategray': [119, 136, 153, 1], + 'lightslategrey': [119, 136, 153, 1], 'lightsteelblue': [176, 196, 222, 1], + 'lightyellow': [255, 255, 224, 1], 'lime': [0, 255, 0, 1], + 'limegreen': [50, 205, 50, 1], 'linen': [250, 240, 230, 1], + 'magenta': [255, 0, 255, 1], 'maroon': [128, 0, 0, 1], + 'mediumaquamarine': [102, 205, 170, 1], 'mediumblue': [0, 0, 205, 1], + 'mediumorchid': [186, 85, 211, 1], 'mediumpurple': [147, 112, 219, 1], + 'mediumseagreen': [60, 179, 113, 1], 'mediumslateblue': [123, 104, 238, 1], + 'mediumspringgreen': [0, 250, 154, 1], 'mediumturquoise': [72, 209, 204, 1], + 'mediumvioletred': [199, 21, 133, 1], 'midnightblue': [25, 25, 112, 1], + 'mintcream': [245, 255, 250, 1], 'mistyrose': [255, 228, 225, 1], + 'moccasin': [255, 228, 181, 1], 'navajowhite': [255, 222, 173, 1], + 'navy': [0, 0, 128, 1], 'oldlace': [253, 245, 230, 1], + 'olive': [128, 128, 0, 1], 'olivedrab': [107, 142, 35, 1], + 'orange': [255, 165, 0, 1], 'orangered': [255, 69, 0, 1], + 'orchid': [218, 112, 214, 1], 'palegoldenrod': [238, 232, 170, 1], + 'palegreen': [152, 251, 152, 1], 'paleturquoise': [175, 238, 238, 1], + 'palevioletred': [219, 112, 147, 1], 'papayawhip': [255, 239, 213, 1], + 'peachpuff': [255, 218, 185, 1], 'peru': [205, 133, 63, 1], + 'pink': [255, 192, 203, 1], 'plum': [221, 160, 221, 1], + 'powderblue': [176, 224, 230, 1], 'purple': [128, 0, 128, 1], + 'red': [255, 0, 0, 1], 'rosybrown': [188, 143, 143, 1], + 'royalblue': [65, 105, 225, 1], 'saddlebrown': [139, 69, 19, 1], + 'salmon': [250, 128, 114, 1], 'sandybrown': [244, 164, 96, 1], + 'seagreen': [46, 139, 87, 1], 'seashell': [255, 245, 238, 1], + 'sienna': [160, 82, 45, 1], 'silver': [192, 192, 192, 1], + 'skyblue': [135, 206, 235, 1], 'slateblue': [106, 90, 205, 1], + 'slategray': [112, 128, 144, 1], 'slategrey': [112, 128, 144, 1], + 'snow': [255, 250, 250, 1], 'springgreen': [0, 255, 127, 1], + 'steelblue': [70, 130, 180, 1], 'tan': [210, 180, 140, 1], + 'teal': [0, 128, 128, 1], 'thistle': [216, 191, 216, 1], + 'tomato': [255, 99, 71, 1], 'turquoise': [64, 224, 208, 1], + 'violet': [238, 130, 238, 1], 'wheat': [245, 222, 179, 1], + 'white': [255, 255, 255, 1], 'whitesmoke': [245, 245, 245, 1], + 'yellow': [255, 255, 0, 1], 'yellowgreen': [154, 205, 50, 1] + }; + function clampCssByte(i) { + i = Math.round(i); + return i < 0 ? 0 : i > 255 ? 255 : i; + } + function clampCssAngle(i) { + i = Math.round(i); + return i < 0 ? 0 : i > 360 ? 360 : i; + } + function clampCssFloat(f) { + return f < 0 ? 0 : f > 1 ? 1 : f; + } + function parseCssInt(val) { + var str = val; + if (str.length && str.charAt(str.length - 1) === '%') { + return clampCssByte(parseFloat(str) / 100 * 255); + } + return clampCssByte(parseInt(str, 10)); + } + function parseCssFloat(val) { + var str = val; + if (str.length && str.charAt(str.length - 1) === '%') { + return clampCssFloat(parseFloat(str) / 100); + } + return clampCssFloat(parseFloat(str)); + } + function cssHueToRgb(m1, m2, h) { + if (h < 0) { + h += 1; + } + else if (h > 1) { + h -= 1; + } + if (h * 6 < 1) { + return m1 + (m2 - m1) * h * 6; + } + if (h * 2 < 1) { + return m2; + } + if (h * 3 < 2) { + return m1 + (m2 - m1) * (2 / 3 - h) * 6; + } + return m1; + } + function lerpNumber(a, b, p) { + return a + (b - a) * p; + } + function setRgba(out, r, g, b, a) { + out[0] = r; + out[1] = g; + out[2] = b; + out[3] = a; + return out; + } + function copyRgba(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; + } + var colorCache = new LRU(20); + var lastRemovedArr = null; + function putToCache(colorStr, rgbaArr) { + if (lastRemovedArr) { + copyRgba(lastRemovedArr, rgbaArr); + } + lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice())); + } + function parse(colorStr, rgbaArr) { + if (!colorStr) { + return; + } + rgbaArr = rgbaArr || []; + var cached = colorCache.get(colorStr); + if (cached) { + return copyRgba(rgbaArr, cached); + } + colorStr = colorStr + ''; + var str = colorStr.replace(/ /g, '').toLowerCase(); + if (str in kCSSColorTable) { + copyRgba(rgbaArr, kCSSColorTable[str]); + putToCache(colorStr, rgbaArr); + return rgbaArr; + } + var strLen = str.length; + if (str.charAt(0) === '#') { + if (strLen === 4 || strLen === 5) { + var iv = parseInt(str.slice(1, 4), 16); + if (!(iv >= 0 && iv <= 0xfff)) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + setRgba(rgbaArr, ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8), (iv & 0xf0) | ((iv & 0xf0) >> 4), (iv & 0xf) | ((iv & 0xf) << 4), strLen === 5 ? parseInt(str.slice(4), 16) / 0xf : 1); + putToCache(colorStr, rgbaArr); + return rgbaArr; + } + else if (strLen === 7 || strLen === 9) { + var iv = parseInt(str.slice(1, 7), 16); + if (!(iv >= 0 && iv <= 0xffffff)) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + setRgba(rgbaArr, (iv & 0xff0000) >> 16, (iv & 0xff00) >> 8, iv & 0xff, strLen === 9 ? parseInt(str.slice(7), 16) / 0xff : 1); + putToCache(colorStr, rgbaArr); + return rgbaArr; + } + return; + } + var op = str.indexOf('('); + var ep = str.indexOf(')'); + if (op !== -1 && ep + 1 === strLen) { + var fname = str.substr(0, op); + var params = str.substr(op + 1, ep - (op + 1)).split(','); + var alpha = 1; + switch (fname) { + case 'rgba': + if (params.length !== 4) { + return params.length === 3 + ? setRgba(rgbaArr, +params[0], +params[1], +params[2], 1) + : setRgba(rgbaArr, 0, 0, 0, 1); + } + alpha = parseCssFloat(params.pop()); + case 'rgb': + if (params.length !== 3) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + setRgba(rgbaArr, parseCssInt(params[0]), parseCssInt(params[1]), parseCssInt(params[2]), alpha); + putToCache(colorStr, rgbaArr); + return rgbaArr; + case 'hsla': + if (params.length !== 4) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + params[3] = parseCssFloat(params[3]); + hsla2rgba(params, rgbaArr); + putToCache(colorStr, rgbaArr); + return rgbaArr; + case 'hsl': + if (params.length !== 3) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + hsla2rgba(params, rgbaArr); + putToCache(colorStr, rgbaArr); + return rgbaArr; + default: + return; + } + } + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + function hsla2rgba(hsla, rgba) { + var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360; + var s = parseCssFloat(hsla[1]); + var l = parseCssFloat(hsla[2]); + var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; + var m1 = l * 2 - m2; + rgba = rgba || []; + setRgba(rgba, clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255), clampCssByte(cssHueToRgb(m1, m2, h) * 255), clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255), 1); + if (hsla.length === 4) { + rgba[3] = hsla[3]; + } + return rgba; + } + function rgba2hsla(rgba) { + if (!rgba) { + return; + } + var R = rgba[0] / 255; + var G = rgba[1] / 255; + var B = rgba[2] / 255; + var vMin = Math.min(R, G, B); + var vMax = Math.max(R, G, B); + var delta = vMax - vMin; + var L = (vMax + vMin) / 2; + var H; + var S; + if (delta === 0) { + H = 0; + S = 0; + } + else { + if (L < 0.5) { + S = delta / (vMax + vMin); + } + else { + S = delta / (2 - vMax - vMin); + } + var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta; + var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta; + var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta; + if (R === vMax) { + H = deltaB - deltaG; + } + else if (G === vMax) { + H = (1 / 3) + deltaR - deltaB; + } + else if (B === vMax) { + H = (2 / 3) + deltaG - deltaR; + } + if (H < 0) { + H += 1; + } + if (H > 1) { + H -= 1; + } + } + var hsla = [H * 360, S, L]; + if (rgba[3] != null) { + hsla.push(rgba[3]); + } + return hsla; + } + function lift(color, level) { + var colorArr = parse(color); + if (colorArr) { + for (var i = 0; i < 3; i++) { + if (level < 0) { + colorArr[i] = colorArr[i] * (1 - level) | 0; + } + else { + colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0; + } + if (colorArr[i] > 255) { + colorArr[i] = 255; + } + else if (colorArr[i] < 0) { + colorArr[i] = 0; + } + } + return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb'); + } + } + function toHex(color) { + var colorArr = parse(color); + if (colorArr) { + return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1); + } + } + function fastLerp(normalizedValue, colors, out) { + if (!(colors && colors.length) + || !(normalizedValue >= 0 && normalizedValue <= 1)) { + return; + } + out = out || []; + var value = normalizedValue * (colors.length - 1); + var leftIndex = Math.floor(value); + var rightIndex = Math.ceil(value); + var leftColor = colors[leftIndex]; + var rightColor = colors[rightIndex]; + var dv = value - leftIndex; + out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)); + out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)); + out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)); + out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv)); + return out; + } + var fastMapToColor = fastLerp; + function lerp$1(normalizedValue, colors, fullOutput) { + if (!(colors && colors.length) + || !(normalizedValue >= 0 && normalizedValue <= 1)) { + return; + } + var value = normalizedValue * (colors.length - 1); + var leftIndex = Math.floor(value); + var rightIndex = Math.ceil(value); + var leftColor = parse(colors[leftIndex]); + var rightColor = parse(colors[rightIndex]); + var dv = value - leftIndex; + var color = stringify([ + clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)), + clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)), + clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)), + clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv)) + ], 'rgba'); + return fullOutput + ? { + color: color, + leftIndex: leftIndex, + rightIndex: rightIndex, + value: value + } + : color; + } + var mapToColor = lerp$1; + function modifyHSL(color, h, s, l) { + var colorArr = parse(color); + if (color) { + colorArr = rgba2hsla(colorArr); + h != null && (colorArr[0] = clampCssAngle(h)); + s != null && (colorArr[1] = parseCssFloat(s)); + l != null && (colorArr[2] = parseCssFloat(l)); + return stringify(hsla2rgba(colorArr), 'rgba'); + } + } + function modifyAlpha(color, alpha) { + var colorArr = parse(color); + if (colorArr && alpha != null) { + colorArr[3] = clampCssFloat(alpha); + return stringify(colorArr, 'rgba'); + } + } + function stringify(arrColor, type) { + if (!arrColor || !arrColor.length) { + return; + } + var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2]; + if (type === 'rgba' || type === 'hsva' || type === 'hsla') { + colorStr += ',' + arrColor[3]; + } + return type + '(' + colorStr + ')'; + } + function lum(color, backgroundLum) { + var arr = parse(color); + return arr + ? (0.299 * arr[0] + 0.587 * arr[1] + 0.114 * arr[2]) * arr[3] / 255 + + (1 - arr[3]) * backgroundLum + : 0; + } + function random() { + return stringify([ + Math.round(Math.random() * 255), + Math.round(Math.random() * 255), + Math.round(Math.random() * 255) + ], 'rgb'); + } + + var color = /*#__PURE__*/Object.freeze({ + __proto__: null, + parse: parse, + lift: lift, + toHex: toHex, + fastLerp: fastLerp, + fastMapToColor: fastMapToColor, + lerp: lerp$1, + mapToColor: mapToColor, + modifyHSL: modifyHSL, + modifyAlpha: modifyAlpha, + stringify: stringify, + lum: lum, + random: random + }); + + var mathRound = Math.round; + function normalizeColor(color) { + var opacity; + if (!color || color === 'transparent') { + color = 'none'; + } + else if (typeof color === 'string' && color.indexOf('rgba') > -1) { + var arr = parse(color); + if (arr) { + color = 'rgb(' + arr[0] + ',' + arr[1] + ',' + arr[2] + ')'; + opacity = arr[3]; + } + } + return { + color: color, + opacity: opacity == null ? 1 : opacity + }; + } + var EPSILON$1 = 1e-4; + function isAroundZero$1(transform) { + return transform < EPSILON$1 && transform > -EPSILON$1; + } + function round3(transform) { + return mathRound(transform * 1e3) / 1e3; + } + function round4(transform) { + return mathRound(transform * 1e4) / 1e4; + } + function getMatrixStr(m) { + return 'matrix(' + + round3(m[0]) + ',' + + round3(m[1]) + ',' + + round3(m[2]) + ',' + + round3(m[3]) + ',' + + round4(m[4]) + ',' + + round4(m[5]) + + ')'; + } + var TEXT_ALIGN_TO_ANCHOR = { + left: 'start', + right: 'end', + center: 'middle', + middle: 'middle' + }; + function adjustTextY(y, lineHeight, textBaseline) { + if (textBaseline === 'top') { + y += lineHeight / 2; + } + else if (textBaseline === 'bottom') { + y -= lineHeight / 2; + } + return y; + } + function hasShadow(style) { + return style + && (style.shadowBlur || style.shadowOffsetX || style.shadowOffsetY); + } + function getShadowKey(displayable) { + var style = displayable.style; + var globalScale = displayable.getGlobalScale(); + return [ + style.shadowColor, + (style.shadowBlur || 0).toFixed(2), + (style.shadowOffsetX || 0).toFixed(2), + (style.shadowOffsetY || 0).toFixed(2), + globalScale[0], + globalScale[1] + ].join(','); + } + function isImagePattern(val) { + return val && (!!val.image); + } + function isSVGPattern(val) { + return val && (!!val.svgElement); + } + function isPattern(val) { + return isImagePattern(val) || isSVGPattern(val); + } + function isLinearGradient(val) { + return val.type === 'linear'; + } + function isRadialGradient(val) { + return val.type === 'radial'; + } + function isGradient(val) { + return val && (val.type === 'linear' + || val.type === 'radial'); + } + function getIdURL(id) { + return "url(#" + id + ")"; + } + function getPathPrecision(el) { + var scale = el.getGlobalScale(); + var size = Math.max(scale[0], scale[1]); + return Math.max(Math.ceil(Math.log(size) / Math.log(10)), 1); + } + function getSRTTransformString(transform) { + var x = transform.x || 0; + var y = transform.y || 0; + var rotation = (transform.rotation || 0) * RADIAN_TO_DEGREE; + var scaleX = retrieve2(transform.scaleX, 1); + var scaleY = retrieve2(transform.scaleY, 1); + var skewX = transform.skewX || 0; + var skewY = transform.skewY || 0; + var res = []; + if (x || y) { + res.push("translate(" + x + "px," + y + "px)"); + } + if (rotation) { + res.push("rotate(" + rotation + ")"); + } + if (scaleX !== 1 || scaleY !== 1) { + res.push("scale(" + scaleX + "," + scaleY + ")"); + } + if (skewX || skewY) { + res.push("skew(" + mathRound(skewX * RADIAN_TO_DEGREE) + "deg, " + mathRound(skewY * RADIAN_TO_DEGREE) + "deg)"); + } + return res.join(' '); + } + var encodeBase64 = (function () { + if (env.hasGlobalWindow && isFunction(window.btoa)) { + return function (str) { + return window.btoa(unescape(str)); + }; + } + if (typeof Buffer !== 'undefined') { + return function (str) { + return Buffer.from(str).toString('base64'); + }; + } + return function (str) { + if ("development" !== 'production') { + logError('Base64 isn\'t natively supported in the current environment.'); + } + return null; + }; + })(); + + var arraySlice = Array.prototype.slice; + function interpolateNumber(p0, p1, percent) { + return (p1 - p0) * percent + p0; + } + function interpolate1DArray(out, p0, p1, percent) { + var len = p0.length; + for (var i = 0; i < len; i++) { + out[i] = interpolateNumber(p0[i], p1[i], percent); + } + return out; + } + function interpolate2DArray(out, p0, p1, percent) { + var len = p0.length; + var len2 = len && p0[0].length; + for (var i = 0; i < len; i++) { + if (!out[i]) { + out[i] = []; + } + for (var j = 0; j < len2; j++) { + out[i][j] = interpolateNumber(p0[i][j], p1[i][j], percent); + } + } + return out; + } + function add1DArray(out, p0, p1, sign) { + var len = p0.length; + for (var i = 0; i < len; i++) { + out[i] = p0[i] + p1[i] * sign; + } + return out; + } + function add2DArray(out, p0, p1, sign) { + var len = p0.length; + var len2 = len && p0[0].length; + for (var i = 0; i < len; i++) { + if (!out[i]) { + out[i] = []; + } + for (var j = 0; j < len2; j++) { + out[i][j] = p0[i][j] + p1[i][j] * sign; + } + } + return out; + } + function fillColorStops(val0, val1) { + var len0 = val0.length; + var len1 = val1.length; + var shorterArr = len0 > len1 ? val1 : val0; + var shorterLen = Math.min(len0, len1); + var last = shorterArr[shorterLen - 1] || { color: [0, 0, 0, 0], offset: 0 }; + for (var i = shorterLen; i < Math.max(len0, len1); i++) { + shorterArr.push({ + offset: last.offset, + color: last.color.slice() + }); + } + } + function fillArray(val0, val1, arrDim) { + var arr0 = val0; + var arr1 = val1; + if (!arr0.push || !arr1.push) { + return; + } + var arr0Len = arr0.length; + var arr1Len = arr1.length; + if (arr0Len !== arr1Len) { + var isPreviousLarger = arr0Len > arr1Len; + if (isPreviousLarger) { + arr0.length = arr1Len; + } + else { + for (var i = arr0Len; i < arr1Len; i++) { + arr0.push(arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])); + } + } + } + var len2 = arr0[0] && arr0[0].length; + for (var i = 0; i < arr0.length; i++) { + if (arrDim === 1) { + if (isNaN(arr0[i])) { + arr0[i] = arr1[i]; + } + } + else { + for (var j = 0; j < len2; j++) { + if (isNaN(arr0[i][j])) { + arr0[i][j] = arr1[i][j]; + } + } + } + } + } + function cloneValue(value) { + if (isArrayLike(value)) { + var len = value.length; + if (isArrayLike(value[0])) { + var ret = []; + for (var i = 0; i < len; i++) { + ret.push(arraySlice.call(value[i])); + } + return ret; + } + return arraySlice.call(value); + } + return value; + } + function rgba2String(rgba) { + rgba[0] = Math.floor(rgba[0]) || 0; + rgba[1] = Math.floor(rgba[1]) || 0; + rgba[2] = Math.floor(rgba[2]) || 0; + rgba[3] = rgba[3] == null ? 1 : rgba[3]; + return 'rgba(' + rgba.join(',') + ')'; + } + function guessArrayDim(value) { + return isArrayLike(value && value[0]) ? 2 : 1; + } + var VALUE_TYPE_NUMBER = 0; + var VALUE_TYPE_1D_ARRAY = 1; + var VALUE_TYPE_2D_ARRAY = 2; + var VALUE_TYPE_COLOR = 3; + var VALUE_TYPE_LINEAR_GRADIENT = 4; + var VALUE_TYPE_RADIAL_GRADIENT = 5; + var VALUE_TYPE_UNKOWN = 6; + function isGradientValueType(valType) { + return valType === VALUE_TYPE_LINEAR_GRADIENT || valType === VALUE_TYPE_RADIAL_GRADIENT; + } + function isArrayValueType(valType) { + return valType === VALUE_TYPE_1D_ARRAY || valType === VALUE_TYPE_2D_ARRAY; + } + var tmpRgba = [0, 0, 0, 0]; + var Track = (function () { + function Track(propName) { + this.keyframes = []; + this.discrete = false; + this._invalid = false; + this._needsSort = false; + this._lastFr = 0; + this._lastFrP = 0; + this.propName = propName; + } + Track.prototype.isFinished = function () { + return this._finished; + }; + Track.prototype.setFinished = function () { + this._finished = true; + if (this._additiveTrack) { + this._additiveTrack.setFinished(); + } + }; + Track.prototype.needsAnimate = function () { + return this.keyframes.length >= 1; + }; + Track.prototype.getAdditiveTrack = function () { + return this._additiveTrack; + }; + Track.prototype.addKeyframe = function (time, rawValue, easing) { + this._needsSort = true; + var keyframes = this.keyframes; + var len = keyframes.length; + var discrete = false; + var valType = VALUE_TYPE_UNKOWN; + var value = rawValue; + if (isArrayLike(rawValue)) { + var arrayDim = guessArrayDim(rawValue); + valType = arrayDim; + if (arrayDim === 1 && !isNumber(rawValue[0]) + || arrayDim === 2 && !isNumber(rawValue[0][0])) { + discrete = true; + } + } + else { + if (isNumber(rawValue) && !eqNaN(rawValue)) { + valType = VALUE_TYPE_NUMBER; + } + else if (isString(rawValue)) { + if (!isNaN(+rawValue)) { + valType = VALUE_TYPE_NUMBER; + } + else { + var colorArray = parse(rawValue); + if (colorArray) { + value = colorArray; + valType = VALUE_TYPE_COLOR; + } + } + } + else if (isGradientObject(rawValue)) { + var parsedGradient = extend({}, value); + parsedGradient.colorStops = map(rawValue.colorStops, function (colorStop) { return ({ + offset: colorStop.offset, + color: parse(colorStop.color) + }); }); + if (isLinearGradient(rawValue)) { + valType = VALUE_TYPE_LINEAR_GRADIENT; + } + else if (isRadialGradient(rawValue)) { + valType = VALUE_TYPE_RADIAL_GRADIENT; + } + value = parsedGradient; + } + } + if (len === 0) { + this.valType = valType; + } + else if (valType !== this.valType || valType === VALUE_TYPE_UNKOWN) { + discrete = true; + } + this.discrete = this.discrete || discrete; + var kf = { + time: time, + value: value, + rawValue: rawValue, + percent: 0 + }; + if (easing) { + kf.easing = easing; + kf.easingFunc = isFunction(easing) + ? easing + : easingFuncs[easing] || createCubicEasingFunc(easing); + } + keyframes.push(kf); + return kf; + }; + Track.prototype.prepare = function (maxTime, additiveTrack) { + var kfs = this.keyframes; + if (this._needsSort) { + kfs.sort(function (a, b) { + return a.time - b.time; + }); + } + var valType = this.valType; + var kfsLen = kfs.length; + var lastKf = kfs[kfsLen - 1]; + var isDiscrete = this.discrete; + var isArr = isArrayValueType(valType); + var isGradient = isGradientValueType(valType); + for (var i = 0; i < kfsLen; i++) { + var kf = kfs[i]; + var value = kf.value; + var lastValue = lastKf.value; + kf.percent = kf.time / maxTime; + if (!isDiscrete) { + if (isArr && i !== kfsLen - 1) { + fillArray(value, lastValue, valType); + } + else if (isGradient) { + fillColorStops(value.colorStops, lastValue.colorStops); + } + } + } + if (!isDiscrete + && valType !== VALUE_TYPE_RADIAL_GRADIENT + && additiveTrack + && this.needsAnimate() + && additiveTrack.needsAnimate() + && valType === additiveTrack.valType + && !additiveTrack._finished) { + this._additiveTrack = additiveTrack; + var startValue = kfs[0].value; + for (var i = 0; i < kfsLen; i++) { + if (valType === VALUE_TYPE_NUMBER) { + kfs[i].additiveValue = kfs[i].value - startValue; + } + else if (valType === VALUE_TYPE_COLOR) { + kfs[i].additiveValue = + add1DArray([], kfs[i].value, startValue, -1); + } + else if (isArrayValueType(valType)) { + kfs[i].additiveValue = valType === VALUE_TYPE_1D_ARRAY + ? add1DArray([], kfs[i].value, startValue, -1) + : add2DArray([], kfs[i].value, startValue, -1); + } + } + } + }; + Track.prototype.step = function (target, percent) { + if (this._finished) { + return; + } + if (this._additiveTrack && this._additiveTrack._finished) { + this._additiveTrack = null; + } + var isAdditive = this._additiveTrack != null; + var valueKey = isAdditive ? 'additiveValue' : 'value'; + var valType = this.valType; + var keyframes = this.keyframes; + var kfsNum = keyframes.length; + var propName = this.propName; + var isValueColor = valType === VALUE_TYPE_COLOR; + var frameIdx; + var lastFrame = this._lastFr; + var mathMin = Math.min; + var frame; + var nextFrame; + if (kfsNum === 1) { + frame = nextFrame = keyframes[0]; + } + else { + if (percent < 0) { + frameIdx = 0; + } + else if (percent < this._lastFrP) { + var start = mathMin(lastFrame + 1, kfsNum - 1); + for (frameIdx = start; frameIdx >= 0; frameIdx--) { + if (keyframes[frameIdx].percent <= percent) { + break; + } + } + frameIdx = mathMin(frameIdx, kfsNum - 2); + } + else { + for (frameIdx = lastFrame; frameIdx < kfsNum; frameIdx++) { + if (keyframes[frameIdx].percent > percent) { + break; + } + } + frameIdx = mathMin(frameIdx - 1, kfsNum - 2); + } + nextFrame = keyframes[frameIdx + 1]; + frame = keyframes[frameIdx]; + } + if (!(frame && nextFrame)) { + return; + } + this._lastFr = frameIdx; + this._lastFrP = percent; + var interval = (nextFrame.percent - frame.percent); + var w = interval === 0 ? 1 : mathMin((percent - frame.percent) / interval, 1); + if (nextFrame.easingFunc) { + w = nextFrame.easingFunc(w); + } + var targetArr = isAdditive ? this._additiveValue + : (isValueColor ? tmpRgba : target[propName]); + if ((isArrayValueType(valType) || isValueColor) && !targetArr) { + targetArr = this._additiveValue = []; + } + if (this.discrete) { + target[propName] = w < 1 ? frame.rawValue : nextFrame.rawValue; + } + else if (isArrayValueType(valType)) { + valType === VALUE_TYPE_1D_ARRAY + ? interpolate1DArray(targetArr, frame[valueKey], nextFrame[valueKey], w) + : interpolate2DArray(targetArr, frame[valueKey], nextFrame[valueKey], w); + } + else if (isGradientValueType(valType)) { + var val = frame[valueKey]; + var nextVal_1 = nextFrame[valueKey]; + var isLinearGradient_1 = valType === VALUE_TYPE_LINEAR_GRADIENT; + target[propName] = { + type: isLinearGradient_1 ? 'linear' : 'radial', + x: interpolateNumber(val.x, nextVal_1.x, w), + y: interpolateNumber(val.y, nextVal_1.y, w), + colorStops: map(val.colorStops, function (colorStop, idx) { + var nextColorStop = nextVal_1.colorStops[idx]; + return { + offset: interpolateNumber(colorStop.offset, nextColorStop.offset, w), + color: rgba2String(interpolate1DArray([], colorStop.color, nextColorStop.color, w)) + }; + }), + global: nextVal_1.global + }; + if (isLinearGradient_1) { + target[propName].x2 = interpolateNumber(val.x2, nextVal_1.x2, w); + target[propName].y2 = interpolateNumber(val.y2, nextVal_1.y2, w); + } + else { + target[propName].r = interpolateNumber(val.r, nextVal_1.r, w); + } + } + else if (isValueColor) { + interpolate1DArray(targetArr, frame[valueKey], nextFrame[valueKey], w); + if (!isAdditive) { + target[propName] = rgba2String(targetArr); + } + } + else { + var value = interpolateNumber(frame[valueKey], nextFrame[valueKey], w); + if (isAdditive) { + this._additiveValue = value; + } + else { + target[propName] = value; + } + } + if (isAdditive) { + this._addToTarget(target); + } + }; + Track.prototype._addToTarget = function (target) { + var valType = this.valType; + var propName = this.propName; + var additiveValue = this._additiveValue; + if (valType === VALUE_TYPE_NUMBER) { + target[propName] = target[propName] + additiveValue; + } + else if (valType === VALUE_TYPE_COLOR) { + parse(target[propName], tmpRgba); + add1DArray(tmpRgba, tmpRgba, additiveValue, 1); + target[propName] = rgba2String(tmpRgba); + } + else if (valType === VALUE_TYPE_1D_ARRAY) { + add1DArray(target[propName], target[propName], additiveValue, 1); + } + else if (valType === VALUE_TYPE_2D_ARRAY) { + add2DArray(target[propName], target[propName], additiveValue, 1); + } + }; + return Track; + }()); + var Animator = (function () { + function Animator(target, loop, allowDiscreteAnimation, additiveTo) { + this._tracks = {}; + this._trackKeys = []; + this._maxTime = 0; + this._started = 0; + this._clip = null; + this._target = target; + this._loop = loop; + if (loop && additiveTo) { + logError('Can\' use additive animation on looped animation.'); + return; + } + this._additiveAnimators = additiveTo; + this._allowDiscrete = allowDiscreteAnimation; + } + Animator.prototype.getMaxTime = function () { + return this._maxTime; + }; + Animator.prototype.getDelay = function () { + return this._delay; + }; + Animator.prototype.getLoop = function () { + return this._loop; + }; + Animator.prototype.getTarget = function () { + return this._target; + }; + Animator.prototype.changeTarget = function (target) { + this._target = target; + }; + Animator.prototype.when = function (time, props, easing) { + return this.whenWithKeys(time, props, keys(props), easing); + }; + Animator.prototype.whenWithKeys = function (time, props, propNames, easing) { + var tracks = this._tracks; + for (var i = 0; i < propNames.length; i++) { + var propName = propNames[i]; + var track = tracks[propName]; + if (!track) { + track = tracks[propName] = new Track(propName); + var initialValue = void 0; + var additiveTrack = this._getAdditiveTrack(propName); + if (additiveTrack) { + var addtiveTrackKfs = additiveTrack.keyframes; + var lastFinalKf = addtiveTrackKfs[addtiveTrackKfs.length - 1]; + initialValue = lastFinalKf && lastFinalKf.value; + if (additiveTrack.valType === VALUE_TYPE_COLOR && initialValue) { + initialValue = rgba2String(initialValue); + } + } + else { + initialValue = this._target[propName]; + } + if (initialValue == null) { + continue; + } + if (time > 0) { + track.addKeyframe(0, cloneValue(initialValue), easing); + } + this._trackKeys.push(propName); + } + track.addKeyframe(time, cloneValue(props[propName]), easing); + } + this._maxTime = Math.max(this._maxTime, time); + return this; + }; + Animator.prototype.pause = function () { + this._clip.pause(); + this._paused = true; + }; + Animator.prototype.resume = function () { + this._clip.resume(); + this._paused = false; + }; + Animator.prototype.isPaused = function () { + return !!this._paused; + }; + Animator.prototype.duration = function (duration) { + this._maxTime = duration; + this._force = true; + return this; + }; + Animator.prototype._doneCallback = function () { + this._setTracksFinished(); + this._clip = null; + var doneList = this._doneCbs; + if (doneList) { + var len = doneList.length; + for (var i = 0; i < len; i++) { + doneList[i].call(this); + } + } + }; + Animator.prototype._abortedCallback = function () { + this._setTracksFinished(); + var animation = this.animation; + var abortedList = this._abortedCbs; + if (animation) { + animation.removeClip(this._clip); + } + this._clip = null; + if (abortedList) { + for (var i = 0; i < abortedList.length; i++) { + abortedList[i].call(this); + } + } + }; + Animator.prototype._setTracksFinished = function () { + var tracks = this._tracks; + var tracksKeys = this._trackKeys; + for (var i = 0; i < tracksKeys.length; i++) { + tracks[tracksKeys[i]].setFinished(); + } + }; + Animator.prototype._getAdditiveTrack = function (trackName) { + var additiveTrack; + var additiveAnimators = this._additiveAnimators; + if (additiveAnimators) { + for (var i = 0; i < additiveAnimators.length; i++) { + var track = additiveAnimators[i].getTrack(trackName); + if (track) { + additiveTrack = track; + } + } + } + return additiveTrack; + }; + Animator.prototype.start = function (easing) { + if (this._started > 0) { + return; + } + this._started = 1; + var self = this; + var tracks = []; + var maxTime = this._maxTime || 0; + for (var i = 0; i < this._trackKeys.length; i++) { + var propName = this._trackKeys[i]; + var track = this._tracks[propName]; + var additiveTrack = this._getAdditiveTrack(propName); + var kfs = track.keyframes; + var kfsNum = kfs.length; + track.prepare(maxTime, additiveTrack); + if (track.needsAnimate()) { + if (!this._allowDiscrete && track.discrete) { + var lastKf = kfs[kfsNum - 1]; + if (lastKf) { + self._target[track.propName] = lastKf.rawValue; + } + track.setFinished(); + } + else { + tracks.push(track); + } + } + } + if (tracks.length || this._force) { + var clip = new Clip({ + life: maxTime, + loop: this._loop, + delay: this._delay || 0, + onframe: function (percent) { + self._started = 2; + var additiveAnimators = self._additiveAnimators; + if (additiveAnimators) { + var stillHasAdditiveAnimator = false; + for (var i = 0; i < additiveAnimators.length; i++) { + if (additiveAnimators[i]._clip) { + stillHasAdditiveAnimator = true; + break; + } + } + if (!stillHasAdditiveAnimator) { + self._additiveAnimators = null; + } + } + for (var i = 0; i < tracks.length; i++) { + tracks[i].step(self._target, percent); + } + var onframeList = self._onframeCbs; + if (onframeList) { + for (var i = 0; i < onframeList.length; i++) { + onframeList[i](self._target, percent); + } + } + }, + ondestroy: function () { + self._doneCallback(); + } + }); + this._clip = clip; + if (this.animation) { + this.animation.addClip(clip); + } + if (easing) { + clip.setEasing(easing); + } + } + else { + this._doneCallback(); + } + return this; + }; + Animator.prototype.stop = function (forwardToLast) { + if (!this._clip) { + return; + } + var clip = this._clip; + if (forwardToLast) { + clip.onframe(1); + } + this._abortedCallback(); + }; + Animator.prototype.delay = function (time) { + this._delay = time; + return this; + }; + Animator.prototype.during = function (cb) { + if (cb) { + if (!this._onframeCbs) { + this._onframeCbs = []; + } + this._onframeCbs.push(cb); + } + return this; + }; + Animator.prototype.done = function (cb) { + if (cb) { + if (!this._doneCbs) { + this._doneCbs = []; + } + this._doneCbs.push(cb); + } + return this; + }; + Animator.prototype.aborted = function (cb) { + if (cb) { + if (!this._abortedCbs) { + this._abortedCbs = []; + } + this._abortedCbs.push(cb); + } + return this; + }; + Animator.prototype.getClip = function () { + return this._clip; + }; + Animator.prototype.getTrack = function (propName) { + return this._tracks[propName]; + }; + Animator.prototype.getTracks = function () { + var _this = this; + return map(this._trackKeys, function (key) { return _this._tracks[key]; }); + }; + Animator.prototype.stopTracks = function (propNames, forwardToLast) { + if (!propNames.length || !this._clip) { + return true; + } + var tracks = this._tracks; + var tracksKeys = this._trackKeys; + for (var i = 0; i < propNames.length; i++) { + var track = tracks[propNames[i]]; + if (track && !track.isFinished()) { + if (forwardToLast) { + track.step(this._target, 1); + } + else if (this._started === 1) { + track.step(this._target, 0); + } + track.setFinished(); + } + } + var allAborted = true; + for (var i = 0; i < tracksKeys.length; i++) { + if (!tracks[tracksKeys[i]].isFinished()) { + allAborted = false; + break; + } + } + if (allAborted) { + this._abortedCallback(); + } + return allAborted; + }; + Animator.prototype.saveTo = function (target, trackKeys, firstOrLast) { + if (!target) { + return; + } + trackKeys = trackKeys || this._trackKeys; + for (var i = 0; i < trackKeys.length; i++) { + var propName = trackKeys[i]; + var track = this._tracks[propName]; + if (!track || track.isFinished()) { + continue; + } + var kfs = track.keyframes; + var kf = kfs[firstOrLast ? 0 : kfs.length - 1]; + if (kf) { + target[propName] = cloneValue(kf.rawValue); + } + } + }; + Animator.prototype.__changeFinalValue = function (finalProps, trackKeys) { + trackKeys = trackKeys || keys(finalProps); + for (var i = 0; i < trackKeys.length; i++) { + var propName = trackKeys[i]; + var track = this._tracks[propName]; + if (!track) { + continue; + } + var kfs = track.keyframes; + if (kfs.length > 1) { + var lastKf = kfs.pop(); + track.addKeyframe(lastKf.time, finalProps[propName]); + track.prepare(this._maxTime, track.getAdditiveTrack()); + } + } + }; + return Animator; + }()); + + function getTime() { + return new Date().getTime(); + } + var Animation = (function (_super) { + __extends(Animation, _super); + function Animation(opts) { + var _this = _super.call(this) || this; + _this._running = false; + _this._time = 0; + _this._pausedTime = 0; + _this._pauseStart = 0; + _this._paused = false; + opts = opts || {}; + _this.stage = opts.stage || {}; + return _this; + } + Animation.prototype.addClip = function (clip) { + if (clip.animation) { + this.removeClip(clip); + } + if (!this._head) { + this._head = this._tail = clip; + } + else { + this._tail.next = clip; + clip.prev = this._tail; + clip.next = null; + this._tail = clip; + } + clip.animation = this; + }; + Animation.prototype.addAnimator = function (animator) { + animator.animation = this; + var clip = animator.getClip(); + if (clip) { + this.addClip(clip); + } + }; + Animation.prototype.removeClip = function (clip) { + if (!clip.animation) { + return; + } + var prev = clip.prev; + var next = clip.next; + if (prev) { + prev.next = next; + } + else { + this._head = next; + } + if (next) { + next.prev = prev; + } + else { + this._tail = prev; + } + clip.next = clip.prev = clip.animation = null; + }; + Animation.prototype.removeAnimator = function (animator) { + var clip = animator.getClip(); + if (clip) { + this.removeClip(clip); + } + animator.animation = null; + }; + Animation.prototype.update = function (notTriggerFrameAndStageUpdate) { + var time = getTime() - this._pausedTime; + var delta = time - this._time; + var clip = this._head; + while (clip) { + var nextClip = clip.next; + var finished = clip.step(time, delta); + if (finished) { + clip.ondestroy(); + this.removeClip(clip); + clip = nextClip; + } + else { + clip = nextClip; + } + } + this._time = time; + if (!notTriggerFrameAndStageUpdate) { + this.trigger('frame', delta); + this.stage.update && this.stage.update(); + } + }; + Animation.prototype._startLoop = function () { + var self = this; + this._running = true; + function step() { + if (self._running) { + requestAnimationFrame$1(step); + !self._paused && self.update(); + } + } + requestAnimationFrame$1(step); + }; + Animation.prototype.start = function () { + if (this._running) { + return; + } + this._time = getTime(); + this._pausedTime = 0; + this._startLoop(); + }; + Animation.prototype.stop = function () { + this._running = false; + }; + Animation.prototype.pause = function () { + if (!this._paused) { + this._pauseStart = getTime(); + this._paused = true; + } + }; + Animation.prototype.resume = function () { + if (this._paused) { + this._pausedTime += getTime() - this._pauseStart; + this._paused = false; + } + }; + Animation.prototype.clear = function () { + var clip = this._head; + while (clip) { + var nextClip = clip.next; + clip.prev = clip.next = clip.animation = null; + clip = nextClip; + } + this._head = this._tail = null; + }; + Animation.prototype.isFinished = function () { + return this._head == null; + }; + Animation.prototype.animate = function (target, options) { + options = options || {}; + this.start(); + var animator = new Animator(target, options.loop); + this.addAnimator(animator); + return animator; + }; + return Animation; + }(Eventful)); + + var TOUCH_CLICK_DELAY = 300; + var globalEventSupported = env.domSupported; + var localNativeListenerNames = (function () { + var mouseHandlerNames = [ + 'click', 'dblclick', 'mousewheel', 'wheel', 'mouseout', + 'mouseup', 'mousedown', 'mousemove', 'contextmenu' + ]; + var touchHandlerNames = [ + 'touchstart', 'touchend', 'touchmove' + ]; + var pointerEventNameMap = { + pointerdown: 1, pointerup: 1, pointermove: 1, pointerout: 1 + }; + var pointerHandlerNames = map(mouseHandlerNames, function (name) { + var nm = name.replace('mouse', 'pointer'); + return pointerEventNameMap.hasOwnProperty(nm) ? nm : name; + }); + return { + mouse: mouseHandlerNames, + touch: touchHandlerNames, + pointer: pointerHandlerNames + }; + })(); + var globalNativeListenerNames = { + mouse: ['mousemove', 'mouseup'], + pointer: ['pointermove', 'pointerup'] + }; + var wheelEventSupported = false; + function isPointerFromTouch(event) { + var pointerType = event.pointerType; + return pointerType === 'pen' || pointerType === 'touch'; + } + function setTouchTimer(scope) { + scope.touching = true; + if (scope.touchTimer != null) { + clearTimeout(scope.touchTimer); + scope.touchTimer = null; + } + scope.touchTimer = setTimeout(function () { + scope.touching = false; + scope.touchTimer = null; + }, 700); + } + function markTouch(event) { + event && (event.zrByTouch = true); + } + function normalizeGlobalEvent(instance, event) { + return normalizeEvent(instance.dom, new FakeGlobalEvent(instance, event), true); + } + function isLocalEl(instance, el) { + var elTmp = el; + var isLocal = false; + while (elTmp && elTmp.nodeType !== 9 + && !(isLocal = elTmp.domBelongToZr + || (elTmp !== el && elTmp === instance.painterRoot))) { + elTmp = elTmp.parentNode; + } + return isLocal; + } + var FakeGlobalEvent = (function () { + function FakeGlobalEvent(instance, event) { + this.stopPropagation = noop; + this.stopImmediatePropagation = noop; + this.preventDefault = noop; + this.type = event.type; + this.target = this.currentTarget = instance.dom; + this.pointerType = event.pointerType; + this.clientX = event.clientX; + this.clientY = event.clientY; + } + return FakeGlobalEvent; + }()); + var localDOMHandlers = { + mousedown: function (event) { + event = normalizeEvent(this.dom, event); + this.__mayPointerCapture = [event.zrX, event.zrY]; + this.trigger('mousedown', event); + }, + mousemove: function (event) { + event = normalizeEvent(this.dom, event); + var downPoint = this.__mayPointerCapture; + if (downPoint && (event.zrX !== downPoint[0] || event.zrY !== downPoint[1])) { + this.__togglePointerCapture(true); + } + this.trigger('mousemove', event); + }, + mouseup: function (event) { + event = normalizeEvent(this.dom, event); + this.__togglePointerCapture(false); + this.trigger('mouseup', event); + }, + mouseout: function (event) { + event = normalizeEvent(this.dom, event); + var element = event.toElement || event.relatedTarget; + if (!isLocalEl(this, element)) { + if (this.__pointerCapturing) { + event.zrEventControl = 'no_globalout'; + } + this.trigger('mouseout', event); + } + }, + wheel: function (event) { + wheelEventSupported = true; + event = normalizeEvent(this.dom, event); + this.trigger('mousewheel', event); + }, + mousewheel: function (event) { + if (wheelEventSupported) { + return; + } + event = normalizeEvent(this.dom, event); + this.trigger('mousewheel', event); + }, + touchstart: function (event) { + event = normalizeEvent(this.dom, event); + markTouch(event); + this.__lastTouchMoment = new Date(); + this.handler.processGesture(event, 'start'); + localDOMHandlers.mousemove.call(this, event); + localDOMHandlers.mousedown.call(this, event); + }, + touchmove: function (event) { + event = normalizeEvent(this.dom, event); + markTouch(event); + this.handler.processGesture(event, 'change'); + localDOMHandlers.mousemove.call(this, event); + }, + touchend: function (event) { + event = normalizeEvent(this.dom, event); + markTouch(event); + this.handler.processGesture(event, 'end'); + localDOMHandlers.mouseup.call(this, event); + if (+new Date() - (+this.__lastTouchMoment) < TOUCH_CLICK_DELAY) { + localDOMHandlers.click.call(this, event); + } + }, + pointerdown: function (event) { + localDOMHandlers.mousedown.call(this, event); + }, + pointermove: function (event) { + if (!isPointerFromTouch(event)) { + localDOMHandlers.mousemove.call(this, event); + } + }, + pointerup: function (event) { + localDOMHandlers.mouseup.call(this, event); + }, + pointerout: function (event) { + if (!isPointerFromTouch(event)) { + localDOMHandlers.mouseout.call(this, event); + } + } + }; + each(['click', 'dblclick', 'contextmenu'], function (name) { + localDOMHandlers[name] = function (event) { + event = normalizeEvent(this.dom, event); + this.trigger(name, event); + }; + }); + var globalDOMHandlers = { + pointermove: function (event) { + if (!isPointerFromTouch(event)) { + globalDOMHandlers.mousemove.call(this, event); + } + }, + pointerup: function (event) { + globalDOMHandlers.mouseup.call(this, event); + }, + mousemove: function (event) { + this.trigger('mousemove', event); + }, + mouseup: function (event) { + var pointerCaptureReleasing = this.__pointerCapturing; + this.__togglePointerCapture(false); + this.trigger('mouseup', event); + if (pointerCaptureReleasing) { + event.zrEventControl = 'only_globalout'; + this.trigger('mouseout', event); + } + } + }; + function mountLocalDOMEventListeners(instance, scope) { + var domHandlers = scope.domHandlers; + if (env.pointerEventsSupported) { + each(localNativeListenerNames.pointer, function (nativeEventName) { + mountSingleDOMEventListener(scope, nativeEventName, function (event) { + domHandlers[nativeEventName].call(instance, event); + }); + }); + } + else { + if (env.touchEventsSupported) { + each(localNativeListenerNames.touch, function (nativeEventName) { + mountSingleDOMEventListener(scope, nativeEventName, function (event) { + domHandlers[nativeEventName].call(instance, event); + setTouchTimer(scope); + }); + }); + } + each(localNativeListenerNames.mouse, function (nativeEventName) { + mountSingleDOMEventListener(scope, nativeEventName, function (event) { + event = getNativeEvent(event); + if (!scope.touching) { + domHandlers[nativeEventName].call(instance, event); + } + }); + }); + } + } + function mountGlobalDOMEventListeners(instance, scope) { + if (env.pointerEventsSupported) { + each(globalNativeListenerNames.pointer, mount); + } + else if (!env.touchEventsSupported) { + each(globalNativeListenerNames.mouse, mount); + } + function mount(nativeEventName) { + function nativeEventListener(event) { + event = getNativeEvent(event); + if (!isLocalEl(instance, event.target)) { + event = normalizeGlobalEvent(instance, event); + scope.domHandlers[nativeEventName].call(instance, event); + } + } + mountSingleDOMEventListener(scope, nativeEventName, nativeEventListener, { capture: true }); + } + } + function mountSingleDOMEventListener(scope, nativeEventName, listener, opt) { + scope.mounted[nativeEventName] = listener; + scope.listenerOpts[nativeEventName] = opt; + addEventListener(scope.domTarget, nativeEventName, listener, opt); + } + function unmountDOMEventListeners(scope) { + var mounted = scope.mounted; + for (var nativeEventName in mounted) { + if (mounted.hasOwnProperty(nativeEventName)) { + removeEventListener(scope.domTarget, nativeEventName, mounted[nativeEventName], scope.listenerOpts[nativeEventName]); + } + } + scope.mounted = {}; + } + var DOMHandlerScope = (function () { + function DOMHandlerScope(domTarget, domHandlers) { + this.mounted = {}; + this.listenerOpts = {}; + this.touching = false; + this.domTarget = domTarget; + this.domHandlers = domHandlers; + } + return DOMHandlerScope; + }()); + var HandlerDomProxy = (function (_super) { + __extends(HandlerDomProxy, _super); + function HandlerDomProxy(dom, painterRoot) { + var _this = _super.call(this) || this; + _this.__pointerCapturing = false; + _this.dom = dom; + _this.painterRoot = painterRoot; + _this._localHandlerScope = new DOMHandlerScope(dom, localDOMHandlers); + if (globalEventSupported) { + _this._globalHandlerScope = new DOMHandlerScope(document, globalDOMHandlers); + } + mountLocalDOMEventListeners(_this, _this._localHandlerScope); + return _this; + } + HandlerDomProxy.prototype.dispose = function () { + unmountDOMEventListeners(this._localHandlerScope); + if (globalEventSupported) { + unmountDOMEventListeners(this._globalHandlerScope); + } + }; + HandlerDomProxy.prototype.setCursor = function (cursorStyle) { + this.dom.style && (this.dom.style.cursor = cursorStyle || 'default'); + }; + HandlerDomProxy.prototype.__togglePointerCapture = function (isPointerCapturing) { + this.__mayPointerCapture = null; + if (globalEventSupported + && ((+this.__pointerCapturing) ^ (+isPointerCapturing))) { + this.__pointerCapturing = isPointerCapturing; + var globalHandlerScope = this._globalHandlerScope; + isPointerCapturing + ? mountGlobalDOMEventListeners(this, globalHandlerScope) + : unmountDOMEventListeners(globalHandlerScope); + } + }; + return HandlerDomProxy; + }(Eventful)); + + var dpr = 1; + if (env.hasGlobalWindow) { + dpr = Math.max(window.devicePixelRatio + || (window.screen && window.screen.deviceXDPI / window.screen.logicalXDPI) + || 1, 1); + } + var devicePixelRatio = dpr; + var DARK_MODE_THRESHOLD = 0.4; + var DARK_LABEL_COLOR = '#333'; + var LIGHT_LABEL_COLOR = '#ccc'; + var LIGHTER_LABEL_COLOR = '#eee'; + + function create$1() { + return [1, 0, 0, 1, 0, 0]; + } + function identity(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; + } + function copy$1(out, m) { + out[0] = m[0]; + out[1] = m[1]; + out[2] = m[2]; + out[3] = m[3]; + out[4] = m[4]; + out[5] = m[5]; + return out; + } + function mul$1(out, m1, m2) { + var out0 = m1[0] * m2[0] + m1[2] * m2[1]; + var out1 = m1[1] * m2[0] + m1[3] * m2[1]; + var out2 = m1[0] * m2[2] + m1[2] * m2[3]; + var out3 = m1[1] * m2[2] + m1[3] * m2[3]; + var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4]; + var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5]; + out[0] = out0; + out[1] = out1; + out[2] = out2; + out[3] = out3; + out[4] = out4; + out[5] = out5; + return out; + } + function translate(out, a, v) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4] + v[0]; + out[5] = a[5] + v[1]; + return out; + } + function rotate(out, a, rad) { + var aa = a[0]; + var ac = a[2]; + var atx = a[4]; + var ab = a[1]; + var ad = a[3]; + var aty = a[5]; + var st = Math.sin(rad); + var ct = Math.cos(rad); + out[0] = aa * ct + ab * st; + out[1] = -aa * st + ab * ct; + out[2] = ac * ct + ad * st; + out[3] = -ac * st + ct * ad; + out[4] = ct * atx + st * aty; + out[5] = ct * aty - st * atx; + return out; + } + function scale$1(out, a, v) { + var vx = v[0]; + var vy = v[1]; + out[0] = a[0] * vx; + out[1] = a[1] * vy; + out[2] = a[2] * vx; + out[3] = a[3] * vy; + out[4] = a[4] * vx; + out[5] = a[5] * vy; + return out; + } + function invert(out, a) { + var aa = a[0]; + var ac = a[2]; + var atx = a[4]; + var ab = a[1]; + var ad = a[3]; + var aty = a[5]; + var det = aa * ad - ab * ac; + if (!det) { + return null; + } + det = 1.0 / det; + out[0] = ad * det; + out[1] = -ab * det; + out[2] = -ac * det; + out[3] = aa * det; + out[4] = (ac * aty - ad * atx) * det; + out[5] = (ab * atx - aa * aty) * det; + return out; + } + function clone$2(a) { + var b = create$1(); + copy$1(b, a); + return b; + } + + var matrix = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$1, + identity: identity, + copy: copy$1, + mul: mul$1, + translate: translate, + rotate: rotate, + scale: scale$1, + invert: invert, + clone: clone$2 + }); + + var mIdentity = identity; + var EPSILON$2 = 5e-5; + function isNotAroundZero$1(val) { + return val > EPSILON$2 || val < -EPSILON$2; + } + var scaleTmp = []; + var tmpTransform = []; + var originTransform = create$1(); + var abs = Math.abs; + var Transformable = (function () { + function Transformable() { + } + Transformable.prototype.getLocalTransform = function (m) { + return Transformable.getLocalTransform(this, m); + }; + Transformable.prototype.setPosition = function (arr) { + this.x = arr[0]; + this.y = arr[1]; + }; + Transformable.prototype.setScale = function (arr) { + this.scaleX = arr[0]; + this.scaleY = arr[1]; + }; + Transformable.prototype.setSkew = function (arr) { + this.skewX = arr[0]; + this.skewY = arr[1]; + }; + Transformable.prototype.setOrigin = function (arr) { + this.originX = arr[0]; + this.originY = arr[1]; + }; + Transformable.prototype.needLocalTransform = function () { + return isNotAroundZero$1(this.rotation) + || isNotAroundZero$1(this.x) + || isNotAroundZero$1(this.y) + || isNotAroundZero$1(this.scaleX - 1) + || isNotAroundZero$1(this.scaleY - 1) + || isNotAroundZero$1(this.skewX) + || isNotAroundZero$1(this.skewY); + }; + Transformable.prototype.updateTransform = function () { + var parentTransform = this.parent && this.parent.transform; + var needLocalTransform = this.needLocalTransform(); + var m = this.transform; + if (!(needLocalTransform || parentTransform)) { + m && mIdentity(m); + return; + } + m = m || create$1(); + if (needLocalTransform) { + this.getLocalTransform(m); + } + else { + mIdentity(m); + } + if (parentTransform) { + if (needLocalTransform) { + mul$1(m, parentTransform, m); + } + else { + copy$1(m, parentTransform); + } + } + this.transform = m; + this._resolveGlobalScaleRatio(m); + }; + Transformable.prototype._resolveGlobalScaleRatio = function (m) { + var globalScaleRatio = this.globalScaleRatio; + if (globalScaleRatio != null && globalScaleRatio !== 1) { + this.getGlobalScale(scaleTmp); + var relX = scaleTmp[0] < 0 ? -1 : 1; + var relY = scaleTmp[1] < 0 ? -1 : 1; + var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0; + var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0; + m[0] *= sx; + m[1] *= sx; + m[2] *= sy; + m[3] *= sy; + } + this.invTransform = this.invTransform || create$1(); + invert(this.invTransform, m); + }; + Transformable.prototype.getComputedTransform = function () { + var transformNode = this; + var ancestors = []; + while (transformNode) { + ancestors.push(transformNode); + transformNode = transformNode.parent; + } + while (transformNode = ancestors.pop()) { + transformNode.updateTransform(); + } + return this.transform; + }; + Transformable.prototype.setLocalTransform = function (m) { + if (!m) { + return; + } + var sx = m[0] * m[0] + m[1] * m[1]; + var sy = m[2] * m[2] + m[3] * m[3]; + var rotation = Math.atan2(m[1], m[0]); + var shearX = Math.PI / 2 + rotation - Math.atan2(m[3], m[2]); + sy = Math.sqrt(sy) * Math.cos(shearX); + sx = Math.sqrt(sx); + this.skewX = shearX; + this.skewY = 0; + this.rotation = -rotation; + this.x = +m[4]; + this.y = +m[5]; + this.scaleX = sx; + this.scaleY = sy; + this.originX = 0; + this.originY = 0; + }; + Transformable.prototype.decomposeTransform = function () { + if (!this.transform) { + return; + } + var parent = this.parent; + var m = this.transform; + if (parent && parent.transform) { + mul$1(tmpTransform, parent.invTransform, m); + m = tmpTransform; + } + var ox = this.originX; + var oy = this.originY; + if (ox || oy) { + originTransform[4] = ox; + originTransform[5] = oy; + mul$1(tmpTransform, m, originTransform); + tmpTransform[4] -= ox; + tmpTransform[5] -= oy; + m = tmpTransform; + } + this.setLocalTransform(m); + }; + Transformable.prototype.getGlobalScale = function (out) { + var m = this.transform; + out = out || []; + if (!m) { + out[0] = 1; + out[1] = 1; + return out; + } + out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]); + out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]); + if (m[0] < 0) { + out[0] = -out[0]; + } + if (m[3] < 0) { + out[1] = -out[1]; + } + return out; + }; + Transformable.prototype.transformCoordToLocal = function (x, y) { + var v2 = [x, y]; + var invTransform = this.invTransform; + if (invTransform) { + applyTransform(v2, v2, invTransform); + } + return v2; + }; + Transformable.prototype.transformCoordToGlobal = function (x, y) { + var v2 = [x, y]; + var transform = this.transform; + if (transform) { + applyTransform(v2, v2, transform); + } + return v2; + }; + Transformable.prototype.getLineScale = function () { + var m = this.transform; + return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10 + ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1])) + : 1; + }; + Transformable.prototype.copyTransform = function (source) { + copyTransform(this, source); + }; + Transformable.getLocalTransform = function (target, m) { + m = m || []; + var ox = target.originX || 0; + var oy = target.originY || 0; + var sx = target.scaleX; + var sy = target.scaleY; + var ax = target.anchorX; + var ay = target.anchorY; + var rotation = target.rotation || 0; + var x = target.x; + var y = target.y; + var skewX = target.skewX ? Math.tan(target.skewX) : 0; + var skewY = target.skewY ? Math.tan(-target.skewY) : 0; + if (ox || oy || ax || ay) { + var dx = ox + ax; + var dy = oy + ay; + m[4] = -dx * sx - skewX * dy * sy; + m[5] = -dy * sy - skewY * dx * sx; + } + else { + m[4] = m[5] = 0; + } + m[0] = sx; + m[3] = sy; + m[1] = skewY * sx; + m[2] = skewX * sy; + rotation && rotate(m, m, rotation); + m[4] += ox + x; + m[5] += oy + y; + return m; + }; + Transformable.initDefaultProps = (function () { + var proto = Transformable.prototype; + proto.scaleX = + proto.scaleY = + proto.globalScaleRatio = 1; + proto.x = + proto.y = + proto.originX = + proto.originY = + proto.skewX = + proto.skewY = + proto.rotation = + proto.anchorX = + proto.anchorY = 0; + })(); + return Transformable; + }()); + var TRANSFORMABLE_PROPS = [ + 'x', 'y', 'originX', 'originY', 'anchorX', 'anchorY', 'rotation', 'scaleX', 'scaleY', 'skewX', 'skewY' + ]; + function copyTransform(target, source) { + for (var i = 0; i < TRANSFORMABLE_PROPS.length; i++) { + var propName = TRANSFORMABLE_PROPS[i]; + target[propName] = source[propName]; + } + } + + var Point = (function () { + function Point(x, y) { + this.x = x || 0; + this.y = y || 0; + } + Point.prototype.copy = function (other) { + this.x = other.x; + this.y = other.y; + return this; + }; + Point.prototype.clone = function () { + return new Point(this.x, this.y); + }; + Point.prototype.set = function (x, y) { + this.x = x; + this.y = y; + return this; + }; + Point.prototype.equal = function (other) { + return other.x === this.x && other.y === this.y; + }; + Point.prototype.add = function (other) { + this.x += other.x; + this.y += other.y; + return this; + }; + Point.prototype.scale = function (scalar) { + this.x *= scalar; + this.y *= scalar; + }; + Point.prototype.scaleAndAdd = function (other, scalar) { + this.x += other.x * scalar; + this.y += other.y * scalar; + }; + Point.prototype.sub = function (other) { + this.x -= other.x; + this.y -= other.y; + return this; + }; + Point.prototype.dot = function (other) { + return this.x * other.x + this.y * other.y; + }; + Point.prototype.len = function () { + return Math.sqrt(this.x * this.x + this.y * this.y); + }; + Point.prototype.lenSquare = function () { + return this.x * this.x + this.y * this.y; + }; + Point.prototype.normalize = function () { + var len = this.len(); + this.x /= len; + this.y /= len; + return this; + }; + Point.prototype.distance = function (other) { + var dx = this.x - other.x; + var dy = this.y - other.y; + return Math.sqrt(dx * dx + dy * dy); + }; + Point.prototype.distanceSquare = function (other) { + var dx = this.x - other.x; + var dy = this.y - other.y; + return dx * dx + dy * dy; + }; + Point.prototype.negate = function () { + this.x = -this.x; + this.y = -this.y; + return this; + }; + Point.prototype.transform = function (m) { + if (!m) { + return; + } + var x = this.x; + var y = this.y; + this.x = m[0] * x + m[2] * y + m[4]; + this.y = m[1] * x + m[3] * y + m[5]; + return this; + }; + Point.prototype.toArray = function (out) { + out[0] = this.x; + out[1] = this.y; + return out; + }; + Point.prototype.fromArray = function (input) { + this.x = input[0]; + this.y = input[1]; + }; + Point.set = function (p, x, y) { + p.x = x; + p.y = y; + }; + Point.copy = function (p, p2) { + p.x = p2.x; + p.y = p2.y; + }; + Point.len = function (p) { + return Math.sqrt(p.x * p.x + p.y * p.y); + }; + Point.lenSquare = function (p) { + return p.x * p.x + p.y * p.y; + }; + Point.dot = function (p0, p1) { + return p0.x * p1.x + p0.y * p1.y; + }; + Point.add = function (out, p0, p1) { + out.x = p0.x + p1.x; + out.y = p0.y + p1.y; + }; + Point.sub = function (out, p0, p1) { + out.x = p0.x - p1.x; + out.y = p0.y - p1.y; + }; + Point.scale = function (out, p0, scalar) { + out.x = p0.x * scalar; + out.y = p0.y * scalar; + }; + Point.scaleAndAdd = function (out, p0, p1, scalar) { + out.x = p0.x + p1.x * scalar; + out.y = p0.y + p1.y * scalar; + }; + Point.lerp = function (out, p0, p1, t) { + var onet = 1 - t; + out.x = onet * p0.x + t * p1.x; + out.y = onet * p0.y + t * p1.y; + }; + return Point; + }()); + + var mathMin = Math.min; + var mathMax = Math.max; + var lt = new Point(); + var rb = new Point(); + var lb = new Point(); + var rt = new Point(); + var minTv = new Point(); + var maxTv = new Point(); + var BoundingRect = (function () { + function BoundingRect(x, y, width, height) { + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + BoundingRect.prototype.union = function (other) { + var x = mathMin(other.x, this.x); + var y = mathMin(other.y, this.y); + if (isFinite(this.x) && isFinite(this.width)) { + this.width = mathMax(other.x + other.width, this.x + this.width) - x; + } + else { + this.width = other.width; + } + if (isFinite(this.y) && isFinite(this.height)) { + this.height = mathMax(other.y + other.height, this.y + this.height) - y; + } + else { + this.height = other.height; + } + this.x = x; + this.y = y; + }; + BoundingRect.prototype.applyTransform = function (m) { + BoundingRect.applyTransform(this, this, m); + }; + BoundingRect.prototype.calculateTransform = function (b) { + var a = this; + var sx = b.width / a.width; + var sy = b.height / a.height; + var m = create$1(); + translate(m, m, [-a.x, -a.y]); + scale$1(m, m, [sx, sy]); + translate(m, m, [b.x, b.y]); + return m; + }; + BoundingRect.prototype.intersect = function (b, mtv) { + if (!b) { + return false; + } + if (!(b instanceof BoundingRect)) { + b = BoundingRect.create(b); + } + var a = this; + var ax0 = a.x; + var ax1 = a.x + a.width; + var ay0 = a.y; + var ay1 = a.y + a.height; + var bx0 = b.x; + var bx1 = b.x + b.width; + var by0 = b.y; + var by1 = b.y + b.height; + var overlap = !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0); + if (mtv) { + var dMin = Infinity; + var dMax = 0; + var d0 = Math.abs(ax1 - bx0); + var d1 = Math.abs(bx1 - ax0); + var d2 = Math.abs(ay1 - by0); + var d3 = Math.abs(by1 - ay0); + var dx = Math.min(d0, d1); + var dy = Math.min(d2, d3); + if (ax1 < bx0 || bx1 < ax0) { + if (dx > dMax) { + dMax = dx; + if (d0 < d1) { + Point.set(maxTv, -d0, 0); + } + else { + Point.set(maxTv, d1, 0); + } + } + } + else { + if (dx < dMin) { + dMin = dx; + if (d0 < d1) { + Point.set(minTv, d0, 0); + } + else { + Point.set(minTv, -d1, 0); + } + } + } + if (ay1 < by0 || by1 < ay0) { + if (dy > dMax) { + dMax = dy; + if (d2 < d3) { + Point.set(maxTv, 0, -d2); + } + else { + Point.set(maxTv, 0, d3); + } + } + } + else { + if (dx < dMin) { + dMin = dx; + if (d2 < d3) { + Point.set(minTv, 0, d2); + } + else { + Point.set(minTv, 0, -d3); + } + } + } + } + if (mtv) { + Point.copy(mtv, overlap ? minTv : maxTv); + } + return overlap; + }; + BoundingRect.prototype.contain = function (x, y) { + var rect = this; + return x >= rect.x + && x <= (rect.x + rect.width) + && y >= rect.y + && y <= (rect.y + rect.height); + }; + BoundingRect.prototype.clone = function () { + return new BoundingRect(this.x, this.y, this.width, this.height); + }; + BoundingRect.prototype.copy = function (other) { + BoundingRect.copy(this, other); + }; + BoundingRect.prototype.plain = function () { + return { + x: this.x, + y: this.y, + width: this.width, + height: this.height + }; + }; + BoundingRect.prototype.isFinite = function () { + return isFinite(this.x) + && isFinite(this.y) + && isFinite(this.width) + && isFinite(this.height); + }; + BoundingRect.prototype.isZero = function () { + return this.width === 0 || this.height === 0; + }; + BoundingRect.create = function (rect) { + return new BoundingRect(rect.x, rect.y, rect.width, rect.height); + }; + BoundingRect.copy = function (target, source) { + target.x = source.x; + target.y = source.y; + target.width = source.width; + target.height = source.height; + }; + BoundingRect.applyTransform = function (target, source, m) { + if (!m) { + if (target !== source) { + BoundingRect.copy(target, source); + } + return; + } + if (m[1] < 1e-5 && m[1] > -1e-5 && m[2] < 1e-5 && m[2] > -1e-5) { + var sx = m[0]; + var sy = m[3]; + var tx = m[4]; + var ty = m[5]; + target.x = source.x * sx + tx; + target.y = source.y * sy + ty; + target.width = source.width * sx; + target.height = source.height * sy; + if (target.width < 0) { + target.x += target.width; + target.width = -target.width; + } + if (target.height < 0) { + target.y += target.height; + target.height = -target.height; + } + return; + } + lt.x = lb.x = source.x; + lt.y = rt.y = source.y; + rb.x = rt.x = source.x + source.width; + rb.y = lb.y = source.y + source.height; + lt.transform(m); + rt.transform(m); + rb.transform(m); + lb.transform(m); + target.x = mathMin(lt.x, rb.x, lb.x, rt.x); + target.y = mathMin(lt.y, rb.y, lb.y, rt.y); + var maxX = mathMax(lt.x, rb.x, lb.x, rt.x); + var maxY = mathMax(lt.y, rb.y, lb.y, rt.y); + target.width = maxX - target.x; + target.height = maxY - target.y; + }; + return BoundingRect; + }()); + + var textWidthCache = {}; + function getWidth(text, font) { + font = font || DEFAULT_FONT; + var cacheOfFont = textWidthCache[font]; + if (!cacheOfFont) { + cacheOfFont = textWidthCache[font] = new LRU(500); + } + var width = cacheOfFont.get(text); + if (width == null) { + width = platformApi.measureText(text, font).width; + cacheOfFont.put(text, width); + } + return width; + } + function innerGetBoundingRect(text, font, textAlign, textBaseline) { + var width = getWidth(text, font); + var height = getLineHeight(font); + var x = adjustTextX(0, width, textAlign); + var y = adjustTextY$1(0, height, textBaseline); + var rect = new BoundingRect(x, y, width, height); + return rect; + } + function getBoundingRect(text, font, textAlign, textBaseline) { + var textLines = ((text || '') + '').split('\n'); + var len = textLines.length; + if (len === 1) { + return innerGetBoundingRect(textLines[0], font, textAlign, textBaseline); + } + else { + var uniondRect = new BoundingRect(0, 0, 0, 0); + for (var i = 0; i < textLines.length; i++) { + var rect = innerGetBoundingRect(textLines[i], font, textAlign, textBaseline); + i === 0 ? uniondRect.copy(rect) : uniondRect.union(rect); + } + return uniondRect; + } + } + function adjustTextX(x, width, textAlign) { + if (textAlign === 'right') { + x -= width; + } + else if (textAlign === 'center') { + x -= width / 2; + } + return x; + } + function adjustTextY$1(y, height, verticalAlign) { + if (verticalAlign === 'middle') { + y -= height / 2; + } + else if (verticalAlign === 'bottom') { + y -= height; + } + return y; + } + function getLineHeight(font) { + return getWidth('国', font); + } + function parsePercent(value, maxValue) { + if (typeof value === 'string') { + if (value.lastIndexOf('%') >= 0) { + return parseFloat(value) / 100 * maxValue; + } + return parseFloat(value); + } + return value; + } + function calculateTextPosition(out, opts, rect) { + var textPosition = opts.position || 'inside'; + var distance = opts.distance != null ? opts.distance : 5; + var height = rect.height; + var width = rect.width; + var halfHeight = height / 2; + var x = rect.x; + var y = rect.y; + var textAlign = 'left'; + var textVerticalAlign = 'top'; + if (textPosition instanceof Array) { + x += parsePercent(textPosition[0], rect.width); + y += parsePercent(textPosition[1], rect.height); + textAlign = null; + textVerticalAlign = null; + } + else { + switch (textPosition) { + case 'left': + x -= distance; + y += halfHeight; + textAlign = 'right'; + textVerticalAlign = 'middle'; + break; + case 'right': + x += distance + width; + y += halfHeight; + textVerticalAlign = 'middle'; + break; + case 'top': + x += width / 2; + y -= distance; + textAlign = 'center'; + textVerticalAlign = 'bottom'; + break; + case 'bottom': + x += width / 2; + y += height + distance; + textAlign = 'center'; + break; + case 'inside': + x += width / 2; + y += halfHeight; + textAlign = 'center'; + textVerticalAlign = 'middle'; + break; + case 'insideLeft': + x += distance; + y += halfHeight; + textVerticalAlign = 'middle'; + break; + case 'insideRight': + x += width - distance; + y += halfHeight; + textAlign = 'right'; + textVerticalAlign = 'middle'; + break; + case 'insideTop': + x += width / 2; + y += distance; + textAlign = 'center'; + break; + case 'insideBottom': + x += width / 2; + y += height - distance; + textAlign = 'center'; + textVerticalAlign = 'bottom'; + break; + case 'insideTopLeft': + x += distance; + y += distance; + break; + case 'insideTopRight': + x += width - distance; + y += distance; + textAlign = 'right'; + break; + case 'insideBottomLeft': + x += distance; + y += height - distance; + textVerticalAlign = 'bottom'; + break; + case 'insideBottomRight': + x += width - distance; + y += height - distance; + textAlign = 'right'; + textVerticalAlign = 'bottom'; + break; + } + } + out = out || {}; + out.x = x; + out.y = y; + out.align = textAlign; + out.verticalAlign = textVerticalAlign; + return out; + } + + var PRESERVED_NORMAL_STATE = '__zr_normal__'; + var PRIMARY_STATES_KEYS = TRANSFORMABLE_PROPS.concat(['ignore']); + var DEFAULT_ANIMATABLE_MAP = reduce(TRANSFORMABLE_PROPS, function (obj, key) { + obj[key] = true; + return obj; + }, { ignore: false }); + var tmpTextPosCalcRes = {}; + var tmpBoundingRect = new BoundingRect(0, 0, 0, 0); + var Element = (function () { + function Element(props) { + this.id = guid(); + this.animators = []; + this.currentStates = []; + this.states = {}; + this._init(props); + } + Element.prototype._init = function (props) { + this.attr(props); + }; + Element.prototype.drift = function (dx, dy, e) { + switch (this.draggable) { + case 'horizontal': + dy = 0; + break; + case 'vertical': + dx = 0; + break; + } + var m = this.transform; + if (!m) { + m = this.transform = [1, 0, 0, 1, 0, 0]; + } + m[4] += dx; + m[5] += dy; + this.decomposeTransform(); + this.markRedraw(); + }; + Element.prototype.beforeUpdate = function () { }; + Element.prototype.afterUpdate = function () { }; + Element.prototype.update = function () { + this.updateTransform(); + if (this.__dirty) { + this.updateInnerText(); + } + }; + Element.prototype.updateInnerText = function (forceUpdate) { + var textEl = this._textContent; + if (textEl && (!textEl.ignore || forceUpdate)) { + if (!this.textConfig) { + this.textConfig = {}; + } + var textConfig = this.textConfig; + var isLocal = textConfig.local; + var innerTransformable = textEl.innerTransformable; + var textAlign = void 0; + var textVerticalAlign = void 0; + var textStyleChanged = false; + innerTransformable.parent = isLocal ? this : null; + var innerOrigin = false; + innerTransformable.copyTransform(textEl); + if (textConfig.position != null) { + var layoutRect = tmpBoundingRect; + if (textConfig.layoutRect) { + layoutRect.copy(textConfig.layoutRect); + } + else { + layoutRect.copy(this.getBoundingRect()); + } + if (!isLocal) { + layoutRect.applyTransform(this.transform); + } + if (this.calculateTextPosition) { + this.calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect); + } + else { + calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect); + } + innerTransformable.x = tmpTextPosCalcRes.x; + innerTransformable.y = tmpTextPosCalcRes.y; + textAlign = tmpTextPosCalcRes.align; + textVerticalAlign = tmpTextPosCalcRes.verticalAlign; + var textOrigin = textConfig.origin; + if (textOrigin && textConfig.rotation != null) { + var relOriginX = void 0; + var relOriginY = void 0; + if (textOrigin === 'center') { + relOriginX = layoutRect.width * 0.5; + relOriginY = layoutRect.height * 0.5; + } + else { + relOriginX = parsePercent(textOrigin[0], layoutRect.width); + relOriginY = parsePercent(textOrigin[1], layoutRect.height); + } + innerOrigin = true; + innerTransformable.originX = -innerTransformable.x + relOriginX + (isLocal ? 0 : layoutRect.x); + innerTransformable.originY = -innerTransformable.y + relOriginY + (isLocal ? 0 : layoutRect.y); + } + } + if (textConfig.rotation != null) { + innerTransformable.rotation = textConfig.rotation; + } + var textOffset = textConfig.offset; + if (textOffset) { + innerTransformable.x += textOffset[0]; + innerTransformable.y += textOffset[1]; + if (!innerOrigin) { + innerTransformable.originX = -textOffset[0]; + innerTransformable.originY = -textOffset[1]; + } + } + var isInside = textConfig.inside == null + ? (typeof textConfig.position === 'string' && textConfig.position.indexOf('inside') >= 0) + : textConfig.inside; + var innerTextDefaultStyle = this._innerTextDefaultStyle || (this._innerTextDefaultStyle = {}); + var textFill = void 0; + var textStroke = void 0; + var autoStroke = void 0; + if (isInside && this.canBeInsideText()) { + textFill = textConfig.insideFill; + textStroke = textConfig.insideStroke; + if (textFill == null || textFill === 'auto') { + textFill = this.getInsideTextFill(); + } + if (textStroke == null || textStroke === 'auto') { + textStroke = this.getInsideTextStroke(textFill); + autoStroke = true; + } + } + else { + textFill = textConfig.outsideFill; + textStroke = textConfig.outsideStroke; + if (textFill == null || textFill === 'auto') { + textFill = this.getOutsideFill(); + } + if (textStroke == null || textStroke === 'auto') { + textStroke = this.getOutsideStroke(textFill); + autoStroke = true; + } + } + textFill = textFill || '#000'; + if (textFill !== innerTextDefaultStyle.fill + || textStroke !== innerTextDefaultStyle.stroke + || autoStroke !== innerTextDefaultStyle.autoStroke + || textAlign !== innerTextDefaultStyle.align + || textVerticalAlign !== innerTextDefaultStyle.verticalAlign) { + textStyleChanged = true; + innerTextDefaultStyle.fill = textFill; + innerTextDefaultStyle.stroke = textStroke; + innerTextDefaultStyle.autoStroke = autoStroke; + innerTextDefaultStyle.align = textAlign; + innerTextDefaultStyle.verticalAlign = textVerticalAlign; + textEl.setDefaultTextStyle(innerTextDefaultStyle); + } + textEl.__dirty |= REDRAW_BIT; + if (textStyleChanged) { + textEl.dirtyStyle(true); + } + } + }; + Element.prototype.canBeInsideText = function () { + return true; + }; + Element.prototype.getInsideTextFill = function () { + return '#fff'; + }; + Element.prototype.getInsideTextStroke = function (textFill) { + return '#000'; + }; + Element.prototype.getOutsideFill = function () { + return this.__zr && this.__zr.isDarkMode() ? LIGHT_LABEL_COLOR : DARK_LABEL_COLOR; + }; + Element.prototype.getOutsideStroke = function (textFill) { + var backgroundColor = this.__zr && this.__zr.getBackgroundColor(); + var colorArr = typeof backgroundColor === 'string' && parse(backgroundColor); + if (!colorArr) { + colorArr = [255, 255, 255, 1]; + } + var alpha = colorArr[3]; + var isDark = this.__zr.isDarkMode(); + for (var i = 0; i < 3; i++) { + colorArr[i] = colorArr[i] * alpha + (isDark ? 0 : 255) * (1 - alpha); + } + colorArr[3] = 1; + return stringify(colorArr, 'rgba'); + }; + Element.prototype.traverse = function (cb, context) { }; + Element.prototype.attrKV = function (key, value) { + if (key === 'textConfig') { + this.setTextConfig(value); + } + else if (key === 'textContent') { + this.setTextContent(value); + } + else if (key === 'clipPath') { + this.setClipPath(value); + } + else if (key === 'extra') { + this.extra = this.extra || {}; + extend(this.extra, value); + } + else { + this[key] = value; + } + }; + Element.prototype.hide = function () { + this.ignore = true; + this.markRedraw(); + }; + Element.prototype.show = function () { + this.ignore = false; + this.markRedraw(); + }; + Element.prototype.attr = function (keyOrObj, value) { + if (typeof keyOrObj === 'string') { + this.attrKV(keyOrObj, value); + } + else if (isObject(keyOrObj)) { + var obj = keyOrObj; + var keysArr = keys(obj); + for (var i = 0; i < keysArr.length; i++) { + var key = keysArr[i]; + this.attrKV(key, keyOrObj[key]); + } + } + this.markRedraw(); + return this; + }; + Element.prototype.saveCurrentToNormalState = function (toState) { + this._innerSaveToNormal(toState); + var normalState = this._normalState; + for (var i = 0; i < this.animators.length; i++) { + var animator = this.animators[i]; + var fromStateTransition = animator.__fromStateTransition; + if (animator.getLoop() || fromStateTransition && fromStateTransition !== PRESERVED_NORMAL_STATE) { + continue; + } + var targetName = animator.targetName; + var target = targetName + ? normalState[targetName] : normalState; + animator.saveTo(target); + } + }; + Element.prototype._innerSaveToNormal = function (toState) { + var normalState = this._normalState; + if (!normalState) { + normalState = this._normalState = {}; + } + if (toState.textConfig && !normalState.textConfig) { + normalState.textConfig = this.textConfig; + } + this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS); + }; + Element.prototype._savePrimaryToNormal = function (toState, normalState, primaryKeys) { + for (var i = 0; i < primaryKeys.length; i++) { + var key = primaryKeys[i]; + if (toState[key] != null && !(key in normalState)) { + normalState[key] = this[key]; + } + } + }; + Element.prototype.hasState = function () { + return this.currentStates.length > 0; + }; + Element.prototype.getState = function (name) { + return this.states[name]; + }; + Element.prototype.ensureState = function (name) { + var states = this.states; + if (!states[name]) { + states[name] = {}; + } + return states[name]; + }; + Element.prototype.clearStates = function (noAnimation) { + this.useState(PRESERVED_NORMAL_STATE, false, noAnimation); + }; + Element.prototype.useState = function (stateName, keepCurrentStates, noAnimation, forceUseHoverLayer) { + var toNormalState = stateName === PRESERVED_NORMAL_STATE; + var hasStates = this.hasState(); + if (!hasStates && toNormalState) { + return; + } + var currentStates = this.currentStates; + var animationCfg = this.stateTransition; + if (indexOf(currentStates, stateName) >= 0 && (keepCurrentStates || currentStates.length === 1)) { + return; + } + var state; + if (this.stateProxy && !toNormalState) { + state = this.stateProxy(stateName); + } + if (!state) { + state = (this.states && this.states[stateName]); + } + if (!state && !toNormalState) { + logError("State " + stateName + " not exists."); + return; + } + if (!toNormalState) { + this.saveCurrentToNormalState(state); + } + var useHoverLayer = !!((state && state.hoverLayer) || forceUseHoverLayer); + if (useHoverLayer) { + this._toggleHoverLayerFlag(true); + } + this._applyStateObj(stateName, state, this._normalState, keepCurrentStates, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg); + var textContent = this._textContent; + var textGuide = this._textGuide; + if (textContent) { + textContent.useState(stateName, keepCurrentStates, noAnimation, useHoverLayer); + } + if (textGuide) { + textGuide.useState(stateName, keepCurrentStates, noAnimation, useHoverLayer); + } + if (toNormalState) { + this.currentStates = []; + this._normalState = {}; + } + else { + if (!keepCurrentStates) { + this.currentStates = [stateName]; + } + else { + this.currentStates.push(stateName); + } + } + this._updateAnimationTargets(); + this.markRedraw(); + if (!useHoverLayer && this.__inHover) { + this._toggleHoverLayerFlag(false); + this.__dirty &= ~REDRAW_BIT; + } + return state; + }; + Element.prototype.useStates = function (states, noAnimation, forceUseHoverLayer) { + if (!states.length) { + this.clearStates(); + } + else { + var stateObjects = []; + var currentStates = this.currentStates; + var len = states.length; + var notChange = len === currentStates.length; + if (notChange) { + for (var i = 0; i < len; i++) { + if (states[i] !== currentStates[i]) { + notChange = false; + break; + } + } + } + if (notChange) { + return; + } + for (var i = 0; i < len; i++) { + var stateName = states[i]; + var stateObj = void 0; + if (this.stateProxy) { + stateObj = this.stateProxy(stateName, states); + } + if (!stateObj) { + stateObj = this.states[stateName]; + } + if (stateObj) { + stateObjects.push(stateObj); + } + } + var lastStateObj = stateObjects[len - 1]; + var useHoverLayer = !!((lastStateObj && lastStateObj.hoverLayer) || forceUseHoverLayer); + if (useHoverLayer) { + this._toggleHoverLayerFlag(true); + } + var mergedState = this._mergeStates(stateObjects); + var animationCfg = this.stateTransition; + this.saveCurrentToNormalState(mergedState); + this._applyStateObj(states.join(','), mergedState, this._normalState, false, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg); + var textContent = this._textContent; + var textGuide = this._textGuide; + if (textContent) { + textContent.useStates(states, noAnimation, useHoverLayer); + } + if (textGuide) { + textGuide.useStates(states, noAnimation, useHoverLayer); + } + this._updateAnimationTargets(); + this.currentStates = states.slice(); + this.markRedraw(); + if (!useHoverLayer && this.__inHover) { + this._toggleHoverLayerFlag(false); + this.__dirty &= ~REDRAW_BIT; + } + } + }; + Element.prototype._updateAnimationTargets = function () { + for (var i = 0; i < this.animators.length; i++) { + var animator = this.animators[i]; + if (animator.targetName) { + animator.changeTarget(this[animator.targetName]); + } + } + }; + Element.prototype.removeState = function (state) { + var idx = indexOf(this.currentStates, state); + if (idx >= 0) { + var currentStates = this.currentStates.slice(); + currentStates.splice(idx, 1); + this.useStates(currentStates); + } + }; + Element.prototype.replaceState = function (oldState, newState, forceAdd) { + var currentStates = this.currentStates.slice(); + var idx = indexOf(currentStates, oldState); + var newStateExists = indexOf(currentStates, newState) >= 0; + if (idx >= 0) { + if (!newStateExists) { + currentStates[idx] = newState; + } + else { + currentStates.splice(idx, 1); + } + } + else if (forceAdd && !newStateExists) { + currentStates.push(newState); + } + this.useStates(currentStates); + }; + Element.prototype.toggleState = function (state, enable) { + if (enable) { + this.useState(state, true); + } + else { + this.removeState(state); + } + }; + Element.prototype._mergeStates = function (states) { + var mergedState = {}; + var mergedTextConfig; + for (var i = 0; i < states.length; i++) { + var state = states[i]; + extend(mergedState, state); + if (state.textConfig) { + mergedTextConfig = mergedTextConfig || {}; + extend(mergedTextConfig, state.textConfig); + } + } + if (mergedTextConfig) { + mergedState.textConfig = mergedTextConfig; + } + return mergedState; + }; + Element.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) { + var needsRestoreToNormal = !(state && keepCurrentStates); + if (state && state.textConfig) { + this.textConfig = extend({}, keepCurrentStates ? this.textConfig : normalState.textConfig); + extend(this.textConfig, state.textConfig); + } + else if (needsRestoreToNormal) { + if (normalState.textConfig) { + this.textConfig = normalState.textConfig; + } + } + var transitionTarget = {}; + var hasTransition = false; + for (var i = 0; i < PRIMARY_STATES_KEYS.length; i++) { + var key = PRIMARY_STATES_KEYS[i]; + var propNeedsTransition = transition && DEFAULT_ANIMATABLE_MAP[key]; + if (state && state[key] != null) { + if (propNeedsTransition) { + hasTransition = true; + transitionTarget[key] = state[key]; + } + else { + this[key] = state[key]; + } + } + else if (needsRestoreToNormal) { + if (normalState[key] != null) { + if (propNeedsTransition) { + hasTransition = true; + transitionTarget[key] = normalState[key]; + } + else { + this[key] = normalState[key]; + } + } + } + } + if (!transition) { + for (var i = 0; i < this.animators.length; i++) { + var animator = this.animators[i]; + var targetName = animator.targetName; + if (!animator.getLoop()) { + animator.__changeFinalValue(targetName + ? (state || normalState)[targetName] + : (state || normalState)); + } + } + } + if (hasTransition) { + this._transitionState(stateName, transitionTarget, animationCfg); + } + }; + Element.prototype._attachComponent = function (componentEl) { + if (componentEl.__zr && !componentEl.__hostTarget) { + if ("development" !== 'production') { + throw new Error('Text element has been added to zrender.'); + } + return; + } + if (componentEl === this) { + if ("development" !== 'production') { + throw new Error('Recursive component attachment.'); + } + return; + } + var zr = this.__zr; + if (zr) { + componentEl.addSelfToZr(zr); + } + componentEl.__zr = zr; + componentEl.__hostTarget = this; + }; + Element.prototype._detachComponent = function (componentEl) { + if (componentEl.__zr) { + componentEl.removeSelfFromZr(componentEl.__zr); + } + componentEl.__zr = null; + componentEl.__hostTarget = null; + }; + Element.prototype.getClipPath = function () { + return this._clipPath; + }; + Element.prototype.setClipPath = function (clipPath) { + if (this._clipPath && this._clipPath !== clipPath) { + this.removeClipPath(); + } + this._attachComponent(clipPath); + this._clipPath = clipPath; + this.markRedraw(); + }; + Element.prototype.removeClipPath = function () { + var clipPath = this._clipPath; + if (clipPath) { + this._detachComponent(clipPath); + this._clipPath = null; + this.markRedraw(); + } + }; + Element.prototype.getTextContent = function () { + return this._textContent; + }; + Element.prototype.setTextContent = function (textEl) { + var previousTextContent = this._textContent; + if (previousTextContent === textEl) { + return; + } + if (previousTextContent && previousTextContent !== textEl) { + this.removeTextContent(); + } + if ("development" !== 'production') { + if (textEl.__zr && !textEl.__hostTarget) { + throw new Error('Text element has been added to zrender.'); + } + } + textEl.innerTransformable = new Transformable(); + this._attachComponent(textEl); + this._textContent = textEl; + this.markRedraw(); + }; + Element.prototype.setTextConfig = function (cfg) { + if (!this.textConfig) { + this.textConfig = {}; + } + extend(this.textConfig, cfg); + this.markRedraw(); + }; + Element.prototype.removeTextConfig = function () { + this.textConfig = null; + this.markRedraw(); + }; + Element.prototype.removeTextContent = function () { + var textEl = this._textContent; + if (textEl) { + textEl.innerTransformable = null; + this._detachComponent(textEl); + this._textContent = null; + this._innerTextDefaultStyle = null; + this.markRedraw(); + } + }; + Element.prototype.getTextGuideLine = function () { + return this._textGuide; + }; + Element.prototype.setTextGuideLine = function (guideLine) { + if (this._textGuide && this._textGuide !== guideLine) { + this.removeTextGuideLine(); + } + this._attachComponent(guideLine); + this._textGuide = guideLine; + this.markRedraw(); + }; + Element.prototype.removeTextGuideLine = function () { + var textGuide = this._textGuide; + if (textGuide) { + this._detachComponent(textGuide); + this._textGuide = null; + this.markRedraw(); + } + }; + Element.prototype.markRedraw = function () { + this.__dirty |= REDRAW_BIT; + var zr = this.__zr; + if (zr) { + if (this.__inHover) { + zr.refreshHover(); + } + else { + zr.refresh(); + } + } + if (this.__hostTarget) { + this.__hostTarget.markRedraw(); + } + }; + Element.prototype.dirty = function () { + this.markRedraw(); + }; + Element.prototype._toggleHoverLayerFlag = function (inHover) { + this.__inHover = inHover; + var textContent = this._textContent; + var textGuide = this._textGuide; + if (textContent) { + textContent.__inHover = inHover; + } + if (textGuide) { + textGuide.__inHover = inHover; + } + }; + Element.prototype.addSelfToZr = function (zr) { + if (this.__zr === zr) { + return; + } + this.__zr = zr; + var animators = this.animators; + if (animators) { + for (var i = 0; i < animators.length; i++) { + zr.animation.addAnimator(animators[i]); + } + } + if (this._clipPath) { + this._clipPath.addSelfToZr(zr); + } + if (this._textContent) { + this._textContent.addSelfToZr(zr); + } + if (this._textGuide) { + this._textGuide.addSelfToZr(zr); + } + }; + Element.prototype.removeSelfFromZr = function (zr) { + if (!this.__zr) { + return; + } + this.__zr = null; + var animators = this.animators; + if (animators) { + for (var i = 0; i < animators.length; i++) { + zr.animation.removeAnimator(animators[i]); + } + } + if (this._clipPath) { + this._clipPath.removeSelfFromZr(zr); + } + if (this._textContent) { + this._textContent.removeSelfFromZr(zr); + } + if (this._textGuide) { + this._textGuide.removeSelfFromZr(zr); + } + }; + Element.prototype.animate = function (key, loop, allowDiscreteAnimation) { + var target = key ? this[key] : this; + if ("development" !== 'production') { + if (!target) { + logError('Property "' + + key + + '" is not existed in element ' + + this.id); + return; + } + } + var animator = new Animator(target, loop, allowDiscreteAnimation); + key && (animator.targetName = key); + this.addAnimator(animator, key); + return animator; + }; + Element.prototype.addAnimator = function (animator, key) { + var zr = this.__zr; + var el = this; + animator.during(function () { + el.updateDuringAnimation(key); + }).done(function () { + var animators = el.animators; + var idx = indexOf(animators, animator); + if (idx >= 0) { + animators.splice(idx, 1); + } + }); + this.animators.push(animator); + if (zr) { + zr.animation.addAnimator(animator); + } + zr && zr.wakeUp(); + }; + Element.prototype.updateDuringAnimation = function (key) { + this.markRedraw(); + }; + Element.prototype.stopAnimation = function (scope, forwardToLast) { + var animators = this.animators; + var len = animators.length; + var leftAnimators = []; + for (var i = 0; i < len; i++) { + var animator = animators[i]; + if (!scope || scope === animator.scope) { + animator.stop(forwardToLast); + } + else { + leftAnimators.push(animator); + } + } + this.animators = leftAnimators; + return this; + }; + Element.prototype.animateTo = function (target, cfg, animationProps) { + animateTo(this, target, cfg, animationProps); + }; + Element.prototype.animateFrom = function (target, cfg, animationProps) { + animateTo(this, target, cfg, animationProps, true); + }; + Element.prototype._transitionState = function (stateName, target, cfg, animationProps) { + var animators = animateTo(this, target, cfg, animationProps); + for (var i = 0; i < animators.length; i++) { + animators[i].__fromStateTransition = stateName; + } + }; + Element.prototype.getBoundingRect = function () { + return null; + }; + Element.prototype.getPaintRect = function () { + return null; + }; + Element.initDefaultProps = (function () { + var elProto = Element.prototype; + elProto.type = 'element'; + elProto.name = ''; + elProto.ignore = + elProto.silent = + elProto.isGroup = + elProto.draggable = + elProto.dragging = + elProto.ignoreClip = + elProto.__inHover = false; + elProto.__dirty = REDRAW_BIT; + var logs = {}; + function logDeprecatedError(key, xKey, yKey) { + if (!logs[key + xKey + yKey]) { + console.warn("DEPRECATED: '" + key + "' has been deprecated. use '" + xKey + "', '" + yKey + "' instead"); + logs[key + xKey + yKey] = true; + } + } + function createLegacyProperty(key, privateKey, xKey, yKey) { + Object.defineProperty(elProto, key, { + get: function () { + if ("development" !== 'production') { + logDeprecatedError(key, xKey, yKey); + } + if (!this[privateKey]) { + var pos = this[privateKey] = []; + enhanceArray(this, pos); + } + return this[privateKey]; + }, + set: function (pos) { + if ("development" !== 'production') { + logDeprecatedError(key, xKey, yKey); + } + this[xKey] = pos[0]; + this[yKey] = pos[1]; + this[privateKey] = pos; + enhanceArray(this, pos); + } + }); + function enhanceArray(self, pos) { + Object.defineProperty(pos, 0, { + get: function () { + return self[xKey]; + }, + set: function (val) { + self[xKey] = val; + } + }); + Object.defineProperty(pos, 1, { + get: function () { + return self[yKey]; + }, + set: function (val) { + self[yKey] = val; + } + }); + } + } + if (Object.defineProperty) { + createLegacyProperty('position', '_legacyPos', 'x', 'y'); + createLegacyProperty('scale', '_legacyScale', 'scaleX', 'scaleY'); + createLegacyProperty('origin', '_legacyOrigin', 'originX', 'originY'); + } + })(); + return Element; + }()); + mixin(Element, Eventful); + mixin(Element, Transformable); + function animateTo(animatable, target, cfg, animationProps, reverse) { + cfg = cfg || {}; + var animators = []; + animateToShallow(animatable, '', animatable, target, cfg, animationProps, animators, reverse); + var finishCount = animators.length; + var doneHappened = false; + var cfgDone = cfg.done; + var cfgAborted = cfg.aborted; + var doneCb = function () { + doneHappened = true; + finishCount--; + if (finishCount <= 0) { + doneHappened + ? (cfgDone && cfgDone()) + : (cfgAborted && cfgAborted()); + } + }; + var abortedCb = function () { + finishCount--; + if (finishCount <= 0) { + doneHappened + ? (cfgDone && cfgDone()) + : (cfgAborted && cfgAborted()); + } + }; + if (!finishCount) { + cfgDone && cfgDone(); + } + if (animators.length > 0 && cfg.during) { + animators[0].during(function (target, percent) { + cfg.during(percent); + }); + } + for (var i = 0; i < animators.length; i++) { + var animator = animators[i]; + if (doneCb) { + animator.done(doneCb); + } + if (abortedCb) { + animator.aborted(abortedCb); + } + if (cfg.force) { + animator.duration(cfg.duration); + } + animator.start(cfg.easing); + } + return animators; + } + function copyArrShallow(source, target, len) { + for (var i = 0; i < len; i++) { + source[i] = target[i]; + } + } + function is2DArray(value) { + return isArrayLike(value[0]); + } + function copyValue(target, source, key) { + if (isArrayLike(source[key])) { + if (!isArrayLike(target[key])) { + target[key] = []; + } + if (isTypedArray(source[key])) { + var len = source[key].length; + if (target[key].length !== len) { + target[key] = new (source[key].constructor)(len); + copyArrShallow(target[key], source[key], len); + } + } + else { + var sourceArr = source[key]; + var targetArr = target[key]; + var len0 = sourceArr.length; + if (is2DArray(sourceArr)) { + var len1 = sourceArr[0].length; + for (var i = 0; i < len0; i++) { + if (!targetArr[i]) { + targetArr[i] = Array.prototype.slice.call(sourceArr[i]); + } + else { + copyArrShallow(targetArr[i], sourceArr[i], len1); + } + } + } + else { + copyArrShallow(targetArr, sourceArr, len0); + } + targetArr.length = sourceArr.length; + } + } + else { + target[key] = source[key]; + } + } + function isValueSame(val1, val2) { + return val1 === val2 + || isArrayLike(val1) && isArrayLike(val2) && is1DArraySame(val1, val2); + } + function is1DArraySame(arr0, arr1) { + var len = arr0.length; + if (len !== arr1.length) { + return false; + } + for (var i = 0; i < len; i++) { + if (arr0[i] !== arr1[i]) { + return false; + } + } + return true; + } + function animateToShallow(animatable, topKey, animateObj, target, cfg, animationProps, animators, reverse) { + var targetKeys = keys(target); + var duration = cfg.duration; + var delay = cfg.delay; + var additive = cfg.additive; + var setToFinal = cfg.setToFinal; + var animateAll = !isObject(animationProps); + var existsAnimators = animatable.animators; + var animationKeys = []; + for (var k = 0; k < targetKeys.length; k++) { + var innerKey = targetKeys[k]; + var targetVal = target[innerKey]; + if (targetVal != null && animateObj[innerKey] != null + && (animateAll || animationProps[innerKey])) { + if (isObject(targetVal) + && !isArrayLike(targetVal) + && !isGradientObject(targetVal)) { + if (topKey) { + if (!reverse) { + animateObj[innerKey] = targetVal; + animatable.updateDuringAnimation(topKey); + } + continue; + } + animateToShallow(animatable, innerKey, animateObj[innerKey], targetVal, cfg, animationProps && animationProps[innerKey], animators, reverse); + } + else { + animationKeys.push(innerKey); + } + } + else if (!reverse) { + animateObj[innerKey] = targetVal; + animatable.updateDuringAnimation(topKey); + animationKeys.push(innerKey); + } + } + var keyLen = animationKeys.length; + if (!additive && keyLen) { + for (var i = 0; i < existsAnimators.length; i++) { + var animator = existsAnimators[i]; + if (animator.targetName === topKey) { + var allAborted = animator.stopTracks(animationKeys); + if (allAborted) { + var idx = indexOf(existsAnimators, animator); + existsAnimators.splice(idx, 1); + } + } + } + } + if (!cfg.force) { + animationKeys = filter(animationKeys, function (key) { return !isValueSame(target[key], animateObj[key]); }); + keyLen = animationKeys.length; + } + if (keyLen > 0 + || (cfg.force && !animators.length)) { + var revertedSource = void 0; + var reversedTarget = void 0; + var sourceClone = void 0; + if (reverse) { + reversedTarget = {}; + if (setToFinal) { + revertedSource = {}; + } + for (var i = 0; i < keyLen; i++) { + var innerKey = animationKeys[i]; + reversedTarget[innerKey] = animateObj[innerKey]; + if (setToFinal) { + revertedSource[innerKey] = target[innerKey]; + } + else { + animateObj[innerKey] = target[innerKey]; + } + } + } + else if (setToFinal) { + sourceClone = {}; + for (var i = 0; i < keyLen; i++) { + var innerKey = animationKeys[i]; + sourceClone[innerKey] = cloneValue(animateObj[innerKey]); + copyValue(animateObj, target, innerKey); + } + } + var animator = new Animator(animateObj, false, false, additive ? filter(existsAnimators, function (animator) { return animator.targetName === topKey; }) : null); + animator.targetName = topKey; + if (cfg.scope) { + animator.scope = cfg.scope; + } + if (setToFinal && revertedSource) { + animator.whenWithKeys(0, revertedSource, animationKeys); + } + if (sourceClone) { + animator.whenWithKeys(0, sourceClone, animationKeys); + } + animator.whenWithKeys(duration == null ? 500 : duration, reverse ? reversedTarget : target, animationKeys).delay(delay || 0); + animatable.addAnimator(animator, topKey); + animators.push(animator); + } + } + + var Group = (function (_super) { + __extends(Group, _super); + function Group(opts) { + var _this = _super.call(this) || this; + _this.isGroup = true; + _this._children = []; + _this.attr(opts); + return _this; + } + Group.prototype.childrenRef = function () { + return this._children; + }; + Group.prototype.children = function () { + return this._children.slice(); + }; + Group.prototype.childAt = function (idx) { + return this._children[idx]; + }; + Group.prototype.childOfName = function (name) { + var children = this._children; + for (var i = 0; i < children.length; i++) { + if (children[i].name === name) { + return children[i]; + } + } + }; + Group.prototype.childCount = function () { + return this._children.length; + }; + Group.prototype.add = function (child) { + if (child) { + if (child !== this && child.parent !== this) { + this._children.push(child); + this._doAdd(child); + } + if ("development" !== 'production') { + if (child.__hostTarget) { + throw 'This elemenet has been used as an attachment'; + } + } + } + return this; + }; + Group.prototype.addBefore = function (child, nextSibling) { + if (child && child !== this && child.parent !== this + && nextSibling && nextSibling.parent === this) { + var children = this._children; + var idx = children.indexOf(nextSibling); + if (idx >= 0) { + children.splice(idx, 0, child); + this._doAdd(child); + } + } + return this; + }; + Group.prototype.replace = function (oldChild, newChild) { + var idx = indexOf(this._children, oldChild); + if (idx >= 0) { + this.replaceAt(newChild, idx); + } + return this; + }; + Group.prototype.replaceAt = function (child, index) { + var children = this._children; + var old = children[index]; + if (child && child !== this && child.parent !== this && child !== old) { + children[index] = child; + old.parent = null; + var zr = this.__zr; + if (zr) { + old.removeSelfFromZr(zr); + } + this._doAdd(child); + } + return this; + }; + Group.prototype._doAdd = function (child) { + if (child.parent) { + child.parent.remove(child); + } + child.parent = this; + var zr = this.__zr; + if (zr && zr !== child.__zr) { + child.addSelfToZr(zr); + } + zr && zr.refresh(); + }; + Group.prototype.remove = function (child) { + var zr = this.__zr; + var children = this._children; + var idx = indexOf(children, child); + if (idx < 0) { + return this; + } + children.splice(idx, 1); + child.parent = null; + if (zr) { + child.removeSelfFromZr(zr); + } + zr && zr.refresh(); + return this; + }; + Group.prototype.removeAll = function () { + var children = this._children; + var zr = this.__zr; + for (var i = 0; i < children.length; i++) { + var child = children[i]; + if (zr) { + child.removeSelfFromZr(zr); + } + child.parent = null; + } + children.length = 0; + return this; + }; + Group.prototype.eachChild = function (cb, context) { + var children = this._children; + for (var i = 0; i < children.length; i++) { + var child = children[i]; + cb.call(context, child, i); + } + return this; + }; + Group.prototype.traverse = function (cb, context) { + for (var i = 0; i < this._children.length; i++) { + var child = this._children[i]; + var stopped = cb.call(context, child); + if (child.isGroup && !stopped) { + child.traverse(cb, context); + } + } + return this; + }; + Group.prototype.addSelfToZr = function (zr) { + _super.prototype.addSelfToZr.call(this, zr); + for (var i = 0; i < this._children.length; i++) { + var child = this._children[i]; + child.addSelfToZr(zr); + } + }; + Group.prototype.removeSelfFromZr = function (zr) { + _super.prototype.removeSelfFromZr.call(this, zr); + for (var i = 0; i < this._children.length; i++) { + var child = this._children[i]; + child.removeSelfFromZr(zr); + } + }; + Group.prototype.getBoundingRect = function (includeChildren) { + var tmpRect = new BoundingRect(0, 0, 0, 0); + var children = includeChildren || this._children; + var tmpMat = []; + var rect = null; + for (var i = 0; i < children.length; i++) { + var child = children[i]; + if (child.ignore || child.invisible) { + continue; + } + var childRect = child.getBoundingRect(); + var transform = child.getLocalTransform(tmpMat); + if (transform) { + BoundingRect.applyTransform(tmpRect, childRect, transform); + rect = rect || tmpRect.clone(); + rect.union(tmpRect); + } + else { + rect = rect || childRect.clone(); + rect.union(childRect); + } + } + return rect || tmpRect; + }; + return Group; + }(Element)); + Group.prototype.type = 'group'; + + /*! + * ZRender, a high performance 2d drawing library. + * + * Copyright (c) 2013, Baidu Inc. + * All rights reserved. + * + * LICENSE + * https://github.com/ecomfe/zrender/blob/master/LICENSE.txt + */ + var painterCtors = {}; + var instances = {}; + function delInstance(id) { + delete instances[id]; + } + function isDarkMode(backgroundColor) { + if (!backgroundColor) { + return false; + } + if (typeof backgroundColor === 'string') { + return lum(backgroundColor, 1) < DARK_MODE_THRESHOLD; + } + else if (backgroundColor.colorStops) { + var colorStops = backgroundColor.colorStops; + var totalLum = 0; + var len = colorStops.length; + for (var i = 0; i < len; i++) { + totalLum += lum(colorStops[i].color, 1); + } + totalLum /= len; + return totalLum < DARK_MODE_THRESHOLD; + } + return false; + } + var ZRender = (function () { + function ZRender(id, dom, opts) { + var _this = this; + this._sleepAfterStill = 10; + this._stillFrameAccum = 0; + this._needsRefresh = true; + this._needsRefreshHover = true; + this._darkMode = false; + opts = opts || {}; + this.dom = dom; + this.id = id; + var storage = new Storage(); + var rendererType = opts.renderer || 'canvas'; + if (!painterCtors[rendererType]) { + rendererType = keys(painterCtors)[0]; + } + if ("development" !== 'production') { + if (!painterCtors[rendererType]) { + throw new Error("Renderer '" + rendererType + "' is not imported. Please import it first."); + } + } + opts.useDirtyRect = opts.useDirtyRect == null + ? false + : opts.useDirtyRect; + var painter = new painterCtors[rendererType](dom, storage, opts, id); + var ssrMode = opts.ssr || painter.ssrOnly; + this.storage = storage; + this.painter = painter; + var handerProxy = (!env.node && !env.worker && !ssrMode) + ? new HandlerDomProxy(painter.getViewportRoot(), painter.root) + : null; + this.handler = new Handler(storage, painter, handerProxy, painter.root); + this.animation = new Animation({ + stage: { + update: ssrMode ? null : function () { return _this._flush(true); } + } + }); + if (!ssrMode) { + this.animation.start(); + } + } + ZRender.prototype.add = function (el) { + if (!el) { + return; + } + this.storage.addRoot(el); + el.addSelfToZr(this); + this.refresh(); + }; + ZRender.prototype.remove = function (el) { + if (!el) { + return; + } + this.storage.delRoot(el); + el.removeSelfFromZr(this); + this.refresh(); + }; + ZRender.prototype.configLayer = function (zLevel, config) { + if (this.painter.configLayer) { + this.painter.configLayer(zLevel, config); + } + this.refresh(); + }; + ZRender.prototype.setBackgroundColor = function (backgroundColor) { + if (this.painter.setBackgroundColor) { + this.painter.setBackgroundColor(backgroundColor); + } + this.refresh(); + this._backgroundColor = backgroundColor; + this._darkMode = isDarkMode(backgroundColor); + }; + ZRender.prototype.getBackgroundColor = function () { + return this._backgroundColor; + }; + ZRender.prototype.setDarkMode = function (darkMode) { + this._darkMode = darkMode; + }; + ZRender.prototype.isDarkMode = function () { + return this._darkMode; + }; + ZRender.prototype.refreshImmediately = function (fromInside) { + if (!fromInside) { + this.animation.update(true); + } + this._needsRefresh = false; + this.painter.refresh(); + this._needsRefresh = false; + }; + ZRender.prototype.refresh = function () { + this._needsRefresh = true; + this.animation.start(); + }; + ZRender.prototype.flush = function () { + this._flush(false); + }; + ZRender.prototype._flush = function (fromInside) { + var triggerRendered; + var start = getTime(); + if (this._needsRefresh) { + triggerRendered = true; + this.refreshImmediately(fromInside); + } + if (this._needsRefreshHover) { + triggerRendered = true; + this.refreshHoverImmediately(); + } + var end = getTime(); + if (triggerRendered) { + this._stillFrameAccum = 0; + this.trigger('rendered', { + elapsedTime: end - start + }); + } + else if (this._sleepAfterStill > 0) { + this._stillFrameAccum++; + if (this._stillFrameAccum > this._sleepAfterStill) { + this.animation.stop(); + } + } + }; + ZRender.prototype.setSleepAfterStill = function (stillFramesCount) { + this._sleepAfterStill = stillFramesCount; + }; + ZRender.prototype.wakeUp = function () { + this.animation.start(); + this._stillFrameAccum = 0; + }; + ZRender.prototype.refreshHover = function () { + this._needsRefreshHover = true; + }; + ZRender.prototype.refreshHoverImmediately = function () { + this._needsRefreshHover = false; + if (this.painter.refreshHover && this.painter.getType() === 'canvas') { + this.painter.refreshHover(); + } + }; + ZRender.prototype.resize = function (opts) { + opts = opts || {}; + this.painter.resize(opts.width, opts.height); + this.handler.resize(); + }; + ZRender.prototype.clearAnimation = function () { + this.animation.clear(); + }; + ZRender.prototype.getWidth = function () { + return this.painter.getWidth(); + }; + ZRender.prototype.getHeight = function () { + return this.painter.getHeight(); + }; + ZRender.prototype.setCursorStyle = function (cursorStyle) { + this.handler.setCursorStyle(cursorStyle); + }; + ZRender.prototype.findHover = function (x, y) { + return this.handler.findHover(x, y); + }; + ZRender.prototype.on = function (eventName, eventHandler, context) { + this.handler.on(eventName, eventHandler, context); + return this; + }; + ZRender.prototype.off = function (eventName, eventHandler) { + this.handler.off(eventName, eventHandler); + }; + ZRender.prototype.trigger = function (eventName, event) { + this.handler.trigger(eventName, event); + }; + ZRender.prototype.clear = function () { + var roots = this.storage.getRoots(); + for (var i = 0; i < roots.length; i++) { + if (roots[i] instanceof Group) { + roots[i].removeSelfFromZr(this); + } + } + this.storage.delAllRoots(); + this.painter.clear(); + }; + ZRender.prototype.dispose = function () { + this.animation.stop(); + this.clear(); + this.storage.dispose(); + this.painter.dispose(); + this.handler.dispose(); + this.animation = + this.storage = + this.painter = + this.handler = null; + delInstance(this.id); + }; + return ZRender; + }()); + function init(dom, opts) { + var zr = new ZRender(guid(), dom, opts); + instances[zr.id] = zr; + return zr; + } + function dispose(zr) { + zr.dispose(); + } + function disposeAll() { + for (var key in instances) { + if (instances.hasOwnProperty(key)) { + instances[key].dispose(); + } + } + instances = {}; + } + function getInstance(id) { + return instances[id]; + } + function registerPainter(name, Ctor) { + painterCtors[name] = Ctor; + } + var version = '5.3.0'; + + var zrender = /*#__PURE__*/Object.freeze({ + __proto__: null, + init: init, + dispose: dispose, + disposeAll: disposeAll, + getInstance: getInstance, + registerPainter: registerPainter, + version: version + }); + + var RADIAN_EPSILON = 1e-4; // Although chrome already enlarge this number to 100 for `toFixed`, but + // we sill follow the spec for compatibility. + + var ROUND_SUPPORTED_PRECISION_MAX = 20; + + function _trim(str) { + return str.replace(/^\s+|\s+$/g, ''); + } + /** + * Linear mapping a value from domain to range + * @param val + * @param domain Domain extent domain[0] can be bigger than domain[1] + * @param range Range extent range[0] can be bigger than range[1] + * @param clamp Default to be false + */ + + + function linearMap(val, domain, range, clamp) { + var d0 = domain[0]; + var d1 = domain[1]; + var r0 = range[0]; + var r1 = range[1]; + var subDomain = d1 - d0; + var subRange = r1 - r0; + + if (subDomain === 0) { + return subRange === 0 ? r0 : (r0 + r1) / 2; + } // Avoid accuracy problem in edge, such as + // 146.39 - 62.83 === 83.55999999999999. + // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError + // It is a little verbose for efficiency considering this method + // is a hotspot. + + + if (clamp) { + if (subDomain > 0) { + if (val <= d0) { + return r0; + } else if (val >= d1) { + return r1; + } + } else { + if (val >= d0) { + return r0; + } else if (val <= d1) { + return r1; + } + } + } else { + if (val === d0) { + return r0; + } + + if (val === d1) { + return r1; + } + } + + return (val - d0) / subDomain * subRange + r0; + } + /** + * Convert a percent string to absolute number. + * Returns NaN if percent is not a valid string or number + */ + + function parsePercent$1(percent, all) { + switch (percent) { + case 'center': + case 'middle': + percent = '50%'; + break; + + case 'left': + case 'top': + percent = '0%'; + break; + + case 'right': + case 'bottom': + percent = '100%'; + break; + } + + if (isString(percent)) { + if (_trim(percent).match(/%$/)) { + return parseFloat(percent) / 100 * all; + } + + return parseFloat(percent); + } + + return percent == null ? NaN : +percent; + } + function round(x, precision, returnStr) { + if (precision == null) { + precision = 10; + } // Avoid range error + + + precision = Math.min(Math.max(0, precision), ROUND_SUPPORTED_PRECISION_MAX); // PENDING: 1.005.toFixed(2) is '1.00' rather than '1.01' + + x = (+x).toFixed(precision); + return returnStr ? x : +x; + } + /** + * Inplacd asc sort arr. + * The input arr will be modified. + */ + + function asc(arr) { + arr.sort(function (a, b) { + return a - b; + }); + return arr; + } + /** + * Get precision. + */ + + function getPrecision(val) { + val = +val; + + if (isNaN(val)) { + return 0; + } // It is much faster than methods converting number to string as follows + // let tmp = val.toString(); + // return tmp.length - 1 - tmp.indexOf('.'); + // especially when precision is low + // Notice: + // (1) If the loop count is over about 20, it is slower than `getPrecisionSafe`. + // (see https://jsbench.me/2vkpcekkvw/1) + // (2) If the val is less than for example 1e-15, the result may be incorrect. + // (see test/ut/spec/util/number.test.ts `getPrecision_equal_random`) + + + if (val > 1e-14) { + var e = 1; + + for (var i = 0; i < 15; i++, e *= 10) { + if (Math.round(val * e) / e === val) { + return i; + } + } + } + + return getPrecisionSafe(val); + } + /** + * Get precision with slow but safe method + */ + + function getPrecisionSafe(val) { + // toLowerCase for: '3.4E-12' + var str = val.toString().toLowerCase(); // Consider scientific notation: '3.4e-12' '3.4e+12' + + var eIndex = str.indexOf('e'); + var exp = eIndex > 0 ? +str.slice(eIndex + 1) : 0; + var significandPartLen = eIndex > 0 ? eIndex : str.length; + var dotIndex = str.indexOf('.'); + var decimalPartLen = dotIndex < 0 ? 0 : significandPartLen - 1 - dotIndex; + return Math.max(0, decimalPartLen - exp); + } + /** + * Minimal dicernible data precisioin according to a single pixel. + */ + + function getPixelPrecision(dataExtent, pixelExtent) { + var log = Math.log; + var LN10 = Math.LN10; + var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10); + var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10); // toFixed() digits argument must be between 0 and 20. + + var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20); + return !isFinite(precision) ? 20 : precision; + } + /** + * Get a data of given precision, assuring the sum of percentages + * in valueList is 1. + * The largest remainer method is used. + * https://en.wikipedia.org/wiki/Largest_remainder_method + * + * @param valueList a list of all data + * @param idx index of the data to be processed in valueList + * @param precision integer number showing digits of precision + * @return percent ranging from 0 to 100 + */ + + function getPercentWithPrecision(valueList, idx, precision) { + if (!valueList[idx]) { + return 0; + } + + var sum = reduce(valueList, function (acc, val) { + return acc + (isNaN(val) ? 0 : val); + }, 0); + + if (sum === 0) { + return 0; + } + + var digits = Math.pow(10, precision); + var votesPerQuota = map(valueList, function (val) { + return (isNaN(val) ? 0 : val) / sum * digits * 100; + }); + var targetSeats = digits * 100; + var seats = map(votesPerQuota, function (votes) { + // Assign automatic seats. + return Math.floor(votes); + }); + var currentSum = reduce(seats, function (acc, val) { + return acc + val; + }, 0); + var remainder = map(votesPerQuota, function (votes, idx) { + return votes - seats[idx]; + }); // Has remainding votes. + + while (currentSum < targetSeats) { + // Find next largest remainder. + var max = Number.NEGATIVE_INFINITY; + var maxId = null; + + for (var i = 0, len = remainder.length; i < len; ++i) { + if (remainder[i] > max) { + max = remainder[i]; + maxId = i; + } + } // Add a vote to max remainder. + + + ++seats[maxId]; + remainder[maxId] = 0; + ++currentSum; + } + + return seats[idx] / digits; + } + /** + * Solve the floating point adding problem like 0.1 + 0.2 === 0.30000000000000004 + * See + */ + + function addSafe(val0, val1) { + var maxPrecision = Math.max(getPrecision(val0), getPrecision(val1)); // const multiplier = Math.pow(10, maxPrecision); + // return (Math.round(val0 * multiplier) + Math.round(val1 * multiplier)) / multiplier; + + var sum = val0 + val1; // // PENDING: support more? + + return maxPrecision > ROUND_SUPPORTED_PRECISION_MAX ? sum : round(sum, maxPrecision); + } // Number.MAX_SAFE_INTEGER, ie do not support. + + var MAX_SAFE_INTEGER = 9007199254740991; + /** + * To 0 - 2 * PI, considering negative radian. + */ + + function remRadian(radian) { + var pi2 = Math.PI * 2; + return (radian % pi2 + pi2) % pi2; + } + /** + * @param {type} radian + * @return {boolean} + */ + + function isRadianAroundZero(val) { + return val > -RADIAN_EPSILON && val < RADIAN_EPSILON; + } // eslint-disable-next-line + + var TIME_REG = /^(?:(\d{4})(?:[-\/](\d{1,2})(?:[-\/](\d{1,2})(?:[T ](\d{1,2})(?::(\d{1,2})(?::(\d{1,2})(?:[.,](\d+))?)?)?(Z|[\+\-]\d\d:?\d\d)?)?)?)?)?$/; // jshint ignore:line + + /** + * @param value valid type: number | string | Date, otherwise return `new Date(NaN)` + * These values can be accepted: + * + An instance of Date, represent a time in its own time zone. + * + Or string in a subset of ISO 8601, only including: + * + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06', + * + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123', + * + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00', + * all of which will be treated as local time if time zone is not specified + * (see ). + * + Or other string format, including (all of which will be treated as loacal time): + * '2012', '2012-3-1', '2012/3/1', '2012/03/01', + * '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123' + * + a timestamp, which represent a time in UTC. + * @return date Never be null/undefined. If invalid, return `new Date(NaN)`. + */ + + function parseDate(value) { + if (value instanceof Date) { + return value; + } else if (isString(value)) { + // Different browsers parse date in different way, so we parse it manually. + // Some other issues: + // new Date('1970-01-01') is UTC, + // new Date('1970/01/01') and new Date('1970-1-01') is local. + // See issue #3623 + var match = TIME_REG.exec(value); + + if (!match) { + // return Invalid Date. + return new Date(NaN); + } // Use local time when no timezone offset specifed. + + + if (!match[8]) { + // match[n] can only be string or undefined. + // But take care of '12' + 1 => '121'. + return new Date(+match[1], +(match[2] || 1) - 1, +match[3] || 1, +match[4] || 0, +(match[5] || 0), +match[6] || 0, match[7] ? +match[7].substring(0, 3) : 0); + } // Timezoneoffset of Javascript Date has considered DST (Daylight Saving Time, + // https://tc39.github.io/ecma262/#sec-daylight-saving-time-adjustment). + // For example, system timezone is set as "Time Zone: America/Toronto", + // then these code will get different result: + // `new Date(1478411999999).getTimezoneOffset(); // get 240` + // `new Date(1478412000000).getTimezoneOffset(); // get 300` + // So we should not use `new Date`, but use `Date.UTC`. + else { + var hour = +match[4] || 0; + + if (match[8].toUpperCase() !== 'Z') { + hour -= +match[8].slice(0, 3); + } + + return new Date(Date.UTC(+match[1], +(match[2] || 1) - 1, +match[3] || 1, hour, +(match[5] || 0), +match[6] || 0, match[7] ? +match[7].substring(0, 3) : 0)); + } + } else if (value == null) { + return new Date(NaN); + } + + return new Date(Math.round(value)); + } + /** + * Quantity of a number. e.g. 0.1, 1, 10, 100 + * + * @param val + * @return + */ + + function quantity(val) { + return Math.pow(10, quantityExponent(val)); + } + /** + * Exponent of the quantity of a number + * e.g., 1234 equals to 1.234*10^3, so quantityExponent(1234) is 3 + * + * @param val non-negative value + * @return + */ + + function quantityExponent(val) { + if (val === 0) { + return 0; + } + + var exp = Math.floor(Math.log(val) / Math.LN10); + /** + * exp is expected to be the rounded-down result of the base-10 log of val. + * But due to the precision loss with Math.log(val), we need to restore it + * using 10^exp to make sure we can get val back from exp. #11249 + */ + + if (val / Math.pow(10, exp) >= 10) { + exp++; + } + + return exp; + } + /** + * find a “nice” number approximately equal to x. Round the number if round = true, + * take ceiling if round = false. The primary observation is that the “nicest” + * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers. + * + * See "Nice Numbers for Graph Labels" of Graphic Gems. + * + * @param val Non-negative value. + * @param round + * @return Niced number + */ + + function nice(val, round) { + var exponent = quantityExponent(val); + var exp10 = Math.pow(10, exponent); + var f = val / exp10; // 1 <= f < 10 + + var nf; + + if (round) { + if (f < 1.5) { + nf = 1; + } else if (f < 2.5) { + nf = 2; + } else if (f < 4) { + nf = 3; + } else if (f < 7) { + nf = 5; + } else { + nf = 10; + } + } else { + if (f < 1) { + nf = 1; + } else if (f < 2) { + nf = 2; + } else if (f < 3) { + nf = 3; + } else if (f < 5) { + nf = 5; + } else { + nf = 10; + } + } + + val = nf * exp10; // Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754). + // 20 is the uppper bound of toFixed. + + return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val; + } + /** + * This code was copied from "d3.js" + * . + * See the license statement at the head of this file. + * @param ascArr + */ + + function quantile(ascArr, p) { + var H = (ascArr.length - 1) * p + 1; + var h = Math.floor(H); + var v = +ascArr[h - 1]; + var e = H - h; + return e ? v + e * (ascArr[h] - v) : v; + } + /** + * Order intervals asc, and split them when overlap. + * expect(numberUtil.reformIntervals([ + * {interval: [18, 62], close: [1, 1]}, + * {interval: [-Infinity, -70], close: [0, 0]}, + * {interval: [-70, -26], close: [1, 1]}, + * {interval: [-26, 18], close: [1, 1]}, + * {interval: [62, 150], close: [1, 1]}, + * {interval: [106, 150], close: [1, 1]}, + * {interval: [150, Infinity], close: [0, 0]} + * ])).toEqual([ + * {interval: [-Infinity, -70], close: [0, 0]}, + * {interval: [-70, -26], close: [1, 1]}, + * {interval: [-26, 18], close: [0, 1]}, + * {interval: [18, 62], close: [0, 1]}, + * {interval: [62, 150], close: [0, 1]}, + * {interval: [150, Infinity], close: [0, 0]} + * ]); + * @param list, where `close` mean open or close + * of the interval, and Infinity can be used. + * @return The origin list, which has been reformed. + */ + + function reformIntervals(list) { + list.sort(function (a, b) { + return littleThan(a, b, 0) ? -1 : 1; + }); + var curr = -Infinity; + var currClose = 1; + + for (var i = 0; i < list.length;) { + var interval = list[i].interval; + var close_1 = list[i].close; + + for (var lg = 0; lg < 2; lg++) { + if (interval[lg] <= curr) { + interval[lg] = curr; + close_1[lg] = !lg ? 1 - currClose : 1; + } + + curr = interval[lg]; + currClose = close_1[lg]; + } + + if (interval[0] === interval[1] && close_1[0] * close_1[1] !== 1) { + list.splice(i, 1); + } else { + i++; + } + } + + return list; + + function littleThan(a, b, lg) { + return a.interval[lg] < b.interval[lg] || a.interval[lg] === b.interval[lg] && (a.close[lg] - b.close[lg] === (!lg ? 1 : -1) || !lg && littleThan(a, b, 1)); + } + } + /** + * [Numberic is defined as]: + * `parseFloat(val) == val` + * For example: + * numeric: + * typeof number except NaN, '-123', '123', '2e3', '-2e3', '011', 'Infinity', Infinity, + * and they rounded by white-spaces or line-terminal like ' -123 \n ' (see es spec) + * not-numeric: + * null, undefined, [], {}, true, false, 'NaN', NaN, '123ab', + * empty string, string with only white-spaces or line-terminal (see es spec), + * 0x12, '0x12', '-0x12', 012, '012', '-012', + * non-string, ... + * + * @test See full test cases in `test/ut/spec/util/number.js`. + * @return Must be a typeof number. If not numeric, return NaN. + */ + + function numericToNumber(val) { + var valFloat = parseFloat(val); + return valFloat == val // eslint-disable-line eqeqeq + && (valFloat !== 0 || !isString(val) || val.indexOf('x') <= 0) // For case ' 0x0 '. + ? valFloat : NaN; + } + /** + * Definition of "numeric": see `numericToNumber`. + */ + + function isNumeric(val) { + return !isNaN(numericToNumber(val)); + } + /** + * Use random base to prevent users hard code depending on + * this auto generated marker id. + * @return An positive integer. + */ + + function getRandomIdBase() { + return Math.round(Math.random() * 9); + } + /** + * Get the greatest common dividor + * + * @param {number} a one number + * @param {number} b the other number + */ + + function getGreatestCommonDividor(a, b) { + if (b === 0) { + return a; + } + + return getGreatestCommonDividor(b, a % b); + } + /** + * Get the least common multiple + * + * @param {number} a one number + * @param {number} b the other number + */ + + function getLeastCommonMultiple(a, b) { + if (a == null) { + return b; + } + + if (b == null) { + return a; + } + + return a * b / getGreatestCommonDividor(a, b); + } + + var ECHARTS_PREFIX = '[ECharts] '; + var storedLogs = {}; + var hasConsole = typeof console !== 'undefined' // eslint-disable-next-line + && console.warn && console.log; + + function outputLog(type, str, onlyOnce) { + if (hasConsole) { + if (onlyOnce) { + if (storedLogs[str]) { + return; + } + + storedLogs[str] = true; + } // eslint-disable-next-line + + + console[type](ECHARTS_PREFIX + str); + } + } + + function log(str, onlyOnce) { + outputLog('log', str, onlyOnce); + } + function warn(str, onlyOnce) { + outputLog('warn', str, onlyOnce); + } + function error(str, onlyOnce) { + outputLog('error', str, onlyOnce); + } + function deprecateLog(str) { + if ("development" !== 'production') { + // Not display duplicate message. + outputLog('warn', 'DEPRECATED: ' + str, true); + } + } + function deprecateReplaceLog(oldOpt, newOpt, scope) { + if ("development" !== 'production') { + deprecateLog((scope ? "[" + scope + "]" : '') + (oldOpt + " is deprecated, use " + newOpt + " instead.")); + } + } + /** + * If in __DEV__ environment, get console printable message for users hint. + * Parameters are separated by ' '. + * @usuage + * makePrintable('This is an error on', someVar, someObj); + * + * @param hintInfo anything about the current execution context to hint users. + * @throws Error + */ + + function makePrintable() { + var hintInfo = []; + + for (var _i = 0; _i < arguments.length; _i++) { + hintInfo[_i] = arguments[_i]; + } + + var msg = ''; + + if ("development" !== 'production') { + // Fuzzy stringify for print. + // This code only exist in dev environment. + var makePrintableStringIfPossible_1 = function (val) { + return val === void 0 ? 'undefined' : val === Infinity ? 'Infinity' : val === -Infinity ? '-Infinity' : eqNaN(val) ? 'NaN' : val instanceof Date ? 'Date(' + val.toISOString() + ')' : isFunction(val) ? 'function () { ... }' : isRegExp(val) ? val + '' : null; + }; + + msg = map(hintInfo, function (arg) { + if (isString(arg)) { + // Print without quotation mark for some statement. + return arg; + } else { + var printableStr = makePrintableStringIfPossible_1(arg); + + if (printableStr != null) { + return printableStr; + } else if (typeof JSON !== 'undefined' && JSON.stringify) { + try { + return JSON.stringify(arg, function (n, val) { + var printableStr = makePrintableStringIfPossible_1(val); + return printableStr == null ? val : printableStr; + }); // In most cases the info object is small, so do not line break. + } catch (err) { + return '?'; + } + } else { + return '?'; + } + } + }).join(' '); + } + + return msg; + } + /** + * @throws Error + */ + + function throwError(msg) { + throw new Error(msg); + } + + function interpolateNumber$1(p0, p1, percent) { + return (p1 - p0) * percent + p0; + } + /** + * Make the name displayable. But we should + * make sure it is not duplicated with user + * specified name, so use '\0'; + */ + + + var DUMMY_COMPONENT_NAME_PREFIX = 'series\0'; + var INTERNAL_COMPONENT_ID_PREFIX = '\0_ec_\0'; + /** + * If value is not array, then translate it to array. + * @param {*} value + * @return {Array} [value] or value + */ + + function normalizeToArray(value) { + return value instanceof Array ? value : value == null ? [] : [value]; + } + /** + * Sync default option between normal and emphasis like `position` and `show` + * In case some one will write code like + * label: { + * show: false, + * position: 'outside', + * fontSize: 18 + * }, + * emphasis: { + * label: { show: true } + * } + */ + + function defaultEmphasis(opt, key, subOpts) { + // Caution: performance sensitive. + if (opt) { + opt[key] = opt[key] || {}; + opt.emphasis = opt.emphasis || {}; + opt.emphasis[key] = opt.emphasis[key] || {}; // Default emphasis option from normal + + for (var i = 0, len = subOpts.length; i < len; i++) { + var subOptName = subOpts[i]; + + if (!opt.emphasis[key].hasOwnProperty(subOptName) && opt[key].hasOwnProperty(subOptName)) { + opt.emphasis[key][subOptName] = opt[key][subOptName]; + } + } + } + } + var TEXT_STYLE_OPTIONS = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'rich', 'tag', 'color', 'textBorderColor', 'textBorderWidth', 'width', 'height', 'lineHeight', 'align', 'verticalAlign', 'baseline', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY', 'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY', 'backgroundColor', 'borderColor', 'borderWidth', 'borderRadius', 'padding']; // modelUtil.LABEL_OPTIONS = modelUtil.TEXT_STYLE_OPTIONS.concat([ + // 'position', 'offset', 'rotate', 'origin', 'show', 'distance', 'formatter', + // 'fontStyle', 'fontWeight', 'fontSize', 'fontFamily', + // // FIXME: deprecated, check and remove it. + // 'textStyle' + // ]); + + /** + * The method do not ensure performance. + * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}] + * This helper method retieves value from data. + */ + + function getDataItemValue(dataItem) { + return isObject(dataItem) && !isArray(dataItem) && !(dataItem instanceof Date) ? dataItem.value : dataItem; + } + /** + * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}] + * This helper method determine if dataItem has extra option besides value + */ + + function isDataItemOption(dataItem) { + return isObject(dataItem) && !(dataItem instanceof Array); // // markLine data can be array + // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array)); + } + /** + * Mapping to existings for merge. + * + * Mode "normalMege": + * The mapping result (merge result) will keep the order of the existing + * component, rather than the order of new option. Because we should ensure + * some specified index reference (like xAxisIndex) keep work. + * And in most cases, "merge option" is used to update partial option but not + * be expected to change the order. + * + * Mode "replaceMege": + * (1) Only the id mapped components will be merged. + * (2) Other existing components (except internal compoonets) will be removed. + * (3) Other new options will be used to create new component. + * (4) The index of the existing compoents will not be modified. + * That means their might be "hole" after the removal. + * The new components are created first at those available index. + * + * Mode "replaceAll": + * This mode try to support that reproduce an echarts instance from another + * echarts instance (via `getOption`) in some simple cases. + * In this senario, the `result` index are exactly the consistent with the `newCmptOptions`, + * which ensures the compoennt index referring (like `xAxisIndex: ?`) corrent. That is, + * the "hole" in `newCmptOptions` will also be kept. + * On the contrary, other modes try best to eliminate holes. + * PENDING: This is an experimental mode yet. + * + * @return See the comment of . + */ + + function mappingToExists(existings, newCmptOptions, mode) { + var isNormalMergeMode = mode === 'normalMerge'; + var isReplaceMergeMode = mode === 'replaceMerge'; + var isReplaceAllMode = mode === 'replaceAll'; + existings = existings || []; + newCmptOptions = (newCmptOptions || []).slice(); + var existingIdIdxMap = createHashMap(); // Validate id and name on user input option. + + each(newCmptOptions, function (cmptOption, index) { + if (!isObject(cmptOption)) { + newCmptOptions[index] = null; + return; + } + + if ("development" !== 'production') { + // There is some legacy case that name is set as `false`. + // But should work normally rather than throw error. + if (cmptOption.id != null && !isValidIdOrName(cmptOption.id)) { + warnInvalidateIdOrName(cmptOption.id); + } + + if (cmptOption.name != null && !isValidIdOrName(cmptOption.name)) { + warnInvalidateIdOrName(cmptOption.name); + } + } + }); + var result = prepareResult(existings, existingIdIdxMap, mode); + + if (isNormalMergeMode || isReplaceMergeMode) { + mappingById(result, existings, existingIdIdxMap, newCmptOptions); + } + + if (isNormalMergeMode) { + mappingByName(result, newCmptOptions); + } + + if (isNormalMergeMode || isReplaceMergeMode) { + mappingByIndex(result, newCmptOptions, isReplaceMergeMode); + } else if (isReplaceAllMode) { + mappingInReplaceAllMode(result, newCmptOptions); + } + + makeIdAndName(result); // The array `result` MUST NOT contain elided items, otherwise the + // forEach will ommit those items and result in incorrect result. + + return result; + } + + function prepareResult(existings, existingIdIdxMap, mode) { + var result = []; + + if (mode === 'replaceAll') { + return result; + } // Do not use native `map` to in case that the array `existings` + // contains elided items, which will be ommited. + + + for (var index = 0; index < existings.length; index++) { + var existing = existings[index]; // Because of replaceMerge, `existing` may be null/undefined. + + if (existing && existing.id != null) { + existingIdIdxMap.set(existing.id, index); + } // For non-internal-componnets: + // Mode "normalMerge": all existings kept. + // Mode "replaceMerge": all existing removed unless mapped by id. + // For internal-components: + // go with "replaceMerge" approach in both mode. + + + result.push({ + existing: mode === 'replaceMerge' || isComponentIdInternal(existing) ? null : existing, + newOption: null, + keyInfo: null, + brandNew: null + }); + } + + return result; + } + + function mappingById(result, existings, existingIdIdxMap, newCmptOptions) { + // Mapping by id if specified. + each(newCmptOptions, function (cmptOption, index) { + if (!cmptOption || cmptOption.id == null) { + return; + } + + var optionId = makeComparableKey(cmptOption.id); + var existingIdx = existingIdIdxMap.get(optionId); + + if (existingIdx != null) { + var resultItem = result[existingIdx]; + assert(!resultItem.newOption, 'Duplicated option on id "' + optionId + '".'); + resultItem.newOption = cmptOption; // In both mode, if id matched, new option will be merged to + // the existings rather than creating new component model. + + resultItem.existing = existings[existingIdx]; + newCmptOptions[index] = null; + } + }); + } + + function mappingByName(result, newCmptOptions) { + // Mapping by name if specified. + each(newCmptOptions, function (cmptOption, index) { + if (!cmptOption || cmptOption.name == null) { + return; + } + + for (var i = 0; i < result.length; i++) { + var existing = result[i].existing; + + if (!result[i].newOption // Consider name: two map to one. + // Can not match when both ids existing but different. + && existing && (existing.id == null || cmptOption.id == null) && !isComponentIdInternal(cmptOption) && !isComponentIdInternal(existing) && keyExistAndEqual('name', existing, cmptOption)) { + result[i].newOption = cmptOption; + newCmptOptions[index] = null; + return; + } + } + }); + } + + function mappingByIndex(result, newCmptOptions, brandNew) { + each(newCmptOptions, function (cmptOption) { + if (!cmptOption) { + return; + } // Find the first place that not mapped by id and not internal component (consider the "hole"). + + + var resultItem; + var nextIdx = 0; + + while ( // Be `!resultItem` only when `nextIdx >= result.length`. + (resultItem = result[nextIdx]) && ( // (1) Existing models that already have id should be able to mapped to. Because + // after mapping performed, model will always be assigned with an id if user not given. + // After that all models have id. + // (2) If new option has id, it can only set to a hole or append to the last. It should + // not be merged to the existings with different id. Because id should not be overwritten. + // (3) Name can be overwritten, because axis use name as 'show label text'. + resultItem.newOption || isComponentIdInternal(resultItem.existing) || // In mode "replaceMerge", here no not-mapped-non-internal-existing. + resultItem.existing && cmptOption.id != null && !keyExistAndEqual('id', cmptOption, resultItem.existing))) { + nextIdx++; + } + + if (resultItem) { + resultItem.newOption = cmptOption; + resultItem.brandNew = brandNew; + } else { + result.push({ + newOption: cmptOption, + brandNew: brandNew, + existing: null, + keyInfo: null + }); + } + + nextIdx++; + }); + } + + function mappingInReplaceAllMode(result, newCmptOptions) { + each(newCmptOptions, function (cmptOption) { + // The feature "reproduce" requires "hole" will also reproduced + // in case that compoennt index referring are broken. + result.push({ + newOption: cmptOption, + brandNew: true, + existing: null, + keyInfo: null + }); + }); + } + /** + * Make id and name for mapping result (result of mappingToExists) + * into `keyInfo` field. + */ + + + function makeIdAndName(mapResult) { + // We use this id to hash component models and view instances + // in echarts. id can be specified by user, or auto generated. + // The id generation rule ensures new view instance are able + // to mapped to old instance when setOption are called in + // no-merge mode. So we generate model id by name and plus + // type in view id. + // name can be duplicated among components, which is convenient + // to specify multi components (like series) by one name. + // Ensure that each id is distinct. + var idMap = createHashMap(); + each(mapResult, function (item) { + var existing = item.existing; + existing && idMap.set(existing.id, item); + }); + each(mapResult, function (item) { + var opt = item.newOption; // Force ensure id not duplicated. + + assert(!opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item, 'id duplicates: ' + (opt && opt.id)); + opt && opt.id != null && idMap.set(opt.id, item); + !item.keyInfo && (item.keyInfo = {}); + }); // Make name and id. + + each(mapResult, function (item, index) { + var existing = item.existing; + var opt = item.newOption; + var keyInfo = item.keyInfo; + + if (!isObject(opt)) { + return; + } // name can be overwitten. Consider case: axis.name = '20km'. + // But id generated by name will not be changed, which affect + // only in that case: setOption with 'not merge mode' and view + // instance will be recreated, which can be accepted. + + + keyInfo.name = opt.name != null ? makeComparableKey(opt.name) : existing ? existing.name // Avoid diffferent series has the same name, + // because name may be used like in color pallet. + : DUMMY_COMPONENT_NAME_PREFIX + index; + + if (existing) { + keyInfo.id = makeComparableKey(existing.id); + } else if (opt.id != null) { + keyInfo.id = makeComparableKey(opt.id); + } else { + // Consider this situatoin: + // optionA: [{name: 'a'}, {name: 'a'}, {..}] + // optionB [{..}, {name: 'a'}, {name: 'a'}] + // Series with the same name between optionA and optionB + // should be mapped. + var idNum = 0; + + do { + keyInfo.id = '\0' + keyInfo.name + '\0' + idNum++; + } while (idMap.get(keyInfo.id)); + } + + idMap.set(keyInfo.id, item); + }); + } + + function keyExistAndEqual(attr, obj1, obj2) { + var key1 = convertOptionIdName(obj1[attr], null); + var key2 = convertOptionIdName(obj2[attr], null); // See `MappingExistingItem`. `id` and `name` trade string equals to number. + + return key1 != null && key2 != null && key1 === key2; + } + /** + * @return return null if not exist. + */ + + + function makeComparableKey(val) { + if ("development" !== 'production') { + if (val == null) { + throw new Error(); + } + } + + return convertOptionIdName(val, ''); + } + + function convertOptionIdName(idOrName, defaultValue) { + if (idOrName == null) { + return defaultValue; + } + + return isString(idOrName) ? idOrName : isNumber(idOrName) || isStringSafe(idOrName) ? idOrName + '' : defaultValue; + } + + function warnInvalidateIdOrName(idOrName) { + if ("development" !== 'production') { + warn('`' + idOrName + '` is invalid id or name. Must be a string or number.'); + } + } + + function isValidIdOrName(idOrName) { + return isStringSafe(idOrName) || isNumeric(idOrName); + } + + function isNameSpecified(componentModel) { + var name = componentModel.name; // Is specified when `indexOf` get -1 or > 0. + + return !!(name && name.indexOf(DUMMY_COMPONENT_NAME_PREFIX)); + } + /** + * @public + * @param {Object} cmptOption + * @return {boolean} + */ + + function isComponentIdInternal(cmptOption) { + return cmptOption && cmptOption.id != null && makeComparableKey(cmptOption.id).indexOf(INTERNAL_COMPONENT_ID_PREFIX) === 0; + } + function makeInternalComponentId(idSuffix) { + return INTERNAL_COMPONENT_ID_PREFIX + idSuffix; + } + function setComponentTypeToKeyInfo(mappingResult, mainType, componentModelCtor) { + // Set mainType and complete subType. + each(mappingResult, function (item) { + var newOption = item.newOption; + + if (isObject(newOption)) { + item.keyInfo.mainType = mainType; + item.keyInfo.subType = determineSubType(mainType, newOption, item.existing, componentModelCtor); + } + }); + } + + function determineSubType(mainType, newCmptOption, existComponent, componentModelCtor) { + var subType = newCmptOption.type ? newCmptOption.type : existComponent ? existComponent.subType // Use determineSubType only when there is no existComponent. + : componentModelCtor.determineSubType(mainType, newCmptOption); // tooltip, markline, markpoint may always has no subType + + return subType; + } + /** + * A helper for removing duplicate items between batchA and batchB, + * and in themselves, and categorize by series. + * + * @param batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...] + * @param batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...] + * @return result: [resultBatchA, resultBatchB] + */ + + + function compressBatches(batchA, batchB) { + var mapA = {}; + var mapB = {}; + makeMap(batchA || [], mapA); + makeMap(batchB || [], mapB, mapA); + return [mapToArray(mapA), mapToArray(mapB)]; + + function makeMap(sourceBatch, map, otherMap) { + for (var i = 0, len = sourceBatch.length; i < len; i++) { + var seriesId = convertOptionIdName(sourceBatch[i].seriesId, null); + + if (seriesId == null) { + return; + } + + var dataIndices = normalizeToArray(sourceBatch[i].dataIndex); + var otherDataIndices = otherMap && otherMap[seriesId]; + + for (var j = 0, lenj = dataIndices.length; j < lenj; j++) { + var dataIndex = dataIndices[j]; + + if (otherDataIndices && otherDataIndices[dataIndex]) { + otherDataIndices[dataIndex] = null; + } else { + (map[seriesId] || (map[seriesId] = {}))[dataIndex] = 1; + } + } + } + } + + function mapToArray(map, isData) { + var result = []; + + for (var i in map) { + if (map.hasOwnProperty(i) && map[i] != null) { + if (isData) { + result.push(+i); + } else { + var dataIndices = mapToArray(map[i], true); + dataIndices.length && result.push({ + seriesId: i, + dataIndex: dataIndices + }); + } + } + } + + return result; + } + } + /** + * @param payload Contains dataIndex (means rawIndex) / dataIndexInside / name + * each of which can be Array or primary type. + * @return dataIndex If not found, return undefined/null. + */ + + function queryDataIndex(data, payload) { + if (payload.dataIndexInside != null) { + return payload.dataIndexInside; + } else if (payload.dataIndex != null) { + return isArray(payload.dataIndex) ? map(payload.dataIndex, function (value) { + return data.indexOfRawIndex(value); + }) : data.indexOfRawIndex(payload.dataIndex); + } else if (payload.name != null) { + return isArray(payload.name) ? map(payload.name, function (value) { + return data.indexOfName(value); + }) : data.indexOfName(payload.name); + } + } + /** + * Enable property storage to any host object. + * Notice: Serialization is not supported. + * + * For example: + * let inner = zrUitl.makeInner(); + * + * function some1(hostObj) { + * inner(hostObj).someProperty = 1212; + * ... + * } + * function some2() { + * let fields = inner(this); + * fields.someProperty1 = 1212; + * fields.someProperty2 = 'xx'; + * ... + * } + * + * @return {Function} + */ + + function makeInner() { + var key = '__ec_inner_' + innerUniqueIndex++; + return function (hostObj) { + return hostObj[key] || (hostObj[key] = {}); + }; + } + var innerUniqueIndex = getRandomIdBase(); + /** + * The same behavior as `component.getReferringComponents`. + */ + + function parseFinder(ecModel, finderInput, opt) { + var _a = preParseFinder(finderInput, opt), + mainTypeSpecified = _a.mainTypeSpecified, + queryOptionMap = _a.queryOptionMap, + others = _a.others; + + var result = others; + var defaultMainType = opt ? opt.defaultMainType : null; + + if (!mainTypeSpecified && defaultMainType) { + queryOptionMap.set(defaultMainType, {}); + } + + queryOptionMap.each(function (queryOption, mainType) { + var queryResult = queryReferringComponents(ecModel, mainType, queryOption, { + useDefault: defaultMainType === mainType, + enableAll: opt && opt.enableAll != null ? opt.enableAll : true, + enableNone: opt && opt.enableNone != null ? opt.enableNone : true + }); + result[mainType + 'Models'] = queryResult.models; + result[mainType + 'Model'] = queryResult.models[0]; + }); + return result; + } + function preParseFinder(finderInput, opt) { + var finder; + + if (isString(finderInput)) { + var obj = {}; + obj[finderInput + 'Index'] = 0; + finder = obj; + } else { + finder = finderInput; + } + + var queryOptionMap = createHashMap(); + var others = {}; + var mainTypeSpecified = false; + each(finder, function (value, key) { + // Exclude 'dataIndex' and other illgal keys. + if (key === 'dataIndex' || key === 'dataIndexInside') { + others[key] = value; + return; + } + + var parsedKey = key.match(/^(\w+)(Index|Id|Name)$/) || []; + var mainType = parsedKey[1]; + var queryType = (parsedKey[2] || '').toLowerCase(); + + if (!mainType || !queryType || opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0) { + return; + } + + mainTypeSpecified = mainTypeSpecified || !!mainType; + var queryOption = queryOptionMap.get(mainType) || queryOptionMap.set(mainType, {}); + queryOption[queryType] = value; + }); + return { + mainTypeSpecified: mainTypeSpecified, + queryOptionMap: queryOptionMap, + others: others + }; + } + var SINGLE_REFERRING = { + useDefault: true, + enableAll: false, + enableNone: false + }; + var MULTIPLE_REFERRING = { + useDefault: false, + enableAll: true, + enableNone: true + }; + function queryReferringComponents(ecModel, mainType, userOption, opt) { + opt = opt || SINGLE_REFERRING; + var indexOption = userOption.index; + var idOption = userOption.id; + var nameOption = userOption.name; + var result = { + models: null, + specified: indexOption != null || idOption != null || nameOption != null + }; + + if (!result.specified) { + // Use the first as default if `useDefault`. + var firstCmpt = void 0; + result.models = opt.useDefault && (firstCmpt = ecModel.getComponent(mainType)) ? [firstCmpt] : []; + return result; + } + + if (indexOption === 'none' || indexOption === false) { + assert(opt.enableNone, '`"none"` or `false` is not a valid value on index option.'); + result.models = []; + return result; + } // `queryComponents` will return all components if + // both all of index/id/name are null/undefined. + + + if (indexOption === 'all') { + assert(opt.enableAll, '`"all"` is not a valid value on index option.'); + indexOption = idOption = nameOption = null; + } + + result.models = ecModel.queryComponents({ + mainType: mainType, + index: indexOption, + id: idOption, + name: nameOption + }); + return result; + } + function setAttribute(dom, key, value) { + dom.setAttribute ? dom.setAttribute(key, value) : dom[key] = value; + } + function getAttribute(dom, key) { + return dom.getAttribute ? dom.getAttribute(key) : dom[key]; + } + function getTooltipRenderMode(renderModeOption) { + if (renderModeOption === 'auto') { + // Using html when `document` exists, use richText otherwise + return env.domSupported ? 'html' : 'richText'; + } else { + return renderModeOption || 'html'; + } + } + /** + * Group a list by key. + */ + + function groupData(array, getKey // return key + ) { + var buckets = createHashMap(); + var keys = []; + each(array, function (item) { + var key = getKey(item); + (buckets.get(key) || (keys.push(key), buckets.set(key, []))).push(item); + }); + return { + keys: keys, + buckets: buckets + }; + } + /** + * Interpolate raw values of a series with percent + * + * @param data data + * @param labelModel label model of the text element + * @param sourceValue start value. May be null/undefined when init. + * @param targetValue end value + * @param percent 0~1 percentage; 0 uses start value while 1 uses end value + * @return interpolated values + * If `sourceValue` and `targetValue` are `number`, return `number`. + * If `sourceValue` and `targetValue` are `string`, return `string`. + * If `sourceValue` and `targetValue` are `(string | number)[]`, return `(string | number)[]`. + * Other cases do not supported. + */ + + function interpolateRawValues(data, precision, sourceValue, targetValue, percent) { + var isAutoPrecision = precision == null || precision === 'auto'; + + if (targetValue == null) { + return targetValue; + } + + if (isNumber(targetValue)) { + var value = interpolateNumber$1(sourceValue || 0, targetValue, percent); + return round(value, isAutoPrecision ? Math.max(getPrecision(sourceValue || 0), getPrecision(targetValue)) : precision); + } else if (isString(targetValue)) { + return percent < 1 ? sourceValue : targetValue; + } else { + var interpolated = []; + var leftArr = sourceValue; + var rightArr = targetValue; + var length_1 = Math.max(leftArr ? leftArr.length : 0, rightArr.length); + + for (var i = 0; i < length_1; ++i) { + var info = data.getDimensionInfo(i); // Don't interpolate ordinal dims + + if (info && info.type === 'ordinal') { + // In init, there is no `sourceValue`, but should better not to get undefined result. + interpolated[i] = (percent < 1 && leftArr ? leftArr : rightArr)[i]; + } else { + var leftVal = leftArr && leftArr[i] ? leftArr[i] : 0; + var rightVal = rightArr[i]; + var value = interpolateNumber$1(leftVal, rightVal, percent); + interpolated[i] = round(value, isAutoPrecision ? Math.max(getPrecision(leftVal), getPrecision(rightVal)) : precision); + } + } + + return interpolated; + } + } + + var TYPE_DELIMITER = '.'; + var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___'; + var IS_EXTENDED_CLASS = '___EC__EXTENDED_CLASS___'; + /** + * Notice, parseClassType('') should returns {main: '', sub: ''} + * @public + */ + + function parseClassType(componentType) { + var ret = { + main: '', + sub: '' + }; + + if (componentType) { + var typeArr = componentType.split(TYPE_DELIMITER); + ret.main = typeArr[0] || ''; + ret.sub = typeArr[1] || ''; + } + + return ret; + } + /** + * @public + */ + + function checkClassType(componentType) { + assert(/^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType), 'componentType "' + componentType + '" illegal'); + } + + function isExtendedClass(clz) { + return !!(clz && clz[IS_EXTENDED_CLASS]); + } + /** + * Implements `ExtendableConstructor` for `rootClz`. + * + * @usage + * ```ts + * class Xxx {} + * type XxxConstructor = typeof Xxx & ExtendableConstructor + * enableClassExtend(Xxx as XxxConstructor); + * ``` + */ + + function enableClassExtend(rootClz, mandatoryMethods) { + rootClz.$constructor = rootClz; // FIXME: not necessary? + + rootClz.extend = function (proto) { + if ("development" !== 'production') { + each(mandatoryMethods, function (method) { + if (!proto[method]) { + console.warn('Method `' + method + '` should be implemented' + (proto.type ? ' in ' + proto.type : '') + '.'); + } + }); + } + + var superClass = this; + var ExtendedClass; + + if (isESClass(superClass)) { + ExtendedClass = + /** @class */ + function (_super) { + __extends(class_1, _super); + + function class_1() { + return _super.apply(this, arguments) || this; + } + + return class_1; + }(superClass); + } else { + // For backward compat, we both support ts class inheritance and this + // "extend" approach. + // The constructor should keep the same behavior as ts class inheritance: + // If this constructor/$constructor is not declared, auto invoke the super + // constructor. + // If this constructor/$constructor is declared, it is responsible for + // calling the super constructor. + ExtendedClass = function () { + (proto.$constructor || superClass).apply(this, arguments); + }; + + inherits(ExtendedClass, this); + } + + extend(ExtendedClass.prototype, proto); + ExtendedClass[IS_EXTENDED_CLASS] = true; + ExtendedClass.extend = this.extend; + ExtendedClass.superCall = superCall; + ExtendedClass.superApply = superApply; + ExtendedClass.superClass = superClass; + return ExtendedClass; + }; + } + + function isESClass(fn) { + return isFunction(fn) && /^class\s/.test(Function.prototype.toString.call(fn)); + } + /** + * A work around to both support ts extend and this extend mechanism. + * on sub-class. + * @usage + * ```ts + * class Component { ... } + * classUtil.enableClassExtend(Component); + * classUtil.enableClassManagement(Component, {registerWhenExtend: true}); + * + * class Series extends Component { ... } + * // Without calling `markExtend`, `registerWhenExtend` will not work. + * Component.markExtend(Series); + * ``` + */ + + + function mountExtend(SubClz, SupperClz) { + SubClz.extend = SupperClz.extend; + } // A random offset. + + var classBase = Math.round(Math.random() * 10); + /** + * Implements `CheckableConstructor` for `target`. + * Can not use instanceof, consider different scope by + * cross domain or es module import in ec extensions. + * Mount a method "isInstance()" to Clz. + * + * @usage + * ```ts + * class Xxx {} + * type XxxConstructor = typeof Xxx & CheckableConstructor; + * enableClassCheck(Xxx as XxxConstructor) + * ``` + */ + + function enableClassCheck(target) { + var classAttr = ['__\0is_clz', classBase++].join('_'); + target.prototype[classAttr] = true; + + if ("development" !== 'production') { + assert(!target.isInstance, 'The method "is" can not be defined.'); + } + + target.isInstance = function (obj) { + return !!(obj && obj[classAttr]); + }; + } // superCall should have class info, which can not be fetch from 'this'. + // Consider this case: + // class A has method f, + // class B inherits class A, overrides method f, f call superApply('f'), + // class C inherits class B, do not overrides method f, + // then when method of class C is called, dead loop occured. + + function superCall(context, methodName) { + var args = []; + + for (var _i = 2; _i < arguments.length; _i++) { + args[_i - 2] = arguments[_i]; + } + + return this.superClass.prototype[methodName].apply(context, args); + } + + function superApply(context, methodName, args) { + return this.superClass.prototype[methodName].apply(context, args); + } + /** + * Implements `ClassManager` for `target` + * + * @usage + * ```ts + * class Xxx {} + * type XxxConstructor = typeof Xxx & ClassManager + * enableClassManagement(Xxx as XxxConstructor); + * ``` + */ + + + function enableClassManagement(target) { + /** + * Component model classes + * key: componentType, + * value: + * componentClass, when componentType is 'xxx' + * or Object., when componentType is 'xxx.yy' + */ + var storage = {}; + + target.registerClass = function (clz) { + // `type` should not be a "instance memeber". + // If using TS class, should better declared as `static type = 'series.pie'`. + // otherwise users have to mount `type` on prototype manually. + // For backward compat and enable instance visit type via `this.type`, + // we stil support fetch `type` from prototype. + var componentFullType = clz.type || clz.prototype.type; + + if (componentFullType) { + checkClassType(componentFullType); // If only static type declared, we assign it to prototype mandatorily. + + clz.prototype.type = componentFullType; + var componentTypeInfo = parseClassType(componentFullType); + + if (!componentTypeInfo.sub) { + if ("development" !== 'production') { + if (storage[componentTypeInfo.main]) { + console.warn(componentTypeInfo.main + ' exists.'); + } + } + + storage[componentTypeInfo.main] = clz; + } else if (componentTypeInfo.sub !== IS_CONTAINER) { + var container = makeContainer(componentTypeInfo); + container[componentTypeInfo.sub] = clz; + } + } + + return clz; + }; + + target.getClass = function (mainType, subType, throwWhenNotFound) { + var clz = storage[mainType]; + + if (clz && clz[IS_CONTAINER]) { + clz = subType ? clz[subType] : null; + } + + if (throwWhenNotFound && !clz) { + throw new Error(!subType ? mainType + '.' + 'type should be specified.' : 'Component ' + mainType + '.' + (subType || '') + ' is used but not imported.'); + } + + return clz; + }; + + target.getClassesByMainType = function (componentType) { + var componentTypeInfo = parseClassType(componentType); + var result = []; + var obj = storage[componentTypeInfo.main]; + + if (obj && obj[IS_CONTAINER]) { + each(obj, function (o, type) { + type !== IS_CONTAINER && result.push(o); + }); + } else { + result.push(obj); + } + + return result; + }; + + target.hasClass = function (componentType) { + // Just consider componentType.main. + var componentTypeInfo = parseClassType(componentType); + return !!storage[componentTypeInfo.main]; + }; + /** + * @return Like ['aa', 'bb'], but can not be ['aa.xx'] + */ + + + target.getAllClassMainTypes = function () { + var types = []; + each(storage, function (obj, type) { + types.push(type); + }); + return types; + }; + /** + * If a main type is container and has sub types + */ + + + target.hasSubTypes = function (componentType) { + var componentTypeInfo = parseClassType(componentType); + var obj = storage[componentTypeInfo.main]; + return obj && obj[IS_CONTAINER]; + }; + + function makeContainer(componentTypeInfo) { + var container = storage[componentTypeInfo.main]; + + if (!container || !container[IS_CONTAINER]) { + container = storage[componentTypeInfo.main] = {}; + container[IS_CONTAINER] = true; + } + + return container; + } + } // /** + // * @param {string|Array.} properties + // */ + // export function setReadOnly(obj, properties) { + // FIXME It seems broken in IE8 simulation of IE11 + // if (!zrUtil.isArray(properties)) { + // properties = properties != null ? [properties] : []; + // } + // zrUtil.each(properties, function (prop) { + // let value = obj[prop]; + // Object.defineProperty + // && Object.defineProperty(obj, prop, { + // value: value, writable: false + // }); + // zrUtil.isArray(obj[prop]) + // && Object.freeze + // && Object.freeze(obj[prop]); + // }); + // } + + function makeStyleMapper(properties, ignoreParent) { + // Normalize + for (var i = 0; i < properties.length; i++) { + if (!properties[i][1]) { + properties[i][1] = properties[i][0]; + } + } + + ignoreParent = ignoreParent || false; + return function (model, excludes, includes) { + var style = {}; + + for (var i = 0; i < properties.length; i++) { + var propName = properties[i][1]; + + if (excludes && indexOf(excludes, propName) >= 0 || includes && indexOf(includes, propName) < 0) { + continue; + } + + var val = model.getShallow(propName, ignoreParent); + + if (val != null) { + style[properties[i][0]] = val; + } + } // TODO Text or image? + + + return style; + }; + } + + var AREA_STYLE_KEY_MAP = [['fill', 'color'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['opacity'], ['shadowColor'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`. + // So do not transfer decal directly. + ]; + var getAreaStyle = makeStyleMapper(AREA_STYLE_KEY_MAP); + + var AreaStyleMixin = + /** @class */ + function () { + function AreaStyleMixin() {} + + AreaStyleMixin.prototype.getAreaStyle = function (excludes, includes) { + return getAreaStyle(this, excludes, includes); + }; + + return AreaStyleMixin; + }(); + + var globalImageCache = new LRU(50); + function findExistImage(newImageOrSrc) { + if (typeof newImageOrSrc === 'string') { + var cachedImgObj = globalImageCache.get(newImageOrSrc); + return cachedImgObj && cachedImgObj.image; + } + else { + return newImageOrSrc; + } + } + function createOrUpdateImage(newImageOrSrc, image, hostEl, onload, cbPayload) { + if (!newImageOrSrc) { + return image; + } + else if (typeof newImageOrSrc === 'string') { + if ((image && image.__zrImageSrc === newImageOrSrc) || !hostEl) { + return image; + } + var cachedImgObj = globalImageCache.get(newImageOrSrc); + var pendingWrap = { hostEl: hostEl, cb: onload, cbPayload: cbPayload }; + if (cachedImgObj) { + image = cachedImgObj.image; + !isImageReady(image) && cachedImgObj.pending.push(pendingWrap); + } + else { + var image_1 = platformApi.loadImage(newImageOrSrc, imageOnLoad, imageOnLoad); + image_1.__zrImageSrc = newImageOrSrc; + globalImageCache.put(newImageOrSrc, image_1.__cachedImgObj = { + image: image_1, + pending: [pendingWrap] + }); + } + return image; + } + else { + return newImageOrSrc; + } + } + function imageOnLoad() { + var cachedImgObj = this.__cachedImgObj; + this.onload = this.onerror = this.__cachedImgObj = null; + for (var i = 0; i < cachedImgObj.pending.length; i++) { + var pendingWrap = cachedImgObj.pending[i]; + var cb = pendingWrap.cb; + cb && cb(this, pendingWrap.cbPayload); + pendingWrap.hostEl.dirty(); + } + cachedImgObj.pending.length = 0; + } + function isImageReady(image) { + return image && image.width && image.height; + } + + var STYLE_REG = /\{([a-zA-Z0-9_]+)\|([^}]*)\}/g; + function truncateText(text, containerWidth, font, ellipsis, options) { + if (!containerWidth) { + return ''; + } + var textLines = (text + '').split('\n'); + options = prepareTruncateOptions(containerWidth, font, ellipsis, options); + for (var i = 0, len = textLines.length; i < len; i++) { + textLines[i] = truncateSingleLine(textLines[i], options); + } + return textLines.join('\n'); + } + function prepareTruncateOptions(containerWidth, font, ellipsis, options) { + options = options || {}; + var preparedOpts = extend({}, options); + preparedOpts.font = font; + ellipsis = retrieve2(ellipsis, '...'); + preparedOpts.maxIterations = retrieve2(options.maxIterations, 2); + var minChar = preparedOpts.minChar = retrieve2(options.minChar, 0); + preparedOpts.cnCharWidth = getWidth('国', font); + var ascCharWidth = preparedOpts.ascCharWidth = getWidth('a', font); + preparedOpts.placeholder = retrieve2(options.placeholder, ''); + var contentWidth = containerWidth = Math.max(0, containerWidth - 1); + for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) { + contentWidth -= ascCharWidth; + } + var ellipsisWidth = getWidth(ellipsis, font); + if (ellipsisWidth > contentWidth) { + ellipsis = ''; + ellipsisWidth = 0; + } + contentWidth = containerWidth - ellipsisWidth; + preparedOpts.ellipsis = ellipsis; + preparedOpts.ellipsisWidth = ellipsisWidth; + preparedOpts.contentWidth = contentWidth; + preparedOpts.containerWidth = containerWidth; + return preparedOpts; + } + function truncateSingleLine(textLine, options) { + var containerWidth = options.containerWidth; + var font = options.font; + var contentWidth = options.contentWidth; + if (!containerWidth) { + return ''; + } + var lineWidth = getWidth(textLine, font); + if (lineWidth <= containerWidth) { + return textLine; + } + for (var j = 0;; j++) { + if (lineWidth <= contentWidth || j >= options.maxIterations) { + textLine += options.ellipsis; + break; + } + var subLength = j === 0 + ? estimateLength(textLine, contentWidth, options.ascCharWidth, options.cnCharWidth) + : lineWidth > 0 + ? Math.floor(textLine.length * contentWidth / lineWidth) + : 0; + textLine = textLine.substr(0, subLength); + lineWidth = getWidth(textLine, font); + } + if (textLine === '') { + textLine = options.placeholder; + } + return textLine; + } + function estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) { + var width = 0; + var i = 0; + for (var len = text.length; i < len && width < contentWidth; i++) { + var charCode = text.charCodeAt(i); + width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth; + } + return i; + } + function parsePlainText(text, style) { + text != null && (text += ''); + var overflow = style.overflow; + var padding = style.padding; + var font = style.font; + var truncate = overflow === 'truncate'; + var calculatedLineHeight = getLineHeight(font); + var lineHeight = retrieve2(style.lineHeight, calculatedLineHeight); + var bgColorDrawn = !!(style.backgroundColor); + var truncateLineOverflow = style.lineOverflow === 'truncate'; + var width = style.width; + var lines; + if (width != null && (overflow === 'break' || overflow === 'breakAll')) { + lines = text ? wrapText(text, style.font, width, overflow === 'breakAll', 0).lines : []; + } + else { + lines = text ? text.split('\n') : []; + } + var contentHeight = lines.length * lineHeight; + var height = retrieve2(style.height, contentHeight); + if (contentHeight > height && truncateLineOverflow) { + var lineCount = Math.floor(height / lineHeight); + lines = lines.slice(0, lineCount); + } + if (text && truncate && width != null) { + var options = prepareTruncateOptions(width, font, style.ellipsis, { + minChar: style.truncateMinChar, + placeholder: style.placeholder + }); + for (var i = 0; i < lines.length; i++) { + lines[i] = truncateSingleLine(lines[i], options); + } + } + var outerHeight = height; + var contentWidth = 0; + for (var i = 0; i < lines.length; i++) { + contentWidth = Math.max(getWidth(lines[i], font), contentWidth); + } + if (width == null) { + width = contentWidth; + } + var outerWidth = contentWidth; + if (padding) { + outerHeight += padding[0] + padding[2]; + outerWidth += padding[1] + padding[3]; + width += padding[1] + padding[3]; + } + if (bgColorDrawn) { + outerWidth = width; + } + return { + lines: lines, + height: height, + outerWidth: outerWidth, + outerHeight: outerHeight, + lineHeight: lineHeight, + calculatedLineHeight: calculatedLineHeight, + contentWidth: contentWidth, + contentHeight: contentHeight, + width: width + }; + } + var RichTextToken = (function () { + function RichTextToken() { + } + return RichTextToken; + }()); + var RichTextLine = (function () { + function RichTextLine(tokens) { + this.tokens = []; + if (tokens) { + this.tokens = tokens; + } + } + return RichTextLine; + }()); + var RichTextContentBlock = (function () { + function RichTextContentBlock() { + this.width = 0; + this.height = 0; + this.contentWidth = 0; + this.contentHeight = 0; + this.outerWidth = 0; + this.outerHeight = 0; + this.lines = []; + } + return RichTextContentBlock; + }()); + function parseRichText(text, style) { + var contentBlock = new RichTextContentBlock(); + text != null && (text += ''); + if (!text) { + return contentBlock; + } + var topWidth = style.width; + var topHeight = style.height; + var overflow = style.overflow; + var wrapInfo = (overflow === 'break' || overflow === 'breakAll') && topWidth != null + ? { width: topWidth, accumWidth: 0, breakAll: overflow === 'breakAll' } + : null; + var lastIndex = STYLE_REG.lastIndex = 0; + var result; + while ((result = STYLE_REG.exec(text)) != null) { + var matchedIndex = result.index; + if (matchedIndex > lastIndex) { + pushTokens(contentBlock, text.substring(lastIndex, matchedIndex), style, wrapInfo); + } + pushTokens(contentBlock, result[2], style, wrapInfo, result[1]); + lastIndex = STYLE_REG.lastIndex; + } + if (lastIndex < text.length) { + pushTokens(contentBlock, text.substring(lastIndex, text.length), style, wrapInfo); + } + var pendingList = []; + var calculatedHeight = 0; + var calculatedWidth = 0; + var stlPadding = style.padding; + var truncate = overflow === 'truncate'; + var truncateLine = style.lineOverflow === 'truncate'; + function finishLine(line, lineWidth, lineHeight) { + line.width = lineWidth; + line.lineHeight = lineHeight; + calculatedHeight += lineHeight; + calculatedWidth = Math.max(calculatedWidth, lineWidth); + } + outer: for (var i = 0; i < contentBlock.lines.length; i++) { + var line = contentBlock.lines[i]; + var lineHeight = 0; + var lineWidth = 0; + for (var j = 0; j < line.tokens.length; j++) { + var token = line.tokens[j]; + var tokenStyle = token.styleName && style.rich[token.styleName] || {}; + var textPadding = token.textPadding = tokenStyle.padding; + var paddingH = textPadding ? textPadding[1] + textPadding[3] : 0; + var font = token.font = tokenStyle.font || style.font; + token.contentHeight = getLineHeight(font); + var tokenHeight = retrieve2(tokenStyle.height, token.contentHeight); + token.innerHeight = tokenHeight; + textPadding && (tokenHeight += textPadding[0] + textPadding[2]); + token.height = tokenHeight; + token.lineHeight = retrieve3(tokenStyle.lineHeight, style.lineHeight, tokenHeight); + token.align = tokenStyle && tokenStyle.align || style.align; + token.verticalAlign = tokenStyle && tokenStyle.verticalAlign || 'middle'; + if (truncateLine && topHeight != null && calculatedHeight + token.lineHeight > topHeight) { + if (j > 0) { + line.tokens = line.tokens.slice(0, j); + finishLine(line, lineWidth, lineHeight); + contentBlock.lines = contentBlock.lines.slice(0, i + 1); + } + else { + contentBlock.lines = contentBlock.lines.slice(0, i); + } + break outer; + } + var styleTokenWidth = tokenStyle.width; + var tokenWidthNotSpecified = styleTokenWidth == null || styleTokenWidth === 'auto'; + if (typeof styleTokenWidth === 'string' && styleTokenWidth.charAt(styleTokenWidth.length - 1) === '%') { + token.percentWidth = styleTokenWidth; + pendingList.push(token); + token.contentWidth = getWidth(token.text, font); + } + else { + if (tokenWidthNotSpecified) { + var textBackgroundColor = tokenStyle.backgroundColor; + var bgImg = textBackgroundColor && textBackgroundColor.image; + if (bgImg) { + bgImg = findExistImage(bgImg); + if (isImageReady(bgImg)) { + token.width = Math.max(token.width, bgImg.width * tokenHeight / bgImg.height); + } + } + } + var remainTruncWidth = truncate && topWidth != null + ? topWidth - lineWidth : null; + if (remainTruncWidth != null && remainTruncWidth < token.width) { + if (!tokenWidthNotSpecified || remainTruncWidth < paddingH) { + token.text = ''; + token.width = token.contentWidth = 0; + } + else { + token.text = truncateText(token.text, remainTruncWidth - paddingH, font, style.ellipsis, { minChar: style.truncateMinChar }); + token.width = token.contentWidth = getWidth(token.text, font); + } + } + else { + token.contentWidth = getWidth(token.text, font); + } + } + token.width += paddingH; + lineWidth += token.width; + tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight)); + } + finishLine(line, lineWidth, lineHeight); + } + contentBlock.outerWidth = contentBlock.width = retrieve2(topWidth, calculatedWidth); + contentBlock.outerHeight = contentBlock.height = retrieve2(topHeight, calculatedHeight); + contentBlock.contentHeight = calculatedHeight; + contentBlock.contentWidth = calculatedWidth; + if (stlPadding) { + contentBlock.outerWidth += stlPadding[1] + stlPadding[3]; + contentBlock.outerHeight += stlPadding[0] + stlPadding[2]; + } + for (var i = 0; i < pendingList.length; i++) { + var token = pendingList[i]; + var percentWidth = token.percentWidth; + token.width = parseInt(percentWidth, 10) / 100 * contentBlock.width; + } + return contentBlock; + } + function pushTokens(block, str, style, wrapInfo, styleName) { + var isEmptyStr = str === ''; + var tokenStyle = styleName && style.rich[styleName] || {}; + var lines = block.lines; + var font = tokenStyle.font || style.font; + var newLine = false; + var strLines; + var linesWidths; + if (wrapInfo) { + var tokenPadding = tokenStyle.padding; + var tokenPaddingH = tokenPadding ? tokenPadding[1] + tokenPadding[3] : 0; + if (tokenStyle.width != null && tokenStyle.width !== 'auto') { + var outerWidth_1 = parsePercent(tokenStyle.width, wrapInfo.width) + tokenPaddingH; + if (lines.length > 0) { + if (outerWidth_1 + wrapInfo.accumWidth > wrapInfo.width) { + strLines = str.split('\n'); + newLine = true; + } + } + wrapInfo.accumWidth = outerWidth_1; + } + else { + var res = wrapText(str, font, wrapInfo.width, wrapInfo.breakAll, wrapInfo.accumWidth); + wrapInfo.accumWidth = res.accumWidth + tokenPaddingH; + linesWidths = res.linesWidths; + strLines = res.lines; + } + } + else { + strLines = str.split('\n'); + } + for (var i = 0; i < strLines.length; i++) { + var text = strLines[i]; + var token = new RichTextToken(); + token.styleName = styleName; + token.text = text; + token.isLineHolder = !text && !isEmptyStr; + if (typeof tokenStyle.width === 'number') { + token.width = tokenStyle.width; + } + else { + token.width = linesWidths + ? linesWidths[i] + : getWidth(text, font); + } + if (!i && !newLine) { + var tokens = (lines[lines.length - 1] || (lines[0] = new RichTextLine())).tokens; + var tokensLen = tokens.length; + (tokensLen === 1 && tokens[0].isLineHolder) + ? (tokens[0] = token) + : ((text || !tokensLen || isEmptyStr) && tokens.push(token)); + } + else { + lines.push(new RichTextLine([token])); + } + } + } + function isLatin(ch) { + var code = ch.charCodeAt(0); + return code >= 0x21 && code <= 0x17F; + } + var breakCharMap = reduce(',&?/;] '.split(''), function (obj, ch) { + obj[ch] = true; + return obj; + }, {}); + function isWordBreakChar(ch) { + if (isLatin(ch)) { + if (breakCharMap[ch]) { + return true; + } + return false; + } + return true; + } + function wrapText(text, font, lineWidth, isBreakAll, lastAccumWidth) { + var lines = []; + var linesWidths = []; + var line = ''; + var currentWord = ''; + var currentWordWidth = 0; + var accumWidth = 0; + for (var i = 0; i < text.length; i++) { + var ch = text.charAt(i); + if (ch === '\n') { + if (currentWord) { + line += currentWord; + accumWidth += currentWordWidth; + } + lines.push(line); + linesWidths.push(accumWidth); + line = ''; + currentWord = ''; + currentWordWidth = 0; + accumWidth = 0; + continue; + } + var chWidth = getWidth(ch, font); + var inWord = isBreakAll ? false : !isWordBreakChar(ch); + if (!lines.length + ? lastAccumWidth + accumWidth + chWidth > lineWidth + : accumWidth + chWidth > lineWidth) { + if (!accumWidth) { + if (inWord) { + lines.push(currentWord); + linesWidths.push(currentWordWidth); + currentWord = ch; + currentWordWidth = chWidth; + } + else { + lines.push(ch); + linesWidths.push(chWidth); + } + } + else if (line || currentWord) { + if (inWord) { + if (!line) { + line = currentWord; + currentWord = ''; + currentWordWidth = 0; + accumWidth = currentWordWidth; + } + lines.push(line); + linesWidths.push(accumWidth - currentWordWidth); + currentWord += ch; + currentWordWidth += chWidth; + line = ''; + accumWidth = currentWordWidth; + } + else { + if (currentWord) { + line += currentWord; + currentWord = ''; + currentWordWidth = 0; + } + lines.push(line); + linesWidths.push(accumWidth); + line = ch; + accumWidth = chWidth; + } + } + continue; + } + accumWidth += chWidth; + if (inWord) { + currentWord += ch; + currentWordWidth += chWidth; + } + else { + if (currentWord) { + line += currentWord; + currentWord = ''; + currentWordWidth = 0; + } + line += ch; + } + } + if (!lines.length && !line) { + line = text; + currentWord = ''; + currentWordWidth = 0; + } + if (currentWord) { + line += currentWord; + } + if (line) { + lines.push(line); + linesWidths.push(accumWidth); + } + if (lines.length === 1) { + accumWidth += lastAccumWidth; + } + return { + accumWidth: accumWidth, + lines: lines, + linesWidths: linesWidths + }; + } + + var STYLE_MAGIC_KEY = '__zr_style_' + Math.round((Math.random() * 10)); + var DEFAULT_COMMON_STYLE = { + shadowBlur: 0, + shadowOffsetX: 0, + shadowOffsetY: 0, + shadowColor: '#000', + opacity: 1, + blend: 'source-over' + }; + var DEFAULT_COMMON_ANIMATION_PROPS = { + style: { + shadowBlur: true, + shadowOffsetX: true, + shadowOffsetY: true, + shadowColor: true, + opacity: true + } + }; + DEFAULT_COMMON_STYLE[STYLE_MAGIC_KEY] = true; + var PRIMARY_STATES_KEYS$1 = ['z', 'z2', 'invisible']; + var PRIMARY_STATES_KEYS_IN_HOVER_LAYER = ['invisible']; + var Displayable = (function (_super) { + __extends(Displayable, _super); + function Displayable(props) { + return _super.call(this, props) || this; + } + Displayable.prototype._init = function (props) { + var keysArr = keys(props); + for (var i = 0; i < keysArr.length; i++) { + var key = keysArr[i]; + if (key === 'style') { + this.useStyle(props[key]); + } + else { + _super.prototype.attrKV.call(this, key, props[key]); + } + } + if (!this.style) { + this.useStyle({}); + } + }; + Displayable.prototype.beforeBrush = function () { }; + Displayable.prototype.afterBrush = function () { }; + Displayable.prototype.innerBeforeBrush = function () { }; + Displayable.prototype.innerAfterBrush = function () { }; + Displayable.prototype.shouldBePainted = function (viewWidth, viewHeight, considerClipPath, considerAncestors) { + var m = this.transform; + if (this.ignore + || this.invisible + || this.style.opacity === 0 + || (this.culling + && isDisplayableCulled(this, viewWidth, viewHeight)) + || (m && !m[0] && !m[3])) { + return false; + } + if (considerClipPath && this.__clipPaths) { + for (var i = 0; i < this.__clipPaths.length; ++i) { + if (this.__clipPaths[i].isZeroArea()) { + return false; + } + } + } + if (considerAncestors && this.parent) { + var parent_1 = this.parent; + while (parent_1) { + if (parent_1.ignore) { + return false; + } + parent_1 = parent_1.parent; + } + } + return true; + }; + Displayable.prototype.contain = function (x, y) { + return this.rectContain(x, y); + }; + Displayable.prototype.traverse = function (cb, context) { + cb.call(context, this); + }; + Displayable.prototype.rectContain = function (x, y) { + var coord = this.transformCoordToLocal(x, y); + var rect = this.getBoundingRect(); + return rect.contain(coord[0], coord[1]); + }; + Displayable.prototype.getPaintRect = function () { + var rect = this._paintRect; + if (!this._paintRect || this.__dirty) { + var transform = this.transform; + var elRect = this.getBoundingRect(); + var style = this.style; + var shadowSize = style.shadowBlur || 0; + var shadowOffsetX = style.shadowOffsetX || 0; + var shadowOffsetY = style.shadowOffsetY || 0; + rect = this._paintRect || (this._paintRect = new BoundingRect(0, 0, 0, 0)); + if (transform) { + BoundingRect.applyTransform(rect, elRect, transform); + } + else { + rect.copy(elRect); + } + if (shadowSize || shadowOffsetX || shadowOffsetY) { + rect.width += shadowSize * 2 + Math.abs(shadowOffsetX); + rect.height += shadowSize * 2 + Math.abs(shadowOffsetY); + rect.x = Math.min(rect.x, rect.x + shadowOffsetX - shadowSize); + rect.y = Math.min(rect.y, rect.y + shadowOffsetY - shadowSize); + } + var tolerance = this.dirtyRectTolerance; + if (!rect.isZero()) { + rect.x = Math.floor(rect.x - tolerance); + rect.y = Math.floor(rect.y - tolerance); + rect.width = Math.ceil(rect.width + 1 + tolerance * 2); + rect.height = Math.ceil(rect.height + 1 + tolerance * 2); + } + } + return rect; + }; + Displayable.prototype.setPrevPaintRect = function (paintRect) { + if (paintRect) { + this._prevPaintRect = this._prevPaintRect || new BoundingRect(0, 0, 0, 0); + this._prevPaintRect.copy(paintRect); + } + else { + this._prevPaintRect = null; + } + }; + Displayable.prototype.getPrevPaintRect = function () { + return this._prevPaintRect; + }; + Displayable.prototype.animateStyle = function (loop) { + return this.animate('style', loop); + }; + Displayable.prototype.updateDuringAnimation = function (targetKey) { + if (targetKey === 'style') { + this.dirtyStyle(); + } + else { + this.markRedraw(); + } + }; + Displayable.prototype.attrKV = function (key, value) { + if (key !== 'style') { + _super.prototype.attrKV.call(this, key, value); + } + else { + if (!this.style) { + this.useStyle(value); + } + else { + this.setStyle(value); + } + } + }; + Displayable.prototype.setStyle = function (keyOrObj, value) { + if (typeof keyOrObj === 'string') { + this.style[keyOrObj] = value; + } + else { + extend(this.style, keyOrObj); + } + this.dirtyStyle(); + return this; + }; + Displayable.prototype.dirtyStyle = function (notRedraw) { + if (!notRedraw) { + this.markRedraw(); + } + this.__dirty |= STYLE_CHANGED_BIT; + if (this._rect) { + this._rect = null; + } + }; + Displayable.prototype.dirty = function () { + this.dirtyStyle(); + }; + Displayable.prototype.styleChanged = function () { + return !!(this.__dirty & STYLE_CHANGED_BIT); + }; + Displayable.prototype.styleUpdated = function () { + this.__dirty &= ~STYLE_CHANGED_BIT; + }; + Displayable.prototype.createStyle = function (obj) { + return createObject(DEFAULT_COMMON_STYLE, obj); + }; + Displayable.prototype.useStyle = function (obj) { + if (!obj[STYLE_MAGIC_KEY]) { + obj = this.createStyle(obj); + } + if (this.__inHover) { + this.__hoverStyle = obj; + } + else { + this.style = obj; + } + this.dirtyStyle(); + }; + Displayable.prototype.isStyleObject = function (obj) { + return obj[STYLE_MAGIC_KEY]; + }; + Displayable.prototype._innerSaveToNormal = function (toState) { + _super.prototype._innerSaveToNormal.call(this, toState); + var normalState = this._normalState; + if (toState.style && !normalState.style) { + normalState.style = this._mergeStyle(this.createStyle(), this.style); + } + this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS$1); + }; + Displayable.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) { + _super.prototype._applyStateObj.call(this, stateName, state, normalState, keepCurrentStates, transition, animationCfg); + var needsRestoreToNormal = !(state && keepCurrentStates); + var targetStyle; + if (state && state.style) { + if (transition) { + if (keepCurrentStates) { + targetStyle = state.style; + } + else { + targetStyle = this._mergeStyle(this.createStyle(), normalState.style); + this._mergeStyle(targetStyle, state.style); + } + } + else { + targetStyle = this._mergeStyle(this.createStyle(), keepCurrentStates ? this.style : normalState.style); + this._mergeStyle(targetStyle, state.style); + } + } + else if (needsRestoreToNormal) { + targetStyle = normalState.style; + } + if (targetStyle) { + if (transition) { + var sourceStyle = this.style; + this.style = this.createStyle(needsRestoreToNormal ? {} : sourceStyle); + if (needsRestoreToNormal) { + var changedKeys = keys(sourceStyle); + for (var i = 0; i < changedKeys.length; i++) { + var key = changedKeys[i]; + if (key in targetStyle) { + targetStyle[key] = targetStyle[key]; + this.style[key] = sourceStyle[key]; + } + } + } + var targetKeys = keys(targetStyle); + for (var i = 0; i < targetKeys.length; i++) { + var key = targetKeys[i]; + this.style[key] = this.style[key]; + } + this._transitionState(stateName, { + style: targetStyle + }, animationCfg, this.getAnimationStyleProps()); + } + else { + this.useStyle(targetStyle); + } + } + var statesKeys = this.__inHover ? PRIMARY_STATES_KEYS_IN_HOVER_LAYER : PRIMARY_STATES_KEYS$1; + for (var i = 0; i < statesKeys.length; i++) { + var key = statesKeys[i]; + if (state && state[key] != null) { + this[key] = state[key]; + } + else if (needsRestoreToNormal) { + if (normalState[key] != null) { + this[key] = normalState[key]; + } + } + } + }; + Displayable.prototype._mergeStates = function (states) { + var mergedState = _super.prototype._mergeStates.call(this, states); + var mergedStyle; + for (var i = 0; i < states.length; i++) { + var state = states[i]; + if (state.style) { + mergedStyle = mergedStyle || {}; + this._mergeStyle(mergedStyle, state.style); + } + } + if (mergedStyle) { + mergedState.style = mergedStyle; + } + return mergedState; + }; + Displayable.prototype._mergeStyle = function (targetStyle, sourceStyle) { + extend(targetStyle, sourceStyle); + return targetStyle; + }; + Displayable.prototype.getAnimationStyleProps = function () { + return DEFAULT_COMMON_ANIMATION_PROPS; + }; + Displayable.initDefaultProps = (function () { + var dispProto = Displayable.prototype; + dispProto.type = 'displayable'; + dispProto.invisible = false; + dispProto.z = 0; + dispProto.z2 = 0; + dispProto.zlevel = 0; + dispProto.culling = false; + dispProto.cursor = 'pointer'; + dispProto.rectHover = false; + dispProto.incremental = false; + dispProto._rect = null; + dispProto.dirtyRectTolerance = 0; + dispProto.__dirty = REDRAW_BIT | STYLE_CHANGED_BIT; + })(); + return Displayable; + }(Element)); + var tmpRect = new BoundingRect(0, 0, 0, 0); + var viewRect = new BoundingRect(0, 0, 0, 0); + function isDisplayableCulled(el, width, height) { + tmpRect.copy(el.getBoundingRect()); + if (el.transform) { + tmpRect.applyTransform(el.transform); + } + viewRect.width = width; + viewRect.height = height; + return !tmpRect.intersect(viewRect); + } + + var mathMin$1 = Math.min; + var mathMax$1 = Math.max; + var mathSin = Math.sin; + var mathCos = Math.cos; + var PI2 = Math.PI * 2; + var start = create(); + var end = create(); + var extremity = create(); + function fromPoints(points, min, max) { + if (points.length === 0) { + return; + } + var p = points[0]; + var left = p[0]; + var right = p[0]; + var top = p[1]; + var bottom = p[1]; + for (var i = 1; i < points.length; i++) { + p = points[i]; + left = mathMin$1(left, p[0]); + right = mathMax$1(right, p[0]); + top = mathMin$1(top, p[1]); + bottom = mathMax$1(bottom, p[1]); + } + min[0] = left; + min[1] = top; + max[0] = right; + max[1] = bottom; + } + function fromLine(x0, y0, x1, y1, min, max) { + min[0] = mathMin$1(x0, x1); + min[1] = mathMin$1(y0, y1); + max[0] = mathMax$1(x0, x1); + max[1] = mathMax$1(y0, y1); + } + var xDim = []; + var yDim = []; + function fromCubic(x0, y0, x1, y1, x2, y2, x3, y3, min, max) { + var cubicExtrema$1 = cubicExtrema; + var cubicAt$1 = cubicAt; + var n = cubicExtrema$1(x0, x1, x2, x3, xDim); + min[0] = Infinity; + min[1] = Infinity; + max[0] = -Infinity; + max[1] = -Infinity; + for (var i = 0; i < n; i++) { + var x = cubicAt$1(x0, x1, x2, x3, xDim[i]); + min[0] = mathMin$1(x, min[0]); + max[0] = mathMax$1(x, max[0]); + } + n = cubicExtrema$1(y0, y1, y2, y3, yDim); + for (var i = 0; i < n; i++) { + var y = cubicAt$1(y0, y1, y2, y3, yDim[i]); + min[1] = mathMin$1(y, min[1]); + max[1] = mathMax$1(y, max[1]); + } + min[0] = mathMin$1(x0, min[0]); + max[0] = mathMax$1(x0, max[0]); + min[0] = mathMin$1(x3, min[0]); + max[0] = mathMax$1(x3, max[0]); + min[1] = mathMin$1(y0, min[1]); + max[1] = mathMax$1(y0, max[1]); + min[1] = mathMin$1(y3, min[1]); + max[1] = mathMax$1(y3, max[1]); + } + function fromQuadratic(x0, y0, x1, y1, x2, y2, min, max) { + var quadraticExtremum$1 = quadraticExtremum; + var quadraticAt$1 = quadraticAt; + var tx = mathMax$1(mathMin$1(quadraticExtremum$1(x0, x1, x2), 1), 0); + var ty = mathMax$1(mathMin$1(quadraticExtremum$1(y0, y1, y2), 1), 0); + var x = quadraticAt$1(x0, x1, x2, tx); + var y = quadraticAt$1(y0, y1, y2, ty); + min[0] = mathMin$1(x0, x2, x); + min[1] = mathMin$1(y0, y2, y); + max[0] = mathMax$1(x0, x2, x); + max[1] = mathMax$1(y0, y2, y); + } + function fromArc(x, y, rx, ry, startAngle, endAngle, anticlockwise, min$1, max$1) { + var vec2Min = min; + var vec2Max = max; + var diff = Math.abs(startAngle - endAngle); + if (diff % PI2 < 1e-4 && diff > 1e-4) { + min$1[0] = x - rx; + min$1[1] = y - ry; + max$1[0] = x + rx; + max$1[1] = y + ry; + return; + } + start[0] = mathCos(startAngle) * rx + x; + start[1] = mathSin(startAngle) * ry + y; + end[0] = mathCos(endAngle) * rx + x; + end[1] = mathSin(endAngle) * ry + y; + vec2Min(min$1, start, end); + vec2Max(max$1, start, end); + startAngle = startAngle % (PI2); + if (startAngle < 0) { + startAngle = startAngle + PI2; + } + endAngle = endAngle % (PI2); + if (endAngle < 0) { + endAngle = endAngle + PI2; + } + if (startAngle > endAngle && !anticlockwise) { + endAngle += PI2; + } + else if (startAngle < endAngle && anticlockwise) { + startAngle += PI2; + } + if (anticlockwise) { + var tmp = endAngle; + endAngle = startAngle; + startAngle = tmp; + } + for (var angle = 0; angle < endAngle; angle += Math.PI / 2) { + if (angle > startAngle) { + extremity[0] = mathCos(angle) * rx + x; + extremity[1] = mathSin(angle) * ry + y; + vec2Min(min$1, extremity, min$1); + vec2Max(max$1, extremity, max$1); + } + } + } + + var CMD = { + M: 1, + L: 2, + C: 3, + Q: 4, + A: 5, + Z: 6, + R: 7 + }; + var tmpOutX = []; + var tmpOutY = []; + var min$1 = []; + var max$1 = []; + var min2 = []; + var max2 = []; + var mathMin$2 = Math.min; + var mathMax$2 = Math.max; + var mathCos$1 = Math.cos; + var mathSin$1 = Math.sin; + var mathAbs = Math.abs; + var PI = Math.PI; + var PI2$1 = PI * 2; + var hasTypedArray = typeof Float32Array !== 'undefined'; + var tmpAngles = []; + function modPI2(radian) { + var n = Math.round(radian / PI * 1e8) / 1e8; + return (n % 2) * PI; + } + function normalizeArcAngles(angles, anticlockwise) { + var newStartAngle = modPI2(angles[0]); + if (newStartAngle < 0) { + newStartAngle += PI2$1; + } + var delta = newStartAngle - angles[0]; + var newEndAngle = angles[1]; + newEndAngle += delta; + if (!anticlockwise && newEndAngle - newStartAngle >= PI2$1) { + newEndAngle = newStartAngle + PI2$1; + } + else if (anticlockwise && newStartAngle - newEndAngle >= PI2$1) { + newEndAngle = newStartAngle - PI2$1; + } + else if (!anticlockwise && newStartAngle > newEndAngle) { + newEndAngle = newStartAngle + (PI2$1 - modPI2(newStartAngle - newEndAngle)); + } + else if (anticlockwise && newStartAngle < newEndAngle) { + newEndAngle = newStartAngle - (PI2$1 - modPI2(newEndAngle - newStartAngle)); + } + angles[0] = newStartAngle; + angles[1] = newEndAngle; + } + var PathProxy = (function () { + function PathProxy(notSaveData) { + this.dpr = 1; + this._xi = 0; + this._yi = 0; + this._x0 = 0; + this._y0 = 0; + this._len = 0; + if (notSaveData) { + this._saveData = false; + } + if (this._saveData) { + this.data = []; + } + } + PathProxy.prototype.increaseVersion = function () { + this._version++; + }; + PathProxy.prototype.getVersion = function () { + return this._version; + }; + PathProxy.prototype.setScale = function (sx, sy, segmentIgnoreThreshold) { + segmentIgnoreThreshold = segmentIgnoreThreshold || 0; + if (segmentIgnoreThreshold > 0) { + this._ux = mathAbs(segmentIgnoreThreshold / devicePixelRatio / sx) || 0; + this._uy = mathAbs(segmentIgnoreThreshold / devicePixelRatio / sy) || 0; + } + }; + PathProxy.prototype.setDPR = function (dpr) { + this.dpr = dpr; + }; + PathProxy.prototype.setContext = function (ctx) { + this._ctx = ctx; + }; + PathProxy.prototype.getContext = function () { + return this._ctx; + }; + PathProxy.prototype.beginPath = function () { + this._ctx && this._ctx.beginPath(); + this.reset(); + return this; + }; + PathProxy.prototype.reset = function () { + if (this._saveData) { + this._len = 0; + } + if (this._pathSegLen) { + this._pathSegLen = null; + this._pathLen = 0; + } + this._version++; + }; + PathProxy.prototype.moveTo = function (x, y) { + this._drawPendingPt(); + this.addData(CMD.M, x, y); + this._ctx && this._ctx.moveTo(x, y); + this._x0 = x; + this._y0 = y; + this._xi = x; + this._yi = y; + return this; + }; + PathProxy.prototype.lineTo = function (x, y) { + var dx = mathAbs(x - this._xi); + var dy = mathAbs(y - this._yi); + var exceedUnit = dx > this._ux || dy > this._uy; + this.addData(CMD.L, x, y); + if (this._ctx && exceedUnit) { + this._ctx.lineTo(x, y); + } + if (exceedUnit) { + this._xi = x; + this._yi = y; + this._pendingPtDist = 0; + } + else { + var d2 = dx * dx + dy * dy; + if (d2 > this._pendingPtDist) { + this._pendingPtX = x; + this._pendingPtY = y; + this._pendingPtDist = d2; + } + } + return this; + }; + PathProxy.prototype.bezierCurveTo = function (x1, y1, x2, y2, x3, y3) { + this._drawPendingPt(); + this.addData(CMD.C, x1, y1, x2, y2, x3, y3); + if (this._ctx) { + this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3); + } + this._xi = x3; + this._yi = y3; + return this; + }; + PathProxy.prototype.quadraticCurveTo = function (x1, y1, x2, y2) { + this._drawPendingPt(); + this.addData(CMD.Q, x1, y1, x2, y2); + if (this._ctx) { + this._ctx.quadraticCurveTo(x1, y1, x2, y2); + } + this._xi = x2; + this._yi = y2; + return this; + }; + PathProxy.prototype.arc = function (cx, cy, r, startAngle, endAngle, anticlockwise) { + this._drawPendingPt(); + tmpAngles[0] = startAngle; + tmpAngles[1] = endAngle; + normalizeArcAngles(tmpAngles, anticlockwise); + startAngle = tmpAngles[0]; + endAngle = tmpAngles[1]; + var delta = endAngle - startAngle; + this.addData(CMD.A, cx, cy, r, r, startAngle, delta, 0, anticlockwise ? 0 : 1); + this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise); + this._xi = mathCos$1(endAngle) * r + cx; + this._yi = mathSin$1(endAngle) * r + cy; + return this; + }; + PathProxy.prototype.arcTo = function (x1, y1, x2, y2, radius) { + this._drawPendingPt(); + if (this._ctx) { + this._ctx.arcTo(x1, y1, x2, y2, radius); + } + return this; + }; + PathProxy.prototype.rect = function (x, y, w, h) { + this._drawPendingPt(); + this._ctx && this._ctx.rect(x, y, w, h); + this.addData(CMD.R, x, y, w, h); + return this; + }; + PathProxy.prototype.closePath = function () { + this._drawPendingPt(); + this.addData(CMD.Z); + var ctx = this._ctx; + var x0 = this._x0; + var y0 = this._y0; + if (ctx) { + ctx.closePath(); + } + this._xi = x0; + this._yi = y0; + return this; + }; + PathProxy.prototype.fill = function (ctx) { + ctx && ctx.fill(); + this.toStatic(); + }; + PathProxy.prototype.stroke = function (ctx) { + ctx && ctx.stroke(); + this.toStatic(); + }; + PathProxy.prototype.len = function () { + return this._len; + }; + PathProxy.prototype.setData = function (data) { + var len = data.length; + if (!(this.data && this.data.length === len) && hasTypedArray) { + this.data = new Float32Array(len); + } + for (var i = 0; i < len; i++) { + this.data[i] = data[i]; + } + this._len = len; + }; + PathProxy.prototype.appendPath = function (path) { + if (!(path instanceof Array)) { + path = [path]; + } + var len = path.length; + var appendSize = 0; + var offset = this._len; + for (var i = 0; i < len; i++) { + appendSize += path[i].len(); + } + if (hasTypedArray && (this.data instanceof Float32Array)) { + this.data = new Float32Array(offset + appendSize); + } + for (var i = 0; i < len; i++) { + var appendPathData = path[i].data; + for (var k = 0; k < appendPathData.length; k++) { + this.data[offset++] = appendPathData[k]; + } + } + this._len = offset; + }; + PathProxy.prototype.addData = function (cmd, a, b, c, d, e, f, g, h) { + if (!this._saveData) { + return; + } + var data = this.data; + if (this._len + arguments.length > data.length) { + this._expandData(); + data = this.data; + } + for (var i = 0; i < arguments.length; i++) { + data[this._len++] = arguments[i]; + } + }; + PathProxy.prototype._drawPendingPt = function () { + if (this._pendingPtDist > 0) { + this._ctx && this._ctx.lineTo(this._pendingPtX, this._pendingPtY); + this._pendingPtDist = 0; + } + }; + PathProxy.prototype._expandData = function () { + if (!(this.data instanceof Array)) { + var newData = []; + for (var i = 0; i < this._len; i++) { + newData[i] = this.data[i]; + } + this.data = newData; + } + }; + PathProxy.prototype.toStatic = function () { + if (!this._saveData) { + return; + } + this._drawPendingPt(); + var data = this.data; + if (data instanceof Array) { + data.length = this._len; + if (hasTypedArray && this._len > 11) { + this.data = new Float32Array(data); + } + } + }; + PathProxy.prototype.getBoundingRect = function () { + min$1[0] = min$1[1] = min2[0] = min2[1] = Number.MAX_VALUE; + max$1[0] = max$1[1] = max2[0] = max2[1] = -Number.MAX_VALUE; + var data = this.data; + var xi = 0; + var yi = 0; + var x0 = 0; + var y0 = 0; + var i; + for (i = 0; i < this._len;) { + var cmd = data[i++]; + var isFirst = i === 1; + if (isFirst) { + xi = data[i]; + yi = data[i + 1]; + x0 = xi; + y0 = yi; + } + switch (cmd) { + case CMD.M: + xi = x0 = data[i++]; + yi = y0 = data[i++]; + min2[0] = x0; + min2[1] = y0; + max2[0] = x0; + max2[1] = y0; + break; + case CMD.L: + fromLine(xi, yi, data[i], data[i + 1], min2, max2); + xi = data[i++]; + yi = data[i++]; + break; + case CMD.C: + fromCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], min2, max2); + xi = data[i++]; + yi = data[i++]; + break; + case CMD.Q: + fromQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], min2, max2); + xi = data[i++]; + yi = data[i++]; + break; + case CMD.A: + var cx = data[i++]; + var cy = data[i++]; + var rx = data[i++]; + var ry = data[i++]; + var startAngle = data[i++]; + var endAngle = data[i++] + startAngle; + i += 1; + var anticlockwise = !data[i++]; + if (isFirst) { + x0 = mathCos$1(startAngle) * rx + cx; + y0 = mathSin$1(startAngle) * ry + cy; + } + fromArc(cx, cy, rx, ry, startAngle, endAngle, anticlockwise, min2, max2); + xi = mathCos$1(endAngle) * rx + cx; + yi = mathSin$1(endAngle) * ry + cy; + break; + case CMD.R: + x0 = xi = data[i++]; + y0 = yi = data[i++]; + var width = data[i++]; + var height = data[i++]; + fromLine(x0, y0, x0 + width, y0 + height, min2, max2); + break; + case CMD.Z: + xi = x0; + yi = y0; + break; + } + min(min$1, min$1, min2); + max(max$1, max$1, max2); + } + if (i === 0) { + min$1[0] = min$1[1] = max$1[0] = max$1[1] = 0; + } + return new BoundingRect(min$1[0], min$1[1], max$1[0] - min$1[0], max$1[1] - min$1[1]); + }; + PathProxy.prototype._calculateLength = function () { + var data = this.data; + var len = this._len; + var ux = this._ux; + var uy = this._uy; + var xi = 0; + var yi = 0; + var x0 = 0; + var y0 = 0; + if (!this._pathSegLen) { + this._pathSegLen = []; + } + var pathSegLen = this._pathSegLen; + var pathTotalLen = 0; + var segCount = 0; + for (var i = 0; i < len;) { + var cmd = data[i++]; + var isFirst = i === 1; + if (isFirst) { + xi = data[i]; + yi = data[i + 1]; + x0 = xi; + y0 = yi; + } + var l = -1; + switch (cmd) { + case CMD.M: + xi = x0 = data[i++]; + yi = y0 = data[i++]; + break; + case CMD.L: { + var x2 = data[i++]; + var y2 = data[i++]; + var dx = x2 - xi; + var dy = y2 - yi; + if (mathAbs(dx) > ux || mathAbs(dy) > uy || i === len - 1) { + l = Math.sqrt(dx * dx + dy * dy); + xi = x2; + yi = y2; + } + break; + } + case CMD.C: { + var x1 = data[i++]; + var y1 = data[i++]; + var x2 = data[i++]; + var y2 = data[i++]; + var x3 = data[i++]; + var y3 = data[i++]; + l = cubicLength(xi, yi, x1, y1, x2, y2, x3, y3, 10); + xi = x3; + yi = y3; + break; + } + case CMD.Q: { + var x1 = data[i++]; + var y1 = data[i++]; + var x2 = data[i++]; + var y2 = data[i++]; + l = quadraticLength(xi, yi, x1, y1, x2, y2, 10); + xi = x2; + yi = y2; + break; + } + case CMD.A: + var cx = data[i++]; + var cy = data[i++]; + var rx = data[i++]; + var ry = data[i++]; + var startAngle = data[i++]; + var delta = data[i++]; + var endAngle = delta + startAngle; + i += 1; + var anticlockwise = !data[i++]; + if (isFirst) { + x0 = mathCos$1(startAngle) * rx + cx; + y0 = mathSin$1(startAngle) * ry + cy; + } + l = mathMax$2(rx, ry) * mathMin$2(PI2$1, Math.abs(delta)); + xi = mathCos$1(endAngle) * rx + cx; + yi = mathSin$1(endAngle) * ry + cy; + break; + case CMD.R: { + x0 = xi = data[i++]; + y0 = yi = data[i++]; + var width = data[i++]; + var height = data[i++]; + l = width * 2 + height * 2; + break; + } + case CMD.Z: { + var dx = x0 - xi; + var dy = y0 - yi; + l = Math.sqrt(dx * dx + dy * dy); + xi = x0; + yi = y0; + break; + } + } + if (l >= 0) { + pathSegLen[segCount++] = l; + pathTotalLen += l; + } + } + this._pathLen = pathTotalLen; + return pathTotalLen; + }; + PathProxy.prototype.rebuildPath = function (ctx, percent) { + var d = this.data; + var ux = this._ux; + var uy = this._uy; + var len = this._len; + var x0; + var y0; + var xi; + var yi; + var x; + var y; + var drawPart = percent < 1; + var pathSegLen; + var pathTotalLen; + var accumLength = 0; + var segCount = 0; + var displayedLength; + var pendingPtDist = 0; + var pendingPtX; + var pendingPtY; + if (drawPart) { + if (!this._pathSegLen) { + this._calculateLength(); + } + pathSegLen = this._pathSegLen; + pathTotalLen = this._pathLen; + displayedLength = percent * pathTotalLen; + if (!displayedLength) { + return; + } + } + lo: for (var i = 0; i < len;) { + var cmd = d[i++]; + var isFirst = i === 1; + if (isFirst) { + xi = d[i]; + yi = d[i + 1]; + x0 = xi; + y0 = yi; + } + if (cmd !== CMD.L && pendingPtDist > 0) { + ctx.lineTo(pendingPtX, pendingPtY); + pendingPtDist = 0; + } + switch (cmd) { + case CMD.M: + x0 = xi = d[i++]; + y0 = yi = d[i++]; + ctx.moveTo(xi, yi); + break; + case CMD.L: { + x = d[i++]; + y = d[i++]; + var dx = mathAbs(x - xi); + var dy = mathAbs(y - yi); + if (dx > ux || dy > uy) { + if (drawPart) { + var l = pathSegLen[segCount++]; + if (accumLength + l > displayedLength) { + var t = (displayedLength - accumLength) / l; + ctx.lineTo(xi * (1 - t) + x * t, yi * (1 - t) + y * t); + break lo; + } + accumLength += l; + } + ctx.lineTo(x, y); + xi = x; + yi = y; + pendingPtDist = 0; + } + else { + var d2 = dx * dx + dy * dy; + if (d2 > pendingPtDist) { + pendingPtX = x; + pendingPtY = y; + pendingPtDist = d2; + } + } + break; + } + case CMD.C: { + var x1 = d[i++]; + var y1 = d[i++]; + var x2 = d[i++]; + var y2 = d[i++]; + var x3 = d[i++]; + var y3 = d[i++]; + if (drawPart) { + var l = pathSegLen[segCount++]; + if (accumLength + l > displayedLength) { + var t = (displayedLength - accumLength) / l; + cubicSubdivide(xi, x1, x2, x3, t, tmpOutX); + cubicSubdivide(yi, y1, y2, y3, t, tmpOutY); + ctx.bezierCurveTo(tmpOutX[1], tmpOutY[1], tmpOutX[2], tmpOutY[2], tmpOutX[3], tmpOutY[3]); + break lo; + } + accumLength += l; + } + ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3); + xi = x3; + yi = y3; + break; + } + case CMD.Q: { + var x1 = d[i++]; + var y1 = d[i++]; + var x2 = d[i++]; + var y2 = d[i++]; + if (drawPart) { + var l = pathSegLen[segCount++]; + if (accumLength + l > displayedLength) { + var t = (displayedLength - accumLength) / l; + quadraticSubdivide(xi, x1, x2, t, tmpOutX); + quadraticSubdivide(yi, y1, y2, t, tmpOutY); + ctx.quadraticCurveTo(tmpOutX[1], tmpOutY[1], tmpOutX[2], tmpOutY[2]); + break lo; + } + accumLength += l; + } + ctx.quadraticCurveTo(x1, y1, x2, y2); + xi = x2; + yi = y2; + break; + } + case CMD.A: + var cx = d[i++]; + var cy = d[i++]; + var rx = d[i++]; + var ry = d[i++]; + var startAngle = d[i++]; + var delta = d[i++]; + var psi = d[i++]; + var anticlockwise = !d[i++]; + var r = (rx > ry) ? rx : ry; + var isEllipse = mathAbs(rx - ry) > 1e-3; + var endAngle = startAngle + delta; + var breakBuild = false; + if (drawPart) { + var l = pathSegLen[segCount++]; + if (accumLength + l > displayedLength) { + endAngle = startAngle + delta * (displayedLength - accumLength) / l; + breakBuild = true; + } + accumLength += l; + } + if (isEllipse && ctx.ellipse) { + ctx.ellipse(cx, cy, rx, ry, psi, startAngle, endAngle, anticlockwise); + } + else { + ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise); + } + if (breakBuild) { + break lo; + } + if (isFirst) { + x0 = mathCos$1(startAngle) * rx + cx; + y0 = mathSin$1(startAngle) * ry + cy; + } + xi = mathCos$1(endAngle) * rx + cx; + yi = mathSin$1(endAngle) * ry + cy; + break; + case CMD.R: + x0 = xi = d[i]; + y0 = yi = d[i + 1]; + x = d[i++]; + y = d[i++]; + var width = d[i++]; + var height = d[i++]; + if (drawPart) { + var l = pathSegLen[segCount++]; + if (accumLength + l > displayedLength) { + var d_1 = displayedLength - accumLength; + ctx.moveTo(x, y); + ctx.lineTo(x + mathMin$2(d_1, width), y); + d_1 -= width; + if (d_1 > 0) { + ctx.lineTo(x + width, y + mathMin$2(d_1, height)); + } + d_1 -= height; + if (d_1 > 0) { + ctx.lineTo(x + mathMax$2(width - d_1, 0), y + height); + } + d_1 -= width; + if (d_1 > 0) { + ctx.lineTo(x, y + mathMax$2(height - d_1, 0)); + } + break lo; + } + accumLength += l; + } + ctx.rect(x, y, width, height); + break; + case CMD.Z: + if (drawPart) { + var l = pathSegLen[segCount++]; + if (accumLength + l > displayedLength) { + var t = (displayedLength - accumLength) / l; + ctx.lineTo(xi * (1 - t) + x0 * t, yi * (1 - t) + y0 * t); + break lo; + } + accumLength += l; + } + ctx.closePath(); + xi = x0; + yi = y0; + } + } + }; + PathProxy.prototype.clone = function () { + var newProxy = new PathProxy(); + var data = this.data; + newProxy.data = data.slice ? data.slice() + : Array.prototype.slice.call(data); + newProxy._len = this._len; + return newProxy; + }; + PathProxy.CMD = CMD; + PathProxy.initDefaultProps = (function () { + var proto = PathProxy.prototype; + proto._saveData = true; + proto._ux = 0; + proto._uy = 0; + proto._pendingPtDist = 0; + proto._version = 0; + })(); + return PathProxy; + }()); + + function containStroke(x0, y0, x1, y1, lineWidth, x, y) { + if (lineWidth === 0) { + return false; + } + var _l = lineWidth; + var _a = 0; + var _b = x0; + if ((y > y0 + _l && y > y1 + _l) + || (y < y0 - _l && y < y1 - _l) + || (x > x0 + _l && x > x1 + _l) + || (x < x0 - _l && x < x1 - _l)) { + return false; + } + if (x0 !== x1) { + _a = (y0 - y1) / (x0 - x1); + _b = (x0 * y1 - x1 * y0) / (x0 - x1); + } + else { + return Math.abs(x - x0) <= _l / 2; + } + var tmp = _a * x - y + _b; + var _s = tmp * tmp / (_a * _a + 1); + return _s <= _l / 2 * _l / 2; + } + + function containStroke$1(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) { + if (lineWidth === 0) { + return false; + } + var _l = lineWidth; + if ((y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l) + || (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l) + || (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l) + || (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l)) { + return false; + } + var d = cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, null); + return d <= _l / 2; + } + + function containStroke$2(x0, y0, x1, y1, x2, y2, lineWidth, x, y) { + if (lineWidth === 0) { + return false; + } + var _l = lineWidth; + if ((y > y0 + _l && y > y1 + _l && y > y2 + _l) + || (y < y0 - _l && y < y1 - _l && y < y2 - _l) + || (x > x0 + _l && x > x1 + _l && x > x2 + _l) + || (x < x0 - _l && x < x1 - _l && x < x2 - _l)) { + return false; + } + var d = quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, null); + return d <= _l / 2; + } + + var PI2$2 = Math.PI * 2; + function normalizeRadian(angle) { + angle %= PI2$2; + if (angle < 0) { + angle += PI2$2; + } + return angle; + } + + var PI2$3 = Math.PI * 2; + function containStroke$3(cx, cy, r, startAngle, endAngle, anticlockwise, lineWidth, x, y) { + if (lineWidth === 0) { + return false; + } + var _l = lineWidth; + x -= cx; + y -= cy; + var d = Math.sqrt(x * x + y * y); + if ((d - _l > r) || (d + _l < r)) { + return false; + } + if (Math.abs(startAngle - endAngle) % PI2$3 < 1e-4) { + return true; + } + if (anticlockwise) { + var tmp = startAngle; + startAngle = normalizeRadian(endAngle); + endAngle = normalizeRadian(tmp); + } + else { + startAngle = normalizeRadian(startAngle); + endAngle = normalizeRadian(endAngle); + } + if (startAngle > endAngle) { + endAngle += PI2$3; + } + var angle = Math.atan2(y, x); + if (angle < 0) { + angle += PI2$3; + } + return (angle >= startAngle && angle <= endAngle) + || (angle + PI2$3 >= startAngle && angle + PI2$3 <= endAngle); + } + + function windingLine(x0, y0, x1, y1, x, y) { + if ((y > y0 && y > y1) || (y < y0 && y < y1)) { + return 0; + } + if (y1 === y0) { + return 0; + } + var t = (y - y0) / (y1 - y0); + var dir = y1 < y0 ? 1 : -1; + if (t === 1 || t === 0) { + dir = y1 < y0 ? 0.5 : -0.5; + } + var x_ = t * (x1 - x0) + x0; + return x_ === x ? Infinity : x_ > x ? dir : 0; + } + + var CMD$1 = PathProxy.CMD; + var PI2$4 = Math.PI * 2; + var EPSILON$3 = 1e-4; + function isAroundEqual(a, b) { + return Math.abs(a - b) < EPSILON$3; + } + var roots = [-1, -1, -1]; + var extrema = [-1, -1]; + function swapExtrema() { + var tmp = extrema[0]; + extrema[0] = extrema[1]; + extrema[1] = tmp; + } + function windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) { + if ((y > y0 && y > y1 && y > y2 && y > y3) + || (y < y0 && y < y1 && y < y2 && y < y3)) { + return 0; + } + var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots); + if (nRoots === 0) { + return 0; + } + else { + var w = 0; + var nExtrema = -1; + var y0_ = void 0; + var y1_ = void 0; + for (var i = 0; i < nRoots; i++) { + var t = roots[i]; + var unit = (t === 0 || t === 1) ? 0.5 : 1; + var x_ = cubicAt(x0, x1, x2, x3, t); + if (x_ < x) { + continue; + } + if (nExtrema < 0) { + nExtrema = cubicExtrema(y0, y1, y2, y3, extrema); + if (extrema[1] < extrema[0] && nExtrema > 1) { + swapExtrema(); + } + y0_ = cubicAt(y0, y1, y2, y3, extrema[0]); + if (nExtrema > 1) { + y1_ = cubicAt(y0, y1, y2, y3, extrema[1]); + } + } + if (nExtrema === 2) { + if (t < extrema[0]) { + w += y0_ < y0 ? unit : -unit; + } + else if (t < extrema[1]) { + w += y1_ < y0_ ? unit : -unit; + } + else { + w += y3 < y1_ ? unit : -unit; + } + } + else { + if (t < extrema[0]) { + w += y0_ < y0 ? unit : -unit; + } + else { + w += y3 < y0_ ? unit : -unit; + } + } + } + return w; + } + } + function windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) { + if ((y > y0 && y > y1 && y > y2) + || (y < y0 && y < y1 && y < y2)) { + return 0; + } + var nRoots = quadraticRootAt(y0, y1, y2, y, roots); + if (nRoots === 0) { + return 0; + } + else { + var t = quadraticExtremum(y0, y1, y2); + if (t >= 0 && t <= 1) { + var w = 0; + var y_ = quadraticAt(y0, y1, y2, t); + for (var i = 0; i < nRoots; i++) { + var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1; + var x_ = quadraticAt(x0, x1, x2, roots[i]); + if (x_ < x) { + continue; + } + if (roots[i] < t) { + w += y_ < y0 ? unit : -unit; + } + else { + w += y2 < y_ ? unit : -unit; + } + } + return w; + } + else { + var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1; + var x_ = quadraticAt(x0, x1, x2, roots[0]); + if (x_ < x) { + return 0; + } + return y2 < y0 ? unit : -unit; + } + } + } + function windingArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y) { + y -= cy; + if (y > r || y < -r) { + return 0; + } + var tmp = Math.sqrt(r * r - y * y); + roots[0] = -tmp; + roots[1] = tmp; + var dTheta = Math.abs(startAngle - endAngle); + if (dTheta < 1e-4) { + return 0; + } + if (dTheta >= PI2$4 - 1e-4) { + startAngle = 0; + endAngle = PI2$4; + var dir = anticlockwise ? 1 : -1; + if (x >= roots[0] + cx && x <= roots[1] + cx) { + return dir; + } + else { + return 0; + } + } + if (startAngle > endAngle) { + var tmp_1 = startAngle; + startAngle = endAngle; + endAngle = tmp_1; + } + if (startAngle < 0) { + startAngle += PI2$4; + endAngle += PI2$4; + } + var w = 0; + for (var i = 0; i < 2; i++) { + var x_ = roots[i]; + if (x_ + cx > x) { + var angle = Math.atan2(y, x_); + var dir = anticlockwise ? 1 : -1; + if (angle < 0) { + angle = PI2$4 + angle; + } + if ((angle >= startAngle && angle <= endAngle) + || (angle + PI2$4 >= startAngle && angle + PI2$4 <= endAngle)) { + if (angle > Math.PI / 2 && angle < Math.PI * 1.5) { + dir = -dir; + } + w += dir; + } + } + } + return w; + } + function containPath(path, lineWidth, isStroke, x, y) { + var data = path.data; + var len = path.len(); + var w = 0; + var xi = 0; + var yi = 0; + var x0 = 0; + var y0 = 0; + var x1; + var y1; + for (var i = 0; i < len;) { + var cmd = data[i++]; + var isFirst = i === 1; + if (cmd === CMD$1.M && i > 1) { + if (!isStroke) { + w += windingLine(xi, yi, x0, y0, x, y); + } + } + if (isFirst) { + xi = data[i]; + yi = data[i + 1]; + x0 = xi; + y0 = yi; + } + switch (cmd) { + case CMD$1.M: + x0 = data[i++]; + y0 = data[i++]; + xi = x0; + yi = y0; + break; + case CMD$1.L: + if (isStroke) { + if (containStroke(xi, yi, data[i], data[i + 1], lineWidth, x, y)) { + return true; + } + } + else { + w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0; + } + xi = data[i++]; + yi = data[i++]; + break; + case CMD$1.C: + if (isStroke) { + if (containStroke$1(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) { + return true; + } + } + else { + w += windingCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y) || 0; + } + xi = data[i++]; + yi = data[i++]; + break; + case CMD$1.Q: + if (isStroke) { + if (containStroke$2(xi, yi, data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) { + return true; + } + } + else { + w += windingQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y) || 0; + } + xi = data[i++]; + yi = data[i++]; + break; + case CMD$1.A: + var cx = data[i++]; + var cy = data[i++]; + var rx = data[i++]; + var ry = data[i++]; + var theta = data[i++]; + var dTheta = data[i++]; + i += 1; + var anticlockwise = !!(1 - data[i++]); + x1 = Math.cos(theta) * rx + cx; + y1 = Math.sin(theta) * ry + cy; + if (!isFirst) { + w += windingLine(xi, yi, x1, y1, x, y); + } + else { + x0 = x1; + y0 = y1; + } + var _x = (x - cx) * ry / rx + cx; + if (isStroke) { + if (containStroke$3(cx, cy, ry, theta, theta + dTheta, anticlockwise, lineWidth, _x, y)) { + return true; + } + } + else { + w += windingArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y); + } + xi = Math.cos(theta + dTheta) * rx + cx; + yi = Math.sin(theta + dTheta) * ry + cy; + break; + case CMD$1.R: + x0 = xi = data[i++]; + y0 = yi = data[i++]; + var width = data[i++]; + var height = data[i++]; + x1 = x0 + width; + y1 = y0 + height; + if (isStroke) { + if (containStroke(x0, y0, x1, y0, lineWidth, x, y) + || containStroke(x1, y0, x1, y1, lineWidth, x, y) + || containStroke(x1, y1, x0, y1, lineWidth, x, y) + || containStroke(x0, y1, x0, y0, lineWidth, x, y)) { + return true; + } + } + else { + w += windingLine(x1, y0, x1, y1, x, y); + w += windingLine(x0, y1, x0, y0, x, y); + } + break; + case CMD$1.Z: + if (isStroke) { + if (containStroke(xi, yi, x0, y0, lineWidth, x, y)) { + return true; + } + } + else { + w += windingLine(xi, yi, x0, y0, x, y); + } + xi = x0; + yi = y0; + break; + } + } + if (!isStroke && !isAroundEqual(yi, y0)) { + w += windingLine(xi, yi, x0, y0, x, y) || 0; + } + return w !== 0; + } + function contain(pathProxy, x, y) { + return containPath(pathProxy, 0, false, x, y); + } + function containStroke$4(pathProxy, lineWidth, x, y) { + return containPath(pathProxy, lineWidth, true, x, y); + } + + var DEFAULT_PATH_STYLE = defaults({ + fill: '#000', + stroke: null, + strokePercent: 1, + fillOpacity: 1, + strokeOpacity: 1, + lineDashOffset: 0, + lineWidth: 1, + lineCap: 'butt', + miterLimit: 10, + strokeNoScale: false, + strokeFirst: false + }, DEFAULT_COMMON_STYLE); + var DEFAULT_PATH_ANIMATION_PROPS = { + style: defaults({ + fill: true, + stroke: true, + strokePercent: true, + fillOpacity: true, + strokeOpacity: true, + lineDashOffset: true, + lineWidth: true, + miterLimit: true + }, DEFAULT_COMMON_ANIMATION_PROPS.style) + }; + var pathCopyParams = TRANSFORMABLE_PROPS.concat(['invisible', + 'culling', 'z', 'z2', 'zlevel', 'parent' + ]); + var Path = (function (_super) { + __extends(Path, _super); + function Path(opts) { + return _super.call(this, opts) || this; + } + Path.prototype.update = function () { + var _this = this; + _super.prototype.update.call(this); + var style = this.style; + if (style.decal) { + var decalEl = this._decalEl = this._decalEl || new Path(); + if (decalEl.buildPath === Path.prototype.buildPath) { + decalEl.buildPath = function (ctx) { + _this.buildPath(ctx, _this.shape); + }; + } + decalEl.silent = true; + var decalElStyle = decalEl.style; + for (var key in style) { + if (decalElStyle[key] !== style[key]) { + decalElStyle[key] = style[key]; + } + } + decalElStyle.fill = style.fill ? style.decal : null; + decalElStyle.decal = null; + decalElStyle.shadowColor = null; + style.strokeFirst && (decalElStyle.stroke = null); + for (var i = 0; i < pathCopyParams.length; ++i) { + decalEl[pathCopyParams[i]] = this[pathCopyParams[i]]; + } + decalEl.__dirty |= REDRAW_BIT; + } + else if (this._decalEl) { + this._decalEl = null; + } + }; + Path.prototype.getDecalElement = function () { + return this._decalEl; + }; + Path.prototype._init = function (props) { + var keysArr = keys(props); + this.shape = this.getDefaultShape(); + var defaultStyle = this.getDefaultStyle(); + if (defaultStyle) { + this.useStyle(defaultStyle); + } + for (var i = 0; i < keysArr.length; i++) { + var key = keysArr[i]; + var value = props[key]; + if (key === 'style') { + if (!this.style) { + this.useStyle(value); + } + else { + extend(this.style, value); + } + } + else if (key === 'shape') { + extend(this.shape, value); + } + else { + _super.prototype.attrKV.call(this, key, value); + } + } + if (!this.style) { + this.useStyle({}); + } + }; + Path.prototype.getDefaultStyle = function () { + return null; + }; + Path.prototype.getDefaultShape = function () { + return {}; + }; + Path.prototype.canBeInsideText = function () { + return this.hasFill(); + }; + Path.prototype.getInsideTextFill = function () { + var pathFill = this.style.fill; + if (pathFill !== 'none') { + if (isString(pathFill)) { + var fillLum = lum(pathFill, 0); + if (fillLum > 0.5) { + return DARK_LABEL_COLOR; + } + else if (fillLum > 0.2) { + return LIGHTER_LABEL_COLOR; + } + return LIGHT_LABEL_COLOR; + } + else if (pathFill) { + return LIGHT_LABEL_COLOR; + } + } + return DARK_LABEL_COLOR; + }; + Path.prototype.getInsideTextStroke = function (textFill) { + var pathFill = this.style.fill; + if (isString(pathFill)) { + var zr = this.__zr; + var isDarkMode = !!(zr && zr.isDarkMode()); + var isDarkLabel = lum(textFill, 0) < DARK_MODE_THRESHOLD; + if (isDarkMode === isDarkLabel) { + return pathFill; + } + } + }; + Path.prototype.buildPath = function (ctx, shapeCfg, inBatch) { }; + Path.prototype.pathUpdated = function () { + this.__dirty &= ~SHAPE_CHANGED_BIT; + }; + Path.prototype.getUpdatedPathProxy = function (inBatch) { + !this.path && this.createPathProxy(); + this.path.beginPath(); + this.buildPath(this.path, this.shape, inBatch); + return this.path; + }; + Path.prototype.createPathProxy = function () { + this.path = new PathProxy(false); + }; + Path.prototype.hasStroke = function () { + var style = this.style; + var stroke = style.stroke; + return !(stroke == null || stroke === 'none' || !(style.lineWidth > 0)); + }; + Path.prototype.hasFill = function () { + var style = this.style; + var fill = style.fill; + return fill != null && fill !== 'none'; + }; + Path.prototype.getBoundingRect = function () { + var rect = this._rect; + var style = this.style; + var needsUpdateRect = !rect; + if (needsUpdateRect) { + var firstInvoke = false; + if (!this.path) { + firstInvoke = true; + this.createPathProxy(); + } + var path = this.path; + if (firstInvoke || (this.__dirty & SHAPE_CHANGED_BIT)) { + path.beginPath(); + this.buildPath(path, this.shape, false); + this.pathUpdated(); + } + rect = path.getBoundingRect(); + } + this._rect = rect; + if (this.hasStroke() && this.path && this.path.len() > 0) { + var rectStroke = this._rectStroke || (this._rectStroke = rect.clone()); + if (this.__dirty || needsUpdateRect) { + rectStroke.copy(rect); + var lineScale = style.strokeNoScale ? this.getLineScale() : 1; + var w = style.lineWidth; + if (!this.hasFill()) { + var strokeContainThreshold = this.strokeContainThreshold; + w = Math.max(w, strokeContainThreshold == null ? 4 : strokeContainThreshold); + } + if (lineScale > 1e-10) { + rectStroke.width += w / lineScale; + rectStroke.height += w / lineScale; + rectStroke.x -= w / lineScale / 2; + rectStroke.y -= w / lineScale / 2; + } + } + return rectStroke; + } + return rect; + }; + Path.prototype.contain = function (x, y) { + var localPos = this.transformCoordToLocal(x, y); + var rect = this.getBoundingRect(); + var style = this.style; + x = localPos[0]; + y = localPos[1]; + if (rect.contain(x, y)) { + var pathProxy = this.path; + if (this.hasStroke()) { + var lineWidth = style.lineWidth; + var lineScale = style.strokeNoScale ? this.getLineScale() : 1; + if (lineScale > 1e-10) { + if (!this.hasFill()) { + lineWidth = Math.max(lineWidth, this.strokeContainThreshold); + } + if (containStroke$4(pathProxy, lineWidth / lineScale, x, y)) { + return true; + } + } + } + if (this.hasFill()) { + return contain(pathProxy, x, y); + } + } + return false; + }; + Path.prototype.dirtyShape = function () { + this.__dirty |= SHAPE_CHANGED_BIT; + if (this._rect) { + this._rect = null; + } + if (this._decalEl) { + this._decalEl.dirtyShape(); + } + this.markRedraw(); + }; + Path.prototype.dirty = function () { + this.dirtyStyle(); + this.dirtyShape(); + }; + Path.prototype.animateShape = function (loop) { + return this.animate('shape', loop); + }; + Path.prototype.updateDuringAnimation = function (targetKey) { + if (targetKey === 'style') { + this.dirtyStyle(); + } + else if (targetKey === 'shape') { + this.dirtyShape(); + } + else { + this.markRedraw(); + } + }; + Path.prototype.attrKV = function (key, value) { + if (key === 'shape') { + this.setShape(value); + } + else { + _super.prototype.attrKV.call(this, key, value); + } + }; + Path.prototype.setShape = function (keyOrObj, value) { + var shape = this.shape; + if (!shape) { + shape = this.shape = {}; + } + if (typeof keyOrObj === 'string') { + shape[keyOrObj] = value; + } + else { + extend(shape, keyOrObj); + } + this.dirtyShape(); + return this; + }; + Path.prototype.shapeChanged = function () { + return !!(this.__dirty & SHAPE_CHANGED_BIT); + }; + Path.prototype.createStyle = function (obj) { + return createObject(DEFAULT_PATH_STYLE, obj); + }; + Path.prototype._innerSaveToNormal = function (toState) { + _super.prototype._innerSaveToNormal.call(this, toState); + var normalState = this._normalState; + if (toState.shape && !normalState.shape) { + normalState.shape = extend({}, this.shape); + } + }; + Path.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) { + _super.prototype._applyStateObj.call(this, stateName, state, normalState, keepCurrentStates, transition, animationCfg); + var needsRestoreToNormal = !(state && keepCurrentStates); + var targetShape; + if (state && state.shape) { + if (transition) { + if (keepCurrentStates) { + targetShape = state.shape; + } + else { + targetShape = extend({}, normalState.shape); + extend(targetShape, state.shape); + } + } + else { + targetShape = extend({}, keepCurrentStates ? this.shape : normalState.shape); + extend(targetShape, state.shape); + } + } + else if (needsRestoreToNormal) { + targetShape = normalState.shape; + } + if (targetShape) { + if (transition) { + this.shape = extend({}, this.shape); + var targetShapePrimaryProps = {}; + var shapeKeys = keys(targetShape); + for (var i = 0; i < shapeKeys.length; i++) { + var key = shapeKeys[i]; + if (typeof targetShape[key] === 'object') { + this.shape[key] = targetShape[key]; + } + else { + targetShapePrimaryProps[key] = targetShape[key]; + } + } + this._transitionState(stateName, { + shape: targetShapePrimaryProps + }, animationCfg); + } + else { + this.shape = targetShape; + this.dirtyShape(); + } + } + }; + Path.prototype._mergeStates = function (states) { + var mergedState = _super.prototype._mergeStates.call(this, states); + var mergedShape; + for (var i = 0; i < states.length; i++) { + var state = states[i]; + if (state.shape) { + mergedShape = mergedShape || {}; + this._mergeStyle(mergedShape, state.shape); + } + } + if (mergedShape) { + mergedState.shape = mergedShape; + } + return mergedState; + }; + Path.prototype.getAnimationStyleProps = function () { + return DEFAULT_PATH_ANIMATION_PROPS; + }; + Path.prototype.isZeroArea = function () { + return false; + }; + Path.extend = function (defaultProps) { + var Sub = (function (_super) { + __extends(Sub, _super); + function Sub(opts) { + var _this = _super.call(this, opts) || this; + defaultProps.init && defaultProps.init.call(_this, opts); + return _this; + } + Sub.prototype.getDefaultStyle = function () { + return clone(defaultProps.style); + }; + Sub.prototype.getDefaultShape = function () { + return clone(defaultProps.shape); + }; + return Sub; + }(Path)); + for (var key in defaultProps) { + if (typeof defaultProps[key] === 'function') { + Sub.prototype[key] = defaultProps[key]; + } + } + return Sub; + }; + Path.initDefaultProps = (function () { + var pathProto = Path.prototype; + pathProto.type = 'path'; + pathProto.strokeContainThreshold = 5; + pathProto.segmentIgnoreThreshold = 0; + pathProto.subPixelOptimize = false; + pathProto.autoBatch = false; + pathProto.__dirty = REDRAW_BIT | STYLE_CHANGED_BIT | SHAPE_CHANGED_BIT; + })(); + return Path; + }(Displayable)); + + var DEFAULT_TSPAN_STYLE = defaults({ + strokeFirst: true, + font: DEFAULT_FONT, + x: 0, + y: 0, + textAlign: 'left', + textBaseline: 'top', + miterLimit: 2 + }, DEFAULT_PATH_STYLE); + var TSpan = (function (_super) { + __extends(TSpan, _super); + function TSpan() { + return _super !== null && _super.apply(this, arguments) || this; + } + TSpan.prototype.hasStroke = function () { + var style = this.style; + var stroke = style.stroke; + return stroke != null && stroke !== 'none' && style.lineWidth > 0; + }; + TSpan.prototype.hasFill = function () { + var style = this.style; + var fill = style.fill; + return fill != null && fill !== 'none'; + }; + TSpan.prototype.createStyle = function (obj) { + return createObject(DEFAULT_TSPAN_STYLE, obj); + }; + TSpan.prototype.setBoundingRect = function (rect) { + this._rect = rect; + }; + TSpan.prototype.getBoundingRect = function () { + var style = this.style; + if (!this._rect) { + var text = style.text; + text != null ? (text += '') : (text = ''); + var rect = getBoundingRect(text, style.font, style.textAlign, style.textBaseline); + rect.x += style.x || 0; + rect.y += style.y || 0; + if (this.hasStroke()) { + var w = style.lineWidth; + rect.x -= w / 2; + rect.y -= w / 2; + rect.width += w; + rect.height += w; + } + this._rect = rect; + } + return this._rect; + }; + TSpan.initDefaultProps = (function () { + var tspanProto = TSpan.prototype; + tspanProto.dirtyRectTolerance = 10; + })(); + return TSpan; + }(Displayable)); + TSpan.prototype.type = 'tspan'; + + var DEFAULT_IMAGE_STYLE = defaults({ + x: 0, + y: 0 + }, DEFAULT_COMMON_STYLE); + var DEFAULT_IMAGE_ANIMATION_PROPS = { + style: defaults({ + x: true, + y: true, + width: true, + height: true, + sx: true, + sy: true, + sWidth: true, + sHeight: true + }, DEFAULT_COMMON_ANIMATION_PROPS.style) + }; + function isImageLike(source) { + return !!(source + && typeof source !== 'string' + && source.width && source.height); + } + var ZRImage = (function (_super) { + __extends(ZRImage, _super); + function ZRImage() { + return _super !== null && _super.apply(this, arguments) || this; + } + ZRImage.prototype.createStyle = function (obj) { + return createObject(DEFAULT_IMAGE_STYLE, obj); + }; + ZRImage.prototype._getSize = function (dim) { + var style = this.style; + var size = style[dim]; + if (size != null) { + return size; + } + var imageSource = isImageLike(style.image) + ? style.image : this.__image; + if (!imageSource) { + return 0; + } + var otherDim = dim === 'width' ? 'height' : 'width'; + var otherDimSize = style[otherDim]; + if (otherDimSize == null) { + return imageSource[dim]; + } + else { + return imageSource[dim] / imageSource[otherDim] * otherDimSize; + } + }; + ZRImage.prototype.getWidth = function () { + return this._getSize('width'); + }; + ZRImage.prototype.getHeight = function () { + return this._getSize('height'); + }; + ZRImage.prototype.getAnimationStyleProps = function () { + return DEFAULT_IMAGE_ANIMATION_PROPS; + }; + ZRImage.prototype.getBoundingRect = function () { + var style = this.style; + if (!this._rect) { + this._rect = new BoundingRect(style.x || 0, style.y || 0, this.getWidth(), this.getHeight()); + } + return this._rect; + }; + return ZRImage; + }(Displayable)); + ZRImage.prototype.type = 'image'; + + function buildPath(ctx, shape) { + var x = shape.x; + var y = shape.y; + var width = shape.width; + var height = shape.height; + var r = shape.r; + var r1; + var r2; + var r3; + var r4; + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + if (typeof r === 'number') { + r1 = r2 = r3 = r4 = r; + } + else if (r instanceof Array) { + if (r.length === 1) { + r1 = r2 = r3 = r4 = r[0]; + } + else if (r.length === 2) { + r1 = r3 = r[0]; + r2 = r4 = r[1]; + } + else if (r.length === 3) { + r1 = r[0]; + r2 = r4 = r[1]; + r3 = r[2]; + } + else { + r1 = r[0]; + r2 = r[1]; + r3 = r[2]; + r4 = r[3]; + } + } + else { + r1 = r2 = r3 = r4 = 0; + } + var total; + if (r1 + r2 > width) { + total = r1 + r2; + r1 *= width / total; + r2 *= width / total; + } + if (r3 + r4 > width) { + total = r3 + r4; + r3 *= width / total; + r4 *= width / total; + } + if (r2 + r3 > height) { + total = r2 + r3; + r2 *= height / total; + r3 *= height / total; + } + if (r1 + r4 > height) { + total = r1 + r4; + r1 *= height / total; + r4 *= height / total; + } + ctx.moveTo(x + r1, y); + ctx.lineTo(x + width - r2, y); + r2 !== 0 && ctx.arc(x + width - r2, y + r2, r2, -Math.PI / 2, 0); + ctx.lineTo(x + width, y + height - r3); + r3 !== 0 && ctx.arc(x + width - r3, y + height - r3, r3, 0, Math.PI / 2); + ctx.lineTo(x + r4, y + height); + r4 !== 0 && ctx.arc(x + r4, y + height - r4, r4, Math.PI / 2, Math.PI); + ctx.lineTo(x, y + r1); + r1 !== 0 && ctx.arc(x + r1, y + r1, r1, Math.PI, Math.PI * 1.5); + } + + var round$1 = Math.round; + function subPixelOptimizeLine(outputShape, inputShape, style) { + if (!inputShape) { + return; + } + var x1 = inputShape.x1; + var x2 = inputShape.x2; + var y1 = inputShape.y1; + var y2 = inputShape.y2; + outputShape.x1 = x1; + outputShape.x2 = x2; + outputShape.y1 = y1; + outputShape.y2 = y2; + var lineWidth = style && style.lineWidth; + if (!lineWidth) { + return outputShape; + } + if (round$1(x1 * 2) === round$1(x2 * 2)) { + outputShape.x1 = outputShape.x2 = subPixelOptimize(x1, lineWidth, true); + } + if (round$1(y1 * 2) === round$1(y2 * 2)) { + outputShape.y1 = outputShape.y2 = subPixelOptimize(y1, lineWidth, true); + } + return outputShape; + } + function subPixelOptimizeRect(outputShape, inputShape, style) { + if (!inputShape) { + return; + } + var originX = inputShape.x; + var originY = inputShape.y; + var originWidth = inputShape.width; + var originHeight = inputShape.height; + outputShape.x = originX; + outputShape.y = originY; + outputShape.width = originWidth; + outputShape.height = originHeight; + var lineWidth = style && style.lineWidth; + if (!lineWidth) { + return outputShape; + } + outputShape.x = subPixelOptimize(originX, lineWidth, true); + outputShape.y = subPixelOptimize(originY, lineWidth, true); + outputShape.width = Math.max(subPixelOptimize(originX + originWidth, lineWidth, false) - outputShape.x, originWidth === 0 ? 0 : 1); + outputShape.height = Math.max(subPixelOptimize(originY + originHeight, lineWidth, false) - outputShape.y, originHeight === 0 ? 0 : 1); + return outputShape; + } + function subPixelOptimize(position, lineWidth, positiveOrNegative) { + if (!lineWidth) { + return position; + } + var doubledPosition = round$1(position * 2); + return (doubledPosition + round$1(lineWidth)) % 2 === 0 + ? doubledPosition / 2 + : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2; + } + + var RectShape = (function () { + function RectShape() { + this.x = 0; + this.y = 0; + this.width = 0; + this.height = 0; + } + return RectShape; + }()); + var subPixelOptimizeOutputShape = {}; + var Rect = (function (_super) { + __extends(Rect, _super); + function Rect(opts) { + return _super.call(this, opts) || this; + } + Rect.prototype.getDefaultShape = function () { + return new RectShape(); + }; + Rect.prototype.buildPath = function (ctx, shape) { + var x; + var y; + var width; + var height; + if (this.subPixelOptimize) { + var optimizedShape = subPixelOptimizeRect(subPixelOptimizeOutputShape, shape, this.style); + x = optimizedShape.x; + y = optimizedShape.y; + width = optimizedShape.width; + height = optimizedShape.height; + optimizedShape.r = shape.r; + shape = optimizedShape; + } + else { + x = shape.x; + y = shape.y; + width = shape.width; + height = shape.height; + } + if (!shape.r) { + ctx.rect(x, y, width, height); + } + else { + buildPath(ctx, shape); + } + }; + Rect.prototype.isZeroArea = function () { + return !this.shape.width || !this.shape.height; + }; + return Rect; + }(Path)); + Rect.prototype.type = 'rect'; + + var DEFAULT_RICH_TEXT_COLOR = { + fill: '#000' + }; + var DEFAULT_STROKE_LINE_WIDTH = 2; + var DEFAULT_TEXT_ANIMATION_PROPS = { + style: defaults({ + fill: true, + stroke: true, + fillOpacity: true, + strokeOpacity: true, + lineWidth: true, + fontSize: true, + lineHeight: true, + width: true, + height: true, + textShadowColor: true, + textShadowBlur: true, + textShadowOffsetX: true, + textShadowOffsetY: true, + backgroundColor: true, + padding: true, + borderColor: true, + borderWidth: true, + borderRadius: true + }, DEFAULT_COMMON_ANIMATION_PROPS.style) + }; + var ZRText = (function (_super) { + __extends(ZRText, _super); + function ZRText(opts) { + var _this = _super.call(this) || this; + _this.type = 'text'; + _this._children = []; + _this._defaultStyle = DEFAULT_RICH_TEXT_COLOR; + _this.attr(opts); + return _this; + } + ZRText.prototype.childrenRef = function () { + return this._children; + }; + ZRText.prototype.update = function () { + _super.prototype.update.call(this); + if (this.styleChanged()) { + this._updateSubTexts(); + } + for (var i = 0; i < this._children.length; i++) { + var child = this._children[i]; + child.zlevel = this.zlevel; + child.z = this.z; + child.z2 = this.z2; + child.culling = this.culling; + child.cursor = this.cursor; + child.invisible = this.invisible; + } + }; + ZRText.prototype.updateTransform = function () { + var innerTransformable = this.innerTransformable; + if (innerTransformable) { + innerTransformable.updateTransform(); + if (innerTransformable.transform) { + this.transform = innerTransformable.transform; + } + } + else { + _super.prototype.updateTransform.call(this); + } + }; + ZRText.prototype.getLocalTransform = function (m) { + var innerTransformable = this.innerTransformable; + return innerTransformable + ? innerTransformable.getLocalTransform(m) + : _super.prototype.getLocalTransform.call(this, m); + }; + ZRText.prototype.getComputedTransform = function () { + if (this.__hostTarget) { + this.__hostTarget.getComputedTransform(); + this.__hostTarget.updateInnerText(true); + } + return _super.prototype.getComputedTransform.call(this); + }; + ZRText.prototype._updateSubTexts = function () { + this._childCursor = 0; + normalizeTextStyle(this.style); + this.style.rich + ? this._updateRichTexts() + : this._updatePlainTexts(); + this._children.length = this._childCursor; + this.styleUpdated(); + }; + ZRText.prototype.addSelfToZr = function (zr) { + _super.prototype.addSelfToZr.call(this, zr); + for (var i = 0; i < this._children.length; i++) { + this._children[i].__zr = zr; + } + }; + ZRText.prototype.removeSelfFromZr = function (zr) { + _super.prototype.removeSelfFromZr.call(this, zr); + for (var i = 0; i < this._children.length; i++) { + this._children[i].__zr = null; + } + }; + ZRText.prototype.getBoundingRect = function () { + if (this.styleChanged()) { + this._updateSubTexts(); + } + if (!this._rect) { + var tmpRect = new BoundingRect(0, 0, 0, 0); + var children = this._children; + var tmpMat = []; + var rect = null; + for (var i = 0; i < children.length; i++) { + var child = children[i]; + var childRect = child.getBoundingRect(); + var transform = child.getLocalTransform(tmpMat); + if (transform) { + tmpRect.copy(childRect); + tmpRect.applyTransform(transform); + rect = rect || tmpRect.clone(); + rect.union(tmpRect); + } + else { + rect = rect || childRect.clone(); + rect.union(childRect); + } + } + this._rect = rect || tmpRect; + } + return this._rect; + }; + ZRText.prototype.setDefaultTextStyle = function (defaultTextStyle) { + this._defaultStyle = defaultTextStyle || DEFAULT_RICH_TEXT_COLOR; + }; + ZRText.prototype.setTextContent = function (textContent) { + if ("development" !== 'production') { + throw new Error('Can\'t attach text on another text'); + } + }; + ZRText.prototype._mergeStyle = function (targetStyle, sourceStyle) { + if (!sourceStyle) { + return targetStyle; + } + var sourceRich = sourceStyle.rich; + var targetRich = targetStyle.rich || (sourceRich && {}); + extend(targetStyle, sourceStyle); + if (sourceRich && targetRich) { + this._mergeRich(targetRich, sourceRich); + targetStyle.rich = targetRich; + } + else if (targetRich) { + targetStyle.rich = targetRich; + } + return targetStyle; + }; + ZRText.prototype._mergeRich = function (targetRich, sourceRich) { + var richNames = keys(sourceRich); + for (var i = 0; i < richNames.length; i++) { + var richName = richNames[i]; + targetRich[richName] = targetRich[richName] || {}; + extend(targetRich[richName], sourceRich[richName]); + } + }; + ZRText.prototype.getAnimationStyleProps = function () { + return DEFAULT_TEXT_ANIMATION_PROPS; + }; + ZRText.prototype._getOrCreateChild = function (Ctor) { + var child = this._children[this._childCursor]; + if (!child || !(child instanceof Ctor)) { + child = new Ctor(); + } + this._children[this._childCursor++] = child; + child.__zr = this.__zr; + child.parent = this; + return child; + }; + ZRText.prototype._updatePlainTexts = function () { + var style = this.style; + var textFont = style.font || DEFAULT_FONT; + var textPadding = style.padding; + var text = getStyleText(style); + var contentBlock = parsePlainText(text, style); + var needDrawBg = needDrawBackground(style); + var bgColorDrawn = !!(style.backgroundColor); + var outerHeight = contentBlock.outerHeight; + var outerWidth = contentBlock.outerWidth; + var contentWidth = contentBlock.contentWidth; + var textLines = contentBlock.lines; + var lineHeight = contentBlock.lineHeight; + var defaultStyle = this._defaultStyle; + var baseX = style.x || 0; + var baseY = style.y || 0; + var textAlign = style.align || defaultStyle.align || 'left'; + var verticalAlign = style.verticalAlign || defaultStyle.verticalAlign || 'top'; + var textX = baseX; + var textY = adjustTextY$1(baseY, contentBlock.contentHeight, verticalAlign); + if (needDrawBg || textPadding) { + var boxX = adjustTextX(baseX, outerWidth, textAlign); + var boxY = adjustTextY$1(baseY, outerHeight, verticalAlign); + needDrawBg && this._renderBackground(style, style, boxX, boxY, outerWidth, outerHeight); + } + textY += lineHeight / 2; + if (textPadding) { + textX = getTextXForPadding(baseX, textAlign, textPadding); + if (verticalAlign === 'top') { + textY += textPadding[0]; + } + else if (verticalAlign === 'bottom') { + textY -= textPadding[2]; + } + } + var defaultLineWidth = 0; + var useDefaultFill = false; + var textFill = getFill('fill' in style + ? style.fill + : (useDefaultFill = true, defaultStyle.fill)); + var textStroke = getStroke('stroke' in style + ? style.stroke + : (!bgColorDrawn + && (!defaultStyle.autoStroke || useDefaultFill)) + ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, defaultStyle.stroke) + : null); + var hasShadow = style.textShadowBlur > 0; + var fixedBoundingRect = style.width != null + && (style.overflow === 'truncate' || style.overflow === 'break' || style.overflow === 'breakAll'); + var calculatedLineHeight = contentBlock.calculatedLineHeight; + for (var i = 0; i < textLines.length; i++) { + var el = this._getOrCreateChild(TSpan); + var subElStyle = el.createStyle(); + el.useStyle(subElStyle); + subElStyle.text = textLines[i]; + subElStyle.x = textX; + subElStyle.y = textY; + if (textAlign) { + subElStyle.textAlign = textAlign; + } + subElStyle.textBaseline = 'middle'; + subElStyle.opacity = style.opacity; + subElStyle.strokeFirst = true; + if (hasShadow) { + subElStyle.shadowBlur = style.textShadowBlur || 0; + subElStyle.shadowColor = style.textShadowColor || 'transparent'; + subElStyle.shadowOffsetX = style.textShadowOffsetX || 0; + subElStyle.shadowOffsetY = style.textShadowOffsetY || 0; + } + subElStyle.stroke = textStroke; + subElStyle.fill = textFill; + if (textStroke) { + subElStyle.lineWidth = style.lineWidth || defaultLineWidth; + subElStyle.lineDash = style.lineDash; + subElStyle.lineDashOffset = style.lineDashOffset || 0; + } + subElStyle.font = textFont; + setSeparateFont(subElStyle, style); + textY += lineHeight; + if (fixedBoundingRect) { + el.setBoundingRect(new BoundingRect(adjustTextX(subElStyle.x, style.width, subElStyle.textAlign), adjustTextY$1(subElStyle.y, calculatedLineHeight, subElStyle.textBaseline), contentWidth, calculatedLineHeight)); + } + } + }; + ZRText.prototype._updateRichTexts = function () { + var style = this.style; + var text = getStyleText(style); + var contentBlock = parseRichText(text, style); + var contentWidth = contentBlock.width; + var outerWidth = contentBlock.outerWidth; + var outerHeight = contentBlock.outerHeight; + var textPadding = style.padding; + var baseX = style.x || 0; + var baseY = style.y || 0; + var defaultStyle = this._defaultStyle; + var textAlign = style.align || defaultStyle.align; + var verticalAlign = style.verticalAlign || defaultStyle.verticalAlign; + var boxX = adjustTextX(baseX, outerWidth, textAlign); + var boxY = adjustTextY$1(baseY, outerHeight, verticalAlign); + var xLeft = boxX; + var lineTop = boxY; + if (textPadding) { + xLeft += textPadding[3]; + lineTop += textPadding[0]; + } + var xRight = xLeft + contentWidth; + if (needDrawBackground(style)) { + this._renderBackground(style, style, boxX, boxY, outerWidth, outerHeight); + } + var bgColorDrawn = !!(style.backgroundColor); + for (var i = 0; i < contentBlock.lines.length; i++) { + var line = contentBlock.lines[i]; + var tokens = line.tokens; + var tokenCount = tokens.length; + var lineHeight = line.lineHeight; + var remainedWidth = line.width; + var leftIndex = 0; + var lineXLeft = xLeft; + var lineXRight = xRight; + var rightIndex = tokenCount - 1; + var token = void 0; + while (leftIndex < tokenCount + && (token = tokens[leftIndex], !token.align || token.align === 'left')) { + this._placeToken(token, style, lineHeight, lineTop, lineXLeft, 'left', bgColorDrawn); + remainedWidth -= token.width; + lineXLeft += token.width; + leftIndex++; + } + while (rightIndex >= 0 + && (token = tokens[rightIndex], token.align === 'right')) { + this._placeToken(token, style, lineHeight, lineTop, lineXRight, 'right', bgColorDrawn); + remainedWidth -= token.width; + lineXRight -= token.width; + rightIndex--; + } + lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - remainedWidth) / 2; + while (leftIndex <= rightIndex) { + token = tokens[leftIndex]; + this._placeToken(token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center', bgColorDrawn); + lineXLeft += token.width; + leftIndex++; + } + lineTop += lineHeight; + } + }; + ZRText.prototype._placeToken = function (token, style, lineHeight, lineTop, x, textAlign, parentBgColorDrawn) { + var tokenStyle = style.rich[token.styleName] || {}; + tokenStyle.text = token.text; + var verticalAlign = token.verticalAlign; + var y = lineTop + lineHeight / 2; + if (verticalAlign === 'top') { + y = lineTop + token.height / 2; + } + else if (verticalAlign === 'bottom') { + y = lineTop + lineHeight - token.height / 2; + } + var needDrawBg = !token.isLineHolder && needDrawBackground(tokenStyle); + needDrawBg && this._renderBackground(tokenStyle, style, textAlign === 'right' + ? x - token.width + : textAlign === 'center' + ? x - token.width / 2 + : x, y - token.height / 2, token.width, token.height); + var bgColorDrawn = !!tokenStyle.backgroundColor; + var textPadding = token.textPadding; + if (textPadding) { + x = getTextXForPadding(x, textAlign, textPadding); + y -= token.height / 2 - textPadding[0] - token.innerHeight / 2; + } + var el = this._getOrCreateChild(TSpan); + var subElStyle = el.createStyle(); + el.useStyle(subElStyle); + var defaultStyle = this._defaultStyle; + var useDefaultFill = false; + var defaultLineWidth = 0; + var textFill = getFill('fill' in tokenStyle ? tokenStyle.fill + : 'fill' in style ? style.fill + : (useDefaultFill = true, defaultStyle.fill)); + var textStroke = getStroke('stroke' in tokenStyle ? tokenStyle.stroke + : 'stroke' in style ? style.stroke + : (!bgColorDrawn + && !parentBgColorDrawn + && (!defaultStyle.autoStroke || useDefaultFill)) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, defaultStyle.stroke) + : null); + var hasShadow = tokenStyle.textShadowBlur > 0 + || style.textShadowBlur > 0; + subElStyle.text = token.text; + subElStyle.x = x; + subElStyle.y = y; + if (hasShadow) { + subElStyle.shadowBlur = tokenStyle.textShadowBlur || style.textShadowBlur || 0; + subElStyle.shadowColor = tokenStyle.textShadowColor || style.textShadowColor || 'transparent'; + subElStyle.shadowOffsetX = tokenStyle.textShadowOffsetX || style.textShadowOffsetX || 0; + subElStyle.shadowOffsetY = tokenStyle.textShadowOffsetY || style.textShadowOffsetY || 0; + } + subElStyle.textAlign = textAlign; + subElStyle.textBaseline = 'middle'; + subElStyle.font = token.font || DEFAULT_FONT; + subElStyle.opacity = retrieve3(tokenStyle.opacity, style.opacity, 1); + setSeparateFont(subElStyle, tokenStyle); + if (textStroke) { + subElStyle.lineWidth = retrieve3(tokenStyle.lineWidth, style.lineWidth, defaultLineWidth); + subElStyle.lineDash = retrieve2(tokenStyle.lineDash, style.lineDash); + subElStyle.lineDashOffset = style.lineDashOffset || 0; + subElStyle.stroke = textStroke; + } + if (textFill) { + subElStyle.fill = textFill; + } + var textWidth = token.contentWidth; + var textHeight = token.contentHeight; + el.setBoundingRect(new BoundingRect(adjustTextX(subElStyle.x, textWidth, subElStyle.textAlign), adjustTextY$1(subElStyle.y, textHeight, subElStyle.textBaseline), textWidth, textHeight)); + }; + ZRText.prototype._renderBackground = function (style, topStyle, x, y, width, height) { + var textBackgroundColor = style.backgroundColor; + var textBorderWidth = style.borderWidth; + var textBorderColor = style.borderColor; + var isImageBg = textBackgroundColor && textBackgroundColor.image; + var isPlainOrGradientBg = textBackgroundColor && !isImageBg; + var textBorderRadius = style.borderRadius; + var self = this; + var rectEl; + var imgEl; + if (isPlainOrGradientBg || style.lineHeight || (textBorderWidth && textBorderColor)) { + rectEl = this._getOrCreateChild(Rect); + rectEl.useStyle(rectEl.createStyle()); + rectEl.style.fill = null; + var rectShape = rectEl.shape; + rectShape.x = x; + rectShape.y = y; + rectShape.width = width; + rectShape.height = height; + rectShape.r = textBorderRadius; + rectEl.dirtyShape(); + } + if (isPlainOrGradientBg) { + var rectStyle = rectEl.style; + rectStyle.fill = textBackgroundColor || null; + rectStyle.fillOpacity = retrieve2(style.fillOpacity, 1); + } + else if (isImageBg) { + imgEl = this._getOrCreateChild(ZRImage); + imgEl.onload = function () { + self.dirtyStyle(); + }; + var imgStyle = imgEl.style; + imgStyle.image = textBackgroundColor.image; + imgStyle.x = x; + imgStyle.y = y; + imgStyle.width = width; + imgStyle.height = height; + } + if (textBorderWidth && textBorderColor) { + var rectStyle = rectEl.style; + rectStyle.lineWidth = textBorderWidth; + rectStyle.stroke = textBorderColor; + rectStyle.strokeOpacity = retrieve2(style.strokeOpacity, 1); + rectStyle.lineDash = style.borderDash; + rectStyle.lineDashOffset = style.borderDashOffset || 0; + rectEl.strokeContainThreshold = 0; + if (rectEl.hasFill() && rectEl.hasStroke()) { + rectStyle.strokeFirst = true; + rectStyle.lineWidth *= 2; + } + } + var commonStyle = (rectEl || imgEl).style; + commonStyle.shadowBlur = style.shadowBlur || 0; + commonStyle.shadowColor = style.shadowColor || 'transparent'; + commonStyle.shadowOffsetX = style.shadowOffsetX || 0; + commonStyle.shadowOffsetY = style.shadowOffsetY || 0; + commonStyle.opacity = retrieve3(style.opacity, topStyle.opacity, 1); + }; + ZRText.makeFont = function (style) { + var font = ''; + if (hasSeparateFont(style)) { + font = [ + style.fontStyle, + style.fontWeight, + parseFontSize(style.fontSize), + style.fontFamily || 'sans-serif' + ].join(' '); + } + return font && trim(font) || style.textFont || style.font; + }; + return ZRText; + }(Displayable)); + var VALID_TEXT_ALIGN = { left: true, right: 1, center: 1 }; + var VALID_TEXT_VERTICAL_ALIGN = { top: 1, bottom: 1, middle: 1 }; + var FONT_PARTS = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily']; + function parseFontSize(fontSize) { + if (typeof fontSize === 'string' + && (fontSize.indexOf('px') !== -1 + || fontSize.indexOf('rem') !== -1 + || fontSize.indexOf('em') !== -1)) { + return fontSize; + } + else if (!isNaN(+fontSize)) { + return fontSize + 'px'; + } + else { + return DEFAULT_FONT_SIZE + 'px'; + } + } + function setSeparateFont(targetStyle, sourceStyle) { + for (var i = 0; i < FONT_PARTS.length; i++) { + var fontProp = FONT_PARTS[i]; + var val = sourceStyle[fontProp]; + if (val != null) { + targetStyle[fontProp] = val; + } + } + } + function hasSeparateFont(style) { + return style.fontSize != null || style.fontFamily || style.fontWeight; + } + function normalizeTextStyle(style) { + normalizeStyle(style); + each(style.rich, normalizeStyle); + return style; + } + function normalizeStyle(style) { + if (style) { + style.font = ZRText.makeFont(style); + var textAlign = style.align; + textAlign === 'middle' && (textAlign = 'center'); + style.align = (textAlign == null || VALID_TEXT_ALIGN[textAlign]) ? textAlign : 'left'; + var verticalAlign = style.verticalAlign; + verticalAlign === 'center' && (verticalAlign = 'middle'); + style.verticalAlign = (verticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[verticalAlign]) ? verticalAlign : 'top'; + var textPadding = style.padding; + if (textPadding) { + style.padding = normalizeCssArray(style.padding); + } + } + } + function getStroke(stroke, lineWidth) { + return (stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none') + ? null + : (stroke.image || stroke.colorStops) + ? '#000' + : stroke; + } + function getFill(fill) { + return (fill == null || fill === 'none') + ? null + : (fill.image || fill.colorStops) + ? '#000' + : fill; + } + function getTextXForPadding(x, textAlign, textPadding) { + return textAlign === 'right' + ? (x - textPadding[1]) + : textAlign === 'center' + ? (x + textPadding[3] / 2 - textPadding[1] / 2) + : (x + textPadding[3]); + } + function getStyleText(style) { + var text = style.text; + text != null && (text += ''); + return text; + } + function needDrawBackground(style) { + return !!(style.backgroundColor + || style.lineHeight + || (style.borderWidth && style.borderColor)); + } + + var getECData = makeInner(); + var setCommonECData = function (seriesIndex, dataType, dataIdx, el) { + if (el) { + var ecData = getECData(el); // Add data index and series index for indexing the data by element + // Useful in tooltip + + ecData.dataIndex = dataIdx; + ecData.dataType = dataType; + ecData.seriesIndex = seriesIndex; // TODO: not store dataIndex on children. + + if (el.type === 'group') { + el.traverse(function (child) { + var childECData = getECData(child); + childECData.seriesIndex = seriesIndex; + childECData.dataIndex = dataIdx; + childECData.dataType = dataType; + }); + } + } + }; + + var _highlightNextDigit = 1; + var _highlightKeyMap = {}; + var getSavedStates = makeInner(); + var getComponentStates = makeInner(); + var HOVER_STATE_NORMAL = 0; + var HOVER_STATE_BLUR = 1; + var HOVER_STATE_EMPHASIS = 2; + var SPECIAL_STATES = ['emphasis', 'blur', 'select']; + var DISPLAY_STATES = ['normal', 'emphasis', 'blur', 'select']; + var Z2_EMPHASIS_LIFT = 10; + var Z2_SELECT_LIFT = 9; + var HIGHLIGHT_ACTION_TYPE = 'highlight'; + var DOWNPLAY_ACTION_TYPE = 'downplay'; + var SELECT_ACTION_TYPE = 'select'; + var UNSELECT_ACTION_TYPE = 'unselect'; + var TOGGLE_SELECT_ACTION_TYPE = 'toggleSelect'; + + function hasFillOrStroke(fillOrStroke) { + return fillOrStroke != null && fillOrStroke !== 'none'; + } // Most lifted color are duplicated. + + + var liftedColorCache = new LRU(100); + + function liftColor(color$1) { + if (isString(color$1)) { + var liftedColor = liftedColorCache.get(color$1); + + if (!liftedColor) { + liftedColor = lift(color$1, -0.1); + liftedColorCache.put(color$1, liftedColor); + } + + return liftedColor; + } else if (isGradientObject(color$1)) { + var ret = extend({}, color$1); + ret.colorStops = map(color$1.colorStops, function (stop) { + return { + offset: stop.offset, + color: lift(stop.color, -0.1) + }; + }); + return ret; + } // Change nothing. + + + return color$1; + } + + function doChangeHoverState(el, stateName, hoverStateEnum) { + if (el.onHoverStateChange && (el.hoverState || 0) !== hoverStateEnum) { + el.onHoverStateChange(stateName); + } + + el.hoverState = hoverStateEnum; + } + + function singleEnterEmphasis(el) { + // Only mark the flag. + // States will be applied in the echarts.ts in next frame. + doChangeHoverState(el, 'emphasis', HOVER_STATE_EMPHASIS); + } + + function singleLeaveEmphasis(el) { + // Only mark the flag. + // States will be applied in the echarts.ts in next frame. + if (el.hoverState === HOVER_STATE_EMPHASIS) { + doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL); + } + } + + function singleEnterBlur(el) { + doChangeHoverState(el, 'blur', HOVER_STATE_BLUR); + } + + function singleLeaveBlur(el) { + if (el.hoverState === HOVER_STATE_BLUR) { + doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL); + } + } + + function singleEnterSelect(el) { + el.selected = true; + } + + function singleLeaveSelect(el) { + el.selected = false; + } + + function updateElementState(el, updater, commonParam) { + updater(el, commonParam); + } + + function traverseUpdateState(el, updater, commonParam) { + updateElementState(el, updater, commonParam); + el.isGroup && el.traverse(function (child) { + updateElementState(child, updater, commonParam); + }); + } + + function setStatesFlag(el, stateName) { + switch (stateName) { + case 'emphasis': + el.hoverState = HOVER_STATE_EMPHASIS; + break; + + case 'normal': + el.hoverState = HOVER_STATE_NORMAL; + break; + + case 'blur': + el.hoverState = HOVER_STATE_BLUR; + break; + + case 'select': + el.selected = true; + } + } + + function getFromStateStyle(el, props, toStateName, defaultValue) { + var style = el.style; + var fromState = {}; + + for (var i = 0; i < props.length; i++) { + var propName = props[i]; + var val = style[propName]; + fromState[propName] = val == null ? defaultValue && defaultValue[propName] : val; + } + + for (var i = 0; i < el.animators.length; i++) { + var animator = el.animators[i]; + + if (animator.__fromStateTransition // Dont consider the animation to emphasis state. + && animator.__fromStateTransition.indexOf(toStateName) < 0 && animator.targetName === 'style') { + animator.saveTo(fromState, props); + } + } + + return fromState; + } + + function createEmphasisDefaultState(el, stateName, targetStates, state) { + var hasSelect = targetStates && indexOf(targetStates, 'select') >= 0; + var cloned = false; + + if (el instanceof Path) { + var store = getSavedStates(el); + var fromFill = hasSelect ? store.selectFill || store.normalFill : store.normalFill; + var fromStroke = hasSelect ? store.selectStroke || store.normalStroke : store.normalStroke; + + if (hasFillOrStroke(fromFill) || hasFillOrStroke(fromStroke)) { + state = state || {}; + var emphasisStyle = state.style || {}; // inherit case + + if (emphasisStyle.fill === 'inherit') { + cloned = true; + state = extend({}, state); + emphasisStyle = extend({}, emphasisStyle); + emphasisStyle.fill = fromFill; + } // Apply default color lift + else if (!hasFillOrStroke(emphasisStyle.fill) && hasFillOrStroke(fromFill)) { + cloned = true; // Not modify the original value. + + state = extend({}, state); + emphasisStyle = extend({}, emphasisStyle); // Already being applied 'emphasis'. DON'T lift color multiple times. + + emphasisStyle.fill = liftColor(fromFill); + } // Not highlight stroke if fill has been highlighted. + else if (!hasFillOrStroke(emphasisStyle.stroke) && hasFillOrStroke(fromStroke)) { + if (!cloned) { + state = extend({}, state); + emphasisStyle = extend({}, emphasisStyle); + } + + emphasisStyle.stroke = liftColor(fromStroke); + } + + state.style = emphasisStyle; + } + } + + if (state) { + // TODO Share with textContent? + if (state.z2 == null) { + if (!cloned) { + state = extend({}, state); + } + + var z2EmphasisLift = el.z2EmphasisLift; + state.z2 = el.z2 + (z2EmphasisLift != null ? z2EmphasisLift : Z2_EMPHASIS_LIFT); + } + } + + return state; + } + + function createSelectDefaultState(el, stateName, state) { + // const hasSelect = indexOf(el.currentStates, stateName) >= 0; + if (state) { + // TODO Share with textContent? + if (state.z2 == null) { + state = extend({}, state); + var z2SelectLift = el.z2SelectLift; + state.z2 = el.z2 + (z2SelectLift != null ? z2SelectLift : Z2_SELECT_LIFT); + } + } + + return state; + } + + function createBlurDefaultState(el, stateName, state) { + var hasBlur = indexOf(el.currentStates, stateName) >= 0; + var currentOpacity = el.style.opacity; + var fromState = !hasBlur ? getFromStateStyle(el, ['opacity'], stateName, { + opacity: 1 + }) : null; + state = state || {}; + var blurStyle = state.style || {}; + + if (blurStyle.opacity == null) { + // clone state + state = extend({}, state); + blurStyle = extend({ + // Already being applied 'emphasis'. DON'T mul opacity multiple times. + opacity: hasBlur ? currentOpacity : fromState.opacity * 0.1 + }, blurStyle); + state.style = blurStyle; + } + + return state; + } + + function elementStateProxy(stateName, targetStates) { + var state = this.states[stateName]; + + if (this.style) { + if (stateName === 'emphasis') { + return createEmphasisDefaultState(this, stateName, targetStates, state); + } else if (stateName === 'blur') { + return createBlurDefaultState(this, stateName, state); + } else if (stateName === 'select') { + return createSelectDefaultState(this, stateName, state); + } + } + + return state; + } + /**FI + * Set hover style (namely "emphasis style") of element. + * @param el Should not be `zrender/graphic/Group`. + * @param focus 'self' | 'selfInSeries' | 'series' + */ + + + function setDefaultStateProxy(el) { + el.stateProxy = elementStateProxy; + var textContent = el.getTextContent(); + var textGuide = el.getTextGuideLine(); + + if (textContent) { + textContent.stateProxy = elementStateProxy; + } + + if (textGuide) { + textGuide.stateProxy = elementStateProxy; + } + } + function enterEmphasisWhenMouseOver(el, e) { + !shouldSilent(el, e) // "emphasis" event highlight has higher priority than mouse highlight. + && !el.__highByOuter && traverseUpdateState(el, singleEnterEmphasis); + } + function leaveEmphasisWhenMouseOut(el, e) { + !shouldSilent(el, e) // "emphasis" event highlight has higher priority than mouse highlight. + && !el.__highByOuter && traverseUpdateState(el, singleLeaveEmphasis); + } + function enterEmphasis(el, highlightDigit) { + el.__highByOuter |= 1 << (highlightDigit || 0); + traverseUpdateState(el, singleEnterEmphasis); + } + function leaveEmphasis(el, highlightDigit) { + !(el.__highByOuter &= ~(1 << (highlightDigit || 0))) && traverseUpdateState(el, singleLeaveEmphasis); + } + function enterBlur(el) { + traverseUpdateState(el, singleEnterBlur); + } + function leaveBlur(el) { + traverseUpdateState(el, singleLeaveBlur); + } + function enterSelect(el) { + traverseUpdateState(el, singleEnterSelect); + } + function leaveSelect(el) { + traverseUpdateState(el, singleLeaveSelect); + } + + function shouldSilent(el, e) { + return el.__highDownSilentOnTouch && e.zrByTouch; + } + + function allLeaveBlur(api) { + var model = api.getModel(); + var leaveBlurredSeries = []; + var allComponentViews = []; + model.eachComponent(function (componentType, componentModel) { + var componentStates = getComponentStates(componentModel); + var isSeries = componentType === 'series'; + var view = isSeries ? api.getViewOfSeriesModel(componentModel) : api.getViewOfComponentModel(componentModel); + !isSeries && allComponentViews.push(view); + + if (componentStates.isBlured) { + // Leave blur anyway + view.group.traverse(function (child) { + singleLeaveBlur(child); + }); + isSeries && leaveBlurredSeries.push(componentModel); + } + + componentStates.isBlured = false; + }); + each(allComponentViews, function (view) { + if (view && view.toggleBlurSeries) { + view.toggleBlurSeries(leaveBlurredSeries, false, model); + } + }); + } + function blurSeries(targetSeriesIndex, focus, blurScope, api) { + var ecModel = api.getModel(); + blurScope = blurScope || 'coordinateSystem'; + + function leaveBlurOfIndices(data, dataIndices) { + for (var i = 0; i < dataIndices.length; i++) { + var itemEl = data.getItemGraphicEl(dataIndices[i]); + itemEl && leaveBlur(itemEl); + } + } + + if (targetSeriesIndex == null) { + return; + } + + if (!focus || focus === 'none') { + return; + } + + var targetSeriesModel = ecModel.getSeriesByIndex(targetSeriesIndex); + var targetCoordSys = targetSeriesModel.coordinateSystem; + + if (targetCoordSys && targetCoordSys.master) { + targetCoordSys = targetCoordSys.master; + } + + var blurredSeries = []; + ecModel.eachSeries(function (seriesModel) { + var sameSeries = targetSeriesModel === seriesModel; + var coordSys = seriesModel.coordinateSystem; + + if (coordSys && coordSys.master) { + coordSys = coordSys.master; + } + + var sameCoordSys = coordSys && targetCoordSys ? coordSys === targetCoordSys : sameSeries; // If there is no coordinate system. use sameSeries instead. + + if (!( // Not blur other series if blurScope series + blurScope === 'series' && !sameSeries // Not blur other coordinate system if blurScope is coordinateSystem + || blurScope === 'coordinateSystem' && !sameCoordSys // Not blur self series if focus is series. + || focus === 'series' && sameSeries // TODO blurScope: coordinate system + )) { + var view = api.getViewOfSeriesModel(seriesModel); + view.group.traverse(function (child) { + singleEnterBlur(child); + }); + + if (isArrayLike(focus)) { + leaveBlurOfIndices(seriesModel.getData(), focus); + } else if (isObject(focus)) { + var dataTypes = keys(focus); + + for (var d = 0; d < dataTypes.length; d++) { + leaveBlurOfIndices(seriesModel.getData(dataTypes[d]), focus[dataTypes[d]]); + } + } + + blurredSeries.push(seriesModel); + getComponentStates(seriesModel).isBlured = true; + } + }); + ecModel.eachComponent(function (componentType, componentModel) { + if (componentType === 'series') { + return; + } + + var view = api.getViewOfComponentModel(componentModel); + + if (view && view.toggleBlurSeries) { + view.toggleBlurSeries(blurredSeries, true, ecModel); + } + }); + } + function blurComponent(componentMainType, componentIndex, api) { + if (componentMainType == null || componentIndex == null) { + return; + } + + var componentModel = api.getModel().getComponent(componentMainType, componentIndex); + + if (!componentModel) { + return; + } + + getComponentStates(componentModel).isBlured = true; + var view = api.getViewOfComponentModel(componentModel); + + if (!view || !view.focusBlurEnabled) { + return; + } + + view.group.traverse(function (child) { + singleEnterBlur(child); + }); + } + function blurSeriesFromHighlightPayload(seriesModel, payload, api) { + var seriesIndex = seriesModel.seriesIndex; + var data = seriesModel.getData(payload.dataType); + + if (!data) { + if ("development" !== 'production') { + error("Unknown dataType " + payload.dataType); + } + + return; + } + + var dataIndex = queryDataIndex(data, payload); // Pick the first one if there is multiple/none exists. + + dataIndex = (isArray(dataIndex) ? dataIndex[0] : dataIndex) || 0; + var el = data.getItemGraphicEl(dataIndex); + + if (!el) { + var count = data.count(); + var current = 0; // If data on dataIndex is NaN. + + while (!el && current < count) { + el = data.getItemGraphicEl(current++); + } + } + + if (el) { + var ecData = getECData(el); + blurSeries(seriesIndex, ecData.focus, ecData.blurScope, api); + } else { + // If there is no element put on the data. Try getting it from raw option + // TODO Should put it on seriesModel? + var focus_1 = seriesModel.get(['emphasis', 'focus']); + var blurScope = seriesModel.get(['emphasis', 'blurScope']); + + if (focus_1 != null) { + blurSeries(seriesIndex, focus_1, blurScope, api); + } + } + } + function findComponentHighDownDispatchers(componentMainType, componentIndex, name, api) { + var ret = { + focusSelf: false, + dispatchers: null + }; + + if (componentMainType == null || componentMainType === 'series' || componentIndex == null || name == null) { + return ret; + } + + var componentModel = api.getModel().getComponent(componentMainType, componentIndex); + + if (!componentModel) { + return ret; + } + + var view = api.getViewOfComponentModel(componentModel); + + if (!view || !view.findHighDownDispatchers) { + return ret; + } + + var dispatchers = view.findHighDownDispatchers(name); // At presnet, the component (like Geo) only blur inside itself. + // So we do not use `blurScope` in component. + + var focusSelf; + + for (var i = 0; i < dispatchers.length; i++) { + if ("development" !== 'production' && !isHighDownDispatcher(dispatchers[i])) { + error('param should be highDownDispatcher'); + } + + if (getECData(dispatchers[i]).focus === 'self') { + focusSelf = true; + break; + } + } + + return { + focusSelf: focusSelf, + dispatchers: dispatchers + }; + } + function handleGlobalMouseOverForHighDown(dispatcher, e, api) { + if ("development" !== 'production' && !isHighDownDispatcher(dispatcher)) { + error('param should be highDownDispatcher'); + } + + var ecData = getECData(dispatcher); + + var _a = findComponentHighDownDispatchers(ecData.componentMainType, ecData.componentIndex, ecData.componentHighDownName, api), + dispatchers = _a.dispatchers, + focusSelf = _a.focusSelf; // If `findHighDownDispatchers` is supported on the component, + // highlight/downplay elements with the same name. + + + if (dispatchers) { + if (focusSelf) { + blurComponent(ecData.componentMainType, ecData.componentIndex, api); + } + + each(dispatchers, function (dispatcher) { + return enterEmphasisWhenMouseOver(dispatcher, e); + }); + } else { + // Try blur all in the related series. Then emphasis the hoverred. + // TODO. progressive mode. + blurSeries(ecData.seriesIndex, ecData.focus, ecData.blurScope, api); + + if (ecData.focus === 'self') { + blurComponent(ecData.componentMainType, ecData.componentIndex, api); + } // Other than series, component that not support `findHighDownDispatcher` will + // also use it. But in this case, highlight/downplay are only supported in + // mouse hover but not in dispatchAction. + + + enterEmphasisWhenMouseOver(dispatcher, e); + } + } + function handleGlobalMouseOutForHighDown(dispatcher, e, api) { + if ("development" !== 'production' && !isHighDownDispatcher(dispatcher)) { + error('param should be highDownDispatcher'); + } + + allLeaveBlur(api); + var ecData = getECData(dispatcher); + var dispatchers = findComponentHighDownDispatchers(ecData.componentMainType, ecData.componentIndex, ecData.componentHighDownName, api).dispatchers; + + if (dispatchers) { + each(dispatchers, function (dispatcher) { + return leaveEmphasisWhenMouseOut(dispatcher, e); + }); + } else { + leaveEmphasisWhenMouseOut(dispatcher, e); + } + } + function toggleSelectionFromPayload(seriesModel, payload, api) { + if (!isSelectChangePayload(payload)) { + return; + } + + var dataType = payload.dataType; + var data = seriesModel.getData(dataType); + var dataIndex = queryDataIndex(data, payload); + + if (!isArray(dataIndex)) { + dataIndex = [dataIndex]; + } + + seriesModel[payload.type === TOGGLE_SELECT_ACTION_TYPE ? 'toggleSelect' : payload.type === SELECT_ACTION_TYPE ? 'select' : 'unselect'](dataIndex, dataType); + } + function updateSeriesElementSelection(seriesModel) { + var allData = seriesModel.getAllData(); + each(allData, function (_a) { + var data = _a.data, + type = _a.type; + data.eachItemGraphicEl(function (el, idx) { + seriesModel.isSelected(idx, type) ? enterSelect(el) : leaveSelect(el); + }); + }); + } + function getAllSelectedIndices(ecModel) { + var ret = []; + ecModel.eachSeries(function (seriesModel) { + var allData = seriesModel.getAllData(); + each(allData, function (_a) { + var data = _a.data, + type = _a.type; + var dataIndices = seriesModel.getSelectedDataIndices(); + + if (dataIndices.length > 0) { + var item = { + dataIndex: dataIndices, + seriesIndex: seriesModel.seriesIndex + }; + + if (type != null) { + item.dataType = type; + } + + ret.push(item); + } + }); + }); + return ret; + } + /** + * Enable the function that mouseover will trigger the emphasis state. + * + * NOTE: + * This function should be used on the element with dataIndex, seriesIndex. + * + */ + + function enableHoverEmphasis(el, focus, blurScope) { + setAsHighDownDispatcher(el, true); + traverseUpdateState(el, setDefaultStateProxy); + enableHoverFocus(el, focus, blurScope); + } + function disableHoverEmphasis(el) { + setAsHighDownDispatcher(el, false); + } + function toggleHoverEmphasis(el, focus, blurScope, isDisabled) { + isDisabled ? disableHoverEmphasis(el) : enableHoverEmphasis(el, focus, blurScope); + } + function enableHoverFocus(el, focus, blurScope) { + var ecData = getECData(el); + + if (focus != null) { + // TODO dataIndex may be set after this function. This check is not useful. + // if (ecData.dataIndex == null) { + // if (__DEV__) { + // console.warn('focus can only been set on element with dataIndex'); + // } + // } + // else { + ecData.focus = focus; + ecData.blurScope = blurScope; // } + } else if (ecData.focus) { + ecData.focus = null; + } + } + var OTHER_STATES = ['emphasis', 'blur', 'select']; + var defaultStyleGetterMap = { + itemStyle: 'getItemStyle', + lineStyle: 'getLineStyle', + areaStyle: 'getAreaStyle' + }; + /** + * Set emphasis/blur/selected states of element. + */ + + function setStatesStylesFromModel(el, itemModel, styleType, // default itemStyle + getter) { + styleType = styleType || 'itemStyle'; + + for (var i = 0; i < OTHER_STATES.length; i++) { + var stateName = OTHER_STATES[i]; + var model = itemModel.getModel([stateName, styleType]); + var state = el.ensureState(stateName); // Let it throw error if getterType is not found. + + state.style = getter ? getter(model) : model[defaultStyleGetterMap[styleType]](); + } + } + /** + * + * Set element as highlight / downplay dispatcher. + * It will be checked when element recieved mouseover event or from highlight action. + * It's in change of all highlight/downplay behavior of it's children. + * + * @param el + * @param el.highDownSilentOnTouch + * In touch device, mouseover event will be trigger on touchstart event + * (see module:zrender/dom/HandlerProxy). By this mechanism, we can + * conveniently use hoverStyle when tap on touch screen without additional + * code for compatibility. + * But if the chart/component has select feature, which usually also use + * hoverStyle, there might be conflict between 'select-highlight' and + * 'hover-highlight' especially when roam is enabled (see geo for example). + * In this case, `highDownSilentOnTouch` should be used to disable + * hover-highlight on touch device. + * @param asDispatcher If `false`, do not set as "highDownDispatcher". + */ + + function setAsHighDownDispatcher(el, asDispatcher) { + var disable = asDispatcher === false; + var extendedEl = el; // Make `highDownSilentOnTouch` and `onStateChange` only work after + // `setAsHighDownDispatcher` called. Avoid it is modified by user unexpectedly. + + if (el.highDownSilentOnTouch) { + extendedEl.__highDownSilentOnTouch = el.highDownSilentOnTouch; + } // Simple optimize, since this method might be + // called for each elements of a group in some cases. + + + if (!disable || extendedEl.__highDownDispatcher) { + // Emphasis, normal can be triggered manually by API or other components like hover link. + // el[method]('emphasis', onElementEmphasisEvent)[method]('normal', onElementNormalEvent); + // Also keep previous record. + extendedEl.__highByOuter = extendedEl.__highByOuter || 0; + extendedEl.__highDownDispatcher = !disable; + } + } + function isHighDownDispatcher(el) { + return !!(el && el.__highDownDispatcher); + } + /** + * Enable component highlight/downplay features: + * + hover link (within the same name) + * + focus blur in component + */ + + function enableComponentHighDownFeatures(el, componentModel, componentHighDownName) { + var ecData = getECData(el); + ecData.componentMainType = componentModel.mainType; + ecData.componentIndex = componentModel.componentIndex; + ecData.componentHighDownName = componentHighDownName; + } + /** + * Support hightlight/downplay record on each elements. + * For the case: hover highlight/downplay (legend, visualMap, ...) and + * user triggerred hightlight/downplay should not conflict. + * Only all of the highlightDigit cleared, return to normal. + * @param {string} highlightKey + * @return {number} highlightDigit + */ + + function getHighlightDigit(highlightKey) { + var highlightDigit = _highlightKeyMap[highlightKey]; + + if (highlightDigit == null && _highlightNextDigit <= 32) { + highlightDigit = _highlightKeyMap[highlightKey] = _highlightNextDigit++; + } + + return highlightDigit; + } + function isSelectChangePayload(payload) { + var payloadType = payload.type; + return payloadType === SELECT_ACTION_TYPE || payloadType === UNSELECT_ACTION_TYPE || payloadType === TOGGLE_SELECT_ACTION_TYPE; + } + function isHighDownPayload(payload) { + var payloadType = payload.type; + return payloadType === HIGHLIGHT_ACTION_TYPE || payloadType === DOWNPLAY_ACTION_TYPE; + } + function savePathStates(el) { + var store = getSavedStates(el); + store.normalFill = el.style.fill; + store.normalStroke = el.style.stroke; + var selectState = el.states.select || {}; + store.selectFill = selectState.style && selectState.style.fill || null; + store.selectStroke = selectState.style && selectState.style.stroke || null; + } + + var CMD$2 = PathProxy.CMD; + var points = [[], [], []]; + var mathSqrt$1 = Math.sqrt; + var mathAtan2 = Math.atan2; + function transformPath(path, m) { + if (!m) { + return; + } + var data = path.data; + var len = path.len(); + var cmd; + var nPoint; + var i; + var j; + var k; + var p; + var M = CMD$2.M; + var C = CMD$2.C; + var L = CMD$2.L; + var R = CMD$2.R; + var A = CMD$2.A; + var Q = CMD$2.Q; + for (i = 0, j = 0; i < len;) { + cmd = data[i++]; + j = i; + nPoint = 0; + switch (cmd) { + case M: + nPoint = 1; + break; + case L: + nPoint = 1; + break; + case C: + nPoint = 3; + break; + case Q: + nPoint = 2; + break; + case A: + var x = m[4]; + var y = m[5]; + var sx = mathSqrt$1(m[0] * m[0] + m[1] * m[1]); + var sy = mathSqrt$1(m[2] * m[2] + m[3] * m[3]); + var angle = mathAtan2(-m[1] / sy, m[0] / sx); + data[i] *= sx; + data[i++] += x; + data[i] *= sy; + data[i++] += y; + data[i++] *= sx; + data[i++] *= sy; + data[i++] += angle; + data[i++] += angle; + i += 2; + j = i; + break; + case R: + p[0] = data[i++]; + p[1] = data[i++]; + applyTransform(p, p, m); + data[j++] = p[0]; + data[j++] = p[1]; + p[0] += data[i++]; + p[1] += data[i++]; + applyTransform(p, p, m); + data[j++] = p[0]; + data[j++] = p[1]; + } + for (k = 0; k < nPoint; k++) { + var p_1 = points[k]; + p_1[0] = data[i++]; + p_1[1] = data[i++]; + applyTransform(p_1, p_1, m); + data[j++] = p_1[0]; + data[j++] = p_1[1]; + } + } + path.increaseVersion(); + } + + var mathSqrt$2 = Math.sqrt; + var mathSin$2 = Math.sin; + var mathCos$2 = Math.cos; + var PI$1 = Math.PI; + function vMag(v) { + return Math.sqrt(v[0] * v[0] + v[1] * v[1]); + } + function vRatio(u, v) { + return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v)); + } + function vAngle(u, v) { + return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) + * Math.acos(vRatio(u, v)); + } + function processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) { + var psi = psiDeg * (PI$1 / 180.0); + var xp = mathCos$2(psi) * (x1 - x2) / 2.0 + + mathSin$2(psi) * (y1 - y2) / 2.0; + var yp = -1 * mathSin$2(psi) * (x1 - x2) / 2.0 + + mathCos$2(psi) * (y1 - y2) / 2.0; + var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry); + if (lambda > 1) { + rx *= mathSqrt$2(lambda); + ry *= mathSqrt$2(lambda); + } + var f = (fa === fs ? -1 : 1) + * mathSqrt$2((((rx * rx) * (ry * ry)) + - ((rx * rx) * (yp * yp)) + - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp) + + (ry * ry) * (xp * xp))) || 0; + var cxp = f * rx * yp / ry; + var cyp = f * -ry * xp / rx; + var cx = (x1 + x2) / 2.0 + + mathCos$2(psi) * cxp + - mathSin$2(psi) * cyp; + var cy = (y1 + y2) / 2.0 + + mathSin$2(psi) * cxp + + mathCos$2(psi) * cyp; + var theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]); + var u = [(xp - cxp) / rx, (yp - cyp) / ry]; + var v = [(-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry]; + var dTheta = vAngle(u, v); + if (vRatio(u, v) <= -1) { + dTheta = PI$1; + } + if (vRatio(u, v) >= 1) { + dTheta = 0; + } + if (dTheta < 0) { + var n = Math.round(dTheta / PI$1 * 1e6) / 1e6; + dTheta = PI$1 * 2 + (n % 2) * PI$1; + } + path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs); + } + var commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig; + var numberReg = /-?([0-9]*\.)?[0-9]+([eE]-?[0-9]+)?/g; + function createPathProxyFromString(data) { + var path = new PathProxy(); + if (!data) { + return path; + } + var cpx = 0; + var cpy = 0; + var subpathX = cpx; + var subpathY = cpy; + var prevCmd; + var CMD = PathProxy.CMD; + var cmdList = data.match(commandReg); + if (!cmdList) { + return path; + } + for (var l = 0; l < cmdList.length; l++) { + var cmdText = cmdList[l]; + var cmdStr = cmdText.charAt(0); + var cmd = void 0; + var p = cmdText.match(numberReg) || []; + var pLen = p.length; + for (var i = 0; i < pLen; i++) { + p[i] = parseFloat(p[i]); + } + var off = 0; + while (off < pLen) { + var ctlPtx = void 0; + var ctlPty = void 0; + var rx = void 0; + var ry = void 0; + var psi = void 0; + var fa = void 0; + var fs = void 0; + var x1 = cpx; + var y1 = cpy; + var len = void 0; + var pathData = void 0; + switch (cmdStr) { + case 'l': + cpx += p[off++]; + cpy += p[off++]; + cmd = CMD.L; + path.addData(cmd, cpx, cpy); + break; + case 'L': + cpx = p[off++]; + cpy = p[off++]; + cmd = CMD.L; + path.addData(cmd, cpx, cpy); + break; + case 'm': + cpx += p[off++]; + cpy += p[off++]; + cmd = CMD.M; + path.addData(cmd, cpx, cpy); + subpathX = cpx; + subpathY = cpy; + cmdStr = 'l'; + break; + case 'M': + cpx = p[off++]; + cpy = p[off++]; + cmd = CMD.M; + path.addData(cmd, cpx, cpy); + subpathX = cpx; + subpathY = cpy; + cmdStr = 'L'; + break; + case 'h': + cpx += p[off++]; + cmd = CMD.L; + path.addData(cmd, cpx, cpy); + break; + case 'H': + cpx = p[off++]; + cmd = CMD.L; + path.addData(cmd, cpx, cpy); + break; + case 'v': + cpy += p[off++]; + cmd = CMD.L; + path.addData(cmd, cpx, cpy); + break; + case 'V': + cpy = p[off++]; + cmd = CMD.L; + path.addData(cmd, cpx, cpy); + break; + case 'C': + cmd = CMD.C; + path.addData(cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]); + cpx = p[off - 2]; + cpy = p[off - 1]; + break; + case 'c': + cmd = CMD.C; + path.addData(cmd, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy); + cpx += p[off - 2]; + cpy += p[off - 1]; + break; + case 'S': + ctlPtx = cpx; + ctlPty = cpy; + len = path.len(); + pathData = path.data; + if (prevCmd === CMD.C) { + ctlPtx += cpx - pathData[len - 4]; + ctlPty += cpy - pathData[len - 3]; + } + cmd = CMD.C; + x1 = p[off++]; + y1 = p[off++]; + cpx = p[off++]; + cpy = p[off++]; + path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy); + break; + case 's': + ctlPtx = cpx; + ctlPty = cpy; + len = path.len(); + pathData = path.data; + if (prevCmd === CMD.C) { + ctlPtx += cpx - pathData[len - 4]; + ctlPty += cpy - pathData[len - 3]; + } + cmd = CMD.C; + x1 = cpx + p[off++]; + y1 = cpy + p[off++]; + cpx += p[off++]; + cpy += p[off++]; + path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy); + break; + case 'Q': + x1 = p[off++]; + y1 = p[off++]; + cpx = p[off++]; + cpy = p[off++]; + cmd = CMD.Q; + path.addData(cmd, x1, y1, cpx, cpy); + break; + case 'q': + x1 = p[off++] + cpx; + y1 = p[off++] + cpy; + cpx += p[off++]; + cpy += p[off++]; + cmd = CMD.Q; + path.addData(cmd, x1, y1, cpx, cpy); + break; + case 'T': + ctlPtx = cpx; + ctlPty = cpy; + len = path.len(); + pathData = path.data; + if (prevCmd === CMD.Q) { + ctlPtx += cpx - pathData[len - 4]; + ctlPty += cpy - pathData[len - 3]; + } + cpx = p[off++]; + cpy = p[off++]; + cmd = CMD.Q; + path.addData(cmd, ctlPtx, ctlPty, cpx, cpy); + break; + case 't': + ctlPtx = cpx; + ctlPty = cpy; + len = path.len(); + pathData = path.data; + if (prevCmd === CMD.Q) { + ctlPtx += cpx - pathData[len - 4]; + ctlPty += cpy - pathData[len - 3]; + } + cpx += p[off++]; + cpy += p[off++]; + cmd = CMD.Q; + path.addData(cmd, ctlPtx, ctlPty, cpx, cpy); + break; + case 'A': + rx = p[off++]; + ry = p[off++]; + psi = p[off++]; + fa = p[off++]; + fs = p[off++]; + x1 = cpx, y1 = cpy; + cpx = p[off++]; + cpy = p[off++]; + cmd = CMD.A; + processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path); + break; + case 'a': + rx = p[off++]; + ry = p[off++]; + psi = p[off++]; + fa = p[off++]; + fs = p[off++]; + x1 = cpx, y1 = cpy; + cpx += p[off++]; + cpy += p[off++]; + cmd = CMD.A; + processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path); + break; + } + } + if (cmdStr === 'z' || cmdStr === 'Z') { + cmd = CMD.Z; + path.addData(cmd); + cpx = subpathX; + cpy = subpathY; + } + prevCmd = cmd; + } + path.toStatic(); + return path; + } + var SVGPath = (function (_super) { + __extends(SVGPath, _super); + function SVGPath() { + return _super !== null && _super.apply(this, arguments) || this; + } + SVGPath.prototype.applyTransform = function (m) { }; + return SVGPath; + }(Path)); + function isPathProxy(path) { + return path.setData != null; + } + function createPathOptions(str, opts) { + var pathProxy = createPathProxyFromString(str); + var innerOpts = extend({}, opts); + innerOpts.buildPath = function (path) { + if (isPathProxy(path)) { + path.setData(pathProxy.data); + var ctx = path.getContext(); + if (ctx) { + path.rebuildPath(ctx, 1); + } + } + else { + var ctx = path; + pathProxy.rebuildPath(ctx, 1); + } + }; + innerOpts.applyTransform = function (m) { + transformPath(pathProxy, m); + this.dirtyShape(); + }; + return innerOpts; + } + function createFromString(str, opts) { + return new SVGPath(createPathOptions(str, opts)); + } + function extendFromString(str, defaultOpts) { + var innerOpts = createPathOptions(str, defaultOpts); + var Sub = (function (_super) { + __extends(Sub, _super); + function Sub(opts) { + var _this = _super.call(this, opts) || this; + _this.applyTransform = innerOpts.applyTransform; + _this.buildPath = innerOpts.buildPath; + return _this; + } + return Sub; + }(SVGPath)); + return Sub; + } + function mergePath(pathEls, opts) { + var pathList = []; + var len = pathEls.length; + for (var i = 0; i < len; i++) { + var pathEl = pathEls[i]; + pathList.push(pathEl.getUpdatedPathProxy(true)); + } + var pathBundle = new Path(opts); + pathBundle.createPathProxy(); + pathBundle.buildPath = function (path) { + if (isPathProxy(path)) { + path.appendPath(pathList); + var ctx = path.getContext(); + if (ctx) { + path.rebuildPath(ctx, 1); + } + } + }; + return pathBundle; + } + function clonePath(sourcePath, opts) { + opts = opts || {}; + var path = new Path(); + if (sourcePath.shape) { + path.setShape(sourcePath.shape); + } + path.setStyle(sourcePath.style); + if (opts.bakeTransform) { + transformPath(path.path, sourcePath.getComputedTransform()); + } + else { + if (opts.toLocal) { + path.setLocalTransform(sourcePath.getComputedTransform()); + } + else { + path.copyTransform(sourcePath); + } + } + path.buildPath = sourcePath.buildPath; + path.applyTransform = path.applyTransform; + path.z = sourcePath.z; + path.z2 = sourcePath.z2; + path.zlevel = sourcePath.zlevel; + return path; + } + + var CircleShape = (function () { + function CircleShape() { + this.cx = 0; + this.cy = 0; + this.r = 0; + } + return CircleShape; + }()); + var Circle = (function (_super) { + __extends(Circle, _super); + function Circle(opts) { + return _super.call(this, opts) || this; + } + Circle.prototype.getDefaultShape = function () { + return new CircleShape(); + }; + Circle.prototype.buildPath = function (ctx, shape) { + ctx.moveTo(shape.cx + shape.r, shape.cy); + ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2); + }; + return Circle; + }(Path)); + Circle.prototype.type = 'circle'; + + var EllipseShape = (function () { + function EllipseShape() { + this.cx = 0; + this.cy = 0; + this.rx = 0; + this.ry = 0; + } + return EllipseShape; + }()); + var Ellipse = (function (_super) { + __extends(Ellipse, _super); + function Ellipse(opts) { + return _super.call(this, opts) || this; + } + Ellipse.prototype.getDefaultShape = function () { + return new EllipseShape(); + }; + Ellipse.prototype.buildPath = function (ctx, shape) { + var k = 0.5522848; + var x = shape.cx; + var y = shape.cy; + var a = shape.rx; + var b = shape.ry; + var ox = a * k; + var oy = b * k; + ctx.moveTo(x - a, y); + ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b); + ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y); + ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b); + ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y); + ctx.closePath(); + }; + return Ellipse; + }(Path)); + Ellipse.prototype.type = 'ellipse'; + + var PI$2 = Math.PI; + var PI2$5 = PI$2 * 2; + var mathSin$3 = Math.sin; + var mathCos$3 = Math.cos; + var mathACos = Math.acos; + var mathATan2 = Math.atan2; + var mathAbs$1 = Math.abs; + var mathSqrt$3 = Math.sqrt; + var mathMax$3 = Math.max; + var mathMin$3 = Math.min; + var e = 1e-4; + function intersect(x0, y0, x1, y1, x2, y2, x3, y3) { + var dx10 = x1 - x0; + var dy10 = y1 - y0; + var dx32 = x3 - x2; + var dy32 = y3 - y2; + var t = dy32 * dx10 - dx32 * dy10; + if (t * t < e) { + return; + } + t = (dx32 * (y0 - y2) - dy32 * (x0 - x2)) / t; + return [x0 + t * dx10, y0 + t * dy10]; + } + function computeCornerTangents(x0, y0, x1, y1, radius, cr, clockwise) { + var x01 = x0 - x1; + var y01 = y0 - y1; + var lo = (clockwise ? cr : -cr) / mathSqrt$3(x01 * x01 + y01 * y01); + var ox = lo * y01; + var oy = -lo * x01; + var x11 = x0 + ox; + var y11 = y0 + oy; + var x10 = x1 + ox; + var y10 = y1 + oy; + var x00 = (x11 + x10) / 2; + var y00 = (y11 + y10) / 2; + var dx = x10 - x11; + var dy = y10 - y11; + var d2 = dx * dx + dy * dy; + var r = radius - cr; + var s = x11 * y10 - x10 * y11; + var d = (dy < 0 ? -1 : 1) * mathSqrt$3(mathMax$3(0, r * r * d2 - s * s)); + var cx0 = (s * dy - dx * d) / d2; + var cy0 = (-s * dx - dy * d) / d2; + var cx1 = (s * dy + dx * d) / d2; + var cy1 = (-s * dx + dy * d) / d2; + var dx0 = cx0 - x00; + var dy0 = cy0 - y00; + var dx1 = cx1 - x00; + var dy1 = cy1 - y00; + if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) { + cx0 = cx1; + cy0 = cy1; + } + return { + cx: cx0, + cy: cy0, + x0: -ox, + y0: -oy, + x1: cx0 * (radius / r - 1), + y1: cy0 * (radius / r - 1) + }; + } + function normalizeCornerRadius(cr) { + var arr; + if (isArray(cr)) { + var len = cr.length; + if (!len) { + return cr; + } + if (len === 1) { + arr = [cr[0], cr[0], 0, 0]; + } + else if (len === 2) { + arr = [cr[0], cr[0], cr[1], cr[1]]; + } + else if (len === 3) { + arr = cr.concat(cr[2]); + } + else { + arr = cr; + } + } + else { + arr = [cr, cr, cr, cr]; + } + return arr; + } + function buildPath$1(ctx, shape) { + var _a; + var radius = mathMax$3(shape.r, 0); + var innerRadius = mathMax$3(shape.r0 || 0, 0); + var hasRadius = radius > 0; + var hasInnerRadius = innerRadius > 0; + if (!hasRadius && !hasInnerRadius) { + return; + } + if (!hasRadius) { + radius = innerRadius; + innerRadius = 0; + } + if (innerRadius > radius) { + var tmp = radius; + radius = innerRadius; + innerRadius = tmp; + } + var startAngle = shape.startAngle, endAngle = shape.endAngle; + if (isNaN(startAngle) || isNaN(endAngle)) { + return; + } + var cx = shape.cx, cy = shape.cy; + var clockwise = !!shape.clockwise; + var arc = mathAbs$1(endAngle - startAngle); + var mod = arc > PI2$5 && arc % PI2$5; + mod > e && (arc = mod); + if (!(radius > e)) { + ctx.moveTo(cx, cy); + } + else if (arc > PI2$5 - e) { + ctx.moveTo(cx + radius * mathCos$3(startAngle), cy + radius * mathSin$3(startAngle)); + ctx.arc(cx, cy, radius, startAngle, endAngle, !clockwise); + if (innerRadius > e) { + ctx.moveTo(cx + innerRadius * mathCos$3(endAngle), cy + innerRadius * mathSin$3(endAngle)); + ctx.arc(cx, cy, innerRadius, endAngle, startAngle, clockwise); + } + } + else { + var icrStart = void 0; + var icrEnd = void 0; + var ocrStart = void 0; + var ocrEnd = void 0; + var ocrs = void 0; + var ocre = void 0; + var icrs = void 0; + var icre = void 0; + var ocrMax = void 0; + var icrMax = void 0; + var limitedOcrMax = void 0; + var limitedIcrMax = void 0; + var xre = void 0; + var yre = void 0; + var xirs = void 0; + var yirs = void 0; + var xrs = radius * mathCos$3(startAngle); + var yrs = radius * mathSin$3(startAngle); + var xire = innerRadius * mathCos$3(endAngle); + var yire = innerRadius * mathSin$3(endAngle); + var hasArc = arc > e; + if (hasArc) { + var cornerRadius = shape.cornerRadius; + if (cornerRadius) { + _a = normalizeCornerRadius(cornerRadius), icrStart = _a[0], icrEnd = _a[1], ocrStart = _a[2], ocrEnd = _a[3]; + } + var halfRd = mathAbs$1(radius - innerRadius) / 2; + ocrs = mathMin$3(halfRd, ocrStart); + ocre = mathMin$3(halfRd, ocrEnd); + icrs = mathMin$3(halfRd, icrStart); + icre = mathMin$3(halfRd, icrEnd); + limitedOcrMax = ocrMax = mathMax$3(ocrs, ocre); + limitedIcrMax = icrMax = mathMax$3(icrs, icre); + if (ocrMax > e || icrMax > e) { + xre = radius * mathCos$3(endAngle); + yre = radius * mathSin$3(endAngle); + xirs = innerRadius * mathCos$3(startAngle); + yirs = innerRadius * mathSin$3(startAngle); + if (arc < PI$2) { + var it_1 = intersect(xrs, yrs, xirs, yirs, xre, yre, xire, yire); + if (it_1) { + var x0 = xrs - it_1[0]; + var y0 = yrs - it_1[1]; + var x1 = xre - it_1[0]; + var y1 = yre - it_1[1]; + var a = 1 / mathSin$3(mathACos((x0 * x1 + y0 * y1) / (mathSqrt$3(x0 * x0 + y0 * y0) * mathSqrt$3(x1 * x1 + y1 * y1))) / 2); + var b = mathSqrt$3(it_1[0] * it_1[0] + it_1[1] * it_1[1]); + limitedOcrMax = mathMin$3(ocrMax, (radius - b) / (a + 1)); + limitedIcrMax = mathMin$3(icrMax, (innerRadius - b) / (a - 1)); + } + } + } + } + if (!hasArc) { + ctx.moveTo(cx + xrs, cy + yrs); + } + else if (limitedOcrMax > e) { + var crStart = mathMin$3(ocrStart, limitedOcrMax); + var crEnd = mathMin$3(ocrEnd, limitedOcrMax); + var ct0 = computeCornerTangents(xirs, yirs, xrs, yrs, radius, crStart, clockwise); + var ct1 = computeCornerTangents(xre, yre, xire, yire, radius, crEnd, clockwise); + ctx.moveTo(cx + ct0.cx + ct0.x0, cy + ct0.cy + ct0.y0); + if (limitedOcrMax < ocrMax && crStart === crEnd) { + ctx.arc(cx + ct0.cx, cy + ct0.cy, limitedOcrMax, mathATan2(ct0.y0, ct0.x0), mathATan2(ct1.y0, ct1.x0), !clockwise); + } + else { + crStart > 0 && ctx.arc(cx + ct0.cx, cy + ct0.cy, crStart, mathATan2(ct0.y0, ct0.x0), mathATan2(ct0.y1, ct0.x1), !clockwise); + ctx.arc(cx, cy, radius, mathATan2(ct0.cy + ct0.y1, ct0.cx + ct0.x1), mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1), !clockwise); + crEnd > 0 && ctx.arc(cx + ct1.cx, cy + ct1.cy, crEnd, mathATan2(ct1.y1, ct1.x1), mathATan2(ct1.y0, ct1.x0), !clockwise); + } + } + else { + ctx.moveTo(cx + xrs, cy + yrs); + ctx.arc(cx, cy, radius, startAngle, endAngle, !clockwise); + } + if (!(innerRadius > e) || !hasArc) { + ctx.lineTo(cx + xire, cy + yire); + } + else if (limitedIcrMax > e) { + var crStart = mathMin$3(icrStart, limitedIcrMax); + var crEnd = mathMin$3(icrEnd, limitedIcrMax); + var ct0 = computeCornerTangents(xire, yire, xre, yre, innerRadius, -crEnd, clockwise); + var ct1 = computeCornerTangents(xrs, yrs, xirs, yirs, innerRadius, -crStart, clockwise); + ctx.lineTo(cx + ct0.cx + ct0.x0, cy + ct0.cy + ct0.y0); + if (limitedIcrMax < icrMax && crStart === crEnd) { + ctx.arc(cx + ct0.cx, cy + ct0.cy, limitedIcrMax, mathATan2(ct0.y0, ct0.x0), mathATan2(ct1.y0, ct1.x0), !clockwise); + } + else { + crEnd > 0 && ctx.arc(cx + ct0.cx, cy + ct0.cy, crEnd, mathATan2(ct0.y0, ct0.x0), mathATan2(ct0.y1, ct0.x1), !clockwise); + ctx.arc(cx, cy, innerRadius, mathATan2(ct0.cy + ct0.y1, ct0.cx + ct0.x1), mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1), clockwise); + crStart > 0 && ctx.arc(cx + ct1.cx, cy + ct1.cy, crStart, mathATan2(ct1.y1, ct1.x1), mathATan2(ct1.y0, ct1.x0), !clockwise); + } + } + else { + ctx.lineTo(cx + xire, cy + yire); + ctx.arc(cx, cy, innerRadius, endAngle, startAngle, clockwise); + } + } + ctx.closePath(); + } + + var SectorShape = (function () { + function SectorShape() { + this.cx = 0; + this.cy = 0; + this.r0 = 0; + this.r = 0; + this.startAngle = 0; + this.endAngle = Math.PI * 2; + this.clockwise = true; + this.cornerRadius = 0; + } + return SectorShape; + }()); + var Sector = (function (_super) { + __extends(Sector, _super); + function Sector(opts) { + return _super.call(this, opts) || this; + } + Sector.prototype.getDefaultShape = function () { + return new SectorShape(); + }; + Sector.prototype.buildPath = function (ctx, shape) { + buildPath$1(ctx, shape); + }; + Sector.prototype.isZeroArea = function () { + return this.shape.startAngle === this.shape.endAngle + || this.shape.r === this.shape.r0; + }; + return Sector; + }(Path)); + Sector.prototype.type = 'sector'; + + var RingShape = (function () { + function RingShape() { + this.cx = 0; + this.cy = 0; + this.r = 0; + this.r0 = 0; + } + return RingShape; + }()); + var Ring = (function (_super) { + __extends(Ring, _super); + function Ring(opts) { + return _super.call(this, opts) || this; + } + Ring.prototype.getDefaultShape = function () { + return new RingShape(); + }; + Ring.prototype.buildPath = function (ctx, shape) { + var x = shape.cx; + var y = shape.cy; + var PI2 = Math.PI * 2; + ctx.moveTo(x + shape.r, y); + ctx.arc(x, y, shape.r, 0, PI2, false); + ctx.moveTo(x + shape.r0, y); + ctx.arc(x, y, shape.r0, 0, PI2, true); + }; + return Ring; + }(Path)); + Ring.prototype.type = 'ring'; + + function smoothBezier(points, smooth, isLoop, constraint) { + var cps = []; + var v = []; + var v1 = []; + var v2 = []; + var prevPoint; + var nextPoint; + var min$1; + var max$1; + if (constraint) { + min$1 = [Infinity, Infinity]; + max$1 = [-Infinity, -Infinity]; + for (var i = 0, len = points.length; i < len; i++) { + min(min$1, min$1, points[i]); + max(max$1, max$1, points[i]); + } + min(min$1, min$1, constraint[0]); + max(max$1, max$1, constraint[1]); + } + for (var i = 0, len = points.length; i < len; i++) { + var point = points[i]; + if (isLoop) { + prevPoint = points[i ? i - 1 : len - 1]; + nextPoint = points[(i + 1) % len]; + } + else { + if (i === 0 || i === len - 1) { + cps.push(clone$1(points[i])); + continue; + } + else { + prevPoint = points[i - 1]; + nextPoint = points[i + 1]; + } + } + sub(v, nextPoint, prevPoint); + scale(v, v, smooth); + var d0 = distance(point, prevPoint); + var d1 = distance(point, nextPoint); + var sum = d0 + d1; + if (sum !== 0) { + d0 /= sum; + d1 /= sum; + } + scale(v1, v, -d0); + scale(v2, v, d1); + var cp0 = add([], point, v1); + var cp1 = add([], point, v2); + if (constraint) { + max(cp0, cp0, min$1); + min(cp0, cp0, max$1); + max(cp1, cp1, min$1); + min(cp1, cp1, max$1); + } + cps.push(cp0); + cps.push(cp1); + } + if (isLoop) { + cps.push(cps.shift()); + } + return cps; + } + + function buildPath$2(ctx, shape, closePath) { + var smooth = shape.smooth; + var points = shape.points; + if (points && points.length >= 2) { + if (smooth) { + var controlPoints = smoothBezier(points, smooth, closePath, shape.smoothConstraint); + ctx.moveTo(points[0][0], points[0][1]); + var len = points.length; + for (var i = 0; i < (closePath ? len : len - 1); i++) { + var cp1 = controlPoints[i * 2]; + var cp2 = controlPoints[i * 2 + 1]; + var p = points[(i + 1) % len]; + ctx.bezierCurveTo(cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]); + } + } + else { + ctx.moveTo(points[0][0], points[0][1]); + for (var i = 1, l = points.length; i < l; i++) { + ctx.lineTo(points[i][0], points[i][1]); + } + } + closePath && ctx.closePath(); + } + } + + var PolygonShape = (function () { + function PolygonShape() { + this.points = null; + this.smooth = 0; + this.smoothConstraint = null; + } + return PolygonShape; + }()); + var Polygon = (function (_super) { + __extends(Polygon, _super); + function Polygon(opts) { + return _super.call(this, opts) || this; + } + Polygon.prototype.getDefaultShape = function () { + return new PolygonShape(); + }; + Polygon.prototype.buildPath = function (ctx, shape) { + buildPath$2(ctx, shape, true); + }; + return Polygon; + }(Path)); + Polygon.prototype.type = 'polygon'; + + var PolylineShape = (function () { + function PolylineShape() { + this.points = null; + this.percent = 1; + this.smooth = 0; + this.smoothConstraint = null; + } + return PolylineShape; + }()); + var Polyline = (function (_super) { + __extends(Polyline, _super); + function Polyline(opts) { + return _super.call(this, opts) || this; + } + Polyline.prototype.getDefaultStyle = function () { + return { + stroke: '#000', + fill: null + }; + }; + Polyline.prototype.getDefaultShape = function () { + return new PolylineShape(); + }; + Polyline.prototype.buildPath = function (ctx, shape) { + buildPath$2(ctx, shape, false); + }; + return Polyline; + }(Path)); + Polyline.prototype.type = 'polyline'; + + var subPixelOptimizeOutputShape$1 = {}; + var LineShape = (function () { + function LineShape() { + this.x1 = 0; + this.y1 = 0; + this.x2 = 0; + this.y2 = 0; + this.percent = 1; + } + return LineShape; + }()); + var Line = (function (_super) { + __extends(Line, _super); + function Line(opts) { + return _super.call(this, opts) || this; + } + Line.prototype.getDefaultStyle = function () { + return { + stroke: '#000', + fill: null + }; + }; + Line.prototype.getDefaultShape = function () { + return new LineShape(); + }; + Line.prototype.buildPath = function (ctx, shape) { + var x1; + var y1; + var x2; + var y2; + if (this.subPixelOptimize) { + var optimizedShape = subPixelOptimizeLine(subPixelOptimizeOutputShape$1, shape, this.style); + x1 = optimizedShape.x1; + y1 = optimizedShape.y1; + x2 = optimizedShape.x2; + y2 = optimizedShape.y2; + } + else { + x1 = shape.x1; + y1 = shape.y1; + x2 = shape.x2; + y2 = shape.y2; + } + var percent = shape.percent; + if (percent === 0) { + return; + } + ctx.moveTo(x1, y1); + if (percent < 1) { + x2 = x1 * (1 - percent) + x2 * percent; + y2 = y1 * (1 - percent) + y2 * percent; + } + ctx.lineTo(x2, y2); + }; + Line.prototype.pointAt = function (p) { + var shape = this.shape; + return [ + shape.x1 * (1 - p) + shape.x2 * p, + shape.y1 * (1 - p) + shape.y2 * p + ]; + }; + return Line; + }(Path)); + Line.prototype.type = 'line'; + + var out = []; + var BezierCurveShape = (function () { + function BezierCurveShape() { + this.x1 = 0; + this.y1 = 0; + this.x2 = 0; + this.y2 = 0; + this.cpx1 = 0; + this.cpy1 = 0; + this.percent = 1; + } + return BezierCurveShape; + }()); + function someVectorAt(shape, t, isTangent) { + var cpx2 = shape.cpx2; + var cpy2 = shape.cpy2; + if (cpx2 != null || cpy2 != null) { + return [ + (isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t), + (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t) + ]; + } + else { + return [ + (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t), + (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t) + ]; + } + } + var BezierCurve = (function (_super) { + __extends(BezierCurve, _super); + function BezierCurve(opts) { + return _super.call(this, opts) || this; + } + BezierCurve.prototype.getDefaultStyle = function () { + return { + stroke: '#000', + fill: null + }; + }; + BezierCurve.prototype.getDefaultShape = function () { + return new BezierCurveShape(); + }; + BezierCurve.prototype.buildPath = function (ctx, shape) { + var x1 = shape.x1; + var y1 = shape.y1; + var x2 = shape.x2; + var y2 = shape.y2; + var cpx1 = shape.cpx1; + var cpy1 = shape.cpy1; + var cpx2 = shape.cpx2; + var cpy2 = shape.cpy2; + var percent = shape.percent; + if (percent === 0) { + return; + } + ctx.moveTo(x1, y1); + if (cpx2 == null || cpy2 == null) { + if (percent < 1) { + quadraticSubdivide(x1, cpx1, x2, percent, out); + cpx1 = out[1]; + x2 = out[2]; + quadraticSubdivide(y1, cpy1, y2, percent, out); + cpy1 = out[1]; + y2 = out[2]; + } + ctx.quadraticCurveTo(cpx1, cpy1, x2, y2); + } + else { + if (percent < 1) { + cubicSubdivide(x1, cpx1, cpx2, x2, percent, out); + cpx1 = out[1]; + cpx2 = out[2]; + x2 = out[3]; + cubicSubdivide(y1, cpy1, cpy2, y2, percent, out); + cpy1 = out[1]; + cpy2 = out[2]; + y2 = out[3]; + } + ctx.bezierCurveTo(cpx1, cpy1, cpx2, cpy2, x2, y2); + } + }; + BezierCurve.prototype.pointAt = function (t) { + return someVectorAt(this.shape, t, false); + }; + BezierCurve.prototype.tangentAt = function (t) { + var p = someVectorAt(this.shape, t, true); + return normalize(p, p); + }; + return BezierCurve; + }(Path)); + BezierCurve.prototype.type = 'bezier-curve'; + + var ArcShape = (function () { + function ArcShape() { + this.cx = 0; + this.cy = 0; + this.r = 0; + this.startAngle = 0; + this.endAngle = Math.PI * 2; + this.clockwise = true; + } + return ArcShape; + }()); + var Arc = (function (_super) { + __extends(Arc, _super); + function Arc(opts) { + return _super.call(this, opts) || this; + } + Arc.prototype.getDefaultStyle = function () { + return { + stroke: '#000', + fill: null + }; + }; + Arc.prototype.getDefaultShape = function () { + return new ArcShape(); + }; + Arc.prototype.buildPath = function (ctx, shape) { + var x = shape.cx; + var y = shape.cy; + var r = Math.max(shape.r, 0); + var startAngle = shape.startAngle; + var endAngle = shape.endAngle; + var clockwise = shape.clockwise; + var unitX = Math.cos(startAngle); + var unitY = Math.sin(startAngle); + ctx.moveTo(unitX * r + x, unitY * r + y); + ctx.arc(x, y, r, startAngle, endAngle, !clockwise); + }; + return Arc; + }(Path)); + Arc.prototype.type = 'arc'; + + var CompoundPath = (function (_super) { + __extends(CompoundPath, _super); + function CompoundPath() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.type = 'compound'; + return _this; + } + CompoundPath.prototype._updatePathDirty = function () { + var paths = this.shape.paths; + var dirtyPath = this.shapeChanged(); + for (var i = 0; i < paths.length; i++) { + dirtyPath = dirtyPath || paths[i].shapeChanged(); + } + if (dirtyPath) { + this.dirtyShape(); + } + }; + CompoundPath.prototype.beforeBrush = function () { + this._updatePathDirty(); + var paths = this.shape.paths || []; + var scale = this.getGlobalScale(); + for (var i = 0; i < paths.length; i++) { + if (!paths[i].path) { + paths[i].createPathProxy(); + } + paths[i].path.setScale(scale[0], scale[1], paths[i].segmentIgnoreThreshold); + } + }; + CompoundPath.prototype.buildPath = function (ctx, shape) { + var paths = shape.paths || []; + for (var i = 0; i < paths.length; i++) { + paths[i].buildPath(ctx, paths[i].shape, true); + } + }; + CompoundPath.prototype.afterBrush = function () { + var paths = this.shape.paths || []; + for (var i = 0; i < paths.length; i++) { + paths[i].pathUpdated(); + } + }; + CompoundPath.prototype.getBoundingRect = function () { + this._updatePathDirty.call(this); + return Path.prototype.getBoundingRect.call(this); + }; + return CompoundPath; + }(Path)); + + var Gradient = (function () { + function Gradient(colorStops) { + this.colorStops = colorStops || []; + } + Gradient.prototype.addColorStop = function (offset, color) { + this.colorStops.push({ + offset: offset, + color: color + }); + }; + return Gradient; + }()); + + var LinearGradient = (function (_super) { + __extends(LinearGradient, _super); + function LinearGradient(x, y, x2, y2, colorStops, globalCoord) { + var _this = _super.call(this, colorStops) || this; + _this.x = x == null ? 0 : x; + _this.y = y == null ? 0 : y; + _this.x2 = x2 == null ? 1 : x2; + _this.y2 = y2 == null ? 0 : y2; + _this.type = 'linear'; + _this.global = globalCoord || false; + return _this; + } + return LinearGradient; + }(Gradient)); + + var RadialGradient = (function (_super) { + __extends(RadialGradient, _super); + function RadialGradient(x, y, r, colorStops, globalCoord) { + var _this = _super.call(this, colorStops) || this; + _this.x = x == null ? 0.5 : x; + _this.y = y == null ? 0.5 : y; + _this.r = r == null ? 0.5 : r; + _this.type = 'radial'; + _this.global = globalCoord || false; + return _this; + } + return RadialGradient; + }(Gradient)); + + var extent = [0, 0]; + var extent2 = [0, 0]; + var minTv$1 = new Point(); + var maxTv$1 = new Point(); + var OrientedBoundingRect = (function () { + function OrientedBoundingRect(rect, transform) { + this._corners = []; + this._axes = []; + this._origin = [0, 0]; + for (var i = 0; i < 4; i++) { + this._corners[i] = new Point(); + } + for (var i = 0; i < 2; i++) { + this._axes[i] = new Point(); + } + if (rect) { + this.fromBoundingRect(rect, transform); + } + } + OrientedBoundingRect.prototype.fromBoundingRect = function (rect, transform) { + var corners = this._corners; + var axes = this._axes; + var x = rect.x; + var y = rect.y; + var x2 = x + rect.width; + var y2 = y + rect.height; + corners[0].set(x, y); + corners[1].set(x2, y); + corners[2].set(x2, y2); + corners[3].set(x, y2); + if (transform) { + for (var i = 0; i < 4; i++) { + corners[i].transform(transform); + } + } + Point.sub(axes[0], corners[1], corners[0]); + Point.sub(axes[1], corners[3], corners[0]); + axes[0].normalize(); + axes[1].normalize(); + for (var i = 0; i < 2; i++) { + this._origin[i] = axes[i].dot(corners[0]); + } + }; + OrientedBoundingRect.prototype.intersect = function (other, mtv) { + var overlapped = true; + var noMtv = !mtv; + minTv$1.set(Infinity, Infinity); + maxTv$1.set(0, 0); + if (!this._intersectCheckOneSide(this, other, minTv$1, maxTv$1, noMtv, 1)) { + overlapped = false; + if (noMtv) { + return overlapped; + } + } + if (!this._intersectCheckOneSide(other, this, minTv$1, maxTv$1, noMtv, -1)) { + overlapped = false; + if (noMtv) { + return overlapped; + } + } + if (!noMtv) { + Point.copy(mtv, overlapped ? minTv$1 : maxTv$1); + } + return overlapped; + }; + OrientedBoundingRect.prototype._intersectCheckOneSide = function (self, other, minTv, maxTv, noMtv, inverse) { + var overlapped = true; + for (var i = 0; i < 2; i++) { + var axis = this._axes[i]; + this._getProjMinMaxOnAxis(i, self._corners, extent); + this._getProjMinMaxOnAxis(i, other._corners, extent2); + if (extent[1] < extent2[0] || extent[0] > extent2[1]) { + overlapped = false; + if (noMtv) { + return overlapped; + } + var dist0 = Math.abs(extent2[0] - extent[1]); + var dist1 = Math.abs(extent[0] - extent2[1]); + if (Math.min(dist0, dist1) > maxTv.len()) { + if (dist0 < dist1) { + Point.scale(maxTv, axis, -dist0 * inverse); + } + else { + Point.scale(maxTv, axis, dist1 * inverse); + } + } + } + else if (minTv) { + var dist0 = Math.abs(extent2[0] - extent[1]); + var dist1 = Math.abs(extent[0] - extent2[1]); + if (Math.min(dist0, dist1) < minTv.len()) { + if (dist0 < dist1) { + Point.scale(minTv, axis, dist0 * inverse); + } + else { + Point.scale(minTv, axis, -dist1 * inverse); + } + } + } + } + return overlapped; + }; + OrientedBoundingRect.prototype._getProjMinMaxOnAxis = function (dim, corners, out) { + var axis = this._axes[dim]; + var origin = this._origin; + var proj = corners[0].dot(axis) + origin[dim]; + var min = proj; + var max = proj; + for (var i = 1; i < corners.length; i++) { + var proj_1 = corners[i].dot(axis) + origin[dim]; + min = Math.min(proj_1, min); + max = Math.max(proj_1, max); + } + out[0] = min; + out[1] = max; + }; + return OrientedBoundingRect; + }()); + + var m = []; + var IncrementalDisplayable = (function (_super) { + __extends(IncrementalDisplayable, _super); + function IncrementalDisplayable() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.notClear = true; + _this.incremental = true; + _this._displayables = []; + _this._temporaryDisplayables = []; + _this._cursor = 0; + return _this; + } + IncrementalDisplayable.prototype.traverse = function (cb, context) { + cb.call(context, this); + }; + IncrementalDisplayable.prototype.useStyle = function () { + this.style = {}; + }; + IncrementalDisplayable.prototype.getCursor = function () { + return this._cursor; + }; + IncrementalDisplayable.prototype.innerAfterBrush = function () { + this._cursor = this._displayables.length; + }; + IncrementalDisplayable.prototype.clearDisplaybles = function () { + this._displayables = []; + this._temporaryDisplayables = []; + this._cursor = 0; + this.markRedraw(); + this.notClear = false; + }; + IncrementalDisplayable.prototype.clearTemporalDisplayables = function () { + this._temporaryDisplayables = []; + }; + IncrementalDisplayable.prototype.addDisplayable = function (displayable, notPersistent) { + if (notPersistent) { + this._temporaryDisplayables.push(displayable); + } + else { + this._displayables.push(displayable); + } + this.markRedraw(); + }; + IncrementalDisplayable.prototype.addDisplayables = function (displayables, notPersistent) { + notPersistent = notPersistent || false; + for (var i = 0; i < displayables.length; i++) { + this.addDisplayable(displayables[i], notPersistent); + } + }; + IncrementalDisplayable.prototype.getDisplayables = function () { + return this._displayables; + }; + IncrementalDisplayable.prototype.getTemporalDisplayables = function () { + return this._temporaryDisplayables; + }; + IncrementalDisplayable.prototype.eachPendingDisplayable = function (cb) { + for (var i = this._cursor; i < this._displayables.length; i++) { + cb && cb(this._displayables[i]); + } + for (var i = 0; i < this._temporaryDisplayables.length; i++) { + cb && cb(this._temporaryDisplayables[i]); + } + }; + IncrementalDisplayable.prototype.update = function () { + this.updateTransform(); + for (var i = this._cursor; i < this._displayables.length; i++) { + var displayable = this._displayables[i]; + displayable.parent = this; + displayable.update(); + displayable.parent = null; + } + for (var i = 0; i < this._temporaryDisplayables.length; i++) { + var displayable = this._temporaryDisplayables[i]; + displayable.parent = this; + displayable.update(); + displayable.parent = null; + } + }; + IncrementalDisplayable.prototype.getBoundingRect = function () { + if (!this._rect) { + var rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity); + for (var i = 0; i < this._displayables.length; i++) { + var displayable = this._displayables[i]; + var childRect = displayable.getBoundingRect().clone(); + if (displayable.needLocalTransform()) { + childRect.applyTransform(displayable.getLocalTransform(m)); + } + rect.union(childRect); + } + this._rect = rect; + } + return this._rect; + }; + IncrementalDisplayable.prototype.contain = function (x, y) { + var localPos = this.transformCoordToLocal(x, y); + var rect = this.getBoundingRect(); + if (rect.contain(localPos[0], localPos[1])) { + for (var i = 0; i < this._displayables.length; i++) { + var displayable = this._displayables[i]; + if (displayable.contain(x, y)) { + return true; + } + } + } + return false; + }; + return IncrementalDisplayable; + }(Displayable)); + + var transitionStore = makeInner(); + /** + * Return null if animation is disabled. + */ + + function getAnimationConfig(animationType, animatableModel, dataIndex, // Extra opts can override the option in animatable model. + extraOpts, // TODO It's only for pictorial bar now. + extraDelayParams) { + var animationPayload; // Check if there is global animation configuration from dataZoom/resize can override the config in option. + // If animation is enabled. Will use this animation config in payload. + // If animation is disabled. Just ignore it. + + if (animatableModel && animatableModel.ecModel) { + var updatePayload = animatableModel.ecModel.getUpdatePayload(); + animationPayload = updatePayload && updatePayload.animation; + } + + var animationEnabled = animatableModel && animatableModel.isAnimationEnabled(); + var isUpdate = animationType === 'update'; + + if (animationEnabled) { + var duration = void 0; + var easing = void 0; + var delay = void 0; + + if (extraOpts) { + duration = retrieve2(extraOpts.duration, 200); + easing = retrieve2(extraOpts.easing, 'cubicOut'); + delay = 0; + } else { + duration = animatableModel.getShallow(isUpdate ? 'animationDurationUpdate' : 'animationDuration'); + easing = animatableModel.getShallow(isUpdate ? 'animationEasingUpdate' : 'animationEasing'); + delay = animatableModel.getShallow(isUpdate ? 'animationDelayUpdate' : 'animationDelay'); + } // animation from payload has highest priority. + + + if (animationPayload) { + animationPayload.duration != null && (duration = animationPayload.duration); + animationPayload.easing != null && (easing = animationPayload.easing); + animationPayload.delay != null && (delay = animationPayload.delay); + } + + if (isFunction(delay)) { + delay = delay(dataIndex, extraDelayParams); + } + + if (isFunction(duration)) { + duration = duration(dataIndex); + } + + var config = { + duration: duration || 0, + delay: delay, + easing: easing + }; + return config; + } else { + return null; + } + } + + function animateOrSetProps(animationType, el, props, animatableModel, dataIndex, cb, during) { + var isFrom = false; + var removeOpt; + + if (isFunction(dataIndex)) { + during = cb; + cb = dataIndex; + dataIndex = null; + } else if (isObject(dataIndex)) { + cb = dataIndex.cb; + during = dataIndex.during; + isFrom = dataIndex.isFrom; + removeOpt = dataIndex.removeOpt; + dataIndex = dataIndex.dataIndex; + } + + var isRemove = animationType === 'leave'; + + if (!isRemove) { + // Must stop the remove animation. + el.stopAnimation('leave'); + } + + var animationConfig = getAnimationConfig(animationType, animatableModel, dataIndex, isRemove ? removeOpt || {} : null, animatableModel && animatableModel.getAnimationDelayParams ? animatableModel.getAnimationDelayParams(el, dataIndex) : null); + + if (animationConfig && animationConfig.duration > 0) { + var duration = animationConfig.duration; + var animationDelay = animationConfig.delay; + var animationEasing = animationConfig.easing; + var animateConfig = { + duration: duration, + delay: animationDelay || 0, + easing: animationEasing, + done: cb, + force: !!cb || !!during, + // Set to final state in update/init animation. + // So the post processing based on the path shape can be done correctly. + setToFinal: !isRemove, + scope: animationType, + during: during + }; + isFrom ? el.animateFrom(props, animateConfig) : el.animateTo(props, animateConfig); + } else { + el.stopAnimation(); // If `isFrom`, the props is the "from" props. + + !isFrom && el.attr(props); // Call during at least once. + + during && during(1); + cb && cb(); + } + } + /** + * Update graphic element properties with or without animation according to the + * configuration in series. + * + * Caution: this method will stop previous animation. + * So do not use this method to one element twice before + * animation starts, unless you know what you are doing. + * @example + * graphic.updateProps(el, { + * position: [100, 100] + * }, seriesModel, dataIndex, function () { console.log('Animation done!'); }); + * // Or + * graphic.updateProps(el, { + * position: [100, 100] + * }, seriesModel, function () { console.log('Animation done!'); }); + */ + + + function updateProps(el, props, // TODO: TYPE AnimatableModel + animatableModel, dataIndex, cb, during) { + animateOrSetProps('update', el, props, animatableModel, dataIndex, cb, during); + } + /** + * Init graphic element properties with or without animation according to the + * configuration in series. + * + * Caution: this method will stop previous animation. + * So do not use this method to one element twice before + * animation starts, unless you know what you are doing. + */ + + function initProps(el, props, animatableModel, dataIndex, cb, during) { + animateOrSetProps('enter', el, props, animatableModel, dataIndex, cb, during); + } + /** + * If element is removed. + * It can determine if element is having remove animation. + */ + + function isElementRemoved(el) { + if (!el.__zr) { + return true; + } + + for (var i = 0; i < el.animators.length; i++) { + var animator = el.animators[i]; + + if (animator.scope === 'leave') { + return true; + } + } + + return false; + } + /** + * Remove graphic element + */ + + function removeElement(el, props, animatableModel, dataIndex, cb, during) { + // Don't do remove animation twice. + if (isElementRemoved(el)) { + return; + } + + animateOrSetProps('leave', el, props, animatableModel, dataIndex, cb, during); + } + + function fadeOutDisplayable(el, animatableModel, dataIndex, done) { + el.removeTextContent(); + el.removeTextGuideLine(); + removeElement(el, { + style: { + opacity: 0 + } + }, animatableModel, dataIndex, done); + } + + function removeElementWithFadeOut(el, animatableModel, dataIndex) { + function doRemove() { + el.parent && el.parent.remove(el); + } // Hide label and labelLine first + // TODO Also use fade out animation? + + + if (!el.isGroup) { + fadeOutDisplayable(el, animatableModel, dataIndex, doRemove); + } else { + el.traverse(function (disp) { + if (!disp.isGroup) { + // Can invoke doRemove multiple times. + fadeOutDisplayable(disp, animatableModel, dataIndex, doRemove); + } + }); + } + } + /** + * Save old style for style transition in universalTransition module. + * It's used when element will be reused in each render. + * For chart like map, heatmap, which will always create new element. + * We don't need to save this because universalTransition can get old style from the old element + */ + + function saveOldStyle(el) { + transitionStore(el).oldStyle = el.style; + } + function getOldStyle(el) { + return transitionStore(el).oldStyle; + } + + var mathMax$4 = Math.max; + var mathMin$4 = Math.min; + var _customShapeMap = {}; + /** + * Extend shape with parameters + */ + + function extendShape(opts) { + return Path.extend(opts); + } + var extendPathFromString = extendFromString; + /** + * Extend path + */ + + function extendPath(pathData, opts) { + return extendPathFromString(pathData, opts); + } + /** + * Register a user defined shape. + * The shape class can be fetched by `getShapeClass` + * This method will overwrite the registered shapes, including + * the registered built-in shapes, if using the same `name`. + * The shape can be used in `custom series` and + * `graphic component` by declaring `{type: name}`. + * + * @param name + * @param ShapeClass Can be generated by `extendShape`. + */ + + function registerShape(name, ShapeClass) { + _customShapeMap[name] = ShapeClass; + } + /** + * Find shape class registered by `registerShape`. Usually used in + * fetching user defined shape. + * + * [Caution]: + * (1) This method **MUST NOT be used inside echarts !!!**, unless it is prepared + * to use user registered shapes. + * Because the built-in shape (see `getBuiltInShape`) will be registered by + * `registerShape` by default. That enables users to get both built-in + * shapes as well as the shapes belonging to themsleves. But users can overwrite + * the built-in shapes by using names like 'circle', 'rect' via calling + * `registerShape`. So the echarts inner featrues should not fetch shapes from here + * in case that it is overwritten by users, except that some features, like + * `custom series`, `graphic component`, do it deliberately. + * + * (2) In the features like `custom series`, `graphic component`, the user input + * `{tpye: 'xxx'}` does not only specify shapes but also specify other graphic + * elements like `'group'`, `'text'`, `'image'` or event `'path'`. Those names + * are reserved names, that is, if some user register a shape named `'image'`, + * the shape will not be used. If we intending to add some more reserved names + * in feature, that might bring break changes (disable some existing user shape + * names). But that case probably rearly happen. So we dont make more mechanism + * to resolve this issue here. + * + * @param name + * @return The shape class. If not found, return nothing. + */ + + function getShapeClass(name) { + if (_customShapeMap.hasOwnProperty(name)) { + return _customShapeMap[name]; + } + } + /** + * Create a path element from path data string + * @param pathData + * @param opts + * @param rect + * @param layout 'center' or 'cover' default to be cover + */ + + function makePath(pathData, opts, rect, layout) { + var path = createFromString(pathData, opts); + + if (rect) { + if (layout === 'center') { + rect = centerGraphic(rect, path.getBoundingRect()); + } + + resizePath(path, rect); + } + + return path; + } + /** + * Create a image element from image url + * @param imageUrl image url + * @param opts options + * @param rect constrain rect + * @param layout 'center' or 'cover'. Default to be 'cover' + */ + + function makeImage(imageUrl, rect, layout) { + var zrImg = new ZRImage({ + style: { + image: imageUrl, + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height + }, + onload: function (img) { + if (layout === 'center') { + var boundingRect = { + width: img.width, + height: img.height + }; + zrImg.setStyle(centerGraphic(rect, boundingRect)); + } + } + }); + return zrImg; + } + /** + * Get position of centered element in bounding box. + * + * @param rect element local bounding box + * @param boundingRect constraint bounding box + * @return element position containing x, y, width, and height + */ + + function centerGraphic(rect, boundingRect) { + // Set rect to center, keep width / height ratio. + var aspect = boundingRect.width / boundingRect.height; + var width = rect.height * aspect; + var height; + + if (width <= rect.width) { + height = rect.height; + } else { + width = rect.width; + height = width / aspect; + } + + var cx = rect.x + rect.width / 2; + var cy = rect.y + rect.height / 2; + return { + x: cx - width / 2, + y: cy - height / 2, + width: width, + height: height + }; + } + + var mergePath$1 = mergePath; + /** + * Resize a path to fit the rect + * @param path + * @param rect + */ + + function resizePath(path, rect) { + if (!path.applyTransform) { + return; + } + + var pathRect = path.getBoundingRect(); + var m = pathRect.calculateTransform(rect); + path.applyTransform(m); + } + /** + * Sub pixel optimize line for canvas + */ + + function subPixelOptimizeLine$1(param) { + subPixelOptimizeLine(param.shape, param.shape, param.style); + return param; + } + /** + * Sub pixel optimize rect for canvas + */ + + function subPixelOptimizeRect$1(param) { + subPixelOptimizeRect(param.shape, param.shape, param.style); + return param; + } + /** + * Sub pixel optimize for canvas + * + * @param position Coordinate, such as x, y + * @param lineWidth Should be nonnegative integer. + * @param positiveOrNegative Default false (negative). + * @return Optimized position. + */ + + var subPixelOptimize$1 = subPixelOptimize; + /** + * Get transform matrix of target (param target), + * in coordinate of its ancestor (param ancestor) + * + * @param target + * @param [ancestor] + */ + + function getTransform(target, ancestor) { + var mat = identity([]); + + while (target && target !== ancestor) { + mul$1(mat, target.getLocalTransform(), mat); + target = target.parent; + } + + return mat; + } + /** + * Apply transform to an vertex. + * @param target [x, y] + * @param transform Can be: + * + Transform matrix: like [1, 0, 0, 1, 0, 0] + * + {position, rotation, scale}, the same as `zrender/Transformable`. + * @param invert Whether use invert matrix. + * @return [x, y] + */ + + function applyTransform$1(target, transform, invert$1) { + if (transform && !isArrayLike(transform)) { + transform = Transformable.getLocalTransform(transform); + } + + if (invert$1) { + transform = invert([], transform); + } + + return applyTransform([], target, transform); + } + /** + * @param direction 'left' 'right' 'top' 'bottom' + * @param transform Transform matrix: like [1, 0, 0, 1, 0, 0] + * @param invert Whether use invert matrix. + * @return Transformed direction. 'left' 'right' 'top' 'bottom' + */ + + function transformDirection(direction, transform, invert) { + // Pick a base, ensure that transform result will not be (0, 0). + var hBase = transform[4] === 0 || transform[5] === 0 || transform[0] === 0 ? 1 : Math.abs(2 * transform[4] / transform[0]); + var vBase = transform[4] === 0 || transform[5] === 0 || transform[2] === 0 ? 1 : Math.abs(2 * transform[4] / transform[2]); + var vertex = [direction === 'left' ? -hBase : direction === 'right' ? hBase : 0, direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0]; + vertex = applyTransform$1(vertex, transform, invert); + return Math.abs(vertex[0]) > Math.abs(vertex[1]) ? vertex[0] > 0 ? 'right' : 'left' : vertex[1] > 0 ? 'bottom' : 'top'; + } + + function isNotGroup(el) { + return !el.isGroup; + } + + function isPath(el) { + return el.shape != null; + } + /** + * Apply group transition animation from g1 to g2. + * If no animatableModel, no animation. + */ + + + function groupTransition(g1, g2, animatableModel) { + if (!g1 || !g2) { + return; + } + + function getElMap(g) { + var elMap = {}; + g.traverse(function (el) { + if (isNotGroup(el) && el.anid) { + elMap[el.anid] = el; + } + }); + return elMap; + } + + function getAnimatableProps(el) { + var obj = { + x: el.x, + y: el.y, + rotation: el.rotation + }; + + if (isPath(el)) { + obj.shape = extend({}, el.shape); + } + + return obj; + } + + var elMap1 = getElMap(g1); + g2.traverse(function (el) { + if (isNotGroup(el) && el.anid) { + var oldEl = elMap1[el.anid]; + + if (oldEl) { + var newProp = getAnimatableProps(el); + el.attr(getAnimatableProps(oldEl)); + updateProps(el, newProp, animatableModel, getECData(el).dataIndex); + } + } + }); + } + function clipPointsByRect(points, rect) { + // FIXME: this way migth be incorrect when grpahic clipped by a corner. + // and when element have border. + return map(points, function (point) { + var x = point[0]; + x = mathMax$4(x, rect.x); + x = mathMin$4(x, rect.x + rect.width); + var y = point[1]; + y = mathMax$4(y, rect.y); + y = mathMin$4(y, rect.y + rect.height); + return [x, y]; + }); + } + /** + * Return a new clipped rect. If rect size are negative, return undefined. + */ + + function clipRectByRect(targetRect, rect) { + var x = mathMax$4(targetRect.x, rect.x); + var x2 = mathMin$4(targetRect.x + targetRect.width, rect.x + rect.width); + var y = mathMax$4(targetRect.y, rect.y); + var y2 = mathMin$4(targetRect.y + targetRect.height, rect.y + rect.height); // If the total rect is cliped, nothing, including the border, + // should be painted. So return undefined. + + if (x2 >= x && y2 >= y) { + return { + x: x, + y: y, + width: x2 - x, + height: y2 - y + }; + } + } + function createIcon(iconStr, // Support 'image://' or 'path://' or direct svg path. + opt, rect) { + var innerOpts = extend({ + rectHover: true + }, opt); + var style = innerOpts.style = { + strokeNoScale: true + }; + rect = rect || { + x: -1, + y: -1, + width: 2, + height: 2 + }; + + if (iconStr) { + return iconStr.indexOf('image://') === 0 ? (style.image = iconStr.slice(8), defaults(style, rect), new ZRImage(innerOpts)) : makePath(iconStr.replace('path://', ''), innerOpts, rect, 'center'); + } + } + /** + * Return `true` if the given line (line `a`) and the given polygon + * are intersect. + * Note that we do not count colinear as intersect here because no + * requirement for that. We could do that if required in future. + */ + + function linePolygonIntersect(a1x, a1y, a2x, a2y, points) { + for (var i = 0, p2 = points[points.length - 1]; i < points.length; i++) { + var p = points[i]; + + if (lineLineIntersect(a1x, a1y, a2x, a2y, p[0], p[1], p2[0], p2[1])) { + return true; + } + + p2 = p; + } + } + /** + * Return `true` if the given two lines (line `a` and line `b`) + * are intersect. + * Note that we do not count colinear as intersect here because no + * requirement for that. We could do that if required in future. + */ + + function lineLineIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) { + // let `vec_m` to be `vec_a2 - vec_a1` and `vec_n` to be `vec_b2 - vec_b1`. + var mx = a2x - a1x; + var my = a2y - a1y; + var nx = b2x - b1x; + var ny = b2y - b1y; // `vec_m` and `vec_n` are parallel iff + // exising `k` such that `vec_m = k · vec_n`, equivalent to `vec_m X vec_n = 0`. + + var nmCrossProduct = crossProduct2d(nx, ny, mx, my); + + if (nearZero(nmCrossProduct)) { + return false; + } // `vec_m` and `vec_n` are intersect iff + // existing `p` and `q` in [0, 1] such that `vec_a1 + p * vec_m = vec_b1 + q * vec_n`, + // such that `q = ((vec_a1 - vec_b1) X vec_m) / (vec_n X vec_m)` + // and `p = ((vec_a1 - vec_b1) X vec_n) / (vec_n X vec_m)`. + + + var b1a1x = a1x - b1x; + var b1a1y = a1y - b1y; + var q = crossProduct2d(b1a1x, b1a1y, mx, my) / nmCrossProduct; + + if (q < 0 || q > 1) { + return false; + } + + var p = crossProduct2d(b1a1x, b1a1y, nx, ny) / nmCrossProduct; + + if (p < 0 || p > 1) { + return false; + } + + return true; + } + /** + * Cross product of 2-dimension vector. + */ + + function crossProduct2d(x1, y1, x2, y2) { + return x1 * y2 - x2 * y1; + } + + function nearZero(val) { + return val <= 1e-6 && val >= -1e-6; + } + + function setTooltipConfig(opt) { + var itemTooltipOption = opt.itemTooltipOption; + var componentModel = opt.componentModel; + var itemName = opt.itemName; + var itemTooltipOptionObj = isString(itemTooltipOption) ? { + formatter: itemTooltipOption + } : itemTooltipOption; + var mainType = componentModel.mainType; + var componentIndex = componentModel.componentIndex; + var formatterParams = { + componentType: mainType, + name: itemName, + $vars: ['name'] + }; + formatterParams[mainType + 'Index'] = componentIndex; + var formatterParamsExtra = opt.formatterParamsExtra; + + if (formatterParamsExtra) { + each(keys(formatterParamsExtra), function (key) { + if (!hasOwn(formatterParams, key)) { + formatterParams[key] = formatterParamsExtra[key]; + formatterParams.$vars.push(key); + } + }); + } + + var ecData = getECData(opt.el); + ecData.componentMainType = mainType; + ecData.componentIndex = componentIndex; + ecData.tooltipConfig = { + name: itemName, + option: defaults({ + content: itemName, + formatterParams: formatterParams + }, itemTooltipOptionObj) + }; + } + + function traverseElement(el, cb) { + var stopped; // TODO + // Polyfill for fixing zrender group traverse don't visit it's root issue. + + if (el.isGroup) { + stopped = cb(el); + } + + if (!stopped) { + el.traverse(cb); + } + } + + function traverseElements(els, cb) { + if (els) { + if (isArray(els)) { + for (var i = 0; i < els.length; i++) { + traverseElement(els[i], cb); + } + } else { + traverseElement(els, cb); + } + } + } // Register built-in shapes. These shapes might be overwirtten + // by users, although we do not recommend that. + + registerShape('circle', Circle); + registerShape('ellipse', Ellipse); + registerShape('sector', Sector); + registerShape('ring', Ring); + registerShape('polygon', Polygon); + registerShape('polyline', Polyline); + registerShape('rect', Rect); + registerShape('line', Line); + registerShape('bezierCurve', BezierCurve); + registerShape('arc', Arc); + + var graphic = /*#__PURE__*/Object.freeze({ + __proto__: null, + updateProps: updateProps, + initProps: initProps, + removeElement: removeElement, + removeElementWithFadeOut: removeElementWithFadeOut, + isElementRemoved: isElementRemoved, + extendShape: extendShape, + extendPath: extendPath, + registerShape: registerShape, + getShapeClass: getShapeClass, + makePath: makePath, + makeImage: makeImage, + mergePath: mergePath$1, + resizePath: resizePath, + subPixelOptimizeLine: subPixelOptimizeLine$1, + subPixelOptimizeRect: subPixelOptimizeRect$1, + subPixelOptimize: subPixelOptimize$1, + getTransform: getTransform, + applyTransform: applyTransform$1, + transformDirection: transformDirection, + groupTransition: groupTransition, + clipPointsByRect: clipPointsByRect, + clipRectByRect: clipRectByRect, + createIcon: createIcon, + linePolygonIntersect: linePolygonIntersect, + lineLineIntersect: lineLineIntersect, + setTooltipConfig: setTooltipConfig, + traverseElements: traverseElements, + Group: Group, + Image: ZRImage, + Text: ZRText, + Circle: Circle, + Ellipse: Ellipse, + Sector: Sector, + Ring: Ring, + Polygon: Polygon, + Polyline: Polyline, + Rect: Rect, + Line: Line, + BezierCurve: BezierCurve, + Arc: Arc, + IncrementalDisplayable: IncrementalDisplayable, + CompoundPath: CompoundPath, + LinearGradient: LinearGradient, + RadialGradient: RadialGradient, + BoundingRect: BoundingRect, + OrientedBoundingRect: OrientedBoundingRect, + Point: Point, + Path: Path + }); + + var EMPTY_OBJ = {}; + function setLabelText(label, labelTexts) { + for (var i = 0; i < SPECIAL_STATES.length; i++) { + var stateName = SPECIAL_STATES[i]; + var text = labelTexts[stateName]; + var state = label.ensureState(stateName); + state.style = state.style || {}; + state.style.text = text; + } + + var oldStates = label.currentStates.slice(); + label.clearStates(true); + label.setStyle({ + text: labelTexts.normal + }); + label.useStates(oldStates, true); + } + + function getLabelText(opt, stateModels, interpolatedValue) { + var labelFetcher = opt.labelFetcher; + var labelDataIndex = opt.labelDataIndex; + var labelDimIndex = opt.labelDimIndex; + var normalModel = stateModels.normal; + var baseText; + + if (labelFetcher) { + baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex, normalModel && normalModel.get('formatter'), interpolatedValue != null ? { + interpolatedValue: interpolatedValue + } : null); + } + + if (baseText == null) { + baseText = isFunction(opt.defaultText) ? opt.defaultText(labelDataIndex, opt, interpolatedValue) : opt.defaultText; + } + + var statesText = { + normal: baseText + }; + + for (var i = 0; i < SPECIAL_STATES.length; i++) { + var stateName = SPECIAL_STATES[i]; + var stateModel = stateModels[stateName]; + statesText[stateName] = retrieve2(labelFetcher ? labelFetcher.getFormattedLabel(labelDataIndex, stateName, null, labelDimIndex, stateModel && stateModel.get('formatter')) : null, baseText); + } + + return statesText; + } + + function setLabelStyle(targetEl, labelStatesModels, opt, stateSpecified // TODO specified position? + ) { + opt = opt || EMPTY_OBJ; + var isSetOnText = targetEl instanceof ZRText; + var needsCreateText = false; + + for (var i = 0; i < DISPLAY_STATES.length; i++) { + var stateModel = labelStatesModels[DISPLAY_STATES[i]]; + + if (stateModel && stateModel.getShallow('show')) { + needsCreateText = true; + break; + } + } + + var textContent = isSetOnText ? targetEl : targetEl.getTextContent(); + + if (needsCreateText) { + if (!isSetOnText) { + // Reuse the previous + if (!textContent) { + textContent = new ZRText(); + targetEl.setTextContent(textContent); + } // Use same state proxy + + + if (targetEl.stateProxy) { + textContent.stateProxy = targetEl.stateProxy; + } + } + + var labelStatesTexts = getLabelText(opt, labelStatesModels); + var normalModel = labelStatesModels.normal; + var showNormal = !!normalModel.getShallow('show'); + var normalStyle = createTextStyle(normalModel, stateSpecified && stateSpecified.normal, opt, false, !isSetOnText); + normalStyle.text = labelStatesTexts.normal; + + if (!isSetOnText) { + // Always create new + targetEl.setTextConfig(createTextConfig(normalModel, opt, false)); + } + + for (var i = 0; i < SPECIAL_STATES.length; i++) { + var stateName = SPECIAL_STATES[i]; + var stateModel = labelStatesModels[stateName]; + + if (stateModel) { + var stateObj = textContent.ensureState(stateName); + var stateShow = !!retrieve2(stateModel.getShallow('show'), showNormal); + + if (stateShow !== showNormal) { + stateObj.ignore = !stateShow; + } + + stateObj.style = createTextStyle(stateModel, stateSpecified && stateSpecified[stateName], opt, true, !isSetOnText); + stateObj.style.text = labelStatesTexts[stateName]; + + if (!isSetOnText) { + var targetElEmphasisState = targetEl.ensureState(stateName); + targetElEmphasisState.textConfig = createTextConfig(stateModel, opt, true); + } + } + } // PENDING: if there is many requirements that emphasis position + // need to be different from normal position, we might consider + // auto slient is those cases. + + + textContent.silent = !!normalModel.getShallow('silent'); // Keep x and y + + if (textContent.style.x != null) { + normalStyle.x = textContent.style.x; + } + + if (textContent.style.y != null) { + normalStyle.y = textContent.style.y; + } + + textContent.ignore = !showNormal; // Always create new style. + + textContent.useStyle(normalStyle); + textContent.dirty(); + + if (opt.enableTextSetter) { + labelInner(textContent).setLabelText = function (interpolatedValue) { + var labelStatesTexts = getLabelText(opt, labelStatesModels, interpolatedValue); + setLabelText(textContent, labelStatesTexts); + }; + } + } else if (textContent) { + // Not display rich text. + textContent.ignore = true; + } + + targetEl.dirty(); + } + function getLabelStatesModels(itemModel, labelName) { + labelName = labelName || 'label'; + var statesModels = { + normal: itemModel.getModel(labelName) + }; + + for (var i = 0; i < SPECIAL_STATES.length; i++) { + var stateName = SPECIAL_STATES[i]; + statesModels[stateName] = itemModel.getModel([stateName, labelName]); + } + + return statesModels; + } + /** + * Set basic textStyle properties. + */ + + function createTextStyle(textStyleModel, specifiedTextStyle, // Fixed style in the code. Can't be set by model. + opt, isNotNormal, isAttached // If text is attached on an element. If so, auto color will handling in zrender. + ) { + var textStyle = {}; + setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached); + specifiedTextStyle && extend(textStyle, specifiedTextStyle); // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false); + + return textStyle; + } + function createTextConfig(textStyleModel, opt, isNotNormal) { + opt = opt || {}; + var textConfig = {}; + var labelPosition; + var labelRotate = textStyleModel.getShallow('rotate'); + var labelDistance = retrieve2(textStyleModel.getShallow('distance'), isNotNormal ? null : 5); + var labelOffset = textStyleModel.getShallow('offset'); + labelPosition = textStyleModel.getShallow('position') || (isNotNormal ? null : 'inside'); // 'outside' is not a valid zr textPostion value, but used + // in bar series, and magric type should be considered. + + labelPosition === 'outside' && (labelPosition = opt.defaultOutsidePosition || 'top'); + + if (labelPosition != null) { + textConfig.position = labelPosition; + } + + if (labelOffset != null) { + textConfig.offset = labelOffset; + } + + if (labelRotate != null) { + labelRotate *= Math.PI / 180; + textConfig.rotation = labelRotate; + } + + if (labelDistance != null) { + textConfig.distance = labelDistance; + } // fill and auto is determined by the color of path fill if it's not specified by developers. + + + textConfig.outsideFill = textStyleModel.get('color') === 'inherit' ? opt.inheritColor || null : 'auto'; + return textConfig; + } + /** + * The uniform entry of set text style, that is, retrieve style definitions + * from `model` and set to `textStyle` object. + * + * Never in merge mode, but in overwrite mode, that is, all of the text style + * properties will be set. (Consider the states of normal and emphasis and + * default value can be adopted, merge would make the logic too complicated + * to manage.) + */ + + function setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached) { + // Consider there will be abnormal when merge hover style to normal style if given default value. + opt = opt || EMPTY_OBJ; + var ecModel = textStyleModel.ecModel; + var globalTextStyle = ecModel && ecModel.option.textStyle; // Consider case: + // { + // data: [{ + // value: 12, + // label: { + // rich: { + // // no 'a' here but using parent 'a'. + // } + // } + // }], + // rich: { + // a: { ... } + // } + // } + + var richItemNames = getRichItemNames(textStyleModel); + var richResult; + + if (richItemNames) { + richResult = {}; + + for (var name_1 in richItemNames) { + if (richItemNames.hasOwnProperty(name_1)) { + // Cascade is supported in rich. + var richTextStyle = textStyleModel.getModel(['rich', name_1]); // In rich, never `disableBox`. + // FIXME: consider `label: {formatter: '{a|xx}', color: 'blue', rich: {a: {}}}`, + // the default color `'blue'` will not be adopted if no color declared in `rich`. + // That might confuses users. So probably we should put `textStyleModel` as the + // root ancestor of the `richTextStyle`. But that would be a break change. + + setTokenTextStyle(richResult[name_1] = {}, richTextStyle, globalTextStyle, opt, isNotNormal, isAttached, false, true); + } + } + } + + if (richResult) { + textStyle.rich = richResult; + } + + var overflow = textStyleModel.get('overflow'); + + if (overflow) { + textStyle.overflow = overflow; + } + + var margin = textStyleModel.get('minMargin'); + + if (margin != null) { + textStyle.margin = margin; + } + + setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isNotNormal, isAttached, true, false); + } // Consider case: + // { + // data: [{ + // value: 12, + // label: { + // rich: { + // // no 'a' here but using parent 'a'. + // } + // } + // }], + // rich: { + // a: { ... } + // } + // } + // TODO TextStyleModel + + + function getRichItemNames(textStyleModel) { + // Use object to remove duplicated names. + var richItemNameMap; + + while (textStyleModel && textStyleModel !== textStyleModel.ecModel) { + var rich = (textStyleModel.option || EMPTY_OBJ).rich; + + if (rich) { + richItemNameMap = richItemNameMap || {}; + var richKeys = keys(rich); + + for (var i = 0; i < richKeys.length; i++) { + var richKey = richKeys[i]; + richItemNameMap[richKey] = 1; + } + } + + textStyleModel = textStyleModel.parentModel; + } + + return richItemNameMap; + } + + var TEXT_PROPS_WITH_GLOBAL = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY']; + var TEXT_PROPS_SELF = ['align', 'lineHeight', 'width', 'height', 'tag', 'verticalAlign']; + var TEXT_PROPS_BOX = ['padding', 'borderWidth', 'borderRadius', 'borderDashOffset', 'backgroundColor', 'borderColor', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY']; + + function setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isNotNormal, isAttached, isBlock, inRich) { + // In merge mode, default value should not be given. + globalTextStyle = !isNotNormal && globalTextStyle || EMPTY_OBJ; + var inheritColor = opt && opt.inheritColor; + var fillColor = textStyleModel.getShallow('color'); + var strokeColor = textStyleModel.getShallow('textBorderColor'); + var opacity = retrieve2(textStyleModel.getShallow('opacity'), globalTextStyle.opacity); + + if (fillColor === 'inherit' || fillColor === 'auto') { + if ("development" !== 'production') { + if (fillColor === 'auto') { + deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\''); + } + } + + if (inheritColor) { + fillColor = inheritColor; + } else { + fillColor = null; + } + } + + if (strokeColor === 'inherit' || strokeColor === 'auto') { + if ("development" !== 'production') { + if (strokeColor === 'auto') { + deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\''); + } + } + + if (inheritColor) { + strokeColor = inheritColor; + } else { + strokeColor = null; + } + } + + if (!isAttached) { + // Only use default global textStyle.color if text is individual. + // Otherwise it will use the strategy of attached text color because text may be on a path. + fillColor = fillColor || globalTextStyle.color; + strokeColor = strokeColor || globalTextStyle.textBorderColor; + } + + if (fillColor != null) { + textStyle.fill = fillColor; + } + + if (strokeColor != null) { + textStyle.stroke = strokeColor; + } + + var textBorderWidth = retrieve2(textStyleModel.getShallow('textBorderWidth'), globalTextStyle.textBorderWidth); + + if (textBorderWidth != null) { + textStyle.lineWidth = textBorderWidth; + } + + var textBorderType = retrieve2(textStyleModel.getShallow('textBorderType'), globalTextStyle.textBorderType); + + if (textBorderType != null) { + textStyle.lineDash = textBorderType; + } + + var textBorderDashOffset = retrieve2(textStyleModel.getShallow('textBorderDashOffset'), globalTextStyle.textBorderDashOffset); + + if (textBorderDashOffset != null) { + textStyle.lineDashOffset = textBorderDashOffset; + } + + if (!isNotNormal && opacity == null && !inRich) { + opacity = opt && opt.defaultOpacity; + } + + if (opacity != null) { + textStyle.opacity = opacity; + } // TODO + + + if (!isNotNormal && !isAttached) { + // Set default finally. + if (textStyle.fill == null && opt.inheritColor) { + textStyle.fill = opt.inheritColor; + } + } // Do not use `getFont` here, because merge should be supported, where + // part of these properties may be changed in emphasis style, and the + // others should remain their original value got from normal style. + + + for (var i = 0; i < TEXT_PROPS_WITH_GLOBAL.length; i++) { + var key = TEXT_PROPS_WITH_GLOBAL[i]; + var val = retrieve2(textStyleModel.getShallow(key), globalTextStyle[key]); + + if (val != null) { + textStyle[key] = val; + } + } + + for (var i = 0; i < TEXT_PROPS_SELF.length; i++) { + var key = TEXT_PROPS_SELF[i]; + var val = textStyleModel.getShallow(key); + + if (val != null) { + textStyle[key] = val; + } + } + + if (textStyle.verticalAlign == null) { + var baseline = textStyleModel.getShallow('baseline'); + + if (baseline != null) { + textStyle.verticalAlign = baseline; + } + } + + if (!isBlock || !opt.disableBox) { + for (var i = 0; i < TEXT_PROPS_BOX.length; i++) { + var key = TEXT_PROPS_BOX[i]; + var val = textStyleModel.getShallow(key); + + if (val != null) { + textStyle[key] = val; + } + } + + var borderType = textStyleModel.getShallow('borderType'); + + if (borderType != null) { + textStyle.borderDash = borderType; + } + + if ((textStyle.backgroundColor === 'auto' || textStyle.backgroundColor === 'inherit') && inheritColor) { + if ("development" !== 'production') { + if (textStyle.backgroundColor === 'auto') { + deprecateReplaceLog('backgroundColor: \'auto\'', 'backgroundColor: \'inherit\''); + } + } + + textStyle.backgroundColor = inheritColor; + } + + if ((textStyle.borderColor === 'auto' || textStyle.borderColor === 'inherit') && inheritColor) { + if ("development" !== 'production') { + if (textStyle.borderColor === 'auto') { + deprecateReplaceLog('borderColor: \'auto\'', 'borderColor: \'inherit\''); + } + } + + textStyle.borderColor = inheritColor; + } + } + } + + function getFont(opt, ecModel) { + var gTextStyleModel = ecModel && ecModel.getModel('textStyle'); + return trim([// FIXME in node-canvas fontWeight is before fontStyle + opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '', opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '', (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px', opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'].join(' ')); + } + var labelInner = makeInner(); + function setLabelValueAnimation(label, labelStatesModels, value, getDefaultText) { + if (!label) { + return; + } + + var obj = labelInner(label); + obj.prevValue = obj.value; + obj.value = value; + var normalLabelModel = labelStatesModels.normal; + obj.valueAnimation = normalLabelModel.get('valueAnimation'); + + if (obj.valueAnimation) { + obj.precision = normalLabelModel.get('precision'); + obj.defaultInterpolatedText = getDefaultText; + obj.statesModels = labelStatesModels; + } + } + function animateLabelValue(textEl, dataIndex, data, animatableModel, labelFetcher) { + var labelInnerStore = labelInner(textEl); + + if (!labelInnerStore.valueAnimation || labelInnerStore.prevValue === labelInnerStore.value) { + // Value not changed, no new label animation + return; + } + + var defaultInterpolatedText = labelInnerStore.defaultInterpolatedText; // Consider the case that being animating, do not use the `obj.value`, + // Otherwise it will jump to the `obj.value` when this new animation started. + + var currValue = retrieve2(labelInnerStore.interpolatedValue, labelInnerStore.prevValue); + var targetValue = labelInnerStore.value; + + function during(percent) { + var interpolated = interpolateRawValues(data, labelInnerStore.precision, currValue, targetValue, percent); + labelInnerStore.interpolatedValue = percent === 1 ? null : interpolated; + var labelText = getLabelText({ + labelDataIndex: dataIndex, + labelFetcher: labelFetcher, + defaultText: defaultInterpolatedText ? defaultInterpolatedText(interpolated) : interpolated + '' + }, labelInnerStore.statesModels, interpolated); + setLabelText(textEl, labelText); + } + + textEl.percent = 0; + (labelInnerStore.prevValue == null ? initProps : updateProps)(textEl, { + // percent is used to prevent animation from being aborted #15916 + percent: 1 + }, animatableModel, dataIndex, null, during); + } + + var PATH_COLOR = ['textStyle', 'color']; + var textStyleParams = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'padding', 'lineHeight', 'rich', 'width', 'height', 'overflow']; // TODO Performance improvement? + + var tmpText = new ZRText(); + + var TextStyleMixin = + /** @class */ + function () { + function TextStyleMixin() {} + /** + * Get color property or get color from option.textStyle.color + */ + // TODO Callback + + + TextStyleMixin.prototype.getTextColor = function (isEmphasis) { + var ecModel = this.ecModel; + return this.getShallow('color') || (!isEmphasis && ecModel ? ecModel.get(PATH_COLOR) : null); + }; + /** + * Create font string from fontStyle, fontWeight, fontSize, fontFamily + * @return {string} + */ + + + TextStyleMixin.prototype.getFont = function () { + return getFont({ + fontStyle: this.getShallow('fontStyle'), + fontWeight: this.getShallow('fontWeight'), + fontSize: this.getShallow('fontSize'), + fontFamily: this.getShallow('fontFamily') + }, this.ecModel); + }; + + TextStyleMixin.prototype.getTextRect = function (text) { + var style = { + text: text, + verticalAlign: this.getShallow('verticalAlign') || this.getShallow('baseline') + }; + + for (var i = 0; i < textStyleParams.length; i++) { + style[textStyleParams[i]] = this.getShallow(textStyleParams[i]); + } + + tmpText.useStyle(style); + tmpText.update(); + return tmpText.getBoundingRect(); + }; + + return TextStyleMixin; + }(); + + var LINE_STYLE_KEY_MAP = [['lineWidth', 'width'], ['stroke', 'color'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'], ['lineDash', 'type'], ['lineDashOffset', 'dashOffset'], ['lineCap', 'cap'], ['lineJoin', 'join'], ['miterLimit'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`. + // So do not transfer decal directly. + ]; + var getLineStyle = makeStyleMapper(LINE_STYLE_KEY_MAP); + + var LineStyleMixin = + /** @class */ + function () { + function LineStyleMixin() {} + + LineStyleMixin.prototype.getLineStyle = function (excludes) { + return getLineStyle(this, excludes); + }; + + return LineStyleMixin; + }(); + + var ITEM_STYLE_KEY_MAP = [['fill', 'color'], ['stroke', 'borderColor'], ['lineWidth', 'borderWidth'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'], ['lineDash', 'borderType'], ['lineDashOffset', 'borderDashOffset'], ['lineCap', 'borderCap'], ['lineJoin', 'borderJoin'], ['miterLimit', 'borderMiterLimit'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`. + // So do not transfer decal directly. + ]; + var getItemStyle = makeStyleMapper(ITEM_STYLE_KEY_MAP); + + var ItemStyleMixin = + /** @class */ + function () { + function ItemStyleMixin() {} + + ItemStyleMixin.prototype.getItemStyle = function (excludes, includes) { + return getItemStyle(this, excludes, includes); + }; + + return ItemStyleMixin; + }(); + + var Model = + /** @class */ + function () { + function Model(option, parentModel, ecModel) { + this.parentModel = parentModel; + this.ecModel = ecModel; + this.option = option; // Simple optimization + // if (this.init) { + // if (arguments.length <= 4) { + // this.init(option, parentModel, ecModel, extraOpt); + // } + // else { + // this.init.apply(this, arguments); + // } + // } + } + + Model.prototype.init = function (option, parentModel, ecModel) { + var rest = []; + + for (var _i = 3; _i < arguments.length; _i++) { + rest[_i - 3] = arguments[_i]; + } + }; + /** + * Merge the input option to me. + */ + + + Model.prototype.mergeOption = function (option, ecModel) { + merge(this.option, option, true); + }; // `path` can be 'xxx.yyy.zzz', so the return value type have to be `ModelOption` + // TODO: TYPE strict key check? + // get(path: string | string[], ignoreParent?: boolean): ModelOption; + + + Model.prototype.get = function (path, ignoreParent) { + if (path == null) { + return this.option; + } + + return this._doGet(this.parsePath(path), !ignoreParent && this.parentModel); + }; + + Model.prototype.getShallow = function (key, ignoreParent) { + var option = this.option; + var val = option == null ? option : option[key]; + + if (val == null && !ignoreParent) { + var parentModel = this.parentModel; + + if (parentModel) { + // FIXME:TS do not know how to make it works + val = parentModel.getShallow(key); + } + } + + return val; + }; // `path` can be 'xxx.yyy.zzz', so the return value type have to be `Model` + // getModel(path: string | string[], parentModel?: Model): Model; + // TODO 'xxx.yyy.zzz' is deprecated + + + Model.prototype.getModel = function (path, parentModel) { + var hasPath = path != null; + var pathFinal = hasPath ? this.parsePath(path) : null; + var obj = hasPath ? this._doGet(pathFinal) : this.option; + parentModel = parentModel || this.parentModel && this.parentModel.getModel(this.resolveParentPath(pathFinal)); + return new Model(obj, parentModel, this.ecModel); + }; + /** + * If model has option + */ + + + Model.prototype.isEmpty = function () { + return this.option == null; + }; + + Model.prototype.restoreData = function () {}; // Pending + + + Model.prototype.clone = function () { + var Ctor = this.constructor; + return new Ctor(clone(this.option)); + }; // setReadOnly(properties): void { + // clazzUtil.setReadOnly(this, properties); + // } + // If path is null/undefined, return null/undefined. + + + Model.prototype.parsePath = function (path) { + if (typeof path === 'string') { + return path.split('.'); + } + + return path; + }; // Resolve path for parent. Perhaps useful when parent use a different property. + // Default to be a identity resolver. + // Can be modified to a different resolver. + + + Model.prototype.resolveParentPath = function (path) { + return path; + }; // FIXME:TS check whether put this method here + + + Model.prototype.isAnimationEnabled = function () { + if (!env.node && this.option) { + if (this.option.animation != null) { + return !!this.option.animation; + } else if (this.parentModel) { + return this.parentModel.isAnimationEnabled(); + } + } + }; + + Model.prototype._doGet = function (pathArr, parentModel) { + var obj = this.option; + + if (!pathArr) { + return obj; + } + + for (var i = 0; i < pathArr.length; i++) { + // Ignore empty + if (!pathArr[i]) { + continue; + } // obj could be number/string/... (like 0) + + + obj = obj && typeof obj === 'object' ? obj[pathArr[i]] : null; + + if (obj == null) { + break; + } + } + + if (obj == null && parentModel) { + obj = parentModel._doGet(this.resolveParentPath(pathArr), parentModel.parentModel); + } + + return obj; + }; + + return Model; + }(); + + enableClassExtend(Model); + enableClassCheck(Model); + mixin(Model, LineStyleMixin); + mixin(Model, ItemStyleMixin); + mixin(Model, AreaStyleMixin); + mixin(Model, TextStyleMixin); + + var base = Math.round(Math.random() * 10); + /** + * @public + * @param {string} type + * @return {string} + */ + + function getUID(type) { + // Considering the case of crossing js context, + // use Math.random to make id as unique as possible. + return [type || '', base++].join('_'); + } + /** + * Implements `SubTypeDefaulterManager` for `target`. + */ + + function enableSubTypeDefaulter(target) { + var subTypeDefaulters = {}; + + target.registerSubTypeDefaulter = function (componentType, defaulter) { + var componentTypeInfo = parseClassType(componentType); + subTypeDefaulters[componentTypeInfo.main] = defaulter; + }; + + target.determineSubType = function (componentType, option) { + var type = option.type; + + if (!type) { + var componentTypeMain = parseClassType(componentType).main; + + if (target.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) { + type = subTypeDefaulters[componentTypeMain](option); + } + } + + return type; + }; + } + /** + * Implements `TopologicalTravelable` for `entity`. + * + * Topological travel on Activity Network (Activity On Vertices). + * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis']. + * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology. + * If there is circular dependencey, Error will be thrown. + */ + + function enableTopologicalTravel(entity, dependencyGetter) { + /** + * @param targetNameList Target Component type list. + * Can be ['aa', 'bb', 'aa.xx'] + * @param fullNameList By which we can build dependency graph. + * @param callback Params: componentType, dependencies. + * @param context Scope of callback. + */ + entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) { + if (!targetNameList.length) { + return; + } + + var result = makeDepndencyGraph(fullNameList); + var graph = result.graph; + var noEntryList = result.noEntryList; + var targetNameSet = {}; + each(targetNameList, function (name) { + targetNameSet[name] = true; + }); + + while (noEntryList.length) { + var currComponentType = noEntryList.pop(); + var currVertex = graph[currComponentType]; + var isInTargetNameSet = !!targetNameSet[currComponentType]; + + if (isInTargetNameSet) { + callback.call(context, currComponentType, currVertex.originalDeps.slice()); + delete targetNameSet[currComponentType]; + } + + each(currVertex.successor, isInTargetNameSet ? removeEdgeAndAdd : removeEdge); + } + + each(targetNameSet, function () { + var errMsg = ''; + + if ("development" !== 'production') { + errMsg = makePrintable('Circular dependency may exists: ', targetNameSet, targetNameList, fullNameList); + } + + throw new Error(errMsg); + }); + + function removeEdge(succComponentType) { + graph[succComponentType].entryCount--; + + if (graph[succComponentType].entryCount === 0) { + noEntryList.push(succComponentType); + } + } // Consider this case: legend depends on series, and we call + // chart.setOption({series: [...]}), where only series is in option. + // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will + // not be called, but only sereis.mergeOption is called. Thus legend + // have no chance to update its local record about series (like which + // name of series is available in legend). + + + function removeEdgeAndAdd(succComponentType) { + targetNameSet[succComponentType] = true; + removeEdge(succComponentType); + } + }; + + function makeDepndencyGraph(fullNameList) { + var graph = {}; + var noEntryList = []; + each(fullNameList, function (name) { + var thisItem = createDependencyGraphItem(graph, name); + var originalDeps = thisItem.originalDeps = dependencyGetter(name); + var availableDeps = getAvailableDependencies(originalDeps, fullNameList); + thisItem.entryCount = availableDeps.length; + + if (thisItem.entryCount === 0) { + noEntryList.push(name); + } + + each(availableDeps, function (dependentName) { + if (indexOf(thisItem.predecessor, dependentName) < 0) { + thisItem.predecessor.push(dependentName); + } + + var thatItem = createDependencyGraphItem(graph, dependentName); + + if (indexOf(thatItem.successor, dependentName) < 0) { + thatItem.successor.push(name); + } + }); + }); + return { + graph: graph, + noEntryList: noEntryList + }; + } + + function createDependencyGraphItem(graph, name) { + if (!graph[name]) { + graph[name] = { + predecessor: [], + successor: [] + }; + } + + return graph[name]; + } + + function getAvailableDependencies(originalDeps, fullNameList) { + var availableDeps = []; + each(originalDeps, function (dep) { + indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep); + }); + return availableDeps; + } + } + function inheritDefaultOption(superOption, subOption) { + // See also `model/Component.ts#getDefaultOption` + return merge(merge({}, superOption, true), subOption, true); + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * Language: English. + */ + var langEN = { + time: { + month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + monthAbbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + dayOfWeek: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + dayOfWeekAbbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] + }, + legend: { + selector: { + all: 'All', + inverse: 'Inv' + } + }, + toolbox: { + brush: { + title: { + rect: 'Box Select', + polygon: 'Lasso Select', + lineX: 'Horizontally Select', + lineY: 'Vertically Select', + keep: 'Keep Selections', + clear: 'Clear Selections' + } + }, + dataView: { + title: 'Data View', + lang: ['Data View', 'Close', 'Refresh'] + }, + dataZoom: { + title: { + zoom: 'Zoom', + back: 'Zoom Reset' + } + }, + magicType: { + title: { + line: 'Switch to Line Chart', + bar: 'Switch to Bar Chart', + stack: 'Stack', + tiled: 'Tile' + } + }, + restore: { + title: 'Restore' + }, + saveAsImage: { + title: 'Save as Image', + lang: ['Right Click to Save Image'] + } + }, + series: { + typeNames: { + pie: 'Pie chart', + bar: 'Bar chart', + line: 'Line chart', + scatter: 'Scatter plot', + effectScatter: 'Ripple scatter plot', + radar: 'Radar chart', + tree: 'Tree', + treemap: 'Treemap', + boxplot: 'Boxplot', + candlestick: 'Candlestick', + k: 'K line chart', + heatmap: 'Heat map', + map: 'Map', + parallel: 'Parallel coordinate map', + lines: 'Line graph', + graph: 'Relationship graph', + sankey: 'Sankey diagram', + funnel: 'Funnel chart', + gauge: 'Gauge', + pictorialBar: 'Pictorial bar', + themeRiver: 'Theme River Map', + sunburst: 'Sunburst' + } + }, + aria: { + general: { + withTitle: 'This is a chart about "{title}"', + withoutTitle: 'This is a chart' + }, + series: { + single: { + prefix: '', + withName: ' with type {seriesType} named {seriesName}.', + withoutName: ' with type {seriesType}.' + }, + multiple: { + prefix: '. It consists of {seriesCount} series count.', + withName: ' The {seriesId} series is a {seriesType} representing {seriesName}.', + withoutName: ' The {seriesId} series is a {seriesType}.', + separator: { + middle: '', + end: '' + } + } + }, + data: { + allData: 'The data is as follows: ', + partialData: 'The first {displayCnt} items are: ', + withName: 'the data for {name} is {value}', + withoutName: '{value}', + separator: { + middle: ', ', + end: '. ' + } + } + } + }; + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + var langZH = { + time: { + month: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], + monthAbbr: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], + dayOfWeek: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'], + dayOfWeekAbbr: ['日', '一', '二', '三', '四', '五', '六'] + }, + legend: { + selector: { + all: '全选', + inverse: '反选' + } + }, + toolbox: { + brush: { + title: { + rect: '矩形选择', + polygon: '圈选', + lineX: '横向选择', + lineY: '纵向选择', + keep: '保持选择', + clear: '清除选择' + } + }, + dataView: { + title: '数据视图', + lang: ['数据视图', '关闭', '刷新'] + }, + dataZoom: { + title: { + zoom: '区域缩放', + back: '区域缩放还原' + } + }, + magicType: { + title: { + line: '切换为折线图', + bar: '切换为柱状图', + stack: '切换为堆叠', + tiled: '切换为平铺' + } + }, + restore: { + title: '还原' + }, + saveAsImage: { + title: '保存为图片', + lang: ['右键另存为图片'] + } + }, + series: { + typeNames: { + pie: '饼图', + bar: '柱状图', + line: '折线图', + scatter: '散点图', + effectScatter: '涟漪散点图', + radar: '雷达图', + tree: '树图', + treemap: '矩形树图', + boxplot: '箱型图', + candlestick: 'K线图', + k: 'K线图', + heatmap: '热力图', + map: '地图', + parallel: '平行坐标图', + lines: '线图', + graph: '关系图', + sankey: '桑基图', + funnel: '漏斗图', + gauge: '仪表盘图', + pictorialBar: '象形柱图', + themeRiver: '主题河流图', + sunburst: '旭日图' + } + }, + aria: { + general: { + withTitle: '这是一个关于“{title}”的图表。', + withoutTitle: '这是一个图表,' + }, + series: { + single: { + prefix: '', + withName: '图表类型是{seriesType},表示{seriesName}。', + withoutName: '图表类型是{seriesType}。' + }, + multiple: { + prefix: '它由{seriesCount}个图表系列组成。', + withName: '第{seriesId}个系列是一个表示{seriesName}的{seriesType},', + withoutName: '第{seriesId}个系列是一个{seriesType},', + separator: { + middle: ';', + end: '。' + } + } + }, + data: { + allData: '其数据是——', + partialData: '其中,前{displayCnt}项是——', + withName: '{name}的数据是{value}', + withoutName: '{value}', + separator: { + middle: ',', + end: '' + } + } + } + }; + + var LOCALE_ZH = 'ZH'; + var LOCALE_EN = 'EN'; + var DEFAULT_LOCALE = LOCALE_EN; + var localeStorage = {}; + var localeModels = {}; + var SYSTEM_LANG = !env.domSupported ? DEFAULT_LOCALE : function () { + var langStr = ( + /* eslint-disable-next-line */ + document.documentElement.lang || navigator.language || navigator.browserLanguage).toUpperCase(); + return langStr.indexOf(LOCALE_ZH) > -1 ? LOCALE_ZH : DEFAULT_LOCALE; + }(); + function registerLocale(locale, localeObj) { + locale = locale.toUpperCase(); + localeModels[locale] = new Model(localeObj); + localeStorage[locale] = localeObj; + } // export function getLocale(locale: string) { + // return localeStorage[locale]; + // } + + function createLocaleObject(locale) { + if (isString(locale)) { + var localeObj = localeStorage[locale.toUpperCase()] || {}; + + if (locale === LOCALE_ZH || locale === LOCALE_EN) { + return clone(localeObj); + } else { + return merge(clone(localeObj), clone(localeStorage[DEFAULT_LOCALE]), false); + } + } else { + return merge(clone(locale), clone(localeStorage[DEFAULT_LOCALE]), false); + } + } + function getLocaleModel(lang) { + return localeModels[lang]; + } + function getDefaultLocaleModel() { + return localeModels[DEFAULT_LOCALE]; + } // Default locale + + registerLocale(LOCALE_EN, langEN); + registerLocale(LOCALE_ZH, langZH); + + var ONE_SECOND = 1000; + var ONE_MINUTE = ONE_SECOND * 60; + var ONE_HOUR = ONE_MINUTE * 60; + var ONE_DAY = ONE_HOUR * 24; + var ONE_YEAR = ONE_DAY * 365; + var defaultLeveledFormatter = { + year: '{yyyy}', + month: '{MMM}', + day: '{d}', + hour: '{HH}:{mm}', + minute: '{HH}:{mm}', + second: '{HH}:{mm}:{ss}', + millisecond: '{HH}:{mm}:{ss} {SSS}', + none: '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss} {SSS}' + }; + var fullDayFormatter = '{yyyy}-{MM}-{dd}'; + var fullLeveledFormatter = { + year: '{yyyy}', + month: '{yyyy}-{MM}', + day: fullDayFormatter, + hour: fullDayFormatter + ' ' + defaultLeveledFormatter.hour, + minute: fullDayFormatter + ' ' + defaultLeveledFormatter.minute, + second: fullDayFormatter + ' ' + defaultLeveledFormatter.second, + millisecond: defaultLeveledFormatter.none + }; + var primaryTimeUnits = ['year', 'month', 'day', 'hour', 'minute', 'second', 'millisecond']; + var timeUnits = ['year', 'half-year', 'quarter', 'month', 'week', 'half-week', 'day', 'half-day', 'quarter-day', 'hour', 'minute', 'second', 'millisecond']; + function pad(str, len) { + str += ''; + return '0000'.substr(0, len - str.length) + str; + } + function getPrimaryTimeUnit(timeUnit) { + switch (timeUnit) { + case 'half-year': + case 'quarter': + return 'month'; + + case 'week': + case 'half-week': + return 'day'; + + case 'half-day': + case 'quarter-day': + return 'hour'; + + default: + // year, minutes, second, milliseconds + return timeUnit; + } + } + function isPrimaryTimeUnit(timeUnit) { + return timeUnit === getPrimaryTimeUnit(timeUnit); + } + function getDefaultFormatPrecisionOfInterval(timeUnit) { + switch (timeUnit) { + case 'year': + case 'month': + return 'day'; + + case 'millisecond': + return 'millisecond'; + + default: + // Also for day, hour, minute, second + return 'second'; + } + } + function format( // Note: The result based on `isUTC` are totally different, which can not be just simply + // substituted by the result without `isUTC`. So we make the param `isUTC` mandatory. + time, template, isUTC, lang) { + var date = parseDate(time); + var y = date[fullYearGetterName(isUTC)](); + var M = date[monthGetterName(isUTC)]() + 1; + var q = Math.floor((M - 1) / 4) + 1; + var d = date[dateGetterName(isUTC)](); + var e = date['get' + (isUTC ? 'UTC' : '') + 'Day'](); + var H = date[hoursGetterName(isUTC)](); + var h = (H - 1) % 12 + 1; + var m = date[minutesGetterName(isUTC)](); + var s = date[secondsGetterName(isUTC)](); + var S = date[millisecondsGetterName(isUTC)](); + var localeModel = lang instanceof Model ? lang : getLocaleModel(lang || SYSTEM_LANG) || getDefaultLocaleModel(); + var timeModel = localeModel.getModel('time'); + var month = timeModel.get('month'); + var monthAbbr = timeModel.get('monthAbbr'); + var dayOfWeek = timeModel.get('dayOfWeek'); + var dayOfWeekAbbr = timeModel.get('dayOfWeekAbbr'); + return (template || '').replace(/{yyyy}/g, y + '').replace(/{yy}/g, y % 100 + '').replace(/{Q}/g, q + '').replace(/{MMMM}/g, month[M - 1]).replace(/{MMM}/g, monthAbbr[M - 1]).replace(/{MM}/g, pad(M, 2)).replace(/{M}/g, M + '').replace(/{dd}/g, pad(d, 2)).replace(/{d}/g, d + '').replace(/{eeee}/g, dayOfWeek[e]).replace(/{ee}/g, dayOfWeekAbbr[e]).replace(/{e}/g, e + '').replace(/{HH}/g, pad(H, 2)).replace(/{H}/g, H + '').replace(/{hh}/g, pad(h + '', 2)).replace(/{h}/g, h + '').replace(/{mm}/g, pad(m, 2)).replace(/{m}/g, m + '').replace(/{ss}/g, pad(s, 2)).replace(/{s}/g, s + '').replace(/{SSS}/g, pad(S, 3)).replace(/{S}/g, S + ''); + } + function leveledFormat(tick, idx, formatter, lang, isUTC) { + var template = null; + + if (isString(formatter)) { + // Single formatter for all units at all levels + template = formatter; + } else if (isFunction(formatter)) { + // Callback formatter + template = formatter(tick.value, idx, { + level: tick.level + }); + } else { + var defaults$1 = extend({}, defaultLeveledFormatter); + + if (tick.level > 0) { + for (var i = 0; i < primaryTimeUnits.length; ++i) { + defaults$1[primaryTimeUnits[i]] = "{primary|" + defaults$1[primaryTimeUnits[i]] + "}"; + } + } + + var mergedFormatter = formatter ? formatter.inherit === false ? formatter // Use formatter with bigger units + : defaults(formatter, defaults$1) : defaults$1; + var unit = getUnitFromValue(tick.value, isUTC); + + if (mergedFormatter[unit]) { + template = mergedFormatter[unit]; + } else if (mergedFormatter.inherit) { + // Unit formatter is not defined and should inherit from bigger units + var targetId = timeUnits.indexOf(unit); + + for (var i = targetId - 1; i >= 0; --i) { + if (mergedFormatter[unit]) { + template = mergedFormatter[unit]; + break; + } + } + + template = template || defaults$1.none; + } + + if (isArray(template)) { + var levelId = tick.level == null ? 0 : tick.level >= 0 ? tick.level : template.length + tick.level; + levelId = Math.min(levelId, template.length - 1); + template = template[levelId]; + } + } + + return format(new Date(tick.value), template, isUTC, lang); + } + function getUnitFromValue(value, isUTC) { + var date = parseDate(value); + var M = date[monthGetterName(isUTC)]() + 1; + var d = date[dateGetterName(isUTC)](); + var h = date[hoursGetterName(isUTC)](); + var m = date[minutesGetterName(isUTC)](); + var s = date[secondsGetterName(isUTC)](); + var S = date[millisecondsGetterName(isUTC)](); + var isSecond = S === 0; + var isMinute = isSecond && s === 0; + var isHour = isMinute && m === 0; + var isDay = isHour && h === 0; + var isMonth = isDay && d === 1; + var isYear = isMonth && M === 1; + + if (isYear) { + return 'year'; + } else if (isMonth) { + return 'month'; + } else if (isDay) { + return 'day'; + } else if (isHour) { + return 'hour'; + } else if (isMinute) { + return 'minute'; + } else if (isSecond) { + return 'second'; + } else { + return 'millisecond'; + } + } + function getUnitValue(value, unit, isUTC) { + var date = isNumber(value) ? parseDate(value) : value; + unit = unit || getUnitFromValue(value, isUTC); + + switch (unit) { + case 'year': + return date[fullYearGetterName(isUTC)](); + + case 'half-year': + return date[monthGetterName(isUTC)]() >= 6 ? 1 : 0; + + case 'quarter': + return Math.floor((date[monthGetterName(isUTC)]() + 1) / 4); + + case 'month': + return date[monthGetterName(isUTC)](); + + case 'day': + return date[dateGetterName(isUTC)](); + + case 'half-day': + return date[hoursGetterName(isUTC)]() / 24; + + case 'hour': + return date[hoursGetterName(isUTC)](); + + case 'minute': + return date[minutesGetterName(isUTC)](); + + case 'second': + return date[secondsGetterName(isUTC)](); + + case 'millisecond': + return date[millisecondsGetterName(isUTC)](); + } + } + function fullYearGetterName(isUTC) { + return isUTC ? 'getUTCFullYear' : 'getFullYear'; + } + function monthGetterName(isUTC) { + return isUTC ? 'getUTCMonth' : 'getMonth'; + } + function dateGetterName(isUTC) { + return isUTC ? 'getUTCDate' : 'getDate'; + } + function hoursGetterName(isUTC) { + return isUTC ? 'getUTCHours' : 'getHours'; + } + function minutesGetterName(isUTC) { + return isUTC ? 'getUTCMinutes' : 'getMinutes'; + } + function secondsGetterName(isUTC) { + return isUTC ? 'getUTCSeconds' : 'getSeconds'; + } + function millisecondsGetterName(isUTC) { + return isUTC ? 'getUTCMilliseconds' : 'getMilliseconds'; + } + function fullYearSetterName(isUTC) { + return isUTC ? 'setUTCFullYear' : 'setFullYear'; + } + function monthSetterName(isUTC) { + return isUTC ? 'setUTCMonth' : 'setMonth'; + } + function dateSetterName(isUTC) { + return isUTC ? 'setUTCDate' : 'setDate'; + } + function hoursSetterName(isUTC) { + return isUTC ? 'setUTCHours' : 'setHours'; + } + function minutesSetterName(isUTC) { + return isUTC ? 'setUTCMinutes' : 'setMinutes'; + } + function secondsSetterName(isUTC) { + return isUTC ? 'setUTCSeconds' : 'setSeconds'; + } + function millisecondsSetterName(isUTC) { + return isUTC ? 'setUTCMilliseconds' : 'setMilliseconds'; + } + + function getTextRect(text, font, align, verticalAlign, padding, rich, truncate, lineHeight) { + var textEl = new ZRText({ + style: { + text: text, + font: font, + align: align, + verticalAlign: verticalAlign, + padding: padding, + rich: rich, + overflow: truncate ? 'truncate' : null, + lineHeight: lineHeight + } + }); + return textEl.getBoundingRect(); + } + + /** + * Add a comma each three digit. + */ + + function addCommas(x) { + if (!isNumeric(x)) { + return isString(x) ? x : '-'; + } + + var parts = (x + '').split('.'); + return parts[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g, '$1,') + (parts.length > 1 ? '.' + parts[1] : ''); + } + function toCamelCase(str, upperCaseFirst) { + str = (str || '').toLowerCase().replace(/-(.)/g, function (match, group1) { + return group1.toUpperCase(); + }); + + if (upperCaseFirst && str) { + str = str.charAt(0).toUpperCase() + str.slice(1); + } + + return str; + } + var normalizeCssArray$1 = normalizeCssArray; + var replaceReg = /([&<>"'])/g; + var replaceMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''' + }; + function encodeHTML(source) { + return source == null ? '' : (source + '').replace(replaceReg, function (str, c) { + return replaceMap[c]; + }); + } + /** + * Make value user readable for tooltip and label. + * "User readable": + * Try to not print programmer-specific text like NaN, Infinity, null, undefined. + * Avoid to display an empty string, which users can not recognize there is + * a value and it might look like a bug. + */ + + function makeValueReadable(value, valueType, useUTC) { + var USER_READABLE_DEFUALT_TIME_PATTERN = '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}'; + + function stringToUserReadable(str) { + return str && trim(str) ? str : '-'; + } + + function isNumberUserReadable(num) { + return !!(num != null && !isNaN(num) && isFinite(num)); + } + + var isTypeTime = valueType === 'time'; + var isValueDate = value instanceof Date; + + if (isTypeTime || isValueDate) { + var date = isTypeTime ? parseDate(value) : value; + + if (!isNaN(+date)) { + return format(date, USER_READABLE_DEFUALT_TIME_PATTERN, useUTC); + } else if (isValueDate) { + return '-'; + } // In other cases, continue to try to display the value in the following code. + + } + + if (valueType === 'ordinal') { + return isStringSafe(value) ? stringToUserReadable(value) : isNumber(value) ? isNumberUserReadable(value) ? value + '' : '-' : '-'; + } // By default. + + + var numericResult = numericToNumber(value); + return isNumberUserReadable(numericResult) ? addCommas(numericResult) : isStringSafe(value) ? stringToUserReadable(value) : typeof value === 'boolean' ? value + '' : '-'; + } + var TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; + + var wrapVar = function (varName, seriesIdx) { + return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}'; + }; + /** + * Template formatter + * @param {Array.|Object} paramsList + */ + + + function formatTpl(tpl, paramsList, encode) { + if (!isArray(paramsList)) { + paramsList = [paramsList]; + } + + var seriesLen = paramsList.length; + + if (!seriesLen) { + return ''; + } + + var $vars = paramsList[0].$vars || []; + + for (var i = 0; i < $vars.length; i++) { + var alias = TPL_VAR_ALIAS[i]; + tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0)); + } + + for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) { + for (var k = 0; k < $vars.length; k++) { + var val = paramsList[seriesIdx][$vars[k]]; + tpl = tpl.replace(wrapVar(TPL_VAR_ALIAS[k], seriesIdx), encode ? encodeHTML(val) : val); + } + } + + return tpl; + } + /** + * simple Template formatter + */ + + function formatTplSimple(tpl, param, encode) { + each(param, function (value, key) { + tpl = tpl.replace('{' + key + '}', encode ? encodeHTML(value) : value); + }); + return tpl; + } + function getTooltipMarker(inOpt, extraCssText) { + var opt = isString(inOpt) ? { + color: inOpt, + extraCssText: extraCssText + } : inOpt || {}; + var color = opt.color; + var type = opt.type; + extraCssText = opt.extraCssText; + var renderMode = opt.renderMode || 'html'; + + if (!color) { + return ''; + } + + if (renderMode === 'html') { + return type === 'subItem' ? '' : ''; + } else { + // Should better not to auto generate style name by auto-increment number here. + // Because this util is usually called in tooltip formatter, which is probably + // called repeatly when mouse move and the auto-increment number increases fast. + // Users can make their own style name by theirselves, make it unique and readable. + var markerId = opt.markerId || 'markerX'; + return { + renderMode: renderMode, + content: '{' + markerId + '|} ', + style: type === 'subItem' ? { + width: 4, + height: 4, + borderRadius: 2, + backgroundColor: color + } : { + width: 10, + height: 10, + borderRadius: 5, + backgroundColor: color + } + }; + } + } + /** + * @deprecated Use `time/format` instead. + * ISO Date format + * @param {string} tpl + * @param {number} value + * @param {boolean} [isUTC=false] Default in local time. + * see `module:echarts/scale/Time` + * and `module:echarts/util/number#parseDate`. + * @inner + */ + + function formatTime(tpl, value, isUTC) { + if ("development" !== 'production') { + deprecateReplaceLog('echarts.format.formatTime', 'echarts.time.format'); + } + + if (tpl === 'week' || tpl === 'month' || tpl === 'quarter' || tpl === 'half-year' || tpl === 'year') { + tpl = 'MM-dd\nyyyy'; + } + + var date = parseDate(value); + var getUTC = isUTC ? 'getUTC' : 'get'; + var y = date[getUTC + 'FullYear'](); + var M = date[getUTC + 'Month']() + 1; + var d = date[getUTC + 'Date'](); + var h = date[getUTC + 'Hours'](); + var m = date[getUTC + 'Minutes'](); + var s = date[getUTC + 'Seconds'](); + var S = date[getUTC + 'Milliseconds'](); + tpl = tpl.replace('MM', pad(M, 2)).replace('M', M).replace('yyyy', y).replace('yy', y % 100 + '').replace('dd', pad(d, 2)).replace('d', d).replace('hh', pad(h, 2)).replace('h', h).replace('mm', pad(m, 2)).replace('m', m).replace('ss', pad(s, 2)).replace('s', s).replace('SSS', pad(S, 3)); + return tpl; + } + /** + * Capital first + * @param {string} str + * @return {string} + */ + + function capitalFirst(str) { + return str ? str.charAt(0).toUpperCase() + str.substr(1) : str; + } + /** + * @return Never be null/undefined. + */ + + function convertToColorString(color, defaultColor) { + defaultColor = defaultColor || 'transparent'; + return isString(color) ? color : isObject(color) ? color.colorStops && (color.colorStops[0] || {}).color || defaultColor : defaultColor; + } + /** + * open new tab + * @param link url + * @param target blank or self + */ + + function windowOpen(link, target) { + /* global window */ + if (target === '_blank' || target === 'blank') { + var blank = window.open(); + blank.opener = null; + blank.location.href = link; + } else { + window.open(link, target); + } + } + + var each$1 = each; + /** + * @public + */ + + var LOCATION_PARAMS = ['left', 'right', 'top', 'bottom', 'width', 'height']; + /** + * @public + */ + + var HV_NAMES = [['width', 'left', 'right'], ['height', 'top', 'bottom']]; + + function boxLayout(orient, group, gap, maxWidth, maxHeight) { + var x = 0; + var y = 0; + + if (maxWidth == null) { + maxWidth = Infinity; + } + + if (maxHeight == null) { + maxHeight = Infinity; + } + + var currentLineMaxSize = 0; + group.eachChild(function (child, idx) { + var rect = child.getBoundingRect(); + var nextChild = group.childAt(idx + 1); + var nextChildRect = nextChild && nextChild.getBoundingRect(); + var nextX; + var nextY; + + if (orient === 'horizontal') { + var moveX = rect.width + (nextChildRect ? -nextChildRect.x + rect.x : 0); + nextX = x + moveX; // Wrap when width exceeds maxWidth or meet a `newline` group + // FIXME compare before adding gap? + + if (nextX > maxWidth || child.newline) { + x = 0; + nextX = moveX; + y += currentLineMaxSize + gap; + currentLineMaxSize = rect.height; + } else { + // FIXME: consider rect.y is not `0`? + currentLineMaxSize = Math.max(currentLineMaxSize, rect.height); + } + } else { + var moveY = rect.height + (nextChildRect ? -nextChildRect.y + rect.y : 0); + nextY = y + moveY; // Wrap when width exceeds maxHeight or meet a `newline` group + + if (nextY > maxHeight || child.newline) { + x += currentLineMaxSize + gap; + y = 0; + nextY = moveY; + currentLineMaxSize = rect.width; + } else { + currentLineMaxSize = Math.max(currentLineMaxSize, rect.width); + } + } + + if (child.newline) { + return; + } + + child.x = x; + child.y = y; + child.markRedraw(); + orient === 'horizontal' ? x = nextX + gap : y = nextY + gap; + }); + } + /** + * VBox or HBox layouting + * @param {string} orient + * @param {module:zrender/graphic/Group} group + * @param {number} gap + * @param {number} [width=Infinity] + * @param {number} [height=Infinity] + */ + + + var box = boxLayout; + /** + * VBox layouting + * @param {module:zrender/graphic/Group} group + * @param {number} gap + * @param {number} [width=Infinity] + * @param {number} [height=Infinity] + */ + + var vbox = curry(boxLayout, 'vertical'); + /** + * HBox layouting + * @param {module:zrender/graphic/Group} group + * @param {number} gap + * @param {number} [width=Infinity] + * @param {number} [height=Infinity] + */ + + var hbox = curry(boxLayout, 'horizontal'); + /** + * If x or x2 is not specified or 'center' 'left' 'right', + * the width would be as long as possible. + * If y or y2 is not specified or 'middle' 'top' 'bottom', + * the height would be as long as possible. + */ + + function getAvailableSize(positionInfo, containerRect, margin) { + var containerWidth = containerRect.width; + var containerHeight = containerRect.height; + var x = parsePercent$1(positionInfo.left, containerWidth); + var y = parsePercent$1(positionInfo.top, containerHeight); + var x2 = parsePercent$1(positionInfo.right, containerWidth); + var y2 = parsePercent$1(positionInfo.bottom, containerHeight); + (isNaN(x) || isNaN(parseFloat(positionInfo.left))) && (x = 0); + (isNaN(x2) || isNaN(parseFloat(positionInfo.right))) && (x2 = containerWidth); + (isNaN(y) || isNaN(parseFloat(positionInfo.top))) && (y = 0); + (isNaN(y2) || isNaN(parseFloat(positionInfo.bottom))) && (y2 = containerHeight); + margin = normalizeCssArray$1(margin || 0); + return { + width: Math.max(x2 - x - margin[1] - margin[3], 0), + height: Math.max(y2 - y - margin[0] - margin[2], 0) + }; + } + /** + * Parse position info. + */ + + function getLayoutRect(positionInfo, containerRect, margin) { + margin = normalizeCssArray$1(margin || 0); + var containerWidth = containerRect.width; + var containerHeight = containerRect.height; + var left = parsePercent$1(positionInfo.left, containerWidth); + var top = parsePercent$1(positionInfo.top, containerHeight); + var right = parsePercent$1(positionInfo.right, containerWidth); + var bottom = parsePercent$1(positionInfo.bottom, containerHeight); + var width = parsePercent$1(positionInfo.width, containerWidth); + var height = parsePercent$1(positionInfo.height, containerHeight); + var verticalMargin = margin[2] + margin[0]; + var horizontalMargin = margin[1] + margin[3]; + var aspect = positionInfo.aspect; // If width is not specified, calculate width from left and right + + if (isNaN(width)) { + width = containerWidth - right - horizontalMargin - left; + } + + if (isNaN(height)) { + height = containerHeight - bottom - verticalMargin - top; + } + + if (aspect != null) { + // If width and height are not given + // 1. Graph should not exceeds the container + // 2. Aspect must be keeped + // 3. Graph should take the space as more as possible + // FIXME + // Margin is not considered, because there is no case that both + // using margin and aspect so far. + if (isNaN(width) && isNaN(height)) { + if (aspect > containerWidth / containerHeight) { + width = containerWidth * 0.8; + } else { + height = containerHeight * 0.8; + } + } // Calculate width or height with given aspect + + + if (isNaN(width)) { + width = aspect * height; + } + + if (isNaN(height)) { + height = width / aspect; + } + } // If left is not specified, calculate left from right and width + + + if (isNaN(left)) { + left = containerWidth - right - width - horizontalMargin; + } + + if (isNaN(top)) { + top = containerHeight - bottom - height - verticalMargin; + } // Align left and top + + + switch (positionInfo.left || positionInfo.right) { + case 'center': + left = containerWidth / 2 - width / 2 - margin[3]; + break; + + case 'right': + left = containerWidth - width - horizontalMargin; + break; + } + + switch (positionInfo.top || positionInfo.bottom) { + case 'middle': + case 'center': + top = containerHeight / 2 - height / 2 - margin[0]; + break; + + case 'bottom': + top = containerHeight - height - verticalMargin; + break; + } // If something is wrong and left, top, width, height are calculated as NaN + + + left = left || 0; + top = top || 0; + + if (isNaN(width)) { + // Width may be NaN if only one value is given except width + width = containerWidth - horizontalMargin - left - (right || 0); + } + + if (isNaN(height)) { + // Height may be NaN if only one value is given except height + height = containerHeight - verticalMargin - top - (bottom || 0); + } + + var rect = new BoundingRect(left + margin[3], top + margin[0], width, height); + rect.margin = margin; + return rect; + } + /** + * Position a zr element in viewport + * Group position is specified by either + * {left, top}, {right, bottom} + * If all properties exists, right and bottom will be igonred. + * + * Logic: + * 1. Scale (against origin point in parent coord) + * 2. Rotate (against origin point in parent coord) + * 3. Traslate (with el.position by this method) + * So this method only fixes the last step 'Traslate', which does not affect + * scaling and rotating. + * + * If be called repeatly with the same input el, the same result will be gotten. + * + * Return true if the layout happend. + * + * @param el Should have `getBoundingRect` method. + * @param positionInfo + * @param positionInfo.left + * @param positionInfo.top + * @param positionInfo.right + * @param positionInfo.bottom + * @param positionInfo.width Only for opt.boundingModel: 'raw' + * @param positionInfo.height Only for opt.boundingModel: 'raw' + * @param containerRect + * @param margin + * @param opt + * @param opt.hv Only horizontal or only vertical. Default to be [1, 1] + * @param opt.boundingMode + * Specify how to calculate boundingRect when locating. + * 'all': Position the boundingRect that is transformed and uioned + * both itself and its descendants. + * This mode simplies confine the elements in the bounding + * of their container (e.g., using 'right: 0'). + * 'raw': Position the boundingRect that is not transformed and only itself. + * This mode is useful when you want a element can overflow its + * container. (Consider a rotated circle needs to be located in a corner.) + * In this mode positionInfo.width/height can only be number. + */ + + function positionElement(el, positionInfo, containerRect, margin, opt, out) { + var h = !opt || !opt.hv || opt.hv[0]; + var v = !opt || !opt.hv || opt.hv[1]; + var boundingMode = opt && opt.boundingMode || 'all'; + out = out || el; + out.x = el.x; + out.y = el.y; + + if (!h && !v) { + return false; + } + + var rect; + + if (boundingMode === 'raw') { + rect = el.type === 'group' ? new BoundingRect(0, 0, +positionInfo.width || 0, +positionInfo.height || 0) : el.getBoundingRect(); + } else { + rect = el.getBoundingRect(); + + if (el.needLocalTransform()) { + var transform = el.getLocalTransform(); // Notice: raw rect may be inner object of el, + // which should not be modified. + + rect = rect.clone(); + rect.applyTransform(transform); + } + } // The real width and height can not be specified but calculated by the given el. + + + var layoutRect = getLayoutRect(defaults({ + width: rect.width, + height: rect.height + }, positionInfo), containerRect, margin); // Because 'tranlate' is the last step in transform + // (see zrender/core/Transformable#getLocalTransform), + // we can just only modify el.position to get final result. + + var dx = h ? layoutRect.x - rect.x : 0; + var dy = v ? layoutRect.y - rect.y : 0; + + if (boundingMode === 'raw') { + out.x = dx; + out.y = dy; + } else { + out.x += dx; + out.y += dy; + } + + if (out === el) { + el.markRedraw(); + } + + return true; + } + /** + * @param option Contains some of the properties in HV_NAMES. + * @param hvIdx 0: horizontal; 1: vertical. + */ + + function sizeCalculable(option, hvIdx) { + return option[HV_NAMES[hvIdx][0]] != null || option[HV_NAMES[hvIdx][1]] != null && option[HV_NAMES[hvIdx][2]] != null; + } + function fetchLayoutMode(ins) { + var layoutMode = ins.layoutMode || ins.constructor.layoutMode; + return isObject(layoutMode) ? layoutMode : layoutMode ? { + type: layoutMode + } : null; + } + /** + * Consider Case: + * When default option has {left: 0, width: 100}, and we set {right: 0} + * through setOption or media query, using normal zrUtil.merge will cause + * {right: 0} does not take effect. + * + * @example + * ComponentModel.extend({ + * init: function () { + * ... + * let inputPositionParams = layout.getLayoutParams(option); + * this.mergeOption(inputPositionParams); + * }, + * mergeOption: function (newOption) { + * newOption && zrUtil.merge(thisOption, newOption, true); + * layout.mergeLayoutParam(thisOption, newOption); + * } + * }); + * + * @param targetOption + * @param newOption + * @param opt + */ + + function mergeLayoutParam(targetOption, newOption, opt) { + var ignoreSize = opt && opt.ignoreSize; + !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]); + var hResult = merge(HV_NAMES[0], 0); + var vResult = merge(HV_NAMES[1], 1); + copy(HV_NAMES[0], targetOption, hResult); + copy(HV_NAMES[1], targetOption, vResult); + + function merge(names, hvIdx) { + var newParams = {}; + var newValueCount = 0; + var merged = {}; + var mergedValueCount = 0; + var enoughParamNumber = 2; + each$1(names, function (name) { + merged[name] = targetOption[name]; + }); + each$1(names, function (name) { + // Consider case: newOption.width is null, which is + // set by user for removing width setting. + hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]); + hasValue(newParams, name) && newValueCount++; + hasValue(merged, name) && mergedValueCount++; + }); + + if (ignoreSize[hvIdx]) { + // Only one of left/right is premitted to exist. + if (hasValue(newOption, names[1])) { + merged[names[2]] = null; + } else if (hasValue(newOption, names[2])) { + merged[names[1]] = null; + } + + return merged; + } // Case: newOption: {width: ..., right: ...}, + // or targetOption: {right: ...} and newOption: {width: ...}, + // There is no conflict when merged only has params count + // little than enoughParamNumber. + + + if (mergedValueCount === enoughParamNumber || !newValueCount) { + return merged; + } // Case: newOption: {width: ..., right: ...}, + // Than we can make sure user only want those two, and ignore + // all origin params in targetOption. + else if (newValueCount >= enoughParamNumber) { + return newParams; + } else { + // Chose another param from targetOption by priority. + for (var i = 0; i < names.length; i++) { + var name_1 = names[i]; + + if (!hasProp(newParams, name_1) && hasProp(targetOption, name_1)) { + newParams[name_1] = targetOption[name_1]; + break; + } + } + + return newParams; + } + } + + function hasProp(obj, name) { + return obj.hasOwnProperty(name); + } + + function hasValue(obj, name) { + return obj[name] != null && obj[name] !== 'auto'; + } + + function copy(names, target, source) { + each$1(names, function (name) { + target[name] = source[name]; + }); + } + } + /** + * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object. + */ + + function getLayoutParams(source) { + return copyLayoutParams({}, source); + } + /** + * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object. + * @param {Object} source + * @return {Object} Result contains those props. + */ + + function copyLayoutParams(target, source) { + source && target && each$1(LOCATION_PARAMS, function (name) { + source.hasOwnProperty(name) && (target[name] = source[name]); + }); + return target; + } + + var inner = makeInner(); + + var ComponentModel = + /** @class */ + function (_super) { + __extends(ComponentModel, _super); + + function ComponentModel(option, parentModel, ecModel) { + var _this = _super.call(this, option, parentModel, ecModel) || this; + + _this.uid = getUID('ec_cpt_model'); + return _this; + } + + ComponentModel.prototype.init = function (option, parentModel, ecModel) { + this.mergeDefaultAndTheme(option, ecModel); + }; + + ComponentModel.prototype.mergeDefaultAndTheme = function (option, ecModel) { + var layoutMode = fetchLayoutMode(this); + var inputPositionParams = layoutMode ? getLayoutParams(option) : {}; + var themeModel = ecModel.getTheme(); + merge(option, themeModel.get(this.mainType)); + merge(option, this.getDefaultOption()); + + if (layoutMode) { + mergeLayoutParam(option, inputPositionParams, layoutMode); + } + }; + + ComponentModel.prototype.mergeOption = function (option, ecModel) { + merge(this.option, option, true); + var layoutMode = fetchLayoutMode(this); + + if (layoutMode) { + mergeLayoutParam(this.option, option, layoutMode); + } + }; + /** + * Called immediately after `init` or `mergeOption` of this instance called. + */ + + + ComponentModel.prototype.optionUpdated = function (newCptOption, isInit) {}; + /** + * [How to declare defaultOption]: + * + * (A) If using class declaration in typescript (since echarts 5): + * ```ts + * import {ComponentOption} from '../model/option.js'; + * export interface XxxOption extends ComponentOption { + * aaa: number + * } + * export class XxxModel extends Component { + * static type = 'xxx'; + * static defaultOption: XxxOption = { + * aaa: 123 + * } + * } + * Component.registerClass(XxxModel); + * ``` + * ```ts + * import {inheritDefaultOption} from '../util/component.js'; + * import {XxxModel, XxxOption} from './XxxModel.js'; + * export interface XxxSubOption extends XxxOption { + * bbb: number + * } + * class XxxSubModel extends XxxModel { + * static defaultOption: XxxSubOption = inheritDefaultOption(XxxModel.defaultOption, { + * bbb: 456 + * }) + * fn() { + * let opt = this.getDefaultOption(); + * // opt is {aaa: 123, bbb: 456} + * } + * } + * ``` + * + * (B) If using class extend (previous approach in echarts 3 & 4): + * ```js + * let XxxComponent = Component.extend({ + * defaultOption: { + * xx: 123 + * } + * }) + * ``` + * ```js + * let XxxSubComponent = XxxComponent.extend({ + * defaultOption: { + * yy: 456 + * }, + * fn: function () { + * let opt = this.getDefaultOption(); + * // opt is {xx: 123, yy: 456} + * } + * }) + * ``` + */ + + + ComponentModel.prototype.getDefaultOption = function () { + var ctor = this.constructor; // If using class declaration, it is different to travel super class + // in legacy env and auto merge defaultOption. So if using class + // declaration, defaultOption should be merged manually. + + if (!isExtendedClass(ctor)) { + // When using ts class, defaultOption must be declared as static. + return ctor.defaultOption; + } // FIXME: remove this approach? + + + var fields = inner(this); + + if (!fields.defaultOption) { + var optList = []; + var clz = ctor; + + while (clz) { + var opt = clz.prototype.defaultOption; + opt && optList.push(opt); + clz = clz.superClass; + } + + var defaultOption = {}; + + for (var i = optList.length - 1; i >= 0; i--) { + defaultOption = merge(defaultOption, optList[i], true); + } + + fields.defaultOption = defaultOption; + } + + return fields.defaultOption; + }; + /** + * Notice: always force to input param `useDefault` in case that forget to consider it. + * The same behavior as `modelUtil.parseFinder`. + * + * @param useDefault In many cases like series refer axis and axis refer grid, + * If axis index / axis id not specified, use the first target as default. + * In other cases like dataZoom refer axis, if not specified, measn no refer. + */ + + + ComponentModel.prototype.getReferringComponents = function (mainType, opt) { + var indexKey = mainType + 'Index'; + var idKey = mainType + 'Id'; + return queryReferringComponents(this.ecModel, mainType, { + index: this.get(indexKey, true), + id: this.get(idKey, true) + }, opt); + }; + + ComponentModel.prototype.getBoxLayoutParams = function () { + // Consider itself having box layout configs. + var boxLayoutModel = this; + return { + left: boxLayoutModel.get('left'), + top: boxLayoutModel.get('top'), + right: boxLayoutModel.get('right'), + bottom: boxLayoutModel.get('bottom'), + width: boxLayoutModel.get('width'), + height: boxLayoutModel.get('height') + }; + }; + /** + * Get key for zlevel. + * If developers don't configure zlevel. We will assign zlevel to series based on the key. + * For example, lines with trail effect and progressive series will in an individual zlevel. + */ + + + ComponentModel.prototype.getZLevelKey = function () { + return ''; + }; + + ComponentModel.prototype.setZLevel = function (zlevel) { + this.option.zlevel = zlevel; + }; + + ComponentModel.protoInitialize = function () { + var proto = ComponentModel.prototype; + proto.type = 'component'; + proto.id = ''; + proto.name = ''; + proto.mainType = ''; + proto.subType = ''; + proto.componentIndex = 0; + }(); + + return ComponentModel; + }(Model); + + mountExtend(ComponentModel, Model); + enableClassManagement(ComponentModel); + enableSubTypeDefaulter(ComponentModel); + enableTopologicalTravel(ComponentModel, getDependencies); + + function getDependencies(componentType) { + var deps = []; + each(ComponentModel.getClassesByMainType(componentType), function (clz) { + deps = deps.concat(clz.dependencies || clz.prototype.dependencies || []); + }); // Ensure main type. + + deps = map(deps, function (type) { + return parseClassType(type).main; + }); // Hack dataset for convenience. + + if (componentType !== 'dataset' && indexOf(deps, 'dataset') <= 0) { + deps.unshift('dataset'); + } + + return deps; + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + var platform = ''; // Navigator not exists in node + + if (typeof navigator !== 'undefined') { + /* global navigator */ + platform = navigator.platform || ''; + } + + var decalColor = 'rgba(0, 0, 0, 0.2)'; + var globalDefault = { + darkMode: 'auto', + // backgroundColor: 'rgba(0,0,0,0)', + colorBy: 'series', + color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'], + gradientColor: ['#f6efa6', '#d88273', '#bf444c'], + aria: { + decal: { + decals: [{ + color: decalColor, + dashArrayX: [1, 0], + dashArrayY: [2, 5], + symbolSize: 1, + rotation: Math.PI / 6 + }, { + color: decalColor, + symbol: 'circle', + dashArrayX: [[8, 8], [0, 8, 8, 0]], + dashArrayY: [6, 0], + symbolSize: 0.8 + }, { + color: decalColor, + dashArrayX: [1, 0], + dashArrayY: [4, 3], + rotation: -Math.PI / 4 + }, { + color: decalColor, + dashArrayX: [[6, 6], [0, 6, 6, 0]], + dashArrayY: [6, 0] + }, { + color: decalColor, + dashArrayX: [[1, 0], [1, 6]], + dashArrayY: [1, 0, 6, 0], + rotation: Math.PI / 4 + }, { + color: decalColor, + symbol: 'triangle', + dashArrayX: [[9, 9], [0, 9, 9, 0]], + dashArrayY: [7, 2], + symbolSize: 0.75 + }] + } + }, + // If xAxis and yAxis declared, grid is created by default. + // grid: {}, + textStyle: { + // color: '#000', + // decoration: 'none', + // PENDING + fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif', + // fontFamily: 'Arial, Verdana, sans-serif', + fontSize: 12, + fontStyle: 'normal', + fontWeight: 'normal' + }, + // http://blogs.adobe.com/webplatform/2014/02/24/using-blend-modes-in-html-canvas/ + // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation + // Default is source-over + blendMode: null, + stateAnimation: { + duration: 300, + easing: 'cubicOut' + }, + animation: 'auto', + animationDuration: 1000, + animationDurationUpdate: 500, + animationEasing: 'cubicInOut', + animationEasingUpdate: 'cubicInOut', + animationThreshold: 2000, + // Configuration for progressive/incremental rendering + progressiveThreshold: 3000, + progressive: 400, + // Threshold of if use single hover layer to optimize. + // It is recommended that `hoverLayerThreshold` is equivalent to or less than + // `progressiveThreshold`, otherwise hover will cause restart of progressive, + // which is unexpected. + // see example . + hoverLayerThreshold: 3000, + // See: module:echarts/scale/Time + useUTC: false + }; + + var VISUAL_DIMENSIONS = createHashMap(['tooltip', 'label', 'itemName', 'itemId', 'itemGroupId', 'seriesName']); + var SOURCE_FORMAT_ORIGINAL = 'original'; + var SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows'; + var SOURCE_FORMAT_OBJECT_ROWS = 'objectRows'; + var SOURCE_FORMAT_KEYED_COLUMNS = 'keyedColumns'; + var SOURCE_FORMAT_TYPED_ARRAY = 'typedArray'; + var SOURCE_FORMAT_UNKNOWN = 'unknown'; + var SERIES_LAYOUT_BY_COLUMN = 'column'; + var SERIES_LAYOUT_BY_ROW = 'row'; + + var BE_ORDINAL = { + Must: 1, + Might: 2, + Not: 3 // Other cases + + }; + var innerGlobalModel = makeInner(); + /** + * MUST be called before mergeOption of all series. + */ + + function resetSourceDefaulter(ecModel) { + // `datasetMap` is used to make default encode. + innerGlobalModel(ecModel).datasetMap = createHashMap(); + } + /** + * [The strategy of the arrengment of data dimensions for dataset]: + * "value way": all axes are non-category axes. So series one by one take + * several (the number is coordSysDims.length) dimensions from dataset. + * The result of data arrengment of data dimensions like: + * | ser0_x | ser0_y | ser1_x | ser1_y | ser2_x | ser2_y | + * "category way": at least one axis is category axis. So the the first data + * dimension is always mapped to the first category axis and shared by + * all of the series. The other data dimensions are taken by series like + * "value way" does. + * The result of data arrengment of data dimensions like: + * | ser_shared_x | ser0_y | ser1_y | ser2_y | + * + * @return encode Never be `null/undefined`. + */ + + function makeSeriesEncodeForAxisCoordSys(coordDimensions, seriesModel, source) { + var encode = {}; + var datasetModel = querySeriesUpstreamDatasetModel(seriesModel); // Currently only make default when using dataset, util more reqirements occur. + + if (!datasetModel || !coordDimensions) { + return encode; + } + + var encodeItemName = []; + var encodeSeriesName = []; + var ecModel = seriesModel.ecModel; + var datasetMap = innerGlobalModel(ecModel).datasetMap; + var key = datasetModel.uid + '_' + source.seriesLayoutBy; + var baseCategoryDimIndex; + var categoryWayValueDimStart; + coordDimensions = coordDimensions.slice(); + each(coordDimensions, function (coordDimInfoLoose, coordDimIdx) { + var coordDimInfo = isObject(coordDimInfoLoose) ? coordDimInfoLoose : coordDimensions[coordDimIdx] = { + name: coordDimInfoLoose + }; + + if (coordDimInfo.type === 'ordinal' && baseCategoryDimIndex == null) { + baseCategoryDimIndex = coordDimIdx; + categoryWayValueDimStart = getDataDimCountOnCoordDim(coordDimInfo); + } + + encode[coordDimInfo.name] = []; + }); + var datasetRecord = datasetMap.get(key) || datasetMap.set(key, { + categoryWayDim: categoryWayValueDimStart, + valueWayDim: 0 + }); // TODO + // Auto detect first time axis and do arrangement. + + each(coordDimensions, function (coordDimInfo, coordDimIdx) { + var coordDimName = coordDimInfo.name; + var count = getDataDimCountOnCoordDim(coordDimInfo); // In value way. + + if (baseCategoryDimIndex == null) { + var start = datasetRecord.valueWayDim; + pushDim(encode[coordDimName], start, count); + pushDim(encodeSeriesName, start, count); + datasetRecord.valueWayDim += count; // ??? TODO give a better default series name rule? + // especially when encode x y specified. + // consider: when mutiple series share one dimension + // category axis, series name should better use + // the other dimsion name. On the other hand, use + // both dimensions name. + } // In category way, the first category axis. + else if (baseCategoryDimIndex === coordDimIdx) { + pushDim(encode[coordDimName], 0, count); + pushDim(encodeItemName, 0, count); + } // In category way, the other axis. + else { + var start = datasetRecord.categoryWayDim; + pushDim(encode[coordDimName], start, count); + pushDim(encodeSeriesName, start, count); + datasetRecord.categoryWayDim += count; + } + }); + + function pushDim(dimIdxArr, idxFrom, idxCount) { + for (var i = 0; i < idxCount; i++) { + dimIdxArr.push(idxFrom + i); + } + } + + function getDataDimCountOnCoordDim(coordDimInfo) { + var dimsDef = coordDimInfo.dimsDef; + return dimsDef ? dimsDef.length : 1; + } + + encodeItemName.length && (encode.itemName = encodeItemName); + encodeSeriesName.length && (encode.seriesName = encodeSeriesName); + return encode; + } + /** + * Work for data like [{name: ..., value: ...}, ...]. + * + * @return encode Never be `null/undefined`. + */ + + function makeSeriesEncodeForNameBased(seriesModel, source, dimCount) { + var encode = {}; + var datasetModel = querySeriesUpstreamDatasetModel(seriesModel); // Currently only make default when using dataset, util more reqirements occur. + + if (!datasetModel) { + return encode; + } + + var sourceFormat = source.sourceFormat; + var dimensionsDefine = source.dimensionsDefine; + var potentialNameDimIndex; + + if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS || sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) { + each(dimensionsDefine, function (dim, idx) { + if ((isObject(dim) ? dim.name : dim) === 'name') { + potentialNameDimIndex = idx; + } + }); + } + + var idxResult = function () { + var idxRes0 = {}; + var idxRes1 = {}; + var guessRecords = []; // 5 is an experience value. + + for (var i = 0, len = Math.min(5, dimCount); i < len; i++) { + var guessResult = doGuessOrdinal(source.data, sourceFormat, source.seriesLayoutBy, dimensionsDefine, source.startIndex, i); + guessRecords.push(guessResult); + var isPureNumber = guessResult === BE_ORDINAL.Not; // [Strategy of idxRes0]: find the first BE_ORDINAL.Not as the value dim, + // and then find a name dim with the priority: + // "BE_ORDINAL.Might|BE_ORDINAL.Must" > "other dim" > "the value dim itself". + + if (isPureNumber && idxRes0.v == null && i !== potentialNameDimIndex) { + idxRes0.v = i; + } + + if (idxRes0.n == null || idxRes0.n === idxRes0.v || !isPureNumber && guessRecords[idxRes0.n] === BE_ORDINAL.Not) { + idxRes0.n = i; + } + + if (fulfilled(idxRes0) && guessRecords[idxRes0.n] !== BE_ORDINAL.Not) { + return idxRes0; + } // [Strategy of idxRes1]: if idxRes0 not satisfied (that is, no BE_ORDINAL.Not), + // find the first BE_ORDINAL.Might as the value dim, + // and then find a name dim with the priority: + // "other dim" > "the value dim itself". + // That is for backward compat: number-like (e.g., `'3'`, `'55'`) can be + // treated as number. + + + if (!isPureNumber) { + if (guessResult === BE_ORDINAL.Might && idxRes1.v == null && i !== potentialNameDimIndex) { + idxRes1.v = i; + } + + if (idxRes1.n == null || idxRes1.n === idxRes1.v) { + idxRes1.n = i; + } + } + } + + function fulfilled(idxResult) { + return idxResult.v != null && idxResult.n != null; + } + + return fulfilled(idxRes0) ? idxRes0 : fulfilled(idxRes1) ? idxRes1 : null; + }(); + + if (idxResult) { + encode.value = [idxResult.v]; // `potentialNameDimIndex` has highest priority. + + var nameDimIndex = potentialNameDimIndex != null ? potentialNameDimIndex : idxResult.n; // By default, label use itemName in charts. + // So we dont set encodeLabel here. + + encode.itemName = [nameDimIndex]; + encode.seriesName = [nameDimIndex]; + } + + return encode; + } + /** + * @return If return null/undefined, indicate that should not use datasetModel. + */ + + function querySeriesUpstreamDatasetModel(seriesModel) { + // Caution: consider the scenario: + // A dataset is declared and a series is not expected to use the dataset, + // and at the beginning `setOption({series: { noData })` (just prepare other + // option but no data), then `setOption({series: {data: [...]}); In this case, + // the user should set an empty array to avoid that dataset is used by default. + var thisData = seriesModel.get('data', true); + + if (!thisData) { + return queryReferringComponents(seriesModel.ecModel, 'dataset', { + index: seriesModel.get('datasetIndex', true), + id: seriesModel.get('datasetId', true) + }, SINGLE_REFERRING).models[0]; + } + } + /** + * @return Always return an array event empty. + */ + + function queryDatasetUpstreamDatasetModels(datasetModel) { + // Only these attributes declared, we by defualt reference to `datasetIndex: 0`. + // Otherwise, no reference. + if (!datasetModel.get('transform', true) && !datasetModel.get('fromTransformResult', true)) { + return []; + } + + return queryReferringComponents(datasetModel.ecModel, 'dataset', { + index: datasetModel.get('fromDatasetIndex', true), + id: datasetModel.get('fromDatasetId', true) + }, SINGLE_REFERRING).models; + } + /** + * The rule should not be complex, otherwise user might not + * be able to known where the data is wrong. + * The code is ugly, but how to make it neat? + */ + + function guessOrdinal(source, dimIndex) { + return doGuessOrdinal(source.data, source.sourceFormat, source.seriesLayoutBy, source.dimensionsDefine, source.startIndex, dimIndex); + } // dimIndex may be overflow source data. + // return {BE_ORDINAL} + + function doGuessOrdinal(data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex) { + var result; // Experience value. + + var maxLoop = 5; + + if (isTypedArray(data)) { + return BE_ORDINAL.Not; + } // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine + // always exists in source. + + + var dimName; + var dimType; + + if (dimensionsDefine) { + var dimDefItem = dimensionsDefine[dimIndex]; + + if (isObject(dimDefItem)) { + dimName = dimDefItem.name; + dimType = dimDefItem.type; + } else if (isString(dimDefItem)) { + dimName = dimDefItem; + } + } + + if (dimType != null) { + return dimType === 'ordinal' ? BE_ORDINAL.Must : BE_ORDINAL.Not; + } + + if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) { + var dataArrayRows = data; + + if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) { + var sample = dataArrayRows[dimIndex]; + + for (var i = 0; i < (sample || []).length && i < maxLoop; i++) { + if ((result = detectValue(sample[startIndex + i])) != null) { + return result; + } + } + } else { + for (var i = 0; i < dataArrayRows.length && i < maxLoop; i++) { + var row = dataArrayRows[startIndex + i]; + + if (row && (result = detectValue(row[dimIndex])) != null) { + return result; + } + } + } + } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) { + var dataObjectRows = data; + + if (!dimName) { + return BE_ORDINAL.Not; + } + + for (var i = 0; i < dataObjectRows.length && i < maxLoop; i++) { + var item = dataObjectRows[i]; + + if (item && (result = detectValue(item[dimName])) != null) { + return result; + } + } + } else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) { + var dataKeyedColumns = data; + + if (!dimName) { + return BE_ORDINAL.Not; + } + + var sample = dataKeyedColumns[dimName]; + + if (!sample || isTypedArray(sample)) { + return BE_ORDINAL.Not; + } + + for (var i = 0; i < sample.length && i < maxLoop; i++) { + if ((result = detectValue(sample[i])) != null) { + return result; + } + } + } else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) { + var dataOriginal = data; + + for (var i = 0; i < dataOriginal.length && i < maxLoop; i++) { + var item = dataOriginal[i]; + var val = getDataItemValue(item); + + if (!isArray(val)) { + return BE_ORDINAL.Not; + } + + if ((result = detectValue(val[dimIndex])) != null) { + return result; + } + } + } + + function detectValue(val) { + var beStr = isString(val); // Consider usage convenience, '1', '2' will be treated as "number". + // `isFinit('')` get `true`. + + if (val != null && isFinite(val) && val !== '') { + return beStr ? BE_ORDINAL.Might : BE_ORDINAL.Not; + } else if (beStr && val !== '-') { + return BE_ORDINAL.Must; + } + } + + return BE_ORDINAL.Not; + } + + var internalOptionCreatorMap = createHashMap(); + function registerInternalOptionCreator(mainType, creator) { + assert(internalOptionCreatorMap.get(mainType) == null && creator); + internalOptionCreatorMap.set(mainType, creator); + } + function concatInternalOptions(ecModel, mainType, newCmptOptionList) { + var internalOptionCreator = internalOptionCreatorMap.get(mainType); + + if (!internalOptionCreator) { + return newCmptOptionList; + } + + var internalOptions = internalOptionCreator(ecModel); + + if (!internalOptions) { + return newCmptOptionList; + } + + if ("development" !== 'production') { + for (var i = 0; i < internalOptions.length; i++) { + assert(isComponentIdInternal(internalOptions[i])); + } + } + + return newCmptOptionList.concat(internalOptions); + } + + var innerColor = makeInner(); + var innerDecal = makeInner(); + + var PaletteMixin = + /** @class */ + function () { + function PaletteMixin() {} + + PaletteMixin.prototype.getColorFromPalette = function (name, scope, requestNum) { + var defaultPalette = normalizeToArray(this.get('color', true)); + var layeredPalette = this.get('colorLayer', true); + return getFromPalette(this, innerColor, defaultPalette, layeredPalette, name, scope, requestNum); + }; + + PaletteMixin.prototype.clearColorPalette = function () { + clearPalette(this, innerColor); + }; + + return PaletteMixin; + }(); + + function getDecalFromPalette(ecModel, name, scope, requestNum) { + var defaultDecals = normalizeToArray(ecModel.get(['aria', 'decal', 'decals'])); + return getFromPalette(ecModel, innerDecal, defaultDecals, null, name, scope, requestNum); + } + + function getNearestPalette(palettes, requestColorNum) { + var paletteNum = palettes.length; // TODO palettes must be in order + + for (var i = 0; i < paletteNum; i++) { + if (palettes[i].length > requestColorNum) { + return palettes[i]; + } + } + + return palettes[paletteNum - 1]; + } + /** + * @param name MUST NOT be null/undefined. Otherwise call this function + * twise with the same parameters will get different result. + * @param scope default this. + * @return Can be null/undefined + */ + + + function getFromPalette(that, inner, defaultPalette, layeredPalette, name, scope, requestNum) { + scope = scope || that; + var scopeFields = inner(scope); + var paletteIdx = scopeFields.paletteIdx || 0; + var paletteNameMap = scopeFields.paletteNameMap = scopeFields.paletteNameMap || {}; // Use `hasOwnProperty` to avoid conflict with Object.prototype. + + if (paletteNameMap.hasOwnProperty(name)) { + return paletteNameMap[name]; + } + + var palette = requestNum == null || !layeredPalette ? defaultPalette : getNearestPalette(layeredPalette, requestNum); // In case can't find in layered color palette. + + palette = palette || defaultPalette; + + if (!palette || !palette.length) { + return; + } + + var pickedPaletteItem = palette[paletteIdx]; + + if (name) { + paletteNameMap[name] = pickedPaletteItem; + } + + scopeFields.paletteIdx = (paletteIdx + 1) % palette.length; + return pickedPaletteItem; + } + + function clearPalette(that, inner) { + inner(that).paletteIdx = 0; + inner(that).paletteNameMap = {}; + } + + // Internal method names: + // ----------------------- + + var reCreateSeriesIndices; + var assertSeriesInitialized; + var initBase; + var OPTION_INNER_KEY = '\0_ec_inner'; + var OPTION_INNER_VALUE = 1; + var BUITIN_COMPONENTS_MAP = { + grid: 'GridComponent', + polar: 'PolarComponent', + geo: 'GeoComponent', + singleAxis: 'SingleAxisComponent', + parallel: 'ParallelComponent', + calendar: 'CalendarComponent', + graphic: 'GraphicComponent', + toolbox: 'ToolboxComponent', + tooltip: 'TooltipComponent', + axisPointer: 'AxisPointerComponent', + brush: 'BrushComponent', + title: 'TitleComponent', + timeline: 'TimelineComponent', + markPoint: 'MarkPointComponent', + markLine: 'MarkLineComponent', + markArea: 'MarkAreaComponent', + legend: 'LegendComponent', + dataZoom: 'DataZoomComponent', + visualMap: 'VisualMapComponent', + // aria: 'AriaComponent', + // dataset: 'DatasetComponent', + // Dependencies + xAxis: 'GridComponent', + yAxis: 'GridComponent', + angleAxis: 'PolarComponent', + radiusAxis: 'PolarComponent' + }; + var BUILTIN_CHARTS_MAP = { + line: 'LineChart', + bar: 'BarChart', + pie: 'PieChart', + scatter: 'ScatterChart', + radar: 'RadarChart', + map: 'MapChart', + tree: 'TreeChart', + treemap: 'TreemapChart', + graph: 'GraphChart', + gauge: 'GaugeChart', + funnel: 'FunnelChart', + parallel: 'ParallelChart', + sankey: 'SankeyChart', + boxplot: 'BoxplotChart', + candlestick: 'CandlestickChart', + effectScatter: 'EffectScatterChart', + lines: 'LinesChart', + heatmap: 'HeatmapChart', + pictorialBar: 'PictorialBarChart', + themeRiver: 'ThemeRiverChart', + sunburst: 'SunburstChart', + custom: 'CustomChart' + }; + var componetsMissingLogPrinted = {}; + + function checkMissingComponents(option) { + each(option, function (componentOption, mainType) { + if (!ComponentModel.hasClass(mainType)) { + var componentImportName = BUITIN_COMPONENTS_MAP[mainType]; + + if (componentImportName && !componetsMissingLogPrinted[componentImportName]) { + error("Component " + mainType + " is used but not imported.\nimport { " + componentImportName + " } from 'echarts/components';\necharts.use([" + componentImportName + "]);"); + componetsMissingLogPrinted[componentImportName] = true; + } + } + }); + } + + var GlobalModel = + /** @class */ + function (_super) { + __extends(GlobalModel, _super); + + function GlobalModel() { + return _super !== null && _super.apply(this, arguments) || this; + } + + GlobalModel.prototype.init = function (option, parentModel, ecModel, theme, locale, optionManager) { + theme = theme || {}; + this.option = null; // Mark as not initialized. + + this._theme = new Model(theme); + this._locale = new Model(locale); + this._optionManager = optionManager; + }; + + GlobalModel.prototype.setOption = function (option, opts, optionPreprocessorFuncs) { + if ("development" !== 'production') { + assert(option != null, 'option is null/undefined'); + assert(option[OPTION_INNER_KEY] !== OPTION_INNER_VALUE, 'please use chart.getOption()'); + } + + var innerOpt = normalizeSetOptionInput(opts); + + this._optionManager.setOption(option, optionPreprocessorFuncs, innerOpt); + + this._resetOption(null, innerOpt); + }; + /** + * @param type null/undefined: reset all. + * 'recreate': force recreate all. + * 'timeline': only reset timeline option + * 'media': only reset media query option + * @return Whether option changed. + */ + + + GlobalModel.prototype.resetOption = function (type, opt) { + return this._resetOption(type, normalizeSetOptionInput(opt)); + }; + + GlobalModel.prototype._resetOption = function (type, opt) { + var optionChanged = false; + var optionManager = this._optionManager; + + if (!type || type === 'recreate') { + var baseOption = optionManager.mountOption(type === 'recreate'); + + if ("development" !== 'production') { + checkMissingComponents(baseOption); + } + + if (!this.option || type === 'recreate') { + initBase(this, baseOption); + } else { + this.restoreData(); + + this._mergeOption(baseOption, opt); + } + + optionChanged = true; + } + + if (type === 'timeline' || type === 'media') { + this.restoreData(); + } // By design, if `setOption(option2)` at the second time, and `option2` is a `ECUnitOption`, + // it should better not have the same props with `MediaUnit['option']`. + // Becuase either `option2` or `MediaUnit['option']` will be always merged to "current option" + // rather than original "baseOption". If they both override a prop, the result might be + // unexpected when media state changed after `setOption` called. + // If we really need to modify a props in each `MediaUnit['option']`, use the full version + // (`{baseOption, media}`) in `setOption`. + // For `timeline`, the case is the same. + + + if (!type || type === 'recreate' || type === 'timeline') { + var timelineOption = optionManager.getTimelineOption(this); + + if (timelineOption) { + optionChanged = true; + + this._mergeOption(timelineOption, opt); + } + } + + if (!type || type === 'recreate' || type === 'media') { + var mediaOptions = optionManager.getMediaOption(this); + + if (mediaOptions.length) { + each(mediaOptions, function (mediaOption) { + optionChanged = true; + + this._mergeOption(mediaOption, opt); + }, this); + } + } + + return optionChanged; + }; + + GlobalModel.prototype.mergeOption = function (option) { + this._mergeOption(option, null); + }; + + GlobalModel.prototype._mergeOption = function (newOption, opt) { + var option = this.option; + var componentsMap = this._componentsMap; + var componentsCount = this._componentsCount; + var newCmptTypes = []; + var newCmptTypeMap = createHashMap(); + var replaceMergeMainTypeMap = opt && opt.replaceMergeMainTypeMap; + resetSourceDefaulter(this); // If no component class, merge directly. + // For example: color, animaiton options, etc. + + each(newOption, function (componentOption, mainType) { + if (componentOption == null) { + return; + } + + if (!ComponentModel.hasClass(mainType)) { + // globalSettingTask.dirty(); + option[mainType] = option[mainType] == null ? clone(componentOption) : merge(option[mainType], componentOption, true); + } else if (mainType) { + newCmptTypes.push(mainType); + newCmptTypeMap.set(mainType, true); + } + }); + + if (replaceMergeMainTypeMap) { + // If there is a mainType `xxx` in `replaceMerge` but not declared in option, + // we trade it as it is declared in option as `{xxx: []}`. Because: + // (1) for normal merge, `{xxx: null/undefined}` are the same meaning as `{xxx: []}`. + // (2) some preprocessor may convert some of `{xxx: null/undefined}` to `{xxx: []}`. + replaceMergeMainTypeMap.each(function (val, mainTypeInReplaceMerge) { + if (ComponentModel.hasClass(mainTypeInReplaceMerge) && !newCmptTypeMap.get(mainTypeInReplaceMerge)) { + newCmptTypes.push(mainTypeInReplaceMerge); + newCmptTypeMap.set(mainTypeInReplaceMerge, true); + } + }); + } + + ComponentModel.topologicalTravel(newCmptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this); + + function visitComponent(mainType) { + var newCmptOptionList = concatInternalOptions(this, mainType, normalizeToArray(newOption[mainType])); + var oldCmptList = componentsMap.get(mainType); + var mergeMode = // `!oldCmptList` means init. See the comment in `mappingToExists` + !oldCmptList ? 'replaceAll' : replaceMergeMainTypeMap && replaceMergeMainTypeMap.get(mainType) ? 'replaceMerge' : 'normalMerge'; + var mappingResult = mappingToExists(oldCmptList, newCmptOptionList, mergeMode); // Set mainType and complete subType. + + setComponentTypeToKeyInfo(mappingResult, mainType, ComponentModel); // Empty it before the travel, in order to prevent `this._componentsMap` + // from being used in the `init`/`mergeOption`/`optionUpdated` of some + // components, which is probably incorrect logic. + + option[mainType] = null; + componentsMap.set(mainType, null); + componentsCount.set(mainType, 0); + var optionsByMainType = []; + var cmptsByMainType = []; + var cmptsCountByMainType = 0; + var tooltipExists; + var tooltipWarningLogged; + each(mappingResult, function (resultItem, index) { + var componentModel = resultItem.existing; + var newCmptOption = resultItem.newOption; + + if (!newCmptOption) { + if (componentModel) { + // Consider where is no new option and should be merged using {}, + // see removeEdgeAndAdd in topologicalTravel and + // ComponentModel.getAllClassMainTypes. + componentModel.mergeOption({}, this); + componentModel.optionUpdated({}, false); + } // If no both `resultItem.exist` and `resultItem.option`, + // either it is in `replaceMerge` and not matched by any id, + // or it has been removed in previous `replaceMerge` and left a "hole" in this component index. + + } else { + var isSeriesType = mainType === 'series'; + var ComponentModelClass = ComponentModel.getClass(mainType, resultItem.keyInfo.subType, !isSeriesType // Give a more detailed warn later if series don't exists + ); + + if (!ComponentModelClass) { + if ("development" !== 'production') { + var subType = resultItem.keyInfo.subType; + var seriesImportName = BUILTIN_CHARTS_MAP[subType]; + + if (!componetsMissingLogPrinted[subType]) { + componetsMissingLogPrinted[subType] = true; + + if (seriesImportName) { + error("Series " + subType + " is used but not imported.\nimport { " + seriesImportName + " } from 'echarts/charts';\necharts.use([" + seriesImportName + "]);"); + } else { + error("Unkown series " + subType); + } + } + } + + return; + } // TODO Before multiple tooltips get supported, we do this check to avoid unexpected exception. + + + if (mainType === 'tooltip') { + if (tooltipExists) { + if ("development" !== 'production') { + if (!tooltipWarningLogged) { + warn('Currently only one tooltip component is allowed.'); + tooltipWarningLogged = true; + } + } + + return; + } + + tooltipExists = true; + } + + if (componentModel && componentModel.constructor === ComponentModelClass) { + componentModel.name = resultItem.keyInfo.name; // componentModel.settingTask && componentModel.settingTask.dirty(); + + componentModel.mergeOption(newCmptOption, this); + componentModel.optionUpdated(newCmptOption, false); + } else { + // PENDING Global as parent ? + var extraOpt = extend({ + componentIndex: index + }, resultItem.keyInfo); + componentModel = new ComponentModelClass(newCmptOption, this, this, extraOpt); // Assign `keyInfo` + + extend(componentModel, extraOpt); + + if (resultItem.brandNew) { + componentModel.__requireNewView = true; + } + + componentModel.init(newCmptOption, this, this); // Call optionUpdated after init. + // newCmptOption has been used as componentModel.option + // and may be merged with theme and default, so pass null + // to avoid confusion. + + componentModel.optionUpdated(null, true); + } + } + + if (componentModel) { + optionsByMainType.push(componentModel.option); + cmptsByMainType.push(componentModel); + cmptsCountByMainType++; + } else { + // Always do assign to avoid elided item in array. + optionsByMainType.push(void 0); + cmptsByMainType.push(void 0); + } + }, this); + option[mainType] = optionsByMainType; + componentsMap.set(mainType, cmptsByMainType); + componentsCount.set(mainType, cmptsCountByMainType); // Backup series for filtering. + + if (mainType === 'series') { + reCreateSeriesIndices(this); + } + } // If no series declared, ensure `_seriesIndices` initialized. + + + if (!this._seriesIndices) { + reCreateSeriesIndices(this); + } + }; + /** + * Get option for output (cloned option and inner info removed) + */ + + + GlobalModel.prototype.getOption = function () { + var option = clone(this.option); + each(option, function (optInMainType, mainType) { + if (ComponentModel.hasClass(mainType)) { + var opts = normalizeToArray(optInMainType); // Inner cmpts need to be removed. + // Inner cmpts might not be at last since ec5.0, but still + // compatible for users: if inner cmpt at last, splice the returned array. + + var realLen = opts.length; + var metNonInner = false; + + for (var i = realLen - 1; i >= 0; i--) { + // Remove options with inner id. + if (opts[i] && !isComponentIdInternal(opts[i])) { + metNonInner = true; + } else { + opts[i] = null; + !metNonInner && realLen--; + } + } + + opts.length = realLen; + option[mainType] = opts; + } + }); + delete option[OPTION_INNER_KEY]; + return option; + }; + + GlobalModel.prototype.getTheme = function () { + return this._theme; + }; + + GlobalModel.prototype.getLocaleModel = function () { + return this._locale; + }; + + GlobalModel.prototype.setUpdatePayload = function (payload) { + this._payload = payload; + }; + + GlobalModel.prototype.getUpdatePayload = function () { + return this._payload; + }; + /** + * @param idx If not specified, return the first one. + */ + + + GlobalModel.prototype.getComponent = function (mainType, idx) { + var list = this._componentsMap.get(mainType); + + if (list) { + var cmpt = list[idx || 0]; + + if (cmpt) { + return cmpt; + } else if (idx == null) { + for (var i = 0; i < list.length; i++) { + if (list[i]) { + return list[i]; + } + } + } + } + }; + /** + * @return Never be null/undefined. + */ + + + GlobalModel.prototype.queryComponents = function (condition) { + var mainType = condition.mainType; + + if (!mainType) { + return []; + } + + var index = condition.index; + var id = condition.id; + var name = condition.name; + + var cmpts = this._componentsMap.get(mainType); + + if (!cmpts || !cmpts.length) { + return []; + } + + var result; + + if (index != null) { + result = []; + each(normalizeToArray(index), function (idx) { + cmpts[idx] && result.push(cmpts[idx]); + }); + } else if (id != null) { + result = queryByIdOrName('id', id, cmpts); + } else if (name != null) { + result = queryByIdOrName('name', name, cmpts); + } else { + // Return all non-empty components in that mainType + result = filter(cmpts, function (cmpt) { + return !!cmpt; + }); + } + + return filterBySubType(result, condition); + }; + /** + * The interface is different from queryComponents, + * which is convenient for inner usage. + * + * @usage + * let result = findComponents( + * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}} + * ); + * let result = findComponents( + * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}} + * ); + * let result = findComponents( + * {mainType: 'series', + * filter: function (model, index) {...}} + * ); + * // result like [component0, componnet1, ...] + */ + + + GlobalModel.prototype.findComponents = function (condition) { + var query = condition.query; + var mainType = condition.mainType; + var queryCond = getQueryCond(query); + var result = queryCond ? this.queryComponents(queryCond) // Retrieve all non-empty components. + : filter(this._componentsMap.get(mainType), function (cmpt) { + return !!cmpt; + }); + return doFilter(filterBySubType(result, condition)); + + function getQueryCond(q) { + var indexAttr = mainType + 'Index'; + var idAttr = mainType + 'Id'; + var nameAttr = mainType + 'Name'; + return q && (q[indexAttr] != null || q[idAttr] != null || q[nameAttr] != null) ? { + mainType: mainType, + // subType will be filtered finally. + index: q[indexAttr], + id: q[idAttr], + name: q[nameAttr] + } : null; + } + + function doFilter(res) { + return condition.filter ? filter(res, condition.filter) : res; + } + }; + + GlobalModel.prototype.eachComponent = function (mainType, cb, context) { + var componentsMap = this._componentsMap; + + if (isFunction(mainType)) { + var ctxForAll_1 = cb; + var cbForAll_1 = mainType; + componentsMap.each(function (cmpts, componentType) { + for (var i = 0; cmpts && i < cmpts.length; i++) { + var cmpt = cmpts[i]; + cmpt && cbForAll_1.call(ctxForAll_1, componentType, cmpt, cmpt.componentIndex); + } + }); + } else { + var cmpts = isString(mainType) ? componentsMap.get(mainType) : isObject(mainType) ? this.findComponents(mainType) : null; + + for (var i = 0; cmpts && i < cmpts.length; i++) { + var cmpt = cmpts[i]; + cmpt && cb.call(context, cmpt, cmpt.componentIndex); + } + } + }; + /** + * Get series list before filtered by name. + */ + + + GlobalModel.prototype.getSeriesByName = function (name) { + var nameStr = convertOptionIdName(name, null); + return filter(this._componentsMap.get('series'), function (oneSeries) { + return !!oneSeries && nameStr != null && oneSeries.name === nameStr; + }); + }; + /** + * Get series list before filtered by index. + */ + + + GlobalModel.prototype.getSeriesByIndex = function (seriesIndex) { + return this._componentsMap.get('series')[seriesIndex]; + }; + /** + * Get series list before filtered by type. + * FIXME: rename to getRawSeriesByType? + */ + + + GlobalModel.prototype.getSeriesByType = function (subType) { + return filter(this._componentsMap.get('series'), function (oneSeries) { + return !!oneSeries && oneSeries.subType === subType; + }); + }; + /** + * Get all series before filtered. + */ + + + GlobalModel.prototype.getSeries = function () { + return filter(this._componentsMap.get('series'), function (oneSeries) { + return !!oneSeries; + }); + }; + /** + * Count series before filtered. + */ + + + GlobalModel.prototype.getSeriesCount = function () { + return this._componentsCount.get('series'); + }; + /** + * After filtering, series may be different + * frome raw series. + */ + + + GlobalModel.prototype.eachSeries = function (cb, context) { + assertSeriesInitialized(this); + each(this._seriesIndices, function (rawSeriesIndex) { + var series = this._componentsMap.get('series')[rawSeriesIndex]; + + cb.call(context, series, rawSeriesIndex); + }, this); + }; + /** + * Iterate raw series before filtered. + * + * @param {Function} cb + * @param {*} context + */ + + + GlobalModel.prototype.eachRawSeries = function (cb, context) { + each(this._componentsMap.get('series'), function (series) { + series && cb.call(context, series, series.componentIndex); + }); + }; + /** + * After filtering, series may be different. + * frome raw series. + */ + + + GlobalModel.prototype.eachSeriesByType = function (subType, cb, context) { + assertSeriesInitialized(this); + each(this._seriesIndices, function (rawSeriesIndex) { + var series = this._componentsMap.get('series')[rawSeriesIndex]; + + if (series.subType === subType) { + cb.call(context, series, rawSeriesIndex); + } + }, this); + }; + /** + * Iterate raw series before filtered of given type. + */ + + + GlobalModel.prototype.eachRawSeriesByType = function (subType, cb, context) { + return each(this.getSeriesByType(subType), cb, context); + }; + + GlobalModel.prototype.isSeriesFiltered = function (seriesModel) { + assertSeriesInitialized(this); + return this._seriesIndicesMap.get(seriesModel.componentIndex) == null; + }; + + GlobalModel.prototype.getCurrentSeriesIndices = function () { + return (this._seriesIndices || []).slice(); + }; + + GlobalModel.prototype.filterSeries = function (cb, context) { + assertSeriesInitialized(this); + var newSeriesIndices = []; + each(this._seriesIndices, function (seriesRawIdx) { + var series = this._componentsMap.get('series')[seriesRawIdx]; + + cb.call(context, series, seriesRawIdx) && newSeriesIndices.push(seriesRawIdx); + }, this); + this._seriesIndices = newSeriesIndices; + this._seriesIndicesMap = createHashMap(newSeriesIndices); + }; + + GlobalModel.prototype.restoreData = function (payload) { + reCreateSeriesIndices(this); + var componentsMap = this._componentsMap; + var componentTypes = []; + componentsMap.each(function (components, componentType) { + if (ComponentModel.hasClass(componentType)) { + componentTypes.push(componentType); + } + }); + ComponentModel.topologicalTravel(componentTypes, ComponentModel.getAllClassMainTypes(), function (componentType) { + each(componentsMap.get(componentType), function (component) { + if (component && (componentType !== 'series' || !isNotTargetSeries(component, payload))) { + component.restoreData(); + } + }); + }); + }; + + GlobalModel.internalField = function () { + reCreateSeriesIndices = function (ecModel) { + var seriesIndices = ecModel._seriesIndices = []; + each(ecModel._componentsMap.get('series'), function (series) { + // series may have been removed by `replaceMerge`. + series && seriesIndices.push(series.componentIndex); + }); + ecModel._seriesIndicesMap = createHashMap(seriesIndices); + }; + + assertSeriesInitialized = function (ecModel) { + // Components that use _seriesIndices should depends on series component, + // which make sure that their initialization is after series. + if ("development" !== 'production') { + if (!ecModel._seriesIndices) { + throw new Error('Option should contains series.'); + } + } + }; + + initBase = function (ecModel, baseOption) { + // Using OPTION_INNER_KEY to mark that this option can not be used outside, + // i.e. `chart.setOption(chart.getModel().option);` is forbiden. + ecModel.option = {}; + ecModel.option[OPTION_INNER_KEY] = OPTION_INNER_VALUE; // Init with series: [], in case of calling findSeries method + // before series initialized. + + ecModel._componentsMap = createHashMap({ + series: [] + }); + ecModel._componentsCount = createHashMap(); // If user spefied `option.aria`, aria will be enable. This detection should be + // performed before theme and globalDefault merge. + + var airaOption = baseOption.aria; + + if (isObject(airaOption) && airaOption.enabled == null) { + airaOption.enabled = true; + } + + mergeTheme(baseOption, ecModel._theme.option); // TODO Needs clone when merging to the unexisted property + + merge(baseOption, globalDefault, false); + + ecModel._mergeOption(baseOption, null); + }; + }(); + + return GlobalModel; + }(Model); + + function isNotTargetSeries(seriesModel, payload) { + if (payload) { + var index = payload.seriesIndex; + var id = payload.seriesId; + var name_1 = payload.seriesName; + return index != null && seriesModel.componentIndex !== index || id != null && seriesModel.id !== id || name_1 != null && seriesModel.name !== name_1; + } + } + + function mergeTheme(option, theme) { + // PENDING + // NOT use `colorLayer` in theme if option has `color` + var notMergeColorLayer = option.color && !option.colorLayer; + each(theme, function (themeItem, name) { + if (name === 'colorLayer' && notMergeColorLayer) { + return; + } // If it is component model mainType, the model handles that merge later. + // otherwise, merge them here. + + + if (!ComponentModel.hasClass(name)) { + if (typeof themeItem === 'object') { + option[name] = !option[name] ? clone(themeItem) : merge(option[name], themeItem, false); + } else { + if (option[name] == null) { + option[name] = themeItem; + } + } + } + }); + } + + function queryByIdOrName(attr, idOrName, cmpts) { + // Here is a break from echarts4: string and number are + // treated as equal. + if (isArray(idOrName)) { + var keyMap_1 = createHashMap(); + each(idOrName, function (idOrNameItem) { + if (idOrNameItem != null) { + var idName = convertOptionIdName(idOrNameItem, null); + idName != null && keyMap_1.set(idOrNameItem, true); + } + }); + return filter(cmpts, function (cmpt) { + return cmpt && keyMap_1.get(cmpt[attr]); + }); + } else { + var idName_1 = convertOptionIdName(idOrName, null); + return filter(cmpts, function (cmpt) { + return cmpt && idName_1 != null && cmpt[attr] === idName_1; + }); + } + } + + function filterBySubType(components, condition) { + // Using hasOwnProperty for restrict. Consider + // subType is undefined in user payload. + return condition.hasOwnProperty('subType') ? filter(components, function (cmpt) { + return cmpt && cmpt.subType === condition.subType; + }) : components; + } + + function normalizeSetOptionInput(opts) { + var replaceMergeMainTypeMap = createHashMap(); + opts && each(normalizeToArray(opts.replaceMerge), function (mainType) { + if ("development" !== 'production') { + assert(ComponentModel.hasClass(mainType), '"' + mainType + '" is not valid component main type in "replaceMerge"'); + } + + replaceMergeMainTypeMap.set(mainType, true); + }); + return { + replaceMergeMainTypeMap: replaceMergeMainTypeMap + }; + } + + mixin(GlobalModel, PaletteMixin); + + var availableMethods = ['getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isSSR', 'isDisposed', 'on', 'off', 'getDataURL', 'getConnectedDataURL', // 'getModel', + 'getOption', // 'getViewOfComponentModel', + // 'getViewOfSeriesModel', + 'getId', 'updateLabelLayout']; + + var ExtensionAPI = + /** @class */ + function () { + function ExtensionAPI(ecInstance) { + each(availableMethods, function (methodName) { + this[methodName] = bind(ecInstance[methodName], ecInstance); + }, this); + } + + return ExtensionAPI; + }(); + + var coordinateSystemCreators = {}; + + var CoordinateSystemManager = + /** @class */ + function () { + function CoordinateSystemManager() { + this._coordinateSystems = []; + } + + CoordinateSystemManager.prototype.create = function (ecModel, api) { + var coordinateSystems = []; + each(coordinateSystemCreators, function (creater, type) { + var list = creater.create(ecModel, api); + coordinateSystems = coordinateSystems.concat(list || []); + }); + this._coordinateSystems = coordinateSystems; + }; + + CoordinateSystemManager.prototype.update = function (ecModel, api) { + each(this._coordinateSystems, function (coordSys) { + coordSys.update && coordSys.update(ecModel, api); + }); + }; + + CoordinateSystemManager.prototype.getCoordinateSystems = function () { + return this._coordinateSystems.slice(); + }; + + CoordinateSystemManager.register = function (type, creator) { + coordinateSystemCreators[type] = creator; + }; + + CoordinateSystemManager.get = function (type) { + return coordinateSystemCreators[type]; + }; + + return CoordinateSystemManager; + }(); + + var QUERY_REG = /^(min|max)?(.+)$/; // Key: mainType + // type FakeComponentsMap = HashMap<(MappingExistingItem & { subType: string })[]>; + + /** + * TERM EXPLANATIONS: + * See `ECOption` and `ECUnitOption` in `src/util/types.ts`. + */ + + var OptionManager = + /** @class */ + function () { + // timeline.notMerge is not supported in ec3. Firstly there is rearly + // case that notMerge is needed. Secondly supporting 'notMerge' requires + // rawOption cloned and backuped when timeline changed, which does no + // good to performance. What's more, that both timeline and setOption + // method supply 'notMerge' brings complex and some problems. + // Consider this case: + // (step1) chart.setOption({timeline: {notMerge: false}, ...}, false); + // (step2) chart.setOption({timeline: {notMerge: true}, ...}, false); + function OptionManager(api) { + this._timelineOptions = []; + this._mediaList = []; + /** + * -1, means default. + * empty means no media. + */ + + this._currentMediaIndices = []; + this._api = api; + } + + OptionManager.prototype.setOption = function (rawOption, optionPreprocessorFuncs, opt) { + if (rawOption) { + // That set dat primitive is dangerous if user reuse the data when setOption again. + each(normalizeToArray(rawOption.series), function (series) { + series && series.data && isTypedArray(series.data) && setAsPrimitive(series.data); + }); + each(normalizeToArray(rawOption.dataset), function (dataset) { + dataset && dataset.source && isTypedArray(dataset.source) && setAsPrimitive(dataset.source); + }); + } // Caution: some series modify option data, if do not clone, + // it should ensure that the repeat modify correctly + // (create a new object when modify itself). + + + rawOption = clone(rawOption); // FIXME + // If some property is set in timeline options or media option but + // not set in baseOption, a warning should be given. + + var optionBackup = this._optionBackup; + var newParsedOption = parseRawOption(rawOption, optionPreprocessorFuncs, !optionBackup); + this._newBaseOption = newParsedOption.baseOption; // For setOption at second time (using merge mode); + + if (optionBackup) { + // FIXME + // the restore merge solution is essentially incorrect. + // the mapping can not be 100% consistent with ecModel, which probably brings + // potential bug! + // The first merge is delayed, becuase in most cases, users do not call `setOption` twice. + // let fakeCmptsMap = this._fakeCmptsMap; + // if (!fakeCmptsMap) { + // fakeCmptsMap = this._fakeCmptsMap = createHashMap(); + // mergeToBackupOption(fakeCmptsMap, null, optionBackup.baseOption, null); + // } + // mergeToBackupOption( + // fakeCmptsMap, optionBackup.baseOption, newParsedOption.baseOption, opt + // ); + // For simplicity, timeline options and media options do not support merge, + // that is, if you `setOption` twice and both has timeline options, the latter + // timeline opitons will not be merged to the formers, but just substitude them. + if (newParsedOption.timelineOptions.length) { + optionBackup.timelineOptions = newParsedOption.timelineOptions; + } + + if (newParsedOption.mediaList.length) { + optionBackup.mediaList = newParsedOption.mediaList; + } + + if (newParsedOption.mediaDefault) { + optionBackup.mediaDefault = newParsedOption.mediaDefault; + } + } else { + this._optionBackup = newParsedOption; + } + }; + + OptionManager.prototype.mountOption = function (isRecreate) { + var optionBackup = this._optionBackup; + this._timelineOptions = optionBackup.timelineOptions; + this._mediaList = optionBackup.mediaList; + this._mediaDefault = optionBackup.mediaDefault; + this._currentMediaIndices = []; + return clone(isRecreate // this._optionBackup.baseOption, which is created at the first `setOption` + // called, and is merged into every new option by inner method `mergeToBackupOption` + // each time `setOption` called, can be only used in `isRecreate`, because + // its reliability is under suspicion. In other cases option merge is + // performed by `model.mergeOption`. + ? optionBackup.baseOption : this._newBaseOption); + }; + + OptionManager.prototype.getTimelineOption = function (ecModel) { + var option; + var timelineOptions = this._timelineOptions; + + if (timelineOptions.length) { + // getTimelineOption can only be called after ecModel inited, + // so we can get currentIndex from timelineModel. + var timelineModel = ecModel.getComponent('timeline'); + + if (timelineModel) { + option = clone( // FIXME:TS as TimelineModel or quivlant interface + timelineOptions[timelineModel.getCurrentIndex()]); + } + } + + return option; + }; + + OptionManager.prototype.getMediaOption = function (ecModel) { + var ecWidth = this._api.getWidth(); + + var ecHeight = this._api.getHeight(); + + var mediaList = this._mediaList; + var mediaDefault = this._mediaDefault; + var indices = []; + var result = []; // No media defined. + + if (!mediaList.length && !mediaDefault) { + return result; + } // Multi media may be applied, the latter defined media has higher priority. + + + for (var i = 0, len = mediaList.length; i < len; i++) { + if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) { + indices.push(i); + } + } // FIXME + // Whether mediaDefault should force users to provide? Otherwise + // the change by media query can not be recorvered. + + + if (!indices.length && mediaDefault) { + indices = [-1]; + } + + if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) { + result = map(indices, function (index) { + return clone(index === -1 ? mediaDefault.option : mediaList[index].option); + }); + } // Otherwise return nothing. + + + this._currentMediaIndices = indices; + return result; + }; + + return OptionManager; + }(); + /** + * [RAW_OPTION_PATTERNS] + * (Note: "series: []" represents all other props in `ECUnitOption`) + * + * (1) No prop "baseOption" declared: + * Root option is used as "baseOption" (except prop "options" and "media"). + * ```js + * option = { + * series: [], + * timeline: {}, + * options: [], + * }; + * option = { + * series: [], + * media: {}, + * }; + * option = { + * series: [], + * timeline: {}, + * options: [], + * media: {}, + * } + * ``` + * + * (2) Prop "baseOption" declared: + * If "baseOption" declared, `ECUnitOption` props can only be declared + * inside "baseOption" except prop "timeline" (compat ec2). + * ```js + * option = { + * baseOption: { + * timeline: {}, + * series: [], + * }, + * options: [] + * }; + * option = { + * baseOption: { + * series: [], + * }, + * media: [] + * }; + * option = { + * baseOption: { + * timeline: {}, + * series: [], + * }, + * options: [] + * media: [] + * }; + * option = { + * // ec3 compat ec2: allow (only) `timeline` declared + * // outside baseOption. Keep this setting for compat. + * timeline: {}, + * baseOption: { + * series: [], + * }, + * options: [], + * media: [] + * }; + * ``` + */ + + + function parseRawOption( // `rawOption` May be modified + rawOption, optionPreprocessorFuncs, isNew) { + var mediaList = []; + var mediaDefault; + var baseOption; + var declaredBaseOption = rawOption.baseOption; // Compatible with ec2, [RAW_OPTION_PATTERNS] above. + + var timelineOnRoot = rawOption.timeline; + var timelineOptionsOnRoot = rawOption.options; + var mediaOnRoot = rawOption.media; + var hasMedia = !!rawOption.media; + var hasTimeline = !!(timelineOptionsOnRoot || timelineOnRoot || declaredBaseOption && declaredBaseOption.timeline); + + if (declaredBaseOption) { + baseOption = declaredBaseOption; // For merge option. + + if (!baseOption.timeline) { + baseOption.timeline = timelineOnRoot; + } + } // For convenience, enable to use the root option as the `baseOption`: + // `{ ...normalOptionProps, media: [{ ... }, { ... }] }` + else { + if (hasTimeline || hasMedia) { + rawOption.options = rawOption.media = null; + } + + baseOption = rawOption; + } + + if (hasMedia) { + if (isArray(mediaOnRoot)) { + each(mediaOnRoot, function (singleMedia) { + if ("development" !== 'production') { + // Real case of wrong config. + if (singleMedia && !singleMedia.option && isObject(singleMedia.query) && isObject(singleMedia.query.option)) { + error('Illegal media option. Must be like { media: [ { query: {}, option: {} } ] }'); + } + } + + if (singleMedia && singleMedia.option) { + if (singleMedia.query) { + mediaList.push(singleMedia); + } else if (!mediaDefault) { + // Use the first media default. + mediaDefault = singleMedia; + } + } + }); + } else { + if ("development" !== 'production') { + // Real case of wrong config. + error('Illegal media option. Must be an array. Like { media: [ {...}, {...} ] }'); + } + } + } + + doPreprocess(baseOption); + each(timelineOptionsOnRoot, function (option) { + return doPreprocess(option); + }); + each(mediaList, function (media) { + return doPreprocess(media.option); + }); + + function doPreprocess(option) { + each(optionPreprocessorFuncs, function (preProcess) { + preProcess(option, isNew); + }); + } + + return { + baseOption: baseOption, + timelineOptions: timelineOptionsOnRoot || [], + mediaDefault: mediaDefault, + mediaList: mediaList + }; + } + /** + * @see + * Support: width, height, aspectRatio + * Can use max or min as prefix. + */ + + + function applyMediaQuery(query, ecWidth, ecHeight) { + var realMap = { + width: ecWidth, + height: ecHeight, + aspectratio: ecWidth / ecHeight // lowser case for convenientce. + + }; + var applicatable = true; + each(query, function (value, attr) { + var matched = attr.match(QUERY_REG); + + if (!matched || !matched[1] || !matched[2]) { + return; + } + + var operator = matched[1]; + var realAttr = matched[2].toLowerCase(); + + if (!compare(realMap[realAttr], value, operator)) { + applicatable = false; + } + }); + return applicatable; + } + + function compare(real, expect, operator) { + if (operator === 'min') { + return real >= expect; + } else if (operator === 'max') { + return real <= expect; + } else { + // Equals + return real === expect; + } + } + + function indicesEquals(indices1, indices2) { + // indices is always order by asc and has only finite number. + return indices1.join(',') === indices2.join(','); + } + + var each$2 = each; + var isObject$1 = isObject; + var POSSIBLE_STYLES = ['areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle', 'chordStyle', 'label', 'labelLine']; + + function compatEC2ItemStyle(opt) { + var itemStyleOpt = opt && opt.itemStyle; + + if (!itemStyleOpt) { + return; + } + + for (var i = 0, len = POSSIBLE_STYLES.length; i < len; i++) { + var styleName = POSSIBLE_STYLES[i]; + var normalItemStyleOpt = itemStyleOpt.normal; + var emphasisItemStyleOpt = itemStyleOpt.emphasis; + + if (normalItemStyleOpt && normalItemStyleOpt[styleName]) { + if ("development" !== 'production') { + deprecateReplaceLog("itemStyle.normal." + styleName, styleName); + } + + opt[styleName] = opt[styleName] || {}; + + if (!opt[styleName].normal) { + opt[styleName].normal = normalItemStyleOpt[styleName]; + } else { + merge(opt[styleName].normal, normalItemStyleOpt[styleName]); + } + + normalItemStyleOpt[styleName] = null; + } + + if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) { + if ("development" !== 'production') { + deprecateReplaceLog("itemStyle.emphasis." + styleName, "emphasis." + styleName); + } + + opt[styleName] = opt[styleName] || {}; + + if (!opt[styleName].emphasis) { + opt[styleName].emphasis = emphasisItemStyleOpt[styleName]; + } else { + merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]); + } + + emphasisItemStyleOpt[styleName] = null; + } + } + } + + function convertNormalEmphasis(opt, optType, useExtend) { + if (opt && opt[optType] && (opt[optType].normal || opt[optType].emphasis)) { + var normalOpt = opt[optType].normal; + var emphasisOpt = opt[optType].emphasis; + + if (normalOpt) { + if ("development" !== 'production') { + // eslint-disable-next-line max-len + deprecateLog("'normal' hierarchy in " + optType + " has been removed since 4.0. All style properties are configured in " + optType + " directly now."); + } // Timeline controlStyle has other properties besides normal and emphasis + + + if (useExtend) { + opt[optType].normal = opt[optType].emphasis = null; + defaults(opt[optType], normalOpt); + } else { + opt[optType] = normalOpt; + } + } + + if (emphasisOpt) { + if ("development" !== 'production') { + deprecateLog(optType + ".emphasis has been changed to emphasis." + optType + " since 4.0"); + } + + opt.emphasis = opt.emphasis || {}; + opt.emphasis[optType] = emphasisOpt; // Also compat the case user mix the style and focus together in ec3 style + // for example: { itemStyle: { normal: {}, emphasis: {focus, shadowBlur} } } + + if (emphasisOpt.focus) { + opt.emphasis.focus = emphasisOpt.focus; + } + + if (emphasisOpt.blurScope) { + opt.emphasis.blurScope = emphasisOpt.blurScope; + } + } + } + } + + function removeEC3NormalStatus(opt) { + convertNormalEmphasis(opt, 'itemStyle'); + convertNormalEmphasis(opt, 'lineStyle'); + convertNormalEmphasis(opt, 'areaStyle'); + convertNormalEmphasis(opt, 'label'); + convertNormalEmphasis(opt, 'labelLine'); // treemap + + convertNormalEmphasis(opt, 'upperLabel'); // graph + + convertNormalEmphasis(opt, 'edgeLabel'); + } + + function compatTextStyle(opt, propName) { + // Check whether is not object (string\null\undefined ...) + var labelOptSingle = isObject$1(opt) && opt[propName]; + var textStyle = isObject$1(labelOptSingle) && labelOptSingle.textStyle; + + if (textStyle) { + if ("development" !== 'production') { + // eslint-disable-next-line max-len + deprecateLog("textStyle hierarchy in " + propName + " has been removed since 4.0. All textStyle properties are configured in " + propName + " directly now."); + } + + for (var i = 0, len = TEXT_STYLE_OPTIONS.length; i < len; i++) { + var textPropName = TEXT_STYLE_OPTIONS[i]; + + if (textStyle.hasOwnProperty(textPropName)) { + labelOptSingle[textPropName] = textStyle[textPropName]; + } + } + } + } + + function compatEC3CommonStyles(opt) { + if (opt) { + removeEC3NormalStatus(opt); + compatTextStyle(opt, 'label'); + opt.emphasis && compatTextStyle(opt.emphasis, 'label'); + } + } + + function processSeries(seriesOpt) { + if (!isObject$1(seriesOpt)) { + return; + } + + compatEC2ItemStyle(seriesOpt); + removeEC3NormalStatus(seriesOpt); + compatTextStyle(seriesOpt, 'label'); // treemap + + compatTextStyle(seriesOpt, 'upperLabel'); // graph + + compatTextStyle(seriesOpt, 'edgeLabel'); + + if (seriesOpt.emphasis) { + compatTextStyle(seriesOpt.emphasis, 'label'); // treemap + + compatTextStyle(seriesOpt.emphasis, 'upperLabel'); // graph + + compatTextStyle(seriesOpt.emphasis, 'edgeLabel'); + } + + var markPoint = seriesOpt.markPoint; + + if (markPoint) { + compatEC2ItemStyle(markPoint); + compatEC3CommonStyles(markPoint); + } + + var markLine = seriesOpt.markLine; + + if (markLine) { + compatEC2ItemStyle(markLine); + compatEC3CommonStyles(markLine); + } + + var markArea = seriesOpt.markArea; + + if (markArea) { + compatEC3CommonStyles(markArea); + } + + var data = seriesOpt.data; // Break with ec3: if `setOption` again, there may be no `type` in option, + // then the backward compat based on option type will not be performed. + + if (seriesOpt.type === 'graph') { + data = data || seriesOpt.nodes; + var edgeData = seriesOpt.links || seriesOpt.edges; + + if (edgeData && !isTypedArray(edgeData)) { + for (var i = 0; i < edgeData.length; i++) { + compatEC3CommonStyles(edgeData[i]); + } + } + + each(seriesOpt.categories, function (opt) { + removeEC3NormalStatus(opt); + }); + } + + if (data && !isTypedArray(data)) { + for (var i = 0; i < data.length; i++) { + compatEC3CommonStyles(data[i]); + } + } // mark point data + + + markPoint = seriesOpt.markPoint; + + if (markPoint && markPoint.data) { + var mpData = markPoint.data; + + for (var i = 0; i < mpData.length; i++) { + compatEC3CommonStyles(mpData[i]); + } + } // mark line data + + + markLine = seriesOpt.markLine; + + if (markLine && markLine.data) { + var mlData = markLine.data; + + for (var i = 0; i < mlData.length; i++) { + if (isArray(mlData[i])) { + compatEC3CommonStyles(mlData[i][0]); + compatEC3CommonStyles(mlData[i][1]); + } else { + compatEC3CommonStyles(mlData[i]); + } + } + } // Series + + + if (seriesOpt.type === 'gauge') { + compatTextStyle(seriesOpt, 'axisLabel'); + compatTextStyle(seriesOpt, 'title'); + compatTextStyle(seriesOpt, 'detail'); + } else if (seriesOpt.type === 'treemap') { + convertNormalEmphasis(seriesOpt.breadcrumb, 'itemStyle'); + each(seriesOpt.levels, function (opt) { + removeEC3NormalStatus(opt); + }); + } else if (seriesOpt.type === 'tree') { + removeEC3NormalStatus(seriesOpt.leaves); + } // sunburst starts from ec4, so it does not need to compat levels. + + } + + function toArr(o) { + return isArray(o) ? o : o ? [o] : []; + } + + function toObj(o) { + return (isArray(o) ? o[0] : o) || {}; + } + + function globalCompatStyle(option, isTheme) { + each$2(toArr(option.series), function (seriesOpt) { + isObject$1(seriesOpt) && processSeries(seriesOpt); + }); + var axes = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'parallelAxis', 'radar']; + isTheme && axes.push('valueAxis', 'categoryAxis', 'logAxis', 'timeAxis'); + each$2(axes, function (axisName) { + each$2(toArr(option[axisName]), function (axisOpt) { + if (axisOpt) { + compatTextStyle(axisOpt, 'axisLabel'); + compatTextStyle(axisOpt.axisPointer, 'label'); + } + }); + }); + each$2(toArr(option.parallel), function (parallelOpt) { + var parallelAxisDefault = parallelOpt && parallelOpt.parallelAxisDefault; + compatTextStyle(parallelAxisDefault, 'axisLabel'); + compatTextStyle(parallelAxisDefault && parallelAxisDefault.axisPointer, 'label'); + }); + each$2(toArr(option.calendar), function (calendarOpt) { + convertNormalEmphasis(calendarOpt, 'itemStyle'); + compatTextStyle(calendarOpt, 'dayLabel'); + compatTextStyle(calendarOpt, 'monthLabel'); + compatTextStyle(calendarOpt, 'yearLabel'); + }); // radar.name.textStyle + + each$2(toArr(option.radar), function (radarOpt) { + compatTextStyle(radarOpt, 'name'); // Use axisName instead of name because component has name property + + if (radarOpt.name && radarOpt.axisName == null) { + radarOpt.axisName = radarOpt.name; + delete radarOpt.name; + + if ("development" !== 'production') { + deprecateLog('name property in radar component has been changed to axisName'); + } + } + + if (radarOpt.nameGap != null && radarOpt.axisNameGap == null) { + radarOpt.axisNameGap = radarOpt.nameGap; + delete radarOpt.nameGap; + + if ("development" !== 'production') { + deprecateLog('nameGap property in radar component has been changed to axisNameGap'); + } + } + + if ("development" !== 'production') { + each$2(radarOpt.indicator, function (indicatorOpt) { + if (indicatorOpt.text) { + deprecateReplaceLog('text', 'name', 'radar.indicator'); + } + }); + } + }); + each$2(toArr(option.geo), function (geoOpt) { + if (isObject$1(geoOpt)) { + compatEC3CommonStyles(geoOpt); + each$2(toArr(geoOpt.regions), function (regionObj) { + compatEC3CommonStyles(regionObj); + }); + } + }); + each$2(toArr(option.timeline), function (timelineOpt) { + compatEC3CommonStyles(timelineOpt); + convertNormalEmphasis(timelineOpt, 'label'); + convertNormalEmphasis(timelineOpt, 'itemStyle'); + convertNormalEmphasis(timelineOpt, 'controlStyle', true); + var data = timelineOpt.data; + isArray(data) && each(data, function (item) { + if (isObject(item)) { + convertNormalEmphasis(item, 'label'); + convertNormalEmphasis(item, 'itemStyle'); + } + }); + }); + each$2(toArr(option.toolbox), function (toolboxOpt) { + convertNormalEmphasis(toolboxOpt, 'iconStyle'); + each$2(toolboxOpt.feature, function (featureOpt) { + convertNormalEmphasis(featureOpt, 'iconStyle'); + }); + }); + compatTextStyle(toObj(option.axisPointer), 'label'); + compatTextStyle(toObj(option.tooltip).axisPointer, 'label'); // Clean logs + // storedLogs = {}; + } + + function get(opt, path) { + var pathArr = path.split(','); + var obj = opt; + + for (var i = 0; i < pathArr.length; i++) { + obj = obj && obj[pathArr[i]]; + + if (obj == null) { + break; + } + } + + return obj; + } + + function set$1(opt, path, val, overwrite) { + var pathArr = path.split(','); + var obj = opt; + var key; + var i = 0; + + for (; i < pathArr.length - 1; i++) { + key = pathArr[i]; + + if (obj[key] == null) { + obj[key] = {}; + } + + obj = obj[key]; + } + + if (overwrite || obj[pathArr[i]] == null) { + obj[pathArr[i]] = val; + } + } + + function compatLayoutProperties(option) { + option && each(LAYOUT_PROPERTIES, function (prop) { + if (prop[0] in option && !(prop[1] in option)) { + option[prop[1]] = option[prop[0]]; + } + }); + } + + var LAYOUT_PROPERTIES = [['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']]; + var COMPATITABLE_COMPONENTS = ['grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline']; + var BAR_ITEM_STYLE_MAP = [['borderRadius', 'barBorderRadius'], ['borderColor', 'barBorderColor'], ['borderWidth', 'barBorderWidth']]; + + function compatBarItemStyle(option) { + var itemStyle = option && option.itemStyle; + + if (itemStyle) { + for (var i = 0; i < BAR_ITEM_STYLE_MAP.length; i++) { + var oldName = BAR_ITEM_STYLE_MAP[i][1]; + var newName = BAR_ITEM_STYLE_MAP[i][0]; + + if (itemStyle[oldName] != null) { + itemStyle[newName] = itemStyle[oldName]; + + if ("development" !== 'production') { + deprecateReplaceLog(oldName, newName); + } + } + } + } + } + + function compatPieLabel(option) { + if (!option) { + return; + } + + if (option.alignTo === 'edge' && option.margin != null && option.edgeDistance == null) { + if ("development" !== 'production') { + deprecateReplaceLog('label.margin', 'label.edgeDistance', 'pie'); + } + + option.edgeDistance = option.margin; + } + } + + function compatSunburstState(option) { + if (!option) { + return; + } + + if (option.downplay && !option.blur) { + option.blur = option.downplay; + + if ("development" !== 'production') { + deprecateReplaceLog('downplay', 'blur', 'sunburst'); + } + } + } + + function compatGraphFocus(option) { + if (!option) { + return; + } + + if (option.focusNodeAdjacency != null) { + option.emphasis = option.emphasis || {}; + + if (option.emphasis.focus == null) { + if ("development" !== 'production') { + deprecateReplaceLog('focusNodeAdjacency', 'emphasis: { focus: \'adjacency\'}', 'graph/sankey'); + } + + option.emphasis.focus = 'adjacency'; + } + } + } + + function traverseTree(data, cb) { + if (data) { + for (var i = 0; i < data.length; i++) { + cb(data[i]); + data[i] && traverseTree(data[i].children, cb); + } + } + } + + function globalBackwardCompat(option, isTheme) { + globalCompatStyle(option, isTheme); // Make sure series array for model initialization. + + option.series = normalizeToArray(option.series); + each(option.series, function (seriesOpt) { + if (!isObject(seriesOpt)) { + return; + } + + var seriesType = seriesOpt.type; + + if (seriesType === 'line') { + if (seriesOpt.clipOverflow != null) { + seriesOpt.clip = seriesOpt.clipOverflow; + + if ("development" !== 'production') { + deprecateReplaceLog('clipOverflow', 'clip', 'line'); + } + } + } else if (seriesType === 'pie' || seriesType === 'gauge') { + if (seriesOpt.clockWise != null) { + seriesOpt.clockwise = seriesOpt.clockWise; + + if ("development" !== 'production') { + deprecateReplaceLog('clockWise', 'clockwise'); + } + } + + compatPieLabel(seriesOpt.label); + var data = seriesOpt.data; + + if (data && !isTypedArray(data)) { + for (var i = 0; i < data.length; i++) { + compatPieLabel(data[i]); + } + } + + if (seriesOpt.hoverOffset != null) { + seriesOpt.emphasis = seriesOpt.emphasis || {}; + + if (seriesOpt.emphasis.scaleSize = null) { + if ("development" !== 'production') { + deprecateReplaceLog('hoverOffset', 'emphasis.scaleSize'); + } + + seriesOpt.emphasis.scaleSize = seriesOpt.hoverOffset; + } + } + } else if (seriesType === 'gauge') { + var pointerColor = get(seriesOpt, 'pointer.color'); + pointerColor != null && set$1(seriesOpt, 'itemStyle.color', pointerColor); + } else if (seriesType === 'bar') { + compatBarItemStyle(seriesOpt); + compatBarItemStyle(seriesOpt.backgroundStyle); + compatBarItemStyle(seriesOpt.emphasis); + var data = seriesOpt.data; + + if (data && !isTypedArray(data)) { + for (var i = 0; i < data.length; i++) { + if (typeof data[i] === 'object') { + compatBarItemStyle(data[i]); + compatBarItemStyle(data[i] && data[i].emphasis); + } + } + } + } else if (seriesType === 'sunburst') { + var highlightPolicy = seriesOpt.highlightPolicy; + + if (highlightPolicy) { + seriesOpt.emphasis = seriesOpt.emphasis || {}; + + if (!seriesOpt.emphasis.focus) { + seriesOpt.emphasis.focus = highlightPolicy; + + if ("development" !== 'production') { + deprecateReplaceLog('highlightPolicy', 'emphasis.focus', 'sunburst'); + } + } + } + + compatSunburstState(seriesOpt); + traverseTree(seriesOpt.data, compatSunburstState); + } else if (seriesType === 'graph' || seriesType === 'sankey') { + compatGraphFocus(seriesOpt); // TODO nodes, edges? + } else if (seriesType === 'map') { + if (seriesOpt.mapType && !seriesOpt.map) { + if ("development" !== 'production') { + deprecateReplaceLog('mapType', 'map', 'map'); + } + + seriesOpt.map = seriesOpt.mapType; + } + + if (seriesOpt.mapLocation) { + if ("development" !== 'production') { + deprecateLog('`mapLocation` is not used anymore.'); + } + + defaults(seriesOpt, seriesOpt.mapLocation); + } + } + + if (seriesOpt.hoverAnimation != null) { + seriesOpt.emphasis = seriesOpt.emphasis || {}; + + if (seriesOpt.emphasis && seriesOpt.emphasis.scale == null) { + if ("development" !== 'production') { + deprecateReplaceLog('hoverAnimation', 'emphasis.scale'); + } + + seriesOpt.emphasis.scale = seriesOpt.hoverAnimation; + } + } + + compatLayoutProperties(seriesOpt); + }); // dataRange has changed to visualMap + + if (option.dataRange) { + option.visualMap = option.dataRange; + } + + each(COMPATITABLE_COMPONENTS, function (componentName) { + var options = option[componentName]; + + if (options) { + if (!isArray(options)) { + options = [options]; + } + + each(options, function (option) { + compatLayoutProperties(option); + }); + } + }); + } + + // data processing stage is blocked in stream. + // See + // (2) Only register once when import repeatly. + // Should be executed after series filtered and before stack calculation. + + function dataStack(ecModel) { + var stackInfoMap = createHashMap(); + ecModel.eachSeries(function (seriesModel) { + var stack = seriesModel.get('stack'); // Compatibal: when `stack` is set as '', do not stack. + + if (stack) { + var stackInfoList = stackInfoMap.get(stack) || stackInfoMap.set(stack, []); + var data = seriesModel.getData(); + var stackInfo = { + // Used for calculate axis extent automatically. + // TODO: Type getCalculationInfo return more specific type? + stackResultDimension: data.getCalculationInfo('stackResultDimension'), + stackedOverDimension: data.getCalculationInfo('stackedOverDimension'), + stackedDimension: data.getCalculationInfo('stackedDimension'), + stackedByDimension: data.getCalculationInfo('stackedByDimension'), + isStackedByIndex: data.getCalculationInfo('isStackedByIndex'), + data: data, + seriesModel: seriesModel + }; // If stacked on axis that do not support data stack. + + if (!stackInfo.stackedDimension || !(stackInfo.isStackedByIndex || stackInfo.stackedByDimension)) { + return; + } + + stackInfoList.length && data.setCalculationInfo('stackedOnSeries', stackInfoList[stackInfoList.length - 1].seriesModel); + stackInfoList.push(stackInfo); + } + }); + stackInfoMap.each(calculateStack); + } + + function calculateStack(stackInfoList) { + each(stackInfoList, function (targetStackInfo, idxInStack) { + var resultVal = []; + var resultNaN = [NaN, NaN]; + var dims = [targetStackInfo.stackResultDimension, targetStackInfo.stackedOverDimension]; + var targetData = targetStackInfo.data; + var isStackedByIndex = targetStackInfo.isStackedByIndex; // Should not write on raw data, because stack series model list changes + // depending on legend selection. + + targetData.modify(dims, function (v0, v1, dataIndex) { + var sum = targetData.get(targetStackInfo.stackedDimension, dataIndex); // Consider `connectNulls` of line area, if value is NaN, stackedOver + // should also be NaN, to draw a appropriate belt area. + + if (isNaN(sum)) { + return resultNaN; + } + + var byValue; + var stackedDataRawIndex; + + if (isStackedByIndex) { + stackedDataRawIndex = targetData.getRawIndex(dataIndex); + } else { + byValue = targetData.get(targetStackInfo.stackedByDimension, dataIndex); + } // If stackOver is NaN, chart view will render point on value start. + + + var stackedOver = NaN; + + for (var j = idxInStack - 1; j >= 0; j--) { + var stackInfo = stackInfoList[j]; // Has been optimized by inverted indices on `stackedByDimension`. + + if (!isStackedByIndex) { + stackedDataRawIndex = stackInfo.data.rawIndexOf(stackInfo.stackedByDimension, byValue); + } + + if (stackedDataRawIndex >= 0) { + var val = stackInfo.data.getByRawIndex(stackInfo.stackResultDimension, stackedDataRawIndex); // Considering positive stack, negative stack and empty data + + if (sum >= 0 && val > 0 || // Positive stack + sum <= 0 && val < 0 // Negative stack + ) { + // The sum should be as less as possible to be effected + // by floating arithmetic problem. A wrong result probably + // filtered incorrectly by axis min/max. + sum = addSafe(sum, val); + stackedOver = val; + break; + } + } + } + + resultVal[0] = sum; + resultVal[1] = stackedOver; + return resultVal; + }); + }); + } + + var SourceImpl = + /** @class */ + function () { + function SourceImpl(fields) { + this.data = fields.data || (fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []); + this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN; // Visit config + + this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN; + this.startIndex = fields.startIndex || 0; + this.dimensionsDetectedCount = fields.dimensionsDetectedCount; + this.metaRawOption = fields.metaRawOption; + var dimensionsDefine = this.dimensionsDefine = fields.dimensionsDefine; + + if (dimensionsDefine) { + for (var i = 0; i < dimensionsDefine.length; i++) { + var dim = dimensionsDefine[i]; + + if (dim.type == null) { + if (guessOrdinal(this, i) === BE_ORDINAL.Must) { + dim.type = 'ordinal'; + } + } + } + } + } + + return SourceImpl; + }(); + + function isSourceInstance(val) { + return val instanceof SourceImpl; + } + /** + * Create a source from option. + * NOTE: Created source is immutable. Don't change any properties in it. + */ + + function createSource(sourceData, thisMetaRawOption, // can be null. If not provided, auto detect it from `sourceData`. + sourceFormat) { + sourceFormat = sourceFormat || detectSourceFormat(sourceData); + var seriesLayoutBy = thisMetaRawOption.seriesLayoutBy; + var determined = determineSourceDimensions(sourceData, sourceFormat, seriesLayoutBy, thisMetaRawOption.sourceHeader, thisMetaRawOption.dimensions); + var source = new SourceImpl({ + data: sourceData, + sourceFormat: sourceFormat, + seriesLayoutBy: seriesLayoutBy, + dimensionsDefine: determined.dimensionsDefine, + startIndex: determined.startIndex, + dimensionsDetectedCount: determined.dimensionsDetectedCount, + metaRawOption: clone(thisMetaRawOption) + }); + return source; + } + /** + * Wrap original series data for some compatibility cases. + */ + + function createSourceFromSeriesDataOption(data) { + return new SourceImpl({ + data: data, + sourceFormat: isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL + }); + } + /** + * Clone source but excludes source data. + */ + + function cloneSourceShallow(source) { + return new SourceImpl({ + data: source.data, + sourceFormat: source.sourceFormat, + seriesLayoutBy: source.seriesLayoutBy, + dimensionsDefine: clone(source.dimensionsDefine), + startIndex: source.startIndex, + dimensionsDetectedCount: source.dimensionsDetectedCount + }); + } + /** + * Note: An empty array will be detected as `SOURCE_FORMAT_ARRAY_ROWS`. + */ + + function detectSourceFormat(data) { + var sourceFormat = SOURCE_FORMAT_UNKNOWN; + + if (isTypedArray(data)) { + sourceFormat = SOURCE_FORMAT_TYPED_ARRAY; + } else if (isArray(data)) { + // FIXME Whether tolerate null in top level array? + if (data.length === 0) { + sourceFormat = SOURCE_FORMAT_ARRAY_ROWS; + } + + for (var i = 0, len = data.length; i < len; i++) { + var item = data[i]; + + if (item == null) { + continue; + } else if (isArray(item)) { + sourceFormat = SOURCE_FORMAT_ARRAY_ROWS; + break; + } else if (isObject(item)) { + sourceFormat = SOURCE_FORMAT_OBJECT_ROWS; + break; + } + } + } else if (isObject(data)) { + for (var key in data) { + if (hasOwn(data, key) && isArrayLike(data[key])) { + sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS; + break; + } + } + } + + return sourceFormat; + } + /** + * Determine the source definitions from data standalone dimensions definitions + * are not specified. + */ + + function determineSourceDimensions(data, sourceFormat, seriesLayoutBy, sourceHeader, // standalone raw dimensions definition, like: + // { + // dimensions: ['aa', 'bb', { name: 'cc', type: 'time' }] + // } + // in `dataset` or `series` + dimensionsDefine) { + var dimensionsDetectedCount; + var startIndex; // PEDING: could data be null/undefined here? + // currently, if `dataset.source` not specified, error thrown. + // if `series.data` not specified, nothing rendered without error thrown. + // Should test these cases. + + if (!data) { + return { + dimensionsDefine: normalizeDimensionsOption(dimensionsDefine), + startIndex: startIndex, + dimensionsDetectedCount: dimensionsDetectedCount + }; + } + + if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) { + var dataArrayRows = data; // Rule: Most of the first line are string: it is header. + // Caution: consider a line with 5 string and 1 number, + // it still can not be sure it is a head, because the + // 5 string may be 5 values of category columns. + + if (sourceHeader === 'auto' || sourceHeader == null) { + arrayRowsTravelFirst(function (val) { + // '-' is regarded as null/undefined. + if (val != null && val !== '-') { + if (isString(val)) { + startIndex == null && (startIndex = 1); + } else { + startIndex = 0; + } + } // 10 is an experience number, avoid long loop. + + }, seriesLayoutBy, dataArrayRows, 10); + } else { + startIndex = isNumber(sourceHeader) ? sourceHeader : sourceHeader ? 1 : 0; + } + + if (!dimensionsDefine && startIndex === 1) { + dimensionsDefine = []; + arrayRowsTravelFirst(function (val, index) { + dimensionsDefine[index] = val != null ? val + '' : ''; + }, seriesLayoutBy, dataArrayRows, Infinity); + } + + dimensionsDetectedCount = dimensionsDefine ? dimensionsDefine.length : seriesLayoutBy === SERIES_LAYOUT_BY_ROW ? dataArrayRows.length : dataArrayRows[0] ? dataArrayRows[0].length : null; + } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) { + if (!dimensionsDefine) { + dimensionsDefine = objectRowsCollectDimensions(data); + } + } else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) { + if (!dimensionsDefine) { + dimensionsDefine = []; + each(data, function (colArr, key) { + dimensionsDefine.push(key); + }); + } + } else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) { + var value0 = getDataItemValue(data[0]); + dimensionsDetectedCount = isArray(value0) && value0.length || 1; + } else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) { + if ("development" !== 'production') { + assert(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.'); + } + } + + return { + startIndex: startIndex, + dimensionsDefine: normalizeDimensionsOption(dimensionsDefine), + dimensionsDetectedCount: dimensionsDetectedCount + }; + } + + function objectRowsCollectDimensions(data) { + var firstIndex = 0; + var obj; + + while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line + + + if (obj) { + var dimensions_1 = []; + each(obj, function (value, key) { + dimensions_1.push(key); + }); + return dimensions_1; + } + } // Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'], + // which is reasonable. But dimension name is duplicated. + // Returns undefined or an array contains only object without null/undefiend or string. + + + function normalizeDimensionsOption(dimensionsDefine) { + if (!dimensionsDefine) { + // The meaning of null/undefined is different from empty array. + return; + } + + var nameMap = createHashMap(); + return map(dimensionsDefine, function (rawItem, index) { + rawItem = isObject(rawItem) ? rawItem : { + name: rawItem + }; // Other fields will be discarded. + + var item = { + name: rawItem.name, + displayName: rawItem.displayName, + type: rawItem.type + }; // User can set null in dimensions. + // We dont auto specify name, othewise a given name may + // cause it be refered unexpectedly. + + if (item.name == null) { + return item; + } // Also consider number form like 2012. + + + item.name += ''; // User may also specify displayName. + // displayName will always exists except user not + // specified or dim name is not specified or detected. + // (A auto generated dim name will not be used as + // displayName). + + if (item.displayName == null) { + item.displayName = item.name; + } + + var exist = nameMap.get(item.name); + + if (!exist) { + nameMap.set(item.name, { + count: 1 + }); + } else { + item.name += '-' + exist.count++; + } + + return item; + }); + } + + function arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) { + if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) { + for (var i = 0; i < data.length && i < maxLoop; i++) { + cb(data[i] ? data[i][0] : null, i); + } + } else { + var value0 = data[0] || []; + + for (var i = 0; i < value0.length && i < maxLoop; i++) { + cb(value0[i], i); + } + } + } + + function shouldRetrieveDataByName(source) { + var sourceFormat = source.sourceFormat; + return sourceFormat === SOURCE_FORMAT_OBJECT_ROWS || sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS; + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + var _a, _b, _c; // TODO + var providerMethods; + var mountMethods; + /** + * If normal array used, mutable chunk size is supported. + * If typed array used, chunk size must be fixed. + */ + + var DefaultDataProvider = + /** @class */ + function () { + function DefaultDataProvider(sourceParam, dimSize) { + // let source: Source; + var source = !isSourceInstance(sourceParam) ? createSourceFromSeriesDataOption(sourceParam) : sourceParam; // declare source is Source; + + this._source = source; + var data = this._data = source.data; // Typed array. TODO IE10+? + + if (source.sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) { + if ("development" !== 'production') { + if (dimSize == null) { + throw new Error('Typed array data must specify dimension size'); + } + } + + this._offset = 0; + this._dimSize = dimSize; + this._data = data; + } + + mountMethods(this, data, source); + } + + DefaultDataProvider.prototype.getSource = function () { + return this._source; + }; + + DefaultDataProvider.prototype.count = function () { + return 0; + }; + + DefaultDataProvider.prototype.getItem = function (idx, out) { + return; + }; + + DefaultDataProvider.prototype.appendData = function (newData) {}; + + DefaultDataProvider.prototype.clean = function () {}; + + DefaultDataProvider.protoInitialize = function () { + // PENDING: To avoid potential incompat (e.g., prototype + // is visited somewhere), still init them on prototype. + var proto = DefaultDataProvider.prototype; + proto.pure = false; + proto.persistent = true; + }(); + + DefaultDataProvider.internalField = function () { + var _a; + + mountMethods = function (provider, data, source) { + var sourceFormat = source.sourceFormat; + var seriesLayoutBy = source.seriesLayoutBy; + var startIndex = source.startIndex; + var dimsDef = source.dimensionsDefine; + var methods = providerMethods[getMethodMapKey(sourceFormat, seriesLayoutBy)]; + + if ("development" !== 'production') { + assert(methods, 'Invalide sourceFormat: ' + sourceFormat); + } + + extend(provider, methods); + + if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) { + provider.getItem = getItemForTypedArray; + provider.count = countForTypedArray; + provider.fillStorage = fillStorageForTypedArray; + } else { + var rawItemGetter = getRawSourceItemGetter(sourceFormat, seriesLayoutBy); + provider.getItem = bind(rawItemGetter, null, data, startIndex, dimsDef); + var rawCounter = getRawSourceDataCounter(sourceFormat, seriesLayoutBy); + provider.count = bind(rawCounter, null, data, startIndex, dimsDef); + } + }; + + var getItemForTypedArray = function (idx, out) { + idx = idx - this._offset; + out = out || []; + var data = this._data; + var dimSize = this._dimSize; + var offset = dimSize * idx; + + for (var i = 0; i < dimSize; i++) { + out[i] = data[offset + i]; + } + + return out; + }; + + var fillStorageForTypedArray = function (start, end, storage, extent) { + var data = this._data; + var dimSize = this._dimSize; + + for (var dim = 0; dim < dimSize; dim++) { + var dimExtent = extent[dim]; + var min = dimExtent[0] == null ? Infinity : dimExtent[0]; + var max = dimExtent[1] == null ? -Infinity : dimExtent[1]; + var count = end - start; + var arr = storage[dim]; + + for (var i = 0; i < count; i++) { + // appendData with TypedArray will always do replace in provider. + var val = data[i * dimSize + dim]; + arr[start + i] = val; + val < min && (min = val); + val > max && (max = val); + } + + dimExtent[0] = min; + dimExtent[1] = max; + } + }; + + var countForTypedArray = function () { + return this._data ? this._data.length / this._dimSize : 0; + }; + + providerMethods = (_a = {}, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = { + pure: true, + appendData: appendDataSimply + }, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = { + pure: true, + appendData: function () { + throw new Error('Do not support appendData when set seriesLayoutBy: "row".'); + } + }, _a[SOURCE_FORMAT_OBJECT_ROWS] = { + pure: true, + appendData: appendDataSimply + }, _a[SOURCE_FORMAT_KEYED_COLUMNS] = { + pure: true, + appendData: function (newData) { + var data = this._data; + each(newData, function (newCol, key) { + var oldCol = data[key] || (data[key] = []); + + for (var i = 0; i < (newCol || []).length; i++) { + oldCol.push(newCol[i]); + } + }); + } + }, _a[SOURCE_FORMAT_ORIGINAL] = { + appendData: appendDataSimply + }, _a[SOURCE_FORMAT_TYPED_ARRAY] = { + persistent: false, + pure: true, + appendData: function (newData) { + if ("development" !== 'production') { + assert(isTypedArray(newData), 'Added data must be TypedArray if data in initialization is TypedArray'); + } + + this._data = newData; + }, + // Clean self if data is already used. + clean: function () { + // PENDING + this._offset += this.count(); + this._data = null; + } + }, _a); + + function appendDataSimply(newData) { + for (var i = 0; i < newData.length; i++) { + this._data.push(newData[i]); + } + } + }(); + + return DefaultDataProvider; + }(); + + var getItemSimply = function (rawData, startIndex, dimsDef, idx) { + return rawData[idx]; + }; + + var rawSourceItemGetterMap = (_a = {}, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = function (rawData, startIndex, dimsDef, idx) { + return rawData[idx + startIndex]; + }, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = function (rawData, startIndex, dimsDef, idx, out) { + idx += startIndex; + var item = out || []; + var data = rawData; + + for (var i = 0; i < data.length; i++) { + var row = data[i]; + item[i] = row ? row[idx] : null; + } + + return item; + }, _a[SOURCE_FORMAT_OBJECT_ROWS] = getItemSimply, _a[SOURCE_FORMAT_KEYED_COLUMNS] = function (rawData, startIndex, dimsDef, idx, out) { + var item = out || []; + + for (var i = 0; i < dimsDef.length; i++) { + var dimName = dimsDef[i].name; + + if ("development" !== 'production') { + if (dimName == null) { + throw new Error(); + } + } + + var col = rawData[dimName]; + item[i] = col ? col[idx] : null; + } + + return item; + }, _a[SOURCE_FORMAT_ORIGINAL] = getItemSimply, _a); + function getRawSourceItemGetter(sourceFormat, seriesLayoutBy) { + var method = rawSourceItemGetterMap[getMethodMapKey(sourceFormat, seriesLayoutBy)]; + + if ("development" !== 'production') { + assert(method, 'Do not support get item on "' + sourceFormat + '", "' + seriesLayoutBy + '".'); + } + + return method; + } + + var countSimply = function (rawData, startIndex, dimsDef) { + return rawData.length; + }; + + var rawSourceDataCounterMap = (_b = {}, _b[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = function (rawData, startIndex, dimsDef) { + return Math.max(0, rawData.length - startIndex); + }, _b[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = function (rawData, startIndex, dimsDef) { + var row = rawData[0]; + return row ? Math.max(0, row.length - startIndex) : 0; + }, _b[SOURCE_FORMAT_OBJECT_ROWS] = countSimply, _b[SOURCE_FORMAT_KEYED_COLUMNS] = function (rawData, startIndex, dimsDef) { + var dimName = dimsDef[0].name; + + if ("development" !== 'production') { + if (dimName == null) { + throw new Error(); + } + } + + var col = rawData[dimName]; + return col ? col.length : 0; + }, _b[SOURCE_FORMAT_ORIGINAL] = countSimply, _b); + function getRawSourceDataCounter(sourceFormat, seriesLayoutBy) { + var method = rawSourceDataCounterMap[getMethodMapKey(sourceFormat, seriesLayoutBy)]; + + if ("development" !== 'production') { + assert(method, 'Do not suppport count on "' + sourceFormat + '", "' + seriesLayoutBy + '".'); + } + + return method; + } + + var getRawValueSimply = function (dataItem, dimIndex, property) { + return dataItem[dimIndex]; + }; + + var rawSourceValueGetterMap = (_c = {}, _c[SOURCE_FORMAT_ARRAY_ROWS] = getRawValueSimply, _c[SOURCE_FORMAT_OBJECT_ROWS] = function (dataItem, dimIndex, property) { + return dataItem[property]; + }, _c[SOURCE_FORMAT_KEYED_COLUMNS] = getRawValueSimply, _c[SOURCE_FORMAT_ORIGINAL] = function (dataItem, dimIndex, property) { + // FIXME: In some case (markpoint in geo (geo-map.html)), + // dataItem is {coord: [...]} + var value = getDataItemValue(dataItem); + return !(value instanceof Array) ? value : value[dimIndex]; + }, _c[SOURCE_FORMAT_TYPED_ARRAY] = getRawValueSimply, _c); + function getRawSourceValueGetter(sourceFormat) { + var method = rawSourceValueGetterMap[sourceFormat]; + + if ("development" !== 'production') { + assert(method, 'Do not suppport get value on "' + sourceFormat + '".'); + } + + return method; + } + + function getMethodMapKey(sourceFormat, seriesLayoutBy) { + return sourceFormat === SOURCE_FORMAT_ARRAY_ROWS ? sourceFormat + '_' + seriesLayoutBy : sourceFormat; + } // ??? FIXME can these logic be more neat: getRawValue, getRawDataItem, + // Consider persistent. + // Caution: why use raw value to display on label or tooltip? + // A reason is to avoid format. For example time value we do not know + // how to format is expected. More over, if stack is used, calculated + // value may be 0.91000000001, which have brings trouble to display. + // TODO: consider how to treat null/undefined/NaN when display? + + + function retrieveRawValue(data, dataIndex, // If dimIndex is null/undefined, return OptionDataItem. + // Otherwise, return OptionDataValue. + dim) { + if (!data) { + return; + } // Consider data may be not persistent. + + + var dataItem = data.getRawDataItem(dataIndex); + + if (dataItem == null) { + return; + } + + var store = data.getStore(); + var sourceFormat = store.getSource().sourceFormat; + + if (dim != null) { + var dimIndex = data.getDimensionIndex(dim); + var property = store.getDimensionProperty(dimIndex); + return getRawSourceValueGetter(sourceFormat)(dataItem, dimIndex, property); + } else { + var result = dataItem; + + if (sourceFormat === SOURCE_FORMAT_ORIGINAL) { + result = getDataItemValue(dataItem); + } + + return result; + } + } + + var DIMENSION_LABEL_REG = /\{@(.+?)\}/g; + + var DataFormatMixin = + /** @class */ + function () { + function DataFormatMixin() {} + /** + * Get params for formatter + */ + + + DataFormatMixin.prototype.getDataParams = function (dataIndex, dataType) { + var data = this.getData(dataType); + var rawValue = this.getRawValue(dataIndex, dataType); + var rawDataIndex = data.getRawIndex(dataIndex); + var name = data.getName(dataIndex); + var itemOpt = data.getRawDataItem(dataIndex); + var style = data.getItemVisual(dataIndex, 'style'); + var color = style && style[data.getItemVisual(dataIndex, 'drawType') || 'fill']; + var borderColor = style && style.stroke; + var mainType = this.mainType; + var isSeries = mainType === 'series'; + var userOutput = data.userOutput && data.userOutput.get(); + return { + componentType: mainType, + componentSubType: this.subType, + componentIndex: this.componentIndex, + seriesType: isSeries ? this.subType : null, + seriesIndex: this.seriesIndex, + seriesId: isSeries ? this.id : null, + seriesName: isSeries ? this.name : null, + name: name, + dataIndex: rawDataIndex, + data: itemOpt, + dataType: dataType, + value: rawValue, + color: color, + borderColor: borderColor, + dimensionNames: userOutput ? userOutput.fullDimensions : null, + encode: userOutput ? userOutput.encode : null, + // Param name list for mapping `a`, `b`, `c`, `d`, `e` + $vars: ['seriesName', 'name', 'value'] + }; + }; + /** + * Format label + * @param dataIndex + * @param status 'normal' by default + * @param dataType + * @param labelDimIndex Only used in some chart that + * use formatter in different dimensions, like radar. + * @param formatter Formatter given outside. + * @return return null/undefined if no formatter + */ + + + DataFormatMixin.prototype.getFormattedLabel = function (dataIndex, status, dataType, labelDimIndex, formatter, extendParams) { + status = status || 'normal'; + var data = this.getData(dataType); + var params = this.getDataParams(dataIndex, dataType); + + if (extendParams) { + params.value = extendParams.interpolatedValue; + } + + if (labelDimIndex != null && isArray(params.value)) { + params.value = params.value[labelDimIndex]; + } + + if (!formatter) { + var itemModel = data.getItemModel(dataIndex); // @ts-ignore + + formatter = itemModel.get(status === 'normal' ? ['label', 'formatter'] : [status, 'label', 'formatter']); + } + + if (isFunction(formatter)) { + params.status = status; + params.dimensionIndex = labelDimIndex; + return formatter(params); + } else if (isString(formatter)) { + var str = formatTpl(formatter, params); // Support 'aaa{@[3]}bbb{@product}ccc'. + // Do not support '}' in dim name util have to. + + return str.replace(DIMENSION_LABEL_REG, function (origin, dimStr) { + var len = dimStr.length; + var dimLoose = dimStr; + + if (dimLoose.charAt(0) === '[' && dimLoose.charAt(len - 1) === ']') { + dimLoose = +dimLoose.slice(1, len - 1); // Also support: '[]' => 0 + + if ("development" !== 'production') { + if (isNaN(dimLoose)) { + error("Invalide label formatter: @" + dimStr + ", only support @[0], @[1], @[2], ..."); + } + } + } + + var val = retrieveRawValue(data, dataIndex, dimLoose); + + if (extendParams && isArray(extendParams.interpolatedValue)) { + var dimIndex = data.getDimensionIndex(dimLoose); + + if (dimIndex >= 0) { + val = extendParams.interpolatedValue[dimIndex]; + } + } + + return val != null ? val + '' : ''; + }); + } + }; + /** + * Get raw value in option + */ + + + DataFormatMixin.prototype.getRawValue = function (idx, dataType) { + return retrieveRawValue(this.getData(dataType), idx); + }; + /** + * Should be implemented. + * @param {number} dataIndex + * @param {boolean} [multipleSeries=false] + * @param {string} [dataType] + */ + + + DataFormatMixin.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + // Empty function + return; + }; + + return DataFormatMixin; + }(); + // but guess little chance has been used outside. Do we need to backward + // compat it? + // type TooltipFormatResultLegacyObject = { + // // `html` means the markup language text, either in 'html' or 'richText'. + // // The name `html` is not appropriate becuase in 'richText' it is not a HTML + // // string. But still support it for backward compat. + // html: string; + // markers: Dictionary; + // }; + + /** + * For backward compat, normalize the return from `formatTooltip`. + */ + + function normalizeTooltipFormatResult(result) { + var markupText; // let markers: Dictionary; + + var markupFragment; + + if (isObject(result)) { + if (result.type) { + markupFragment = result; + } else { + if ("development" !== 'production') { + console.warn('The return type of `formatTooltip` is not supported: ' + makePrintable(result)); + } + } // else { + // markupText = (result as TooltipFormatResultLegacyObject).html; + // markers = (result as TooltipFormatResultLegacyObject).markers; + // if (markersExisting) { + // markers = zrUtil.merge(markersExisting, markers); + // } + // } + + } else { + markupText = result; + } + + return { + text: markupText, + // markers: markers || markersExisting, + frag: markupFragment + }; + } + + /** + * @param {Object} define + * @return See the return of `createTask`. + */ + + function createTask(define) { + return new Task(define); + } + + var Task = + /** @class */ + function () { + function Task(define) { + define = define || {}; + this._reset = define.reset; + this._plan = define.plan; + this._count = define.count; + this._onDirty = define.onDirty; + this._dirty = true; + } + /** + * @param step Specified step. + * @param skip Skip customer perform call. + * @param modBy Sampling window size. + * @param modDataCount Sampling count. + * @return whether unfinished. + */ + + + Task.prototype.perform = function (performArgs) { + var upTask = this._upstream; + var skip = performArgs && performArgs.skip; // TODO some refactor. + // Pull data. Must pull data each time, because context.data + // may be updated by Series.setData. + + if (this._dirty && upTask) { + var context = this.context; + context.data = context.outputData = upTask.context.outputData; + } + + if (this.__pipeline) { + this.__pipeline.currentTask = this; + } + + var planResult; + + if (this._plan && !skip) { + planResult = this._plan(this.context); + } // Support sharding by mod, which changes the render sequence and makes the rendered graphic + // elements uniformed distributed when progress, especially when moving or zooming. + + + var lastModBy = normalizeModBy(this._modBy); + var lastModDataCount = this._modDataCount || 0; + var modBy = normalizeModBy(performArgs && performArgs.modBy); + var modDataCount = performArgs && performArgs.modDataCount || 0; + + if (lastModBy !== modBy || lastModDataCount !== modDataCount) { + planResult = 'reset'; + } + + function normalizeModBy(val) { + !(val >= 1) && (val = 1); // jshint ignore:line + + return val; + } + + var forceFirstProgress; + + if (this._dirty || planResult === 'reset') { + this._dirty = false; + forceFirstProgress = this._doReset(skip); + } + + this._modBy = modBy; + this._modDataCount = modDataCount; + var step = performArgs && performArgs.step; + + if (upTask) { + if ("development" !== 'production') { + assert(upTask._outputDueEnd != null); + } + + this._dueEnd = upTask._outputDueEnd; + } // DataTask or overallTask + else { + if ("development" !== 'production') { + assert(!this._progress || this._count); + } + + this._dueEnd = this._count ? this._count(this.context) : Infinity; + } // Note: Stubs, that its host overall task let it has progress, has progress. + // If no progress, pass index from upstream to downstream each time plan called. + + + if (this._progress) { + var start = this._dueIndex; + var end = Math.min(step != null ? this._dueIndex + step : Infinity, this._dueEnd); + + if (!skip && (forceFirstProgress || start < end)) { + var progress = this._progress; + + if (isArray(progress)) { + for (var i = 0; i < progress.length; i++) { + this._doProgress(progress[i], start, end, modBy, modDataCount); + } + } else { + this._doProgress(progress, start, end, modBy, modDataCount); + } + } + + this._dueIndex = end; // If no `outputDueEnd`, assume that output data and + // input data is the same, so use `dueIndex` as `outputDueEnd`. + + var outputDueEnd = this._settedOutputEnd != null ? this._settedOutputEnd : end; + + if ("development" !== 'production') { + // ??? Can not rollback. + assert(outputDueEnd >= this._outputDueEnd); + } + + this._outputDueEnd = outputDueEnd; + } else { + // (1) Some overall task has no progress. + // (2) Stubs, that its host overall task do not let it has progress, has no progress. + // This should always be performed so it can be passed to downstream. + this._dueIndex = this._outputDueEnd = this._settedOutputEnd != null ? this._settedOutputEnd : this._dueEnd; + } + + return this.unfinished(); + }; + + Task.prototype.dirty = function () { + this._dirty = true; + this._onDirty && this._onDirty(this.context); + }; + + Task.prototype._doProgress = function (progress, start, end, modBy, modDataCount) { + iterator.reset(start, end, modBy, modDataCount); + this._callingProgress = progress; + + this._callingProgress({ + start: start, + end: end, + count: end - start, + next: iterator.next + }, this.context); + }; + + Task.prototype._doReset = function (skip) { + this._dueIndex = this._outputDueEnd = this._dueEnd = 0; + this._settedOutputEnd = null; + var progress; + var forceFirstProgress; + + if (!skip && this._reset) { + progress = this._reset(this.context); + + if (progress && progress.progress) { + forceFirstProgress = progress.forceFirstProgress; + progress = progress.progress; + } // To simplify no progress checking, array must has item. + + + if (isArray(progress) && !progress.length) { + progress = null; + } + } + + this._progress = progress; + this._modBy = this._modDataCount = null; + var downstream = this._downstream; + downstream && downstream.dirty(); + return forceFirstProgress; + }; + + Task.prototype.unfinished = function () { + return this._progress && this._dueIndex < this._dueEnd; + }; + /** + * @param downTask The downstream task. + * @return The downstream task. + */ + + + Task.prototype.pipe = function (downTask) { + if ("development" !== 'production') { + assert(downTask && !downTask._disposed && downTask !== this); + } // If already downstream, do not dirty downTask. + + + if (this._downstream !== downTask || this._dirty) { + this._downstream = downTask; + downTask._upstream = this; + downTask.dirty(); + } + }; + + Task.prototype.dispose = function () { + if (this._disposed) { + return; + } + + this._upstream && (this._upstream._downstream = null); + this._downstream && (this._downstream._upstream = null); + this._dirty = false; + this._disposed = true; + }; + + Task.prototype.getUpstream = function () { + return this._upstream; + }; + + Task.prototype.getDownstream = function () { + return this._downstream; + }; + + Task.prototype.setOutputEnd = function (end) { + // This only happend in dataTask, dataZoom, map, currently. + // where dataZoom do not set end each time, but only set + // when reset. So we should record the setted end, in case + // that the stub of dataZoom perform again and earse the + // setted end by upstream. + this._outputDueEnd = this._settedOutputEnd = end; + }; + + return Task; + }(); + + var iterator = function () { + var end; + var current; + var modBy; + var modDataCount; + var winCount; + var it = { + reset: function (s, e, sStep, sCount) { + current = s; + end = e; + modBy = sStep; + modDataCount = sCount; + winCount = Math.ceil(modDataCount / modBy); + it.next = modBy > 1 && modDataCount > 0 ? modNext : sequentialNext; + } + }; + return it; + + function sequentialNext() { + return current < end ? current++ : null; + } + + function modNext() { + var dataIndex = current % winCount * modBy + Math.ceil(current / winCount); + var result = current >= end ? null : dataIndex < modDataCount ? dataIndex // If modDataCount is smaller than data.count() (consider `appendData` case), + // Use normal linear rendering mode. + : current; + current++; + return result; + } + }(); /////////////////////////////////////////////////////////// + // For stream debug (Should be commented out after used!) + // @usage: printTask(this, 'begin'); + // @usage: printTask(this, null, {someExtraProp}); + // @usage: Use `__idxInPipeline` as conditional breakpiont. + // + // window.printTask = function (task: any, prefix: string, extra: { [key: string]: unknown }): void { + // window.ecTaskUID == null && (window.ecTaskUID = 0); + // task.uidDebug == null && (task.uidDebug = `task_${window.ecTaskUID++}`); + // task.agent && task.agent.uidDebug == null && (task.agent.uidDebug = `task_${window.ecTaskUID++}`); + // let props = []; + // if (task.__pipeline) { + // let val = `${task.__idxInPipeline}/${task.__pipeline.tail.__idxInPipeline} ${task.agent ? '(stub)' : ''}`; + // props.push({text: '__idxInPipeline/total', value: val}); + // } else { + // let stubCount = 0; + // task.agentStubMap.each(() => stubCount++); + // props.push({text: 'idx', value: `overall (stubs: ${stubCount})`}); + // } + // props.push({text: 'uid', value: task.uidDebug}); + // if (task.__pipeline) { + // props.push({text: 'pipelineId', value: task.__pipeline.id}); + // task.agent && props.push( + // {text: 'stubFor', value: task.agent.uidDebug} + // ); + // } + // props.push( + // {text: 'dirty', value: task._dirty}, + // {text: 'dueIndex', value: task._dueIndex}, + // {text: 'dueEnd', value: task._dueEnd}, + // {text: 'outputDueEnd', value: task._outputDueEnd} + // ); + // if (extra) { + // Object.keys(extra).forEach(key => { + // props.push({text: key, value: extra[key]}); + // }); + // } + // let args = ['color: blue']; + // let msg = `%c[${prefix || 'T'}] %c` + props.map(item => ( + // args.push('color: green', 'color: red'), + // `${item.text}: %c${item.value}` + // )).join('%c, '); + // console.log.apply(console, [msg].concat(args)); + // // console.log(this); + // }; + // window.printPipeline = function (task: any, prefix: string) { + // const pipeline = task.__pipeline; + // let currTask = pipeline.head; + // while (currTask) { + // window.printTask(currTask, prefix); + // currTask = currTask._downstream; + // } + // }; + // window.showChain = function (chainHeadTask) { + // var chain = []; + // var task = chainHeadTask; + // while (task) { + // chain.push({ + // task: task, + // up: task._upstream, + // down: task._downstream, + // idxInPipeline: task.__idxInPipeline + // }); + // task = task._downstream; + // } + // return chain; + // }; + // window.findTaskInChain = function (task, chainHeadTask) { + // let chain = window.showChain(chainHeadTask); + // let result = []; + // for (let i = 0; i < chain.length; i++) { + // let chainItem = chain[i]; + // if (chainItem.task === task) { + // result.push(i); + // } + // } + // return result; + // }; + // window.printChainAEachInChainB = function (chainHeadTaskA, chainHeadTaskB) { + // let chainA = window.showChain(chainHeadTaskA); + // for (let i = 0; i < chainA.length; i++) { + // console.log('chainAIdx:', i, 'inChainB:', window.findTaskInChain(chainA[i].task, chainHeadTaskB)); + // } + // }; + + /** + * Convert raw the value in to inner value in List. + * + * [Performance sensitive] + * + * [Caution]: this is the key logic of user value parser. + * For backward compatibiliy, do not modify it until have to! + */ + + function parseDataValue(value, // For high performance, do not omit the second param. + opt) { + // Performance sensitive. + var dimType = opt && opt.type; + + if (dimType === 'ordinal') { + // If given value is a category string + return value; + } + + if (dimType === 'time' // spead up when using timestamp + && !isNumber(value) && value != null && value !== '-') { + value = +parseDate(value); + } // dimType defaults 'number'. + // If dimType is not ordinal and value is null or undefined or NaN or '-', + // parse to NaN. + // number-like string (like ' 123 ') can be converted to a number. + // where null/undefined or other string will be converted to NaN. + + + return value == null || value === '' ? NaN // If string (like '-'), using '+' parse to NaN + // If object, also parse to NaN + : +value; + } + var valueParserMap = createHashMap({ + 'number': function (val) { + // Do not use `numericToNumber` here. We have by defualt `numericToNumber`. + // Here the number parser can have loose rule: + // enable to cut suffix: "120px" => 120, "14%" => 14. + return parseFloat(val); + }, + 'time': function (val) { + // return timestamp. + return +parseDate(val); + }, + 'trim': function (val) { + return isString(val) ? trim(val) : val; + } + }); + function getRawValueParser(type) { + return valueParserMap.get(type); + } + var ORDER_COMPARISON_OP_MAP = { + lt: function (lval, rval) { + return lval < rval; + }, + lte: function (lval, rval) { + return lval <= rval; + }, + gt: function (lval, rval) { + return lval > rval; + }, + gte: function (lval, rval) { + return lval >= rval; + } + }; + + var FilterOrderComparator = + /** @class */ + function () { + function FilterOrderComparator(op, rval) { + if (!isNumber(rval)) { + var errMsg = ''; + + if ("development" !== 'production') { + errMsg = 'rvalue of "<", ">", "<=", ">=" can only be number in filter.'; + } + + throwError(errMsg); + } + + this._opFn = ORDER_COMPARISON_OP_MAP[op]; + this._rvalFloat = numericToNumber(rval); + } // Performance sensitive. + + + FilterOrderComparator.prototype.evaluate = function (lval) { + // Most cases is 'number', and typeof maybe 10 times faseter than parseFloat. + return isNumber(lval) ? this._opFn(lval, this._rvalFloat) : this._opFn(numericToNumber(lval), this._rvalFloat); + }; + + return FilterOrderComparator; + }(); + + var SortOrderComparator = + /** @class */ + function () { + /** + * @param order by defualt: 'asc' + * @param incomparable by defualt: Always on the tail. + * That is, if 'asc' => 'max', if 'desc' => 'min' + * See the definition of "incomparable" in [SORT_COMPARISON_RULE] + */ + function SortOrderComparator(order, incomparable) { + var isDesc = order === 'desc'; + this._resultLT = isDesc ? 1 : -1; + + if (incomparable == null) { + incomparable = isDesc ? 'min' : 'max'; + } + + this._incomparable = incomparable === 'min' ? -Infinity : Infinity; + } // See [SORT_COMPARISON_RULE]. + // Performance sensitive. + + + SortOrderComparator.prototype.evaluate = function (lval, rval) { + // Most cases is 'number', and typeof maybe 10 times faseter than parseFloat. + var lvalFloat = isNumber(lval) ? lval : numericToNumber(lval); + var rvalFloat = isNumber(rval) ? rval : numericToNumber(rval); + var lvalNotNumeric = isNaN(lvalFloat); + var rvalNotNumeric = isNaN(rvalFloat); + + if (lvalNotNumeric) { + lvalFloat = this._incomparable; + } + + if (rvalNotNumeric) { + rvalFloat = this._incomparable; + } + + if (lvalNotNumeric && rvalNotNumeric) { + var lvalIsStr = isString(lval); + var rvalIsStr = isString(rval); + + if (lvalIsStr) { + lvalFloat = rvalIsStr ? lval : 0; + } + + if (rvalIsStr) { + rvalFloat = lvalIsStr ? rval : 0; + } + } + + return lvalFloat < rvalFloat ? this._resultLT : lvalFloat > rvalFloat ? -this._resultLT : 0; + }; + + return SortOrderComparator; + }(); + + var FilterEqualityComparator = + /** @class */ + function () { + function FilterEqualityComparator(isEq, rval) { + this._rval = rval; + this._isEQ = isEq; + this._rvalTypeof = typeof rval; + this._rvalFloat = numericToNumber(rval); + } // Performance sensitive. + + + FilterEqualityComparator.prototype.evaluate = function (lval) { + var eqResult = lval === this._rval; + + if (!eqResult) { + var lvalTypeof = typeof lval; + + if (lvalTypeof !== this._rvalTypeof && (lvalTypeof === 'number' || this._rvalTypeof === 'number')) { + eqResult = numericToNumber(lval) === this._rvalFloat; + } + } + + return this._isEQ ? eqResult : !eqResult; + }; + + return FilterEqualityComparator; + }(); + /** + * [FILTER_COMPARISON_RULE] + * `lt`|`lte`|`gt`|`gte`: + * + rval must be a number. And lval will be converted to number (`numericToNumber`) to compare. + * `eq`: + * + If same type, compare with `===`. + * + If there is one number, convert to number (`numericToNumber`) to compare. + * + Else return `false`. + * `ne`: + * + Not `eq`. + * + * + * [SORT_COMPARISON_RULE] + * All the values are grouped into three categories: + * + "numeric" (number and numeric string) + * + "non-numeric-string" (string that excluding numeric string) + * + "others" + * "numeric" vs "numeric": values are ordered by number order. + * "non-numeric-string" vs "non-numeric-string": values are ordered by ES spec (#sec-abstract-relational-comparison). + * "others" vs "others": do not change order (always return 0). + * "numeric" vs "non-numeric-string": "non-numeric-string" is treated as "incomparable". + * "number" vs "others": "others" is treated as "incomparable". + * "non-numeric-string" vs "others": "others" is treated as "incomparable". + * "incomparable" will be seen as -Infinity or Infinity (depends on the settings). + * MEMO: + * non-numeric string sort make sence when need to put the items with the same tag together. + * But if we support string sort, we still need to avoid the misleading like `'2' > '12'`, + * So we treat "numeric-string" sorted by number order rather than string comparison. + * + * + * [CHECK_LIST_OF_THE_RULE_DESIGN] + * + Do not support string comparison until required. And also need to + * void the misleading of "2" > "12". + * + Should avoid the misleading case: + * `" 22 " gte "22"` is `true` but `" 22 " eq "22"` is `false`. + * + JS bad case should be avoided: null <= 0, [] <= 0, ' ' <= 0, ... + * + Only "numeric" can be converted to comparable number, otherwise converted to NaN. + * See `util/number.ts#numericToNumber`. + * + * @return If `op` is not `RelationalOperator`, return null; + */ + + + function createFilterComparator(op, rval) { + return op === 'eq' || op === 'ne' ? new FilterEqualityComparator(op === 'eq', rval) : hasOwn(ORDER_COMPARISON_OP_MAP, op) ? new FilterOrderComparator(op, rval) : null; + } + + /** + * TODO: disable writable. + * This structure will be exposed to users. + */ + + var ExternalSource = + /** @class */ + function () { + function ExternalSource() {} + + ExternalSource.prototype.getRawData = function () { + // Only built-in transform available. + throw new Error('not supported'); + }; + + ExternalSource.prototype.getRawDataItem = function (dataIndex) { + // Only built-in transform available. + throw new Error('not supported'); + }; + + ExternalSource.prototype.cloneRawData = function () { + return; + }; + /** + * @return If dimension not found, return null/undefined. + */ + + + ExternalSource.prototype.getDimensionInfo = function (dim) { + return; + }; + /** + * dimensions defined if and only if either: + * (a) dataset.dimensions are declared. + * (b) dataset data include dimensions definitions in data (detected or via specified `sourceHeader`). + * If dimensions are defined, `dimensionInfoAll` is corresponding to + * the defined dimensions. + * Otherwise, `dimensionInfoAll` is determined by data columns. + * @return Always return an array (even empty array). + */ + + + ExternalSource.prototype.cloneAllDimensionInfo = function () { + return; + }; + + ExternalSource.prototype.count = function () { + return; + }; + /** + * Only support by dimension index. + * No need to support by dimension name in transform function, + * becuase transform function is not case-specific, no need to use name literally. + */ + + + ExternalSource.prototype.retrieveValue = function (dataIndex, dimIndex) { + return; + }; + + ExternalSource.prototype.retrieveValueFromItem = function (dataItem, dimIndex) { + return; + }; + + ExternalSource.prototype.convertValue = function (rawVal, dimInfo) { + return parseDataValue(rawVal, dimInfo); + }; + + return ExternalSource; + }(); + + function createExternalSource(internalSource, externalTransform) { + var extSource = new ExternalSource(); + var data = internalSource.data; + var sourceFormat = extSource.sourceFormat = internalSource.sourceFormat; + var sourceHeaderCount = internalSource.startIndex; + var errMsg = ''; + + if (internalSource.seriesLayoutBy !== SERIES_LAYOUT_BY_COLUMN) { + // For the logic simplicity in transformer, only 'culumn' is + // supported in data transform. Otherwise, the `dimensionsDefine` + // might be detected by 'row', which probably confuses users. + if ("development" !== 'production') { + errMsg = '`seriesLayoutBy` of upstream dataset can only be "column" in data transform.'; + } + + throwError(errMsg); + } // [MEMO] + // Create a new dimensions structure for exposing. + // Do not expose all dimension info to users directly. + // Becuase the dimension is probably auto detected from data and not might reliable. + // Should not lead the transformers to think that is relialbe and return it. + // See [DIMENSION_INHERIT_RULE] in `sourceManager.ts`. + + + var dimensions = []; + var dimsByName = {}; + var dimsDef = internalSource.dimensionsDefine; + + if (dimsDef) { + each(dimsDef, function (dimDef, idx) { + var name = dimDef.name; + var dimDefExt = { + index: idx, + name: name, + displayName: dimDef.displayName + }; + dimensions.push(dimDefExt); // Users probably not sepcify dimension name. For simplicity, data transform + // do not generate dimension name. + + if (name != null) { + // Dimension name should not be duplicated. + // For simplicity, data transform forbid name duplication, do not generate + // new name like module `completeDimensions.ts` did, but just tell users. + var errMsg_1 = ''; + + if (hasOwn(dimsByName, name)) { + if ("development" !== 'production') { + errMsg_1 = 'dimension name "' + name + '" duplicated.'; + } + + throwError(errMsg_1); + } + + dimsByName[name] = dimDefExt; + } + }); + } // If dimension definitions are not defined and can not be detected. + // e.g., pure data `[[11, 22], ...]`. + else { + for (var i = 0; i < internalSource.dimensionsDetectedCount || 0; i++) { + // Do not generete name or anything others. The consequence process in + // `transform` or `series` probably have there own name generation strategry. + dimensions.push({ + index: i + }); + } + } // Implement public methods: + + + var rawItemGetter = getRawSourceItemGetter(sourceFormat, SERIES_LAYOUT_BY_COLUMN); + + if (externalTransform.__isBuiltIn) { + extSource.getRawDataItem = function (dataIndex) { + return rawItemGetter(data, sourceHeaderCount, dimensions, dataIndex); + }; + + extSource.getRawData = bind(getRawData, null, internalSource); + } + + extSource.cloneRawData = bind(cloneRawData, null, internalSource); + var rawCounter = getRawSourceDataCounter(sourceFormat, SERIES_LAYOUT_BY_COLUMN); + extSource.count = bind(rawCounter, null, data, sourceHeaderCount, dimensions); + var rawValueGetter = getRawSourceValueGetter(sourceFormat); + + extSource.retrieveValue = function (dataIndex, dimIndex) { + var rawItem = rawItemGetter(data, sourceHeaderCount, dimensions, dataIndex); + return retrieveValueFromItem(rawItem, dimIndex); + }; + + var retrieveValueFromItem = extSource.retrieveValueFromItem = function (dataItem, dimIndex) { + if (dataItem == null) { + return; + } + + var dimDef = dimensions[dimIndex]; // When `dimIndex` is `null`, `rawValueGetter` return the whole item. + + if (dimDef) { + return rawValueGetter(dataItem, dimIndex, dimDef.name); + } + }; + + extSource.getDimensionInfo = bind(getDimensionInfo, null, dimensions, dimsByName); + extSource.cloneAllDimensionInfo = bind(cloneAllDimensionInfo, null, dimensions); + return extSource; + } + + function getRawData(upstream) { + var sourceFormat = upstream.sourceFormat; + + if (!isSupportedSourceFormat(sourceFormat)) { + var errMsg = ''; + + if ("development" !== 'production') { + errMsg = '`getRawData` is not supported in source format ' + sourceFormat; + } + + throwError(errMsg); + } + + return upstream.data; + } + + function cloneRawData(upstream) { + var sourceFormat = upstream.sourceFormat; + var data = upstream.data; + + if (!isSupportedSourceFormat(sourceFormat)) { + var errMsg = ''; + + if ("development" !== 'production') { + errMsg = '`cloneRawData` is not supported in source format ' + sourceFormat; + } + + throwError(errMsg); + } + + if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) { + var result = []; + + for (var i = 0, len = data.length; i < len; i++) { + // Not strictly clone for performance + result.push(data[i].slice()); + } + + return result; + } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) { + var result = []; + + for (var i = 0, len = data.length; i < len; i++) { + // Not strictly clone for performance + result.push(extend({}, data[i])); + } + + return result; + } + } + + function getDimensionInfo(dimensions, dimsByName, dim) { + if (dim == null) { + return; + } // Keep the same logic as `List::getDimension` did. + + + if (isNumber(dim) // If being a number-like string but not being defined a dimension name. + || !isNaN(dim) && !hasOwn(dimsByName, dim)) { + return dimensions[dim]; + } else if (hasOwn(dimsByName, dim)) { + return dimsByName[dim]; + } + } + + function cloneAllDimensionInfo(dimensions) { + return clone(dimensions); + } + + var externalTransformMap = createHashMap(); + function registerExternalTransform(externalTransform) { + externalTransform = clone(externalTransform); + var type = externalTransform.type; + var errMsg = ''; + + if (!type) { + if ("development" !== 'production') { + errMsg = 'Must have a `type` when `registerTransform`.'; + } + + throwError(errMsg); + } + + var typeParsed = type.split(':'); + + if (typeParsed.length !== 2) { + if ("development" !== 'production') { + errMsg = 'Name must include namespace like "ns:regression".'; + } + + throwError(errMsg); + } // Namespace 'echarts:xxx' is official namespace, where the transforms should + // be called directly via 'xxx' rather than 'echarts:xxx'. + + + var isBuiltIn = false; + + if (typeParsed[0] === 'echarts') { + type = typeParsed[1]; + isBuiltIn = true; + } + + externalTransform.__isBuiltIn = isBuiltIn; + externalTransformMap.set(type, externalTransform); + } + function applyDataTransform(rawTransOption, sourceList, infoForPrint) { + var pipedTransOption = normalizeToArray(rawTransOption); + var pipeLen = pipedTransOption.length; + var errMsg = ''; + + if (!pipeLen) { + if ("development" !== 'production') { + errMsg = 'If `transform` declared, it should at least contain one transform.'; + } + + throwError(errMsg); + } + + for (var i = 0, len = pipeLen; i < len; i++) { + var transOption = pipedTransOption[i]; + sourceList = applySingleDataTransform(transOption, sourceList, infoForPrint, pipeLen === 1 ? null : i); // piped transform only support single input, except the fist one. + // piped transform only support single output, except the last one. + + if (i !== len - 1) { + sourceList.length = Math.max(sourceList.length, 1); + } + } + + return sourceList; + } + + function applySingleDataTransform(transOption, upSourceList, infoForPrint, // If `pipeIndex` is null/undefined, no piped transform. + pipeIndex) { + var errMsg = ''; + + if (!upSourceList.length) { + if ("development" !== 'production') { + errMsg = 'Must have at least one upstream dataset.'; + } + + throwError(errMsg); + } + + if (!isObject(transOption)) { + if ("development" !== 'production') { + errMsg = 'transform declaration must be an object rather than ' + typeof transOption + '.'; + } + + throwError(errMsg); + } + + var transType = transOption.type; + var externalTransform = externalTransformMap.get(transType); + + if (!externalTransform) { + if ("development" !== 'production') { + errMsg = 'Can not find transform on type "' + transType + '".'; + } + + throwError(errMsg); + } // Prepare source + + + var extUpSourceList = map(upSourceList, function (upSource) { + return createExternalSource(upSource, externalTransform); + }); + var resultList = normalizeToArray(externalTransform.transform({ + upstream: extUpSourceList[0], + upstreamList: extUpSourceList, + config: clone(transOption.config) + })); + + if ("development" !== 'production') { + if (transOption.print) { + var printStrArr = map(resultList, function (extSource) { + var pipeIndexStr = pipeIndex != null ? ' === pipe index: ' + pipeIndex : ''; + return ['=== dataset index: ' + infoForPrint.datasetIndex + pipeIndexStr + ' ===', '- transform result data:', makePrintable(extSource.data), '- transform result dimensions:', makePrintable(extSource.dimensions)].join('\n'); + }).join('\n'); + log(printStrArr); + } + } + + return map(resultList, function (result, resultIndex) { + var errMsg = ''; + + if (!isObject(result)) { + if ("development" !== 'production') { + errMsg = 'A transform should not return some empty results.'; + } + + throwError(errMsg); + } + + if (!result.data) { + if ("development" !== 'production') { + errMsg = 'Transform result data should be not be null or undefined'; + } + + throwError(errMsg); + } + + var sourceFormat = detectSourceFormat(result.data); + + if (!isSupportedSourceFormat(sourceFormat)) { + if ("development" !== 'production') { + errMsg = 'Transform result data should be array rows or object rows.'; + } + + throwError(errMsg); + } + + var resultMetaRawOption; + var firstUpSource = upSourceList[0]; + /** + * Intuitively, the end users known the content of the original `dataset.source`, + * calucating the transform result in mind. + * Suppose the original `dataset.source` is: + * ```js + * [ + * ['product', '2012', '2013', '2014', '2015'], + * ['AAA', 41.1, 30.4, 65.1, 53.3], + * ['BBB', 86.5, 92.1, 85.7, 83.1], + * ['CCC', 24.1, 67.2, 79.5, 86.4] + * ] + * ``` + * The dimension info have to be detected from the source data. + * Some of the transformers (like filter, sort) will follow the dimension info + * of upstream, while others use new dimensions (like aggregate). + * Transformer can output a field `dimensions` to define the its own output dimensions. + * We also allow transformers to ignore the output `dimensions` field, and + * inherit the upstream dimensions definition. It can reduce the burden of handling + * dimensions in transformers. + * + * See also [DIMENSION_INHERIT_RULE] in `sourceManager.ts`. + */ + + if (firstUpSource && resultIndex === 0 // If transformer returns `dimensions`, it means that the transformer has different + // dimensions definitions. We do not inherit anything from upstream. + && !result.dimensions) { + var startIndex = firstUpSource.startIndex; // We copy the header of upstream to the result becuase: + // (1) The returned data always does not contain header line and can not be used + // as dimension-detection. In this case we can not use "detected dimensions" of + // upstream directly, because it might be detected based on different `seriesLayoutBy`. + // (2) We should support that the series read the upstream source in `seriesLayoutBy: 'row'`. + // So the original detected header should be add to the result, otherwise they can not be read. + + if (startIndex) { + result.data = firstUpSource.data.slice(0, startIndex).concat(result.data); + } + + resultMetaRawOption = { + seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN, + sourceHeader: startIndex, + dimensions: firstUpSource.metaRawOption.dimensions + }; + } else { + resultMetaRawOption = { + seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN, + sourceHeader: 0, + dimensions: result.dimensions + }; + } + + return createSource(result.data, resultMetaRawOption, null); + }); + } + + function isSupportedSourceFormat(sourceFormat) { + return sourceFormat === SOURCE_FORMAT_ARRAY_ROWS || sourceFormat === SOURCE_FORMAT_OBJECT_ROWS; + } + + var UNDEFINED = 'undefined'; + /* global Float64Array, Int32Array, Uint32Array, Uint16Array */ + // Caution: MUST not use `new CtorUint32Array(arr, 0, len)`, because the Ctor of array is + // different from the Ctor of typed array. + + var CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array; + var CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array; + var CtorInt32Array = typeof Int32Array === UNDEFINED ? Array : Int32Array; + var CtorFloat64Array = typeof Float64Array === UNDEFINED ? Array : Float64Array; + /** + * Multi dimensional data store + */ + + var dataCtors = { + 'float': CtorFloat64Array, + 'int': CtorInt32Array, + // Ordinal data type can be string or int + 'ordinal': Array, + 'number': Array, + 'time': CtorFloat64Array + }; + var defaultDimValueGetters; + + function getIndicesCtor(rawCount) { + // The possible max value in this._indicies is always this._rawCount despite of filtering. + return rawCount > 65535 ? CtorUint32Array : CtorUint16Array; + } + + function getInitialExtent() { + return [Infinity, -Infinity]; + } + + function cloneChunk(originalChunk) { + var Ctor = originalChunk.constructor; // Only shallow clone is enough when Array. + + return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk); + } + + function prepareStore(store, dimIdx, dimType, end, append) { + var DataCtor = dataCtors[dimType || 'float']; + + if (append) { + var oldStore = store[dimIdx]; + var oldLen = oldStore && oldStore.length; + + if (!(oldLen === end)) { + var newStore = new DataCtor(end); // The cost of the copy is probably inconsiderable + // within the initial chunkSize. + + for (var j = 0; j < oldLen; j++) { + newStore[j] = oldStore[j]; + } + + store[dimIdx] = newStore; + } + } else { + store[dimIdx] = new DataCtor(end); + } + } + /** + * Basically, DataStore API keep immutable. + */ + + var DataStore = + /** @class */ + function () { + function DataStore() { + this._chunks = []; // It will not be calculated util needed. + + this._rawExtent = []; + this._extent = []; + this._count = 0; + this._rawCount = 0; + this._calcDimNameToIdx = createHashMap(); + } + /** + * Initialize from data + */ + + + DataStore.prototype.initData = function (provider, inputDimensions, dimValueGetter) { + if ("development" !== 'production') { + assert(isFunction(provider.getItem) && isFunction(provider.count), 'Inavlid data provider.'); + } + + this._provider = provider; // Clear + + this._chunks = []; + this._indices = null; + this.getRawIndex = this._getRawIdxIdentity; + var source = provider.getSource(); + var defaultGetter = this.defaultDimValueGetter = defaultDimValueGetters[source.sourceFormat]; // Default dim value getter + + this._dimValueGetter = dimValueGetter || defaultGetter; // Reset raw extent. + + this._rawExtent = []; + var willRetrieveDataByName = shouldRetrieveDataByName(source); + this._dimensions = map(inputDimensions, function (dim) { + if ("development" !== 'production') { + if (willRetrieveDataByName) { + assert(dim.property != null); + } + } + + return { + // Only pick these two props. Not leak other properties like orderMeta. + type: dim.type, + property: dim.property + }; + }); + + this._initDataFromProvider(0, provider.count()); + }; + + DataStore.prototype.getProvider = function () { + return this._provider; + }; + /** + * Caution: even when a `source` instance owned by a series, the created data store + * may still be shared by different sereis (the source hash does not use all `source` + * props, see `sourceManager`). In this case, the `source` props that are not used in + * hash (like `source.dimensionDefine`) probably only belongs to a certain series and + * thus should not be fetch here. + */ + + + DataStore.prototype.getSource = function () { + return this._provider.getSource(); + }; + /** + * @caution Only used in dataStack. + */ + + + DataStore.prototype.ensureCalculationDimension = function (dimName, type) { + var calcDimNameToIdx = this._calcDimNameToIdx; + var dimensions = this._dimensions; + var calcDimIdx = calcDimNameToIdx.get(dimName); + + if (calcDimIdx != null) { + if (dimensions[calcDimIdx].type === type) { + return calcDimIdx; + } + } else { + calcDimIdx = dimensions.length; + } + + dimensions[calcDimIdx] = { + type: type + }; + calcDimNameToIdx.set(dimName, calcDimIdx); + this._chunks[calcDimIdx] = new dataCtors[type || 'float'](this._rawCount); + this._rawExtent[calcDimIdx] = getInitialExtent(); + return calcDimIdx; + }; + + DataStore.prototype.collectOrdinalMeta = function (dimIdx, ordinalMeta) { + var chunk = this._chunks[dimIdx]; + var dim = this._dimensions[dimIdx]; + var rawExtents = this._rawExtent; + var offset = dim.ordinalOffset || 0; + var len = chunk.length; + + if (offset === 0) { + // We need to reset the rawExtent if collect is from start. + // Because this dimension may be guessed as number and calcuating a wrong extent. + rawExtents[dimIdx] = getInitialExtent(); + } + + var dimRawExtent = rawExtents[dimIdx]; // Parse from previous data offset. len may be changed after appendData + + for (var i = offset; i < len; i++) { + var val = chunk[i] = ordinalMeta.parseAndCollect(chunk[i]); + + if (!isNaN(val)) { + dimRawExtent[0] = Math.min(val, dimRawExtent[0]); + dimRawExtent[1] = Math.max(val, dimRawExtent[1]); + } + } + + dim.ordinalMeta = ordinalMeta; + dim.ordinalOffset = len; + dim.type = 'ordinal'; // Force to be ordinal + }; + + DataStore.prototype.getOrdinalMeta = function (dimIdx) { + var dimInfo = this._dimensions[dimIdx]; + var ordinalMeta = dimInfo.ordinalMeta; + return ordinalMeta; + }; + + DataStore.prototype.getDimensionProperty = function (dimIndex) { + var item = this._dimensions[dimIndex]; + return item && item.property; + }; + /** + * Caution: Can be only called on raw data (before `this._indices` created). + */ + + + DataStore.prototype.appendData = function (data) { + if ("development" !== 'production') { + assert(!this._indices, 'appendData can only be called on raw data.'); + } + + var provider = this._provider; + var start = this.count(); + provider.appendData(data); + var end = provider.count(); + + if (!provider.persistent) { + end += start; + } + + if (start < end) { + this._initDataFromProvider(start, end, true); + } + + return [start, end]; + }; + + DataStore.prototype.appendValues = function (values, minFillLen) { + var chunks = this._chunks; + var dimensions = this._dimensions; + var dimLen = dimensions.length; + var rawExtent = this._rawExtent; + var start = this.count(); + var end = start + Math.max(values.length, minFillLen || 0); + + for (var i = 0; i < dimLen; i++) { + var dim = dimensions[i]; + prepareStore(chunks, i, dim.type, end, true); + } + + var emptyDataItem = []; + + for (var idx = start; idx < end; idx++) { + var sourceIdx = idx - start; // Store the data by dimensions + + for (var dimIdx = 0; dimIdx < dimLen; dimIdx++) { + var dim = dimensions[dimIdx]; + var val = defaultDimValueGetters.arrayRows.call(this, values[sourceIdx] || emptyDataItem, dim.property, sourceIdx, dimIdx); + chunks[dimIdx][idx] = val; + var dimRawExtent = rawExtent[dimIdx]; + val < dimRawExtent[0] && (dimRawExtent[0] = val); + val > dimRawExtent[1] && (dimRawExtent[1] = val); + } + } + + this._rawCount = this._count = end; + return { + start: start, + end: end + }; + }; + + DataStore.prototype._initDataFromProvider = function (start, end, append) { + var provider = this._provider; + var chunks = this._chunks; + var dimensions = this._dimensions; + var dimLen = dimensions.length; + var rawExtent = this._rawExtent; + var dimNames = map(dimensions, function (dim) { + return dim.property; + }); + + for (var i = 0; i < dimLen; i++) { + var dim = dimensions[i]; + + if (!rawExtent[i]) { + rawExtent[i] = getInitialExtent(); + } + + prepareStore(chunks, i, dim.type, end, append); + } + + if (provider.fillStorage) { + provider.fillStorage(start, end, chunks, rawExtent); + } else { + var dataItem = []; + + for (var idx = start; idx < end; idx++) { + // NOTICE: Try not to write things into dataItem + dataItem = provider.getItem(idx, dataItem); // Each data item is value + // [1, 2] + // 2 + // Bar chart, line chart which uses category axis + // only gives the 'y' value. 'x' value is the indices of category + // Use a tempValue to normalize the value to be a (x, y) value + // Store the data by dimensions + + for (var dimIdx = 0; dimIdx < dimLen; dimIdx++) { + var dimStorage = chunks[dimIdx]; // PENDING NULL is empty or zero + + var val = this._dimValueGetter(dataItem, dimNames[dimIdx], idx, dimIdx); + + dimStorage[idx] = val; + var dimRawExtent = rawExtent[dimIdx]; + val < dimRawExtent[0] && (dimRawExtent[0] = val); + val > dimRawExtent[1] && (dimRawExtent[1] = val); + } + } + } + + if (!provider.persistent && provider.clean) { + // Clean unused data if data source is typed array. + provider.clean(); + } + + this._rawCount = this._count = end; // Reset data extent + + this._extent = []; + }; + + DataStore.prototype.count = function () { + return this._count; + }; + /** + * Get value. Return NaN if idx is out of range. + */ + + + DataStore.prototype.get = function (dim, idx) { + if (!(idx >= 0 && idx < this._count)) { + return NaN; + } + + var dimStore = this._chunks[dim]; + return dimStore ? dimStore[this.getRawIndex(idx)] : NaN; + }; + + DataStore.prototype.getValues = function (dimensions, idx) { + var values = []; + var dimArr = []; + + if (idx == null) { + idx = dimensions; // TODO get all from store? + + dimensions = []; // All dimensions + + for (var i = 0; i < this._dimensions.length; i++) { + dimArr.push(i); + } + } else { + dimArr = dimensions; + } + + for (var i = 0, len = dimArr.length; i < len; i++) { + values.push(this.get(dimArr[i], idx)); + } + + return values; + }; + /** + * @param dim concrete dim + */ + + + DataStore.prototype.getByRawIndex = function (dim, rawIdx) { + if (!(rawIdx >= 0 && rawIdx < this._rawCount)) { + return NaN; + } + + var dimStore = this._chunks[dim]; + return dimStore ? dimStore[rawIdx] : NaN; + }; + /** + * Get sum of data in one dimension + */ + + + DataStore.prototype.getSum = function (dim) { + var dimData = this._chunks[dim]; + var sum = 0; + + if (dimData) { + for (var i = 0, len = this.count(); i < len; i++) { + var value = this.get(dim, i); + + if (!isNaN(value)) { + sum += value; + } + } + } + + return sum; + }; + /** + * Get median of data in one dimension + */ + + + DataStore.prototype.getMedian = function (dim) { + var dimDataArray = []; // map all data of one dimension + + this.each([dim], function (val) { + if (!isNaN(val)) { + dimDataArray.push(val); + } + }); // TODO + // Use quick select? + + var sortedDimDataArray = dimDataArray.sort(function (a, b) { + return a - b; + }); + var len = this.count(); // calculate median + + return len === 0 ? 0 : len % 2 === 1 ? sortedDimDataArray[(len - 1) / 2] : (sortedDimDataArray[len / 2] + sortedDimDataArray[len / 2 - 1]) / 2; + }; + /** + * Retreive the index with given raw data index + */ + + + DataStore.prototype.indexOfRawIndex = function (rawIndex) { + if (rawIndex >= this._rawCount || rawIndex < 0) { + return -1; + } + + if (!this._indices) { + return rawIndex; + } // Indices are ascending + + + var indices = this._indices; // If rawIndex === dataIndex + + var rawDataIndex = indices[rawIndex]; + + if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) { + return rawIndex; + } + + var left = 0; + var right = this._count - 1; + + while (left <= right) { + var mid = (left + right) / 2 | 0; + + if (indices[mid] < rawIndex) { + left = mid + 1; + } else if (indices[mid] > rawIndex) { + right = mid - 1; + } else { + return mid; + } + } + + return -1; + }; + /** + * Retreive the index of nearest value + * @param dim + * @param value + * @param [maxDistance=Infinity] + * @return If and only if multiple indices has + * the same value, they are put to the result. + */ + + + DataStore.prototype.indicesOfNearest = function (dim, value, maxDistance) { + var chunks = this._chunks; + var dimData = chunks[dim]; + var nearestIndices = []; + + if (!dimData) { + return nearestIndices; + } + + if (maxDistance == null) { + maxDistance = Infinity; + } + + var minDist = Infinity; + var minDiff = -1; + var nearestIndicesLen = 0; // Check the test case of `test/ut/spec/data/SeriesData.js`. + + for (var i = 0, len = this.count(); i < len; i++) { + var dataIndex = this.getRawIndex(i); + var diff = value - dimData[dataIndex]; + var dist = Math.abs(diff); + + if (dist <= maxDistance) { + // When the `value` is at the middle of `this.get(dim, i)` and `this.get(dim, i+1)`, + // we'd better not push both of them to `nearestIndices`, otherwise it is easy to + // get more than one item in `nearestIndices` (more specifically, in `tooltip`). + // So we chose the one that `diff >= 0` in this csae. + // But if `this.get(dim, i)` and `this.get(dim, j)` get the same value, both of them + // should be push to `nearestIndices`. + if (dist < minDist || dist === minDist && diff >= 0 && minDiff < 0) { + minDist = dist; + minDiff = diff; + nearestIndicesLen = 0; + } + + if (diff === minDiff) { + nearestIndices[nearestIndicesLen++] = i; + } + } + } + + nearestIndices.length = nearestIndicesLen; + return nearestIndices; + }; + + DataStore.prototype.getIndices = function () { + var newIndices; + var indices = this._indices; + + if (indices) { + var Ctor = indices.constructor; + var thisCount = this._count; // `new Array(a, b, c)` is different from `new Uint32Array(a, b, c)`. + + if (Ctor === Array) { + newIndices = new Ctor(thisCount); + + for (var i = 0; i < thisCount; i++) { + newIndices[i] = indices[i]; + } + } else { + newIndices = new Ctor(indices.buffer, 0, thisCount); + } + } else { + var Ctor = getIndicesCtor(this._rawCount); + newIndices = new Ctor(this.count()); + + for (var i = 0; i < newIndices.length; i++) { + newIndices[i] = i; + } + } + + return newIndices; + }; + /** + * Data filter. + */ + + + DataStore.prototype.filter = function (dims, cb) { + if (!this._count) { + return this; + } + + var newStore = this.clone(); + var count = newStore.count(); + var Ctor = getIndicesCtor(newStore._rawCount); + var newIndices = new Ctor(count); + var value = []; + var dimSize = dims.length; + var offset = 0; + var dim0 = dims[0]; + var chunks = newStore._chunks; + + for (var i = 0; i < count; i++) { + var keep = void 0; + var rawIdx = newStore.getRawIndex(i); // Simple optimization + + if (dimSize === 0) { + keep = cb(i); + } else if (dimSize === 1) { + var val = chunks[dim0][rawIdx]; + keep = cb(val, i); + } else { + var k = 0; + + for (; k < dimSize; k++) { + value[k] = chunks[dims[k]][rawIdx]; + } + + value[k] = i; + keep = cb.apply(null, value); + } + + if (keep) { + newIndices[offset++] = rawIdx; + } + } // Set indices after filtered. + + + if (offset < count) { + newStore._indices = newIndices; + } + + newStore._count = offset; // Reset data extent + + newStore._extent = []; + + newStore._updateGetRawIdx(); + + return newStore; + }; + /** + * Select data in range. (For optimization of filter) + * (Manually inline code, support 5 million data filtering in data zoom.) + */ + + + DataStore.prototype.selectRange = function (range) { + var newStore = this.clone(); + var len = newStore._count; + + if (!len) { + return this; + } + + var dims = keys(range); + var dimSize = dims.length; + + if (!dimSize) { + return this; + } + + var originalCount = newStore.count(); + var Ctor = getIndicesCtor(newStore._rawCount); + var newIndices = new Ctor(originalCount); + var offset = 0; + var dim0 = dims[0]; + var min = range[dim0][0]; + var max = range[dim0][1]; + var storeArr = newStore._chunks; + var quickFinished = false; + + if (!newStore._indices) { + // Extreme optimization for common case. About 2x faster in chrome. + var idx = 0; + + if (dimSize === 1) { + var dimStorage = storeArr[dims[0]]; + + for (var i = 0; i < len; i++) { + var val = dimStorage[i]; // NaN will not be filtered. Consider the case, in line chart, empty + // value indicates the line should be broken. But for the case like + // scatter plot, a data item with empty value will not be rendered, + // but the axis extent may be effected if some other dim of the data + // item has value. Fortunately it is not a significant negative effect. + + if (val >= min && val <= max || isNaN(val)) { + newIndices[offset++] = idx; + } + + idx++; + } + + quickFinished = true; + } else if (dimSize === 2) { + var dimStorage = storeArr[dims[0]]; + var dimStorage2 = storeArr[dims[1]]; + var min2 = range[dims[1]][0]; + var max2 = range[dims[1]][1]; + + for (var i = 0; i < len; i++) { + var val = dimStorage[i]; + var val2 = dimStorage2[i]; // Do not filter NaN, see comment above. + + if ((val >= min && val <= max || isNaN(val)) && (val2 >= min2 && val2 <= max2 || isNaN(val2))) { + newIndices[offset++] = idx; + } + + idx++; + } + + quickFinished = true; + } + } + + if (!quickFinished) { + if (dimSize === 1) { + for (var i = 0; i < originalCount; i++) { + var rawIndex = newStore.getRawIndex(i); + var val = storeArr[dims[0]][rawIndex]; // Do not filter NaN, see comment above. + + if (val >= min && val <= max || isNaN(val)) { + newIndices[offset++] = rawIndex; + } + } + } else { + for (var i = 0; i < originalCount; i++) { + var keep = true; + var rawIndex = newStore.getRawIndex(i); + + for (var k = 0; k < dimSize; k++) { + var dimk = dims[k]; + var val = storeArr[dimk][rawIndex]; // Do not filter NaN, see comment above. + + if (val < range[dimk][0] || val > range[dimk][1]) { + keep = false; + } + } + + if (keep) { + newIndices[offset++] = newStore.getRawIndex(i); + } + } + } + } // Set indices after filtered. + + + if (offset < originalCount) { + newStore._indices = newIndices; + } + + newStore._count = offset; // Reset data extent + + newStore._extent = []; + + newStore._updateGetRawIdx(); + + return newStore; + }; // /** + // * Data mapping to a plain array + // */ + // mapArray(dims: DimensionIndex[], cb: MapArrayCb): any[] { + // const result: any[] = []; + // this.each(dims, function () { + // result.push(cb && (cb as MapArrayCb).apply(null, arguments)); + // }); + // return result; + // } + + /** + * Data mapping to a new List with given dimensions + */ + + + DataStore.prototype.map = function (dims, cb) { + // TODO only clone picked chunks. + var target = this.clone(dims); + + this._updateDims(target, dims, cb); + + return target; + }; + /** + * @caution Danger!! Only used in dataStack. + */ + + + DataStore.prototype.modify = function (dims, cb) { + this._updateDims(this, dims, cb); + }; + + DataStore.prototype._updateDims = function (target, dims, cb) { + var targetChunks = target._chunks; + var tmpRetValue = []; + var dimSize = dims.length; + var dataCount = target.count(); + var values = []; + var rawExtent = target._rawExtent; + + for (var i = 0; i < dims.length; i++) { + rawExtent[dims[i]] = getInitialExtent(); + } + + for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) { + var rawIndex = target.getRawIndex(dataIndex); + + for (var k = 0; k < dimSize; k++) { + values[k] = targetChunks[dims[k]][rawIndex]; + } + + values[dimSize] = dataIndex; + var retValue = cb && cb.apply(null, values); + + if (retValue != null) { + // a number or string (in oridinal dimension)? + if (typeof retValue !== 'object') { + tmpRetValue[0] = retValue; + retValue = tmpRetValue; + } + + for (var i = 0; i < retValue.length; i++) { + var dim = dims[i]; + var val = retValue[i]; + var rawExtentOnDim = rawExtent[dim]; + var dimStore = targetChunks[dim]; + + if (dimStore) { + dimStore[rawIndex] = val; + } + + if (val < rawExtentOnDim[0]) { + rawExtentOnDim[0] = val; + } + + if (val > rawExtentOnDim[1]) { + rawExtentOnDim[1] = val; + } + } + } + } + }; + /** + * Large data down sampling using largest-triangle-three-buckets + * @param {string} valueDimension + * @param {number} targetCount + */ + + + DataStore.prototype.lttbDownSample = function (valueDimension, rate) { + var target = this.clone([valueDimension], true); + var targetStorage = target._chunks; + var dimStore = targetStorage[valueDimension]; + var len = this.count(); + var sampledIndex = 0; + var frameSize = Math.floor(1 / rate); + var currentRawIndex = this.getRawIndex(0); + var maxArea; + var area; + var nextRawIndex; + var newIndices = new (getIndicesCtor(this._rawCount))(Math.min((Math.ceil(len / frameSize) + 2) * 2, len)); // First frame use the first data. + + newIndices[sampledIndex++] = currentRawIndex; + + for (var i = 1; i < len - 1; i += frameSize) { + var nextFrameStart = Math.min(i + frameSize, len - 1); + var nextFrameEnd = Math.min(i + frameSize * 2, len); + var avgX = (nextFrameEnd + nextFrameStart) / 2; + var avgY = 0; + + for (var idx = nextFrameStart; idx < nextFrameEnd; idx++) { + var rawIndex = this.getRawIndex(idx); + var y = dimStore[rawIndex]; + + if (isNaN(y)) { + continue; + } + + avgY += y; + } + + avgY /= nextFrameEnd - nextFrameStart; + var frameStart = i; + var frameEnd = Math.min(i + frameSize, len); + var pointAX = i - 1; + var pointAY = dimStore[currentRawIndex]; + maxArea = -1; + nextRawIndex = frameStart; + var firstNaNIndex = -1; + var countNaN = 0; // Find a point from current frame that construct a triangel with largest area with previous selected point + // And the average of next frame. + + for (var idx = frameStart; idx < frameEnd; idx++) { + var rawIndex = this.getRawIndex(idx); + var y = dimStore[rawIndex]; + + if (isNaN(y)) { + countNaN++; + + if (firstNaNIndex < 0) { + firstNaNIndex = rawIndex; + } + + continue; + } // Calculate triangle area over three buckets + + + area = Math.abs((pointAX - avgX) * (y - pointAY) - (pointAX - idx) * (avgY - pointAY)); + + if (area > maxArea) { + maxArea = area; + nextRawIndex = rawIndex; // Next a is this b + } + } + + if (countNaN > 0 && countNaN < frameEnd - frameStart) { + // Append first NaN point in every bucket. + // It is necessary to ensure the correct order of indices. + newIndices[sampledIndex++] = Math.min(firstNaNIndex, nextRawIndex); + nextRawIndex = Math.max(firstNaNIndex, nextRawIndex); + } + + newIndices[sampledIndex++] = nextRawIndex; + currentRawIndex = nextRawIndex; // This a is the next a (chosen b) + } // First frame use the last data. + + + newIndices[sampledIndex++] = this.getRawIndex(len - 1); + target._count = sampledIndex; + target._indices = newIndices; + target.getRawIndex = this._getRawIdx; + return target; + }; + /** + * Large data down sampling on given dimension + * @param sampleIndex Sample index for name and id + */ + + + DataStore.prototype.downSample = function (dimension, rate, sampleValue, sampleIndex) { + var target = this.clone([dimension], true); + var targetStorage = target._chunks; + var frameValues = []; + var frameSize = Math.floor(1 / rate); + var dimStore = targetStorage[dimension]; + var len = this.count(); + var rawExtentOnDim = target._rawExtent[dimension] = getInitialExtent(); + var newIndices = new (getIndicesCtor(this._rawCount))(Math.ceil(len / frameSize)); + var offset = 0; + + for (var i = 0; i < len; i += frameSize) { + // Last frame + if (frameSize > len - i) { + frameSize = len - i; + frameValues.length = frameSize; + } + + for (var k = 0; k < frameSize; k++) { + var dataIdx = this.getRawIndex(i + k); + frameValues[k] = dimStore[dataIdx]; + } + + var value = sampleValue(frameValues); + var sampleFrameIdx = this.getRawIndex(Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)); // Only write value on the filtered data + + dimStore[sampleFrameIdx] = value; + + if (value < rawExtentOnDim[0]) { + rawExtentOnDim[0] = value; + } + + if (value > rawExtentOnDim[1]) { + rawExtentOnDim[1] = value; + } + + newIndices[offset++] = sampleFrameIdx; + } + + target._count = offset; + target._indices = newIndices; + + target._updateGetRawIdx(); + + return target; + }; + /** + * Data iteration + * @param ctx default this + * @example + * list.each('x', function (x, idx) {}); + * list.each(['x', 'y'], function (x, y, idx) {}); + * list.each(function (idx) {}) + */ + + + DataStore.prototype.each = function (dims, cb) { + if (!this._count) { + return; + } + + var dimSize = dims.length; + var chunks = this._chunks; + + for (var i = 0, len = this.count(); i < len; i++) { + var rawIdx = this.getRawIndex(i); // Simple optimization + + switch (dimSize) { + case 0: + cb(i); + break; + + case 1: + cb(chunks[dims[0]][rawIdx], i); + break; + + case 2: + cb(chunks[dims[0]][rawIdx], chunks[dims[1]][rawIdx], i); + break; + + default: + var k = 0; + var value = []; + + for (; k < dimSize; k++) { + value[k] = chunks[dims[k]][rawIdx]; + } // Index + + + value[k] = i; + cb.apply(null, value); + } + } + }; + /** + * Get extent of data in one dimension + */ + + + DataStore.prototype.getDataExtent = function (dim) { + // Make sure use concrete dim as cache name. + var dimData = this._chunks[dim]; + var initialExtent = getInitialExtent(); + + if (!dimData) { + return initialExtent; + } // Make more strict checkings to ensure hitting cache. + + + var currEnd = this.count(); // Consider the most cases when using data zoom, `getDataExtent` + // happened before filtering. We cache raw extent, which is not + // necessary to be cleared and recalculated when restore data. + + var useRaw = !this._indices; + var dimExtent; + + if (useRaw) { + return this._rawExtent[dim].slice(); + } + + dimExtent = this._extent[dim]; + + if (dimExtent) { + return dimExtent.slice(); + } + + dimExtent = initialExtent; + var min = dimExtent[0]; + var max = dimExtent[1]; + + for (var i = 0; i < currEnd; i++) { + var rawIdx = this.getRawIndex(i); + var value = dimData[rawIdx]; + value < min && (min = value); + value > max && (max = value); + } + + dimExtent = [min, max]; + this._extent[dim] = dimExtent; + return dimExtent; + }; + /** + * Get raw data item + */ + + + DataStore.prototype.getRawDataItem = function (idx) { + var rawIdx = this.getRawIndex(idx); + + if (!this._provider.persistent) { + var val = []; + var chunks = this._chunks; + + for (var i = 0; i < chunks.length; i++) { + val.push(chunks[i][rawIdx]); + } + + return val; + } else { + return this._provider.getItem(rawIdx); + } + }; + /** + * Clone shallow. + * + * @param clonedDims Determine which dims to clone. Will share the data if not specified. + */ + + + DataStore.prototype.clone = function (clonedDims, ignoreIndices) { + var target = new DataStore(); + var chunks = this._chunks; + var clonedDimsMap = clonedDims && reduce(clonedDims, function (obj, dimIdx) { + obj[dimIdx] = true; + return obj; + }, {}); + + if (clonedDimsMap) { + for (var i = 0; i < chunks.length; i++) { + // Not clone if dim is not picked. + target._chunks[i] = !clonedDimsMap[i] ? chunks[i] : cloneChunk(chunks[i]); + } + } else { + target._chunks = chunks; + } + + this._copyCommonProps(target); + + if (!ignoreIndices) { + target._indices = this._cloneIndices(); + } + + target._updateGetRawIdx(); + + return target; + }; + + DataStore.prototype._copyCommonProps = function (target) { + target._count = this._count; + target._rawCount = this._rawCount; + target._provider = this._provider; + target._dimensions = this._dimensions; + target._extent = clone(this._extent); + target._rawExtent = clone(this._rawExtent); + }; + + DataStore.prototype._cloneIndices = function () { + if (this._indices) { + var Ctor = this._indices.constructor; + var indices = void 0; + + if (Ctor === Array) { + var thisCount = this._indices.length; + indices = new Ctor(thisCount); + + for (var i = 0; i < thisCount; i++) { + indices[i] = this._indices[i]; + } + } else { + indices = new Ctor(this._indices); + } + + return indices; + } + + return null; + }; + + DataStore.prototype._getRawIdxIdentity = function (idx) { + return idx; + }; + + DataStore.prototype._getRawIdx = function (idx) { + if (idx < this._count && idx >= 0) { + return this._indices[idx]; + } + + return -1; + }; + + DataStore.prototype._updateGetRawIdx = function () { + this.getRawIndex = this._indices ? this._getRawIdx : this._getRawIdxIdentity; + }; + + DataStore.internalField = function () { + function getDimValueSimply(dataItem, property, dataIndex, dimIndex) { + return parseDataValue(dataItem[dimIndex], this._dimensions[dimIndex]); + } + + defaultDimValueGetters = { + arrayRows: getDimValueSimply, + objectRows: function (dataItem, property, dataIndex, dimIndex) { + return parseDataValue(dataItem[property], this._dimensions[dimIndex]); + }, + keyedColumns: getDimValueSimply, + original: function (dataItem, property, dataIndex, dimIndex) { + // Performance sensitive, do not use modelUtil.getDataItemValue. + // If dataItem is an plain object with no value field, the let `value` + // will be assigned with the object, but it will be tread correctly + // in the `convertValue`. + var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value); + return parseDataValue(value instanceof Array ? value[dimIndex] // If value is a single number or something else not array. + : value, this._dimensions[dimIndex]); + }, + typedArray: function (dataItem, property, dataIndex, dimIndex) { + return dataItem[dimIndex]; + } + }; + }(); + + return DataStore; + }(); + + /** + * [REQUIREMENT_MEMO]: + * (0) `metaRawOption` means `dimensions`/`sourceHeader`/`seriesLayoutBy` in raw option. + * (1) Keep support the feature: `metaRawOption` can be specified both on `series` and + * `root-dataset`. Them on `series` has higher priority. + * (2) Do not support to set `metaRawOption` on a `non-root-dataset`, because it might + * confuse users: whether those props indicate how to visit the upstream source or visit + * the transform result source, and some transforms has nothing to do with these props, + * and some transforms might have multiple upstream. + * (3) Transforms should specify `metaRawOption` in each output, just like they can be + * declared in `root-dataset`. + * (4) At present only support visit source in `SERIES_LAYOUT_BY_COLUMN` in transforms. + * That is for reducing complexity in transfroms. + * PENDING: Whether to provide transposition transform? + * + * [IMPLEMENTAION_MEMO]: + * "sourceVisitConfig" are calculated from `metaRawOption` and `data`. + * They will not be calculated until `source` is about to be visited (to prevent from + * duplicate calcuation). `source` is visited only in series and input to transforms. + * + * [DIMENSION_INHERIT_RULE]: + * By default the dimensions are inherited from ancestors, unless a transform return + * a new dimensions definition. + * Consider the case: + * ```js + * dataset: [{ + * source: [ ['Product', 'Sales', 'Prise'], ['Cookies', 321, 44.21], ...] + * }, { + * transform: { type: 'filter', ... } + * }] + * dataset: [{ + * dimension: ['Product', 'Sales', 'Prise'], + * source: [ ['Cookies', 321, 44.21], ...] + * }, { + * transform: { type: 'filter', ... } + * }] + * ``` + * The two types of option should have the same behavior after transform. + * + * + * [SCENARIO]: + * (1) Provide source data directly: + * ```js + * series: { + * encode: {...}, + * dimensions: [...] + * seriesLayoutBy: 'row', + * data: [[...]] + * } + * ``` + * (2) Series refer to dataset. + * ```js + * series: [{ + * encode: {...} + * // Ignore datasetIndex means `datasetIndex: 0` + * // and the dimensions defination in dataset is used + * }, { + * encode: {...}, + * seriesLayoutBy: 'column', + * datasetIndex: 1 + * }] + * ``` + * (3) dataset transform + * ```js + * dataset: [{ + * source: [...] + * }, { + * source: [...] + * }, { + * // By default from 0. + * transform: { type: 'filter', config: {...} } + * }, { + * // Piped. + * transform: [ + * { type: 'filter', config: {...} }, + * { type: 'sort', config: {...} } + * ] + * }, { + * id: 'regressionData', + * fromDatasetIndex: 1, + * // Third-party transform + * transform: { type: 'ecStat:regression', config: {...} } + * }, { + * // retrieve the extra result. + * id: 'regressionFormula', + * fromDatasetId: 'regressionData', + * fromTransformResult: 1 + * }] + * ``` + */ + + var SourceManager = + /** @class */ + function () { + function SourceManager(sourceHost) { + // Cached source. Do not repeat calculating if not dirty. + this._sourceList = []; + this._storeList = []; // version sign of each upstream source manager. + + this._upstreamSignList = []; + this._versionSignBase = 0; + this._dirty = true; + this._sourceHost = sourceHost; + } + /** + * Mark dirty. + */ + + + SourceManager.prototype.dirty = function () { + this._setLocalSource([], []); + + this._storeList = []; + this._dirty = true; + }; + + SourceManager.prototype._setLocalSource = function (sourceList, upstreamSignList) { + this._sourceList = sourceList; + this._upstreamSignList = upstreamSignList; + this._versionSignBase++; + + if (this._versionSignBase > 9e10) { + this._versionSignBase = 0; + } + }; + /** + * For detecting whether the upstream source is dirty, so that + * the local cached source (in `_sourceList`) should be discarded. + */ + + + SourceManager.prototype._getVersionSign = function () { + return this._sourceHost.uid + '_' + this._versionSignBase; + }; + /** + * Always return a source instance. Otherwise throw error. + */ + + + SourceManager.prototype.prepareSource = function () { + // For the case that call `setOption` multiple time but no data changed, + // cache the result source to prevent from repeating transform. + if (this._isDirty()) { + this._createSource(); + + this._dirty = false; + } + }; + + SourceManager.prototype._createSource = function () { + this._setLocalSource([], []); + + var sourceHost = this._sourceHost; + + var upSourceMgrList = this._getUpstreamSourceManagers(); + + var hasUpstream = !!upSourceMgrList.length; + var resultSourceList; + var upstreamSignList; + + if (isSeries(sourceHost)) { + var seriesModel = sourceHost; + var data = void 0; + var sourceFormat = void 0; + var upSource = void 0; // Has upstream dataset + + if (hasUpstream) { + var upSourceMgr = upSourceMgrList[0]; + upSourceMgr.prepareSource(); + upSource = upSourceMgr.getSource(); + data = upSource.data; + sourceFormat = upSource.sourceFormat; + upstreamSignList = [upSourceMgr._getVersionSign()]; + } // Series data is from own. + else { + data = seriesModel.get('data', true); + sourceFormat = isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL; + upstreamSignList = []; + } // See [REQUIREMENT_MEMO], merge settings on series and parent dataset if it is root. + + + var newMetaRawOption = this._getSourceMetaRawOption() || {}; + var upMetaRawOption = upSource && upSource.metaRawOption || {}; + var seriesLayoutBy = retrieve2(newMetaRawOption.seriesLayoutBy, upMetaRawOption.seriesLayoutBy) || null; + var sourceHeader = retrieve2(newMetaRawOption.sourceHeader, upMetaRawOption.sourceHeader); // Note here we should not use `upSource.dimensionsDefine`. Consider the case: + // `upSource.dimensionsDefine` is detected by `seriesLayoutBy: 'column'`, + // but series need `seriesLayoutBy: 'row'`. + + var dimensions = retrieve2(newMetaRawOption.dimensions, upMetaRawOption.dimensions); // We share source with dataset as much as possible + // to avoid extra memroy cost of high dimensional data. + + var needsCreateSource = seriesLayoutBy !== upMetaRawOption.seriesLayoutBy || !!sourceHeader !== !!upMetaRawOption.sourceHeader || dimensions; + resultSourceList = needsCreateSource ? [createSource(data, { + seriesLayoutBy: seriesLayoutBy, + sourceHeader: sourceHeader, + dimensions: dimensions + }, sourceFormat)] : []; + } else { + var datasetModel = sourceHost; // Has upstream dataset. + + if (hasUpstream) { + var result = this._applyTransform(upSourceMgrList); + + resultSourceList = result.sourceList; + upstreamSignList = result.upstreamSignList; + } // Is root dataset. + else { + var sourceData = datasetModel.get('source', true); + resultSourceList = [createSource(sourceData, this._getSourceMetaRawOption(), null)]; + upstreamSignList = []; + } + } + + if ("development" !== 'production') { + assert(resultSourceList && upstreamSignList); + } + + this._setLocalSource(resultSourceList, upstreamSignList); + }; + + SourceManager.prototype._applyTransform = function (upMgrList) { + var datasetModel = this._sourceHost; + var transformOption = datasetModel.get('transform', true); + var fromTransformResult = datasetModel.get('fromTransformResult', true); + + if ("development" !== 'production') { + assert(fromTransformResult != null || transformOption != null); + } + + if (fromTransformResult != null) { + var errMsg = ''; + + if (upMgrList.length !== 1) { + if ("development" !== 'production') { + errMsg = 'When using `fromTransformResult`, there should be only one upstream dataset'; + } + + doThrow(errMsg); + } + } + + var sourceList; + var upSourceList = []; + var upstreamSignList = []; + each(upMgrList, function (upMgr) { + upMgr.prepareSource(); + var upSource = upMgr.getSource(fromTransformResult || 0); + var errMsg = ''; + + if (fromTransformResult != null && !upSource) { + if ("development" !== 'production') { + errMsg = 'Can not retrieve result by `fromTransformResult`: ' + fromTransformResult; + } + + doThrow(errMsg); + } + + upSourceList.push(upSource); + upstreamSignList.push(upMgr._getVersionSign()); + }); + + if (transformOption) { + sourceList = applyDataTransform(transformOption, upSourceList, { + datasetIndex: datasetModel.componentIndex + }); + } else if (fromTransformResult != null) { + sourceList = [cloneSourceShallow(upSourceList[0])]; + } + + return { + sourceList: sourceList, + upstreamSignList: upstreamSignList + }; + }; + + SourceManager.prototype._isDirty = function () { + if (this._dirty) { + return true; + } // All sourceList is from the some upsteam. + + + var upSourceMgrList = this._getUpstreamSourceManagers(); + + for (var i = 0; i < upSourceMgrList.length; i++) { + var upSrcMgr = upSourceMgrList[i]; + + if ( // Consider the case that there is ancestor diry, call it recursively. + // The performance is probably not an issue because usually the chain is not long. + upSrcMgr._isDirty() || this._upstreamSignList[i] !== upSrcMgr._getVersionSign()) { + return true; + } + } + }; + /** + * @param sourceIndex By defualt 0, means "main source". + * Most cases there is only one source. + */ + + + SourceManager.prototype.getSource = function (sourceIndex) { + sourceIndex = sourceIndex || 0; + var source = this._sourceList[sourceIndex]; + + if (!source) { + // Series may share source instance with dataset. + var upSourceMgrList = this._getUpstreamSourceManagers(); + + return upSourceMgrList[0] && upSourceMgrList[0].getSource(sourceIndex); + } + + return source; + }; + /** + * + * Get a data store which can be shared across series. + * Only available for series. + * + * @param seriesDimRequest Dimensions that are generated in series. + * Should have been sorted by `storeDimIndex` asc. + */ + + + SourceManager.prototype.getSharedDataStore = function (seriesDimRequest) { + if ("development" !== 'production') { + assert(isSeries(this._sourceHost), 'Can only call getDataStore on series source manager.'); + } + + var schema = seriesDimRequest.makeStoreSchema(); + return this._innerGetDataStore(schema.dimensions, seriesDimRequest.source, schema.hash); + }; + + SourceManager.prototype._innerGetDataStore = function (storeDims, seriesSource, sourceReadKey) { + // TODO Can use other sourceIndex? + var sourceIndex = 0; + var storeList = this._storeList; + var cachedStoreMap = storeList[sourceIndex]; + + if (!cachedStoreMap) { + cachedStoreMap = storeList[sourceIndex] = {}; + } + + var cachedStore = cachedStoreMap[sourceReadKey]; + + if (!cachedStore) { + var upSourceMgr = this._getUpstreamSourceManagers()[0]; + + if (isSeries(this._sourceHost) && upSourceMgr) { + cachedStore = upSourceMgr._innerGetDataStore(storeDims, seriesSource, sourceReadKey); + } else { + cachedStore = new DataStore(); // Always create store from source of series. + + cachedStore.initData(new DefaultDataProvider(seriesSource, storeDims.length), storeDims); + } + + cachedStoreMap[sourceReadKey] = cachedStore; + } + + return cachedStore; + }; + /** + * PEDING: Is it fast enough? + * If no upstream, return empty array. + */ + + + SourceManager.prototype._getUpstreamSourceManagers = function () { + // Always get the relationship from the raw option. + // Do not cache the link of the dependency graph, so that + // no need to update them when change happen. + var sourceHost = this._sourceHost; + + if (isSeries(sourceHost)) { + var datasetModel = querySeriesUpstreamDatasetModel(sourceHost); + return !datasetModel ? [] : [datasetModel.getSourceManager()]; + } else { + return map(queryDatasetUpstreamDatasetModels(sourceHost), function (datasetModel) { + return datasetModel.getSourceManager(); + }); + } + }; + + SourceManager.prototype._getSourceMetaRawOption = function () { + var sourceHost = this._sourceHost; + var seriesLayoutBy; + var sourceHeader; + var dimensions; + + if (isSeries(sourceHost)) { + seriesLayoutBy = sourceHost.get('seriesLayoutBy', true); + sourceHeader = sourceHost.get('sourceHeader', true); + dimensions = sourceHost.get('dimensions', true); + } // See [REQUIREMENT_MEMO], `non-root-dataset` do not support them. + else if (!this._getUpstreamSourceManagers().length) { + var model = sourceHost; + seriesLayoutBy = model.get('seriesLayoutBy', true); + sourceHeader = model.get('sourceHeader', true); + dimensions = model.get('dimensions', true); + } + + return { + seriesLayoutBy: seriesLayoutBy, + sourceHeader: sourceHeader, + dimensions: dimensions + }; + }; + + return SourceManager; + }(); + // disable the transform merge, but do not disable transfrom clone from rawOption. + + function disableTransformOptionMerge(datasetModel) { + var transformOption = datasetModel.option.transform; + transformOption && setAsPrimitive(datasetModel.option.transform); + } + + function isSeries(sourceHost) { + // Avoid circular dependency with Series.ts + return sourceHost.mainType === 'series'; + } + + function doThrow(errMsg) { + throw new Error(errMsg); + } + + var TOOLTIP_LINE_HEIGHT_CSS = 'line-height:1'; // TODO: more textStyle option + + function getTooltipTextStyle(textStyle, renderMode) { + var nameFontColor = textStyle.color || '#6e7079'; + var nameFontSize = textStyle.fontSize || 12; + var nameFontWeight = textStyle.fontWeight || '400'; + var valueFontColor = textStyle.color || '#464646'; + var valueFontSize = textStyle.fontSize || 14; + var valueFontWeight = textStyle.fontWeight || '900'; + + if (renderMode === 'html') { + // `textStyle` is probably from user input, should be encoded to reduce security risk. + return { + // eslint-disable-next-line max-len + nameStyle: "font-size:" + encodeHTML(nameFontSize + '') + "px;color:" + encodeHTML(nameFontColor) + ";font-weight:" + encodeHTML(nameFontWeight + ''), + // eslint-disable-next-line max-len + valueStyle: "font-size:" + encodeHTML(valueFontSize + '') + "px;color:" + encodeHTML(valueFontColor) + ";font-weight:" + encodeHTML(valueFontWeight + '') + }; + } else { + return { + nameStyle: { + fontSize: nameFontSize, + fill: nameFontColor, + fontWeight: nameFontWeight + }, + valueStyle: { + fontSize: valueFontSize, + fill: valueFontColor, + fontWeight: valueFontWeight + } + }; + } + } // See `TooltipMarkupLayoutIntent['innerGapLevel']`. + // (value from UI design) + + + var HTML_GAPS = [0, 10, 20, 30]; + var RICH_TEXT_GAPS = ['', '\n', '\n\n', '\n\n\n']; // eslint-disable-next-line max-len + + function createTooltipMarkup(type, option) { + option.type = type; + return option; + } + + function isSectionFragment(frag) { + return frag.type === 'section'; + } + + function getBuilder(frag) { + return isSectionFragment(frag) ? buildSection : buildNameValue; + } + + function getBlockGapLevel(frag) { + if (isSectionFragment(frag)) { + var gapLevel_1 = 0; + var subBlockLen = frag.blocks.length; + var hasInnerGap_1 = subBlockLen > 1 || subBlockLen > 0 && !frag.noHeader; + each(frag.blocks, function (subBlock) { + var subGapLevel = getBlockGapLevel(subBlock); // If the some of the sub-blocks have some gaps (like 10px) inside, this block + // should use a larger gap (like 20px) to distinguish those sub-blocks. + + if (subGapLevel >= gapLevel_1) { + gapLevel_1 = subGapLevel + +(hasInnerGap_1 && ( // 0 always can not be readable gap level. + !subGapLevel // If no header, always keep the sub gap level. Otherwise + // look weird in case `multipleSeries`. + || isSectionFragment(subBlock) && !subBlock.noHeader)); + } + }); + return gapLevel_1; + } + + return 0; + } + + function buildSection(ctx, fragment, topMarginForOuterGap, toolTipTextStyle) { + var noHeader = fragment.noHeader; + var gaps = getGap(getBlockGapLevel(fragment)); + var subMarkupTextList = []; + var subBlocks = fragment.blocks || []; + assert(!subBlocks || isArray(subBlocks)); + subBlocks = subBlocks || []; + var orderMode = ctx.orderMode; + + if (fragment.sortBlocks && orderMode) { + subBlocks = subBlocks.slice(); + var orderMap = { + valueAsc: 'asc', + valueDesc: 'desc' + }; + + if (hasOwn(orderMap, orderMode)) { + var comparator_1 = new SortOrderComparator(orderMap[orderMode], null); + subBlocks.sort(function (a, b) { + return comparator_1.evaluate(a.sortParam, b.sortParam); + }); + } // FIXME 'seriesDesc' necessary? + else if (orderMode === 'seriesDesc') { + subBlocks.reverse(); + } + } + + each(subBlocks, function (subBlock, idx) { + var valueFormatter = fragment.valueFormatter; + var subMarkupText = getBuilder(subBlock)( // Inherit valueFormatter + valueFormatter ? extend(extend({}, ctx), { + valueFormatter: valueFormatter + }) : ctx, subBlock, idx > 0 ? gaps.html : 0, toolTipTextStyle); + subMarkupText != null && subMarkupTextList.push(subMarkupText); + }); + var subMarkupText = ctx.renderMode === 'richText' ? subMarkupTextList.join(gaps.richText) : wrapBlockHTML(subMarkupTextList.join(''), noHeader ? topMarginForOuterGap : gaps.html); + + if (noHeader) { + return subMarkupText; + } + + var displayableHeader = makeValueReadable(fragment.header, 'ordinal', ctx.useUTC); + var nameStyle = getTooltipTextStyle(toolTipTextStyle, ctx.renderMode).nameStyle; + + if (ctx.renderMode === 'richText') { + return wrapInlineNameRichText(ctx, displayableHeader, nameStyle) + gaps.richText + subMarkupText; + } else { + return wrapBlockHTML("
            " + encodeHTML(displayableHeader) + '
            ' + subMarkupText, topMarginForOuterGap); + } + } + + function buildNameValue(ctx, fragment, topMarginForOuterGap, toolTipTextStyle) { + var renderMode = ctx.renderMode; + var noName = fragment.noName; + var noValue = fragment.noValue; + var noMarker = !fragment.markerType; + var name = fragment.name; + var useUTC = ctx.useUTC; + + var valueFormatter = fragment.valueFormatter || ctx.valueFormatter || function (value) { + value = isArray(value) ? value : [value]; + return map(value, function (val, idx) { + return makeValueReadable(val, isArray(valueTypeOption) ? valueTypeOption[idx] : valueTypeOption, useUTC); + }); + }; + + if (noName && noValue) { + return; + } + + var markerStr = noMarker ? '' : ctx.markupStyleCreator.makeTooltipMarker(fragment.markerType, fragment.markerColor || '#333', renderMode); + var readableName = noName ? '' : makeValueReadable(name, 'ordinal', useUTC); + var valueTypeOption = fragment.valueType; + var readableValueList = noValue ? [] : valueFormatter(fragment.value); + var valueAlignRight = !noMarker || !noName; // It little weird if only value next to marker but far from marker. + + var valueCloseToMarker = !noMarker && noName; + + var _a = getTooltipTextStyle(toolTipTextStyle, renderMode), + nameStyle = _a.nameStyle, + valueStyle = _a.valueStyle; + + return renderMode === 'richText' ? (noMarker ? '' : markerStr) + (noName ? '' : wrapInlineNameRichText(ctx, readableName, nameStyle)) // Value has commas inside, so use ' ' as delimiter for multiple values. + + (noValue ? '' : wrapInlineValueRichText(ctx, readableValueList, valueAlignRight, valueCloseToMarker, valueStyle)) : wrapBlockHTML((noMarker ? '' : markerStr) + (noName ? '' : wrapInlineNameHTML(readableName, !noMarker, nameStyle)) + (noValue ? '' : wrapInlineValueHTML(readableValueList, valueAlignRight, valueCloseToMarker, valueStyle)), topMarginForOuterGap); + } + /** + * @return markupText. null/undefined means no content. + */ + + + function buildTooltipMarkup(fragment, markupStyleCreator, renderMode, orderMode, useUTC, toolTipTextStyle) { + if (!fragment) { + return; + } + + var builder = getBuilder(fragment); + var ctx = { + useUTC: useUTC, + renderMode: renderMode, + orderMode: orderMode, + markupStyleCreator: markupStyleCreator, + valueFormatter: fragment.valueFormatter + }; + return builder(ctx, fragment, 0, toolTipTextStyle); + } + + function getGap(gapLevel) { + return { + html: HTML_GAPS[gapLevel], + richText: RICH_TEXT_GAPS[gapLevel] + }; + } + + function wrapBlockHTML(encodedContent, topGap) { + var clearfix = '
            '; + var marginCSS = "margin: " + topGap + "px 0 0"; + return "
            " + encodedContent + clearfix + '
            '; + } + + function wrapInlineNameHTML(name, leftHasMarker, style) { + var marginCss = leftHasMarker ? 'margin-left:2px' : ''; + return "" + encodeHTML(name) + ''; + } + + function wrapInlineValueHTML(valueList, alignRight, valueCloseToMarker, style) { + // Do not too close to marker, considering there are multiple values separated by spaces. + var paddingStr = valueCloseToMarker ? '10px' : '20px'; + var alignCSS = alignRight ? "float:right;margin-left:" + paddingStr : ''; + valueList = isArray(valueList) ? valueList : [valueList]; + return "" // Value has commas inside, so use ' ' as delimiter for multiple values. + + map(valueList, function (value) { + return encodeHTML(value); + }).join('  ') + ''; + } + + function wrapInlineNameRichText(ctx, name, style) { + return ctx.markupStyleCreator.wrapRichTextStyle(name, style); + } + + function wrapInlineValueRichText(ctx, values, alignRight, valueCloseToMarker, style) { + var styles = [style]; + var paddingLeft = valueCloseToMarker ? 10 : 20; + alignRight && styles.push({ + padding: [0, 0, 0, paddingLeft], + align: 'right' + }); // Value has commas inside, so use ' ' as delimiter for multiple values. + + return ctx.markupStyleCreator.wrapRichTextStyle(isArray(values) ? values.join(' ') : values, styles); + } + + function retrieveVisualColorForTooltipMarker(series, dataIndex) { + var style = series.getData().getItemVisual(dataIndex, 'style'); + var color = style[series.visualDrawType]; + return convertToColorString(color); + } + function getPaddingFromTooltipModel(model, renderMode) { + var padding = model.get('padding'); + return padding != null ? padding // We give slightly different to look pretty. + : renderMode === 'richText' ? [8, 10] : 10; + } + /** + * The major feature is generate styles for `renderMode: 'richText'`. + * But it also serves `renderMode: 'html'` to provide + * "renderMode-independent" API. + */ + + var TooltipMarkupStyleCreator = + /** @class */ + function () { + function TooltipMarkupStyleCreator() { + this.richTextStyles = {}; // Notice that "generate a style name" usuall happens repeatly when mouse moving and + // displaying a tooltip. So we put the `_nextStyleNameId` as a member of each creator + // rather than static shared by all creators (which will cause it increase to fast). + + this._nextStyleNameId = getRandomIdBase(); + } + + TooltipMarkupStyleCreator.prototype._generateStyleName = function () { + return '__EC_aUTo_' + this._nextStyleNameId++; + }; + + TooltipMarkupStyleCreator.prototype.makeTooltipMarker = function (markerType, colorStr, renderMode) { + var markerId = renderMode === 'richText' ? this._generateStyleName() : null; + var marker = getTooltipMarker({ + color: colorStr, + type: markerType, + renderMode: renderMode, + markerId: markerId + }); + + if (isString(marker)) { + return marker; + } else { + if ("development" !== 'production') { + assert(markerId); + } + + this.richTextStyles[markerId] = marker.style; + return marker.content; + } + }; + /** + * @usage + * ```ts + * const styledText = markupStyleCreator.wrapRichTextStyle([ + * // The styles will be auto merged. + * { + * fontSize: 12, + * color: 'blue' + * }, + * { + * padding: 20 + * } + * ]); + * ``` + */ + + + TooltipMarkupStyleCreator.prototype.wrapRichTextStyle = function (text, styles) { + var finalStl = {}; + + if (isArray(styles)) { + each(styles, function (stl) { + return extend(finalStl, stl); + }); + } else { + extend(finalStl, styles); + } + + var styleName = this._generateStyleName(); + + this.richTextStyles[styleName] = finalStl; + return "{" + styleName + "|" + text + "}"; + }; + + return TooltipMarkupStyleCreator; + }(); + + function defaultSeriesFormatTooltip(opt) { + var series = opt.series; + var dataIndex = opt.dataIndex; + var multipleSeries = opt.multipleSeries; + var data = series.getData(); + var tooltipDims = data.mapDimensionsAll('defaultedTooltip'); + var tooltipDimLen = tooltipDims.length; + var value = series.getRawValue(dataIndex); + var isValueArr = isArray(value); + var markerColor = retrieveVisualColorForTooltipMarker(series, dataIndex); // Complicated rule for pretty tooltip. + + var inlineValue; + var inlineValueType; + var subBlocks; + var sortParam; + + if (tooltipDimLen > 1 || isValueArr && !tooltipDimLen) { + var formatArrResult = formatTooltipArrayValue(value, series, dataIndex, tooltipDims, markerColor); + inlineValue = formatArrResult.inlineValues; + inlineValueType = formatArrResult.inlineValueTypes; + subBlocks = formatArrResult.blocks; // Only support tooltip sort by the first inline value. It's enough in most cases. + + sortParam = formatArrResult.inlineValues[0]; + } else if (tooltipDimLen) { + var dimInfo = data.getDimensionInfo(tooltipDims[0]); + sortParam = inlineValue = retrieveRawValue(data, dataIndex, tooltipDims[0]); + inlineValueType = dimInfo.type; + } else { + sortParam = inlineValue = isValueArr ? value[0] : value; + } // Do not show generated series name. It might not be readable. + + + var seriesNameSpecified = isNameSpecified(series); + var seriesName = seriesNameSpecified && series.name || ''; + var itemName = data.getName(dataIndex); + var inlineName = multipleSeries ? seriesName : itemName; + return createTooltipMarkup('section', { + header: seriesName, + // When series name not specified, do not show a header line with only '-'. + // This case alway happen in tooltip.trigger: 'item'. + noHeader: multipleSeries || !seriesNameSpecified, + sortParam: sortParam, + blocks: [createTooltipMarkup('nameValue', { + markerType: 'item', + markerColor: markerColor, + // Do not mix display seriesName and itemName in one tooltip, + // which might confuses users. + name: inlineName, + // name dimension might be auto assigned, where the name might + // be not readable. So we check trim here. + noName: !trim(inlineName), + value: inlineValue, + valueType: inlineValueType + })].concat(subBlocks || []) + }); + } + + function formatTooltipArrayValue(value, series, dataIndex, tooltipDims, colorStr) { + // check: category-no-encode-has-axis-data in dataset.html + var data = series.getData(); + var isValueMultipleLine = reduce(value, function (isValueMultipleLine, val, idx) { + var dimItem = data.getDimensionInfo(idx); + return isValueMultipleLine = isValueMultipleLine || dimItem && dimItem.tooltip !== false && dimItem.displayName != null; + }, false); + var inlineValues = []; + var inlineValueTypes = []; + var blocks = []; + tooltipDims.length ? each(tooltipDims, function (dim) { + setEachItem(retrieveRawValue(data, dataIndex, dim), dim); + }) // By default, all dims is used on tooltip. + : each(value, setEachItem); + + function setEachItem(val, dim) { + var dimInfo = data.getDimensionInfo(dim); // If `dimInfo.tooltip` is not set, show tooltip. + + if (!dimInfo || dimInfo.otherDims.tooltip === false) { + return; + } + + if (isValueMultipleLine) { + blocks.push(createTooltipMarkup('nameValue', { + markerType: 'subItem', + markerColor: colorStr, + name: dimInfo.displayName, + value: val, + valueType: dimInfo.type + })); + } else { + inlineValues.push(val); + inlineValueTypes.push(dimInfo.type); + } + } + + return { + inlineValues: inlineValues, + inlineValueTypes: inlineValueTypes, + blocks: blocks + }; + } + + var inner$1 = makeInner(); + + function getSelectionKey(data, dataIndex) { + return data.getName(dataIndex) || data.getId(dataIndex); + } + + var SERIES_UNIVERSAL_TRANSITION_PROP = '__universalTransitionEnabled'; + + var SeriesModel = + /** @class */ + function (_super) { + __extends(SeriesModel, _super); + + function SeriesModel() { + // [Caution]: Becuase this class or desecendants can be used as `XXX.extend(subProto)`, + // the class members must not be initialized in constructor or declaration place. + // Otherwise there is bad case: + // class A {xxx = 1;} + // enableClassExtend(A); + // class B extends A {} + // var C = B.extend({xxx: 5}); + // var c = new C(); + // console.log(c.xxx); // expect 5 but always 1. + var _this = _super !== null && _super.apply(this, arguments) || this; // --------------------------------------- + // Props about data selection + // --------------------------------------- + + + _this._selectedDataIndicesMap = {}; + return _this; + } + + SeriesModel.prototype.init = function (option, parentModel, ecModel) { + this.seriesIndex = this.componentIndex; + this.dataTask = createTask({ + count: dataTaskCount, + reset: dataTaskReset + }); + this.dataTask.context = { + model: this + }; + this.mergeDefaultAndTheme(option, ecModel); + var sourceManager = inner$1(this).sourceManager = new SourceManager(this); + sourceManager.prepareSource(); + var data = this.getInitialData(option, ecModel); + wrapData(data, this); + this.dataTask.context.data = data; + + if ("development" !== 'production') { + assert(data, 'getInitialData returned invalid data.'); + } + + inner$1(this).dataBeforeProcessed = data; // If we reverse the order (make data firstly, and then make + // dataBeforeProcessed by cloneShallow), cloneShallow will + // cause data.graph.data !== data when using + // module:echarts/data/Graph or module:echarts/data/Tree. + // See module:echarts/data/helper/linkSeriesData + // Theoretically, it is unreasonable to call `seriesModel.getData()` in the model + // init or merge stage, because the data can be restored. So we do not `restoreData` + // and `setData` here, which forbids calling `seriesModel.getData()` in this stage. + // Call `seriesModel.getRawData()` instead. + // this.restoreData(); + + autoSeriesName(this); + + this._initSelectedMapFromData(data); + }; + /** + * Util for merge default and theme to option + */ + + + SeriesModel.prototype.mergeDefaultAndTheme = function (option, ecModel) { + var layoutMode = fetchLayoutMode(this); + var inputPositionParams = layoutMode ? getLayoutParams(option) : {}; // Backward compat: using subType on theme. + // But if name duplicate between series subType + // (for example: parallel) add component mainType, + // add suffix 'Series'. + + var themeSubType = this.subType; + + if (ComponentModel.hasClass(themeSubType)) { + themeSubType += 'Series'; + } + + merge(option, ecModel.getTheme().get(this.subType)); + merge(option, this.getDefaultOption()); // Default label emphasis `show` + + defaultEmphasis(option, 'label', ['show']); + this.fillDataTextStyle(option.data); + + if (layoutMode) { + mergeLayoutParam(option, inputPositionParams, layoutMode); + } + }; + + SeriesModel.prototype.mergeOption = function (newSeriesOption, ecModel) { + // this.settingTask.dirty(); + newSeriesOption = merge(this.option, newSeriesOption, true); + this.fillDataTextStyle(newSeriesOption.data); + var layoutMode = fetchLayoutMode(this); + + if (layoutMode) { + mergeLayoutParam(this.option, newSeriesOption, layoutMode); + } + + var sourceManager = inner$1(this).sourceManager; + sourceManager.dirty(); + sourceManager.prepareSource(); + var data = this.getInitialData(newSeriesOption, ecModel); + wrapData(data, this); + this.dataTask.dirty(); + this.dataTask.context.data = data; + inner$1(this).dataBeforeProcessed = data; + autoSeriesName(this); + + this._initSelectedMapFromData(data); + }; + + SeriesModel.prototype.fillDataTextStyle = function (data) { + // Default data label emphasis `show` + // FIXME Tree structure data ? + // FIXME Performance ? + if (data && !isTypedArray(data)) { + var props = ['show']; + + for (var i = 0; i < data.length; i++) { + if (data[i] && data[i].label) { + defaultEmphasis(data[i], 'label', props); + } + } + } + }; + /** + * Init a data structure from data related option in series + * Must be overriden. + */ + + + SeriesModel.prototype.getInitialData = function (option, ecModel) { + return; + }; + /** + * Append data to list + */ + + + SeriesModel.prototype.appendData = function (params) { + // FIXME ??? + // (1) If data from dataset, forbidden append. + // (2) support append data of dataset. + var data = this.getRawData(); + data.appendData(params.data); + }; + /** + * Consider some method like `filter`, `map` need make new data, + * We should make sure that `seriesModel.getData()` get correct + * data in the stream procedure. So we fetch data from upstream + * each time `task.perform` called. + */ + + + SeriesModel.prototype.getData = function (dataType) { + var task = getCurrentTask(this); + + if (task) { + var data = task.context.data; + return dataType == null ? data : data.getLinkedData(dataType); + } else { + // When series is not alive (that may happen when click toolbox + // restore or setOption with not merge mode), series data may + // be still need to judge animation or something when graphic + // elements want to know whether fade out. + return inner$1(this).data; + } + }; + + SeriesModel.prototype.getAllData = function () { + var mainData = this.getData(); + return mainData && mainData.getLinkedDataAll ? mainData.getLinkedDataAll() : [{ + data: mainData + }]; + }; + + SeriesModel.prototype.setData = function (data) { + var task = getCurrentTask(this); + + if (task) { + var context = task.context; // Consider case: filter, data sample. + // FIXME:TS never used, so comment it + // if (context.data !== data && task.modifyOutputEnd) { + // task.setOutputEnd(data.count()); + // } + + context.outputData = data; // Caution: setData should update context.data, + // Because getData may be called multiply in a + // single stage and expect to get the data just + // set. (For example, AxisProxy, x y both call + // getData and setDate sequentially). + // So the context.data should be fetched from + // upstream each time when a stage starts to be + // performed. + + if (task !== this.dataTask) { + context.data = data; + } + } + + inner$1(this).data = data; + }; + + SeriesModel.prototype.getEncode = function () { + var encode = this.get('encode', true); + + if (encode) { + return createHashMap(encode); + } + }; + + SeriesModel.prototype.getSourceManager = function () { + return inner$1(this).sourceManager; + }; + + SeriesModel.prototype.getSource = function () { + return this.getSourceManager().getSource(); + }; + /** + * Get data before processed + */ + + + SeriesModel.prototype.getRawData = function () { + return inner$1(this).dataBeforeProcessed; + }; + + SeriesModel.prototype.getColorBy = function () { + var colorBy = this.get('colorBy'); + return colorBy || 'series'; + }; + + SeriesModel.prototype.isColorBySeries = function () { + return this.getColorBy() === 'series'; + }; + /** + * Get base axis if has coordinate system and has axis. + * By default use coordSys.getBaseAxis(); + * Can be overrided for some chart. + * @return {type} description + */ + + + SeriesModel.prototype.getBaseAxis = function () { + var coordSys = this.coordinateSystem; // @ts-ignore + + return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis(); + }; + /** + * Default tooltip formatter + * + * @param dataIndex + * @param multipleSeries + * @param dataType + * @param renderMode valid values: 'html'(by default) and 'richText'. + * 'html' is used for rendering tooltip in extra DOM form, and the result + * string is used as DOM HTML content. + * 'richText' is used for rendering tooltip in rich text form, for those where + * DOM operation is not supported. + * @return formatted tooltip with `html` and `markers` + * Notice: The override method can also return string + */ + + + SeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + return defaultSeriesFormatTooltip({ + series: this, + dataIndex: dataIndex, + multipleSeries: multipleSeries + }); + }; + + SeriesModel.prototype.isAnimationEnabled = function () { + var ecModel = this.ecModel; // Disable animation if using echarts in node but not give ssr flag. + // In ssr mode, renderToString will generate svg with css animation. + + if (env.node && !(ecModel && ecModel.ssr)) { + return false; + } + + var animationEnabled = this.getShallow('animation'); + + if (animationEnabled) { + if (this.getData().count() > this.getShallow('animationThreshold')) { + animationEnabled = false; + } + } + + return !!animationEnabled; + }; + + SeriesModel.prototype.restoreData = function () { + this.dataTask.dirty(); + }; + + SeriesModel.prototype.getColorFromPalette = function (name, scope, requestColorNum) { + var ecModel = this.ecModel; // PENDING + + var color = PaletteMixin.prototype.getColorFromPalette.call(this, name, scope, requestColorNum); + + if (!color) { + color = ecModel.getColorFromPalette(name, scope, requestColorNum); + } + + return color; + }; + /** + * Use `data.mapDimensionsAll(coordDim)` instead. + * @deprecated + */ + + + SeriesModel.prototype.coordDimToDataDim = function (coordDim) { + return this.getRawData().mapDimensionsAll(coordDim); + }; + /** + * Get progressive rendering count each step + */ + + + SeriesModel.prototype.getProgressive = function () { + return this.get('progressive'); + }; + /** + * Get progressive rendering count each step + */ + + + SeriesModel.prototype.getProgressiveThreshold = function () { + return this.get('progressiveThreshold'); + }; // PENGING If selectedMode is null ? + + + SeriesModel.prototype.select = function (innerDataIndices, dataType) { + this._innerSelect(this.getData(dataType), innerDataIndices); + }; + + SeriesModel.prototype.unselect = function (innerDataIndices, dataType) { + var selectedMap = this.option.selectedMap; + + if (!selectedMap) { + return; + } + + var selectedMode = this.option.selectedMode; + var data = this.getData(dataType); + + if (selectedMode === 'series' || selectedMap === 'all') { + this.option.selectedMap = {}; + this._selectedDataIndicesMap = {}; + return; + } + + for (var i = 0; i < innerDataIndices.length; i++) { + var dataIndex = innerDataIndices[i]; + var nameOrId = getSelectionKey(data, dataIndex); + selectedMap[nameOrId] = false; + this._selectedDataIndicesMap[nameOrId] = -1; + } + }; + + SeriesModel.prototype.toggleSelect = function (innerDataIndices, dataType) { + var tmpArr = []; + + for (var i = 0; i < innerDataIndices.length; i++) { + tmpArr[0] = innerDataIndices[i]; + this.isSelected(innerDataIndices[i], dataType) ? this.unselect(tmpArr, dataType) : this.select(tmpArr, dataType); + } + }; + + SeriesModel.prototype.getSelectedDataIndices = function () { + if (this.option.selectedMap === 'all') { + return [].slice.call(this.getData().getIndices()); + } + + var selectedDataIndicesMap = this._selectedDataIndicesMap; + var nameOrIds = keys(selectedDataIndicesMap); + var dataIndices = []; + + for (var i = 0; i < nameOrIds.length; i++) { + var dataIndex = selectedDataIndicesMap[nameOrIds[i]]; + + if (dataIndex >= 0) { + dataIndices.push(dataIndex); + } + } + + return dataIndices; + }; + + SeriesModel.prototype.isSelected = function (dataIndex, dataType) { + var selectedMap = this.option.selectedMap; + + if (!selectedMap) { + return false; + } + + var data = this.getData(dataType); + return (selectedMap === 'all' || selectedMap[getSelectionKey(data, dataIndex)]) && !data.getItemModel(dataIndex).get(['select', 'disabled']); + }; + + SeriesModel.prototype.isUniversalTransitionEnabled = function () { + if (this[SERIES_UNIVERSAL_TRANSITION_PROP]) { + return true; + } + + var universalTransitionOpt = this.option.universalTransition; // Quick reject + + if (!universalTransitionOpt) { + return false; + } + + if (universalTransitionOpt === true) { + return true; + } // Can be simply 'universalTransition: true' + + + return universalTransitionOpt && universalTransitionOpt.enabled; + }; + + SeriesModel.prototype._innerSelect = function (data, innerDataIndices) { + var _a, _b; + + var option = this.option; + var selectedMode = option.selectedMode; + var len = innerDataIndices.length; + + if (!selectedMode || !len) { + return; + } + + if (selectedMode === 'series') { + option.selectedMap = 'all'; + } else if (selectedMode === 'multiple') { + if (!isObject(option.selectedMap)) { + option.selectedMap = {}; + } + + var selectedMap = option.selectedMap; + + for (var i = 0; i < len; i++) { + var dataIndex = innerDataIndices[i]; // TODO diffrent types of data share same object. + + var nameOrId = getSelectionKey(data, dataIndex); + selectedMap[nameOrId] = true; + this._selectedDataIndicesMap[nameOrId] = data.getRawIndex(dataIndex); + } + } else if (selectedMode === 'single' || selectedMode === true) { + var lastDataIndex = innerDataIndices[len - 1]; + var nameOrId = getSelectionKey(data, lastDataIndex); + option.selectedMap = (_a = {}, _a[nameOrId] = true, _a); + this._selectedDataIndicesMap = (_b = {}, _b[nameOrId] = data.getRawIndex(lastDataIndex), _b); + } + }; + + SeriesModel.prototype._initSelectedMapFromData = function (data) { + // Ignore select info in data if selectedMap exists. + // NOTE It's only for legacy usage. edge data is not supported. + if (this.option.selectedMap) { + return; + } + + var dataIndices = []; + + if (data.hasItemOption) { + data.each(function (idx) { + var rawItem = data.getRawDataItem(idx); + + if (rawItem && rawItem.selected) { + dataIndices.push(idx); + } + }); + } + + if (dataIndices.length > 0) { + this._innerSelect(data, dataIndices); + } + }; // /** + // * @see {module:echarts/stream/Scheduler} + // */ + // abstract pipeTask: null + + + SeriesModel.registerClass = function (clz) { + return ComponentModel.registerClass(clz); + }; + + SeriesModel.protoInitialize = function () { + var proto = SeriesModel.prototype; + proto.type = 'series.__base__'; + proto.seriesIndex = 0; + proto.ignoreStyleOnData = false; + proto.hasSymbolVisual = false; + proto.defaultSymbol = 'circle'; // Make sure the values can be accessed! + + proto.visualStyleAccessPath = 'itemStyle'; + proto.visualDrawType = 'fill'; + }(); + + return SeriesModel; + }(ComponentModel); + + mixin(SeriesModel, DataFormatMixin); + mixin(SeriesModel, PaletteMixin); + mountExtend(SeriesModel, ComponentModel); + /** + * MUST be called after `prepareSource` called + * Here we need to make auto series, especially for auto legend. But we + * do not modify series.name in option to avoid side effects. + */ + + function autoSeriesName(seriesModel) { + // User specified name has higher priority, otherwise it may cause + // series can not be queried unexpectedly. + var name = seriesModel.name; + + if (!isNameSpecified(seriesModel)) { + seriesModel.name = getSeriesAutoName(seriesModel) || name; + } + } + + function getSeriesAutoName(seriesModel) { + var data = seriesModel.getRawData(); + var dataDims = data.mapDimensionsAll('seriesName'); + var nameArr = []; + each(dataDims, function (dataDim) { + var dimInfo = data.getDimensionInfo(dataDim); + dimInfo.displayName && nameArr.push(dimInfo.displayName); + }); + return nameArr.join(' '); + } + + function dataTaskCount(context) { + return context.model.getRawData().count(); + } + + function dataTaskReset(context) { + var seriesModel = context.model; + seriesModel.setData(seriesModel.getRawData().cloneShallow()); + return dataTaskProgress; + } + + function dataTaskProgress(param, context) { + // Avoid repead cloneShallow when data just created in reset. + if (context.outputData && param.end > context.outputData.count()) { + context.model.getRawData().cloneShallow(context.outputData); + } + } // TODO refactor + + + function wrapData(data, seriesModel) { + each(concatArray(data.CHANGABLE_METHODS, data.DOWNSAMPLE_METHODS), function (methodName) { + data.wrapMethod(methodName, curry(onDataChange, seriesModel)); + }); + } + + function onDataChange(seriesModel, newList) { + var task = getCurrentTask(seriesModel); + + if (task) { + // Consider case: filter, selectRange + task.setOutputEnd((newList || this).count()); + } + + return newList; + } + + function getCurrentTask(seriesModel) { + var scheduler = (seriesModel.ecModel || {}).scheduler; + var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid); + + if (pipeline) { + // When pipline finished, the currrentTask keep the last + // task (renderTask). + var task = pipeline.currentTask; + + if (task) { + var agentStubMap = task.agentStubMap; + + if (agentStubMap) { + task = agentStubMap.get(seriesModel.uid); + } + } + + return task; + } + } + + var ComponentView = + /** @class */ + function () { + function ComponentView() { + this.group = new Group(); + this.uid = getUID('viewComponent'); + } + + ComponentView.prototype.init = function (ecModel, api) {}; + + ComponentView.prototype.render = function (model, ecModel, api, payload) {}; + + ComponentView.prototype.dispose = function (ecModel, api) {}; + + ComponentView.prototype.updateView = function (model, ecModel, api, payload) {// Do nothing; + }; + + ComponentView.prototype.updateLayout = function (model, ecModel, api, payload) {// Do nothing; + }; + + ComponentView.prototype.updateVisual = function (model, ecModel, api, payload) {// Do nothing; + }; + /** + * Hook for toggle blur target series. + * Can be used in marker for blur or leave blur the markers + */ + + + ComponentView.prototype.toggleBlurSeries = function (seriesModels, isBlur, ecModel) {// Do nothing; + }; + /** + * Traverse the new rendered elements. + * + * It will traverse the new added element in progressive rendering. + * And traverse all in normal rendering. + */ + + + ComponentView.prototype.eachRendered = function (cb) { + var group = this.group; + + if (group) { + group.traverse(cb); + } + }; + + return ComponentView; + }(); + enableClassExtend(ComponentView); + enableClassManagement(ComponentView); + + /** + * @return {string} If large mode changed, return string 'reset'; + */ + + function createRenderPlanner() { + var inner = makeInner(); + return function (seriesModel) { + var fields = inner(seriesModel); + var pipelineContext = seriesModel.pipelineContext; + var originalLarge = !!fields.large; + var originalProgressive = !!fields.progressiveRender; // FIXME: if the planner works on a filtered series, `pipelineContext` does not + // exists. See #11611 . Probably we need to modify this structure, see the comment + // on `performRawSeries` in `Schedular.js`. + + var large = fields.large = !!(pipelineContext && pipelineContext.large); + var progressive = fields.progressiveRender = !!(pipelineContext && pipelineContext.progressiveRender); + return !!(originalLarge !== large || originalProgressive !== progressive) && 'reset'; + }; + } + + var inner$2 = makeInner(); + var renderPlanner = createRenderPlanner(); + + var ChartView = + /** @class */ + function () { + function ChartView() { + this.group = new Group(); + this.uid = getUID('viewChart'); + this.renderTask = createTask({ + plan: renderTaskPlan, + reset: renderTaskReset + }); + this.renderTask.context = { + view: this + }; + } + + ChartView.prototype.init = function (ecModel, api) {}; + + ChartView.prototype.render = function (seriesModel, ecModel, api, payload) { + if ("development" !== 'production') { + throw new Error('render method must been implemented'); + } + }; + /** + * Highlight series or specified data item. + */ + + + ChartView.prototype.highlight = function (seriesModel, ecModel, api, payload) { + var data = seriesModel.getData(payload && payload.dataType); + + if (!data) { + if ("development" !== 'production') { + error("Unknown dataType " + payload.dataType); + } + + return; + } + + toggleHighlight(data, payload, 'emphasis'); + }; + /** + * Downplay series or specified data item. + */ + + + ChartView.prototype.downplay = function (seriesModel, ecModel, api, payload) { + var data = seriesModel.getData(payload && payload.dataType); + + if (!data) { + if ("development" !== 'production') { + error("Unknown dataType " + payload.dataType); + } + + return; + } + + toggleHighlight(data, payload, 'normal'); + }; + /** + * Remove self. + */ + + + ChartView.prototype.remove = function (ecModel, api) { + this.group.removeAll(); + }; + /** + * Dispose self. + */ + + + ChartView.prototype.dispose = function (ecModel, api) {}; + + ChartView.prototype.updateView = function (seriesModel, ecModel, api, payload) { + this.render(seriesModel, ecModel, api, payload); + }; // FIXME never used? + + + ChartView.prototype.updateLayout = function (seriesModel, ecModel, api, payload) { + this.render(seriesModel, ecModel, api, payload); + }; // FIXME never used? + + + ChartView.prototype.updateVisual = function (seriesModel, ecModel, api, payload) { + this.render(seriesModel, ecModel, api, payload); + }; + /** + * Traverse the new rendered elements. + * + * It will traverse the new added element in progressive rendering. + * And traverse all in normal rendering. + */ + + + ChartView.prototype.eachRendered = function (cb) { + traverseElements(this.group, cb); + }; + + ChartView.markUpdateMethod = function (payload, methodName) { + inner$2(payload).updateMethod = methodName; + }; + + ChartView.protoInitialize = function () { + var proto = ChartView.prototype; + proto.type = 'chart'; + }(); + + return ChartView; + }(); + /** + * Set state of single element + */ + + function elSetState(el, state, highlightDigit) { + if (el && isHighDownDispatcher(el)) { + (state === 'emphasis' ? enterEmphasis : leaveEmphasis)(el, highlightDigit); + } + } + + function toggleHighlight(data, payload, state) { + var dataIndex = queryDataIndex(data, payload); + var highlightDigit = payload && payload.highlightKey != null ? getHighlightDigit(payload.highlightKey) : null; + + if (dataIndex != null) { + each(normalizeToArray(dataIndex), function (dataIdx) { + elSetState(data.getItemGraphicEl(dataIdx), state, highlightDigit); + }); + } else { + data.eachItemGraphicEl(function (el) { + elSetState(el, state, highlightDigit); + }); + } + } + + enableClassExtend(ChartView, ['dispose']); + enableClassManagement(ChartView); + + function renderTaskPlan(context) { + return renderPlanner(context.model); + } + + function renderTaskReset(context) { + var seriesModel = context.model; + var ecModel = context.ecModel; + var api = context.api; + var payload = context.payload; // FIXME: remove updateView updateVisual + + var progressiveRender = seriesModel.pipelineContext.progressiveRender; + var view = context.view; + var updateMethod = payload && inner$2(payload).updateMethod; + var methodName = progressiveRender ? 'incrementalPrepareRender' : updateMethod && view[updateMethod] ? updateMethod // `appendData` is also supported when data amount + // is less than progressive threshold. + : 'render'; + + if (methodName !== 'render') { + view[methodName](seriesModel, ecModel, api, payload); + } + + return progressMethodMap[methodName]; + } + + var progressMethodMap = { + incrementalPrepareRender: { + progress: function (params, context) { + context.view.incrementalRender(params, context.model, context.ecModel, context.api, context.payload); + } + }, + render: { + // Put view.render in `progress` to support appendData. But in this case + // view.render should not be called in reset, otherwise it will be called + // twise. Use `forceFirstProgress` to make sure that view.render is called + // in any cases. + forceFirstProgress: true, + progress: function (params, context) { + context.view.render(context.model, context.ecModel, context.api, context.payload); + } + } + }; + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + var ORIGIN_METHOD = '\0__throttleOriginMethod'; + var RATE = '\0__throttleRate'; + var THROTTLE_TYPE = '\0__throttleType'; + /** + * @public + * @param {(Function)} fn + * @param {number} [delay=0] Unit: ms. + * @param {boolean} [debounce=false] + * true: If call interval less than `delay`, only the last call works. + * false: If call interval less than `delay, call works on fixed rate. + * @return {(Function)} throttled fn. + */ + + function throttle(fn, delay, debounce) { + var currCall; + var lastCall = 0; + var lastExec = 0; + var timer = null; + var diff; + var scope; + var args; + var debounceNextCall; + delay = delay || 0; + + function exec() { + lastExec = new Date().getTime(); + timer = null; + fn.apply(scope, args || []); + } + + var cb = function () { + var cbArgs = []; + + for (var _i = 0; _i < arguments.length; _i++) { + cbArgs[_i] = arguments[_i]; + } + + currCall = new Date().getTime(); + scope = this; + args = cbArgs; + var thisDelay = debounceNextCall || delay; + var thisDebounce = debounceNextCall || debounce; + debounceNextCall = null; + diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay; + clearTimeout(timer); // Here we should make sure that: the `exec` SHOULD NOT be called later + // than a new call of `cb`, that is, preserving the command order. Consider + // calculating "scale rate" when roaming as an example. When a call of `cb` + // happens, either the `exec` is called dierectly, or the call is delayed. + // But the delayed call should never be later than next call of `cb`. Under + // this assurance, we can simply update view state each time `dispatchAction` + // triggered by user roaming, but not need to add extra code to avoid the + // state being "rolled-back". + + if (thisDebounce) { + timer = setTimeout(exec, thisDelay); + } else { + if (diff >= 0) { + exec(); + } else { + timer = setTimeout(exec, -diff); + } + } + + lastCall = currCall; + }; + /** + * Clear throttle. + * @public + */ + + + cb.clear = function () { + if (timer) { + clearTimeout(timer); + timer = null; + } + }; + /** + * Enable debounce once. + */ + + + cb.debounceNextCall = function (debounceDelay) { + debounceNextCall = debounceDelay; + }; + + return cb; + } + /** + * Create throttle method or update throttle rate. + * + * @example + * ComponentView.prototype.render = function () { + * ... + * throttle.createOrUpdate( + * this, + * '_dispatchAction', + * this.model.get('throttle'), + * 'fixRate' + * ); + * }; + * ComponentView.prototype.remove = function () { + * throttle.clear(this, '_dispatchAction'); + * }; + * ComponentView.prototype.dispose = function () { + * throttle.clear(this, '_dispatchAction'); + * }; + * + */ + + function createOrUpdate(obj, fnAttr, rate, throttleType) { + var fn = obj[fnAttr]; + + if (!fn) { + return; + } + + var originFn = fn[ORIGIN_METHOD] || fn; + var lastThrottleType = fn[THROTTLE_TYPE]; + var lastRate = fn[RATE]; + + if (lastRate !== rate || lastThrottleType !== throttleType) { + if (rate == null || !throttleType) { + return obj[fnAttr] = originFn; + } + + fn = obj[fnAttr] = throttle(originFn, rate, throttleType === 'debounce'); + fn[ORIGIN_METHOD] = originFn; + fn[THROTTLE_TYPE] = throttleType; + fn[RATE] = rate; + } + + return fn; + } + /** + * Clear throttle. Example see throttle.createOrUpdate. + */ + + function clear(obj, fnAttr) { + var fn = obj[fnAttr]; + + if (fn && fn[ORIGIN_METHOD]) { + // Clear throttle + fn.clear && fn.clear(); + obj[fnAttr] = fn[ORIGIN_METHOD]; + } + } + + var inner$3 = makeInner(); + var defaultStyleMappers = { + itemStyle: makeStyleMapper(ITEM_STYLE_KEY_MAP, true), + lineStyle: makeStyleMapper(LINE_STYLE_KEY_MAP, true) + }; + var defaultColorKey = { + lineStyle: 'stroke', + itemStyle: 'fill' + }; + + function getStyleMapper(seriesModel, stylePath) { + var styleMapper = seriesModel.visualStyleMapper || defaultStyleMappers[stylePath]; + + if (!styleMapper) { + console.warn("Unkown style type '" + stylePath + "'."); + return defaultStyleMappers.itemStyle; + } + + return styleMapper; + } + + function getDefaultColorKey(seriesModel, stylePath) { + // return defaultColorKey[stylePath] || + var colorKey = seriesModel.visualDrawType || defaultColorKey[stylePath]; + + if (!colorKey) { + console.warn("Unkown style type '" + stylePath + "'."); + return 'fill'; + } + + return colorKey; + } + + var seriesStyleTask = { + createOnAllSeries: true, + performRawSeries: true, + reset: function (seriesModel, ecModel) { + var data = seriesModel.getData(); + var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; // Set in itemStyle + + var styleModel = seriesModel.getModel(stylePath); + var getStyle = getStyleMapper(seriesModel, stylePath); + var globalStyle = getStyle(styleModel); + var decalOption = styleModel.getShallow('decal'); + + if (decalOption) { + data.setVisual('decal', decalOption); + decalOption.dirty = true; + } // TODO + + + var colorKey = getDefaultColorKey(seriesModel, stylePath); + var color = globalStyle[colorKey]; // TODO style callback + + var colorCallback = isFunction(color) ? color : null; + var hasAutoColor = globalStyle.fill === 'auto' || globalStyle.stroke === 'auto'; // Get from color palette by default. + + if (!globalStyle[colorKey] || colorCallback || hasAutoColor) { + // Note: if some series has color specified (e.g., by itemStyle.color), we DO NOT + // make it effect palette. Bacause some scenarios users need to make some series + // transparent or as background, which should better not effect the palette. + var colorPalette = seriesModel.getColorFromPalette( // TODO series count changed. + seriesModel.name, null, ecModel.getSeriesCount()); + + if (!globalStyle[colorKey]) { + globalStyle[colorKey] = colorPalette; + data.setVisual('colorFromPalette', true); + } + + globalStyle.fill = globalStyle.fill === 'auto' || isFunction(globalStyle.fill) ? colorPalette : globalStyle.fill; + globalStyle.stroke = globalStyle.stroke === 'auto' || isFunction(globalStyle.stroke) ? colorPalette : globalStyle.stroke; + } + + data.setVisual('style', globalStyle); + data.setVisual('drawType', colorKey); // Only visible series has each data be visual encoded + + if (!ecModel.isSeriesFiltered(seriesModel) && colorCallback) { + data.setVisual('colorFromPalette', false); + return { + dataEach: function (data, idx) { + var dataParams = seriesModel.getDataParams(idx); + var itemStyle = extend({}, globalStyle); + itemStyle[colorKey] = colorCallback(dataParams); + data.setItemVisual(idx, 'style', itemStyle); + } + }; + } + } + }; + var sharedModel = new Model(); + var dataStyleTask = { + createOnAllSeries: true, + performRawSeries: true, + reset: function (seriesModel, ecModel) { + if (seriesModel.ignoreStyleOnData || ecModel.isSeriesFiltered(seriesModel)) { + return; + } + + var data = seriesModel.getData(); + var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; // Set in itemStyle + + var getStyle = getStyleMapper(seriesModel, stylePath); + var colorKey = data.getVisual('drawType'); + return { + dataEach: data.hasItemOption ? function (data, idx) { + // Not use getItemModel for performance considuration + var rawItem = data.getRawDataItem(idx); + + if (rawItem && rawItem[stylePath]) { + sharedModel.option = rawItem[stylePath]; + var style = getStyle(sharedModel); + var existsStyle = data.ensureUniqueItemVisual(idx, 'style'); + extend(existsStyle, style); + + if (sharedModel.option.decal) { + data.setItemVisual(idx, 'decal', sharedModel.option.decal); + sharedModel.option.decal.dirty = true; + } + + if (colorKey in style) { + data.setItemVisual(idx, 'colorFromPalette', false); + } + } + } : null + }; + } + }; // Pick color from palette for the data which has not been set with color yet. + // Note: do not support stream rendering. No such cases yet. + + var dataColorPaletteTask = { + performRawSeries: true, + overallReset: function (ecModel) { + // Each type of series use one scope. + // Pie and funnel are using diferrent scopes + var paletteScopeGroupByType = createHashMap(); + ecModel.eachSeries(function (seriesModel) { + var colorBy = seriesModel.getColorBy(); + + if (seriesModel.isColorBySeries()) { + return; + } + + var key = seriesModel.type + '-' + colorBy; + var colorScope = paletteScopeGroupByType.get(key); + + if (!colorScope) { + colorScope = {}; + paletteScopeGroupByType.set(key, colorScope); + } + + inner$3(seriesModel).scope = colorScope; + }); + ecModel.eachSeries(function (seriesModel) { + if (seriesModel.isColorBySeries() || ecModel.isSeriesFiltered(seriesModel)) { + return; + } + + var dataAll = seriesModel.getRawData(); + var idxMap = {}; + var data = seriesModel.getData(); + var colorScope = inner$3(seriesModel).scope; + var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; + var colorKey = getDefaultColorKey(seriesModel, stylePath); + data.each(function (idx) { + var rawIdx = data.getRawIndex(idx); + idxMap[rawIdx] = idx; + }); // Iterate on data before filtered. To make sure color from palette can be + // Consistent when toggling legend. + + dataAll.each(function (rawIdx) { + var idx = idxMap[rawIdx]; + var fromPalette = data.getItemVisual(idx, 'colorFromPalette'); // Get color from palette for each data only when the color is inherited from series color, which is + // also picked from color palette. So following situation is not in the case: + // 1. series.itemStyle.color is set + // 2. color is encoded by visualMap + + if (fromPalette) { + var itemStyle = data.ensureUniqueItemVisual(idx, 'style'); + var name_1 = dataAll.getName(rawIdx) || rawIdx + ''; + var dataCount = dataAll.count(); + itemStyle[colorKey] = seriesModel.getColorFromPalette(name_1, colorScope, dataCount); + } + }); + }); + } + }; + + var PI$3 = Math.PI; + /** + * @param {module:echarts/ExtensionAPI} api + * @param {Object} [opts] + * @param {string} [opts.text] + * @param {string} [opts.color] + * @param {string} [opts.textColor] + * @return {module:zrender/Element} + */ + + function defaultLoading(api, opts) { + opts = opts || {}; + defaults(opts, { + text: 'loading', + textColor: '#000', + fontSize: 12, + fontWeight: 'normal', + fontStyle: 'normal', + fontFamily: 'sans-serif', + maskColor: 'rgba(255, 255, 255, 0.8)', + showSpinner: true, + color: '#5470c6', + spinnerRadius: 10, + lineWidth: 5, + zlevel: 0 + }); + var group = new Group(); + var mask = new Rect({ + style: { + fill: opts.maskColor + }, + zlevel: opts.zlevel, + z: 10000 + }); + group.add(mask); + var textContent = new ZRText({ + style: { + text: opts.text, + fill: opts.textColor, + fontSize: opts.fontSize, + fontWeight: opts.fontWeight, + fontStyle: opts.fontStyle, + fontFamily: opts.fontFamily + }, + zlevel: opts.zlevel, + z: 10001 + }); + var labelRect = new Rect({ + style: { + fill: 'none' + }, + textContent: textContent, + textConfig: { + position: 'right', + distance: 10 + }, + zlevel: opts.zlevel, + z: 10001 + }); + group.add(labelRect); + var arc; + + if (opts.showSpinner) { + arc = new Arc({ + shape: { + startAngle: -PI$3 / 2, + endAngle: -PI$3 / 2 + 0.1, + r: opts.spinnerRadius + }, + style: { + stroke: opts.color, + lineCap: 'round', + lineWidth: opts.lineWidth + }, + zlevel: opts.zlevel, + z: 10001 + }); + arc.animateShape(true).when(1000, { + endAngle: PI$3 * 3 / 2 + }).start('circularInOut'); + arc.animateShape(true).when(1000, { + startAngle: PI$3 * 3 / 2 + }).delay(300).start('circularInOut'); + group.add(arc); + } // Inject resize + + + group.resize = function () { + var textWidth = textContent.getBoundingRect().width; + var r = opts.showSpinner ? opts.spinnerRadius : 0; // cx = (containerWidth - arcDiameter - textDistance - textWidth) / 2 + // textDistance needs to be calculated when both animation and text exist + + var cx = (api.getWidth() - r * 2 - (opts.showSpinner && textWidth ? 10 : 0) - textWidth) / 2 - (opts.showSpinner && textWidth ? 0 : 5 + textWidth / 2) // only show the text + + (opts.showSpinner ? 0 : textWidth / 2) // only show the spinner + + (textWidth ? 0 : r); + var cy = api.getHeight() / 2; + opts.showSpinner && arc.setShape({ + cx: cx, + cy: cy + }); + labelRect.setShape({ + x: cx - r, + y: cy - r, + width: r * 2, + height: r * 2 + }); + mask.setShape({ + x: 0, + y: 0, + width: api.getWidth(), + height: api.getHeight() + }); + }; + + group.resize(); + return group; + } + + var Scheduler = + /** @class */ + function () { + function Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) { + // key: handlerUID + this._stageTaskMap = createHashMap(); + this.ecInstance = ecInstance; + this.api = api; // Fix current processors in case that in some rear cases that + // processors might be registered after echarts instance created. + // Register processors incrementally for a echarts instance is + // not supported by this stream architecture. + + dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice(); + visualHandlers = this._visualHandlers = visualHandlers.slice(); + this._allHandlers = dataProcessorHandlers.concat(visualHandlers); + } + + Scheduler.prototype.restoreData = function (ecModel, payload) { + // TODO: Only restore needed series and components, but not all components. + // Currently `restoreData` of all of the series and component will be called. + // But some independent components like `title`, `legend`, `graphic`, `toolbox`, + // `tooltip`, `axisPointer`, etc, do not need series refresh when `setOption`, + // and some components like coordinate system, axes, dataZoom, visualMap only + // need their target series refresh. + // (1) If we are implementing this feature some day, we should consider these cases: + // if a data processor depends on a component (e.g., dataZoomProcessor depends + // on the settings of `dataZoom`), it should be re-performed if the component + // is modified by `setOption`. + // (2) If a processor depends on sevral series, speicified by its `getTargetSeries`, + // it should be re-performed when the result array of `getTargetSeries` changed. + // We use `dependencies` to cover these issues. + // (3) How to update target series when coordinate system related components modified. + // TODO: simply the dirty mechanism? Check whether only the case here can set tasks dirty, + // and this case all of the tasks will be set as dirty. + ecModel.restoreData(payload); // Theoretically an overall task not only depends on each of its target series, but also + // depends on all of the series. + // The overall task is not in pipeline, and `ecModel.restoreData` only set pipeline tasks + // dirty. If `getTargetSeries` of an overall task returns nothing, we should also ensure + // that the overall task is set as dirty and to be performed, otherwise it probably cause + // state chaos. So we have to set dirty of all of the overall tasks manually, otherwise it + // probably cause state chaos (consider `dataZoomProcessor`). + + this._stageTaskMap.each(function (taskRecord) { + var overallTask = taskRecord.overallTask; + overallTask && overallTask.dirty(); + }); + }; // If seriesModel provided, incremental threshold is check by series data. + + + Scheduler.prototype.getPerformArgs = function (task, isBlock) { + // For overall task + if (!task.__pipeline) { + return; + } + + var pipeline = this._pipelineMap.get(task.__pipeline.id); + + var pCtx = pipeline.context; + var incremental = !isBlock && pipeline.progressiveEnabled && (!pCtx || pCtx.progressiveRender) && task.__idxInPipeline > pipeline.blockIndex; + var step = incremental ? pipeline.step : null; + var modDataCount = pCtx && pCtx.modDataCount; + var modBy = modDataCount != null ? Math.ceil(modDataCount / step) : null; + return { + step: step, + modBy: modBy, + modDataCount: modDataCount + }; + }; + + Scheduler.prototype.getPipeline = function (pipelineId) { + return this._pipelineMap.get(pipelineId); + }; + /** + * Current, progressive rendering starts from visual and layout. + * Always detect render mode in the same stage, avoiding that incorrect + * detection caused by data filtering. + * Caution: + * `updateStreamModes` use `seriesModel.getData()`. + */ + + + Scheduler.prototype.updateStreamModes = function (seriesModel, view) { + var pipeline = this._pipelineMap.get(seriesModel.uid); + + var data = seriesModel.getData(); + var dataLen = data.count(); // `progressiveRender` means that can render progressively in each + // animation frame. Note that some types of series do not provide + // `view.incrementalPrepareRender` but support `chart.appendData`. We + // use the term `incremental` but not `progressive` to describe the + // case that `chart.appendData`. + + var progressiveRender = pipeline.progressiveEnabled && view.incrementalPrepareRender && dataLen >= pipeline.threshold; + var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold'); // TODO: modDataCount should not updated if `appendData`, otherwise cause whole repaint. + // see `test/candlestick-large3.html` + + var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null; + seriesModel.pipelineContext = pipeline.context = { + progressiveRender: progressiveRender, + modDataCount: modDataCount, + large: large + }; + }; + + Scheduler.prototype.restorePipelines = function (ecModel) { + var scheduler = this; + var pipelineMap = scheduler._pipelineMap = createHashMap(); + ecModel.eachSeries(function (seriesModel) { + var progressive = seriesModel.getProgressive(); + var pipelineId = seriesModel.uid; + pipelineMap.set(pipelineId, { + id: pipelineId, + head: null, + tail: null, + threshold: seriesModel.getProgressiveThreshold(), + progressiveEnabled: progressive && !(seriesModel.preventIncremental && seriesModel.preventIncremental()), + blockIndex: -1, + step: Math.round(progressive || 700), + count: 0 + }); + + scheduler._pipe(seriesModel, seriesModel.dataTask); + }); + }; + + Scheduler.prototype.prepareStageTasks = function () { + var stageTaskMap = this._stageTaskMap; + var ecModel = this.api.getModel(); + var api = this.api; + each(this._allHandlers, function (handler) { + var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, {}); + var errMsg = ''; + + if ("development" !== 'production') { + // Currently do not need to support to sepecify them both. + errMsg = '"reset" and "overallReset" must not be both specified.'; + } + + assert(!(handler.reset && handler.overallReset), errMsg); + handler.reset && this._createSeriesStageTask(handler, record, ecModel, api); + handler.overallReset && this._createOverallStageTask(handler, record, ecModel, api); + }, this); + }; + + Scheduler.prototype.prepareView = function (view, model, ecModel, api) { + var renderTask = view.renderTask; + var context = renderTask.context; + context.model = model; + context.ecModel = ecModel; + context.api = api; + renderTask.__block = !view.incrementalPrepareRender; + + this._pipe(model, renderTask); + }; + + Scheduler.prototype.performDataProcessorTasks = function (ecModel, payload) { + // If we do not use `block` here, it should be considered when to update modes. + this._performStageTasks(this._dataProcessorHandlers, ecModel, payload, { + block: true + }); + }; + + Scheduler.prototype.performVisualTasks = function (ecModel, payload, opt) { + this._performStageTasks(this._visualHandlers, ecModel, payload, opt); + }; + + Scheduler.prototype._performStageTasks = function (stageHandlers, ecModel, payload, opt) { + opt = opt || {}; + var unfinished = false; + var scheduler = this; + each(stageHandlers, function (stageHandler, idx) { + if (opt.visualType && opt.visualType !== stageHandler.visualType) { + return; + } + + var stageHandlerRecord = scheduler._stageTaskMap.get(stageHandler.uid); + + var seriesTaskMap = stageHandlerRecord.seriesTaskMap; + var overallTask = stageHandlerRecord.overallTask; + + if (overallTask) { + var overallNeedDirty_1; + var agentStubMap = overallTask.agentStubMap; + agentStubMap.each(function (stub) { + if (needSetDirty(opt, stub)) { + stub.dirty(); + overallNeedDirty_1 = true; + } + }); + overallNeedDirty_1 && overallTask.dirty(); + scheduler.updatePayload(overallTask, payload); + var performArgs_1 = scheduler.getPerformArgs(overallTask, opt.block); // Execute stubs firstly, which may set the overall task dirty, + // then execute the overall task. And stub will call seriesModel.setData, + // which ensures that in the overallTask seriesModel.getData() will not + // return incorrect data. + + agentStubMap.each(function (stub) { + stub.perform(performArgs_1); + }); + + if (overallTask.perform(performArgs_1)) { + unfinished = true; + } + } else if (seriesTaskMap) { + seriesTaskMap.each(function (task, pipelineId) { + if (needSetDirty(opt, task)) { + task.dirty(); + } + + var performArgs = scheduler.getPerformArgs(task, opt.block); // FIXME + // if intending to decalare `performRawSeries` in handlers, only + // stream-independent (specifically, data item independent) operations can be + // performed. Because is a series is filtered, most of the tasks will not + // be performed. A stream-dependent operation probably cause wrong biz logic. + // Perhaps we should not provide a separate callback for this case instead + // of providing the config `performRawSeries`. The stream-dependent operaions + // and stream-independent operations should better not be mixed. + + performArgs.skip = !stageHandler.performRawSeries && ecModel.isSeriesFiltered(task.context.model); + scheduler.updatePayload(task, payload); + + if (task.perform(performArgs)) { + unfinished = true; + } + }); + } + }); + + function needSetDirty(opt, task) { + return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id)); + } + + this.unfinished = unfinished || this.unfinished; + }; + + Scheduler.prototype.performSeriesTasks = function (ecModel) { + var unfinished; + ecModel.eachSeries(function (seriesModel) { + // Progress to the end for dataInit and dataRestore. + unfinished = seriesModel.dataTask.perform() || unfinished; + }); + this.unfinished = unfinished || this.unfinished; + }; + + Scheduler.prototype.plan = function () { + // Travel pipelines, check block. + this._pipelineMap.each(function (pipeline) { + var task = pipeline.tail; + + do { + if (task.__block) { + pipeline.blockIndex = task.__idxInPipeline; + break; + } + + task = task.getUpstream(); + } while (task); + }); + }; + + Scheduler.prototype.updatePayload = function (task, payload) { + payload !== 'remain' && (task.context.payload = payload); + }; + + Scheduler.prototype._createSeriesStageTask = function (stageHandler, stageHandlerRecord, ecModel, api) { + var scheduler = this; + var oldSeriesTaskMap = stageHandlerRecord.seriesTaskMap; // The count of stages are totally about only several dozen, so + // do not need to reuse the map. + + var newSeriesTaskMap = stageHandlerRecord.seriesTaskMap = createHashMap(); + var seriesType = stageHandler.seriesType; + var getTargetSeries = stageHandler.getTargetSeries; // If a stageHandler should cover all series, `createOnAllSeries` should be declared mandatorily, + // to avoid some typo or abuse. Otherwise if an extension do not specify a `seriesType`, + // it works but it may cause other irrelevant charts blocked. + + if (stageHandler.createOnAllSeries) { + ecModel.eachRawSeries(create); + } else if (seriesType) { + ecModel.eachRawSeriesByType(seriesType, create); + } else if (getTargetSeries) { + getTargetSeries(ecModel, api).each(create); + } + + function create(seriesModel) { + var pipelineId = seriesModel.uid; // Init tasks for each seriesModel only once. + // Reuse original task instance. + + var task = newSeriesTaskMap.set(pipelineId, oldSeriesTaskMap && oldSeriesTaskMap.get(pipelineId) || createTask({ + plan: seriesTaskPlan, + reset: seriesTaskReset, + count: seriesTaskCount + })); + task.context = { + model: seriesModel, + ecModel: ecModel, + api: api, + // PENDING: `useClearVisual` not used? + useClearVisual: stageHandler.isVisual && !stageHandler.isLayout, + plan: stageHandler.plan, + reset: stageHandler.reset, + scheduler: scheduler + }; + + scheduler._pipe(seriesModel, task); + } + }; + + Scheduler.prototype._createOverallStageTask = function (stageHandler, stageHandlerRecord, ecModel, api) { + var scheduler = this; + var overallTask = stageHandlerRecord.overallTask = stageHandlerRecord.overallTask // For overall task, the function only be called on reset stage. + || createTask({ + reset: overallTaskReset + }); + overallTask.context = { + ecModel: ecModel, + api: api, + overallReset: stageHandler.overallReset, + scheduler: scheduler + }; + var oldAgentStubMap = overallTask.agentStubMap; // The count of stages are totally about only several dozen, so + // do not need to reuse the map. + + var newAgentStubMap = overallTask.agentStubMap = createHashMap(); + var seriesType = stageHandler.seriesType; + var getTargetSeries = stageHandler.getTargetSeries; + var overallProgress = true; + var shouldOverallTaskDirty = false; // FIXME:TS never used, so comment it + // let modifyOutputEnd = stageHandler.modifyOutputEnd; + // An overall task with seriesType detected or has `getTargetSeries`, we add + // stub in each pipelines, it will set the overall task dirty when the pipeline + // progress. Moreover, to avoid call the overall task each frame (too frequent), + // we set the pipeline block. + + var errMsg = ''; + + if ("development" !== 'production') { + errMsg = '"createOnAllSeries" do not supported for "overallReset", ' + 'becuase it will block all streams.'; + } + + assert(!stageHandler.createOnAllSeries, errMsg); + + if (seriesType) { + ecModel.eachRawSeriesByType(seriesType, createStub); + } else if (getTargetSeries) { + getTargetSeries(ecModel, api).each(createStub); + } // Otherwise, (usually it is legancy case), the overall task will only be + // executed when upstream dirty. Otherwise the progressive rendering of all + // pipelines will be disabled unexpectedly. But it still needs stubs to receive + // dirty info from upsteam. + else { + overallProgress = false; + each(ecModel.getSeries(), createStub); + } + + function createStub(seriesModel) { + var pipelineId = seriesModel.uid; + var stub = newAgentStubMap.set(pipelineId, oldAgentStubMap && oldAgentStubMap.get(pipelineId) || ( // When the result of `getTargetSeries` changed, the overallTask + // should be set as dirty and re-performed. + shouldOverallTaskDirty = true, createTask({ + reset: stubReset, + onDirty: stubOnDirty + }))); + stub.context = { + model: seriesModel, + overallProgress: overallProgress // FIXME:TS never used, so comment it + // modifyOutputEnd: modifyOutputEnd + + }; + stub.agent = overallTask; + stub.__block = overallProgress; + + scheduler._pipe(seriesModel, stub); + } + + if (shouldOverallTaskDirty) { + overallTask.dirty(); + } + }; + + Scheduler.prototype._pipe = function (seriesModel, task) { + var pipelineId = seriesModel.uid; + + var pipeline = this._pipelineMap.get(pipelineId); + + !pipeline.head && (pipeline.head = task); + pipeline.tail && pipeline.tail.pipe(task); + pipeline.tail = task; + task.__idxInPipeline = pipeline.count++; + task.__pipeline = pipeline; + }; + + Scheduler.wrapStageHandler = function (stageHandler, visualType) { + if (isFunction(stageHandler)) { + stageHandler = { + overallReset: stageHandler, + seriesType: detectSeriseType(stageHandler) + }; + } + + stageHandler.uid = getUID('stageHandler'); + visualType && (stageHandler.visualType = visualType); + return stageHandler; + }; + return Scheduler; + }(); + + function overallTaskReset(context) { + context.overallReset(context.ecModel, context.api, context.payload); + } + + function stubReset(context) { + return context.overallProgress && stubProgress; + } + + function stubProgress() { + this.agent.dirty(); + this.getDownstream().dirty(); + } + + function stubOnDirty() { + this.agent && this.agent.dirty(); + } + + function seriesTaskPlan(context) { + return context.plan ? context.plan(context.model, context.ecModel, context.api, context.payload) : null; + } + + function seriesTaskReset(context) { + if (context.useClearVisual) { + context.data.clearAllVisual(); + } + + var resetDefines = context.resetDefines = normalizeToArray(context.reset(context.model, context.ecModel, context.api, context.payload)); + return resetDefines.length > 1 ? map(resetDefines, function (v, idx) { + return makeSeriesTaskProgress(idx); + }) : singleSeriesTaskProgress; + } + + var singleSeriesTaskProgress = makeSeriesTaskProgress(0); + + function makeSeriesTaskProgress(resetDefineIdx) { + return function (params, context) { + var data = context.data; + var resetDefine = context.resetDefines[resetDefineIdx]; + + if (resetDefine && resetDefine.dataEach) { + for (var i = params.start; i < params.end; i++) { + resetDefine.dataEach(data, i); + } + } else if (resetDefine && resetDefine.progress) { + resetDefine.progress(params, data); + } + }; + } + + function seriesTaskCount(context) { + return context.data.count(); + } + /** + * Only some legacy stage handlers (usually in echarts extensions) are pure function. + * To ensure that they can work normally, they should work in block mode, that is, + * they should not be started util the previous tasks finished. So they cause the + * progressive rendering disabled. We try to detect the series type, to narrow down + * the block range to only the series type they concern, but not all series. + */ + + + function detectSeriseType(legacyFunc) { + seriesType = null; + + try { + // Assume there is no async when calling `eachSeriesByType`. + legacyFunc(ecModelMock, apiMock); + } catch (e) {} + + return seriesType; + } + + var ecModelMock = {}; + var apiMock = {}; + var seriesType; + mockMethods(ecModelMock, GlobalModel); + mockMethods(apiMock, ExtensionAPI); + + ecModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) { + seriesType = type; + }; + + ecModelMock.eachComponent = function (cond) { + if (cond.mainType === 'series' && cond.subType) { + seriesType = cond.subType; + } + }; + + function mockMethods(target, Clz) { + /* eslint-disable */ + for (var name_1 in Clz.prototype) { + // Do not use hasOwnProperty + target[name_1] = noop; + } + /* eslint-enable */ + + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + var colorAll = ['#37A2DA', '#32C5E9', '#67E0E3', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF']; + var lightTheme = { + color: colorAll, + colorLayer: [['#37A2DA', '#ffd85c', '#fd7b5f'], ['#37A2DA', '#67E0E3', '#FFDB5C', '#ff9f7f', '#E062AE', '#9d96f5'], ['#37A2DA', '#32C5E9', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#e7bcf3', '#8378EA', '#96BFFF'], colorAll] + }; + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + var contrastColor = '#B9B8CE'; + var backgroundColor = '#100C2A'; + + var axisCommon = function () { + return { + axisLine: { + lineStyle: { + color: contrastColor + } + }, + splitLine: { + lineStyle: { + color: '#484753' + } + }, + splitArea: { + areaStyle: { + color: ['rgba(255,255,255,0.02)', 'rgba(255,255,255,0.05)'] + } + }, + minorSplitLine: { + lineStyle: { + color: '#20203B' + } + } + }; + }; + + var colorPalette = ['#4992ff', '#7cffb2', '#fddd60', '#ff6e76', '#58d9f9', '#05c091', '#ff8a45', '#8d48e3', '#dd79ff']; + var theme = { + darkMode: true, + color: colorPalette, + backgroundColor: backgroundColor, + axisPointer: { + lineStyle: { + color: '#817f91' + }, + crossStyle: { + color: '#817f91' + }, + label: { + // TODO Contrast of label backgorundColor + color: '#fff' + } + }, + legend: { + textStyle: { + color: contrastColor + } + }, + textStyle: { + color: contrastColor + }, + title: { + textStyle: { + color: '#EEF1FA' + }, + subtextStyle: { + color: '#B9B8CE' + } + }, + toolbox: { + iconStyle: { + borderColor: contrastColor + } + }, + dataZoom: { + borderColor: '#71708A', + textStyle: { + color: contrastColor + }, + brushStyle: { + color: 'rgba(135,163,206,0.3)' + }, + handleStyle: { + color: '#353450', + borderColor: '#C5CBE3' + }, + moveHandleStyle: { + color: '#B0B6C3', + opacity: 0.3 + }, + fillerColor: 'rgba(135,163,206,0.2)', + emphasis: { + handleStyle: { + borderColor: '#91B7F2', + color: '#4D587D' + }, + moveHandleStyle: { + color: '#636D9A', + opacity: 0.7 + } + }, + dataBackground: { + lineStyle: { + color: '#71708A', + width: 1 + }, + areaStyle: { + color: '#71708A' + } + }, + selectedDataBackground: { + lineStyle: { + color: '#87A3CE' + }, + areaStyle: { + color: '#87A3CE' + } + } + }, + visualMap: { + textStyle: { + color: contrastColor + } + }, + timeline: { + lineStyle: { + color: contrastColor + }, + label: { + color: contrastColor + }, + controlStyle: { + color: contrastColor, + borderColor: contrastColor + } + }, + calendar: { + itemStyle: { + color: backgroundColor + }, + dayLabel: { + color: contrastColor + }, + monthLabel: { + color: contrastColor + }, + yearLabel: { + color: contrastColor + } + }, + timeAxis: axisCommon(), + logAxis: axisCommon(), + valueAxis: axisCommon(), + categoryAxis: axisCommon(), + line: { + symbol: 'circle' + }, + graph: { + color: colorPalette + }, + gauge: { + title: { + color: contrastColor + }, + axisLine: { + lineStyle: { + color: [[1, 'rgba(207,212,219,0.2)']] + } + }, + axisLabel: { + color: contrastColor + }, + detail: { + color: '#EEF1FA' + } + }, + candlestick: { + itemStyle: { + color: '#f64e56', + color0: '#54ea92', + borderColor: '#f64e56', + borderColor0: '#54ea92' // borderColor: '#ca2824', + // borderColor0: '#09a443' + + } + } + }; + theme.categoryAxis.splitLine.show = false; + + /** + * Usage of query: + * `chart.on('click', query, handler);` + * The `query` can be: + * + The component type query string, only `mainType` or `mainType.subType`, + * like: 'xAxis', 'series', 'xAxis.category' or 'series.line'. + * + The component query object, like: + * `{seriesIndex: 2}`, `{seriesName: 'xx'}`, `{seriesId: 'some'}`, + * `{xAxisIndex: 2}`, `{xAxisName: 'xx'}`, `{xAxisId: 'some'}`. + * + The data query object, like: + * `{dataIndex: 123}`, `{dataType: 'link'}`, `{name: 'some'}`. + * + The other query object (cmponent customized query), like: + * `{element: 'some'}` (only available in custom series). + * + * Caveat: If a prop in the `query` object is `null/undefined`, it is the + * same as there is no such prop in the `query` object. + */ + + var ECEventProcessor = + /** @class */ + function () { + function ECEventProcessor() {} + + ECEventProcessor.prototype.normalizeQuery = function (query) { + var cptQuery = {}; + var dataQuery = {}; + var otherQuery = {}; // `query` is `mainType` or `mainType.subType` of component. + + if (isString(query)) { + var condCptType = parseClassType(query); // `.main` and `.sub` may be ''. + + cptQuery.mainType = condCptType.main || null; + cptQuery.subType = condCptType.sub || null; + } // `query` is an object, convert to {mainType, index, name, id}. + else { + // `xxxIndex`, `xxxName`, `xxxId`, `name`, `dataIndex`, `dataType` is reserved, + // can not be used in `compomentModel.filterForExposedEvent`. + var suffixes_1 = ['Index', 'Name', 'Id']; + var dataKeys_1 = { + name: 1, + dataIndex: 1, + dataType: 1 + }; + each(query, function (val, key) { + var reserved = false; + + for (var i = 0; i < suffixes_1.length; i++) { + var propSuffix = suffixes_1[i]; + var suffixPos = key.lastIndexOf(propSuffix); + + if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) { + var mainType = key.slice(0, suffixPos); // Consider `dataIndex`. + + if (mainType !== 'data') { + cptQuery.mainType = mainType; + cptQuery[propSuffix.toLowerCase()] = val; + reserved = true; + } + } + } + + if (dataKeys_1.hasOwnProperty(key)) { + dataQuery[key] = val; + reserved = true; + } + + if (!reserved) { + otherQuery[key] = val; + } + }); + } + + return { + cptQuery: cptQuery, + dataQuery: dataQuery, + otherQuery: otherQuery + }; + }; + + ECEventProcessor.prototype.filter = function (eventType, query) { + // They should be assigned before each trigger call. + var eventInfo = this.eventInfo; + + if (!eventInfo) { + return true; + } + + var targetEl = eventInfo.targetEl; + var packedEvent = eventInfo.packedEvent; + var model = eventInfo.model; + var view = eventInfo.view; // For event like 'globalout'. + + if (!model || !view) { + return true; + } + + var cptQuery = query.cptQuery; + var dataQuery = query.dataQuery; + return check(cptQuery, model, 'mainType') && check(cptQuery, model, 'subType') && check(cptQuery, model, 'index', 'componentIndex') && check(cptQuery, model, 'name') && check(cptQuery, model, 'id') && check(dataQuery, packedEvent, 'name') && check(dataQuery, packedEvent, 'dataIndex') && check(dataQuery, packedEvent, 'dataType') && (!view.filterForExposedEvent || view.filterForExposedEvent(eventType, query.otherQuery, targetEl, packedEvent)); + + function check(query, host, prop, propOnHost) { + return query[prop] == null || host[propOnHost || prop] === query[prop]; + } + }; + + ECEventProcessor.prototype.afterTrigger = function () { + // Make sure the eventInfo wont be used in next trigger. + this.eventInfo = null; + }; + + return ECEventProcessor; + }(); + + var SYMBOL_PROPS_WITH_CB = ['symbol', 'symbolSize', 'symbolRotate', 'symbolOffset']; + var SYMBOL_PROPS = SYMBOL_PROPS_WITH_CB.concat(['symbolKeepAspect']); // Encoding visual for all series include which is filtered for legend drawing + + var seriesSymbolTask = { + createOnAllSeries: true, + // For legend. + performRawSeries: true, + reset: function (seriesModel, ecModel) { + var data = seriesModel.getData(); + + if (seriesModel.legendIcon) { + data.setVisual('legendIcon', seriesModel.legendIcon); + } + + if (!seriesModel.hasSymbolVisual) { + return; + } + + var symbolOptions = {}; + var symbolOptionsCb = {}; + var hasCallback = false; + + for (var i = 0; i < SYMBOL_PROPS_WITH_CB.length; i++) { + var symbolPropName = SYMBOL_PROPS_WITH_CB[i]; + var val = seriesModel.get(symbolPropName); + + if (isFunction(val)) { + hasCallback = true; + symbolOptionsCb[symbolPropName] = val; + } else { + symbolOptions[symbolPropName] = val; + } + } + + symbolOptions.symbol = symbolOptions.symbol || seriesModel.defaultSymbol; + data.setVisual(extend({ + legendIcon: seriesModel.legendIcon || symbolOptions.symbol, + symbolKeepAspect: seriesModel.get('symbolKeepAspect') + }, symbolOptions)); // Only visible series has each data be visual encoded + + if (ecModel.isSeriesFiltered(seriesModel)) { + return; + } + + var symbolPropsCb = keys(symbolOptionsCb); + + function dataEach(data, idx) { + var rawValue = seriesModel.getRawValue(idx); + var params = seriesModel.getDataParams(idx); + + for (var i = 0; i < symbolPropsCb.length; i++) { + var symbolPropName = symbolPropsCb[i]; + data.setItemVisual(idx, symbolPropName, symbolOptionsCb[symbolPropName](rawValue, params)); + } + } + + return { + dataEach: hasCallback ? dataEach : null + }; + } + }; + var dataSymbolTask = { + createOnAllSeries: true, + // For legend. + performRawSeries: true, + reset: function (seriesModel, ecModel) { + if (!seriesModel.hasSymbolVisual) { + return; + } // Only visible series has each data be visual encoded + + + if (ecModel.isSeriesFiltered(seriesModel)) { + return; + } + + var data = seriesModel.getData(); + + function dataEach(data, idx) { + var itemModel = data.getItemModel(idx); + + for (var i = 0; i < SYMBOL_PROPS.length; i++) { + var symbolPropName = SYMBOL_PROPS[i]; + var val = itemModel.getShallow(symbolPropName, true); + + if (val != null) { + data.setItemVisual(idx, symbolPropName, val); + } + } + } + + return { + dataEach: data.hasItemOption ? dataEach : null + }; + } + }; + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + function getItemVisualFromData(data, dataIndex, key) { + switch (key) { + case 'color': + var style = data.getItemVisual(dataIndex, 'style'); + return style[data.getVisual('drawType')]; + + case 'opacity': + return data.getItemVisual(dataIndex, 'style').opacity; + + case 'symbol': + case 'symbolSize': + case 'liftZ': + return data.getItemVisual(dataIndex, key); + + default: + if ("development" !== 'production') { + console.warn("Unknown visual type " + key); + } + + } + } + function getVisualFromData(data, key) { + switch (key) { + case 'color': + var style = data.getVisual('style'); + return style[data.getVisual('drawType')]; + + case 'opacity': + return data.getVisual('style').opacity; + + case 'symbol': + case 'symbolSize': + case 'liftZ': + return data.getVisual(key); + + default: + if ("development" !== 'production') { + console.warn("Unknown visual type " + key); + } + + } + } + function setItemVisualFromData(data, dataIndex, key, value) { + switch (key) { + case 'color': + // Make sure not sharing style object. + var style = data.ensureUniqueItemVisual(dataIndex, 'style'); + style[data.getVisual('drawType')] = value; // Mark the color has been changed, not from palette anymore + + data.setItemVisual(dataIndex, 'colorFromPalette', false); + break; + + case 'opacity': + data.ensureUniqueItemVisual(dataIndex, 'style').opacity = value; + break; + + case 'symbol': + case 'symbolSize': + case 'liftZ': + data.setItemVisual(dataIndex, key, value); + break; + + default: + if ("development" !== 'production') { + console.warn("Unknown visual type " + key); + } + + } + } + + // Inlucdes: pieSelect, pieUnSelect, pieToggleSelect, mapSelect, mapUnSelect, mapToggleSelect + + function createLegacyDataSelectAction(seriesType, ecRegisterAction) { + function getSeriesIndices(ecModel, payload) { + var seriesIndices = []; + ecModel.eachComponent({ + mainType: 'series', + subType: seriesType, + query: payload + }, function (seriesModel) { + seriesIndices.push(seriesModel.seriesIndex); + }); + return seriesIndices; + } + + each([[seriesType + 'ToggleSelect', 'toggleSelect'], [seriesType + 'Select', 'select'], [seriesType + 'UnSelect', 'unselect']], function (eventsMap) { + ecRegisterAction(eventsMap[0], function (payload, ecModel, api) { + payload = extend({}, payload); + + if ("development" !== 'production') { + deprecateReplaceLog(payload.type, eventsMap[1]); + } + + api.dispatchAction(extend(payload, { + type: eventsMap[1], + seriesIndex: getSeriesIndices(ecModel, payload) + })); + }); + }); + } + + function handleSeriesLegacySelectEvents(type, eventPostfix, ecIns, ecModel, payload) { + var legacyEventName = type + eventPostfix; + + if (!ecIns.isSilent(legacyEventName)) { + if ("development" !== 'production') { + deprecateLog("event " + legacyEventName + " is deprecated."); + } + + ecModel.eachComponent({ + mainType: 'series', + subType: 'pie' + }, function (seriesModel) { + var seriesIndex = seriesModel.seriesIndex; + var selectedMap = seriesModel.option.selectedMap; + var selected = payload.selected; + + for (var i = 0; i < selected.length; i++) { + if (selected[i].seriesIndex === seriesIndex) { + var data = seriesModel.getData(); + var dataIndex = queryDataIndex(data, payload.fromActionPayload); + ecIns.trigger(legacyEventName, { + type: legacyEventName, + seriesId: seriesModel.id, + name: isArray(dataIndex) ? data.getName(dataIndex[0]) : data.getName(dataIndex), + selected: isString(selectedMap) ? selectedMap : extend({}, selectedMap) + }); + } + } + }); + } + } + + function handleLegacySelectEvents(messageCenter, ecIns, api) { + messageCenter.on('selectchanged', function (params) { + var ecModel = api.getModel(); + + if (params.isFromClick) { + handleSeriesLegacySelectEvents('map', 'selectchanged', ecIns, ecModel, params); + handleSeriesLegacySelectEvents('pie', 'selectchanged', ecIns, ecModel, params); + } else if (params.fromAction === 'select') { + handleSeriesLegacySelectEvents('map', 'selected', ecIns, ecModel, params); + handleSeriesLegacySelectEvents('pie', 'selected', ecIns, ecModel, params); + } else if (params.fromAction === 'unselect') { + handleSeriesLegacySelectEvents('map', 'unselected', ecIns, ecModel, params); + handleSeriesLegacySelectEvents('pie', 'unselected', ecIns, ecModel, params); + } + }); + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + function findEventDispatcher(target, det, returnFirstMatch) { + var found; + + while (target) { + if (det(target)) { + found = target; + + if (returnFirstMatch) { + break; + } + } + + target = target.__hostTarget || target.parent; + } + + return found; + } + + var wmUniqueIndex = Math.round(Math.random() * 9); + var supportDefineProperty = typeof Object.defineProperty === 'function'; + var WeakMap = (function () { + function WeakMap() { + this._id = '__ec_inner_' + wmUniqueIndex++; + } + WeakMap.prototype.get = function (key) { + return this._guard(key)[this._id]; + }; + WeakMap.prototype.set = function (key, value) { + var target = this._guard(key); + if (supportDefineProperty) { + Object.defineProperty(target, this._id, { + value: value, + enumerable: false, + configurable: true + }); + } + else { + target[this._id] = value; + } + return this; + }; + WeakMap.prototype["delete"] = function (key) { + if (this.has(key)) { + delete this._guard(key)[this._id]; + return true; + } + return false; + }; + WeakMap.prototype.has = function (key) { + return !!this._guard(key)[this._id]; + }; + WeakMap.prototype._guard = function (key) { + if (key !== Object(key)) { + throw TypeError('Value of WeakMap is not a non-null object.'); + } + return key; + }; + return WeakMap; + }()); + + /** + * Triangle shape + * @inner + */ + + var Triangle = Path.extend({ + type: 'triangle', + shape: { + cx: 0, + cy: 0, + width: 0, + height: 0 + }, + buildPath: function (path, shape) { + var cx = shape.cx; + var cy = shape.cy; + var width = shape.width / 2; + var height = shape.height / 2; + path.moveTo(cx, cy - height); + path.lineTo(cx + width, cy + height); + path.lineTo(cx - width, cy + height); + path.closePath(); + } + }); + /** + * Diamond shape + * @inner + */ + + var Diamond = Path.extend({ + type: 'diamond', + shape: { + cx: 0, + cy: 0, + width: 0, + height: 0 + }, + buildPath: function (path, shape) { + var cx = shape.cx; + var cy = shape.cy; + var width = shape.width / 2; + var height = shape.height / 2; + path.moveTo(cx, cy - height); + path.lineTo(cx + width, cy); + path.lineTo(cx, cy + height); + path.lineTo(cx - width, cy); + path.closePath(); + } + }); + /** + * Pin shape + * @inner + */ + + var Pin = Path.extend({ + type: 'pin', + shape: { + // x, y on the cusp + x: 0, + y: 0, + width: 0, + height: 0 + }, + buildPath: function (path, shape) { + var x = shape.x; + var y = shape.y; + var w = shape.width / 5 * 3; // Height must be larger than width + + var h = Math.max(w, shape.height); + var r = w / 2; // Dist on y with tangent point and circle center + + var dy = r * r / (h - r); + var cy = y - h + r + dy; + var angle = Math.asin(dy / r); // Dist on x with tangent point and circle center + + var dx = Math.cos(angle) * r; + var tanX = Math.sin(angle); + var tanY = Math.cos(angle); + var cpLen = r * 0.6; + var cpLen2 = r * 0.7; + path.moveTo(x - dx, cy + dy); + path.arc(x, cy, r, Math.PI - angle, Math.PI * 2 + angle); + path.bezierCurveTo(x + dx - tanX * cpLen, cy + dy + tanY * cpLen, x, y - cpLen2, x, y); + path.bezierCurveTo(x, y - cpLen2, x - dx + tanX * cpLen, cy + dy + tanY * cpLen, x - dx, cy + dy); + path.closePath(); + } + }); + /** + * Arrow shape + * @inner + */ + + var Arrow = Path.extend({ + type: 'arrow', + shape: { + x: 0, + y: 0, + width: 0, + height: 0 + }, + buildPath: function (ctx, shape) { + var height = shape.height; + var width = shape.width; + var x = shape.x; + var y = shape.y; + var dx = width / 3 * 2; + ctx.moveTo(x, y); + ctx.lineTo(x + dx, y + height); + ctx.lineTo(x, y + height / 4 * 3); + ctx.lineTo(x - dx, y + height); + ctx.lineTo(x, y); + ctx.closePath(); + } + }); + /** + * Map of path contructors + */ + // TODO Use function to build symbol path. + + var symbolCtors = { + line: Line, + rect: Rect, + roundRect: Rect, + square: Rect, + circle: Circle, + diamond: Diamond, + pin: Pin, + arrow: Arrow, + triangle: Triangle + }; + var symbolShapeMakers = { + line: function (x, y, w, h, shape) { + shape.x1 = x; + shape.y1 = y + h / 2; + shape.x2 = x + w; + shape.y2 = y + h / 2; + }, + rect: function (x, y, w, h, shape) { + shape.x = x; + shape.y = y; + shape.width = w; + shape.height = h; + }, + roundRect: function (x, y, w, h, shape) { + shape.x = x; + shape.y = y; + shape.width = w; + shape.height = h; + shape.r = Math.min(w, h) / 4; + }, + square: function (x, y, w, h, shape) { + var size = Math.min(w, h); + shape.x = x; + shape.y = y; + shape.width = size; + shape.height = size; + }, + circle: function (x, y, w, h, shape) { + // Put circle in the center of square + shape.cx = x + w / 2; + shape.cy = y + h / 2; + shape.r = Math.min(w, h) / 2; + }, + diamond: function (x, y, w, h, shape) { + shape.cx = x + w / 2; + shape.cy = y + h / 2; + shape.width = w; + shape.height = h; + }, + pin: function (x, y, w, h, shape) { + shape.x = x + w / 2; + shape.y = y + h / 2; + shape.width = w; + shape.height = h; + }, + arrow: function (x, y, w, h, shape) { + shape.x = x + w / 2; + shape.y = y + h / 2; + shape.width = w; + shape.height = h; + }, + triangle: function (x, y, w, h, shape) { + shape.cx = x + w / 2; + shape.cy = y + h / 2; + shape.width = w; + shape.height = h; + } + }; + var symbolBuildProxies = {}; + each(symbolCtors, function (Ctor, name) { + symbolBuildProxies[name] = new Ctor(); + }); + var SymbolClz = Path.extend({ + type: 'symbol', + shape: { + symbolType: '', + x: 0, + y: 0, + width: 0, + height: 0 + }, + calculateTextPosition: function (out, config, rect) { + var res = calculateTextPosition(out, config, rect); + var shape = this.shape; + + if (shape && shape.symbolType === 'pin' && config.position === 'inside') { + res.y = rect.y + rect.height * 0.4; + } + + return res; + }, + buildPath: function (ctx, shape, inBundle) { + var symbolType = shape.symbolType; + + if (symbolType !== 'none') { + var proxySymbol = symbolBuildProxies[symbolType]; + + if (!proxySymbol) { + // Default rect + symbolType = 'rect'; + proxySymbol = symbolBuildProxies[symbolType]; + } + + symbolShapeMakers[symbolType](shape.x, shape.y, shape.width, shape.height, proxySymbol.shape); + proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle); + } + } + }); // Provide setColor helper method to avoid determine if set the fill or stroke outside + + function symbolPathSetColor(color, innerColor) { + if (this.type !== 'image') { + var symbolStyle = this.style; + + if (this.__isEmptyBrush) { + symbolStyle.stroke = color; + symbolStyle.fill = innerColor || '#fff'; // TODO Same width with lineStyle in LineView + + symbolStyle.lineWidth = 2; + } else if (this.shape.symbolType === 'line') { + symbolStyle.stroke = color; + } else { + symbolStyle.fill = color; + } + + this.markRedraw(); + } + } + /** + * Create a symbol element with given symbol configuration: shape, x, y, width, height, color + */ + + + function createSymbol(symbolType, x, y, w, h, color, // whether to keep the ratio of w/h, + keepAspect) { + // TODO Support image object, DynamicImage. + var isEmpty = symbolType.indexOf('empty') === 0; + + if (isEmpty) { + symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6); + } + + var symbolPath; + + if (symbolType.indexOf('image://') === 0) { + symbolPath = makeImage(symbolType.slice(8), new BoundingRect(x, y, w, h), keepAspect ? 'center' : 'cover'); + } else if (symbolType.indexOf('path://') === 0) { + symbolPath = makePath(symbolType.slice(7), {}, new BoundingRect(x, y, w, h), keepAspect ? 'center' : 'cover'); + } else { + symbolPath = new SymbolClz({ + shape: { + symbolType: symbolType, + x: x, + y: y, + width: w, + height: h + } + }); + } + + symbolPath.__isEmptyBrush = isEmpty; // TODO Should deprecate setColor + + symbolPath.setColor = symbolPathSetColor; + + if (color) { + symbolPath.setColor(color); + } + + return symbolPath; + } + function normalizeSymbolSize(symbolSize) { + if (!isArray(symbolSize)) { + symbolSize = [+symbolSize, +symbolSize]; + } + + return [symbolSize[0] || 0, symbolSize[1] || 0]; + } + function normalizeSymbolOffset(symbolOffset, symbolSize) { + if (symbolOffset == null) { + return; + } + + if (!isArray(symbolOffset)) { + symbolOffset = [symbolOffset, symbolOffset]; + } + + return [parsePercent$1(symbolOffset[0], symbolSize[0]) || 0, parsePercent$1(retrieve2(symbolOffset[1], symbolOffset[0]), symbolSize[1]) || 0]; + } + + function createLinearGradient(ctx, obj, rect) { + var x = obj.x == null ? 0 : obj.x; + var x2 = obj.x2 == null ? 1 : obj.x2; + var y = obj.y == null ? 0 : obj.y; + var y2 = obj.y2 == null ? 0 : obj.y2; + if (!obj.global) { + x = x * rect.width + rect.x; + x2 = x2 * rect.width + rect.x; + y = y * rect.height + rect.y; + y2 = y2 * rect.height + rect.y; + } + x = isNaN(x) ? 0 : x; + x2 = isNaN(x2) ? 1 : x2; + y = isNaN(y) ? 0 : y; + y2 = isNaN(y2) ? 0 : y2; + var canvasGradient = ctx.createLinearGradient(x, y, x2, y2); + return canvasGradient; + } + function createRadialGradient(ctx, obj, rect) { + var width = rect.width; + var height = rect.height; + var min = Math.min(width, height); + var x = obj.x == null ? 0.5 : obj.x; + var y = obj.y == null ? 0.5 : obj.y; + var r = obj.r == null ? 0.5 : obj.r; + if (!obj.global) { + x = x * width + rect.x; + y = y * height + rect.y; + r = r * min; + } + var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r); + return canvasGradient; + } + function getCanvasGradient(ctx, obj, rect) { + var canvasGradient = obj.type === 'radial' + ? createRadialGradient(ctx, obj, rect) + : createLinearGradient(ctx, obj, rect); + var colorStops = obj.colorStops; + for (var i = 0; i < colorStops.length; i++) { + canvasGradient.addColorStop(colorStops[i].offset, colorStops[i].color); + } + return canvasGradient; + } + function isClipPathChanged(clipPaths, prevClipPaths) { + if (clipPaths === prevClipPaths || (!clipPaths && !prevClipPaths)) { + return false; + } + if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) { + return true; + } + for (var i = 0; i < clipPaths.length; i++) { + if (clipPaths[i] !== prevClipPaths[i]) { + return true; + } + } + return false; + } + function parseInt10(val) { + return parseInt(val, 10); + } + function getSize(root, whIdx, opts) { + var wh = ['width', 'height'][whIdx]; + var cwh = ['clientWidth', 'clientHeight'][whIdx]; + var plt = ['paddingLeft', 'paddingTop'][whIdx]; + var prb = ['paddingRight', 'paddingBottom'][whIdx]; + if (opts[wh] != null && opts[wh] !== 'auto') { + return parseFloat(opts[wh]); + } + var stl = document.defaultView.getComputedStyle(root); + return ((root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh])) + - (parseInt10(stl[plt]) || 0) + - (parseInt10(stl[prb]) || 0)) | 0; + } + + function normalizeLineDash(lineType, lineWidth) { + if (!lineType || lineType === 'solid' || !(lineWidth > 0)) { + return null; + } + return lineType === 'dashed' + ? [4 * lineWidth, 2 * lineWidth] + : lineType === 'dotted' + ? [lineWidth] + : isNumber(lineType) + ? [lineType] : isArray(lineType) ? lineType : null; + } + function getLineDash(el) { + var style = el.style; + var lineDash = style.lineDash && style.lineWidth > 0 && normalizeLineDash(style.lineDash, style.lineWidth); + var lineDashOffset = style.lineDashOffset; + if (lineDash) { + var lineScale_1 = (style.strokeNoScale && el.getLineScale) ? el.getLineScale() : 1; + if (lineScale_1 && lineScale_1 !== 1) { + lineDash = map(lineDash, function (rawVal) { + return rawVal / lineScale_1; + }); + lineDashOffset /= lineScale_1; + } + } + return [lineDash, lineDashOffset]; + } + + var pathProxyForDraw = new PathProxy(true); + function styleHasStroke(style) { + var stroke = style.stroke; + return !(stroke == null || stroke === 'none' || !(style.lineWidth > 0)); + } + function isValidStrokeFillStyle(strokeOrFill) { + return typeof strokeOrFill === 'string' && strokeOrFill !== 'none'; + } + function styleHasFill(style) { + var fill = style.fill; + return fill != null && fill !== 'none'; + } + function doFillPath(ctx, style) { + if (style.fillOpacity != null && style.fillOpacity !== 1) { + var originalGlobalAlpha = ctx.globalAlpha; + ctx.globalAlpha = style.fillOpacity * style.opacity; + ctx.fill(); + ctx.globalAlpha = originalGlobalAlpha; + } + else { + ctx.fill(); + } + } + function doStrokePath(ctx, style) { + if (style.strokeOpacity != null && style.strokeOpacity !== 1) { + var originalGlobalAlpha = ctx.globalAlpha; + ctx.globalAlpha = style.strokeOpacity * style.opacity; + ctx.stroke(); + ctx.globalAlpha = originalGlobalAlpha; + } + else { + ctx.stroke(); + } + } + function createCanvasPattern(ctx, pattern, el) { + var image = createOrUpdateImage(pattern.image, pattern.__image, el); + if (isImageReady(image)) { + var canvasPattern = ctx.createPattern(image, pattern.repeat || 'repeat'); + if (typeof DOMMatrix === 'function' + && canvasPattern + && canvasPattern.setTransform) { + var matrix = new DOMMatrix(); + matrix.translateSelf((pattern.x || 0), (pattern.y || 0)); + matrix.rotateSelf(0, 0, (pattern.rotation || 0) * RADIAN_TO_DEGREE); + matrix.scaleSelf((pattern.scaleX || 1), (pattern.scaleY || 1)); + canvasPattern.setTransform(matrix); + } + return canvasPattern; + } + } + function brushPath(ctx, el, style, inBatch) { + var _a; + var hasStroke = styleHasStroke(style); + var hasFill = styleHasFill(style); + var strokePercent = style.strokePercent; + var strokePart = strokePercent < 1; + var firstDraw = !el.path; + if ((!el.silent || strokePart) && firstDraw) { + el.createPathProxy(); + } + var path = el.path || pathProxyForDraw; + var dirtyFlag = el.__dirty; + if (!inBatch) { + var fill = style.fill; + var stroke = style.stroke; + var hasFillGradient = hasFill && !!fill.colorStops; + var hasStrokeGradient = hasStroke && !!stroke.colorStops; + var hasFillPattern = hasFill && !!fill.image; + var hasStrokePattern = hasStroke && !!stroke.image; + var fillGradient = void 0; + var strokeGradient = void 0; + var fillPattern = void 0; + var strokePattern = void 0; + var rect = void 0; + if (hasFillGradient || hasStrokeGradient) { + rect = el.getBoundingRect(); + } + if (hasFillGradient) { + fillGradient = dirtyFlag + ? getCanvasGradient(ctx, fill, rect) + : el.__canvasFillGradient; + el.__canvasFillGradient = fillGradient; + } + if (hasStrokeGradient) { + strokeGradient = dirtyFlag + ? getCanvasGradient(ctx, stroke, rect) + : el.__canvasStrokeGradient; + el.__canvasStrokeGradient = strokeGradient; + } + if (hasFillPattern) { + fillPattern = (dirtyFlag || !el.__canvasFillPattern) + ? createCanvasPattern(ctx, fill, el) + : el.__canvasFillPattern; + el.__canvasFillPattern = fillPattern; + } + if (hasStrokePattern) { + strokePattern = (dirtyFlag || !el.__canvasStrokePattern) + ? createCanvasPattern(ctx, stroke, el) + : el.__canvasStrokePattern; + el.__canvasStrokePattern = fillPattern; + } + if (hasFillGradient) { + ctx.fillStyle = fillGradient; + } + else if (hasFillPattern) { + if (fillPattern) { + ctx.fillStyle = fillPattern; + } + else { + hasFill = false; + } + } + if (hasStrokeGradient) { + ctx.strokeStyle = strokeGradient; + } + else if (hasStrokePattern) { + if (strokePattern) { + ctx.strokeStyle = strokePattern; + } + else { + hasStroke = false; + } + } + } + var scale = el.getGlobalScale(); + path.setScale(scale[0], scale[1], el.segmentIgnoreThreshold); + var lineDash; + var lineDashOffset; + if (ctx.setLineDash && style.lineDash) { + _a = getLineDash(el), lineDash = _a[0], lineDashOffset = _a[1]; + } + var needsRebuild = true; + if (firstDraw || (dirtyFlag & SHAPE_CHANGED_BIT)) { + path.setDPR(ctx.dpr); + if (strokePart) { + path.setContext(null); + } + else { + path.setContext(ctx); + needsRebuild = false; + } + path.reset(); + el.buildPath(path, el.shape, inBatch); + path.toStatic(); + el.pathUpdated(); + } + if (needsRebuild) { + path.rebuildPath(ctx, strokePart ? strokePercent : 1); + } + if (lineDash) { + ctx.setLineDash(lineDash); + ctx.lineDashOffset = lineDashOffset; + } + if (!inBatch) { + if (style.strokeFirst) { + if (hasStroke) { + doStrokePath(ctx, style); + } + if (hasFill) { + doFillPath(ctx, style); + } + } + else { + if (hasFill) { + doFillPath(ctx, style); + } + if (hasStroke) { + doStrokePath(ctx, style); + } + } + } + if (lineDash) { + ctx.setLineDash([]); + } + } + function brushImage(ctx, el, style) { + var image = el.__image = createOrUpdateImage(style.image, el.__image, el, el.onload); + if (!image || !isImageReady(image)) { + return; + } + var x = style.x || 0; + var y = style.y || 0; + var width = el.getWidth(); + var height = el.getHeight(); + var aspect = image.width / image.height; + if (width == null && height != null) { + width = height * aspect; + } + else if (height == null && width != null) { + height = width / aspect; + } + else if (width == null && height == null) { + width = image.width; + height = image.height; + } + if (style.sWidth && style.sHeight) { + var sx = style.sx || 0; + var sy = style.sy || 0; + ctx.drawImage(image, sx, sy, style.sWidth, style.sHeight, x, y, width, height); + } + else if (style.sx && style.sy) { + var sx = style.sx; + var sy = style.sy; + var sWidth = width - sx; + var sHeight = height - sy; + ctx.drawImage(image, sx, sy, sWidth, sHeight, x, y, width, height); + } + else { + ctx.drawImage(image, x, y, width, height); + } + } + function brushText(ctx, el, style) { + var _a; + var text = style.text; + text != null && (text += ''); + if (text) { + ctx.font = style.font || DEFAULT_FONT; + ctx.textAlign = style.textAlign; + ctx.textBaseline = style.textBaseline; + var lineDash = void 0; + var lineDashOffset = void 0; + if (ctx.setLineDash && style.lineDash) { + _a = getLineDash(el), lineDash = _a[0], lineDashOffset = _a[1]; + } + if (lineDash) { + ctx.setLineDash(lineDash); + ctx.lineDashOffset = lineDashOffset; + } + if (style.strokeFirst) { + if (styleHasStroke(style)) { + ctx.strokeText(text, style.x, style.y); + } + if (styleHasFill(style)) { + ctx.fillText(text, style.x, style.y); + } + } + else { + if (styleHasFill(style)) { + ctx.fillText(text, style.x, style.y); + } + if (styleHasStroke(style)) { + ctx.strokeText(text, style.x, style.y); + } + } + if (lineDash) { + ctx.setLineDash([]); + } + } + } + var SHADOW_NUMBER_PROPS = ['shadowBlur', 'shadowOffsetX', 'shadowOffsetY']; + var STROKE_PROPS = [ + ['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10] + ]; + function bindCommonProps(ctx, style, prevStyle, forceSetAll, scope) { + var styleChanged = false; + if (!forceSetAll) { + prevStyle = prevStyle || {}; + if (style === prevStyle) { + return false; + } + } + if (forceSetAll || style.opacity !== prevStyle.opacity) { + flushPathDrawn(ctx, scope); + styleChanged = true; + var opacity = Math.max(Math.min(style.opacity, 1), 0); + ctx.globalAlpha = isNaN(opacity) ? DEFAULT_COMMON_STYLE.opacity : opacity; + } + if (forceSetAll || style.blend !== prevStyle.blend) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + ctx.globalCompositeOperation = style.blend || DEFAULT_COMMON_STYLE.blend; + } + for (var i = 0; i < SHADOW_NUMBER_PROPS.length; i++) { + var propName = SHADOW_NUMBER_PROPS[i]; + if (forceSetAll || style[propName] !== prevStyle[propName]) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + ctx[propName] = ctx.dpr * (style[propName] || 0); + } + } + if (forceSetAll || style.shadowColor !== prevStyle.shadowColor) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + ctx.shadowColor = style.shadowColor || DEFAULT_COMMON_STYLE.shadowColor; + } + return styleChanged; + } + function bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetAll, scope) { + var style = getStyle(el, scope.inHover); + var prevStyle = forceSetAll + ? null + : (prevEl && getStyle(prevEl, scope.inHover) || {}); + if (style === prevStyle) { + return false; + } + var styleChanged = bindCommonProps(ctx, style, prevStyle, forceSetAll, scope); + if (forceSetAll || style.fill !== prevStyle.fill) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + isValidStrokeFillStyle(style.fill) && (ctx.fillStyle = style.fill); + } + if (forceSetAll || style.stroke !== prevStyle.stroke) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + isValidStrokeFillStyle(style.stroke) && (ctx.strokeStyle = style.stroke); + } + if (forceSetAll || style.opacity !== prevStyle.opacity) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + ctx.globalAlpha = style.opacity == null ? 1 : style.opacity; + } + if (el.hasStroke()) { + var lineWidth = style.lineWidth; + var newLineWidth = lineWidth / ((style.strokeNoScale && el.getLineScale) ? el.getLineScale() : 1); + if (ctx.lineWidth !== newLineWidth) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + ctx.lineWidth = newLineWidth; + } + } + for (var i = 0; i < STROKE_PROPS.length; i++) { + var prop = STROKE_PROPS[i]; + var propName = prop[0]; + if (forceSetAll || style[propName] !== prevStyle[propName]) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + ctx[propName] = style[propName] || prop[1]; + } + } + return styleChanged; + } + function bindImageStyle(ctx, el, prevEl, forceSetAll, scope) { + return bindCommonProps(ctx, getStyle(el, scope.inHover), prevEl && getStyle(prevEl, scope.inHover), forceSetAll, scope); + } + function setContextTransform(ctx, el) { + var m = el.transform; + var dpr = ctx.dpr || 1; + if (m) { + ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]); + } + else { + ctx.setTransform(dpr, 0, 0, dpr, 0, 0); + } + } + function updateClipStatus(clipPaths, ctx, scope) { + var allClipped = false; + for (var i = 0; i < clipPaths.length; i++) { + var clipPath = clipPaths[i]; + allClipped = allClipped || clipPath.isZeroArea(); + setContextTransform(ctx, clipPath); + ctx.beginPath(); + clipPath.buildPath(ctx, clipPath.shape); + ctx.clip(); + } + scope.allClipped = allClipped; + } + function isTransformChanged(m0, m1) { + if (m0 && m1) { + return m0[0] !== m1[0] + || m0[1] !== m1[1] + || m0[2] !== m1[2] + || m0[3] !== m1[3] + || m0[4] !== m1[4] + || m0[5] !== m1[5]; + } + else if (!m0 && !m1) { + return false; + } + return true; + } + var DRAW_TYPE_PATH = 1; + var DRAW_TYPE_IMAGE = 2; + var DRAW_TYPE_TEXT = 3; + var DRAW_TYPE_INCREMENTAL = 4; + function canPathBatch(style) { + var hasFill = styleHasFill(style); + var hasStroke = styleHasStroke(style); + return !(style.lineDash + || !(+hasFill ^ +hasStroke) + || (hasFill && typeof style.fill !== 'string') + || (hasStroke && typeof style.stroke !== 'string') + || style.strokePercent < 1 + || style.strokeOpacity < 1 + || style.fillOpacity < 1); + } + function flushPathDrawn(ctx, scope) { + scope.batchFill && ctx.fill(); + scope.batchStroke && ctx.stroke(); + scope.batchFill = ''; + scope.batchStroke = ''; + } + function getStyle(el, inHover) { + return inHover ? (el.__hoverStyle || el.style) : el.style; + } + function brushSingle(ctx, el) { + brush(ctx, el, { inHover: false, viewWidth: 0, viewHeight: 0 }, true); + } + function brush(ctx, el, scope, isLast) { + var m = el.transform; + if (!el.shouldBePainted(scope.viewWidth, scope.viewHeight, false, false)) { + el.__dirty &= ~REDRAW_BIT; + el.__isRendered = false; + return; + } + var clipPaths = el.__clipPaths; + var prevElClipPaths = scope.prevElClipPaths; + var forceSetTransform = false; + var forceSetStyle = false; + if (!prevElClipPaths || isClipPathChanged(clipPaths, prevElClipPaths)) { + if (prevElClipPaths && prevElClipPaths.length) { + flushPathDrawn(ctx, scope); + ctx.restore(); + forceSetStyle = forceSetTransform = true; + scope.prevElClipPaths = null; + scope.allClipped = false; + scope.prevEl = null; + } + if (clipPaths && clipPaths.length) { + flushPathDrawn(ctx, scope); + ctx.save(); + updateClipStatus(clipPaths, ctx, scope); + forceSetTransform = true; + } + scope.prevElClipPaths = clipPaths; + } + if (scope.allClipped) { + el.__isRendered = false; + return; + } + el.beforeBrush && el.beforeBrush(); + el.innerBeforeBrush(); + var prevEl = scope.prevEl; + if (!prevEl) { + forceSetStyle = forceSetTransform = true; + } + var canBatchPath = el instanceof Path + && el.autoBatch + && canPathBatch(el.style); + if (forceSetTransform || isTransformChanged(m, prevEl.transform)) { + flushPathDrawn(ctx, scope); + setContextTransform(ctx, el); + } + else if (!canBatchPath) { + flushPathDrawn(ctx, scope); + } + var style = getStyle(el, scope.inHover); + if (el instanceof Path) { + if (scope.lastDrawType !== DRAW_TYPE_PATH) { + forceSetStyle = true; + scope.lastDrawType = DRAW_TYPE_PATH; + } + bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetStyle, scope); + if (!canBatchPath || (!scope.batchFill && !scope.batchStroke)) { + ctx.beginPath(); + } + brushPath(ctx, el, style, canBatchPath); + if (canBatchPath) { + scope.batchFill = style.fill || ''; + scope.batchStroke = style.stroke || ''; + } + } + else { + if (el instanceof TSpan) { + if (scope.lastDrawType !== DRAW_TYPE_TEXT) { + forceSetStyle = true; + scope.lastDrawType = DRAW_TYPE_TEXT; + } + bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetStyle, scope); + brushText(ctx, el, style); + } + else if (el instanceof ZRImage) { + if (scope.lastDrawType !== DRAW_TYPE_IMAGE) { + forceSetStyle = true; + scope.lastDrawType = DRAW_TYPE_IMAGE; + } + bindImageStyle(ctx, el, prevEl, forceSetStyle, scope); + brushImage(ctx, el, style); + } + else if (el.getTemporalDisplayables) { + if (scope.lastDrawType !== DRAW_TYPE_INCREMENTAL) { + forceSetStyle = true; + scope.lastDrawType = DRAW_TYPE_INCREMENTAL; + } + brushIncremental(ctx, el, scope); + } + } + if (canBatchPath && isLast) { + flushPathDrawn(ctx, scope); + } + el.innerAfterBrush(); + el.afterBrush && el.afterBrush(); + scope.prevEl = el; + el.__dirty = 0; + el.__isRendered = true; + } + function brushIncremental(ctx, el, scope) { + var displayables = el.getDisplayables(); + var temporalDisplayables = el.getTemporalDisplayables(); + ctx.save(); + var innerScope = { + prevElClipPaths: null, + prevEl: null, + allClipped: false, + viewWidth: scope.viewWidth, + viewHeight: scope.viewHeight, + inHover: scope.inHover + }; + var i; + var len; + for (i = el.getCursor(), len = displayables.length; i < len; i++) { + var displayable = displayables[i]; + displayable.beforeBrush && displayable.beforeBrush(); + displayable.innerBeforeBrush(); + brush(ctx, displayable, innerScope, i === len - 1); + displayable.innerAfterBrush(); + displayable.afterBrush && displayable.afterBrush(); + innerScope.prevEl = displayable; + } + for (var i_1 = 0, len_1 = temporalDisplayables.length; i_1 < len_1; i_1++) { + var displayable = temporalDisplayables[i_1]; + displayable.beforeBrush && displayable.beforeBrush(); + displayable.innerBeforeBrush(); + brush(ctx, displayable, innerScope, i_1 === len_1 - 1); + displayable.innerAfterBrush(); + displayable.afterBrush && displayable.afterBrush(); + innerScope.prevEl = displayable; + } + el.clearTemporalDisplayables(); + el.notClear = true; + ctx.restore(); + } + + var decalMap = new WeakMap(); + var decalCache = new LRU(100); + var decalKeys = ['symbol', 'symbolSize', 'symbolKeepAspect', 'color', 'backgroundColor', 'dashArrayX', 'dashArrayY', 'maxTileWidth', 'maxTileHeight']; + /** + * Create or update pattern image from decal options + * + * @param {InnerDecalObject | 'none'} decalObject decal options, 'none' if no decal + * @return {Pattern} pattern with generated image, null if no decal + */ + + function createOrUpdatePatternFromDecal(decalObject, api) { + if (decalObject === 'none') { + return null; + } + + var dpr = api.getDevicePixelRatio(); + var zr = api.getZr(); + var isSVG = zr.painter.type === 'svg'; + + if (decalObject.dirty) { + decalMap["delete"](decalObject); + } + + var oldPattern = decalMap.get(decalObject); + + if (oldPattern) { + return oldPattern; + } + + var decalOpt = defaults(decalObject, { + symbol: 'rect', + symbolSize: 1, + symbolKeepAspect: true, + color: 'rgba(0, 0, 0, 0.2)', + backgroundColor: null, + dashArrayX: 5, + dashArrayY: 5, + rotation: 0, + maxTileWidth: 512, + maxTileHeight: 512 + }); + + if (decalOpt.backgroundColor === 'none') { + decalOpt.backgroundColor = null; + } + + var pattern = { + repeat: 'repeat' + }; + setPatternnSource(pattern); + pattern.rotation = decalOpt.rotation; + pattern.scaleX = pattern.scaleY = isSVG ? 1 : 1 / dpr; + decalMap.set(decalObject, pattern); + decalObject.dirty = false; + return pattern; + + function setPatternnSource(pattern) { + var keys = [dpr]; + var isValidKey = true; + + for (var i = 0; i < decalKeys.length; ++i) { + var value = decalOpt[decalKeys[i]]; + + if (value != null && !isArray(value) && !isString(value) && !isNumber(value) && typeof value !== 'boolean') { + isValidKey = false; + break; + } + + keys.push(value); + } + + var cacheKey; + + if (isValidKey) { + cacheKey = keys.join(',') + (isSVG ? '-svg' : ''); + var cache = decalCache.get(cacheKey); + + if (cache) { + isSVG ? pattern.svgElement = cache : pattern.image = cache; + } + } + + var dashArrayX = normalizeDashArrayX(decalOpt.dashArrayX); + var dashArrayY = normalizeDashArrayY(decalOpt.dashArrayY); + var symbolArray = normalizeSymbolArray(decalOpt.symbol); + var lineBlockLengthsX = getLineBlockLengthX(dashArrayX); + var lineBlockLengthY = getLineBlockLengthY(dashArrayY); + var canvas = !isSVG && platformApi.createCanvas(); + var svgRoot = isSVG && { + tag: 'g', + attrs: {}, + key: 'dcl', + children: [] + }; + var pSize = getPatternSize(); + var ctx; + + if (canvas) { + canvas.width = pSize.width * dpr; + canvas.height = pSize.height * dpr; + ctx = canvas.getContext('2d'); + } + + brushDecal(); + + if (isValidKey) { + decalCache.put(cacheKey, canvas || svgRoot); + } + + pattern.image = canvas; + pattern.svgElement = svgRoot; + pattern.svgWidth = pSize.width; + pattern.svgHeight = pSize.height; + /** + * Get minumum length that can make a repeatable pattern. + * + * @return {Object} pattern width and height + */ + + function getPatternSize() { + /** + * For example, if dash is [[3, 2], [2, 1]] for X, it looks like + * |--- --- --- --- --- ... + * |-- -- -- -- -- -- -- -- ... + * |--- --- --- --- --- ... + * |-- -- -- -- -- -- -- -- ... + * So the minumum length of X is 15, + * which is the least common multiple of `3 + 2` and `2 + 1` + * |--- --- --- |--- --- ... + * |-- -- -- -- -- |-- -- -- ... + */ + var width = 1; + + for (var i = 0, xlen = lineBlockLengthsX.length; i < xlen; ++i) { + width = getLeastCommonMultiple(width, lineBlockLengthsX[i]); + } + + var symbolRepeats = 1; + + for (var i = 0, xlen = symbolArray.length; i < xlen; ++i) { + symbolRepeats = getLeastCommonMultiple(symbolRepeats, symbolArray[i].length); + } + + width *= symbolRepeats; + var height = lineBlockLengthY * lineBlockLengthsX.length * symbolArray.length; + + if ("development" !== 'production') { + var warn = function (attrName) { + /* eslint-disable-next-line */ + console.warn("Calculated decal size is greater than " + attrName + " due to decal option settings so " + attrName + " is used for the decal size. Please consider changing the decal option to make a smaller decal or set " + attrName + " to be larger to avoid incontinuity."); + }; + + if (width > decalOpt.maxTileWidth) { + warn('maxTileWidth'); + } + + if (height > decalOpt.maxTileHeight) { + warn('maxTileHeight'); + } + } + + return { + width: Math.max(1, Math.min(width, decalOpt.maxTileWidth)), + height: Math.max(1, Math.min(height, decalOpt.maxTileHeight)) + }; + } + + function brushDecal() { + if (ctx) { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + if (decalOpt.backgroundColor) { + ctx.fillStyle = decalOpt.backgroundColor; + ctx.fillRect(0, 0, canvas.width, canvas.height); + } + } + + var ySum = 0; + + for (var i = 0; i < dashArrayY.length; ++i) { + ySum += dashArrayY[i]; + } + + if (ySum <= 0) { + // dashArrayY is 0, draw nothing + return; + } + + var y = -lineBlockLengthY; + var yId = 0; + var yIdTotal = 0; + var xId0 = 0; + + while (y < pSize.height) { + if (yId % 2 === 0) { + var symbolYId = yIdTotal / 2 % symbolArray.length; + var x = 0; + var xId1 = 0; + var xId1Total = 0; + + while (x < pSize.width * 2) { + var xSum = 0; + + for (var i = 0; i < dashArrayX[xId0].length; ++i) { + xSum += dashArrayX[xId0][i]; + } + + if (xSum <= 0) { + // Skip empty line + break; + } // E.g., [15, 5, 20, 5] draws only for 15 and 20 + + + if (xId1 % 2 === 0) { + var size = (1 - decalOpt.symbolSize) * 0.5; + var left = x + dashArrayX[xId0][xId1] * size; + var top_1 = y + dashArrayY[yId] * size; + var width = dashArrayX[xId0][xId1] * decalOpt.symbolSize; + var height = dashArrayY[yId] * decalOpt.symbolSize; + var symbolXId = xId1Total / 2 % symbolArray[symbolYId].length; + brushSymbol(left, top_1, width, height, symbolArray[symbolYId][symbolXId]); + } + + x += dashArrayX[xId0][xId1]; + ++xId1Total; + ++xId1; + + if (xId1 === dashArrayX[xId0].length) { + xId1 = 0; + } + } + + ++xId0; + + if (xId0 === dashArrayX.length) { + xId0 = 0; + } + } + + y += dashArrayY[yId]; + ++yIdTotal; + ++yId; + + if (yId === dashArrayY.length) { + yId = 0; + } + } + + function brushSymbol(x, y, width, height, symbolType) { + var scale = isSVG ? 1 : dpr; + var symbol = createSymbol(symbolType, x * scale, y * scale, width * scale, height * scale, decalOpt.color, decalOpt.symbolKeepAspect); + + if (isSVG) { + var symbolVNode = zr.painter.renderOneToVNode(symbol); + + if (symbolVNode) { + svgRoot.children.push(symbolVNode); + } + } else { + // Paint to canvas for all other renderers. + brushSingle(ctx, symbol); + } + } + } + } + } + /** + * Convert symbol array into normalized array + * + * @param {string | (string | string[])[]} symbol symbol input + * @return {string[][]} normolized symbol array + */ + + function normalizeSymbolArray(symbol) { + if (!symbol || symbol.length === 0) { + return [['rect']]; + } + + if (isString(symbol)) { + return [[symbol]]; + } + + var isAllString = true; + + for (var i = 0; i < symbol.length; ++i) { + if (!isString(symbol[i])) { + isAllString = false; + break; + } + } + + if (isAllString) { + return normalizeSymbolArray([symbol]); + } + + var result = []; + + for (var i = 0; i < symbol.length; ++i) { + if (isString(symbol[i])) { + result.push([symbol[i]]); + } else { + result.push(symbol[i]); + } + } + + return result; + } + /** + * Convert dash input into dashArray + * + * @param {DecalDashArrayX} dash dash input + * @return {number[][]} normolized dash array + */ + + + function normalizeDashArrayX(dash) { + if (!dash || dash.length === 0) { + return [[0, 0]]; + } + + if (isNumber(dash)) { + var dashValue = Math.ceil(dash); + return [[dashValue, dashValue]]; + } + /** + * [20, 5] should be normalized into [[20, 5]], + * while [20, [5, 10]] should be normalized into [[20, 20], [5, 10]] + */ + + + var isAllNumber = true; + + for (var i = 0; i < dash.length; ++i) { + if (!isNumber(dash[i])) { + isAllNumber = false; + break; + } + } + + if (isAllNumber) { + return normalizeDashArrayX([dash]); + } + + var result = []; + + for (var i = 0; i < dash.length; ++i) { + if (isNumber(dash[i])) { + var dashValue = Math.ceil(dash[i]); + result.push([dashValue, dashValue]); + } else { + var dashValue = map(dash[i], function (n) { + return Math.ceil(n); + }); + + if (dashValue.length % 2 === 1) { + // [4, 2, 1] means |---- - -- |---- - -- | + // so normalize it to be [4, 2, 1, 4, 2, 1] + result.push(dashValue.concat(dashValue)); + } else { + result.push(dashValue); + } + } + } + + return result; + } + /** + * Convert dash input into dashArray + * + * @param {DecalDashArrayY} dash dash input + * @return {number[]} normolized dash array + */ + + + function normalizeDashArrayY(dash) { + if (!dash || typeof dash === 'object' && dash.length === 0) { + return [0, 0]; + } + + if (isNumber(dash)) { + var dashValue_1 = Math.ceil(dash); + return [dashValue_1, dashValue_1]; + } + + var dashValue = map(dash, function (n) { + return Math.ceil(n); + }); + return dash.length % 2 ? dashValue.concat(dashValue) : dashValue; + } + /** + * Get block length of each line. A block is the length of dash line and space. + * For example, a line with [4, 1] has a dash line of 4 and a space of 1 after + * that, so the block length of this line is 5. + * + * @param {number[][]} dash dash arrary of X or Y + * @return {number[]} block length of each line + */ + + + function getLineBlockLengthX(dash) { + return map(dash, function (line) { + return getLineBlockLengthY(line); + }); + } + + function getLineBlockLengthY(dash) { + var blockLength = 0; + + for (var i = 0; i < dash.length; ++i) { + blockLength += dash[i]; + } + + if (dash.length % 2 === 1) { + // [4, 2, 1] means |---- - -- |---- - -- | + // So total length is (4 + 2 + 1) * 2 + return blockLength * 2; + } + + return blockLength; + } + + function decalVisual(ecModel, api) { + ecModel.eachRawSeries(function (seriesModel) { + if (ecModel.isSeriesFiltered(seriesModel)) { + return; + } + + var data = seriesModel.getData(); + + if (data.hasItemVisual()) { + data.each(function (idx) { + var decal = data.getItemVisual(idx, 'decal'); + + if (decal) { + var itemStyle = data.ensureUniqueItemVisual(idx, 'style'); + itemStyle.decal = createOrUpdatePatternFromDecal(decal, api); + } + }); + } + + var decal = data.getVisual('decal'); + + if (decal) { + var style = data.getVisual('style'); + style.decal = createOrUpdatePatternFromDecal(decal, api); + } + }); + } + + var lifecycle = new Eventful(); + + // The implentations will be registered when installing the component. + // Avoid these code being bundled to the core module. + + var implsStore = {}; // TODO Type + + function registerImpl(name, impl) { + if ("development" !== 'production') { + if (implsStore[name]) { + error("Already has an implementation of " + name + "."); + } + } + + implsStore[name] = impl; + } + function getImpl(name) { + if ("development" !== 'production') { + if (!implsStore[name]) { + error("Implementation of " + name + " doesn't exists."); + } + } + + return implsStore[name]; + } + + var hasWindow = typeof window !== 'undefined'; + var version$1 = '5.3.2'; + var dependencies = { + zrender: '5.3.1' + }; + var TEST_FRAME_REMAIN_TIME = 1; + var PRIORITY_PROCESSOR_SERIES_FILTER = 800; // Some data processors depends on the stack result dimension (to calculate data extent). + // So data stack stage should be in front of data processing stage. + + var PRIORITY_PROCESSOR_DATASTACK = 900; // "Data filter" will block the stream, so it should be + // put at the begining of data processing. + + var PRIORITY_PROCESSOR_FILTER = 1000; + var PRIORITY_PROCESSOR_DEFAULT = 2000; + var PRIORITY_PROCESSOR_STATISTIC = 5000; + var PRIORITY_VISUAL_LAYOUT = 1000; + var PRIORITY_VISUAL_PROGRESSIVE_LAYOUT = 1100; + var PRIORITY_VISUAL_GLOBAL = 2000; + var PRIORITY_VISUAL_CHART = 3000; + var PRIORITY_VISUAL_COMPONENT = 4000; // Visual property in data. Greater than `PRIORITY_VISUAL_COMPONENT` to enable to + // overwrite the viusal result of component (like `visualMap`) + // using data item specific setting (like itemStyle.xxx on data item) + + var PRIORITY_VISUAL_CHART_DATA_CUSTOM = 4500; // Greater than `PRIORITY_VISUAL_CHART_DATA_CUSTOM` to enable to layout based on + // visual result like `symbolSize`. + + var PRIORITY_VISUAL_POST_CHART_LAYOUT = 4600; + var PRIORITY_VISUAL_BRUSH = 5000; + var PRIORITY_VISUAL_ARIA = 6000; + var PRIORITY_VISUAL_DECAL = 7000; + var PRIORITY = { + PROCESSOR: { + FILTER: PRIORITY_PROCESSOR_FILTER, + SERIES_FILTER: PRIORITY_PROCESSOR_SERIES_FILTER, + STATISTIC: PRIORITY_PROCESSOR_STATISTIC + }, + VISUAL: { + LAYOUT: PRIORITY_VISUAL_LAYOUT, + PROGRESSIVE_LAYOUT: PRIORITY_VISUAL_PROGRESSIVE_LAYOUT, + GLOBAL: PRIORITY_VISUAL_GLOBAL, + CHART: PRIORITY_VISUAL_CHART, + POST_CHART_LAYOUT: PRIORITY_VISUAL_POST_CHART_LAYOUT, + COMPONENT: PRIORITY_VISUAL_COMPONENT, + BRUSH: PRIORITY_VISUAL_BRUSH, + CHART_ITEM: PRIORITY_VISUAL_CHART_DATA_CUSTOM, + ARIA: PRIORITY_VISUAL_ARIA, + DECAL: PRIORITY_VISUAL_DECAL + } + }; // Main process have three entries: `setOption`, `dispatchAction` and `resize`, + // where they must not be invoked nestedly, except the only case: invoke + // dispatchAction with updateMethod "none" in main process. + // This flag is used to carry out this rule. + // All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]). + + var IN_MAIN_PROCESS_KEY = '__flagInMainProcess'; + var PENDING_UPDATE = '__pendingUpdate'; + var STATUS_NEEDS_UPDATE_KEY = '__needsUpdateStatus'; + var ACTION_REG = /^[a-zA-Z0-9_]+$/; + var CONNECT_STATUS_KEY = '__connectUpdateStatus'; + var CONNECT_STATUS_PENDING = 0; + var CONNECT_STATUS_UPDATING = 1; + var CONNECT_STATUS_UPDATED = 2; + + function createRegisterEventWithLowercaseECharts(method) { + return function () { + var args = []; + + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + + if (this.isDisposed()) { + disposedWarning(this.id); + return; + } + + return toLowercaseNameAndCallEventful(this, method, args); + }; + } + + function createRegisterEventWithLowercaseMessageCenter(method) { + return function () { + var args = []; + + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + + return toLowercaseNameAndCallEventful(this, method, args); + }; + } + + function toLowercaseNameAndCallEventful(host, method, args) { + // `args[0]` is event name. Event name is all lowercase. + args[0] = args[0] && args[0].toLowerCase(); + return Eventful.prototype[method].apply(host, args); + } + + var MessageCenter = + /** @class */ + function (_super) { + __extends(MessageCenter, _super); + + function MessageCenter() { + return _super !== null && _super.apply(this, arguments) || this; + } + + return MessageCenter; + }(Eventful); + + var messageCenterProto = MessageCenter.prototype; + messageCenterProto.on = createRegisterEventWithLowercaseMessageCenter('on'); + messageCenterProto.off = createRegisterEventWithLowercaseMessageCenter('off'); // --------------------------------------- + // Internal method names for class ECharts + // --------------------------------------- + + var prepare; + var prepareView; + var updateDirectly; + var updateMethods; + var doConvertPixel; + var updateStreamModes; + var doDispatchAction; + var flushPendingActions; + var triggerUpdatedEvent; + var bindRenderedEvent; + var bindMouseEvent; + var render; + var renderComponents; + var renderSeries; + var createExtensionAPI; + var enableConnect; + var markStatusToUpdate; + var applyChangedStates; + + var ECharts = + /** @class */ + function (_super) { + __extends(ECharts, _super); + + function ECharts(dom, // Theme name or themeOption. + theme, opts) { + var _this = _super.call(this, new ECEventProcessor()) || this; + + _this._chartsViews = []; + _this._chartsMap = {}; + _this._componentsViews = []; + _this._componentsMap = {}; // Can't dispatch action during rendering procedure + + _this._pendingActions = []; + opts = opts || {}; // Get theme by name + + if (isString(theme)) { + theme = themeStorage[theme]; + } + + _this._dom = dom; + var defaultRenderer = 'canvas'; + var defaultUseDirtyRect = false; + + if ("development" !== 'production') { + var root = + /* eslint-disable-next-line */ + hasWindow ? window : global; + defaultRenderer = root.__ECHARTS__DEFAULT__RENDERER__ || defaultRenderer; + var devUseDirtyRect = root.__ECHARTS__DEFAULT__USE_DIRTY_RECT__; + defaultUseDirtyRect = devUseDirtyRect == null ? defaultUseDirtyRect : devUseDirtyRect; + } + + var zr = _this._zr = init(dom, { + renderer: opts.renderer || defaultRenderer, + devicePixelRatio: opts.devicePixelRatio, + width: opts.width, + height: opts.height, + ssr: opts.ssr, + useDirtyRect: opts.useDirtyRect == null ? defaultUseDirtyRect : opts.useDirtyRect + }); + _this._ssr = opts.ssr; // Expect 60 fps. + + _this._throttledZrFlush = throttle(bind(zr.flush, zr), 17); + theme = clone(theme); + theme && globalBackwardCompat(theme, true); + _this._theme = theme; + _this._locale = createLocaleObject(opts.locale || SYSTEM_LANG); + _this._coordSysMgr = new CoordinateSystemManager(); + var api = _this._api = createExtensionAPI(_this); // Sort on demand + + function prioritySortFunc(a, b) { + return a.__prio - b.__prio; + } + + sort(visualFuncs, prioritySortFunc); + sort(dataProcessorFuncs, prioritySortFunc); + _this._scheduler = new Scheduler(_this, api, dataProcessorFuncs, visualFuncs); + _this._messageCenter = new MessageCenter(); // Init mouse events + + _this._initEvents(); // In case some people write `window.onresize = chart.resize` + + + _this.resize = bind(_this.resize, _this); + zr.animation.on('frame', _this._onframe, _this); + bindRenderedEvent(zr, _this); + bindMouseEvent(zr, _this); // ECharts instance can be used as value. + + setAsPrimitive(_this); + return _this; + } + + ECharts.prototype._onframe = function () { + if (this._disposed) { + return; + } + + applyChangedStates(this); + var scheduler = this._scheduler; // Lazy update + + if (this[PENDING_UPDATE]) { + var silent = this[PENDING_UPDATE].silent; + this[IN_MAIN_PROCESS_KEY] = true; + + try { + prepare(this); + updateMethods.update.call(this, null, this[PENDING_UPDATE].updateParams); + } catch (e) { + this[IN_MAIN_PROCESS_KEY] = false; + this[PENDING_UPDATE] = null; + throw e; + } // At present, in each frame, zrender performs: + // (1) animation step forward. + // (2) trigger('frame') (where this `_onframe` is called) + // (3) zrender flush (render). + // If we do nothing here, since we use `setToFinal: true`, the step (3) above + // will render the final state of the elements before the real animation started. + + + this._zr.flush(); + + this[IN_MAIN_PROCESS_KEY] = false; + this[PENDING_UPDATE] = null; + flushPendingActions.call(this, silent); + triggerUpdatedEvent.call(this, silent); + } // Avoid do both lazy update and progress in one frame. + else if (scheduler.unfinished) { + // Stream progress. + var remainTime = TEST_FRAME_REMAIN_TIME; + var ecModel = this._model; + var api = this._api; + scheduler.unfinished = false; + + do { + var startTime = +new Date(); + scheduler.performSeriesTasks(ecModel); // Currently dataProcessorFuncs do not check threshold. + + scheduler.performDataProcessorTasks(ecModel); + updateStreamModes(this, ecModel); // Do not update coordinate system here. Because that coord system update in + // each frame is not a good user experience. So we follow the rule that + // the extent of the coordinate system is determin in the first frame (the + // frame is executed immedietely after task reset. + // this._coordSysMgr.update(ecModel, api); + // console.log('--- ec frame visual ---', remainTime); + + scheduler.performVisualTasks(ecModel); + renderSeries(this, this._model, api, 'remain', {}); + remainTime -= +new Date() - startTime; + } while (remainTime > 0 && scheduler.unfinished); // Call flush explicitly for trigger finished event. + + + if (!scheduler.unfinished) { + this._zr.flush(); + } // Else, zr flushing be ensue within the same frame, + // because zr flushing is after onframe event. + + } + }; + + ECharts.prototype.getDom = function () { + return this._dom; + }; + + ECharts.prototype.getId = function () { + return this.id; + }; + + ECharts.prototype.getZr = function () { + return this._zr; + }; + + ECharts.prototype.isSSR = function () { + return this._ssr; + }; + /* eslint-disable-next-line */ + + + ECharts.prototype.setOption = function (option, notMerge, lazyUpdate) { + if (this[IN_MAIN_PROCESS_KEY]) { + if ("development" !== 'production') { + error('`setOption` should not be called during main process.'); + } + + return; + } + + if (this._disposed) { + disposedWarning(this.id); + return; + } + + var silent; + var replaceMerge; + var transitionOpt; + + if (isObject(notMerge)) { + lazyUpdate = notMerge.lazyUpdate; + silent = notMerge.silent; + replaceMerge = notMerge.replaceMerge; + transitionOpt = notMerge.transition; + notMerge = notMerge.notMerge; + } + + this[IN_MAIN_PROCESS_KEY] = true; + + if (!this._model || notMerge) { + var optionManager = new OptionManager(this._api); + var theme = this._theme; + var ecModel = this._model = new GlobalModel(); + ecModel.scheduler = this._scheduler; + ecModel.ssr = this._ssr; + ecModel.init(null, null, null, theme, this._locale, optionManager); + } + + this._model.setOption(option, { + replaceMerge: replaceMerge + }, optionPreprocessorFuncs); + + var updateParams = { + seriesTransition: transitionOpt, + optionChanged: true + }; + + if (lazyUpdate) { + this[PENDING_UPDATE] = { + silent: silent, + updateParams: updateParams + }; + this[IN_MAIN_PROCESS_KEY] = false; // `setOption(option, {lazyMode: true})` may be called when zrender has been slept. + // It should wake it up to make sure zrender start to render at the next frame. + + this.getZr().wakeUp(); + } else { + try { + prepare(this); + updateMethods.update.call(this, null, updateParams); + } catch (e) { + this[PENDING_UPDATE] = null; + this[IN_MAIN_PROCESS_KEY] = false; + throw e; + } // Ensure zr refresh sychronously, and then pixel in canvas can be + // fetched after `setOption`. + + + if (!this._ssr) { + // not use flush when using ssr mode. + this._zr.flush(); + } + + this[PENDING_UPDATE] = null; + this[IN_MAIN_PROCESS_KEY] = false; + flushPendingActions.call(this, silent); + triggerUpdatedEvent.call(this, silent); + } + }; + /** + * @deprecated + */ + + + ECharts.prototype.setTheme = function () { + deprecateLog('ECharts#setTheme() is DEPRECATED in ECharts 3.0'); + }; // We don't want developers to use getModel directly. + + + ECharts.prototype.getModel = function () { + return this._model; + }; + + ECharts.prototype.getOption = function () { + return this._model && this._model.getOption(); + }; + + ECharts.prototype.getWidth = function () { + return this._zr.getWidth(); + }; + + ECharts.prototype.getHeight = function () { + return this._zr.getHeight(); + }; + + ECharts.prototype.getDevicePixelRatio = function () { + return this._zr.painter.dpr + /* eslint-disable-next-line */ + || hasWindow && window.devicePixelRatio || 1; + }; + /** + * Get canvas which has all thing rendered + * @deprecated Use renderToCanvas instead. + */ + + + ECharts.prototype.getRenderedCanvas = function (opts) { + if ("development" !== 'production') { + deprecateReplaceLog('getRenderedCanvas', 'renderToCanvas'); + } + + return this.renderToCanvas(opts); + }; + + ECharts.prototype.renderToCanvas = function (opts) { + opts = opts || {}; + var painter = this._zr.painter; + + if ("development" !== 'production') { + if (painter.type !== 'canvas') { + throw new Error('renderToCanvas can only be used in the canvas renderer.'); + } + } + + return painter.getRenderedCanvas({ + backgroundColor: opts.backgroundColor || this._model.get('backgroundColor'), + pixelRatio: opts.pixelRatio || this.getDevicePixelRatio() + }); + }; + + ECharts.prototype.renderToSVGString = function (opts) { + opts = opts || {}; + var painter = this._zr.painter; + + if ("development" !== 'production') { + if (painter.type !== 'svg') { + throw new Error('renderToSVGString can only be used in the svg renderer.'); + } + } + + return painter.renderToString({ + useViewBox: opts.useViewBox + }); + }; + /** + * Get svg data url + */ + + + ECharts.prototype.getSvgDataURL = function () { + if (!env.svgSupported) { + return; + } + + var zr = this._zr; + var list = zr.storage.getDisplayList(); // Stop animations + + each(list, function (el) { + el.stopAnimation(null, true); + }); + return zr.painter.toDataURL(); + }; + + ECharts.prototype.getDataURL = function (opts) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + opts = opts || {}; + var excludeComponents = opts.excludeComponents; + var ecModel = this._model; + var excludesComponentViews = []; + var self = this; + each(excludeComponents, function (componentType) { + ecModel.eachComponent({ + mainType: componentType + }, function (component) { + var view = self._componentsMap[component.__viewId]; + + if (!view.group.ignore) { + excludesComponentViews.push(view); + view.group.ignore = true; + } + }); + }); + var url = this._zr.painter.getType() === 'svg' ? this.getSvgDataURL() : this.renderToCanvas(opts).toDataURL('image/' + (opts && opts.type || 'png')); + each(excludesComponentViews, function (view) { + view.group.ignore = false; + }); + return url; + }; + + ECharts.prototype.getConnectedDataURL = function (opts) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + var isSvg = opts.type === 'svg'; + var groupId = this.group; + var mathMin = Math.min; + var mathMax = Math.max; + var MAX_NUMBER = Infinity; + + if (connectedGroups[groupId]) { + var left_1 = MAX_NUMBER; + var top_1 = MAX_NUMBER; + var right_1 = -MAX_NUMBER; + var bottom_1 = -MAX_NUMBER; + var canvasList_1 = []; + var dpr_1 = opts && opts.pixelRatio || this.getDevicePixelRatio(); + each(instances$1, function (chart, id) { + if (chart.group === groupId) { + var canvas = isSvg ? chart.getZr().painter.getSvgDom().innerHTML : chart.renderToCanvas(clone(opts)); + var boundingRect = chart.getDom().getBoundingClientRect(); + left_1 = mathMin(boundingRect.left, left_1); + top_1 = mathMin(boundingRect.top, top_1); + right_1 = mathMax(boundingRect.right, right_1); + bottom_1 = mathMax(boundingRect.bottom, bottom_1); + canvasList_1.push({ + dom: canvas, + left: boundingRect.left, + top: boundingRect.top + }); + } + }); + left_1 *= dpr_1; + top_1 *= dpr_1; + right_1 *= dpr_1; + bottom_1 *= dpr_1; + var width = right_1 - left_1; + var height = bottom_1 - top_1; + var targetCanvas = platformApi.createCanvas(); + var zr_1 = init(targetCanvas, { + renderer: isSvg ? 'svg' : 'canvas' + }); + zr_1.resize({ + width: width, + height: height + }); + + if (isSvg) { + var content_1 = ''; + each(canvasList_1, function (item) { + var x = item.left - left_1; + var y = item.top - top_1; + content_1 += '' + item.dom + ''; + }); + zr_1.painter.getSvgRoot().innerHTML = content_1; + + if (opts.connectedBackgroundColor) { + zr_1.painter.setBackgroundColor(opts.connectedBackgroundColor); + } + + zr_1.refreshImmediately(); + return zr_1.painter.toDataURL(); + } else { + // Background between the charts + if (opts.connectedBackgroundColor) { + zr_1.add(new Rect({ + shape: { + x: 0, + y: 0, + width: width, + height: height + }, + style: { + fill: opts.connectedBackgroundColor + } + })); + } + + each(canvasList_1, function (item) { + var img = new ZRImage({ + style: { + x: item.left * dpr_1 - left_1, + y: item.top * dpr_1 - top_1, + image: item.dom + } + }); + zr_1.add(img); + }); + zr_1.refreshImmediately(); + return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png')); + } + } else { + return this.getDataURL(opts); + } + }; + + ECharts.prototype.convertToPixel = function (finder, value) { + return doConvertPixel(this, 'convertToPixel', finder, value); + }; + + ECharts.prototype.convertFromPixel = function (finder, value) { + return doConvertPixel(this, 'convertFromPixel', finder, value); + }; + /** + * Is the specified coordinate systems or components contain the given pixel point. + * @param {Array|number} value + * @return {boolean} result + */ + + + ECharts.prototype.containPixel = function (finder, value) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + var ecModel = this._model; + var result; + var findResult = parseFinder(ecModel, finder); + each(findResult, function (models, key) { + key.indexOf('Models') >= 0 && each(models, function (model) { + var coordSys = model.coordinateSystem; + + if (coordSys && coordSys.containPoint) { + result = result || !!coordSys.containPoint(value); + } else if (key === 'seriesModels') { + var view = this._chartsMap[model.__viewId]; + + if (view && view.containPoint) { + result = result || view.containPoint(value, model); + } else { + if ("development" !== 'production') { + console.warn(key + ': ' + (view ? 'The found component do not support containPoint.' : 'No view mapping to the found component.')); + } + } + } else { + if ("development" !== 'production') { + console.warn(key + ': containPoint is not supported'); + } + } + }, this); + }, this); + return !!result; + }; + /** + * Get visual from series or data. + * @param finder + * If string, e.g., 'series', means {seriesIndex: 0}. + * If Object, could contain some of these properties below: + * { + * seriesIndex / seriesId / seriesName, + * dataIndex / dataIndexInside + * } + * If dataIndex is not specified, series visual will be fetched, + * but not data item visual. + * If all of seriesIndex, seriesId, seriesName are not specified, + * visual will be fetched from first series. + * @param visualType 'color', 'symbol', 'symbolSize' + */ + + + ECharts.prototype.getVisual = function (finder, visualType) { + var ecModel = this._model; + var parsedFinder = parseFinder(ecModel, finder, { + defaultMainType: 'series' + }); + var seriesModel = parsedFinder.seriesModel; + + if ("development" !== 'production') { + if (!seriesModel) { + console.warn('There is no specified seires model'); + } + } + + var data = seriesModel.getData(); + var dataIndexInside = parsedFinder.hasOwnProperty('dataIndexInside') ? parsedFinder.dataIndexInside : parsedFinder.hasOwnProperty('dataIndex') ? data.indexOfRawIndex(parsedFinder.dataIndex) : null; + return dataIndexInside != null ? getItemVisualFromData(data, dataIndexInside, visualType) : getVisualFromData(data, visualType); + }; + /** + * Get view of corresponding component model + */ + + + ECharts.prototype.getViewOfComponentModel = function (componentModel) { + return this._componentsMap[componentModel.__viewId]; + }; + /** + * Get view of corresponding series model + */ + + + ECharts.prototype.getViewOfSeriesModel = function (seriesModel) { + return this._chartsMap[seriesModel.__viewId]; + }; + + ECharts.prototype._initEvents = function () { + var _this = this; + + each(MOUSE_EVENT_NAMES, function (eveName) { + var handler = function (e) { + var ecModel = _this.getModel(); + + var el = e.target; + var params; + var isGlobalOut = eveName === 'globalout'; // no e.target when 'globalout'. + + if (isGlobalOut) { + params = {}; + } else { + el && findEventDispatcher(el, function (parent) { + var ecData = getECData(parent); + + if (ecData && ecData.dataIndex != null) { + var dataModel = ecData.dataModel || ecModel.getSeriesByIndex(ecData.seriesIndex); + params = dataModel && dataModel.getDataParams(ecData.dataIndex, ecData.dataType) || {}; + return true; + } // If element has custom eventData of components + else if (ecData.eventData) { + params = extend({}, ecData.eventData); + return true; + } + }, true); + } // Contract: if params prepared in mouse event, + // these properties must be specified: + // { + // componentType: string (component main type) + // componentIndex: number + // } + // Otherwise event query can not work. + + + if (params) { + var componentType = params.componentType; + var componentIndex = params.componentIndex; // Special handling for historic reason: when trigger by + // markLine/markPoint/markArea, the componentType is + // 'markLine'/'markPoint'/'markArea', but we should better + // enable them to be queried by seriesIndex, since their + // option is set in each series. + + if (componentType === 'markLine' || componentType === 'markPoint' || componentType === 'markArea') { + componentType = 'series'; + componentIndex = params.seriesIndex; + } + + var model = componentType && componentIndex != null && ecModel.getComponent(componentType, componentIndex); + var view = model && _this[model.mainType === 'series' ? '_chartsMap' : '_componentsMap'][model.__viewId]; + + if ("development" !== 'production') { + // `event.componentType` and `event[componentTpype + 'Index']` must not + // be missed, otherwise there is no way to distinguish source component. + // See `dataFormat.getDataParams`. + if (!isGlobalOut && !(model && view)) { + console.warn('model or view can not be found by params'); + } + } + + params.event = e; + params.type = eveName; + _this._$eventProcessor.eventInfo = { + targetEl: el, + packedEvent: params, + model: model, + view: view + }; + + _this.trigger(eveName, params); + } + }; // Consider that some component (like tooltip, brush, ...) + // register zr event handler, but user event handler might + // do anything, such as call `setOption` or `dispatchAction`, + // which probably update any of the content and probably + // cause problem if it is called previous other inner handlers. + + + handler.zrEventfulCallAtLast = true; + + _this._zr.on(eveName, handler, _this); + }); + each(eventActionMap, function (actionType, eventType) { + _this._messageCenter.on(eventType, function (event) { + this.trigger(eventType, event); + }, _this); + }); // Extra events + // TODO register? + + each(['selectchanged'], function (eventType) { + _this._messageCenter.on(eventType, function (event) { + this.trigger(eventType, event); + }, _this); + }); + handleLegacySelectEvents(this._messageCenter, this, this._api); + }; + + ECharts.prototype.isDisposed = function () { + return this._disposed; + }; + + ECharts.prototype.clear = function () { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + this.setOption({ + series: [] + }, true); + }; + + ECharts.prototype.dispose = function () { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + this._disposed = true; + var dom = this.getDom(); + + if (dom) { + setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, ''); + } + + var chart = this; + var api = chart._api; + var ecModel = chart._model; + each(chart._componentsViews, function (component) { + component.dispose(ecModel, api); + }); + each(chart._chartsViews, function (chart) { + chart.dispose(ecModel, api); + }); // Dispose after all views disposed + + chart._zr.dispose(); // Set properties to null. + // To reduce the memory cost in case the top code still holds this instance unexpectedly. + + + chart._dom = chart._model = chart._chartsMap = chart._componentsMap = chart._chartsViews = chart._componentsViews = chart._scheduler = chart._api = chart._zr = chart._throttledZrFlush = chart._theme = chart._coordSysMgr = chart._messageCenter = null; + delete instances$1[chart.id]; + }; + /** + * Resize the chart + */ + + + ECharts.prototype.resize = function (opts) { + if (this[IN_MAIN_PROCESS_KEY]) { + if ("development" !== 'production') { + error('`resize` should not be called during main process.'); + } + + return; + } + + if (this._disposed) { + disposedWarning(this.id); + return; + } + + this._zr.resize(opts); + + var ecModel = this._model; // Resize loading effect + + this._loadingFX && this._loadingFX.resize(); + + if (!ecModel) { + return; + } + + var needPrepare = ecModel.resetOption('media'); + var silent = opts && opts.silent; // There is some real cases that: + // chart.setOption(option, { lazyUpdate: true }); + // chart.resize(); + + if (this[PENDING_UPDATE]) { + if (silent == null) { + silent = this[PENDING_UPDATE].silent; + } + + needPrepare = true; + this[PENDING_UPDATE] = null; + } + + this[IN_MAIN_PROCESS_KEY] = true; + + try { + needPrepare && prepare(this); + updateMethods.update.call(this, { + type: 'resize', + animation: extend({ + // Disable animation + duration: 0 + }, opts && opts.animation) + }); + } catch (e) { + this[IN_MAIN_PROCESS_KEY] = false; + throw e; + } + + this[IN_MAIN_PROCESS_KEY] = false; + flushPendingActions.call(this, silent); + triggerUpdatedEvent.call(this, silent); + }; + + ECharts.prototype.showLoading = function (name, cfg) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + if (isObject(name)) { + cfg = name; + name = ''; + } + + name = name || 'default'; + this.hideLoading(); + + if (!loadingEffects[name]) { + if ("development" !== 'production') { + console.warn('Loading effects ' + name + ' not exists.'); + } + + return; + } + + var el = loadingEffects[name](this._api, cfg); + var zr = this._zr; + this._loadingFX = el; + zr.add(el); + }; + /** + * Hide loading effect + */ + + + ECharts.prototype.hideLoading = function () { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + this._loadingFX && this._zr.remove(this._loadingFX); + this._loadingFX = null; + }; + + ECharts.prototype.makeActionFromEvent = function (eventObj) { + var payload = extend({}, eventObj); + payload.type = eventActionMap[eventObj.type]; + return payload; + }; + /** + * @param opt If pass boolean, means opt.silent + * @param opt.silent Default `false`. Whether trigger events. + * @param opt.flush Default `undefined`. + * true: Flush immediately, and then pixel in canvas can be fetched + * immediately. Caution: it might affect performance. + * false: Not flush. + * undefined: Auto decide whether perform flush. + */ + + + ECharts.prototype.dispatchAction = function (payload, opt) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + if (!isObject(opt)) { + opt = { + silent: !!opt + }; + } + + if (!actions[payload.type]) { + return; + } // Avoid dispatch action before setOption. Especially in `connect`. + + + if (!this._model) { + return; + } // May dispatchAction in rendering procedure + + + if (this[IN_MAIN_PROCESS_KEY]) { + this._pendingActions.push(payload); + + return; + } + + var silent = opt.silent; + doDispatchAction.call(this, payload, silent); + var flush = opt.flush; + + if (flush) { + this._zr.flush(); + } else if (flush !== false && env.browser.weChat) { + // In WeChat embeded browser, `requestAnimationFrame` and `setInterval` + // hang when sliding page (on touch event), which cause that zr does not + // refresh util user interaction finished, which is not expected. + // But `dispatchAction` may be called too frequently when pan on touch + // screen, which impacts performance if do not throttle them. + this._throttledZrFlush(); + } + + flushPendingActions.call(this, silent); + triggerUpdatedEvent.call(this, silent); + }; + + ECharts.prototype.updateLabelLayout = function () { + lifecycle.trigger('series:layoutlabels', this._model, this._api, { + // Not adding series labels. + // TODO + updatedSeries: [] + }); + }; + + ECharts.prototype.appendData = function (params) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + var seriesIndex = params.seriesIndex; + var ecModel = this.getModel(); + var seriesModel = ecModel.getSeriesByIndex(seriesIndex); + + if ("development" !== 'production') { + assert(params.data && seriesModel); + } + + seriesModel.appendData(params); // Note: `appendData` does not support that update extent of coordinate + // system, util some scenario require that. In the expected usage of + // `appendData`, the initial extent of coordinate system should better + // be fixed by axis `min`/`max` setting or initial data, otherwise if + // the extent changed while `appendData`, the location of the painted + // graphic elements have to be changed, which make the usage of + // `appendData` meaningless. + + this._scheduler.unfinished = true; + this.getZr().wakeUp(); + }; // A work around for no `internal` modifier in ts yet but + // need to strictly hide private methods to JS users. + + + ECharts.internalField = function () { + prepare = function (ecIns) { + var scheduler = ecIns._scheduler; + scheduler.restorePipelines(ecIns._model); + scheduler.prepareStageTasks(); + prepareView(ecIns, true); + prepareView(ecIns, false); + scheduler.plan(); + }; + /** + * Prepare view instances of charts and components + */ + + + prepareView = function (ecIns, isComponent) { + var ecModel = ecIns._model; + var scheduler = ecIns._scheduler; + var viewList = isComponent ? ecIns._componentsViews : ecIns._chartsViews; + var viewMap = isComponent ? ecIns._componentsMap : ecIns._chartsMap; + var zr = ecIns._zr; + var api = ecIns._api; + + for (var i = 0; i < viewList.length; i++) { + viewList[i].__alive = false; + } + + isComponent ? ecModel.eachComponent(function (componentType, model) { + componentType !== 'series' && doPrepare(model); + }) : ecModel.eachSeries(doPrepare); + + function doPrepare(model) { + // By defaut view will be reused if possible for the case that `setOption` with "notMerge" + // mode and need to enable transition animation. (Usually, when they have the same id, or + // especially no id but have the same type & name & index. See the `model.id` generation + // rule in `makeIdAndName` and `viewId` generation rule here). + // But in `replaceMerge` mode, this feature should be able to disabled when it is clear that + // the new model has nothing to do with the old model. + var requireNewView = model.__requireNewView; // This command should not work twice. + + model.__requireNewView = false; // Consider: id same and type changed. + + var viewId = '_ec_' + model.id + '_' + model.type; + var view = !requireNewView && viewMap[viewId]; + + if (!view) { + var classType = parseClassType(model.type); + var Clazz = isComponent ? ComponentView.getClass(classType.main, classType.sub) : // FIXME:TS + // (ChartView as ChartViewConstructor).getClass('series', classType.sub) + // For backward compat, still support a chart type declared as only subType + // like "liquidfill", but recommend "series.liquidfill" + // But need a base class to make a type series. + ChartView.getClass(classType.sub); + + if ("development" !== 'production') { + assert(Clazz, classType.sub + ' does not exist.'); + } + + view = new Clazz(); + view.init(ecModel, api); + viewMap[viewId] = view; + viewList.push(view); + zr.add(view.group); + } + + model.__viewId = view.__id = viewId; + view.__alive = true; + view.__model = model; + view.group.__ecComponentInfo = { + mainType: model.mainType, + index: model.componentIndex + }; + !isComponent && scheduler.prepareView(view, model, ecModel, api); + } + + for (var i = 0; i < viewList.length;) { + var view = viewList[i]; + + if (!view.__alive) { + !isComponent && view.renderTask.dispose(); + zr.remove(view.group); + view.dispose(ecModel, api); + viewList.splice(i, 1); + + if (viewMap[view.__id] === view) { + delete viewMap[view.__id]; + } + + view.__id = view.group.__ecComponentInfo = null; + } else { + i++; + } + } + }; + + updateDirectly = function (ecIns, method, payload, mainType, subType) { + var ecModel = ecIns._model; + ecModel.setUpdatePayload(payload); // broadcast + + if (!mainType) { + // FIXME + // Chart will not be update directly here, except set dirty. + // But there is no such scenario now. + each([].concat(ecIns._componentsViews).concat(ecIns._chartsViews), callView); + return; + } + + var query = {}; + query[mainType + 'Id'] = payload[mainType + 'Id']; + query[mainType + 'Index'] = payload[mainType + 'Index']; + query[mainType + 'Name'] = payload[mainType + 'Name']; + var condition = { + mainType: mainType, + query: query + }; + subType && (condition.subType = subType); // subType may be '' by parseClassType; + + var excludeSeriesId = payload.excludeSeriesId; + var excludeSeriesIdMap; + + if (excludeSeriesId != null) { + excludeSeriesIdMap = createHashMap(); + each(normalizeToArray(excludeSeriesId), function (id) { + var modelId = convertOptionIdName(id, null); + + if (modelId != null) { + excludeSeriesIdMap.set(modelId, true); + } + }); + } // If dispatchAction before setOption, do nothing. + + + ecModel && ecModel.eachComponent(condition, function (model) { + var isExcluded = excludeSeriesIdMap && excludeSeriesIdMap.get(model.id) !== null; + + if (isExcluded) { + return; + } + + if (isHighDownPayload(payload)) { + if (model instanceof SeriesModel) { + if (payload.type === HIGHLIGHT_ACTION_TYPE && !payload.notBlur && !model.get(['emphasis', 'disabled'])) { + blurSeriesFromHighlightPayload(model, payload, ecIns._api); + } + } else { + var _a = findComponentHighDownDispatchers(model.mainType, model.componentIndex, payload.name, ecIns._api), + focusSelf = _a.focusSelf, + dispatchers = _a.dispatchers; + + if (payload.type === HIGHLIGHT_ACTION_TYPE && focusSelf && !payload.notBlur) { + blurComponent(model.mainType, model.componentIndex, ecIns._api); + } // PENDING: + // Whether to put this "enter emphasis" code in `ComponentView`, + // which will be the same as `ChartView` but might be not necessary + // and will be far from this logic. + + + if (dispatchers) { + each(dispatchers, function (dispatcher) { + payload.type === HIGHLIGHT_ACTION_TYPE ? enterEmphasis(dispatcher) : leaveEmphasis(dispatcher); + }); + } + } + } else if (isSelectChangePayload(payload)) { + // TODO geo + if (model instanceof SeriesModel) { + toggleSelectionFromPayload(model, payload, ecIns._api); + updateSeriesElementSelection(model); + markStatusToUpdate(ecIns); + } + } + }, ecIns); + ecModel && ecModel.eachComponent(condition, function (model) { + var isExcluded = excludeSeriesIdMap && excludeSeriesIdMap.get(model.id) !== null; + + if (isExcluded) { + return; + } + callView(ecIns[mainType === 'series' ? '_chartsMap' : '_componentsMap'][model.__viewId]); + }, ecIns); + + function callView(view) { + view && view.__alive && view[method] && view[method](view.__model, ecModel, ecIns._api, payload); + } + }; + + updateMethods = { + prepareAndUpdate: function (payload) { + prepare(this); + updateMethods.update.call(this, payload, { + // Needs to mark option changed if newOption is given. + // It's from MagicType. + // TODO If use a separate flag optionChanged in payload? + optionChanged: payload.newOption != null + }); + }, + update: function (payload, updateParams) { + var ecModel = this._model; + var api = this._api; + var zr = this._zr; + var coordSysMgr = this._coordSysMgr; + var scheduler = this._scheduler; // update before setOption + + if (!ecModel) { + return; + } + + ecModel.setUpdatePayload(payload); + scheduler.restoreData(ecModel, payload); + scheduler.performSeriesTasks(ecModel); // TODO + // Save total ecModel here for undo/redo (after restoring data and before processing data). + // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call. + // Create new coordinate system each update + // In LineView may save the old coordinate system and use it to get the orignal point + + coordSysMgr.create(ecModel, api); + scheduler.performDataProcessorTasks(ecModel, payload); // Current stream render is not supported in data process. So we can update + // stream modes after data processing, where the filtered data is used to + // deteming whether use progressive rendering. + + updateStreamModes(this, ecModel); // We update stream modes before coordinate system updated, then the modes info + // can be fetched when coord sys updating (consider the barGrid extent fix). But + // the drawback is the full coord info can not be fetched. Fortunately this full + // coord is not requied in stream mode updater currently. + + coordSysMgr.update(ecModel, api); + clearColorPalette(ecModel); + scheduler.performVisualTasks(ecModel, payload); + render(this, ecModel, api, payload, updateParams); // Set background + + var backgroundColor = ecModel.get('backgroundColor') || 'transparent'; + var darkMode = ecModel.get('darkMode'); + zr.setBackgroundColor(backgroundColor); // Force set dark mode. + + if (darkMode != null && darkMode !== 'auto') { + zr.setDarkMode(darkMode); + } + + lifecycle.trigger('afterupdate', ecModel, api); + }, + updateTransform: function (payload) { + var _this = this; + + var ecModel = this._model; + var api = this._api; // update before setOption + + if (!ecModel) { + return; + } + + ecModel.setUpdatePayload(payload); // ChartView.markUpdateMethod(payload, 'updateTransform'); + + var componentDirtyList = []; + ecModel.eachComponent(function (componentType, componentModel) { + if (componentType === 'series') { + return; + } + + var componentView = _this.getViewOfComponentModel(componentModel); + + if (componentView && componentView.__alive) { + if (componentView.updateTransform) { + var result = componentView.updateTransform(componentModel, ecModel, api, payload); + result && result.update && componentDirtyList.push(componentView); + } else { + componentDirtyList.push(componentView); + } + } + }); + var seriesDirtyMap = createHashMap(); + ecModel.eachSeries(function (seriesModel) { + var chartView = _this._chartsMap[seriesModel.__viewId]; + + if (chartView.updateTransform) { + var result = chartView.updateTransform(seriesModel, ecModel, api, payload); + result && result.update && seriesDirtyMap.set(seriesModel.uid, 1); + } else { + seriesDirtyMap.set(seriesModel.uid, 1); + } + }); + clearColorPalette(ecModel); // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline. + // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true); + + this._scheduler.performVisualTasks(ecModel, payload, { + setDirty: true, + dirtyMap: seriesDirtyMap + }); // Currently, not call render of components. Geo render cost a lot. + // renderComponents(ecIns, ecModel, api, payload, componentDirtyList); + + + renderSeries(this, ecModel, api, payload, {}, seriesDirtyMap); + lifecycle.trigger('afterupdate', ecModel, api); + }, + updateView: function (payload) { + var ecModel = this._model; // update before setOption + + if (!ecModel) { + return; + } + + ecModel.setUpdatePayload(payload); + ChartView.markUpdateMethod(payload, 'updateView'); + clearColorPalette(ecModel); // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline. + + this._scheduler.performVisualTasks(ecModel, payload, { + setDirty: true + }); + + render(this, ecModel, this._api, payload, {}); + lifecycle.trigger('afterupdate', ecModel, this._api); + }, + updateVisual: function (payload) { + // updateMethods.update.call(this, payload); + var _this = this; + + var ecModel = this._model; // update before setOption + + if (!ecModel) { + return; + } + + ecModel.setUpdatePayload(payload); // clear all visual + + ecModel.eachSeries(function (seriesModel) { + seriesModel.getData().clearAllVisual(); + }); // Perform visual + + ChartView.markUpdateMethod(payload, 'updateVisual'); + clearColorPalette(ecModel); // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline. + + this._scheduler.performVisualTasks(ecModel, payload, { + visualType: 'visual', + setDirty: true + }); + + ecModel.eachComponent(function (componentType, componentModel) { + if (componentType !== 'series') { + var componentView = _this.getViewOfComponentModel(componentModel); + + componentView && componentView.__alive && componentView.updateVisual(componentModel, ecModel, _this._api, payload); + } + }); + ecModel.eachSeries(function (seriesModel) { + var chartView = _this._chartsMap[seriesModel.__viewId]; + chartView.updateVisual(seriesModel, ecModel, _this._api, payload); + }); + lifecycle.trigger('afterupdate', ecModel, this._api); + }, + updateLayout: function (payload) { + updateMethods.update.call(this, payload); + } + }; + + doConvertPixel = function (ecIns, methodName, finder, value) { + if (ecIns._disposed) { + disposedWarning(ecIns.id); + return; + } + + var ecModel = ecIns._model; + + var coordSysList = ecIns._coordSysMgr.getCoordinateSystems(); + + var result; + var parsedFinder = parseFinder(ecModel, finder); + + for (var i = 0; i < coordSysList.length; i++) { + var coordSys = coordSysList[i]; + + if (coordSys[methodName] && (result = coordSys[methodName](ecModel, parsedFinder, value)) != null) { + return result; + } + } + + if ("development" !== 'production') { + console.warn('No coordinate system that supports ' + methodName + ' found by the given finder.'); + } + }; + + updateStreamModes = function (ecIns, ecModel) { + var chartsMap = ecIns._chartsMap; + var scheduler = ecIns._scheduler; + ecModel.eachSeries(function (seriesModel) { + scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]); + }); + }; + + doDispatchAction = function (payload, silent) { + var _this = this; + + var ecModel = this.getModel(); + var payloadType = payload.type; + var escapeConnect = payload.escapeConnect; + var actionWrap = actions[payloadType]; + var actionInfo = actionWrap.actionInfo; + var cptTypeTmp = (actionInfo.update || 'update').split(':'); + var updateMethod = cptTypeTmp.pop(); + var cptType = cptTypeTmp[0] != null && parseClassType(cptTypeTmp[0]); + this[IN_MAIN_PROCESS_KEY] = true; + var payloads = [payload]; + var batched = false; // Batch action + + if (payload.batch) { + batched = true; + payloads = map(payload.batch, function (item) { + item = defaults(extend({}, item), payload); + item.batch = null; + return item; + }); + } + + var eventObjBatch = []; + var eventObj; + var isSelectChange = isSelectChangePayload(payload); + var isHighDown = isHighDownPayload(payload); // Only leave blur once if there are multiple batches. + + if (isHighDown) { + allLeaveBlur(this._api); + } + + each(payloads, function (batchItem) { + // Action can specify the event by return it. + eventObj = actionWrap.action(batchItem, _this._model, _this._api); // Emit event outside + + eventObj = eventObj || extend({}, batchItem); // Convert type to eventType + + eventObj.type = actionInfo.event || eventObj.type; + eventObjBatch.push(eventObj); // light update does not perform data process, layout and visual. + + if (isHighDown) { + var _a = preParseFinder(payload), + queryOptionMap = _a.queryOptionMap, + mainTypeSpecified = _a.mainTypeSpecified; + + var componentMainType = mainTypeSpecified ? queryOptionMap.keys()[0] : 'series'; + updateDirectly(_this, updateMethod, batchItem, componentMainType); + markStatusToUpdate(_this); + } else if (isSelectChange) { + // At present `dispatchAction({ type: 'select', ... })` is not supported on components. + // geo still use 'geoselect'. + updateDirectly(_this, updateMethod, batchItem, 'series'); + markStatusToUpdate(_this); + } else if (cptType) { + updateDirectly(_this, updateMethod, batchItem, cptType.main, cptType.sub); + } + }); + + if (updateMethod !== 'none' && !isHighDown && !isSelectChange && !cptType) { + try { + // Still dirty + if (this[PENDING_UPDATE]) { + prepare(this); + updateMethods.update.call(this, payload); + this[PENDING_UPDATE] = null; + } else { + updateMethods[updateMethod].call(this, payload); + } + } catch (e) { + this[IN_MAIN_PROCESS_KEY] = false; + throw e; + } + } // Follow the rule of action batch + + + if (batched) { + eventObj = { + type: actionInfo.event || payloadType, + escapeConnect: escapeConnect, + batch: eventObjBatch + }; + } else { + eventObj = eventObjBatch[0]; + } + + this[IN_MAIN_PROCESS_KEY] = false; + + if (!silent) { + var messageCenter = this._messageCenter; + messageCenter.trigger(eventObj.type, eventObj); // Extra triggered 'selectchanged' event + + if (isSelectChange) { + var newObj = { + type: 'selectchanged', + escapeConnect: escapeConnect, + selected: getAllSelectedIndices(ecModel), + isFromClick: payload.isFromClick || false, + fromAction: payload.type, + fromActionPayload: payload + }; + messageCenter.trigger(newObj.type, newObj); + } + } + }; + + flushPendingActions = function (silent) { + var pendingActions = this._pendingActions; + + while (pendingActions.length) { + var payload = pendingActions.shift(); + doDispatchAction.call(this, payload, silent); + } + }; + + triggerUpdatedEvent = function (silent) { + !silent && this.trigger('updated'); + }; + /** + * Event `rendered` is triggered when zr + * rendered. It is useful for realtime + * snapshot (reflect animation). + * + * Event `finished` is triggered when: + * (1) zrender rendering finished. + * (2) initial animation finished. + * (3) progressive rendering finished. + * (4) no pending action. + * (5) no delayed setOption needs to be processed. + */ + + + bindRenderedEvent = function (zr, ecIns) { + zr.on('rendered', function (params) { + ecIns.trigger('rendered', params); // The `finished` event should not be triggered repeatly, + // so it should only be triggered when rendering indeed happend + // in zrender. (Consider the case that dipatchAction is keep + // triggering when mouse move). + + if ( // Although zr is dirty if initial animation is not finished + // and this checking is called on frame, we also check + // animation finished for robustness. + zr.animation.isFinished() && !ecIns[PENDING_UPDATE] && !ecIns._scheduler.unfinished && !ecIns._pendingActions.length) { + ecIns.trigger('finished'); + } + }); + }; + + bindMouseEvent = function (zr, ecIns) { + zr.on('mouseover', function (e) { + var el = e.target; + var dispatcher = findEventDispatcher(el, isHighDownDispatcher); + + if (dispatcher) { + handleGlobalMouseOverForHighDown(dispatcher, e, ecIns._api); + markStatusToUpdate(ecIns); + } + }).on('mouseout', function (e) { + var el = e.target; + var dispatcher = findEventDispatcher(el, isHighDownDispatcher); + + if (dispatcher) { + handleGlobalMouseOutForHighDown(dispatcher, e, ecIns._api); + markStatusToUpdate(ecIns); + } + }).on('click', function (e) { + var el = e.target; + var dispatcher = findEventDispatcher(el, function (target) { + return getECData(target).dataIndex != null; + }, true); + + if (dispatcher) { + var actionType = dispatcher.selected ? 'unselect' : 'select'; + var ecData = getECData(dispatcher); + + ecIns._api.dispatchAction({ + type: actionType, + dataType: ecData.dataType, + dataIndexInside: ecData.dataIndex, + seriesIndex: ecData.seriesIndex, + isFromClick: true + }); + } + }); + }; + + function clearColorPalette(ecModel) { + ecModel.clearColorPalette(); + ecModel.eachSeries(function (seriesModel) { + seriesModel.clearColorPalette(); + }); + } + + function allocateZlevels(ecModel) { + var componentZLevels = []; + var seriesZLevels = []; + var hasSeperateZLevel = false; + ecModel.eachComponent(function (componentType, componentModel) { + var zlevel = componentModel.get('zlevel') || 0; + var z = componentModel.get('z') || 0; + var zlevelKey = componentModel.getZLevelKey(); + hasSeperateZLevel = hasSeperateZLevel || !!zlevelKey; + (componentType === 'series' ? seriesZLevels : componentZLevels).push({ + zlevel: zlevel, + z: z, + idx: componentModel.componentIndex, + type: componentType, + key: zlevelKey + }); + }); + + if (hasSeperateZLevel) { + // Series after component + var zLevels = componentZLevels.concat(seriesZLevels); + var lastSeriesZLevel_1; + var lastSeriesKey_1; + sort(zLevels, function (a, b) { + if (a.zlevel === b.zlevel) { + return a.z - b.z; + } + + return a.zlevel - b.zlevel; + }); + each(zLevels, function (item) { + var componentModel = ecModel.getComponent(item.type, item.idx); + var zlevel = item.zlevel; + var key = item.key; + + if (lastSeriesZLevel_1 != null) { + zlevel = Math.max(lastSeriesZLevel_1, zlevel); + } + + if (key) { + if (zlevel === lastSeriesZLevel_1 && key !== lastSeriesKey_1) { + zlevel++; + } + + lastSeriesKey_1 = key; + } else if (lastSeriesKey_1) { + if (zlevel === lastSeriesZLevel_1) { + zlevel++; + } + + lastSeriesKey_1 = ''; + } + + lastSeriesZLevel_1 = zlevel; + componentModel.setZLevel(zlevel); + }); + } + } + + render = function (ecIns, ecModel, api, payload, updateParams) { + allocateZlevels(ecModel); + renderComponents(ecIns, ecModel, api, payload, updateParams); + each(ecIns._chartsViews, function (chart) { + chart.__alive = false; + }); + renderSeries(ecIns, ecModel, api, payload, updateParams); // Remove groups of unrendered charts + + each(ecIns._chartsViews, function (chart) { + if (!chart.__alive) { + chart.remove(ecModel, api); + } + }); + }; + + renderComponents = function (ecIns, ecModel, api, payload, updateParams, dirtyList) { + each(dirtyList || ecIns._componentsViews, function (componentView) { + var componentModel = componentView.__model; + clearStates(componentModel, componentView); + componentView.render(componentModel, ecModel, api, payload); + updateZ(componentModel, componentView); + updateStates(componentModel, componentView); + }); + }; + /** + * Render each chart and component + */ + + + renderSeries = function (ecIns, ecModel, api, payload, updateParams, dirtyMap) { + // Render all charts + var scheduler = ecIns._scheduler; + updateParams = extend(updateParams || {}, { + updatedSeries: ecModel.getSeries() + }); // TODO progressive? + + lifecycle.trigger('series:beforeupdate', ecModel, api, updateParams); + var unfinished = false; + ecModel.eachSeries(function (seriesModel) { + var chartView = ecIns._chartsMap[seriesModel.__viewId]; + chartView.__alive = true; + var renderTask = chartView.renderTask; + scheduler.updatePayload(renderTask, payload); // TODO states on marker. + + clearStates(seriesModel, chartView); + + if (dirtyMap && dirtyMap.get(seriesModel.uid)) { + renderTask.dirty(); + } + + if (renderTask.perform(scheduler.getPerformArgs(renderTask))) { + unfinished = true; + } + + chartView.group.silent = !!seriesModel.get('silent'); // Should not call markRedraw on group, because it will disable zrender + // increamental render (alway render from the __startIndex each frame) + // chartView.group.markRedraw(); + + updateBlend(seriesModel, chartView); + updateSeriesElementSelection(seriesModel); + }); + scheduler.unfinished = unfinished || scheduler.unfinished; + lifecycle.trigger('series:layoutlabels', ecModel, api, updateParams); // transition after label is layouted. + + lifecycle.trigger('series:transition', ecModel, api, updateParams); + ecModel.eachSeries(function (seriesModel) { + var chartView = ecIns._chartsMap[seriesModel.__viewId]; // Update Z after labels updated. Before applying states. + + updateZ(seriesModel, chartView); // NOTE: Update states after label is updated. + // label should be in normal status when layouting. + + updateStates(seriesModel, chartView); + }); // If use hover layer + + updateHoverLayerStatus(ecIns, ecModel); + lifecycle.trigger('series:afterupdate', ecModel, api, updateParams); + }; + + markStatusToUpdate = function (ecIns) { + ecIns[STATUS_NEEDS_UPDATE_KEY] = true; // Wake up zrender if it's sleep. Let it update states in the next frame. + + ecIns.getZr().wakeUp(); + }; + + applyChangedStates = function (ecIns) { + if (!ecIns[STATUS_NEEDS_UPDATE_KEY]) { + return; + } + + ecIns.getZr().storage.traverse(function (el) { + // Not applied on removed elements, it may still in fading. + if (isElementRemoved(el)) { + return; + } + + applyElementStates(el); + }); + ecIns[STATUS_NEEDS_UPDATE_KEY] = false; + }; + + function applyElementStates(el) { + var newStates = []; + var oldStates = el.currentStates; // Keep other states. + + for (var i = 0; i < oldStates.length; i++) { + var stateName = oldStates[i]; + + if (!(stateName === 'emphasis' || stateName === 'blur' || stateName === 'select')) { + newStates.push(stateName); + } + } // Only use states when it's exists. + + + if (el.selected && el.states.select) { + newStates.push('select'); + } + + if (el.hoverState === HOVER_STATE_EMPHASIS && el.states.emphasis) { + newStates.push('emphasis'); + } else if (el.hoverState === HOVER_STATE_BLUR && el.states.blur) { + newStates.push('blur'); + } + + el.useStates(newStates); + } + + function updateHoverLayerStatus(ecIns, ecModel) { + var zr = ecIns._zr; + var storage = zr.storage; + var elCount = 0; + storage.traverse(function (el) { + if (!el.isGroup) { + elCount++; + } + }); + + if (elCount > ecModel.get('hoverLayerThreshold') && !env.node && !env.worker) { + ecModel.eachSeries(function (seriesModel) { + if (seriesModel.preventUsingHoverLayer) { + return; + } + + var chartView = ecIns._chartsMap[seriesModel.__viewId]; + + if (chartView.__alive) { + chartView.eachRendered(function (el) { + if (el.states.emphasis) { + el.states.emphasis.hoverLayer = true; + } + }); + } + }); + } + } + /** + * Update chart and blend. + */ + + function updateBlend(seriesModel, chartView) { + var blendMode = seriesModel.get('blendMode') || null; + chartView.eachRendered(function (el) { + // FIXME marker and other components + if (!el.isGroup) { + // DONT mark the element dirty. In case element is incremental and don't wan't to rerender. + el.style.blend = blendMode; + } + }); + } + + function updateZ(model, view) { + if (model.preventAutoZ) { + return; + } + + var z = model.get('z') || 0; + var zlevel = model.get('zlevel') || 0; // Set z and zlevel + + view.eachRendered(function (el) { + doUpdateZ(el, z, zlevel, -Infinity); // Don't traverse the children because it has been traversed in _updateZ. + + return true; + }); + } + + function doUpdateZ(el, z, zlevel, maxZ2) { + // Group may also have textContent + var label = el.getTextContent(); + var labelLine = el.getTextGuideLine(); + var isGroup = el.isGroup; + + if (isGroup) { + // set z & zlevel of children elements of Group + var children = el.childrenRef(); + + for (var i = 0; i < children.length; i++) { + maxZ2 = Math.max(doUpdateZ(children[i], z, zlevel, maxZ2), maxZ2); + } + } else { + // not Group + el.z = z; + el.zlevel = zlevel; + maxZ2 = Math.max(el.z2, maxZ2); + } // always set z and zlevel if label/labelLine exists + + + if (label) { + label.z = z; + label.zlevel = zlevel; // lift z2 of text content + // TODO if el.emphasis.z2 is spcefied, what about textContent. + + isFinite(maxZ2) && (label.z2 = maxZ2 + 2); + } + + if (labelLine) { + var textGuideLineConfig = el.textGuideLineConfig; + labelLine.z = z; + labelLine.zlevel = zlevel; + isFinite(maxZ2) && (labelLine.z2 = maxZ2 + (textGuideLineConfig && textGuideLineConfig.showAbove ? 1 : -1)); + } + + return maxZ2; + } // Clear states without animation. + // TODO States on component. + + + function clearStates(model, view) { + view.eachRendered(function (el) { + // Not applied on removed elements, it may still in fading. + if (isElementRemoved(el)) { + return; + } + + var textContent = el.getTextContent(); + var textGuide = el.getTextGuideLine(); + + if (el.stateTransition) { + el.stateTransition = null; + } + + if (textContent && textContent.stateTransition) { + textContent.stateTransition = null; + } + + if (textGuide && textGuide.stateTransition) { + textGuide.stateTransition = null; + } // TODO If el is incremental. + + + if (el.hasState()) { + el.prevStates = el.currentStates; + el.clearStates(); + } else if (el.prevStates) { + el.prevStates = null; + } + }); + } + + function updateStates(model, view) { + var stateAnimationModel = model.getModel('stateAnimation'); + var enableAnimation = model.isAnimationEnabled(); + var duration = stateAnimationModel.get('duration'); + var stateTransition = duration > 0 ? { + duration: duration, + delay: stateAnimationModel.get('delay'), + easing: stateAnimationModel.get('easing') // additive: stateAnimationModel.get('additive') + + } : null; + view.eachRendered(function (el) { + if (el.states && el.states.emphasis) { + // Not applied on removed elements, it may still in fading. + if (isElementRemoved(el)) { + return; + } + + if (el instanceof Path) { + savePathStates(el); + } // Only updated on changed element. In case element is incremental and don't wan't to rerender. + // TODO, a more proper way? + + + if (el.__dirty) { + var prevStates = el.prevStates; // Restore states without animation + + if (prevStates) { + el.useStates(prevStates); + } + } // Update state transition and enable animation again. + + + if (enableAnimation) { + el.stateTransition = stateTransition; + var textContent = el.getTextContent(); + var textGuide = el.getTextGuideLine(); // TODO Is it necessary to animate label? + + if (textContent) { + textContent.stateTransition = stateTransition; + } + + if (textGuide) { + textGuide.stateTransition = stateTransition; + } + } // The use higlighted and selected flag to toggle states. + + + if (el.__dirty) { + applyElementStates(el); + } + } + }); + } + + createExtensionAPI = function (ecIns) { + return new ( + /** @class */ + function (_super) { + __extends(class_1, _super); + + function class_1() { + return _super !== null && _super.apply(this, arguments) || this; + } + + class_1.prototype.getCoordinateSystems = function () { + return ecIns._coordSysMgr.getCoordinateSystems(); + }; + + class_1.prototype.getComponentByElement = function (el) { + while (el) { + var modelInfo = el.__ecComponentInfo; + + if (modelInfo != null) { + return ecIns._model.getComponent(modelInfo.mainType, modelInfo.index); + } + + el = el.parent; + } + }; + + class_1.prototype.enterEmphasis = function (el, highlightDigit) { + enterEmphasis(el, highlightDigit); + markStatusToUpdate(ecIns); + }; + + class_1.prototype.leaveEmphasis = function (el, highlightDigit) { + leaveEmphasis(el, highlightDigit); + markStatusToUpdate(ecIns); + }; + + class_1.prototype.enterBlur = function (el) { + enterBlur(el); + markStatusToUpdate(ecIns); + }; + + class_1.prototype.leaveBlur = function (el) { + leaveBlur(el); + markStatusToUpdate(ecIns); + }; + + class_1.prototype.enterSelect = function (el) { + enterSelect(el); + markStatusToUpdate(ecIns); + }; + + class_1.prototype.leaveSelect = function (el) { + leaveSelect(el); + markStatusToUpdate(ecIns); + }; + + class_1.prototype.getModel = function () { + return ecIns.getModel(); + }; + + class_1.prototype.getViewOfComponentModel = function (componentModel) { + return ecIns.getViewOfComponentModel(componentModel); + }; + + class_1.prototype.getViewOfSeriesModel = function (seriesModel) { + return ecIns.getViewOfSeriesModel(seriesModel); + }; + + return class_1; + }(ExtensionAPI))(ecIns); + }; + + enableConnect = function (chart) { + function updateConnectedChartsStatus(charts, status) { + for (var i = 0; i < charts.length; i++) { + var otherChart = charts[i]; + otherChart[CONNECT_STATUS_KEY] = status; + } + } + + each(eventActionMap, function (actionType, eventType) { + chart._messageCenter.on(eventType, function (event) { + if (connectedGroups[chart.group] && chart[CONNECT_STATUS_KEY] !== CONNECT_STATUS_PENDING) { + if (event && event.escapeConnect) { + return; + } + + var action_1 = chart.makeActionFromEvent(event); + var otherCharts_1 = []; + each(instances$1, function (otherChart) { + if (otherChart !== chart && otherChart.group === chart.group) { + otherCharts_1.push(otherChart); + } + }); + updateConnectedChartsStatus(otherCharts_1, CONNECT_STATUS_PENDING); + each(otherCharts_1, function (otherChart) { + if (otherChart[CONNECT_STATUS_KEY] !== CONNECT_STATUS_UPDATING) { + otherChart.dispatchAction(action_1); + } + }); + updateConnectedChartsStatus(otherCharts_1, CONNECT_STATUS_UPDATED); + } + }); + }); + }; + }(); + + return ECharts; + }(Eventful); + + var echartsProto = ECharts.prototype; + echartsProto.on = createRegisterEventWithLowercaseECharts('on'); + echartsProto.off = createRegisterEventWithLowercaseECharts('off'); + /** + * @deprecated + */ + // @ts-ignore + + echartsProto.one = function (eventName, cb, ctx) { + var self = this; + deprecateLog('ECharts#one is deprecated.'); + + function wrapped() { + var args2 = []; + + for (var _i = 0; _i < arguments.length; _i++) { + args2[_i] = arguments[_i]; + } + + cb && cb.apply && cb.apply(this, args2); // @ts-ignore + + self.off(eventName, wrapped); + } + + this.on.call(this, eventName, wrapped, ctx); + }; + + var MOUSE_EVENT_NAMES = ['click', 'dblclick', 'mouseover', 'mouseout', 'mousemove', 'mousedown', 'mouseup', 'globalout', 'contextmenu']; + + function disposedWarning(id) { + if ("development" !== 'production') { + console.warn('Instance ' + id + ' has been disposed'); + } + } + + var actions = {}; + /** + * Map eventType to actionType + */ + + var eventActionMap = {}; + var dataProcessorFuncs = []; + var optionPreprocessorFuncs = []; + var visualFuncs = []; + var themeStorage = {}; + var loadingEffects = {}; + var instances$1 = {}; + var connectedGroups = {}; + var idBase = +new Date() - 0; + var groupIdBase = +new Date() - 0; + var DOM_ATTRIBUTE_KEY = '_echarts_instance_'; + /** + * @param opts.devicePixelRatio Use window.devicePixelRatio by default + * @param opts.renderer Can choose 'canvas' or 'svg' to render the chart. + * @param opts.width Use clientWidth of the input `dom` by default. + * Can be 'auto' (the same as null/undefined) + * @param opts.height Use clientHeight of the input `dom` by default. + * Can be 'auto' (the same as null/undefined) + * @param opts.locale Specify the locale. + * @param opts.useDirtyRect Enable dirty rectangle rendering or not. + */ + + function init$1(dom, theme, opts) { + var isClient = !(opts && opts.ssr); + + if (isClient) { + if ("development" !== 'production') { + if (!dom) { + throw new Error('Initialize failed: invalid dom.'); + } + } + + var existInstance = getInstanceByDom(dom); + + if (existInstance) { + if ("development" !== 'production') { + console.warn('There is a chart instance already initialized on the dom.'); + } + + return existInstance; + } + + if ("development" !== 'production') { + if (isDom(dom) && dom.nodeName.toUpperCase() !== 'CANVAS' && (!dom.clientWidth && (!opts || opts.width == null) || !dom.clientHeight && (!opts || opts.height == null))) { + console.warn('Can\'t get DOM width or height. Please check ' + 'dom.clientWidth and dom.clientHeight. They should not be 0.' + 'For example, you may need to call this in the callback ' + 'of window.onload.'); + } + } + } + + var chart = new ECharts(dom, theme, opts); + chart.id = 'ec_' + idBase++; + instances$1[chart.id] = chart; + isClient && setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id); + enableConnect(chart); + lifecycle.trigger('afterinit', chart); + return chart; + } + /** + * @usage + * (A) + * ```js + * let chart1 = echarts.init(dom1); + * let chart2 = echarts.init(dom2); + * chart1.group = 'xxx'; + * chart2.group = 'xxx'; + * echarts.connect('xxx'); + * ``` + * (B) + * ```js + * let chart1 = echarts.init(dom1); + * let chart2 = echarts.init(dom2); + * echarts.connect('xxx', [chart1, chart2]); + * ``` + */ + + function connect(groupId) { + // Is array of charts + if (isArray(groupId)) { + var charts = groupId; + groupId = null; // If any chart has group + + each(charts, function (chart) { + if (chart.group != null) { + groupId = chart.group; + } + }); + groupId = groupId || 'g_' + groupIdBase++; + each(charts, function (chart) { + chart.group = groupId; + }); + } + + connectedGroups[groupId] = true; + return groupId; + } + /** + * @deprecated + */ + + function disConnect(groupId) { + connectedGroups[groupId] = false; + } + /** + * Alias and backword compat + */ + + var disconnect = disConnect; + /** + * Dispose a chart instance + */ + + function dispose$1(chart) { + if (isString(chart)) { + chart = instances$1[chart]; + } else if (!(chart instanceof ECharts)) { + // Try to treat as dom + chart = getInstanceByDom(chart); + } + + if (chart instanceof ECharts && !chart.isDisposed()) { + chart.dispose(); + } + } + function getInstanceByDom(dom) { + return instances$1[getAttribute(dom, DOM_ATTRIBUTE_KEY)]; + } + function getInstanceById(key) { + return instances$1[key]; + } + /** + * Register theme + */ + + function registerTheme(name, theme) { + themeStorage[name] = theme; + } + /** + * Register option preprocessor + */ + + function registerPreprocessor(preprocessorFunc) { + if (indexOf(optionPreprocessorFuncs, preprocessorFunc) < 0) { + optionPreprocessorFuncs.push(preprocessorFunc); + } + } + function registerProcessor(priority, processor) { + normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_DEFAULT); + } + /** + * Register postIniter + * @param {Function} postInitFunc + */ + + function registerPostInit(postInitFunc) { + registerUpdateLifecycle('afterinit', postInitFunc); + } + /** + * Register postUpdater + * @param {Function} postUpdateFunc + */ + + function registerPostUpdate(postUpdateFunc) { + registerUpdateLifecycle('afterupdate', postUpdateFunc); + } + function registerUpdateLifecycle(name, cb) { + lifecycle.on(name, cb); + } + function registerAction(actionInfo, eventName, action) { + if (isFunction(eventName)) { + action = eventName; + eventName = ''; + } + + var actionType = isObject(actionInfo) ? actionInfo.type : [actionInfo, actionInfo = { + event: eventName + }][0]; // Event name is all lowercase + + actionInfo.event = (actionInfo.event || actionType).toLowerCase(); + eventName = actionInfo.event; + + if (eventActionMap[eventName]) { + // Already registered. + return; + } // Validate action type and event name. + + + assert(ACTION_REG.test(actionType) && ACTION_REG.test(eventName)); + + if (!actions[actionType]) { + actions[actionType] = { + action: action, + actionInfo: actionInfo + }; + } + + eventActionMap[eventName] = actionType; + } + function registerCoordinateSystem(type, coordSysCreator) { + CoordinateSystemManager.register(type, coordSysCreator); + } + /** + * Get dimensions of specified coordinate system. + * @param {string} type + * @return {Array.} + */ + + function getCoordinateSystemDimensions(type) { + var coordSysCreator = CoordinateSystemManager.get(type); + + if (coordSysCreator) { + return coordSysCreator.getDimensionsInfo ? coordSysCreator.getDimensionsInfo() : coordSysCreator.dimensions.slice(); + } + } + + function registerLayout(priority, layoutTask) { + normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout'); + } + + function registerVisual(priority, visualTask) { + normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual'); + } + var registeredTasks = []; + + function normalizeRegister(targetList, priority, fn, defaultPriority, visualType) { + if (isFunction(priority) || isObject(priority)) { + fn = priority; + priority = defaultPriority; + } + + if ("development" !== 'production') { + if (isNaN(priority) || priority == null) { + throw new Error('Illegal priority'); + } // Check duplicate + + + each(targetList, function (wrap) { + assert(wrap.__raw !== fn); + }); + } // Already registered + + + if (indexOf(registeredTasks, fn) >= 0) { + return; + } + + registeredTasks.push(fn); + var stageHandler = Scheduler.wrapStageHandler(fn, visualType); + stageHandler.__prio = priority; + stageHandler.__raw = fn; + targetList.push(stageHandler); + } + + function registerLoading(name, loadingFx) { + loadingEffects[name] = loadingFx; + } + /** + * ZRender need a canvas context to do measureText. + * But in node environment canvas may be created by node-canvas. + * So we need to specify how to create a canvas instead of using document.createElement('canvas') + * + * + * @deprecated use setPlatformAPI({ createCanvas }) instead. + * + * @example + * let Canvas = require('canvas'); + * let echarts = require('echarts'); + * echarts.setCanvasCreator(function () { + * // Small size is enough. + * return new Canvas(32, 32); + * }); + */ + + function setCanvasCreator(creator) { + if ("development" !== 'production') { + deprecateLog('setCanvasCreator is deprecated. Use setPlatformAPI({ createCanvas }) instead.'); + } + + setPlatformAPI({ + createCanvas: creator + }); + } + /** + * The parameters and usage: see `geoSourceManager.registerMap`. + * Compatible with previous `echarts.registerMap`. + */ + + function registerMap(mapName, geoJson, specialAreas) { + var registerMap = getImpl('registerMap'); + registerMap && registerMap(mapName, geoJson, specialAreas); + } + function getMap(mapName) { + var getMap = getImpl('getMap'); + return getMap && getMap(mapName); + } + var registerTransform = registerExternalTransform; + /** + * Globa dispatchAction to a specified chart instance. + */ + // export function dispatchAction(payload: { chartId: string } & Payload, opt?: Parameters[1]) { + // if (!payload || !payload.chartId) { + // // Must have chartId to find chart + // return; + // } + // const chart = instances[payload.chartId]; + // if (chart) { + // chart.dispatchAction(payload, opt); + // } + // } + // Buitlin global visual + + registerVisual(PRIORITY_VISUAL_GLOBAL, seriesStyleTask); + registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataStyleTask); + registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataColorPaletteTask); + registerVisual(PRIORITY_VISUAL_GLOBAL, seriesSymbolTask); + registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataSymbolTask); + registerVisual(PRIORITY_VISUAL_DECAL, decalVisual); + registerPreprocessor(globalBackwardCompat); + registerProcessor(PRIORITY_PROCESSOR_DATASTACK, dataStack); + registerLoading('default', defaultLoading); // Default actions + + registerAction({ + type: HIGHLIGHT_ACTION_TYPE, + event: HIGHLIGHT_ACTION_TYPE, + update: HIGHLIGHT_ACTION_TYPE + }, noop); + registerAction({ + type: DOWNPLAY_ACTION_TYPE, + event: DOWNPLAY_ACTION_TYPE, + update: DOWNPLAY_ACTION_TYPE + }, noop); + registerAction({ + type: SELECT_ACTION_TYPE, + event: SELECT_ACTION_TYPE, + update: SELECT_ACTION_TYPE + }, noop); + registerAction({ + type: UNSELECT_ACTION_TYPE, + event: UNSELECT_ACTION_TYPE, + update: UNSELECT_ACTION_TYPE + }, noop); + registerAction({ + type: TOGGLE_SELECT_ACTION_TYPE, + event: TOGGLE_SELECT_ACTION_TYPE, + update: TOGGLE_SELECT_ACTION_TYPE + }, noop); // Default theme + + registerTheme('light', lightTheme); + registerTheme('dark', theme); // For backward compatibility, where the namespace `dataTool` will + // be mounted on `echarts` is the extension `dataTool` is imported. + + var dataTool = {}; + + var extensions = []; + var extensionRegisters = { + registerPreprocessor: registerPreprocessor, + registerProcessor: registerProcessor, + registerPostInit: registerPostInit, + registerPostUpdate: registerPostUpdate, + registerUpdateLifecycle: registerUpdateLifecycle, + registerAction: registerAction, + registerCoordinateSystem: registerCoordinateSystem, + registerLayout: registerLayout, + registerVisual: registerVisual, + registerTransform: registerTransform, + registerLoading: registerLoading, + registerMap: registerMap, + registerImpl: registerImpl, + PRIORITY: PRIORITY, + ComponentModel: ComponentModel, + ComponentView: ComponentView, + SeriesModel: SeriesModel, + ChartView: ChartView, + // TODO Use ComponentModel and SeriesModel instead of Constructor + registerComponentModel: function (ComponentModelClass) { + ComponentModel.registerClass(ComponentModelClass); + }, + registerComponentView: function (ComponentViewClass) { + ComponentView.registerClass(ComponentViewClass); + }, + registerSeriesModel: function (SeriesModelClass) { + SeriesModel.registerClass(SeriesModelClass); + }, + registerChartView: function (ChartViewClass) { + ChartView.registerClass(ChartViewClass); + }, + registerSubTypeDefaulter: function (componentType, defaulter) { + ComponentModel.registerSubTypeDefaulter(componentType, defaulter); + }, + registerPainter: function (painterType, PainterCtor) { + registerPainter(painterType, PainterCtor); + } + }; + function use(ext) { + if (isArray(ext)) { + // use([ChartLine, ChartBar]); + each(ext, function (singleExt) { + use(singleExt); + }); + return; + } + + if (indexOf(extensions, ext) >= 0) { + return; + } + + extensions.push(ext); + + if (isFunction(ext)) { + ext = { + install: ext + }; + } + + ext.install(extensionRegisters); + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + function dataIndexMapValueLength(valNumOrArrLengthMoreThan2) { + return valNumOrArrLengthMoreThan2 == null ? 0 : valNumOrArrLengthMoreThan2.length || 1; + } + + function defaultKeyGetter(item) { + return item; + } + + var DataDiffer = + /** @class */ + function () { + /** + * @param context Can be visited by this.context in callback. + */ + function DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter, context, // By default: 'oneToOne'. + diffMode) { + this._old = oldArr; + this._new = newArr; + this._oldKeyGetter = oldKeyGetter || defaultKeyGetter; + this._newKeyGetter = newKeyGetter || defaultKeyGetter; // Visible in callback via `this.context`; + + this.context = context; + this._diffModeMultiple = diffMode === 'multiple'; + } + /** + * Callback function when add a data + */ + + + DataDiffer.prototype.add = function (func) { + this._add = func; + return this; + }; + /** + * Callback function when update a data + */ + + + DataDiffer.prototype.update = function (func) { + this._update = func; + return this; + }; + /** + * Callback function when update a data and only work in `cbMode: 'byKey'`. + */ + + + DataDiffer.prototype.updateManyToOne = function (func) { + this._updateManyToOne = func; + return this; + }; + /** + * Callback function when update a data and only work in `cbMode: 'byKey'`. + */ + + + DataDiffer.prototype.updateOneToMany = function (func) { + this._updateOneToMany = func; + return this; + }; + /** + * Callback function when update a data and only work in `cbMode: 'byKey'`. + */ + + + DataDiffer.prototype.updateManyToMany = function (func) { + this._updateManyToMany = func; + return this; + }; + /** + * Callback function when remove a data + */ + + + DataDiffer.prototype.remove = function (func) { + this._remove = func; + return this; + }; + + DataDiffer.prototype.execute = function () { + this[this._diffModeMultiple ? '_executeMultiple' : '_executeOneToOne'](); + }; + + DataDiffer.prototype._executeOneToOne = function () { + var oldArr = this._old; + var newArr = this._new; + var newDataIndexMap = {}; + var oldDataKeyArr = new Array(oldArr.length); + var newDataKeyArr = new Array(newArr.length); + + this._initIndexMap(oldArr, null, oldDataKeyArr, '_oldKeyGetter'); + + this._initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter'); + + for (var i = 0; i < oldArr.length; i++) { + var oldKey = oldDataKeyArr[i]; + var newIdxMapVal = newDataIndexMap[oldKey]; + var newIdxMapValLen = dataIndexMapValueLength(newIdxMapVal); // idx can never be empty array here. see 'set null' logic below. + + if (newIdxMapValLen > 1) { + // Consider there is duplicate key (for example, use dataItem.name as key). + // We should make sure every item in newArr and oldArr can be visited. + var newIdx = newIdxMapVal.shift(); + + if (newIdxMapVal.length === 1) { + newDataIndexMap[oldKey] = newIdxMapVal[0]; + } + + this._update && this._update(newIdx, i); + } else if (newIdxMapValLen === 1) { + newDataIndexMap[oldKey] = null; + this._update && this._update(newIdxMapVal, i); + } else { + this._remove && this._remove(i); + } + } + + this._performRestAdd(newDataKeyArr, newDataIndexMap); + }; + /** + * For example, consider the case: + * oldData: [o0, o1, o2, o3, o4, o5, o6, o7], + * newData: [n0, n1, n2, n3, n4, n5, n6, n7, n8], + * Where: + * o0, o1, n0 has key 'a' (many to one) + * o5, n4, n5, n6 has key 'b' (one to many) + * o2, n1 has key 'c' (one to one) + * n2, n3 has key 'd' (add) + * o3, o4 has key 'e' (remove) + * o6, o7, n7, n8 has key 'f' (many to many, treated as add and remove) + * Then: + * (The order of the following directives are not ensured.) + * this._updateManyToOne(n0, [o0, o1]); + * this._updateOneToMany([n4, n5, n6], o5); + * this._update(n1, o2); + * this._remove(o3); + * this._remove(o4); + * this._remove(o6); + * this._remove(o7); + * this._add(n2); + * this._add(n3); + * this._add(n7); + * this._add(n8); + */ + + + DataDiffer.prototype._executeMultiple = function () { + var oldArr = this._old; + var newArr = this._new; + var oldDataIndexMap = {}; + var newDataIndexMap = {}; + var oldDataKeyArr = []; + var newDataKeyArr = []; + + this._initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter'); + + this._initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter'); + + for (var i = 0; i < oldDataKeyArr.length; i++) { + var oldKey = oldDataKeyArr[i]; + var oldIdxMapVal = oldDataIndexMap[oldKey]; + var newIdxMapVal = newDataIndexMap[oldKey]; + var oldIdxMapValLen = dataIndexMapValueLength(oldIdxMapVal); + var newIdxMapValLen = dataIndexMapValueLength(newIdxMapVal); + + if (oldIdxMapValLen > 1 && newIdxMapValLen === 1) { + this._updateManyToOne && this._updateManyToOne(newIdxMapVal, oldIdxMapVal); + newDataIndexMap[oldKey] = null; + } else if (oldIdxMapValLen === 1 && newIdxMapValLen > 1) { + this._updateOneToMany && this._updateOneToMany(newIdxMapVal, oldIdxMapVal); + newDataIndexMap[oldKey] = null; + } else if (oldIdxMapValLen === 1 && newIdxMapValLen === 1) { + this._update && this._update(newIdxMapVal, oldIdxMapVal); + newDataIndexMap[oldKey] = null; + } else if (oldIdxMapValLen > 1 && newIdxMapValLen > 1) { + this._updateManyToMany && this._updateManyToMany(newIdxMapVal, oldIdxMapVal); + newDataIndexMap[oldKey] = null; + } else if (oldIdxMapValLen > 1) { + for (var i_1 = 0; i_1 < oldIdxMapValLen; i_1++) { + this._remove && this._remove(oldIdxMapVal[i_1]); + } + } else { + this._remove && this._remove(oldIdxMapVal); + } + } + + this._performRestAdd(newDataKeyArr, newDataIndexMap); + }; + + DataDiffer.prototype._performRestAdd = function (newDataKeyArr, newDataIndexMap) { + for (var i = 0; i < newDataKeyArr.length; i++) { + var newKey = newDataKeyArr[i]; + var newIdxMapVal = newDataIndexMap[newKey]; + var idxMapValLen = dataIndexMapValueLength(newIdxMapVal); + + if (idxMapValLen > 1) { + for (var j = 0; j < idxMapValLen; j++) { + this._add && this._add(newIdxMapVal[j]); + } + } else if (idxMapValLen === 1) { + this._add && this._add(newIdxMapVal); + } // Support both `newDataKeyArr` are duplication removed or not removed. + + + newDataIndexMap[newKey] = null; + } + }; + + DataDiffer.prototype._initIndexMap = function (arr, // Can be null. + map, // In 'byKey', the output `keyArr` is duplication removed. + // In 'byIndex', the output `keyArr` is not duplication removed and + // its indices are accurately corresponding to `arr`. + keyArr, keyGetterName) { + var cbModeMultiple = this._diffModeMultiple; + + for (var i = 0; i < arr.length; i++) { + // Add prefix to avoid conflict with Object.prototype. + var key = '_ec_' + this[keyGetterName](arr[i], i); + + if (!cbModeMultiple) { + keyArr[i] = key; + } + + if (!map) { + continue; + } + + var idxMapVal = map[key]; + var idxMapValLen = dataIndexMapValueLength(idxMapVal); + + if (idxMapValLen === 0) { + // Simple optimize: in most cases, one index has one key, + // do not need array. + map[key] = i; + + if (cbModeMultiple) { + keyArr.push(key); + } + } else if (idxMapValLen === 1) { + map[key] = [idxMapVal, i]; + } else { + idxMapVal.push(i); + } + } + }; + + return DataDiffer; + }(); + + var DimensionUserOuput = + /** @class */ + function () { + function DimensionUserOuput(encode, dimRequest) { + this._encode = encode; + this._schema = dimRequest; + } + + DimensionUserOuput.prototype.get = function () { + return { + // Do not generate full dimension name until fist used. + fullDimensions: this._getFullDimensionNames(), + encode: this._encode + }; + }; + /** + * Get all data store dimension names. + * Theoretically a series data store is defined both by series and used dataset (if any). + * If some dimensions are omitted for performance reason in `this.dimensions`, + * the dimension name may not be auto-generated if user does not specify a dimension name. + * In this case, the dimension name is `null`/`undefined`. + */ + + + DimensionUserOuput.prototype._getFullDimensionNames = function () { + if (!this._cachedDimNames) { + this._cachedDimNames = this._schema ? this._schema.makeOutputDimensionNames() : []; + } + + return this._cachedDimNames; + }; + + return DimensionUserOuput; + }(); + function summarizeDimensions(data, schema) { + var summary = {}; + var encode = summary.encode = {}; + var notExtraCoordDimMap = createHashMap(); + var defaultedLabel = []; + var defaultedTooltip = []; + var userOutputEncode = {}; + each(data.dimensions, function (dimName) { + var dimItem = data.getDimensionInfo(dimName); + var coordDim = dimItem.coordDim; + + if (coordDim) { + if ("development" !== 'production') { + assert(VISUAL_DIMENSIONS.get(coordDim) == null); + } + + var coordDimIndex = dimItem.coordDimIndex; + getOrCreateEncodeArr(encode, coordDim)[coordDimIndex] = dimName; + + if (!dimItem.isExtraCoord) { + notExtraCoordDimMap.set(coordDim, 1); // Use the last coord dim (and label friendly) as default label, + // because when dataset is used, it is hard to guess which dimension + // can be value dimension. If both show x, y on label is not look good, + // and conventionally y axis is focused more. + + if (mayLabelDimType(dimItem.type)) { + defaultedLabel[0] = dimName; + } // User output encode do not contain generated coords. + // And it only has index. User can use index to retrieve value from the raw item array. + + + getOrCreateEncodeArr(userOutputEncode, coordDim)[coordDimIndex] = data.getDimensionIndex(dimItem.name); + } + + if (dimItem.defaultTooltip) { + defaultedTooltip.push(dimName); + } + } + + VISUAL_DIMENSIONS.each(function (v, otherDim) { + var encodeArr = getOrCreateEncodeArr(encode, otherDim); + var dimIndex = dimItem.otherDims[otherDim]; + + if (dimIndex != null && dimIndex !== false) { + encodeArr[dimIndex] = dimItem.name; + } + }); + }); + var dataDimsOnCoord = []; + var encodeFirstDimNotExtra = {}; + notExtraCoordDimMap.each(function (v, coordDim) { + var dimArr = encode[coordDim]; + encodeFirstDimNotExtra[coordDim] = dimArr[0]; // Not necessary to remove duplicate, because a data + // dim canot on more than one coordDim. + + dataDimsOnCoord = dataDimsOnCoord.concat(dimArr); + }); + summary.dataDimsOnCoord = dataDimsOnCoord; + summary.dataDimIndicesOnCoord = map(dataDimsOnCoord, function (dimName) { + return data.getDimensionInfo(dimName).storeDimIndex; + }); + summary.encodeFirstDimNotExtra = encodeFirstDimNotExtra; + var encodeLabel = encode.label; // FIXME `encode.label` is not recommanded, because formatter can not be set + // in this way. Use label.formatter instead. May be remove this approach someday. + + if (encodeLabel && encodeLabel.length) { + defaultedLabel = encodeLabel.slice(); + } + + var encodeTooltip = encode.tooltip; + + if (encodeTooltip && encodeTooltip.length) { + defaultedTooltip = encodeTooltip.slice(); + } else if (!defaultedTooltip.length) { + defaultedTooltip = defaultedLabel.slice(); + } + + encode.defaultedLabel = defaultedLabel; + encode.defaultedTooltip = defaultedTooltip; + summary.userOutput = new DimensionUserOuput(userOutputEncode, schema); + return summary; + } + + function getOrCreateEncodeArr(encode, dim) { + if (!encode.hasOwnProperty(dim)) { + encode[dim] = []; + } + + return encode[dim]; + } // FIXME:TS should be type `AxisType` + + + function getDimensionTypeByAxis(axisType) { + return axisType === 'category' ? 'ordinal' : axisType === 'time' ? 'time' : 'float'; + } + + function mayLabelDimType(dimType) { + // In most cases, ordinal and time do not suitable for label. + // Ordinal info can be displayed on axis. Time is too long. + return !(dimType === 'ordinal' || dimType === 'time'); + } // function findTheLastDimMayLabel(data) { + // // Get last value dim + // let dimensions = data.dimensions.slice(); + // let valueType; + // let valueDim; + // while (dimensions.length && ( + // valueDim = dimensions.pop(), + // valueType = data.getDimensionInfo(valueDim).type, + // valueType === 'ordinal' || valueType === 'time' + // )) {} // jshint ignore:line + // return valueDim; + // } + + var SeriesDimensionDefine = + /** @class */ + function () { + /** + * @param opt All of the fields will be shallow copied. + */ + function SeriesDimensionDefine(opt) { + /** + * The format of `otherDims` is: + * ```js + * { + * tooltip?: number + * label?: number + * itemName?: number + * seriesName?: number + * } + * ``` + * + * A `series.encode` can specified these fields: + * ```js + * encode: { + * // "3, 1, 5" is the index of data dimension. + * tooltip: [3, 1, 5], + * label: [0, 3], + * ... + * } + * ``` + * `otherDims` is the parse result of the `series.encode` above, like: + * ```js + * // Suppose the index of this data dimension is `3`. + * this.otherDims = { + * // `3` is at the index `0` of the `encode.tooltip` + * tooltip: 0, + * // `3` is at the index `1` of the `encode.label` + * label: 1 + * }; + * ``` + * + * This prop should never be `null`/`undefined` after initialized. + */ + this.otherDims = {}; + + if (opt != null) { + extend(this, opt); + } + } + + return SeriesDimensionDefine; + }(); + + var inner$4 = makeInner(); + var dimTypeShort = { + float: 'f', + int: 'i', + ordinal: 'o', + number: 'n', + time: 't' + }; + /** + * Represents the dimension requirement of a series. + * + * NOTICE: + * When there are too many dimensions in dataset and many series, only the used dimensions + * (i.e., used by coord sys and declared in `series.encode`) are add to `dimensionDefineList`. + * But users may query data by other unused dimension names. + * In this case, users can only query data if and only if they have defined dimension names + * via ec option, so we provide `getDimensionIndexFromSource`, which only query them from + * `source` dimensions. + */ + + var SeriesDataSchema = + /** @class */ + function () { + function SeriesDataSchema(opt) { + this.dimensions = opt.dimensions; + this._dimOmitted = opt.dimensionOmitted; + this.source = opt.source; + this._fullDimCount = opt.fullDimensionCount; + + this._updateDimOmitted(opt.dimensionOmitted); + } + + SeriesDataSchema.prototype.isDimensionOmitted = function () { + return this._dimOmitted; + }; + + SeriesDataSchema.prototype._updateDimOmitted = function (dimensionOmitted) { + this._dimOmitted = dimensionOmitted; + + if (!dimensionOmitted) { + return; + } + + if (!this._dimNameMap) { + this._dimNameMap = ensureSourceDimNameMap(this.source); + } + }; + /** + * @caution Can only be used when `dimensionOmitted: true`. + * + * Get index by user defined dimension name (i.e., not internal generate name). + * That is, get index from `dimensionsDefine`. + * If no `dimensionsDefine`, or no name get, return -1. + */ + + + SeriesDataSchema.prototype.getSourceDimensionIndex = function (dimName) { + return retrieve2(this._dimNameMap.get(dimName), -1); + }; + /** + * @caution Can only be used when `dimensionOmitted: true`. + * + * Notice: may return `null`/`undefined` if user not specify dimension names. + */ + + + SeriesDataSchema.prototype.getSourceDimension = function (dimIndex) { + var dimensionsDefine = this.source.dimensionsDefine; + + if (dimensionsDefine) { + return dimensionsDefine[dimIndex]; + } + }; + + SeriesDataSchema.prototype.makeStoreSchema = function () { + var dimCount = this._fullDimCount; + var willRetrieveDataByName = shouldRetrieveDataByName(this.source); + var makeHashStrict = !shouldOmitUnusedDimensions(dimCount); // If source don't have dimensions or series don't omit unsed dimensions. + // Generate from seriesDimList directly + + var dimHash = ''; + var dims = []; + + for (var fullDimIdx = 0, seriesDimIdx = 0; fullDimIdx < dimCount; fullDimIdx++) { + var property = void 0; + var type = void 0; + var ordinalMeta = void 0; + var seriesDimDef = this.dimensions[seriesDimIdx]; // The list has been sorted by `storeDimIndex` asc. + + if (seriesDimDef && seriesDimDef.storeDimIndex === fullDimIdx) { + property = willRetrieveDataByName ? seriesDimDef.name : null; + type = seriesDimDef.type; + ordinalMeta = seriesDimDef.ordinalMeta; + seriesDimIdx++; + } else { + var sourceDimDef = this.getSourceDimension(fullDimIdx); + + if (sourceDimDef) { + property = willRetrieveDataByName ? sourceDimDef.name : null; + type = sourceDimDef.type; + } + } + + dims.push({ + property: property, + type: type, + ordinalMeta: ordinalMeta + }); // If retrieving data by index, + // use to determine whether data can be shared. + // (Becuase in this case there might be no dimension name defined in dataset, but indices always exists). + // (indices are always 0, 1, 2, ..., so we can ignore them to shorten the hash). + // Otherwise if retrieving data by property name (like `data: [{aa: 123, bb: 765}, ...]`), + // use in hash. + + if (willRetrieveDataByName && property != null // For data stack, we have make sure each series has its own dim on this store. + // So we do not add property to hash to make sure they can share this store. + && (!seriesDimDef || !seriesDimDef.isCalculationCoord)) { + dimHash += makeHashStrict // Use escape character '`' in case that property name contains '$'. + ? property.replace(/\`/g, '`1').replace(/\$/g, '`2') // For better performance, when there are large dimensions, tolerant this defects that hardly meet. + : property; + } + + dimHash += '$'; + dimHash += dimTypeShort[type] || 'f'; + + if (ordinalMeta) { + dimHash += ordinalMeta.uid; + } + + dimHash += '$'; + } // Source from endpoint(usually series) will be read differently + // when seriesLayoutBy or startIndex(which is affected by sourceHeader) are different. + // So we use this three props as key. + + + var source = this.source; + var hash = [source.seriesLayoutBy, source.startIndex, dimHash].join('$$'); + return { + dimensions: dims, + hash: hash + }; + }; + + SeriesDataSchema.prototype.makeOutputDimensionNames = function () { + var result = []; + + for (var fullDimIdx = 0, seriesDimIdx = 0; fullDimIdx < this._fullDimCount; fullDimIdx++) { + var name_1 = void 0; + var seriesDimDef = this.dimensions[seriesDimIdx]; // The list has been sorted by `storeDimIndex` asc. + + if (seriesDimDef && seriesDimDef.storeDimIndex === fullDimIdx) { + if (!seriesDimDef.isCalculationCoord) { + name_1 = seriesDimDef.name; + } + + seriesDimIdx++; + } else { + var sourceDimDef = this.getSourceDimension(fullDimIdx); + + if (sourceDimDef) { + name_1 = sourceDimDef.name; + } + } + + result.push(name_1); + } + + return result; + }; + + SeriesDataSchema.prototype.appendCalculationDimension = function (dimDef) { + this.dimensions.push(dimDef); + dimDef.isCalculationCoord = true; + this._fullDimCount++; // If append dimension on a data store, consider the store + // might be shared by different series, series dimensions not + // really map to store dimensions. + + this._updateDimOmitted(true); + }; + + return SeriesDataSchema; + }(); + function isSeriesDataSchema(schema) { + return schema instanceof SeriesDataSchema; + } + function createDimNameMap(dimsDef) { + var dataDimNameMap = createHashMap(); + + for (var i = 0; i < (dimsDef || []).length; i++) { + var dimDefItemRaw = dimsDef[i]; + var userDimName = isObject(dimDefItemRaw) ? dimDefItemRaw.name : dimDefItemRaw; + + if (userDimName != null && dataDimNameMap.get(userDimName) == null) { + dataDimNameMap.set(userDimName, i); + } + } + + return dataDimNameMap; + } + function ensureSourceDimNameMap(source) { + var innerSource = inner$4(source); + return innerSource.dimNameMap || (innerSource.dimNameMap = createDimNameMap(source.dimensionsDefine)); + } + function shouldOmitUnusedDimensions(dimCount) { + return dimCount > 30; + } + + var isObject$2 = isObject; + var map$1 = map; + var CtorInt32Array$1 = typeof Int32Array === 'undefined' ? Array : Int32Array; // Use prefix to avoid index to be the same as otherIdList[idx], + // which will cause weird udpate animation. + + var ID_PREFIX = 'e\0\0'; + var INDEX_NOT_FOUND = -1; // type SeriesDimensionIndex = DimensionIndex; + + var TRANSFERABLE_PROPERTIES = ['hasItemOption', '_nameList', '_idList', '_invertedIndicesMap', '_dimSummary', 'userOutput', '_rawData', '_dimValueGetter', '_nameDimIdx', '_idDimIdx', '_nameRepeatCount']; + var CLONE_PROPERTIES = ['_approximateExtent']; // ----------------------------- + // Internal method declarations: + // ----------------------------- + + var prepareInvertedIndex; + var getId; + var getIdNameFromStore; + var normalizeDimensions; + var transferProperties; + var cloneListForMapAndSample; + var makeIdFromName; + + var SeriesData = + /** @class */ + function () { + /** + * @param dimensionsInput.dimensions + * For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...]. + * Dimensions should be concrete names like x, y, z, lng, lat, angle, radius + */ + function SeriesData(dimensionsInput, hostModel) { + this.type = 'list'; + this._dimOmitted = false; + this._nameList = []; + this._idList = []; // Models of data option is stored sparse for optimizing memory cost + // Never used yet (not used yet). + // private _optionModels: Model[] = []; + // Global visual properties after visual coding + + this._visual = {}; // Globel layout properties. + + this._layout = {}; // Item visual properties after visual coding + + this._itemVisuals = []; // Item layout properties after layout + + this._itemLayouts = []; // Graphic elemnents + + this._graphicEls = []; // key: dim, value: extent + + this._approximateExtent = {}; + this._calculationInfo = {}; // Having detected that there is data item is non primitive type + // (in type `OptionDataItemObject`). + // Like `data: [ { value: xx, itemStyle: {...} }, ...]` + // At present it only happen in `SOURCE_FORMAT_ORIGINAL`. + + this.hasItemOption = false; // Methods that create a new list based on this list should be listed here. + // Notice that those method should `RETURN` the new list. + + this.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'lttbDownSample', 'map']; // Methods that change indices of this list should be listed here. + + this.CHANGABLE_METHODS = ['filterSelf', 'selectRange']; + this.DOWNSAMPLE_METHODS = ['downSample', 'lttbDownSample']; + var dimensions; + var assignStoreDimIdx = false; + + if (isSeriesDataSchema(dimensionsInput)) { + dimensions = dimensionsInput.dimensions; + this._dimOmitted = dimensionsInput.isDimensionOmitted(); + this._schema = dimensionsInput; + } else { + assignStoreDimIdx = true; + dimensions = dimensionsInput; + } + + dimensions = dimensions || ['x', 'y']; + var dimensionInfos = {}; + var dimensionNames = []; + var invertedIndicesMap = {}; + var needsHasOwn = false; + var emptyObj = {}; + + for (var i = 0; i < dimensions.length; i++) { + // Use the original dimensions[i], where other flag props may exists. + var dimInfoInput = dimensions[i]; + var dimensionInfo = isString(dimInfoInput) ? new SeriesDimensionDefine({ + name: dimInfoInput + }) : !(dimInfoInput instanceof SeriesDimensionDefine) ? new SeriesDimensionDefine(dimInfoInput) : dimInfoInput; + var dimensionName = dimensionInfo.name; + dimensionInfo.type = dimensionInfo.type || 'float'; + + if (!dimensionInfo.coordDim) { + dimensionInfo.coordDim = dimensionName; + dimensionInfo.coordDimIndex = 0; + } + + var otherDims = dimensionInfo.otherDims = dimensionInfo.otherDims || {}; + dimensionNames.push(dimensionName); + dimensionInfos[dimensionName] = dimensionInfo; + + if (emptyObj[dimensionName] != null) { + needsHasOwn = true; + } + + if (dimensionInfo.createInvertedIndices) { + invertedIndicesMap[dimensionName] = []; + } + + if (otherDims.itemName === 0) { + this._nameDimIdx = i; + } + + if (otherDims.itemId === 0) { + this._idDimIdx = i; + } + + if ("development" !== 'production') { + assert(assignStoreDimIdx || dimensionInfo.storeDimIndex >= 0); + } + + if (assignStoreDimIdx) { + dimensionInfo.storeDimIndex = i; + } + } + + this.dimensions = dimensionNames; + this._dimInfos = dimensionInfos; + + this._initGetDimensionInfo(needsHasOwn); + + this.hostModel = hostModel; + this._invertedIndicesMap = invertedIndicesMap; + + if (this._dimOmitted) { + var dimIdxToName_1 = this._dimIdxToName = createHashMap(); + each(dimensionNames, function (dimName) { + dimIdxToName_1.set(dimensionInfos[dimName].storeDimIndex, dimName); + }); + } + } + /** + * + * Get concrete dimension name by dimension name or dimension index. + * If input a dimension name, do not validate whether the dimension name exits. + * + * @caution + * @param dim Must make sure the dimension is `SeriesDimensionLoose`. + * Because only those dimensions will have auto-generated dimension names if not + * have a user-specified name, and other dimensions will get a return of null/undefined. + * + * @notice Becuause of this reason, should better use `getDimensionIndex` instead, for examples: + * ```js + * const val = data.getStore().get(data.getDimensionIndex(dim), dataIdx); + * ``` + * + * @return Concrete dim name. + */ + + + SeriesData.prototype.getDimension = function (dim) { + var dimIdx = this._recognizeDimIndex(dim); + + if (dimIdx == null) { + return dim; + } + + dimIdx = dim; + + if (!this._dimOmitted) { + return this.dimensions[dimIdx]; + } // Retrieve from series dimension definition becuase it probably contains + // generated dimension name (like 'x', 'y'). + + + var dimName = this._dimIdxToName.get(dimIdx); + + if (dimName != null) { + return dimName; + } + + var sourceDimDef = this._schema.getSourceDimension(dimIdx); + + if (sourceDimDef) { + return sourceDimDef.name; + } + }; + /** + * Get dimension index in data store. Return -1 if not found. + * Can be used to index value from getRawValue. + */ + + + SeriesData.prototype.getDimensionIndex = function (dim) { + var dimIdx = this._recognizeDimIndex(dim); + + if (dimIdx != null) { + return dimIdx; + } + + if (dim == null) { + return -1; + } + + var dimInfo = this._getDimInfo(dim); + + return dimInfo ? dimInfo.storeDimIndex : this._dimOmitted ? this._schema.getSourceDimensionIndex(dim) : -1; + }; + /** + * The meanings of the input parameter `dim`: + * + * + If dim is a number (e.g., `1`), it means the index of the dimension. + * For example, `getDimension(0)` will return 'x' or 'lng' or 'radius'. + * + If dim is a number-like string (e.g., `"1"`): + * + If there is the same concrete dim name defined in `series.dimensions` or `dataset.dimensions`, + * it means that concrete name. + * + If not, it will be converted to a number, which means the index of the dimension. + * (why? because of the backward compatbility. We have been tolerating number-like string in + * dimension setting, although now it seems that it is not a good idea.) + * For example, `visualMap[i].dimension: "1"` is the same meaning as `visualMap[i].dimension: 1`, + * if no dimension name is defined as `"1"`. + * + If dim is a not-number-like string, it means the concrete dim name. + * For example, it can be be default name `"x"`, `"y"`, `"z"`, `"lng"`, `"lat"`, `"angle"`, `"radius"`, + * or customized in `dimensions` property of option like `"age"`. + * + * @return recogonized `DimensionIndex`. Otherwise return null/undefined (means that dim is `DimensionName`). + */ + + + SeriesData.prototype._recognizeDimIndex = function (dim) { + if (isNumber(dim) // If being a number-like string but not being defined as a dimension name. + || dim != null && !isNaN(dim) && !this._getDimInfo(dim) && (!this._dimOmitted || this._schema.getSourceDimensionIndex(dim) < 0)) { + return +dim; + } + }; + + SeriesData.prototype._getStoreDimIndex = function (dim) { + var dimIdx = this.getDimensionIndex(dim); + + if ("development" !== 'production') { + if (dimIdx == null) { + throw new Error('Unkown dimension ' + dim); + } + } + + return dimIdx; + }; + /** + * Get type and calculation info of particular dimension + * @param dim + * Dimension can be concrete names like x, y, z, lng, lat, angle, radius + * Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius' + */ + + + SeriesData.prototype.getDimensionInfo = function (dim) { + // Do not clone, because there may be categories in dimInfo. + return this._getDimInfo(this.getDimension(dim)); + }; + + SeriesData.prototype._initGetDimensionInfo = function (needsHasOwn) { + var dimensionInfos = this._dimInfos; + this._getDimInfo = needsHasOwn ? function (dimName) { + return dimensionInfos.hasOwnProperty(dimName) ? dimensionInfos[dimName] : undefined; + } : function (dimName) { + return dimensionInfos[dimName]; + }; + }; + /** + * concrete dimension name list on coord. + */ + + + SeriesData.prototype.getDimensionsOnCoord = function () { + return this._dimSummary.dataDimsOnCoord.slice(); + }; + + SeriesData.prototype.mapDimension = function (coordDim, idx) { + var dimensionsSummary = this._dimSummary; + + if (idx == null) { + return dimensionsSummary.encodeFirstDimNotExtra[coordDim]; + } + + var dims = dimensionsSummary.encode[coordDim]; + return dims ? dims[idx] : null; + }; + + SeriesData.prototype.mapDimensionsAll = function (coordDim) { + var dimensionsSummary = this._dimSummary; + var dims = dimensionsSummary.encode[coordDim]; + return (dims || []).slice(); + }; + + SeriesData.prototype.getStore = function () { + return this._store; + }; + /** + * Initialize from data + * @param data source or data or data store. + * @param nameList The name of a datum is used on data diff and + * default label/tooltip. + * A name can be specified in encode.itemName, + * or dataItem.name (only for series option data), + * or provided in nameList from outside. + */ + + + SeriesData.prototype.initData = function (data, nameList, dimValueGetter) { + var _this = this; + + var store; + + if (data instanceof DataStore) { + store = data; + } + + if (!store) { + var dimensions = this.dimensions; + var provider = isSourceInstance(data) || isArrayLike(data) ? new DefaultDataProvider(data, dimensions.length) : data; + store = new DataStore(); + var dimensionInfos = map$1(dimensions, function (dimName) { + return { + type: _this._dimInfos[dimName].type, + property: dimName + }; + }); + store.initData(provider, dimensionInfos, dimValueGetter); + } + + this._store = store; // Reset + + this._nameList = (nameList || []).slice(); + this._idList = []; + this._nameRepeatCount = {}; + + this._doInit(0, store.count()); // Cache summary info for fast visit. See "dimensionHelper". + // Needs to be initialized after store is prepared. + + + this._dimSummary = summarizeDimensions(this, this._schema); + this.userOutput = this._dimSummary.userOutput; + }; + /** + * Caution: Can be only called on raw data (before `this._indices` created). + */ + + + SeriesData.prototype.appendData = function (data) { + var range = this._store.appendData(data); + + this._doInit(range[0], range[1]); + }; + /** + * Caution: Can be only called on raw data (before `this._indices` created). + * This method does not modify `rawData` (`dataProvider`), but only + * add values to store. + * + * The final count will be increased by `Math.max(values.length, names.length)`. + * + * @param values That is the SourceType: 'arrayRows', like + * [ + * [12, 33, 44], + * [NaN, 43, 1], + * ['-', 'asdf', 0] + * ] + * Each item is exaclty cooresponding to a dimension. + */ + + + SeriesData.prototype.appendValues = function (values, names) { + var _a = this._store.appendValues(values, names.length), + start = _a.start, + end = _a.end; + + var shouldMakeIdFromName = this._shouldMakeIdFromName(); + + this._updateOrdinalMeta(); + + if (names) { + for (var idx = start; idx < end; idx++) { + var sourceIdx = idx - start; + this._nameList[idx] = names[sourceIdx]; + + if (shouldMakeIdFromName) { + makeIdFromName(this, idx); + } + } + } + }; + + SeriesData.prototype._updateOrdinalMeta = function () { + var store = this._store; + var dimensions = this.dimensions; + + for (var i = 0; i < dimensions.length; i++) { + var dimInfo = this._dimInfos[dimensions[i]]; + + if (dimInfo.ordinalMeta) { + store.collectOrdinalMeta(dimInfo.storeDimIndex, dimInfo.ordinalMeta); + } + } + }; + + SeriesData.prototype._shouldMakeIdFromName = function () { + var provider = this._store.getProvider(); + + return this._idDimIdx == null && provider.getSource().sourceFormat !== SOURCE_FORMAT_TYPED_ARRAY && !provider.fillStorage; + }; + + SeriesData.prototype._doInit = function (start, end) { + if (start >= end) { + return; + } + + var store = this._store; + var provider = store.getProvider(); + + this._updateOrdinalMeta(); + + var nameList = this._nameList; + var idList = this._idList; + var sourceFormat = provider.getSource().sourceFormat; + var isFormatOriginal = sourceFormat === SOURCE_FORMAT_ORIGINAL; // Each data item is value + // [1, 2] + // 2 + // Bar chart, line chart which uses category axis + // only gives the 'y' value. 'x' value is the indices of category + // Use a tempValue to normalize the value to be a (x, y) value + // If dataItem is {name: ...} or {id: ...}, it has highest priority. + // This kind of ids and names are always stored `_nameList` and `_idList`. + + if (isFormatOriginal && !provider.pure) { + var sharedDataItem = []; + + for (var idx = start; idx < end; idx++) { + // NOTICE: Try not to write things into dataItem + var dataItem = provider.getItem(idx, sharedDataItem); + + if (!this.hasItemOption && isDataItemOption(dataItem)) { + this.hasItemOption = true; + } + + if (dataItem) { + var itemName = dataItem.name; + + if (nameList[idx] == null && itemName != null) { + nameList[idx] = convertOptionIdName(itemName, null); + } + + var itemId = dataItem.id; + + if (idList[idx] == null && itemId != null) { + idList[idx] = convertOptionIdName(itemId, null); + } + } + } + } + + if (this._shouldMakeIdFromName()) { + for (var idx = start; idx < end; idx++) { + makeIdFromName(this, idx); + } + } + + prepareInvertedIndex(this); + }; + /** + * PENDING: In fact currently this function is only used to short-circuit + * the calling of `scale.unionExtentFromData` when data have been filtered by modules + * like "dataZoom". `scale.unionExtentFromData` is used to calculate data extent for series on + * an axis, but if a "axis related data filter module" is used, the extent of the axis have + * been fixed and no need to calling `scale.unionExtentFromData` actually. + * But if we add "custom data filter" in future, which is not "axis related", this method may + * be still needed. + * + * Optimize for the scenario that data is filtered by a given extent. + * Consider that if data amount is more than hundreds of thousand, + * extent calculation will cost more than 10ms and the cache will + * be erased because of the filtering. + */ + + + SeriesData.prototype.getApproximateExtent = function (dim) { + return this._approximateExtent[dim] || this._store.getDataExtent(this._getStoreDimIndex(dim)); + }; + /** + * Calculate extent on a filtered data might be time consuming. + * Approximate extent is only used for: calculte extent of filtered data outside. + */ + + + SeriesData.prototype.setApproximateExtent = function (extent, dim) { + dim = this.getDimension(dim); + this._approximateExtent[dim] = extent.slice(); + }; + + SeriesData.prototype.getCalculationInfo = function (key) { + return this._calculationInfo[key]; + }; + + SeriesData.prototype.setCalculationInfo = function (key, value) { + isObject$2(key) ? extend(this._calculationInfo, key) : this._calculationInfo[key] = value; + }; + /** + * @return Never be null/undefined. `number` will be converted to string. Becuase: + * In most cases, name is used in display, where returning a string is more convenient. + * In other cases, name is used in query (see `indexOfName`), where we can keep the + * rule that name `2` equals to name `'2'`. + */ + + + SeriesData.prototype.getName = function (idx) { + var rawIndex = this.getRawIndex(idx); + var name = this._nameList[rawIndex]; + + if (name == null && this._nameDimIdx != null) { + name = getIdNameFromStore(this, this._nameDimIdx, rawIndex); + } + + if (name == null) { + name = ''; + } + + return name; + }; + + SeriesData.prototype._getCategory = function (dimIdx, idx) { + var ordinal = this._store.get(dimIdx, idx); + + var ordinalMeta = this._store.getOrdinalMeta(dimIdx); + + if (ordinalMeta) { + return ordinalMeta.categories[ordinal]; + } + + return ordinal; + }; + /** + * @return Never null/undefined. `number` will be converted to string. Becuase: + * In all cases having encountered at present, id is used in making diff comparison, which + * are usually based on hash map. We can keep the rule that the internal id are always string + * (treat `2` is the same as `'2'`) to make the related logic simple. + */ + + + SeriesData.prototype.getId = function (idx) { + return getId(this, this.getRawIndex(idx)); + }; + + SeriesData.prototype.count = function () { + return this._store.count(); + }; + /** + * Get value. Return NaN if idx is out of range. + * + * @notice Should better to use `data.getStore().get(dimIndex, dataIdx)` instead. + */ + + + SeriesData.prototype.get = function (dim, idx) { + var store = this._store; + var dimInfo = this._dimInfos[dim]; + + if (dimInfo) { + return store.get(dimInfo.storeDimIndex, idx); + } + }; + /** + * @notice Should better to use `data.getStore().getByRawIndex(dimIndex, dataIdx)` instead. + */ + + + SeriesData.prototype.getByRawIndex = function (dim, rawIdx) { + var store = this._store; + var dimInfo = this._dimInfos[dim]; + + if (dimInfo) { + return store.getByRawIndex(dimInfo.storeDimIndex, rawIdx); + } + }; + + SeriesData.prototype.getIndices = function () { + return this._store.getIndices(); + }; + + SeriesData.prototype.getDataExtent = function (dim) { + return this._store.getDataExtent(this._getStoreDimIndex(dim)); + }; + + SeriesData.prototype.getSum = function (dim) { + return this._store.getSum(this._getStoreDimIndex(dim)); + }; + + SeriesData.prototype.getMedian = function (dim) { + return this._store.getMedian(this._getStoreDimIndex(dim)); + }; + + SeriesData.prototype.getValues = function (dimensions, idx) { + var _this = this; + + var store = this._store; + return isArray(dimensions) ? store.getValues(map$1(dimensions, function (dim) { + return _this._getStoreDimIndex(dim); + }), idx) : store.getValues(dimensions); + }; + /** + * If value is NaN. Inlcuding '-' + * Only check the coord dimensions. + */ + + + SeriesData.prototype.hasValue = function (idx) { + var dataDimIndicesOnCoord = this._dimSummary.dataDimIndicesOnCoord; + + for (var i = 0, len = dataDimIndicesOnCoord.length; i < len; i++) { + // Ordinal type originally can be string or number. + // But when an ordinal type is used on coord, it can + // not be string but only number. So we can also use isNaN. + if (isNaN(this._store.get(dataDimIndicesOnCoord[i], idx))) { + return false; + } + } + + return true; + }; + /** + * Retreive the index with given name + */ + + + SeriesData.prototype.indexOfName = function (name) { + for (var i = 0, len = this._store.count(); i < len; i++) { + if (this.getName(i) === name) { + return i; + } + } + + return -1; + }; + + SeriesData.prototype.getRawIndex = function (idx) { + return this._store.getRawIndex(idx); + }; + + SeriesData.prototype.indexOfRawIndex = function (rawIndex) { + return this._store.indexOfRawIndex(rawIndex); + }; + /** + * Only support the dimension which inverted index created. + * Do not support other cases until required. + * @param dim concrete dim + * @param value ordinal index + * @return rawIndex + */ + + + SeriesData.prototype.rawIndexOf = function (dim, value) { + var invertedIndices = dim && this._invertedIndicesMap[dim]; + + if ("development" !== 'production') { + if (!invertedIndices) { + throw new Error('Do not supported yet'); + } + } + + var rawIndex = invertedIndices[value]; + + if (rawIndex == null || isNaN(rawIndex)) { + return INDEX_NOT_FOUND; + } + + return rawIndex; + }; + /** + * Retreive the index of nearest value + * @param dim + * @param value + * @param [maxDistance=Infinity] + * @return If and only if multiple indices has + * the same value, they are put to the result. + */ + + + SeriesData.prototype.indicesOfNearest = function (dim, value, maxDistance) { + return this._store.indicesOfNearest(this._getStoreDimIndex(dim), value, maxDistance); + }; + + SeriesData.prototype.each = function (dims, cb, ctx) { + + if (isFunction(dims)) { + ctx = cb; + cb = dims; + dims = []; + } // ctxCompat just for compat echarts3 + + + var fCtx = ctx || this; + var dimIndices = map$1(normalizeDimensions(dims), this._getStoreDimIndex, this); + + this._store.each(dimIndices, fCtx ? bind(cb, fCtx) : cb); + }; + + SeriesData.prototype.filterSelf = function (dims, cb, ctx) { + + if (isFunction(dims)) { + ctx = cb; + cb = dims; + dims = []; + } // ctxCompat just for compat echarts3 + + + var fCtx = ctx || this; + var dimIndices = map$1(normalizeDimensions(dims), this._getStoreDimIndex, this); + this._store = this._store.filter(dimIndices, fCtx ? bind(cb, fCtx) : cb); + return this; + }; + /** + * Select data in range. (For optimization of filter) + * (Manually inline code, support 5 million data filtering in data zoom.) + */ + + + SeriesData.prototype.selectRange = function (range) { + + var _this = this; + + var innerRange = {}; + var dims = keys(range); + each(dims, function (dim) { + var dimIdx = _this._getStoreDimIndex(dim); + + innerRange[dimIdx] = range[dim]; + }); + this._store = this._store.selectRange(innerRange); + return this; + }; + /* eslint-enable max-len */ + + + SeriesData.prototype.mapArray = function (dims, cb, ctx) { + + if (isFunction(dims)) { + ctx = cb; + cb = dims; + dims = []; + } // ctxCompat just for compat echarts3 + + + ctx = ctx || this; + var result = []; + this.each(dims, function () { + result.push(cb && cb.apply(this, arguments)); + }, ctx); + return result; + }; + + SeriesData.prototype.map = function (dims, cb, ctx, ctxCompat) { + + var fCtx = ctx || ctxCompat || this; + var dimIndices = map$1(normalizeDimensions(dims), this._getStoreDimIndex, this); + var list = cloneListForMapAndSample(this); + list._store = this._store.map(dimIndices, fCtx ? bind(cb, fCtx) : cb); + return list; + }; + + SeriesData.prototype.modify = function (dims, cb, ctx, ctxCompat) { + var _this = this; // ctxCompat just for compat echarts3 + + + var fCtx = ctx || ctxCompat || this; + + if ("development" !== 'production') { + each(normalizeDimensions(dims), function (dim) { + var dimInfo = _this.getDimensionInfo(dim); + + if (!dimInfo.isCalculationCoord) { + console.error('Danger: only stack dimension can be modified'); + } + }); + } + + var dimIndices = map$1(normalizeDimensions(dims), this._getStoreDimIndex, this); // If do shallow clone here, if there are too many stacked series, + // it still cost lots of memory, becuase `_store.dimensions` are not shared. + // We should consider there probably be shallow clone happen in each sereis + // in consequent filter/map. + + this._store.modify(dimIndices, fCtx ? bind(cb, fCtx) : cb); + }; + /** + * Large data down sampling on given dimension + * @param sampleIndex Sample index for name and id + */ + + + SeriesData.prototype.downSample = function (dimension, rate, sampleValue, sampleIndex) { + var list = cloneListForMapAndSample(this); + list._store = this._store.downSample(this._getStoreDimIndex(dimension), rate, sampleValue, sampleIndex); + return list; + }; + /** + * Large data down sampling using largest-triangle-three-buckets + * @param {string} valueDimension + * @param {number} targetCount + */ + + + SeriesData.prototype.lttbDownSample = function (valueDimension, rate) { + var list = cloneListForMapAndSample(this); + list._store = this._store.lttbDownSample(this._getStoreDimIndex(valueDimension), rate); + return list; + }; + + SeriesData.prototype.getRawDataItem = function (idx) { + return this._store.getRawDataItem(idx); + }; + /** + * Get model of one data item. + */ + // TODO: Type of data item + + + SeriesData.prototype.getItemModel = function (idx) { + var hostModel = this.hostModel; + var dataItem = this.getRawDataItem(idx); + return new Model(dataItem, hostModel, hostModel && hostModel.ecModel); + }; + /** + * Create a data differ + */ + + + SeriesData.prototype.diff = function (otherList) { + var thisList = this; + return new DataDiffer(otherList ? otherList.getStore().getIndices() : [], this.getStore().getIndices(), function (idx) { + return getId(otherList, idx); + }, function (idx) { + return getId(thisList, idx); + }); + }; + /** + * Get visual property. + */ + + + SeriesData.prototype.getVisual = function (key) { + var visual = this._visual; + return visual && visual[key]; + }; + + SeriesData.prototype.setVisual = function (kvObj, val) { + this._visual = this._visual || {}; + + if (isObject$2(kvObj)) { + extend(this._visual, kvObj); + } else { + this._visual[kvObj] = val; + } + }; + /** + * Get visual property of single data item + */ + // eslint-disable-next-line + + + SeriesData.prototype.getItemVisual = function (idx, key) { + var itemVisual = this._itemVisuals[idx]; + var val = itemVisual && itemVisual[key]; + + if (val == null) { + // Use global visual property + return this.getVisual(key); + } + + return val; + }; + /** + * If exists visual property of single data item + */ + + + SeriesData.prototype.hasItemVisual = function () { + return this._itemVisuals.length > 0; + }; + /** + * Make sure itemVisual property is unique + */ + // TODO: use key to save visual to reduce memory. + + + SeriesData.prototype.ensureUniqueItemVisual = function (idx, key) { + var itemVisuals = this._itemVisuals; + var itemVisual = itemVisuals[idx]; + + if (!itemVisual) { + itemVisual = itemVisuals[idx] = {}; + } + + var val = itemVisual[key]; + + if (val == null) { + val = this.getVisual(key); // TODO Performance? + + if (isArray(val)) { + val = val.slice(); + } else if (isObject$2(val)) { + val = extend({}, val); + } + + itemVisual[key] = val; + } + + return val; + }; // eslint-disable-next-line + + + SeriesData.prototype.setItemVisual = function (idx, key, value) { + var itemVisual = this._itemVisuals[idx] || {}; + this._itemVisuals[idx] = itemVisual; + + if (isObject$2(key)) { + extend(itemVisual, key); + } else { + itemVisual[key] = value; + } + }; + /** + * Clear itemVisuals and list visual. + */ + + + SeriesData.prototype.clearAllVisual = function () { + this._visual = {}; + this._itemVisuals = []; + }; + + SeriesData.prototype.setLayout = function (key, val) { + isObject$2(key) ? extend(this._layout, key) : this._layout[key] = val; + }; + /** + * Get layout property. + */ + + + SeriesData.prototype.getLayout = function (key) { + return this._layout[key]; + }; + /** + * Get layout of single data item + */ + + + SeriesData.prototype.getItemLayout = function (idx) { + return this._itemLayouts[idx]; + }; + /** + * Set layout of single data item + */ + + + SeriesData.prototype.setItemLayout = function (idx, layout, merge) { + this._itemLayouts[idx] = merge ? extend(this._itemLayouts[idx] || {}, layout) : layout; + }; + /** + * Clear all layout of single data item + */ + + + SeriesData.prototype.clearItemLayouts = function () { + this._itemLayouts.length = 0; + }; + /** + * Set graphic element relative to data. It can be set as null + */ + + + SeriesData.prototype.setItemGraphicEl = function (idx, el) { + var seriesIndex = this.hostModel && this.hostModel.seriesIndex; + setCommonECData(seriesIndex, this.dataType, idx, el); + this._graphicEls[idx] = el; + }; + + SeriesData.prototype.getItemGraphicEl = function (idx) { + return this._graphicEls[idx]; + }; + + SeriesData.prototype.eachItemGraphicEl = function (cb, context) { + each(this._graphicEls, function (el, idx) { + if (el) { + cb && cb.call(context, el, idx); + } + }); + }; + /** + * Shallow clone a new list except visual and layout properties, and graph elements. + * New list only change the indices. + */ + + + SeriesData.prototype.cloneShallow = function (list) { + if (!list) { + list = new SeriesData(this._schema ? this._schema : map$1(this.dimensions, this._getDimInfo, this), this.hostModel); + } + + transferProperties(list, this); + list._store = this._store; + return list; + }; + /** + * Wrap some method to add more feature + */ + + + SeriesData.prototype.wrapMethod = function (methodName, injectFunction) { + var originalMethod = this[methodName]; + + if (!isFunction(originalMethod)) { + return; + } + + this.__wrappedMethods = this.__wrappedMethods || []; + + this.__wrappedMethods.push(methodName); + + this[methodName] = function () { + var res = originalMethod.apply(this, arguments); + return injectFunction.apply(this, [res].concat(slice(arguments))); + }; + }; // ---------------------------------------------------------- + // A work around for internal method visiting private member. + // ---------------------------------------------------------- + + + SeriesData.internalField = function () { + prepareInvertedIndex = function (data) { + var invertedIndicesMap = data._invertedIndicesMap; + each(invertedIndicesMap, function (invertedIndices, dim) { + var dimInfo = data._dimInfos[dim]; // Currently, only dimensions that has ordinalMeta can create inverted indices. + + var ordinalMeta = dimInfo.ordinalMeta; + var store = data._store; + + if (ordinalMeta) { + invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array$1(ordinalMeta.categories.length); // The default value of TypedArray is 0. To avoid miss + // mapping to 0, we should set it as INDEX_NOT_FOUND. + + for (var i = 0; i < invertedIndices.length; i++) { + invertedIndices[i] = INDEX_NOT_FOUND; + } + + for (var i = 0; i < store.count(); i++) { + // Only support the case that all values are distinct. + invertedIndices[store.get(dimInfo.storeDimIndex, i)] = i; + } + } + }); + }; + + getIdNameFromStore = function (data, dimIdx, idx) { + return convertOptionIdName(data._getCategory(dimIdx, idx), null); + }; + /** + * @see the comment of `List['getId']`. + */ + + + getId = function (data, rawIndex) { + var id = data._idList[rawIndex]; + + if (id == null && data._idDimIdx != null) { + id = getIdNameFromStore(data, data._idDimIdx, rawIndex); + } + + if (id == null) { + id = ID_PREFIX + rawIndex; + } + + return id; + }; + + normalizeDimensions = function (dimensions) { + if (!isArray(dimensions)) { + dimensions = dimensions != null ? [dimensions] : []; + } + + return dimensions; + }; + /** + * Data in excludeDimensions is copied, otherwise transfered. + */ + + + cloneListForMapAndSample = function (original) { + var list = new SeriesData(original._schema ? original._schema : map$1(original.dimensions, original._getDimInfo, original), original.hostModel); // FIXME If needs stackedOn, value may already been stacked + + transferProperties(list, original); + return list; + }; + + transferProperties = function (target, source) { + each(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) { + if (source.hasOwnProperty(propName)) { + target[propName] = source[propName]; + } + }); + target.__wrappedMethods = source.__wrappedMethods; + each(CLONE_PROPERTIES, function (propName) { + target[propName] = clone(source[propName]); + }); + target._calculationInfo = extend({}, source._calculationInfo); + }; + + makeIdFromName = function (data, idx) { + var nameList = data._nameList; + var idList = data._idList; + var nameDimIdx = data._nameDimIdx; + var idDimIdx = data._idDimIdx; + var name = nameList[idx]; + var id = idList[idx]; + + if (name == null && nameDimIdx != null) { + nameList[idx] = name = getIdNameFromStore(data, nameDimIdx, idx); + } + + if (id == null && idDimIdx != null) { + idList[idx] = id = getIdNameFromStore(data, idDimIdx, idx); + } + + if (id == null && name != null) { + var nameRepeatCount = data._nameRepeatCount; + var nmCnt = nameRepeatCount[name] = (nameRepeatCount[name] || 0) + 1; + id = name; + + if (nmCnt > 1) { + id += '__ec__' + nmCnt; + } + + idList[idx] = id; + } + }; + }(); + + return SeriesData; + }(); + + /** + * For outside usage compat (like echarts-gl are using it). + */ + + function createDimensions(source, opt) { + return prepareSeriesDataSchema(source, opt).dimensions; + } + /** + * This method builds the relationship between: + * + "what the coord sys or series requires (see `coordDimensions`)", + * + "what the user defines (in `encode` and `dimensions`, see `opt.dimensionsDefine` and `opt.encodeDefine`)" + * + "what the data source provids (see `source`)". + * + * Some guess strategy will be adapted if user does not define something. + * If no 'value' dimension specified, the first no-named dimension will be + * named as 'value'. + * + * @return The results are always sorted by `storeDimIndex` asc. + */ + + function prepareSeriesDataSchema( // TODO: TYPE completeDimensions type + source, opt) { + if (!isSourceInstance(source)) { + source = createSourceFromSeriesDataOption(source); + } + + opt = opt || {}; + var sysDims = opt.coordDimensions || []; + var dimsDef = opt.dimensionsDefine || source.dimensionsDefine || []; + var coordDimNameMap = createHashMap(); + var resultList = []; + var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimensionsCount); // Try to ignore unsed dimensions if sharing a high dimension datastore + // 30 is an experience value. + + var omitUnusedDimensions = opt.canOmitUnusedDimensions && shouldOmitUnusedDimensions(dimCount); + var isUsingSourceDimensionsDef = dimsDef === source.dimensionsDefine; + var dataDimNameMap = isUsingSourceDimensionsDef ? ensureSourceDimNameMap(source) : createDimNameMap(dimsDef); + var encodeDef = opt.encodeDefine; + + if (!encodeDef && opt.encodeDefaulter) { + encodeDef = opt.encodeDefaulter(source, dimCount); + } + + var encodeDefMap = createHashMap(encodeDef); + var indicesMap = new CtorInt32Array(dimCount); + + for (var i = 0; i < indicesMap.length; i++) { + indicesMap[i] = -1; + } + + function getResultItem(dimIdx) { + var idx = indicesMap[dimIdx]; + + if (idx < 0) { + var dimDefItemRaw = dimsDef[dimIdx]; + var dimDefItem = isObject(dimDefItemRaw) ? dimDefItemRaw : { + name: dimDefItemRaw + }; + var resultItem = new SeriesDimensionDefine(); + var userDimName = dimDefItem.name; + + if (userDimName != null && dataDimNameMap.get(userDimName) != null) { + // Only if `series.dimensions` is defined in option + // displayName, will be set, and dimension will be diplayed vertically in + // tooltip by default. + resultItem.name = resultItem.displayName = userDimName; + } + + dimDefItem.type != null && (resultItem.type = dimDefItem.type); + dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName); + var newIdx = resultList.length; + indicesMap[dimIdx] = newIdx; + resultItem.storeDimIndex = dimIdx; + resultList.push(resultItem); + return resultItem; + } + + return resultList[idx]; + } + + if (!omitUnusedDimensions) { + for (var i = 0; i < dimCount; i++) { + getResultItem(i); + } + } // Set `coordDim` and `coordDimIndex` by `encodeDefMap` and normalize `encodeDefMap`. + + + encodeDefMap.each(function (dataDimsRaw, coordDim) { + var dataDims = normalizeToArray(dataDimsRaw).slice(); // Note: It is allowed that `dataDims.length` is `0`, e.g., options is + // `{encode: {x: -1, y: 1}}`. Should not filter anything in + // this case. + + if (dataDims.length === 1 && !isString(dataDims[0]) && dataDims[0] < 0) { + encodeDefMap.set(coordDim, false); + return; + } + + var validDataDims = encodeDefMap.set(coordDim, []); + each(dataDims, function (resultDimIdxOrName, idx) { + // The input resultDimIdx can be dim name or index. + var resultDimIdx = isString(resultDimIdxOrName) ? dataDimNameMap.get(resultDimIdxOrName) : resultDimIdxOrName; + + if (resultDimIdx != null && resultDimIdx < dimCount) { + validDataDims[idx] = resultDimIdx; + applyDim(getResultItem(resultDimIdx), coordDim, idx); + } + }); + }); // Apply templetes and default order from `sysDims`. + + var availDimIdx = 0; + each(sysDims, function (sysDimItemRaw) { + var coordDim; + var sysDimItemDimsDef; + var sysDimItemOtherDims; + var sysDimItem; + + if (isString(sysDimItemRaw)) { + coordDim = sysDimItemRaw; + sysDimItem = {}; + } else { + sysDimItem = sysDimItemRaw; + coordDim = sysDimItem.name; + var ordinalMeta = sysDimItem.ordinalMeta; + sysDimItem.ordinalMeta = null; + sysDimItem = extend({}, sysDimItem); + sysDimItem.ordinalMeta = ordinalMeta; // `coordDimIndex` should not be set directly. + + sysDimItemDimsDef = sysDimItem.dimsDef; + sysDimItemOtherDims = sysDimItem.otherDims; + sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex = sysDimItem.dimsDef = sysDimItem.otherDims = null; + } + + var dataDims = encodeDefMap.get(coordDim); // negative resultDimIdx means no need to mapping. + + if (dataDims === false) { + return; + } + + dataDims = normalizeToArray(dataDims); // dimensions provides default dim sequences. + + if (!dataDims.length) { + for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) { + while (availDimIdx < dimCount && getResultItem(availDimIdx).coordDim != null) { + availDimIdx++; + } + + availDimIdx < dimCount && dataDims.push(availDimIdx++); + } + } // Apply templates. + + + each(dataDims, function (resultDimIdx, coordDimIndex) { + var resultItem = getResultItem(resultDimIdx); // Coordinate system has a higher priority on dim type than source. + + if (isUsingSourceDimensionsDef && sysDimItem.type != null) { + resultItem.type = sysDimItem.type; + } + + applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex); + + if (resultItem.name == null && sysDimItemDimsDef) { + var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex]; + !isObject(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = { + name: sysDimItemDimsDefItem + }); + resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name; + resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip; + } // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}} + + + sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims); + }); + }); + + function applyDim(resultItem, coordDim, coordDimIndex) { + if (VISUAL_DIMENSIONS.get(coordDim) != null) { + resultItem.otherDims[coordDim] = coordDimIndex; + } else { + resultItem.coordDim = coordDim; + resultItem.coordDimIndex = coordDimIndex; + coordDimNameMap.set(coordDim, true); + } + } // Make sure the first extra dim is 'value'. + + + var generateCoord = opt.generateCoord; + var generateCoordCount = opt.generateCoordCount; + var fromZero = generateCoordCount != null; + generateCoordCount = generateCoord ? generateCoordCount || 1 : 0; + var extra = generateCoord || 'value'; + + function ifNoNameFillWithCoordName(resultItem) { + if (resultItem.name == null) { + // Duplication will be removed in the next step. + resultItem.name = resultItem.coordDim; + } + } // Set dim `name` and other `coordDim` and other props. + + + if (!omitUnusedDimensions) { + for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) { + var resultItem = getResultItem(resultDimIdx); + var coordDim = resultItem.coordDim; + + if (coordDim == null) { + // TODO no need to generate coordDim for isExtraCoord? + resultItem.coordDim = genCoordDimName(extra, coordDimNameMap, fromZero); + resultItem.coordDimIndex = 0; // Series specified generateCoord is using out. + + if (!generateCoord || generateCoordCount <= 0) { + resultItem.isExtraCoord = true; + } + + generateCoordCount--; + } + + ifNoNameFillWithCoordName(resultItem); + + if (resultItem.type == null && (guessOrdinal(source, resultDimIdx) === BE_ORDINAL.Must // Consider the case: + // { + // dataset: {source: [ + // ['2001', 123], + // ['2002', 456], + // ... + // ['The others', 987], + // ]}, + // series: {type: 'pie'} + // } + // The first colum should better be treated as a "ordinal" although it + // might not able to be detected as an "ordinal" by `guessOrdinal`. + || resultItem.isExtraCoord && (resultItem.otherDims.itemName != null || resultItem.otherDims.seriesName != null))) { + resultItem.type = 'ordinal'; + } + } + } else { + each(resultList, function (resultItem) { + // PENDING: guessOrdinal or let user specify type: 'ordinal' manually? + ifNoNameFillWithCoordName(resultItem); + }); // Sort dimensions: there are some rule that use the last dim as label, + // and for some latter travel process easier. + + resultList.sort(function (item0, item1) { + return item0.storeDimIndex - item1.storeDimIndex; + }); + } + + removeDuplication(resultList); + return new SeriesDataSchema({ + source: source, + dimensions: resultList, + fullDimensionCount: dimCount, + dimensionOmitted: omitUnusedDimensions + }); + } + + function removeDuplication(result) { + var duplicationMap = createHashMap(); + + for (var i = 0; i < result.length; i++) { + var dim = result[i]; + var dimOriginalName = dim.name; + var count = duplicationMap.get(dimOriginalName) || 0; + + if (count > 0) { + // Starts from 0. + dim.name = dimOriginalName + (count - 1); + } + + count++; + duplicationMap.set(dimOriginalName, count); + } + } // ??? TODO + // Originally detect dimCount by data[0]. Should we + // optimize it to only by sysDims and dimensions and encode. + // So only necessary dims will be initialized. + // But + // (1) custom series should be considered. where other dims + // may be visited. + // (2) sometimes user need to calcualte bubble size or use visualMap + // on other dimensions besides coordSys needed. + // So, dims that is not used by system, should be shared in data store? + + + function getDimCount(source, sysDims, dimsDef, optDimCount) { + // Note that the result dimCount should not small than columns count + // of data, otherwise `dataDimNameMap` checking will be incorrect. + var dimCount = Math.max(source.dimensionsDetectedCount || 1, sysDims.length, dimsDef.length, optDimCount || 0); + each(sysDims, function (sysDimItem) { + var sysDimItemDimsDef; + + if (isObject(sysDimItem) && (sysDimItemDimsDef = sysDimItem.dimsDef)) { + dimCount = Math.max(dimCount, sysDimItemDimsDef.length); + } + }); + return dimCount; + } + + function genCoordDimName(name, map, fromZero) { + var mapData = map.data; + + if (fromZero || mapData.hasOwnProperty(name)) { + var i = 0; + + while (mapData.hasOwnProperty(name + i)) { + i++; + } + + name += i; + } + + map.set(name, true); + return name; + } + + /** + * @class + * For example: + * { + * coordSysName: 'cartesian2d', + * coordSysDims: ['x', 'y', ...], + * axisMap: HashMap({ + * x: xAxisModel, + * y: yAxisModel + * }), + * categoryAxisMap: HashMap({ + * x: xAxisModel, + * y: undefined + * }), + * // The index of the first category axis in `coordSysDims`. + * // `null/undefined` means no category axis exists. + * firstCategoryDimIndex: 1, + * // To replace user specified encode. + * } + */ + + var CoordSysInfo = + /** @class */ + function () { + function CoordSysInfo(coordSysName) { + this.coordSysDims = []; + this.axisMap = createHashMap(); + this.categoryAxisMap = createHashMap(); + this.coordSysName = coordSysName; + } + + return CoordSysInfo; + }(); + + function getCoordSysInfoBySeries(seriesModel) { + var coordSysName = seriesModel.get('coordinateSystem'); + var result = new CoordSysInfo(coordSysName); + var fetch = fetchers[coordSysName]; + + if (fetch) { + fetch(seriesModel, result, result.axisMap, result.categoryAxisMap); + return result; + } + } + var fetchers = { + cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) { + var xAxisModel = seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0]; + var yAxisModel = seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[0]; + + if ("development" !== 'production') { + if (!xAxisModel) { + throw new Error('xAxis "' + retrieve(seriesModel.get('xAxisIndex'), seriesModel.get('xAxisId'), 0) + '" not found'); + } + + if (!yAxisModel) { + throw new Error('yAxis "' + retrieve(seriesModel.get('xAxisIndex'), seriesModel.get('yAxisId'), 0) + '" not found'); + } + } + + result.coordSysDims = ['x', 'y']; + axisMap.set('x', xAxisModel); + axisMap.set('y', yAxisModel); + + if (isCategory(xAxisModel)) { + categoryAxisMap.set('x', xAxisModel); + result.firstCategoryDimIndex = 0; + } + + if (isCategory(yAxisModel)) { + categoryAxisMap.set('y', yAxisModel); + result.firstCategoryDimIndex == null && (result.firstCategoryDimIndex = 1); + } + }, + singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) { + var singleAxisModel = seriesModel.getReferringComponents('singleAxis', SINGLE_REFERRING).models[0]; + + if ("development" !== 'production') { + if (!singleAxisModel) { + throw new Error('singleAxis should be specified.'); + } + } + + result.coordSysDims = ['single']; + axisMap.set('single', singleAxisModel); + + if (isCategory(singleAxisModel)) { + categoryAxisMap.set('single', singleAxisModel); + result.firstCategoryDimIndex = 0; + } + }, + polar: function (seriesModel, result, axisMap, categoryAxisMap) { + var polarModel = seriesModel.getReferringComponents('polar', SINGLE_REFERRING).models[0]; + var radiusAxisModel = polarModel.findAxisModel('radiusAxis'); + var angleAxisModel = polarModel.findAxisModel('angleAxis'); + + if ("development" !== 'production') { + if (!angleAxisModel) { + throw new Error('angleAxis option not found'); + } + + if (!radiusAxisModel) { + throw new Error('radiusAxis option not found'); + } + } + + result.coordSysDims = ['radius', 'angle']; + axisMap.set('radius', radiusAxisModel); + axisMap.set('angle', angleAxisModel); + + if (isCategory(radiusAxisModel)) { + categoryAxisMap.set('radius', radiusAxisModel); + result.firstCategoryDimIndex = 0; + } + + if (isCategory(angleAxisModel)) { + categoryAxisMap.set('angle', angleAxisModel); + result.firstCategoryDimIndex == null && (result.firstCategoryDimIndex = 1); + } + }, + geo: function (seriesModel, result, axisMap, categoryAxisMap) { + result.coordSysDims = ['lng', 'lat']; + }, + parallel: function (seriesModel, result, axisMap, categoryAxisMap) { + var ecModel = seriesModel.ecModel; + var parallelModel = ecModel.getComponent('parallel', seriesModel.get('parallelIndex')); + var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice(); + each(parallelModel.parallelAxisIndex, function (axisIndex, index) { + var axisModel = ecModel.getComponent('parallelAxis', axisIndex); + var axisDim = coordSysDims[index]; + axisMap.set(axisDim, axisModel); + + if (isCategory(axisModel)) { + categoryAxisMap.set(axisDim, axisModel); + + if (result.firstCategoryDimIndex == null) { + result.firstCategoryDimIndex = index; + } + } + }); + } + }; + + function isCategory(axisModel) { + return axisModel.get('type') === 'category'; + } + + /** + * Note that it is too complicated to support 3d stack by value + * (have to create two-dimension inverted index), so in 3d case + * we just support that stacked by index. + * + * @param seriesModel + * @param dimensionsInput The same as the input of . + * The input will be modified. + * @param opt + * @param opt.stackedCoordDimension Specify a coord dimension if needed. + * @param opt.byIndex=false + * @return calculationInfo + * { + * stackedDimension: string + * stackedByDimension: string + * isStackedByIndex: boolean + * stackedOverDimension: string + * stackResultDimension: string + * } + */ + + function enableDataStack(seriesModel, dimensionsInput, opt) { + opt = opt || {}; + var byIndex = opt.byIndex; + var stackedCoordDimension = opt.stackedCoordDimension; + var dimensionDefineList; + var schema; + var store; + + if (isLegacyDimensionsInput(dimensionsInput)) { + dimensionDefineList = dimensionsInput; + } else { + schema = dimensionsInput.schema; + dimensionDefineList = schema.dimensions; + store = dimensionsInput.store; + } // Compatibal: when `stack` is set as '', do not stack. + + + var mayStack = !!(seriesModel && seriesModel.get('stack')); + var stackedByDimInfo; + var stackedDimInfo; + var stackResultDimension; + var stackedOverDimension; + each(dimensionDefineList, function (dimensionInfo, index) { + if (isString(dimensionInfo)) { + dimensionDefineList[index] = dimensionInfo = { + name: dimensionInfo + }; + } + + if (mayStack && !dimensionInfo.isExtraCoord) { + // Find the first ordinal dimension as the stackedByDimInfo. + if (!byIndex && !stackedByDimInfo && dimensionInfo.ordinalMeta) { + stackedByDimInfo = dimensionInfo; + } // Find the first stackable dimension as the stackedDimInfo. + + + if (!stackedDimInfo && dimensionInfo.type !== 'ordinal' && dimensionInfo.type !== 'time' && (!stackedCoordDimension || stackedCoordDimension === dimensionInfo.coordDim)) { + stackedDimInfo = dimensionInfo; + } + } + }); + + if (stackedDimInfo && !byIndex && !stackedByDimInfo) { + // Compatible with previous design, value axis (time axis) only stack by index. + // It may make sense if the user provides elaborately constructed data. + byIndex = true; + } // Add stack dimension, they can be both calculated by coordinate system in `unionExtent`. + // That put stack logic in List is for using conveniently in echarts extensions, but it + // might not be a good way. + + + if (stackedDimInfo) { + // Use a weird name that not duplicated with other names. + // Also need to use seriesModel.id as postfix because different + // series may share same data store. The stack dimension needs to be distinguished. + stackResultDimension = '__\0ecstackresult_' + seriesModel.id; + stackedOverDimension = '__\0ecstackedover_' + seriesModel.id; // Create inverted index to fast query index by value. + + if (stackedByDimInfo) { + stackedByDimInfo.createInvertedIndices = true; + } + + var stackedDimCoordDim_1 = stackedDimInfo.coordDim; + var stackedDimType = stackedDimInfo.type; + var stackedDimCoordIndex_1 = 0; + each(dimensionDefineList, function (dimensionInfo) { + if (dimensionInfo.coordDim === stackedDimCoordDim_1) { + stackedDimCoordIndex_1++; + } + }); + var stackedOverDimensionDefine = { + name: stackResultDimension, + coordDim: stackedDimCoordDim_1, + coordDimIndex: stackedDimCoordIndex_1, + type: stackedDimType, + isExtraCoord: true, + isCalculationCoord: true, + storeDimIndex: dimensionDefineList.length + }; + var stackResultDimensionDefine = { + name: stackedOverDimension, + // This dimension contains stack base (generally, 0), so do not set it as + // `stackedDimCoordDim` to avoid extent calculation, consider log scale. + coordDim: stackedOverDimension, + coordDimIndex: stackedDimCoordIndex_1 + 1, + type: stackedDimType, + isExtraCoord: true, + isCalculationCoord: true, + storeDimIndex: dimensionDefineList.length + 1 + }; + + if (schema) { + if (store) { + stackedOverDimensionDefine.storeDimIndex = store.ensureCalculationDimension(stackedOverDimension, stackedDimType); + stackResultDimensionDefine.storeDimIndex = store.ensureCalculationDimension(stackResultDimension, stackedDimType); + } + + schema.appendCalculationDimension(stackedOverDimensionDefine); + schema.appendCalculationDimension(stackResultDimensionDefine); + } else { + dimensionDefineList.push(stackedOverDimensionDefine); + dimensionDefineList.push(stackResultDimensionDefine); + } + } + + return { + stackedDimension: stackedDimInfo && stackedDimInfo.name, + stackedByDimension: stackedByDimInfo && stackedByDimInfo.name, + isStackedByIndex: byIndex, + stackedOverDimension: stackedOverDimension, + stackResultDimension: stackResultDimension + }; + } + + function isLegacyDimensionsInput(dimensionsInput) { + return !isSeriesDataSchema(dimensionsInput.schema); + } + + function isDimensionStacked(data, stackedDim) { + // Each single series only maps to one pair of axis. So we do not need to + // check stackByDim, whatever stacked by a dimension or stacked by index. + return !!stackedDim && stackedDim === data.getCalculationInfo('stackedDimension'); + } + function getStackedDimension(data, targetDim) { + return isDimensionStacked(data, targetDim) ? data.getCalculationInfo('stackResultDimension') : targetDim; + } + + function getCoordSysDimDefs(seriesModel, coordSysInfo) { + var coordSysName = seriesModel.get('coordinateSystem'); + var registeredCoordSys = CoordinateSystemManager.get(coordSysName); + var coordSysDimDefs; + + if (coordSysInfo && coordSysInfo.coordSysDims) { + coordSysDimDefs = map(coordSysInfo.coordSysDims, function (dim) { + var dimInfo = { + name: dim + }; + var axisModel = coordSysInfo.axisMap.get(dim); + + if (axisModel) { + var axisType = axisModel.get('type'); + dimInfo.type = getDimensionTypeByAxis(axisType); + } + + return dimInfo; + }); + } + + if (!coordSysDimDefs) { + // Get dimensions from registered coordinate system + coordSysDimDefs = registeredCoordSys && (registeredCoordSys.getDimensionsInfo ? registeredCoordSys.getDimensionsInfo() : registeredCoordSys.dimensions.slice()) || ['x', 'y']; + } + + return coordSysDimDefs; + } + + function injectOrdinalMeta(dimInfoList, createInvertedIndices, coordSysInfo) { + var firstCategoryDimIndex; + var hasNameEncode; + coordSysInfo && each(dimInfoList, function (dimInfo, dimIndex) { + var coordDim = dimInfo.coordDim; + var categoryAxisModel = coordSysInfo.categoryAxisMap.get(coordDim); + + if (categoryAxisModel) { + if (firstCategoryDimIndex == null) { + firstCategoryDimIndex = dimIndex; + } + + dimInfo.ordinalMeta = categoryAxisModel.getOrdinalMeta(); + + if (createInvertedIndices) { + dimInfo.createInvertedIndices = true; + } + } + + if (dimInfo.otherDims.itemName != null) { + hasNameEncode = true; + } + }); + + if (!hasNameEncode && firstCategoryDimIndex != null) { + dimInfoList[firstCategoryDimIndex].otherDims.itemName = 0; + } + + return firstCategoryDimIndex; + } + /** + * Caution: there are side effects to `sourceManager` in this method. + * Should better only be called in `Series['getInitialData']`. + */ + + + function createSeriesData(sourceRaw, seriesModel, opt) { + opt = opt || {}; + var sourceManager = seriesModel.getSourceManager(); + var source; + var isOriginalSource = false; + + if (sourceRaw) { + isOriginalSource = true; + source = createSourceFromSeriesDataOption(sourceRaw); + } else { + source = sourceManager.getSource(); // Is series.data. not dataset. + + isOriginalSource = source.sourceFormat === SOURCE_FORMAT_ORIGINAL; + } + + var coordSysInfo = getCoordSysInfoBySeries(seriesModel); + var coordSysDimDefs = getCoordSysDimDefs(seriesModel, coordSysInfo); + var useEncodeDefaulter = opt.useEncodeDefaulter; + var encodeDefaulter = isFunction(useEncodeDefaulter) ? useEncodeDefaulter : useEncodeDefaulter ? curry(makeSeriesEncodeForAxisCoordSys, coordSysDimDefs, seriesModel) : null; + var createDimensionOptions = { + coordDimensions: coordSysDimDefs, + generateCoord: opt.generateCoord, + encodeDefine: seriesModel.getEncode(), + encodeDefaulter: encodeDefaulter, + canOmitUnusedDimensions: !isOriginalSource + }; + var schema = prepareSeriesDataSchema(source, createDimensionOptions); + var firstCategoryDimIndex = injectOrdinalMeta(schema.dimensions, opt.createInvertedIndices, coordSysInfo); + var store = !isOriginalSource ? sourceManager.getSharedDataStore(schema) : null; + var stackCalculationInfo = enableDataStack(seriesModel, { + schema: schema, + store: store + }); + var data = new SeriesData(schema, seriesModel); + data.setCalculationInfo(stackCalculationInfo); + var dimValueGetter = firstCategoryDimIndex != null && isNeedCompleteOrdinalData(source) ? function (itemOpt, dimName, dataIndex, dimIndex) { + // Use dataIndex as ordinal value in categoryAxis + return dimIndex === firstCategoryDimIndex ? dataIndex : this.defaultDimValueGetter(itemOpt, dimName, dataIndex, dimIndex); + } : null; + data.hasItemOption = false; + data.initData( // Try to reuse the data store in sourceManager if using dataset. + isOriginalSource ? source : store, null, dimValueGetter); + return data; + } + + function isNeedCompleteOrdinalData(source) { + if (source.sourceFormat === SOURCE_FORMAT_ORIGINAL) { + var sampleItem = firstDataNotNull(source.data || []); + return !isArray(getDataItemValue(sampleItem)); + } + } + + function firstDataNotNull(arr) { + var i = 0; + + while (i < arr.length && arr[i] == null) { + i++; + } + + return arr[i]; + } + + var Scale = + /** @class */ + function () { + function Scale(setting) { + this._setting = setting || {}; + this._extent = [Infinity, -Infinity]; + } + + Scale.prototype.getSetting = function (name) { + return this._setting[name]; + }; + /** + * Set extent from data + */ + + + Scale.prototype.unionExtent = function (other) { + var extent = this._extent; + other[0] < extent[0] && (extent[0] = other[0]); + other[1] > extent[1] && (extent[1] = other[1]); // not setExtent because in log axis it may transformed to power + // this.setExtent(extent[0], extent[1]); + }; + /** + * Set extent from data + */ + + + Scale.prototype.unionExtentFromData = function (data, dim) { + this.unionExtent(data.getApproximateExtent(dim)); + }; + /** + * Get extent + * + * Extent is always in increase order. + */ + + + Scale.prototype.getExtent = function () { + return this._extent.slice(); + }; + /** + * Set extent + */ + + + Scale.prototype.setExtent = function (start, end) { + var thisExtent = this._extent; + + if (!isNaN(start)) { + thisExtent[0] = start; + } + + if (!isNaN(end)) { + thisExtent[1] = end; + } + }; + /** + * If value is in extent range + */ + + + Scale.prototype.isInExtentRange = function (value) { + return this._extent[0] <= value && this._extent[1] >= value; + }; + /** + * When axis extent depends on data and no data exists, + * axis ticks should not be drawn, which is named 'blank'. + */ + + + Scale.prototype.isBlank = function () { + return this._isBlank; + }; + /** + * When axis extent depends on data and no data exists, + * axis ticks should not be drawn, which is named 'blank'. + */ + + + Scale.prototype.setBlank = function (isBlank) { + this._isBlank = isBlank; + }; + + return Scale; + }(); + + enableClassManagement(Scale); + + var uidBase = 0; + + var OrdinalMeta = + /** @class */ + function () { + function OrdinalMeta(opt) { + this.categories = opt.categories || []; + this._needCollect = opt.needCollect; + this._deduplication = opt.deduplication; + this.uid = ++uidBase; + } + + OrdinalMeta.createByAxisModel = function (axisModel) { + var option = axisModel.option; + var data = option.data; + var categories = data && map(data, getName); + return new OrdinalMeta({ + categories: categories, + needCollect: !categories, + // deduplication is default in axis. + deduplication: option.dedplication !== false + }); + }; + + OrdinalMeta.prototype.getOrdinal = function (category) { + // @ts-ignore + return this._getOrCreateMap().get(category); + }; + /** + * @return The ordinal. If not found, return NaN. + */ + + + OrdinalMeta.prototype.parseAndCollect = function (category) { + var index; + var needCollect = this._needCollect; // The value of category dim can be the index of the given category set. + // This feature is only supported when !needCollect, because we should + // consider a common case: a value is 2017, which is a number but is + // expected to be tread as a category. This case usually happen in dataset, + // where it happent to be no need of the index feature. + + if (!isString(category) && !needCollect) { + return category; + } // Optimize for the scenario: + // category is ['2012-01-01', '2012-01-02', ...], where the input + // data has been ensured not duplicate and is large data. + // Notice, if a dataset dimension provide categroies, usually echarts + // should remove duplication except user tell echarts dont do that + // (set axis.deduplication = false), because echarts do not know whether + // the values in the category dimension has duplication (consider the + // parallel-aqi example) + + + if (needCollect && !this._deduplication) { + index = this.categories.length; + this.categories[index] = category; + return index; + } + + var map = this._getOrCreateMap(); // @ts-ignore + + + index = map.get(category); + + if (index == null) { + if (needCollect) { + index = this.categories.length; + this.categories[index] = category; // @ts-ignore + + map.set(category, index); + } else { + index = NaN; + } + } + + return index; + }; // Consider big data, do not create map until needed. + + + OrdinalMeta.prototype._getOrCreateMap = function () { + return this._map || (this._map = createHashMap(this.categories)); + }; + + return OrdinalMeta; + }(); + + function getName(obj) { + if (isObject(obj) && obj.value != null) { + return obj.value; + } else { + return obj + ''; + } + } + + function isValueNice(val) { + var exp10 = Math.pow(10, quantityExponent(Math.abs(val))); + var f = Math.abs(val / exp10); + return f === 0 || f === 1 || f === 2 || f === 3 || f === 5; + } + function isIntervalOrLogScale(scale) { + return scale.type === 'interval' || scale.type === 'log'; + } + /** + * @param extent Both extent[0] and extent[1] should be valid number. + * Should be extent[0] < extent[1]. + * @param splitNumber splitNumber should be >= 1. + */ + + function intervalScaleNiceTicks(extent, splitNumber, minInterval, maxInterval) { + var result = {}; + var span = extent[1] - extent[0]; + var interval = result.interval = nice(span / splitNumber, true); + + if (minInterval != null && interval < minInterval) { + interval = result.interval = minInterval; + } + + if (maxInterval != null && interval > maxInterval) { + interval = result.interval = maxInterval; + } // Tow more digital for tick. + + + var precision = result.intervalPrecision = getIntervalPrecision(interval); // Niced extent inside original extent + + var niceTickExtent = result.niceTickExtent = [round(Math.ceil(extent[0] / interval) * interval, precision), round(Math.floor(extent[1] / interval) * interval, precision)]; + fixExtent(niceTickExtent, extent); + return result; + } + function increaseInterval(interval) { + var exp10 = Math.pow(10, quantityExponent(interval)); // Increase interval + + var f = interval / exp10; + + if (!f) { + f = 1; + } else if (f === 2) { + f = 3; + } else if (f === 3) { + f = 5; + } else { + // f is 1 or 5 + f *= 2; + } + + return round(f * exp10); + } + /** + * @return interval precision + */ + + function getIntervalPrecision(interval) { + // Tow more digital for tick. + return getPrecision(interval) + 2; + } + + function clamp(niceTickExtent, idx, extent) { + niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]); + } // In some cases (e.g., splitNumber is 1), niceTickExtent may be out of extent. + + + function fixExtent(niceTickExtent, extent) { + !isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]); + !isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]); + clamp(niceTickExtent, 0, extent); + clamp(niceTickExtent, 1, extent); + + if (niceTickExtent[0] > niceTickExtent[1]) { + niceTickExtent[0] = niceTickExtent[1]; + } + } + function contain$1(val, extent) { + return val >= extent[0] && val <= extent[1]; + } + function normalize$1(val, extent) { + if (extent[1] === extent[0]) { + return 0.5; + } + + return (val - extent[0]) / (extent[1] - extent[0]); + } + function scale$2(val, extent) { + return val * (extent[1] - extent[0]) + extent[0]; + } + + var OrdinalScale = + /** @class */ + function (_super) { + __extends(OrdinalScale, _super); + + function OrdinalScale(setting) { + var _this = _super.call(this, setting) || this; + + _this.type = 'ordinal'; + + var ordinalMeta = _this.getSetting('ordinalMeta'); // Caution: Should not use instanceof, consider ec-extensions using + // import approach to get OrdinalMeta class. + + + if (!ordinalMeta) { + ordinalMeta = new OrdinalMeta({}); + } + + if (isArray(ordinalMeta)) { + ordinalMeta = new OrdinalMeta({ + categories: map(ordinalMeta, function (item) { + return isObject(item) ? item.value : item; + }) + }); + } + + _this._ordinalMeta = ordinalMeta; + _this._extent = _this.getSetting('extent') || [0, ordinalMeta.categories.length - 1]; + return _this; + } + + OrdinalScale.prototype.parse = function (val) { + // Caution: Math.round(null) will return `0` rather than `NaN` + if (val == null) { + return NaN; + } + + return isString(val) ? this._ordinalMeta.getOrdinal(val) // val might be float. + : Math.round(val); + }; + + OrdinalScale.prototype.contain = function (rank) { + rank = this.parse(rank); + return contain$1(rank, this._extent) && this._ordinalMeta.categories[rank] != null; + }; + /** + * Normalize given rank or name to linear [0, 1] + * @param val raw ordinal number. + * @return normalized value in [0, 1]. + */ + + + OrdinalScale.prototype.normalize = function (val) { + val = this._getTickNumber(this.parse(val)); + return normalize$1(val, this._extent); + }; + /** + * @param val normalized value in [0, 1]. + * @return raw ordinal number. + */ + + + OrdinalScale.prototype.scale = function (val) { + val = Math.round(scale$2(val, this._extent)); + return this.getRawOrdinalNumber(val); + }; + + OrdinalScale.prototype.getTicks = function () { + var ticks = []; + var extent = this._extent; + var rank = extent[0]; + + while (rank <= extent[1]) { + ticks.push({ + value: rank + }); + rank++; + } + + return ticks; + }; + + OrdinalScale.prototype.getMinorTicks = function (splitNumber) { + // Not support. + return; + }; + /** + * @see `Ordinal['_ordinalNumbersByTick']` + */ + + + OrdinalScale.prototype.setSortInfo = function (info) { + if (info == null) { + this._ordinalNumbersByTick = this._ticksByOrdinalNumber = null; + return; + } + + var infoOrdinalNumbers = info.ordinalNumbers; + var ordinalsByTick = this._ordinalNumbersByTick = []; + var ticksByOrdinal = this._ticksByOrdinalNumber = []; // Unnecessary support negative tick in `realtimeSort`. + + var tickNum = 0; + var allCategoryLen = this._ordinalMeta.categories.length; + + for (var len = Math.min(allCategoryLen, infoOrdinalNumbers.length); tickNum < len; ++tickNum) { + var ordinalNumber = infoOrdinalNumbers[tickNum]; + ordinalsByTick[tickNum] = ordinalNumber; + ticksByOrdinal[ordinalNumber] = tickNum; + } // Handle that `series.data` only covers part of the `axis.category.data`. + + + var unusedOrdinal = 0; + + for (; tickNum < allCategoryLen; ++tickNum) { + while (ticksByOrdinal[unusedOrdinal] != null) { + unusedOrdinal++; + } + ordinalsByTick.push(unusedOrdinal); + ticksByOrdinal[unusedOrdinal] = tickNum; + } + }; + + OrdinalScale.prototype._getTickNumber = function (ordinal) { + var ticksByOrdinalNumber = this._ticksByOrdinalNumber; // also support ordinal out of range of `ordinalMeta.categories.length`, + // where ordinal numbers are used as tick value directly. + + return ticksByOrdinalNumber && ordinal >= 0 && ordinal < ticksByOrdinalNumber.length ? ticksByOrdinalNumber[ordinal] : ordinal; + }; + /** + * @usage + * ```js + * const ordinalNumber = ordinalScale.getRawOrdinalNumber(tickVal); + * + * // case0 + * const rawOrdinalValue = axisModel.getCategories()[ordinalNumber]; + * // case1 + * const rawOrdinalValue = this._ordinalMeta.categories[ordinalNumber]; + * // case2 + * const coord = axis.dataToCoord(ordinalNumber); + * ``` + * + * @param {OrdinalNumber} tickNumber index of display + */ + + + OrdinalScale.prototype.getRawOrdinalNumber = function (tickNumber) { + var ordinalNumbersByTick = this._ordinalNumbersByTick; // tickNumber may be out of range, e.g., when axis max is larger than `ordinalMeta.categories.length`., + // where ordinal numbers are used as tick value directly. + + return ordinalNumbersByTick && tickNumber >= 0 && tickNumber < ordinalNumbersByTick.length ? ordinalNumbersByTick[tickNumber] : tickNumber; + }; + /** + * Get item on tick + */ + + + OrdinalScale.prototype.getLabel = function (tick) { + if (!this.isBlank()) { + var ordinalNumber = this.getRawOrdinalNumber(tick.value); + var cateogry = this._ordinalMeta.categories[ordinalNumber]; // Note that if no data, ordinalMeta.categories is an empty array. + // Return empty if it's not exist. + + return cateogry == null ? '' : cateogry + ''; + } + }; + + OrdinalScale.prototype.count = function () { + return this._extent[1] - this._extent[0] + 1; + }; + + OrdinalScale.prototype.unionExtentFromData = function (data, dim) { + this.unionExtent(data.getApproximateExtent(dim)); + }; + /** + * @override + * If value is in extent range + */ + + + OrdinalScale.prototype.isInExtentRange = function (value) { + value = this._getTickNumber(value); + return this._extent[0] <= value && this._extent[1] >= value; + }; + + OrdinalScale.prototype.getOrdinalMeta = function () { + return this._ordinalMeta; + }; + + OrdinalScale.prototype.calcNiceTicks = function () {}; + + OrdinalScale.prototype.calcNiceExtent = function () {}; + + OrdinalScale.type = 'ordinal'; + return OrdinalScale; + }(Scale); + + Scale.registerClass(OrdinalScale); + + var roundNumber = round; + + var IntervalScale = + /** @class */ + function (_super) { + __extends(IntervalScale, _super); + + function IntervalScale() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'interval'; // Step is calculated in adjustExtent. + + _this._interval = 0; + _this._intervalPrecision = 2; + return _this; + } + + IntervalScale.prototype.parse = function (val) { + return val; + }; + + IntervalScale.prototype.contain = function (val) { + return contain$1(val, this._extent); + }; + + IntervalScale.prototype.normalize = function (val) { + return normalize$1(val, this._extent); + }; + + IntervalScale.prototype.scale = function (val) { + return scale$2(val, this._extent); + }; + + IntervalScale.prototype.setExtent = function (start, end) { + var thisExtent = this._extent; // start,end may be a Number like '25',so... + + if (!isNaN(start)) { + thisExtent[0] = parseFloat(start); + } + + if (!isNaN(end)) { + thisExtent[1] = parseFloat(end); + } + }; + + IntervalScale.prototype.unionExtent = function (other) { + var extent = this._extent; + other[0] < extent[0] && (extent[0] = other[0]); + other[1] > extent[1] && (extent[1] = other[1]); // unionExtent may called by it's sub classes + + this.setExtent(extent[0], extent[1]); + }; + + IntervalScale.prototype.getInterval = function () { + return this._interval; + }; + + IntervalScale.prototype.setInterval = function (interval) { + this._interval = interval; // Dropped auto calculated niceExtent and use user setted extent + // We assume user wan't to set both interval, min, max to get a better result + + this._niceExtent = this._extent.slice(); + this._intervalPrecision = getIntervalPrecision(interval); + }; + /** + * @param expandToNicedExtent Whether expand the ticks to niced extent. + */ + + + IntervalScale.prototype.getTicks = function (expandToNicedExtent) { + var interval = this._interval; + var extent = this._extent; + var niceTickExtent = this._niceExtent; + var intervalPrecision = this._intervalPrecision; + var ticks = []; // If interval is 0, return []; + + if (!interval) { + return ticks; + } // Consider this case: using dataZoom toolbox, zoom and zoom. + + + var safeLimit = 10000; + + if (extent[0] < niceTickExtent[0]) { + if (expandToNicedExtent) { + ticks.push({ + value: roundNumber(niceTickExtent[0] - interval, intervalPrecision) + }); + } else { + ticks.push({ + value: extent[0] + }); + } + } + + var tick = niceTickExtent[0]; + + while (tick <= niceTickExtent[1]) { + ticks.push({ + value: tick + }); // Avoid rounding error + + tick = roundNumber(tick + interval, intervalPrecision); + + if (tick === ticks[ticks.length - 1].value) { + // Consider out of safe float point, e.g., + // -3711126.9907707 + 2e-10 === -3711126.9907707 + break; + } + + if (ticks.length > safeLimit) { + return []; + } + } // Consider this case: the last item of ticks is smaller + // than niceTickExtent[1] and niceTickExtent[1] === extent[1]. + + + var lastNiceTick = ticks.length ? ticks[ticks.length - 1].value : niceTickExtent[1]; + + if (extent[1] > lastNiceTick) { + if (expandToNicedExtent) { + ticks.push({ + value: roundNumber(lastNiceTick + interval, intervalPrecision) + }); + } else { + ticks.push({ + value: extent[1] + }); + } + } + + return ticks; + }; + + IntervalScale.prototype.getMinorTicks = function (splitNumber) { + var ticks = this.getTicks(true); + var minorTicks = []; + var extent = this.getExtent(); + + for (var i = 1; i < ticks.length; i++) { + var nextTick = ticks[i]; + var prevTick = ticks[i - 1]; + var count = 0; + var minorTicksGroup = []; + var interval = nextTick.value - prevTick.value; + var minorInterval = interval / splitNumber; + + while (count < splitNumber - 1) { + var minorTick = roundNumber(prevTick.value + (count + 1) * minorInterval); // For the first and last interval. The count may be less than splitNumber. + + if (minorTick > extent[0] && minorTick < extent[1]) { + minorTicksGroup.push(minorTick); + } + + count++; + } + + minorTicks.push(minorTicksGroup); + } + + return minorTicks; + }; + /** + * @param opt.precision If 'auto', use nice presision. + * @param opt.pad returns 1.50 but not 1.5 if precision is 2. + */ + + + IntervalScale.prototype.getLabel = function (data, opt) { + if (data == null) { + return ''; + } + + var precision = opt && opt.precision; + + if (precision == null) { + precision = getPrecision(data.value) || 0; + } else if (precision === 'auto') { + // Should be more precise then tick. + precision = this._intervalPrecision; + } // (1) If `precision` is set, 12.005 should be display as '12.00500'. + // (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'. + + + var dataNum = roundNumber(data.value, precision, true); + return addCommas(dataNum); + }; + /** + * @param splitNumber By default `5`. + */ + + + IntervalScale.prototype.calcNiceTicks = function (splitNumber, minInterval, maxInterval) { + splitNumber = splitNumber || 5; + var extent = this._extent; + var span = extent[1] - extent[0]; + + if (!isFinite(span)) { + return; + } // User may set axis min 0 and data are all negative + // FIXME If it needs to reverse ? + + + if (span < 0) { + span = -span; + extent.reverse(); + } + + var result = intervalScaleNiceTicks(extent, splitNumber, minInterval, maxInterval); + this._intervalPrecision = result.intervalPrecision; + this._interval = result.interval; + this._niceExtent = result.niceTickExtent; + }; + + IntervalScale.prototype.calcNiceExtent = function (opt) { + var extent = this._extent; // If extent start and end are same, expand them + + if (extent[0] === extent[1]) { + if (extent[0] !== 0) { + // Expand extent + var expandSize = extent[0]; // In the fowllowing case + // Axis has been fixed max 100 + // Plus data are all 100 and axis extent are [100, 100]. + // Extend to the both side will cause expanded max is larger than fixed max. + // So only expand to the smaller side. + + if (!opt.fixMax) { + extent[1] += expandSize / 2; + extent[0] -= expandSize / 2; + } else { + extent[0] -= expandSize / 2; + } + } else { + extent[1] = 1; + } + } + + var span = extent[1] - extent[0]; // If there are no data and extent are [Infinity, -Infinity] + + if (!isFinite(span)) { + extent[0] = 0; + extent[1] = 1; + } + + this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval); // let extent = this._extent; + + var interval = this._interval; + + if (!opt.fixMin) { + extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval); + } + + if (!opt.fixMax) { + extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval); + } + }; + + IntervalScale.prototype.setNiceExtent = function (min, max) { + this._niceExtent = [min, max]; + }; + + IntervalScale.type = 'interval'; + return IntervalScale; + }(Scale); + + Scale.registerClass(IntervalScale); + + /* global Float32Array */ + + var supportFloat32Array = typeof Float32Array !== 'undefined'; + var Float32ArrayCtor = !supportFloat32Array ? Array : Float32Array; + function createFloat32Array(arg) { + if (isArray(arg)) { + // Return self directly if don't support TypedArray. + return supportFloat32Array ? new Float32Array(arg) : arg; + } // Else is number + + + return new Float32ArrayCtor(arg); + } + + var STACK_PREFIX = '__ec_stack_'; + + function getSeriesStackId(seriesModel) { + return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex; + } + + function getAxisKey(axis) { + return axis.dim + axis.index; + } + /** + * @return {Object} {width, offset, offsetCenter} If axis.type is not 'category', return undefined. + */ + + + function getLayoutOnAxis(opt) { + var params = []; + var baseAxis = opt.axis; + var axisKey = 'axis0'; + + if (baseAxis.type !== 'category') { + return; + } + + var bandWidth = baseAxis.getBandWidth(); + + for (var i = 0; i < opt.count || 0; i++) { + params.push(defaults({ + bandWidth: bandWidth, + axisKey: axisKey, + stackId: STACK_PREFIX + i + }, opt)); + } + + var widthAndOffsets = doCalBarWidthAndOffset(params); + var result = []; + + for (var i = 0; i < opt.count; i++) { + var item = widthAndOffsets[axisKey][STACK_PREFIX + i]; + item.offsetCenter = item.offset + item.width / 2; + result.push(item); + } + + return result; + } + function prepareLayoutBarSeries(seriesType, ecModel) { + var seriesModels = []; + ecModel.eachSeriesByType(seriesType, function (seriesModel) { + // Check series coordinate, do layout for cartesian2d only + if (isOnCartesian(seriesModel)) { + seriesModels.push(seriesModel); + } + }); + return seriesModels; + } + /** + * Map from (baseAxis.dim + '_' + baseAxis.index) to min gap of two adjacent + * values. + * This works for time axes, value axes, and log axes. + * For a single time axis, return value is in the form like + * {'x_0': [1000000]}. + * The value of 1000000 is in milliseconds. + */ + + function getValueAxesMinGaps(barSeries) { + /** + * Map from axis.index to values. + * For a single time axis, axisValues is in the form like + * {'x_0': [1495555200000, 1495641600000, 1495728000000]}. + * Items in axisValues[x], e.g. 1495555200000, are time values of all + * series. + */ + var axisValues = {}; + each(barSeries, function (seriesModel) { + var cartesian = seriesModel.coordinateSystem; + var baseAxis = cartesian.getBaseAxis(); + + if (baseAxis.type !== 'time' && baseAxis.type !== 'value') { + return; + } + + var data = seriesModel.getData(); + var key = baseAxis.dim + '_' + baseAxis.index; + var dimIdx = data.getDimensionIndex(data.mapDimension(baseAxis.dim)); + var store = data.getStore(); + + for (var i = 0, cnt = store.count(); i < cnt; ++i) { + var value = store.get(dimIdx, i); + + if (!axisValues[key]) { + // No previous data for the axis + axisValues[key] = [value]; + } else { + // No value in previous series + axisValues[key].push(value); + } // Ignore duplicated time values in the same axis + + } + }); + var axisMinGaps = {}; + + for (var key in axisValues) { + if (axisValues.hasOwnProperty(key)) { + var valuesInAxis = axisValues[key]; + + if (valuesInAxis) { + // Sort axis values into ascending order to calculate gaps + valuesInAxis.sort(function (a, b) { + return a - b; + }); + var min = null; + + for (var j = 1; j < valuesInAxis.length; ++j) { + var delta = valuesInAxis[j] - valuesInAxis[j - 1]; + + if (delta > 0) { + // Ignore 0 delta because they are of the same axis value + min = min === null ? delta : Math.min(min, delta); + } + } // Set to null if only have one data + + + axisMinGaps[key] = min; + } + } + } + + return axisMinGaps; + } + + function makeColumnLayout(barSeries) { + var axisMinGaps = getValueAxesMinGaps(barSeries); + var seriesInfoList = []; + each(barSeries, function (seriesModel) { + var cartesian = seriesModel.coordinateSystem; + var baseAxis = cartesian.getBaseAxis(); + var axisExtent = baseAxis.getExtent(); + var bandWidth; + + if (baseAxis.type === 'category') { + bandWidth = baseAxis.getBandWidth(); + } else if (baseAxis.type === 'value' || baseAxis.type === 'time') { + var key = baseAxis.dim + '_' + baseAxis.index; + var minGap = axisMinGaps[key]; + var extentSpan = Math.abs(axisExtent[1] - axisExtent[0]); + var scale = baseAxis.scale.getExtent(); + var scaleSpan = Math.abs(scale[1] - scale[0]); + bandWidth = minGap ? extentSpan / scaleSpan * minGap : extentSpan; // When there is only one data value + } else { + var data = seriesModel.getData(); + bandWidth = Math.abs(axisExtent[1] - axisExtent[0]) / data.count(); + } + + var barWidth = parsePercent$1(seriesModel.get('barWidth'), bandWidth); + var barMaxWidth = parsePercent$1(seriesModel.get('barMaxWidth'), bandWidth); + var barMinWidth = parsePercent$1( // barMinWidth by default is 0.5 / 1 in cartesian. Because in value axis, + // the auto-calculated bar width might be less than 0.5 / 1. + seriesModel.get('barMinWidth') || (isInLargeMode(seriesModel) ? 0.5 : 1), bandWidth); + var barGap = seriesModel.get('barGap'); + var barCategoryGap = seriesModel.get('barCategoryGap'); + seriesInfoList.push({ + bandWidth: bandWidth, + barWidth: barWidth, + barMaxWidth: barMaxWidth, + barMinWidth: barMinWidth, + barGap: barGap, + barCategoryGap: barCategoryGap, + axisKey: getAxisKey(baseAxis), + stackId: getSeriesStackId(seriesModel) + }); + }); + return doCalBarWidthAndOffset(seriesInfoList); + } + + function doCalBarWidthAndOffset(seriesInfoList) { + // Columns info on each category axis. Key is cartesian name + var columnsMap = {}; + each(seriesInfoList, function (seriesInfo, idx) { + var axisKey = seriesInfo.axisKey; + var bandWidth = seriesInfo.bandWidth; + var columnsOnAxis = columnsMap[axisKey] || { + bandWidth: bandWidth, + remainedWidth: bandWidth, + autoWidthCount: 0, + categoryGap: null, + gap: '20%', + stacks: {} + }; + var stacks = columnsOnAxis.stacks; + columnsMap[axisKey] = columnsOnAxis; + var stackId = seriesInfo.stackId; + + if (!stacks[stackId]) { + columnsOnAxis.autoWidthCount++; + } + + stacks[stackId] = stacks[stackId] || { + width: 0, + maxWidth: 0 + }; // Caution: In a single coordinate system, these barGrid attributes + // will be shared by series. Consider that they have default values, + // only the attributes set on the last series will work. + // Do not change this fact unless there will be a break change. + + var barWidth = seriesInfo.barWidth; + + if (barWidth && !stacks[stackId].width) { + // See #6312, do not restrict width. + stacks[stackId].width = barWidth; + barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth); + columnsOnAxis.remainedWidth -= barWidth; + } + + var barMaxWidth = seriesInfo.barMaxWidth; + barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth); + var barMinWidth = seriesInfo.barMinWidth; + barMinWidth && (stacks[stackId].minWidth = barMinWidth); + var barGap = seriesInfo.barGap; + barGap != null && (columnsOnAxis.gap = barGap); + var barCategoryGap = seriesInfo.barCategoryGap; + barCategoryGap != null && (columnsOnAxis.categoryGap = barCategoryGap); + }); + var result = {}; + each(columnsMap, function (columnsOnAxis, coordSysName) { + result[coordSysName] = {}; + var stacks = columnsOnAxis.stacks; + var bandWidth = columnsOnAxis.bandWidth; + var categoryGapPercent = columnsOnAxis.categoryGap; + + if (categoryGapPercent == null) { + var columnCount = keys(stacks).length; // More columns in one group + // the spaces between group is smaller. Or the column will be too thin. + + categoryGapPercent = Math.max(35 - columnCount * 4, 15) + '%'; + } + + var categoryGap = parsePercent$1(categoryGapPercent, bandWidth); + var barGapPercent = parsePercent$1(columnsOnAxis.gap, 1); + var remainedWidth = columnsOnAxis.remainedWidth; + var autoWidthCount = columnsOnAxis.autoWidthCount; + var autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent); + autoWidth = Math.max(autoWidth, 0); // Find if any auto calculated bar exceeded maxBarWidth + + each(stacks, function (column) { + var maxWidth = column.maxWidth; + var minWidth = column.minWidth; + + if (!column.width) { + var finalWidth = autoWidth; + + if (maxWidth && maxWidth < finalWidth) { + finalWidth = Math.min(maxWidth, remainedWidth); + } // `minWidth` has higher priority. `minWidth` decide that wheter the + // bar is able to be visible. So `minWidth` should not be restricted + // by `maxWidth` or `remainedWidth` (which is from `bandWidth`). In + // the extreme cases for `value` axis, bars are allowed to overlap + // with each other if `minWidth` specified. + + + if (minWidth && minWidth > finalWidth) { + finalWidth = minWidth; + } + + if (finalWidth !== autoWidth) { + column.width = finalWidth; + remainedWidth -= finalWidth + barGapPercent * finalWidth; + autoWidthCount--; + } + } else { + // `barMinWidth/barMaxWidth` has higher priority than `barWidth`, as + // CSS does. Becuase barWidth can be a percent value, where + // `barMaxWidth` can be used to restrict the final width. + var finalWidth = column.width; + + if (maxWidth) { + finalWidth = Math.min(finalWidth, maxWidth); + } // `minWidth` has higher priority, as described above + + + if (minWidth) { + finalWidth = Math.max(finalWidth, minWidth); + } + + column.width = finalWidth; + remainedWidth -= finalWidth + barGapPercent * finalWidth; + autoWidthCount--; + } + }); // Recalculate width again + + autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent); + autoWidth = Math.max(autoWidth, 0); + var widthSum = 0; + var lastColumn; + each(stacks, function (column, idx) { + if (!column.width) { + column.width = autoWidth; + } + + lastColumn = column; + widthSum += column.width * (1 + barGapPercent); + }); + + if (lastColumn) { + widthSum -= lastColumn.width * barGapPercent; + } + + var offset = -widthSum / 2; + each(stacks, function (column, stackId) { + result[coordSysName][stackId] = result[coordSysName][stackId] || { + bandWidth: bandWidth, + offset: offset, + width: column.width + }; + offset += column.width * (1 + barGapPercent); + }); + }); + return result; + } + + function retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) { + if (barWidthAndOffset && axis) { + var result = barWidthAndOffset[getAxisKey(axis)]; + + if (result != null && seriesModel != null) { + return result[getSeriesStackId(seriesModel)]; + } + + return result; + } + } + function layout(seriesType, ecModel) { + var seriesModels = prepareLayoutBarSeries(seriesType, ecModel); + var barWidthAndOffset = makeColumnLayout(seriesModels); + each(seriesModels, function (seriesModel) { + var data = seriesModel.getData(); + var cartesian = seriesModel.coordinateSystem; + var baseAxis = cartesian.getBaseAxis(); + var stackId = getSeriesStackId(seriesModel); + var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId]; + var columnOffset = columnLayoutInfo.offset; + var columnWidth = columnLayoutInfo.width; + data.setLayout({ + bandWidth: columnLayoutInfo.bandWidth, + offset: columnOffset, + size: columnWidth + }); + }); + } // TODO: Do not support stack in large mode yet. + + function createProgressiveLayout(seriesType) { + return { + seriesType: seriesType, + plan: createRenderPlanner(), + reset: function (seriesModel) { + if (!isOnCartesian(seriesModel)) { + return; + } + + var data = seriesModel.getData(); + var cartesian = seriesModel.coordinateSystem; + var baseAxis = cartesian.getBaseAxis(); + var valueAxis = cartesian.getOtherAxis(baseAxis); + var valueDimIdx = data.getDimensionIndex(data.mapDimension(valueAxis.dim)); + var baseDimIdx = data.getDimensionIndex(data.mapDimension(baseAxis.dim)); + var drawBackground = seriesModel.get('showBackground', true); + var valueDim = data.mapDimension(valueAxis.dim); + var stackResultDim = data.getCalculationInfo('stackResultDimension'); + var stacked = isDimensionStacked(data, valueDim) && !!data.getCalculationInfo('stackedOnSeries'); + var isValueAxisH = valueAxis.isHorizontal(); + var valueAxisStart = getValueAxisStart(baseAxis, valueAxis); + var isLarge = isInLargeMode(seriesModel); + var barMinHeight = seriesModel.get('barMinHeight') || 0; + var stackedDimIdx = stackResultDim && data.getDimensionIndex(stackResultDim); // Layout info. + + var columnWidth = data.getLayout('size'); + var columnOffset = data.getLayout('offset'); + return { + progress: function (params, data) { + var count = params.count; + var largePoints = isLarge && createFloat32Array(count * 3); + var largeBackgroundPoints = isLarge && drawBackground && createFloat32Array(count * 3); + var largeDataIndices = isLarge && createFloat32Array(count); + var coordLayout = cartesian.master.getRect(); + var bgSize = isValueAxisH ? coordLayout.width : coordLayout.height; + var dataIndex; + var store = data.getStore(); + var idxOffset = 0; + + while ((dataIndex = params.next()) != null) { + var value = store.get(stacked ? stackedDimIdx : valueDimIdx, dataIndex); + var baseValue = store.get(baseDimIdx, dataIndex); + var baseCoord = valueAxisStart; + var startValue = void 0; // Because of the barMinHeight, we can not use the value in + // stackResultDimension directly. + + if (stacked) { + startValue = +value - store.get(valueDimIdx, dataIndex); + } + + var x = void 0; + var y = void 0; + var width = void 0; + var height = void 0; + + if (isValueAxisH) { + var coord = cartesian.dataToPoint([value, baseValue]); + + if (stacked) { + var startCoord = cartesian.dataToPoint([startValue, baseValue]); + baseCoord = startCoord[0]; + } + + x = baseCoord; + y = coord[1] + columnOffset; + width = coord[0] - baseCoord; + height = columnWidth; + + if (Math.abs(width) < barMinHeight) { + width = (width < 0 ? -1 : 1) * barMinHeight; + } + } else { + var coord = cartesian.dataToPoint([baseValue, value]); + + if (stacked) { + var startCoord = cartesian.dataToPoint([baseValue, startValue]); + baseCoord = startCoord[1]; + } + + x = coord[0] + columnOffset; + y = baseCoord; + width = columnWidth; + height = coord[1] - baseCoord; + + if (Math.abs(height) < barMinHeight) { + // Include zero to has a positive bar + height = (height <= 0 ? -1 : 1) * barMinHeight; + } + } + + if (!isLarge) { + data.setItemLayout(dataIndex, { + x: x, + y: y, + width: width, + height: height + }); + } else { + largePoints[idxOffset] = x; + largePoints[idxOffset + 1] = y; + largePoints[idxOffset + 2] = isValueAxisH ? width : height; + + if (largeBackgroundPoints) { + largeBackgroundPoints[idxOffset] = isValueAxisH ? coordLayout.x : x; + largeBackgroundPoints[idxOffset + 1] = isValueAxisH ? y : coordLayout.y; + largeBackgroundPoints[idxOffset + 2] = bgSize; + } + + largeDataIndices[dataIndex] = dataIndex; + } + + idxOffset += 3; + } + + if (isLarge) { + data.setLayout({ + largePoints: largePoints, + largeDataIndices: largeDataIndices, + largeBackgroundPoints: largeBackgroundPoints, + valueAxisHorizontal: isValueAxisH + }); + } + } + }; + } + }; + } + + function isOnCartesian(seriesModel) { + return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d'; + } + + function isInLargeMode(seriesModel) { + return seriesModel.pipelineContext && seriesModel.pipelineContext.large; + } // See cases in `test/bar-start.html` and `#7412`, `#8747`. + + + function getValueAxisStart(baseAxis, valueAxis) { + return valueAxis.toGlobalCoord(valueAxis.dataToCoord(valueAxis.type === 'log' ? 1 : 0)); + } + + var bisect = function (a, x, lo, hi) { + while (lo < hi) { + var mid = lo + hi >>> 1; + + if (a[mid][1] < x) { + lo = mid + 1; + } else { + hi = mid; + } + } + + return lo; + }; + + var TimeScale = + /** @class */ + function (_super) { + __extends(TimeScale, _super); + + function TimeScale(settings) { + var _this = _super.call(this, settings) || this; + + _this.type = 'time'; + return _this; + } + /** + * Get label is mainly for other components like dataZoom, tooltip. + */ + + + TimeScale.prototype.getLabel = function (tick) { + var useUTC = this.getSetting('useUTC'); + return format(tick.value, fullLeveledFormatter[getDefaultFormatPrecisionOfInterval(getPrimaryTimeUnit(this._minLevelUnit))] || fullLeveledFormatter.second, useUTC, this.getSetting('locale')); + }; + + TimeScale.prototype.getFormattedLabel = function (tick, idx, labelFormatter) { + var isUTC = this.getSetting('useUTC'); + var lang = this.getSetting('locale'); + return leveledFormat(tick, idx, labelFormatter, lang, isUTC); + }; + /** + * @override + */ + + + TimeScale.prototype.getTicks = function () { + var interval = this._interval; + var extent = this._extent; + var ticks = []; // If interval is 0, return []; + + if (!interval) { + return ticks; + } + + ticks.push({ + value: extent[0], + level: 0 + }); + var useUTC = this.getSetting('useUTC'); + var innerTicks = getIntervalTicks(this._minLevelUnit, this._approxInterval, useUTC, extent); + ticks = ticks.concat(innerTicks); + ticks.push({ + value: extent[1], + level: 0 + }); + return ticks; + }; + + TimeScale.prototype.calcNiceExtent = function (opt) { + var extent = this._extent; // If extent start and end are same, expand them + + if (extent[0] === extent[1]) { + // Expand extent + extent[0] -= ONE_DAY; + extent[1] += ONE_DAY; + } // If there are no data and extent are [Infinity, -Infinity] + + + if (extent[1] === -Infinity && extent[0] === Infinity) { + var d = new Date(); + extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate()); + extent[0] = extent[1] - ONE_DAY; + } + + this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval); + }; + + TimeScale.prototype.calcNiceTicks = function (approxTickNum, minInterval, maxInterval) { + approxTickNum = approxTickNum || 10; + var extent = this._extent; + var span = extent[1] - extent[0]; + this._approxInterval = span / approxTickNum; + + if (minInterval != null && this._approxInterval < minInterval) { + this._approxInterval = minInterval; + } + + if (maxInterval != null && this._approxInterval > maxInterval) { + this._approxInterval = maxInterval; + } + + var scaleIntervalsLen = scaleIntervals.length; + var idx = Math.min(bisect(scaleIntervals, this._approxInterval, 0, scaleIntervalsLen), scaleIntervalsLen - 1); // Interval that can be used to calculate ticks + + this._interval = scaleIntervals[idx][1]; // Min level used when picking ticks from top down. + // We check one more level to avoid the ticks are to sparse in some case. + + this._minLevelUnit = scaleIntervals[Math.max(idx - 1, 0)][0]; + }; + + TimeScale.prototype.parse = function (val) { + // val might be float. + return isNumber(val) ? val : +parseDate(val); + }; + + TimeScale.prototype.contain = function (val) { + return contain$1(this.parse(val), this._extent); + }; + + TimeScale.prototype.normalize = function (val) { + return normalize$1(this.parse(val), this._extent); + }; + + TimeScale.prototype.scale = function (val) { + return scale$2(val, this._extent); + }; + + TimeScale.type = 'time'; + return TimeScale; + }(IntervalScale); + /** + * This implementation was originally copied from "d3.js" + * + * with some modifications made for this program. + * See the license statement at the head of this file. + */ + + + var scaleIntervals = [// Format interval + ['second', ONE_SECOND], ['minute', ONE_MINUTE], ['hour', ONE_HOUR], ['quarter-day', ONE_HOUR * 6], ['half-day', ONE_HOUR * 12], ['day', ONE_DAY * 1.2], ['half-week', ONE_DAY * 3.5], ['week', ONE_DAY * 7], ['month', ONE_DAY * 31], ['quarter', ONE_DAY * 95], ['half-year', ONE_YEAR / 2], ['year', ONE_YEAR] // 1Y + ]; + + function isUnitValueSame(unit, valueA, valueB, isUTC) { + var dateA = parseDate(valueA); + var dateB = parseDate(valueB); + + var isSame = function (unit) { + return getUnitValue(dateA, unit, isUTC) === getUnitValue(dateB, unit, isUTC); + }; + + var isSameYear = function () { + return isSame('year'); + }; // const isSameHalfYear = () => isSameYear() && isSame('half-year'); + // const isSameQuater = () => isSameYear() && isSame('quarter'); + + + var isSameMonth = function () { + return isSameYear() && isSame('month'); + }; + + var isSameDay = function () { + return isSameMonth() && isSame('day'); + }; // const isSameHalfDay = () => isSameDay() && isSame('half-day'); + + + var isSameHour = function () { + return isSameDay() && isSame('hour'); + }; + + var isSameMinute = function () { + return isSameHour() && isSame('minute'); + }; + + var isSameSecond = function () { + return isSameMinute() && isSame('second'); + }; + + var isSameMilliSecond = function () { + return isSameSecond() && isSame('millisecond'); + }; + + switch (unit) { + case 'year': + return isSameYear(); + + case 'month': + return isSameMonth(); + + case 'day': + return isSameDay(); + + case 'hour': + return isSameHour(); + + case 'minute': + return isSameMinute(); + + case 'second': + return isSameSecond(); + + case 'millisecond': + return isSameMilliSecond(); + } + } // const primaryUnitGetters = { + // year: fullYearGetterName(), + // month: monthGetterName(), + // day: dateGetterName(), + // hour: hoursGetterName(), + // minute: minutesGetterName(), + // second: secondsGetterName(), + // millisecond: millisecondsGetterName() + // }; + // const primaryUnitUTCGetters = { + // year: fullYearGetterName(true), + // month: monthGetterName(true), + // day: dateGetterName(true), + // hour: hoursGetterName(true), + // minute: minutesGetterName(true), + // second: secondsGetterName(true), + // millisecond: millisecondsGetterName(true) + // }; + // function moveTick(date: Date, unitName: TimeUnit, step: number, isUTC: boolean) { + // step = step || 1; + // switch (getPrimaryTimeUnit(unitName)) { + // case 'year': + // date[fullYearSetterName(isUTC)](date[fullYearGetterName(isUTC)]() + step); + // break; + // case 'month': + // date[monthSetterName(isUTC)](date[monthGetterName(isUTC)]() + step); + // break; + // case 'day': + // date[dateSetterName(isUTC)](date[dateGetterName(isUTC)]() + step); + // break; + // case 'hour': + // date[hoursSetterName(isUTC)](date[hoursGetterName(isUTC)]() + step); + // break; + // case 'minute': + // date[minutesSetterName(isUTC)](date[minutesGetterName(isUTC)]() + step); + // break; + // case 'second': + // date[secondsSetterName(isUTC)](date[secondsGetterName(isUTC)]() + step); + // break; + // case 'millisecond': + // date[millisecondsSetterName(isUTC)](date[millisecondsGetterName(isUTC)]() + step); + // break; + // } + // return date.getTime(); + // } + // const DATE_INTERVALS = [[8, 7.5], [4, 3.5], [2, 1.5]]; + // const MONTH_INTERVALS = [[6, 5.5], [3, 2.5], [2, 1.5]]; + // const MINUTES_SECONDS_INTERVALS = [[30, 30], [20, 20], [15, 15], [10, 10], [5, 5], [2, 2]]; + + + function getDateInterval(approxInterval, daysInMonth) { + approxInterval /= ONE_DAY; + return approxInterval > 16 ? 16 // Math.floor(daysInMonth / 2) + 1 // In this case we only want one tick betwen two month. + : approxInterval > 7.5 ? 7 // TODO week 7 or day 8? + : approxInterval > 3.5 ? 4 : approxInterval > 1.5 ? 2 : 1; + } + + function getMonthInterval(approxInterval) { + var APPROX_ONE_MONTH = 30 * ONE_DAY; + approxInterval /= APPROX_ONE_MONTH; + return approxInterval > 6 ? 6 : approxInterval > 3 ? 3 : approxInterval > 2 ? 2 : 1; + } + + function getHourInterval(approxInterval) { + approxInterval /= ONE_HOUR; + return approxInterval > 12 ? 12 : approxInterval > 6 ? 6 : approxInterval > 3.5 ? 4 : approxInterval > 2 ? 2 : 1; + } + + function getMinutesAndSecondsInterval(approxInterval, isMinutes) { + approxInterval /= isMinutes ? ONE_MINUTE : ONE_SECOND; + return approxInterval > 30 ? 30 : approxInterval > 20 ? 20 : approxInterval > 15 ? 15 : approxInterval > 10 ? 10 : approxInterval > 5 ? 5 : approxInterval > 2 ? 2 : 1; + } + + function getMillisecondsInterval(approxInterval) { + return nice(approxInterval, true); + } + + function getFirstTimestampOfUnit(date, unitName, isUTC) { + var outDate = new Date(date); + + switch (getPrimaryTimeUnit(unitName)) { + case 'year': + case 'month': + outDate[monthSetterName(isUTC)](0); + + case 'day': + outDate[dateSetterName(isUTC)](1); + + case 'hour': + outDate[hoursSetterName(isUTC)](0); + + case 'minute': + outDate[minutesSetterName(isUTC)](0); + + case 'second': + outDate[secondsSetterName(isUTC)](0); + outDate[millisecondsSetterName(isUTC)](0); + } + + return outDate.getTime(); + } + + function getIntervalTicks(bottomUnitName, approxInterval, isUTC, extent) { + var safeLimit = 10000; + var unitNames = timeUnits; + var iter = 0; + + function addTicksInSpan(interval, minTimestamp, maxTimestamp, getMethodName, setMethodName, isDate, out) { + var date = new Date(minTimestamp); + var dateTime = minTimestamp; + var d = date[getMethodName](); // if (isDate) { + // d -= 1; // Starts with 0; PENDING + // } + + while (dateTime < maxTimestamp && dateTime <= extent[1]) { + out.push({ + value: dateTime + }); + d += interval; + date[setMethodName](d); + dateTime = date.getTime(); + } // This extra tick is for calcuating ticks of next level. Will not been added to the final result + + + out.push({ + value: dateTime, + notAdd: true + }); + } + + function addLevelTicks(unitName, lastLevelTicks, levelTicks) { + var newAddedTicks = []; + var isFirstLevel = !lastLevelTicks.length; + + if (isUnitValueSame(getPrimaryTimeUnit(unitName), extent[0], extent[1], isUTC)) { + return; + } + + if (isFirstLevel) { + lastLevelTicks = [{ + // TODO Optimize. Not include so may ticks. + value: getFirstTimestampOfUnit(new Date(extent[0]), unitName, isUTC) + }, { + value: extent[1] + }]; + } + + for (var i = 0; i < lastLevelTicks.length - 1; i++) { + var startTick = lastLevelTicks[i].value; + var endTick = lastLevelTicks[i + 1].value; + + if (startTick === endTick) { + continue; + } + + var interval = void 0; + var getterName = void 0; + var setterName = void 0; + var isDate = false; + + switch (unitName) { + case 'year': + interval = Math.max(1, Math.round(approxInterval / ONE_DAY / 365)); + getterName = fullYearGetterName(isUTC); + setterName = fullYearSetterName(isUTC); + break; + + case 'half-year': + case 'quarter': + case 'month': + interval = getMonthInterval(approxInterval); + getterName = monthGetterName(isUTC); + setterName = monthSetterName(isUTC); + break; + + case 'week': // PENDING If week is added. Ignore day. + + case 'half-week': + case 'day': + interval = getDateInterval(approxInterval); // Use 32 days and let interval been 16 + + getterName = dateGetterName(isUTC); + setterName = dateSetterName(isUTC); + isDate = true; + break; + + case 'half-day': + case 'quarter-day': + case 'hour': + interval = getHourInterval(approxInterval); + getterName = hoursGetterName(isUTC); + setterName = hoursSetterName(isUTC); + break; + + case 'minute': + interval = getMinutesAndSecondsInterval(approxInterval, true); + getterName = minutesGetterName(isUTC); + setterName = minutesSetterName(isUTC); + break; + + case 'second': + interval = getMinutesAndSecondsInterval(approxInterval, false); + getterName = secondsGetterName(isUTC); + setterName = secondsSetterName(isUTC); + break; + + case 'millisecond': + interval = getMillisecondsInterval(approxInterval); + getterName = millisecondsGetterName(isUTC); + setterName = millisecondsSetterName(isUTC); + break; + } + + addTicksInSpan(interval, startTick, endTick, getterName, setterName, isDate, newAddedTicks); + + if (unitName === 'year' && levelTicks.length > 1 && i === 0) { + // Add nearest years to the left extent. + levelTicks.unshift({ + value: levelTicks[0].value - interval + }); + } + } + + for (var i = 0; i < newAddedTicks.length; i++) { + levelTicks.push(newAddedTicks[i]); + } // newAddedTicks.length && console.log(unitName, newAddedTicks); + + + return newAddedTicks; + } + + var levelsTicks = []; + var currentLevelTicks = []; + var tickCount = 0; + var lastLevelTickCount = 0; + + for (var i = 0; i < unitNames.length && iter++ < safeLimit; ++i) { + var primaryTimeUnit = getPrimaryTimeUnit(unitNames[i]); + + if (!isPrimaryTimeUnit(unitNames[i])) { + // TODO + continue; + } + + addLevelTicks(unitNames[i], levelsTicks[levelsTicks.length - 1] || [], currentLevelTicks); + var nextPrimaryTimeUnit = unitNames[i + 1] ? getPrimaryTimeUnit(unitNames[i + 1]) : null; + + if (primaryTimeUnit !== nextPrimaryTimeUnit) { + if (currentLevelTicks.length) { + lastLevelTickCount = tickCount; // Remove the duplicate so the tick count can be precisely. + + currentLevelTicks.sort(function (a, b) { + return a.value - b.value; + }); + var levelTicksRemoveDuplicated = []; + + for (var i_1 = 0; i_1 < currentLevelTicks.length; ++i_1) { + var tickValue = currentLevelTicks[i_1].value; + + if (i_1 === 0 || currentLevelTicks[i_1 - 1].value !== tickValue) { + levelTicksRemoveDuplicated.push(currentLevelTicks[i_1]); + + if (tickValue >= extent[0] && tickValue <= extent[1]) { + tickCount++; + } + } + } + + var targetTickNum = (extent[1] - extent[0]) / approxInterval; // Added too much in this level and not too less in last level + + if (tickCount > targetTickNum * 1.5 && lastLevelTickCount > targetTickNum / 1.5) { + break; + } // Only treat primary time unit as one level. + + + levelsTicks.push(levelTicksRemoveDuplicated); + + if (tickCount > targetTickNum || bottomUnitName === unitNames[i]) { + break; + } + } // Reset if next unitName is primary + + + currentLevelTicks = []; + } + } + + if ("development" !== 'production') { + if (iter >= safeLimit) { + warn('Exceed safe limit.'); + } + } + + var levelsTicksInExtent = filter(map(levelsTicks, function (levelTicks) { + return filter(levelTicks, function (tick) { + return tick.value >= extent[0] && tick.value <= extent[1] && !tick.notAdd; + }); + }), function (levelTicks) { + return levelTicks.length > 0; + }); + var ticks = []; + var maxLevel = levelsTicksInExtent.length - 1; + + for (var i = 0; i < levelsTicksInExtent.length; ++i) { + var levelTicks = levelsTicksInExtent[i]; + + for (var k = 0; k < levelTicks.length; ++k) { + ticks.push({ + value: levelTicks[k].value, + level: maxLevel - i + }); + } + } + + ticks.sort(function (a, b) { + return a.value - b.value; + }); // Remove duplicates + + var result = []; + + for (var i = 0; i < ticks.length; ++i) { + if (i === 0 || ticks[i].value !== ticks[i - 1].value) { + result.push(ticks[i]); + } + } + + return result; + } + + Scale.registerClass(TimeScale); + + var scaleProto = Scale.prototype; // FIXME:TS refactor: not good to call it directly with `this`? + + var intervalScaleProto = IntervalScale.prototype; + var roundingErrorFix = round; + var mathFloor = Math.floor; + var mathCeil = Math.ceil; + var mathPow$1 = Math.pow; + var mathLog = Math.log; + + var LogScale = + /** @class */ + function (_super) { + __extends(LogScale, _super); + + function LogScale() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'log'; + _this.base = 10; + _this._originalScale = new IntervalScale(); // FIXME:TS actually used by `IntervalScale` + + _this._interval = 0; + return _this; + } + /** + * @param Whether expand the ticks to niced extent. + */ + + + LogScale.prototype.getTicks = function (expandToNicedExtent) { + var originalScale = this._originalScale; + var extent = this._extent; + var originalExtent = originalScale.getExtent(); + var ticks = intervalScaleProto.getTicks.call(this, expandToNicedExtent); + return map(ticks, function (tick) { + var val = tick.value; + var powVal = round(mathPow$1(this.base, val)); // Fix #4158 + + powVal = val === extent[0] && this._fixMin ? fixRoundingError(powVal, originalExtent[0]) : powVal; + powVal = val === extent[1] && this._fixMax ? fixRoundingError(powVal, originalExtent[1]) : powVal; + return { + value: powVal + }; + }, this); + }; + + LogScale.prototype.setExtent = function (start, end) { + var base = this.base; + start = mathLog(start) / mathLog(base); + end = mathLog(end) / mathLog(base); + intervalScaleProto.setExtent.call(this, start, end); + }; + /** + * @return {number} end + */ + + + LogScale.prototype.getExtent = function () { + var base = this.base; + var extent = scaleProto.getExtent.call(this); + extent[0] = mathPow$1(base, extent[0]); + extent[1] = mathPow$1(base, extent[1]); // Fix #4158 + + var originalScale = this._originalScale; + var originalExtent = originalScale.getExtent(); + this._fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0])); + this._fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1])); + return extent; + }; + + LogScale.prototype.unionExtent = function (extent) { + this._originalScale.unionExtent(extent); + + var base = this.base; + extent[0] = mathLog(extent[0]) / mathLog(base); + extent[1] = mathLog(extent[1]) / mathLog(base); + scaleProto.unionExtent.call(this, extent); + }; + + LogScale.prototype.unionExtentFromData = function (data, dim) { + // TODO + // filter value that <= 0 + this.unionExtent(data.getApproximateExtent(dim)); + }; + /** + * Update interval and extent of intervals for nice ticks + * @param approxTickNum default 10 Given approx tick number + */ + + + LogScale.prototype.calcNiceTicks = function (approxTickNum) { + approxTickNum = approxTickNum || 10; + var extent = this._extent; + var span = extent[1] - extent[0]; + + if (span === Infinity || span <= 0) { + return; + } + + var interval = quantity(span); + var err = approxTickNum / span * interval; // Filter ticks to get closer to the desired count. + + if (err <= 0.5) { + interval *= 10; + } // Interval should be integer + + + while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) { + interval *= 10; + } + + var niceExtent = [round(mathCeil(extent[0] / interval) * interval), round(mathFloor(extent[1] / interval) * interval)]; + this._interval = interval; + this._niceExtent = niceExtent; + }; + + LogScale.prototype.calcNiceExtent = function (opt) { + intervalScaleProto.calcNiceExtent.call(this, opt); + this._fixMin = opt.fixMin; + this._fixMax = opt.fixMax; + }; + + LogScale.prototype.parse = function (val) { + return val; + }; + + LogScale.prototype.contain = function (val) { + val = mathLog(val) / mathLog(this.base); + return contain$1(val, this._extent); + }; + + LogScale.prototype.normalize = function (val) { + val = mathLog(val) / mathLog(this.base); + return normalize$1(val, this._extent); + }; + + LogScale.prototype.scale = function (val) { + val = scale$2(val, this._extent); + return mathPow$1(this.base, val); + }; + + LogScale.type = 'log'; + return LogScale; + }(Scale); + + var proto = LogScale.prototype; + proto.getMinorTicks = intervalScaleProto.getMinorTicks; + proto.getLabel = intervalScaleProto.getLabel; + + function fixRoundingError(val, originalVal) { + return roundingErrorFix(val, getPrecision(originalVal)); + } + + Scale.registerClass(LogScale); + + var ScaleRawExtentInfo = + /** @class */ + function () { + function ScaleRawExtentInfo(scale, model, // Usually: data extent from all series on this axis. + originalExtent) { + this._prepareParams(scale, model, originalExtent); + } + /** + * Parameters depending on ouside (like model, user callback) + * are prepared and fixed here. + */ + + + ScaleRawExtentInfo.prototype._prepareParams = function (scale, model, // Usually: data extent from all series on this axis. + dataExtent) { + if (dataExtent[1] < dataExtent[0]) { + dataExtent = [NaN, NaN]; + } + + this._dataMin = dataExtent[0]; + this._dataMax = dataExtent[1]; + var isOrdinal = this._isOrdinal = scale.type === 'ordinal'; + this._needCrossZero = scale.type === 'interval' && model.getNeedCrossZero && model.getNeedCrossZero(); + var modelMinRaw = this._modelMinRaw = model.get('min', true); + + if (isFunction(modelMinRaw)) { + // This callback alway provide users the full data extent (before data filtered). + this._modelMinNum = parseAxisModelMinMax(scale, modelMinRaw({ + min: dataExtent[0], + max: dataExtent[1] + })); + } else if (modelMinRaw !== 'dataMin') { + this._modelMinNum = parseAxisModelMinMax(scale, modelMinRaw); + } + + var modelMaxRaw = this._modelMaxRaw = model.get('max', true); + + if (isFunction(modelMaxRaw)) { + // This callback alway provide users the full data extent (before data filtered). + this._modelMaxNum = parseAxisModelMinMax(scale, modelMaxRaw({ + min: dataExtent[0], + max: dataExtent[1] + })); + } else if (modelMaxRaw !== 'dataMax') { + this._modelMaxNum = parseAxisModelMinMax(scale, modelMaxRaw); + } + + if (isOrdinal) { + // FIXME: there is a flaw here: if there is no "block" data processor like `dataZoom`, + // and progressive rendering is using, here the category result might just only contain + // the processed chunk rather than the entire result. + this._axisDataLen = model.getCategories().length; + } else { + var boundaryGap = model.get('boundaryGap'); + var boundaryGapArr = isArray(boundaryGap) ? boundaryGap : [boundaryGap || 0, boundaryGap || 0]; + + if (typeof boundaryGapArr[0] === 'boolean' || typeof boundaryGapArr[1] === 'boolean') { + if ("development" !== 'production') { + console.warn('Boolean type for boundaryGap is only ' + 'allowed for ordinal axis. Please use string in ' + 'percentage instead, e.g., "20%". Currently, ' + 'boundaryGap is set to be 0.'); + } + + this._boundaryGapInner = [0, 0]; + } else { + this._boundaryGapInner = [parsePercent(boundaryGapArr[0], 1), parsePercent(boundaryGapArr[1], 1)]; + } + } + }; + /** + * Calculate extent by prepared parameters. + * This method has no external dependency and can be called duplicatedly, + * getting the same result. + * If parameters changed, should call this method to recalcuate. + */ + + + ScaleRawExtentInfo.prototype.calculate = function () { + // Notice: When min/max is not set (that is, when there are null/undefined, + // which is the most common case), these cases should be ensured: + // (1) For 'ordinal', show all axis.data. + // (2) For others: + // + `boundaryGap` is applied (if min/max set, boundaryGap is + // disabled). + // + If `needCrossZero`, min/max should be zero, otherwise, min/max should + // be the result that originalExtent enlarged by boundaryGap. + // (3) If no data, it should be ensured that `scale.setBlank` is set. + var isOrdinal = this._isOrdinal; + var dataMin = this._dataMin; + var dataMax = this._dataMax; + var axisDataLen = this._axisDataLen; + var boundaryGapInner = this._boundaryGapInner; + var span = !isOrdinal ? dataMax - dataMin || Math.abs(dataMin) : null; // Currently if a `'value'` axis model min is specified as 'dataMin'/'dataMax', + // `boundaryGap` will not be used. It's the different from specifying as `null`/`undefined`. + + var min = this._modelMinRaw === 'dataMin' ? dataMin : this._modelMinNum; + var max = this._modelMaxRaw === 'dataMax' ? dataMax : this._modelMaxNum; // If `_modelMinNum`/`_modelMaxNum` is `null`/`undefined`, should not be fixed. + + var minFixed = min != null; + var maxFixed = max != null; + + if (min == null) { + min = isOrdinal ? axisDataLen ? 0 : NaN : dataMin - boundaryGapInner[0] * span; + } + + if (max == null) { + max = isOrdinal ? axisDataLen ? axisDataLen - 1 : NaN : dataMax + boundaryGapInner[1] * span; + } + + (min == null || !isFinite(min)) && (min = NaN); + (max == null || !isFinite(max)) && (max = NaN); + var isBlank = eqNaN(min) || eqNaN(max) || isOrdinal && !axisDataLen; // If data extent modified, need to recalculated to ensure cross zero. + + if (this._needCrossZero) { + // Axis is over zero and min is not set + if (min > 0 && max > 0 && !minFixed) { + min = 0; // minFixed = true; + } // Axis is under zero and max is not set + + + if (min < 0 && max < 0 && !maxFixed) { + max = 0; // maxFixed = true; + } // PENDING: + // When `needCrossZero` and all data is positive/negative, should it be ensured + // that the results processed by boundaryGap are positive/negative? + // If so, here `minFixed`/`maxFixed` need to be set. + + } + + var determinedMin = this._determinedMin; + var determinedMax = this._determinedMax; + + if (determinedMin != null) { + min = determinedMin; + minFixed = true; + } + + if (determinedMax != null) { + max = determinedMax; + maxFixed = true; + } // Ensure min/max be finite number or NaN here. (not to be null/undefined) + // `NaN` means min/max axis is blank. + + + return { + min: min, + max: max, + minFixed: minFixed, + maxFixed: maxFixed, + isBlank: isBlank + }; + }; + + ScaleRawExtentInfo.prototype.modifyDataMinMax = function (minMaxName, val) { + if ("development" !== 'production') { + assert(!this.frozen); + } + + this[DATA_MIN_MAX_ATTR[minMaxName]] = val; + }; + + ScaleRawExtentInfo.prototype.setDeterminedMinMax = function (minMaxName, val) { + var attr = DETERMINED_MIN_MAX_ATTR[minMaxName]; + + if ("development" !== 'production') { + assert(!this.frozen // Earse them usually means logic flaw. + && this[attr] == null); + } + + this[attr] = val; + }; + + ScaleRawExtentInfo.prototype.freeze = function () { + // @ts-ignore + this.frozen = true; + }; + + return ScaleRawExtentInfo; + }(); + var DETERMINED_MIN_MAX_ATTR = { + min: '_determinedMin', + max: '_determinedMax' + }; + var DATA_MIN_MAX_ATTR = { + min: '_dataMin', + max: '_dataMax' + }; + /** + * Get scale min max and related info only depends on model settings. + * This method can be called after coordinate system created. + * For example, in data processing stage. + * + * Scale extent info probably be required multiple times during a workflow. + * For example: + * (1) `dataZoom` depends it to get the axis extent in "100%" state. + * (2) `processor/extentCalculator` depends it to make sure whether axis extent is specified. + * (3) `coordSys.update` use it to finally decide the scale extent. + * But the callback of `min`/`max` should not be called multiple times. + * The code below should not be implemented repeatedly either. + * So we cache the result in the scale instance, which will be recreated at the begining + * of the workflow (because `scale` instance will be recreated each round of the workflow). + */ + + function ensureScaleRawExtentInfo(scale, model, // Usually: data extent from all series on this axis. + originalExtent) { + // Do not permit to recreate. + var rawExtentInfo = scale.rawExtentInfo; + + if (rawExtentInfo) { + return rawExtentInfo; + } + + rawExtentInfo = new ScaleRawExtentInfo(scale, model, originalExtent); // @ts-ignore + + scale.rawExtentInfo = rawExtentInfo; + return rawExtentInfo; + } + function parseAxisModelMinMax(scale, minMax) { + return minMax == null ? null : eqNaN(minMax) ? NaN : scale.parse(minMax); + } + + /** + * Get axis scale extent before niced. + * Item of returned array can only be number (including Infinity and NaN). + * + * Caution: + * Precondition of calling this method: + * The scale extent has been initialized using series data extent via + * `scale.setExtent` or `scale.unionExtentFromData`; + */ + + function getScaleExtent(scale, model) { + var scaleType = scale.type; + var rawExtentResult = ensureScaleRawExtentInfo(scale, model, scale.getExtent()).calculate(); + scale.setBlank(rawExtentResult.isBlank); + var min = rawExtentResult.min; + var max = rawExtentResult.max; // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis + // is base axis + // FIXME + // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly. + // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent? + // Should not depend on series type `bar`? + // (3) Fix that might overlap when using dataZoom. + // (4) Consider other chart types using `barGrid`? + // See #6728, #4862, `test/bar-overflow-time-plot.html` + + var ecModel = model.ecModel; + + if (ecModel && scaleType === 'time' + /*|| scaleType === 'interval' */ + ) { + var barSeriesModels = prepareLayoutBarSeries('bar', ecModel); + var isBaseAxisAndHasBarSeries_1 = false; + each(barSeriesModels, function (seriesModel) { + isBaseAxisAndHasBarSeries_1 = isBaseAxisAndHasBarSeries_1 || seriesModel.getBaseAxis() === model.axis; + }); + + if (isBaseAxisAndHasBarSeries_1) { + // Calculate placement of bars on axis. TODO should be decoupled + // with barLayout + var barWidthAndOffset = makeColumnLayout(barSeriesModels); // Adjust axis min and max to account for overflow + + var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset); + min = adjustedScale.min; + max = adjustedScale.max; + } + } + + return { + extent: [min, max], + // "fix" means "fixed", the value should not be + // changed in the subsequent steps. + fixMin: rawExtentResult.minFixed, + fixMax: rawExtentResult.maxFixed + }; + } + + function adjustScaleForOverflow(min, max, model, // Only support cartesian coord yet. + barWidthAndOffset) { + // Get Axis Length + var axisExtent = model.axis.getExtent(); + var axisLength = axisExtent[1] - axisExtent[0]; // Get bars on current base axis and calculate min and max overflow + + var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis); + + if (barsOnCurrentAxis === undefined) { + return { + min: min, + max: max + }; + } + + var minOverflow = Infinity; + each(barsOnCurrentAxis, function (item) { + minOverflow = Math.min(item.offset, minOverflow); + }); + var maxOverflow = -Infinity; + each(barsOnCurrentAxis, function (item) { + maxOverflow = Math.max(item.offset + item.width, maxOverflow); + }); + minOverflow = Math.abs(minOverflow); + maxOverflow = Math.abs(maxOverflow); + var totalOverFlow = minOverflow + maxOverflow; // Calculate required buffer based on old range and overflow + + var oldRange = max - min; + var oldRangePercentOfNew = 1 - (minOverflow + maxOverflow) / axisLength; + var overflowBuffer = oldRange / oldRangePercentOfNew - oldRange; + max += overflowBuffer * (maxOverflow / totalOverFlow); + min -= overflowBuffer * (minOverflow / totalOverFlow); + return { + min: min, + max: max + }; + } // Precondition of calling this method: + // The scale extent has been initailized using series data extent via + // `scale.setExtent` or `scale.unionExtentFromData`; + + + function niceScaleExtent(scale, inModel) { + var model = inModel; + var extentInfo = getScaleExtent(scale, model); + var extent = extentInfo.extent; + var splitNumber = model.get('splitNumber'); + + if (scale instanceof LogScale) { + scale.base = model.get('logBase'); + } + + var scaleType = scale.type; + var interval = model.get('interval'); + var isIntervalOrTime = scaleType === 'interval' || scaleType === 'time'; + scale.setExtent(extent[0], extent[1]); + scale.calcNiceExtent({ + splitNumber: splitNumber, + fixMin: extentInfo.fixMin, + fixMax: extentInfo.fixMax, + minInterval: isIntervalOrTime ? model.get('minInterval') : null, + maxInterval: isIntervalOrTime ? model.get('maxInterval') : null + }); // If some one specified the min, max. And the default calculated interval + // is not good enough. He can specify the interval. It is often appeared + // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard + // to be 60. + // FIXME + + if (interval != null) { + scale.setInterval && scale.setInterval(interval); + } + } + /** + * @param axisType Default retrieve from model.type + */ + + function createScaleByModel(model, axisType) { + axisType = axisType || model.get('type'); + + if (axisType) { + switch (axisType) { + // Buildin scale + case 'category': + return new OrdinalScale({ + ordinalMeta: model.getOrdinalMeta ? model.getOrdinalMeta() : model.getCategories(), + extent: [Infinity, -Infinity] + }); + + case 'time': + return new TimeScale({ + locale: model.ecModel.getLocaleModel(), + useUTC: model.ecModel.get('useUTC') + }); + + default: + // case 'value'/'interval', 'log', or others. + return new (Scale.getClass(axisType) || IntervalScale)(); + } + } + } + /** + * Check if the axis cross 0 + */ + + function ifAxisCrossZero(axis) { + var dataExtent = axis.scale.getExtent(); + var min = dataExtent[0]; + var max = dataExtent[1]; + return !(min > 0 && max > 0 || min < 0 && max < 0); + } + /** + * @param axis + * @return Label formatter function. + * param: {number} tickValue, + * param: {number} idx, the index in all ticks. + * If category axis, this param is not required. + * return: {string} label string. + */ + + function makeLabelFormatter(axis) { + var labelFormatter = axis.getLabelModel().get('formatter'); + var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null; + + if (axis.scale.type === 'time') { + return function (tpl) { + return function (tick, idx) { + return axis.scale.getFormattedLabel(tick, idx, tpl); + }; + }(labelFormatter); + } else if (isString(labelFormatter)) { + return function (tpl) { + return function (tick) { + // For category axis, get raw value; for numeric axis, + // get formatted label like '1,333,444'. + var label = axis.scale.getLabel(tick); + var text = tpl.replace('{value}', label != null ? label : ''); + return text; + }; + }(labelFormatter); + } else if (isFunction(labelFormatter)) { + return function (cb) { + return function (tick, idx) { + // The original intention of `idx` is "the index of the tick in all ticks". + // But the previous implementation of category axis do not consider the + // `axisLabel.interval`, which cause that, for example, the `interval` is + // `1`, then the ticks "name5", "name7", "name9" are displayed, where the + // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep + // the definition here for back compatibility. + if (categoryTickStart != null) { + idx = tick.value - categoryTickStart; + } + + return cb(getAxisRawValue(axis, tick), idx, tick.level != null ? { + level: tick.level + } : null); + }; + }(labelFormatter); + } else { + return function (tick) { + return axis.scale.getLabel(tick); + }; + } + } + function getAxisRawValue(axis, tick) { + // In category axis with data zoom, tick is not the original + // index of axis.data. So tick should not be exposed to user + // in category axis. + return axis.type === 'category' ? axis.scale.getLabel(tick) : tick.value; + } + /** + * @param axis + * @return Be null/undefined if no labels. + */ + + function estimateLabelUnionRect(axis) { + var axisModel = axis.model; + var scale = axis.scale; + + if (!axisModel.get(['axisLabel', 'show']) || scale.isBlank()) { + return; + } + + var realNumberScaleTicks; + var tickCount; + var categoryScaleExtent = scale.getExtent(); // Optimize for large category data, avoid call `getTicks()`. + + if (scale instanceof OrdinalScale) { + tickCount = scale.count(); + } else { + realNumberScaleTicks = scale.getTicks(); + tickCount = realNumberScaleTicks.length; + } + + var axisLabelModel = axis.getLabelModel(); + var labelFormatter = makeLabelFormatter(axis); + var rect; + var step = 1; // Simple optimization for large amount of labels + + if (tickCount > 40) { + step = Math.ceil(tickCount / 40); + } + + for (var i = 0; i < tickCount; i += step) { + var tick = realNumberScaleTicks ? realNumberScaleTicks[i] : { + value: categoryScaleExtent[0] + i + }; + var label = labelFormatter(tick, i); + var unrotatedSingleRect = axisLabelModel.getTextRect(label); + var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0); + rect ? rect.union(singleRect) : rect = singleRect; + } + + return rect; + } + + function rotateTextRect(textRect, rotate) { + var rotateRadians = rotate * Math.PI / 180; + var beforeWidth = textRect.width; + var beforeHeight = textRect.height; + var afterWidth = beforeWidth * Math.abs(Math.cos(rotateRadians)) + Math.abs(beforeHeight * Math.sin(rotateRadians)); + var afterHeight = beforeWidth * Math.abs(Math.sin(rotateRadians)) + Math.abs(beforeHeight * Math.cos(rotateRadians)); + var rotatedRect = new BoundingRect(textRect.x, textRect.y, afterWidth, afterHeight); + return rotatedRect; + } + /** + * @param model axisLabelModel or axisTickModel + * @return {number|String} Can be null|'auto'|number|function + */ + + + function getOptionCategoryInterval(model) { + var interval = model.get('interval'); + return interval == null ? 'auto' : interval; + } + /** + * Set `categoryInterval` as 0 implicitly indicates that + * show all labels reguardless of overlap. + * @param {Object} axis axisModel.axis + */ + + function shouldShowAllLabels(axis) { + return axis.type === 'category' && getOptionCategoryInterval(axis.getLabelModel()) === 0; + } + function getDataDimensionsOnAxis(data, axisDim) { + // Remove duplicated dat dimensions caused by `getStackedDimension`. + var dataDimMap = {}; // Currently `mapDimensionsAll` will contain stack result dimension ('__\0ecstackresult'). + // PENDING: is it reasonable? Do we need to remove the original dim from "coord dim" since + // there has been stacked result dim? + + each(data.mapDimensionsAll(axisDim), function (dataDim) { + // For example, the extent of the original dimension + // is [0.1, 0.5], the extent of the `stackResultDimension` + // is [7, 9], the final extent should NOT include [0.1, 0.5], + // because there is no graphic corresponding to [0.1, 0.5]. + // See the case in `test/area-stack.html` `main1`, where area line + // stack needs `yAxis` not start from 0. + dataDimMap[getStackedDimension(data, dataDim)] = true; + }); + return keys(dataDimMap); + } + function unionAxisExtentFromData(dataExtent, data, axisDim) { + if (data) { + each(getDataDimensionsOnAxis(data, axisDim), function (dim) { + var seriesExtent = data.getApproximateExtent(dim); + seriesExtent[0] < dataExtent[0] && (dataExtent[0] = seriesExtent[0]); + seriesExtent[1] > dataExtent[1] && (dataExtent[1] = seriesExtent[1]); + }); + } + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + var AxisModelCommonMixin = + /** @class */ + function () { + function AxisModelCommonMixin() {} + + AxisModelCommonMixin.prototype.getNeedCrossZero = function () { + var option = this.option; + return !option.scale; + }; + /** + * Should be implemented by each axis model if necessary. + * @return coordinate system model + */ + + + AxisModelCommonMixin.prototype.getCoordSysModel = function () { + return; + }; + + return AxisModelCommonMixin; + }(); + + /** + * Create a muti dimension List structure from seriesModel. + */ + + function createList(seriesModel) { + return createSeriesData(null, seriesModel); + } // export function createGraph(seriesModel) { + var dataStack$1 = { + isDimensionStacked: isDimensionStacked, + enableDataStack: enableDataStack, + getStackedDimension: getStackedDimension + }; + /** + * Create scale + * @param {Array.} dataExtent + * @param {Object|module:echarts/Model} option If `optoin.type` + * is secified, it can only be `'value'` currently. + */ + + function createScale(dataExtent, option) { + var axisModel = option; + + if (!(option instanceof Model)) { + axisModel = new Model(option); // FIXME + // Currently AxisModelCommonMixin has nothing to do with the + // the requirements of `axisHelper.createScaleByModel`. For + // example the method `getCategories` and `getOrdinalMeta` + // are required for `'category'` axis, and ecModel are required + // for `'time'` axis. But occationally echarts-gl happened + // to only use `'value'` axis. + // zrUtil.mixin(axisModel, AxisModelCommonMixin); + } + + var scale = createScaleByModel(axisModel); + scale.setExtent(dataExtent[0], dataExtent[1]); + niceScaleExtent(scale, axisModel); + return scale; + } + /** + * Mixin common methods to axis model, + * + * Inlcude methods + * `getFormattedLabels() => Array.` + * `getCategories() => Array.` + * `getMin(origin: boolean) => number` + * `getMax(origin: boolean) => number` + * `getNeedCrossZero() => boolean` + */ + + function mixinAxisModelCommonMethods(Model) { + mixin(Model, AxisModelCommonMixin); + } + function createTextStyle$1(textStyleModel, opts) { + opts = opts || {}; + return createTextStyle(textStyleModel, null, null, opts.state !== 'normal'); + } + + var helper = /*#__PURE__*/Object.freeze({ + __proto__: null, + createList: createList, + getLayoutRect: getLayoutRect, + dataStack: dataStack$1, + createScale: createScale, + mixinAxisModelCommonMethods: mixinAxisModelCommonMethods, + getECData: getECData, + createTextStyle: createTextStyle$1, + createDimensions: createDimensions, + createSymbol: createSymbol, + enableHoverEmphasis: enableHoverEmphasis + }); + + var EPSILON$4 = 1e-8; + function isAroundEqual$1(a, b) { + return Math.abs(a - b) < EPSILON$4; + } + function contain$2(points, x, y) { + var w = 0; + var p = points[0]; + if (!p) { + return false; + } + for (var i = 1; i < points.length; i++) { + var p2 = points[i]; + w += windingLine(p[0], p[1], p2[0], p2[1], x, y); + p = p2; + } + var p0 = points[0]; + if (!isAroundEqual$1(p[0], p0[0]) || !isAroundEqual$1(p[1], p0[1])) { + w += windingLine(p[0], p[1], p0[0], p0[1], x, y); + } + return w !== 0; + } + + var TMP_TRANSFORM = []; + + function transformPoints(points, transform) { + for (var p = 0; p < points.length; p++) { + applyTransform(points[p], points[p], transform); + } + } + + function updateBBoxFromPoints(points, min$1, max$1, projection) { + for (var i = 0; i < points.length; i++) { + var p = points[i]; + + if (projection) { + // projection may return null point. + p = projection.project(p); + } + + if (p && isFinite(p[0]) && isFinite(p[1])) { + min(min$1, min$1, p); + max(max$1, max$1, p); + } + } + } + + function centroid(points) { + var signedArea = 0; + var cx = 0; + var cy = 0; + var len = points.length; + var x0 = points[len - 1][0]; + var y0 = points[len - 1][1]; // Polygon should been closed. + + for (var i = 0; i < len; i++) { + var x1 = points[i][0]; + var y1 = points[i][1]; + var a = x0 * y1 - x1 * y0; + signedArea += a; + cx += (x0 + x1) * a; + cy += (y0 + y1) * a; + x0 = x1; + y0 = y1; + } + + return signedArea ? [cx / signedArea / 3, cy / signedArea / 3, signedArea] : [points[0][0] || 0, points[0][1] || 0]; + } + + var Region = + /** @class */ + function () { + function Region(name) { + this.name = name; + } + + Region.prototype.setCenter = function (center) { + this._center = center; + }; + /** + * Get center point in data unit. That is, + * for GeoJSONRegion, the unit is lat/lng, + * for GeoSVGRegion, the unit is SVG local coord. + */ + + + Region.prototype.getCenter = function () { + var center = this._center; + + if (!center) { + // In most cases there are no need to calculate this center. + // So calculate only when called. + center = this._center = this.calcCenter(); + } + + return center; + }; + + return Region; + }(); + + var GeoJSONPolygonGeometry = + /** @class */ + function () { + function GeoJSONPolygonGeometry(exterior, interiors) { + this.type = 'polygon'; + this.exterior = exterior; + this.interiors = interiors; + } + + return GeoJSONPolygonGeometry; + }(); + + var GeoJSONLineStringGeometry = + /** @class */ + function () { + function GeoJSONLineStringGeometry(points) { + this.type = 'linestring'; + this.points = points; + } + + return GeoJSONLineStringGeometry; + }(); + + var GeoJSONRegion = + /** @class */ + function (_super) { + __extends(GeoJSONRegion, _super); + + function GeoJSONRegion(name, geometries, cp) { + var _this = _super.call(this, name) || this; + + _this.type = 'geoJSON'; + _this.geometries = geometries; + _this._center = cp && [cp[0], cp[1]]; + return _this; + } + + GeoJSONRegion.prototype.calcCenter = function () { + var geometries = this.geometries; + var largestGeo; + var largestGeoSize = 0; + + for (var i = 0; i < geometries.length; i++) { + var geo = geometries[i]; + var exterior = geo.exterior; // Simple trick to use points count instead of polygon area as region size. + // Ignore linestring + + var size = exterior && exterior.length; + + if (size > largestGeoSize) { + largestGeo = geo; + largestGeoSize = size; + } + } + + if (largestGeo) { + return centroid(largestGeo.exterior); + } // from bounding rect by default. + + + var rect = this.getBoundingRect(); + return [rect.x + rect.width / 2, rect.y + rect.height / 2]; + }; + + GeoJSONRegion.prototype.getBoundingRect = function (projection) { + var rect = this._rect; // Always recalculate if using projection. + + if (rect && !projection) { + return rect; + } + + var min = [Infinity, Infinity]; + var max = [-Infinity, -Infinity]; + var geometries = this.geometries; + each(geometries, function (geo) { + if (geo.type === 'polygon') { + // Doesn't consider hole + updateBBoxFromPoints(geo.exterior, min, max, projection); + } else { + each(geo.points, function (points) { + updateBBoxFromPoints(points, min, max, projection); + }); + } + }); // Normalie invalid bounding. + + if (!(isFinite(min[0]) && isFinite(min[1]) && isFinite(max[0]) && isFinite(max[1]))) { + min[0] = min[1] = max[0] = max[1] = 0; + } + + rect = new BoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]); + + if (!projection) { + this._rect = rect; + } + + return rect; + }; + + GeoJSONRegion.prototype.contain = function (coord) { + var rect = this.getBoundingRect(); + var geometries = this.geometries; + + if (!rect.contain(coord[0], coord[1])) { + return false; + } + + loopGeo: for (var i = 0, len = geometries.length; i < len; i++) { + var geo = geometries[i]; // Only support polygon. + + if (geo.type !== 'polygon') { + continue; + } + + var exterior = geo.exterior; + var interiors = geo.interiors; + + if (contain$2(exterior, coord[0], coord[1])) { + // Not in the region if point is in the hole. + for (var k = 0; k < (interiors ? interiors.length : 0); k++) { + if (contain$2(interiors[k], coord[0], coord[1])) { + continue loopGeo; + } + } + + return true; + } + } + + return false; + }; + /** + * Transform the raw coords to target bounding. + * @param x + * @param y + * @param width + * @param height + */ + + + GeoJSONRegion.prototype.transformTo = function (x, y, width, height) { + var rect = this.getBoundingRect(); + var aspect = rect.width / rect.height; + + if (!width) { + width = aspect * height; + } else if (!height) { + height = width / aspect; + } + + var target = new BoundingRect(x, y, width, height); + var transform = rect.calculateTransform(target); + var geometries = this.geometries; + + for (var i = 0; i < geometries.length; i++) { + var geo = geometries[i]; + + if (geo.type === 'polygon') { + transformPoints(geo.exterior, transform); + each(geo.interiors, function (interior) { + transformPoints(interior, transform); + }); + } else { + each(geo.points, function (points) { + transformPoints(points, transform); + }); + } + } + + rect = this._rect; + rect.copy(target); // Update center + + this._center = [rect.x + rect.width / 2, rect.y + rect.height / 2]; + }; + + GeoJSONRegion.prototype.cloneShallow = function (name) { + name == null && (name = this.name); + var newRegion = new GeoJSONRegion(name, this.geometries, this._center); + newRegion._rect = this._rect; + newRegion.transformTo = null; // Simply avoid to be called. + + return newRegion; + }; + + return GeoJSONRegion; + }(Region); + + var GeoSVGRegion = + /** @class */ + function (_super) { + __extends(GeoSVGRegion, _super); + + function GeoSVGRegion(name, elOnlyForCalculate) { + var _this = _super.call(this, name) || this; + + _this.type = 'geoSVG'; + _this._elOnlyForCalculate = elOnlyForCalculate; + return _this; + } + + GeoSVGRegion.prototype.calcCenter = function () { + var el = this._elOnlyForCalculate; + var rect = el.getBoundingRect(); + var center = [rect.x + rect.width / 2, rect.y + rect.height / 2]; + var mat = identity(TMP_TRANSFORM); + var target = el; + + while (target && !target.isGeoSVGGraphicRoot) { + mul$1(mat, target.getLocalTransform(), mat); + target = target.parent; + } + + invert(mat, mat); + applyTransform(center, center, mat); + return center; + }; + + return GeoSVGRegion; + }(Region); + + function decode(json) { + if (!json.UTF8Encoding) { + return json; + } + + var jsonCompressed = json; + var encodeScale = jsonCompressed.UTF8Scale; + + if (encodeScale == null) { + encodeScale = 1024; + } + + var features = jsonCompressed.features; + each(features, function (feature) { + var geometry = feature.geometry; + var encodeOffsets = geometry.encodeOffsets; + var coordinates = geometry.coordinates; // Geometry may be appeded manually in the script after json loaded. + // In this case this geometry is usually not encoded. + + if (!encodeOffsets) { + return; + } + + switch (geometry.type) { + case 'LineString': + geometry.coordinates = decodeRing(coordinates, encodeOffsets, encodeScale); + break; + + case 'Polygon': + decodeRings(coordinates, encodeOffsets, encodeScale); + break; + + case 'MultiLineString': + decodeRings(coordinates, encodeOffsets, encodeScale); + break; + + case 'MultiPolygon': + each(coordinates, function (rings, idx) { + return decodeRings(rings, encodeOffsets[idx], encodeScale); + }); + } + }); // Has been decoded + + jsonCompressed.UTF8Encoding = false; + return jsonCompressed; + } + + function decodeRings(rings, encodeOffsets, encodeScale) { + for (var c = 0; c < rings.length; c++) { + rings[c] = decodeRing(rings[c], encodeOffsets[c], encodeScale); + } + } + + function decodeRing(coordinate, encodeOffsets, encodeScale) { + var result = []; + var prevX = encodeOffsets[0]; + var prevY = encodeOffsets[1]; + + for (var i = 0; i < coordinate.length; i += 2) { + var x = coordinate.charCodeAt(i) - 64; + var y = coordinate.charCodeAt(i + 1) - 64; // ZigZag decoding + + x = x >> 1 ^ -(x & 1); + y = y >> 1 ^ -(y & 1); // Delta deocding + + x += prevX; + y += prevY; + prevX = x; + prevY = y; // Dequantize + + result.push([x / encodeScale, y / encodeScale]); + } + + return result; + } + + function parseGeoJSON(geoJson, nameProperty) { + geoJson = decode(geoJson); + return map(filter(geoJson.features, function (featureObj) { + // Output of mapshaper may have geometry null + return featureObj.geometry && featureObj.properties && featureObj.geometry.coordinates.length > 0; + }), function (featureObj) { + var properties = featureObj.properties; + var geo = featureObj.geometry; + var geometries = []; + + switch (geo.type) { + case 'Polygon': + var coordinates = geo.coordinates; // According to the GeoJSON specification. + // First must be exterior, and the rest are all interior(holes). + + geometries.push(new GeoJSONPolygonGeometry(coordinates[0], coordinates.slice(1))); + break; + + case 'MultiPolygon': + each(geo.coordinates, function (item) { + if (item[0]) { + geometries.push(new GeoJSONPolygonGeometry(item[0], item.slice(1))); + } + }); + break; + + case 'LineString': + geometries.push(new GeoJSONLineStringGeometry([geo.coordinates])); + break; + + case 'MultiLineString': + geometries.push(new GeoJSONLineStringGeometry(geo.coordinates)); + } + + var region = new GeoJSONRegion(properties[nameProperty || 'name'], geometries, properties.cp); + region.properties = properties; + return region; + }); + } + + var number = /*#__PURE__*/Object.freeze({ + __proto__: null, + linearMap: linearMap, + round: round, + asc: asc, + getPrecision: getPrecision, + getPrecisionSafe: getPrecisionSafe, + getPixelPrecision: getPixelPrecision, + getPercentWithPrecision: getPercentWithPrecision, + MAX_SAFE_INTEGER: MAX_SAFE_INTEGER, + remRadian: remRadian, + isRadianAroundZero: isRadianAroundZero, + parseDate: parseDate, + quantity: quantity, + quantityExponent: quantityExponent, + nice: nice, + quantile: quantile, + reformIntervals: reformIntervals, + isNumeric: isNumeric, + numericToNumber: numericToNumber + }); + + var time = /*#__PURE__*/Object.freeze({ + __proto__: null, + parse: parseDate, + format: format + }); + + var graphic$1 = /*#__PURE__*/Object.freeze({ + __proto__: null, + extendShape: extendShape, + extendPath: extendPath, + makePath: makePath, + makeImage: makeImage, + mergePath: mergePath$1, + resizePath: resizePath, + createIcon: createIcon, + updateProps: updateProps, + initProps: initProps, + getTransform: getTransform, + clipPointsByRect: clipPointsByRect, + clipRectByRect: clipRectByRect, + registerShape: registerShape, + getShapeClass: getShapeClass, + Group: Group, + Image: ZRImage, + Text: ZRText, + Circle: Circle, + Ellipse: Ellipse, + Sector: Sector, + Ring: Ring, + Polygon: Polygon, + Polyline: Polyline, + Rect: Rect, + Line: Line, + BezierCurve: BezierCurve, + Arc: Arc, + IncrementalDisplayable: IncrementalDisplayable, + CompoundPath: CompoundPath, + LinearGradient: LinearGradient, + RadialGradient: RadialGradient, + BoundingRect: BoundingRect + }); + + var format$1 = /*#__PURE__*/Object.freeze({ + __proto__: null, + addCommas: addCommas, + toCamelCase: toCamelCase, + normalizeCssArray: normalizeCssArray$1, + encodeHTML: encodeHTML, + formatTpl: formatTpl, + getTooltipMarker: getTooltipMarker, + formatTime: formatTime, + capitalFirst: capitalFirst, + truncateText: truncateText, + getTextRect: getTextRect + }); + + var util$1 = /*#__PURE__*/Object.freeze({ + __proto__: null, + map: map, + each: each, + indexOf: indexOf, + inherits: inherits, + reduce: reduce, + filter: filter, + bind: bind, + curry: curry, + isArray: isArray, + isString: isString, + isObject: isObject, + isFunction: isFunction, + extend: extend, + defaults: defaults, + clone: clone, + merge: merge + }); + + var inner$5 = makeInner(); + function createAxisLabels(axis) { + // Only ordinal scale support tick interval + return axis.type === 'category' ? makeCategoryLabels(axis) : makeRealNumberLabels(axis); + } + /** + * @param {module:echats/coord/Axis} axis + * @param {module:echarts/model/Model} tickModel For example, can be axisTick, splitLine, splitArea. + * @return {Object} { + * ticks: Array. + * tickCategoryInterval: number + * } + */ + + function createAxisTicks(axis, tickModel) { + // Only ordinal scale support tick interval + return axis.type === 'category' ? makeCategoryTicks(axis, tickModel) : { + ticks: map(axis.scale.getTicks(), function (tick) { + return tick.value; + }) + }; + } + + function makeCategoryLabels(axis) { + var labelModel = axis.getLabelModel(); + var result = makeCategoryLabelsActually(axis, labelModel); + return !labelModel.get('show') || axis.scale.isBlank() ? { + labels: [], + labelCategoryInterval: result.labelCategoryInterval + } : result; + } + + function makeCategoryLabelsActually(axis, labelModel) { + var labelsCache = getListCache(axis, 'labels'); + var optionLabelInterval = getOptionCategoryInterval(labelModel); + var result = listCacheGet(labelsCache, optionLabelInterval); + + if (result) { + return result; + } + + var labels; + var numericLabelInterval; + + if (isFunction(optionLabelInterval)) { + labels = makeLabelsByCustomizedCategoryInterval(axis, optionLabelInterval); + } else { + numericLabelInterval = optionLabelInterval === 'auto' ? makeAutoCategoryInterval(axis) : optionLabelInterval; + labels = makeLabelsByNumericCategoryInterval(axis, numericLabelInterval); + } // Cache to avoid calling interval function repeatly. + + + return listCacheSet(labelsCache, optionLabelInterval, { + labels: labels, + labelCategoryInterval: numericLabelInterval + }); + } + + function makeCategoryTicks(axis, tickModel) { + var ticksCache = getListCache(axis, 'ticks'); + var optionTickInterval = getOptionCategoryInterval(tickModel); + var result = listCacheGet(ticksCache, optionTickInterval); + + if (result) { + return result; + } + + var ticks; + var tickCategoryInterval; // Optimize for the case that large category data and no label displayed, + // we should not return all ticks. + + if (!tickModel.get('show') || axis.scale.isBlank()) { + ticks = []; + } + + if (isFunction(optionTickInterval)) { + ticks = makeLabelsByCustomizedCategoryInterval(axis, optionTickInterval, true); + } // Always use label interval by default despite label show. Consider this + // scenario, Use multiple grid with the xAxis sync, and only one xAxis shows + // labels. `splitLine` and `axisTick` should be consistent in this case. + else if (optionTickInterval === 'auto') { + var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel()); + tickCategoryInterval = labelsResult.labelCategoryInterval; + ticks = map(labelsResult.labels, function (labelItem) { + return labelItem.tickValue; + }); + } else { + tickCategoryInterval = optionTickInterval; + ticks = makeLabelsByNumericCategoryInterval(axis, tickCategoryInterval, true); + } // Cache to avoid calling interval function repeatly. + + + return listCacheSet(ticksCache, optionTickInterval, { + ticks: ticks, + tickCategoryInterval: tickCategoryInterval + }); + } + + function makeRealNumberLabels(axis) { + var ticks = axis.scale.getTicks(); + var labelFormatter = makeLabelFormatter(axis); + return { + labels: map(ticks, function (tick, idx) { + return { + level: tick.level, + formattedLabel: labelFormatter(tick, idx), + rawLabel: axis.scale.getLabel(tick), + tickValue: tick.value + }; + }) + }; + } + + function getListCache(axis, prop) { + // Because key can be funciton, and cache size always be small, we use array cache. + return inner$5(axis)[prop] || (inner$5(axis)[prop] = []); + } + + function listCacheGet(cache, key) { + for (var i = 0; i < cache.length; i++) { + if (cache[i].key === key) { + return cache[i].value; + } + } + } + + function listCacheSet(cache, key, value) { + cache.push({ + key: key, + value: value + }); + return value; + } + + function makeAutoCategoryInterval(axis) { + var result = inner$5(axis).autoInterval; + return result != null ? result : inner$5(axis).autoInterval = axis.calculateCategoryInterval(); + } + /** + * Calculate interval for category axis ticks and labels. + * To get precise result, at least one of `getRotate` and `isHorizontal` + * should be implemented in axis. + */ + + + function calculateCategoryInterval(axis) { + var params = fetchAutoCategoryIntervalCalculationParams(axis); + var labelFormatter = makeLabelFormatter(axis); + var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI; + var ordinalScale = axis.scale; + var ordinalExtent = ordinalScale.getExtent(); // Providing this method is for optimization: + // avoid generating a long array by `getTicks` + // in large category data case. + + var tickCount = ordinalScale.count(); + + if (ordinalExtent[1] - ordinalExtent[0] < 1) { + return 0; + } + + var step = 1; // Simple optimization. Empirical value: tick count should less than 40. + + if (tickCount > 40) { + step = Math.max(1, Math.floor(tickCount / 40)); + } + + var tickValue = ordinalExtent[0]; + var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue); + var unitW = Math.abs(unitSpan * Math.cos(rotation)); + var unitH = Math.abs(unitSpan * Math.sin(rotation)); + var maxW = 0; + var maxH = 0; // Caution: Performance sensitive for large category data. + // Consider dataZoom, we should make appropriate step to avoid O(n) loop. + + for (; tickValue <= ordinalExtent[1]; tickValue += step) { + var width = 0; + var height = 0; // Not precise, do not consider align and vertical align + // and each distance from axis line yet. + + var rect = getBoundingRect(labelFormatter({ + value: tickValue + }), params.font, 'center', 'top'); // Magic number + + width = rect.width * 1.3; + height = rect.height * 1.3; // Min size, void long loop. + + maxW = Math.max(maxW, width, 7); + maxH = Math.max(maxH, height, 7); + } + + var dw = maxW / unitW; + var dh = maxH / unitH; // 0/0 is NaN, 1/0 is Infinity. + + isNaN(dw) && (dw = Infinity); + isNaN(dh) && (dh = Infinity); + var interval = Math.max(0, Math.floor(Math.min(dw, dh))); + var cache = inner$5(axis.model); + var axisExtent = axis.getExtent(); + var lastAutoInterval = cache.lastAutoInterval; + var lastTickCount = cache.lastTickCount; // Use cache to keep interval stable while moving zoom window, + // otherwise the calculated interval might jitter when the zoom + // window size is close to the interval-changing size. + // For example, if all of the axis labels are `a, b, c, d, e, f, g`. + // The jitter will cause that sometimes the displayed labels are + // `a, d, g` (interval: 2) sometimes `a, c, e`(interval: 1). + + if (lastAutoInterval != null && lastTickCount != null && Math.abs(lastAutoInterval - interval) <= 1 && Math.abs(lastTickCount - tickCount) <= 1 // Always choose the bigger one, otherwise the critical + // point is not the same when zooming in or zooming out. + && lastAutoInterval > interval // If the axis change is caused by chart resize, the cache should not + // be used. Otherwise some hiden labels might not be shown again. + && cache.axisExtent0 === axisExtent[0] && cache.axisExtent1 === axisExtent[1]) { + interval = lastAutoInterval; + } // Only update cache if cache not used, otherwise the + // changing of interval is too insensitive. + else { + cache.lastTickCount = tickCount; + cache.lastAutoInterval = interval; + cache.axisExtent0 = axisExtent[0]; + cache.axisExtent1 = axisExtent[1]; + } + + return interval; + } + + function fetchAutoCategoryIntervalCalculationParams(axis) { + var labelModel = axis.getLabelModel(); + return { + axisRotate: axis.getRotate ? axis.getRotate() : axis.isHorizontal && !axis.isHorizontal() ? 90 : 0, + labelRotate: labelModel.get('rotate') || 0, + font: labelModel.getFont() + }; + } + + function makeLabelsByNumericCategoryInterval(axis, categoryInterval, onlyTick) { + var labelFormatter = makeLabelFormatter(axis); + var ordinalScale = axis.scale; + var ordinalExtent = ordinalScale.getExtent(); + var labelModel = axis.getLabelModel(); + var result = []; // TODO: axisType: ordinalTime, pick the tick from each month/day/year/... + + var step = Math.max((categoryInterval || 0) + 1, 1); + var startTick = ordinalExtent[0]; + var tickCount = ordinalScale.count(); // Calculate start tick based on zero if possible to keep label consistent + // while zooming and moving while interval > 0. Otherwise the selection + // of displayable ticks and symbols probably keep changing. + // 3 is empirical value. + + if (startTick !== 0 && step > 1 && tickCount / step > 2) { + startTick = Math.round(Math.ceil(startTick / step) * step); + } // (1) Only add min max label here but leave overlap checking + // to render stage, which also ensure the returned list + // suitable for splitLine and splitArea rendering. + // (2) Scales except category always contain min max label so + // do not need to perform this process. + + + var showAllLabel = shouldShowAllLabels(axis); + var includeMinLabel = labelModel.get('showMinLabel') || showAllLabel; + var includeMaxLabel = labelModel.get('showMaxLabel') || showAllLabel; + + if (includeMinLabel && startTick !== ordinalExtent[0]) { + addItem(ordinalExtent[0]); + } // Optimize: avoid generating large array by `ordinalScale.getTicks()`. + + + var tickValue = startTick; + + for (; tickValue <= ordinalExtent[1]; tickValue += step) { + addItem(tickValue); + } + + if (includeMaxLabel && tickValue - step !== ordinalExtent[1]) { + addItem(ordinalExtent[1]); + } + + function addItem(tickValue) { + var tickObj = { + value: tickValue + }; + result.push(onlyTick ? tickValue : { + formattedLabel: labelFormatter(tickObj), + rawLabel: ordinalScale.getLabel(tickObj), + tickValue: tickValue + }); + } + + return result; + } + + function makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) { + var ordinalScale = axis.scale; + var labelFormatter = makeLabelFormatter(axis); + var result = []; + each(ordinalScale.getTicks(), function (tick) { + var rawLabel = ordinalScale.getLabel(tick); + var tickValue = tick.value; + + if (categoryInterval(tick.value, rawLabel)) { + result.push(onlyTick ? tickValue : { + formattedLabel: labelFormatter(tick), + rawLabel: rawLabel, + tickValue: tickValue + }); + } + }); + return result; + } + + var NORMALIZED_EXTENT = [0, 1]; + /** + * Base class of Axis. + */ + + var Axis = + /** @class */ + function () { + function Axis(dim, scale, extent) { + this.onBand = false; + this.inverse = false; + this.dim = dim; + this.scale = scale; + this._extent = extent || [0, 0]; + } + /** + * If axis extent contain given coord + */ + + + Axis.prototype.contain = function (coord) { + var extent = this._extent; + var min = Math.min(extent[0], extent[1]); + var max = Math.max(extent[0], extent[1]); + return coord >= min && coord <= max; + }; + /** + * If axis extent contain given data + */ + + + Axis.prototype.containData = function (data) { + return this.scale.contain(data); + }; + /** + * Get coord extent. + */ + + + Axis.prototype.getExtent = function () { + return this._extent.slice(); + }; + /** + * Get precision used for formatting + */ + + + Axis.prototype.getPixelPrecision = function (dataExtent) { + return getPixelPrecision(dataExtent || this.scale.getExtent(), this._extent); + }; + /** + * Set coord extent + */ + + + Axis.prototype.setExtent = function (start, end) { + var extent = this._extent; + extent[0] = start; + extent[1] = end; + }; + /** + * Convert data to coord. Data is the rank if it has an ordinal scale + */ + + + Axis.prototype.dataToCoord = function (data, clamp) { + var extent = this._extent; + var scale = this.scale; + data = scale.normalize(data); + + if (this.onBand && scale.type === 'ordinal') { + extent = extent.slice(); + fixExtentWithBands(extent, scale.count()); + } + + return linearMap(data, NORMALIZED_EXTENT, extent, clamp); + }; + /** + * Convert coord to data. Data is the rank if it has an ordinal scale + */ + + + Axis.prototype.coordToData = function (coord, clamp) { + var extent = this._extent; + var scale = this.scale; + + if (this.onBand && scale.type === 'ordinal') { + extent = extent.slice(); + fixExtentWithBands(extent, scale.count()); + } + + var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp); + return this.scale.scale(t); + }; + /** + * Convert pixel point to data in axis + */ + + + Axis.prototype.pointToData = function (point, clamp) { + // Should be implemented in derived class if necessary. + return; + }; + /** + * Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`, + * `axis.getTicksCoords` considers `onBand`, which is used by + * `boundaryGap:true` of category axis and splitLine and splitArea. + * @param opt.tickModel default: axis.model.getModel('axisTick') + * @param opt.clamp If `true`, the first and the last + * tick must be at the axis end points. Otherwise, clip ticks + * that outside the axis extent. + */ + + + Axis.prototype.getTicksCoords = function (opt) { + opt = opt || {}; + var tickModel = opt.tickModel || this.getTickModel(); + var result = createAxisTicks(this, tickModel); + var ticks = result.ticks; + var ticksCoords = map(ticks, function (tickVal) { + return { + coord: this.dataToCoord(this.scale.type === 'ordinal' ? this.scale.getRawOrdinalNumber(tickVal) : tickVal), + tickValue: tickVal + }; + }, this); + var alignWithLabel = tickModel.get('alignWithLabel'); + fixOnBandTicksCoords(this, ticksCoords, alignWithLabel, opt.clamp); + return ticksCoords; + }; + + Axis.prototype.getMinorTicksCoords = function () { + if (this.scale.type === 'ordinal') { + // Category axis doesn't support minor ticks + return []; + } + + var minorTickModel = this.model.getModel('minorTick'); + var splitNumber = minorTickModel.get('splitNumber'); // Protection. + + if (!(splitNumber > 0 && splitNumber < 100)) { + splitNumber = 5; + } + + var minorTicks = this.scale.getMinorTicks(splitNumber); + var minorTicksCoords = map(minorTicks, function (minorTicksGroup) { + return map(minorTicksGroup, function (minorTick) { + return { + coord: this.dataToCoord(minorTick), + tickValue: minorTick + }; + }, this); + }, this); + return minorTicksCoords; + }; + + Axis.prototype.getViewLabels = function () { + return createAxisLabels(this).labels; + }; + + Axis.prototype.getLabelModel = function () { + return this.model.getModel('axisLabel'); + }; + /** + * Notice here we only get the default tick model. For splitLine + * or splitArea, we should pass the splitLineModel or splitAreaModel + * manually when calling `getTicksCoords`. + * In GL, this method may be overrided to: + * `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));` + */ + + + Axis.prototype.getTickModel = function () { + return this.model.getModel('axisTick'); + }; + /** + * Get width of band + */ + + + Axis.prototype.getBandWidth = function () { + var axisExtent = this._extent; + var dataExtent = this.scale.getExtent(); + var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0); // Fix #2728, avoid NaN when only one data. + + len === 0 && (len = 1); + var size = Math.abs(axisExtent[1] - axisExtent[0]); + return Math.abs(size) / len; + }; + /** + * Only be called in category axis. + * Can be overrided, consider other axes like in 3D. + * @return Auto interval for cateogry axis tick and label + */ + + + Axis.prototype.calculateCategoryInterval = function () { + return calculateCategoryInterval(this); + }; + + return Axis; + }(); + + function fixExtentWithBands(extent, nTick) { + var size = extent[1] - extent[0]; + var len = nTick; + var margin = size / len / 2; + extent[0] += margin; + extent[1] -= margin; + } // If axis has labels [1, 2, 3, 4]. Bands on the axis are + // |---1---|---2---|---3---|---4---|. + // So the displayed ticks and splitLine/splitArea should between + // each data item, otherwise cause misleading (e.g., split tow bars + // of a single data item when there are two bar series). + // Also consider if tickCategoryInterval > 0 and onBand, ticks and + // splitLine/spliteArea should layout appropriately corresponding + // to displayed labels. (So we should not use `getBandWidth` in this + // case). + + + function fixOnBandTicksCoords(axis, ticksCoords, alignWithLabel, clamp) { + var ticksLen = ticksCoords.length; + + if (!axis.onBand || alignWithLabel || !ticksLen) { + return; + } + + var axisExtent = axis.getExtent(); + var last; + var diffSize; + + if (ticksLen === 1) { + ticksCoords[0].coord = axisExtent[0]; + last = ticksCoords[1] = { + coord: axisExtent[0] + }; + } else { + var crossLen = ticksCoords[ticksLen - 1].tickValue - ticksCoords[0].tickValue; + var shift_1 = (ticksCoords[ticksLen - 1].coord - ticksCoords[0].coord) / crossLen; + each(ticksCoords, function (ticksItem) { + ticksItem.coord -= shift_1 / 2; + }); + var dataExtent = axis.scale.getExtent(); + diffSize = 1 + dataExtent[1] - ticksCoords[ticksLen - 1].tickValue; + last = { + coord: ticksCoords[ticksLen - 1].coord + shift_1 * diffSize + }; + ticksCoords.push(last); + } + + var inverse = axisExtent[0] > axisExtent[1]; // Handling clamp. + + if (littleThan(ticksCoords[0].coord, axisExtent[0])) { + clamp ? ticksCoords[0].coord = axisExtent[0] : ticksCoords.shift(); + } + + if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) { + ticksCoords.unshift({ + coord: axisExtent[0] + }); + } + + if (littleThan(axisExtent[1], last.coord)) { + clamp ? last.coord = axisExtent[1] : ticksCoords.pop(); + } + + if (clamp && littleThan(last.coord, axisExtent[1])) { + ticksCoords.push({ + coord: axisExtent[1] + }); + } + + function littleThan(a, b) { + // Avoid rounding error cause calculated tick coord different with extent. + // It may cause an extra unecessary tick added. + a = round(a); + b = round(b); + return inverse ? a > b : a < b; + } + } + + // Should use `ComponentModel.extend` or `class XXXX extend ComponentModel` to create class. + // Then use `registerComponentModel` in `install` parameter when `use` this extension. For example: + // class Bar3DModel extends ComponentModel {} + // export function install(registers) { regsiters.registerComponentModel(Bar3DModel); } + // echarts.use(install); + + function extendComponentModel(proto) { + var Model = ComponentModel.extend(proto); + ComponentModel.registerClass(Model); + return Model; + } + function extendComponentView(proto) { + var View = ComponentView.extend(proto); + ComponentView.registerClass(View); + return View; + } + function extendSeriesModel(proto) { + var Model = SeriesModel.extend(proto); + SeriesModel.registerClass(Model); + return Model; + } + function extendChartView(proto) { + var View = ChartView.extend(proto); + ChartView.registerClass(View); + return View; + } + + var PI2$6 = Math.PI * 2; + var CMD$3 = PathProxy.CMD; + var DEFAULT_SEARCH_SPACE = ['top', 'right', 'bottom', 'left']; + + function getCandidateAnchor(pos, distance, rect, outPt, outDir) { + var width = rect.width; + var height = rect.height; + + switch (pos) { + case 'top': + outPt.set(rect.x + width / 2, rect.y - distance); + outDir.set(0, -1); + break; + + case 'bottom': + outPt.set(rect.x + width / 2, rect.y + height + distance); + outDir.set(0, 1); + break; + + case 'left': + outPt.set(rect.x - distance, rect.y + height / 2); + outDir.set(-1, 0); + break; + + case 'right': + outPt.set(rect.x + width + distance, rect.y + height / 2); + outDir.set(1, 0); + break; + } + } + + function projectPointToArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y, out) { + x -= cx; + y -= cy; + var d = Math.sqrt(x * x + y * y); + x /= d; + y /= d; // Intersect point. + + var ox = x * r + cx; + var oy = y * r + cy; + + if (Math.abs(startAngle - endAngle) % PI2$6 < 1e-4) { + // Is a circle + out[0] = ox; + out[1] = oy; + return d - r; + } + + if (anticlockwise) { + var tmp = startAngle; + startAngle = normalizeRadian(endAngle); + endAngle = normalizeRadian(tmp); + } else { + startAngle = normalizeRadian(startAngle); + endAngle = normalizeRadian(endAngle); + } + + if (startAngle > endAngle) { + endAngle += PI2$6; + } + + var angle = Math.atan2(y, x); + + if (angle < 0) { + angle += PI2$6; + } + + if (angle >= startAngle && angle <= endAngle || angle + PI2$6 >= startAngle && angle + PI2$6 <= endAngle) { + // Project point is on the arc. + out[0] = ox; + out[1] = oy; + return d - r; + } + + var x1 = r * Math.cos(startAngle) + cx; + var y1 = r * Math.sin(startAngle) + cy; + var x2 = r * Math.cos(endAngle) + cx; + var y2 = r * Math.sin(endAngle) + cy; + var d1 = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y); + var d2 = (x2 - x) * (x2 - x) + (y2 - y) * (y2 - y); + + if (d1 < d2) { + out[0] = x1; + out[1] = y1; + return Math.sqrt(d1); + } else { + out[0] = x2; + out[1] = y2; + return Math.sqrt(d2); + } + } + + function projectPointToLine(x1, y1, x2, y2, x, y, out, limitToEnds) { + var dx = x - x1; + var dy = y - y1; + var dx1 = x2 - x1; + var dy1 = y2 - y1; + var lineLen = Math.sqrt(dx1 * dx1 + dy1 * dy1); + dx1 /= lineLen; + dy1 /= lineLen; // dot product + + var projectedLen = dx * dx1 + dy * dy1; + var t = projectedLen / lineLen; + + if (limitToEnds) { + t = Math.min(Math.max(t, 0), 1); + } + + t *= lineLen; + var ox = out[0] = x1 + t * dx1; + var oy = out[1] = y1 + t * dy1; + return Math.sqrt((ox - x) * (ox - x) + (oy - y) * (oy - y)); + } + + function projectPointToRect(x1, y1, width, height, x, y, out) { + if (width < 0) { + x1 = x1 + width; + width = -width; + } + + if (height < 0) { + y1 = y1 + height; + height = -height; + } + + var x2 = x1 + width; + var y2 = y1 + height; + var ox = out[0] = Math.min(Math.max(x, x1), x2); + var oy = out[1] = Math.min(Math.max(y, y1), y2); + return Math.sqrt((ox - x) * (ox - x) + (oy - y) * (oy - y)); + } + + var tmpPt = []; + + function nearestPointOnRect(pt, rect, out) { + var dist = projectPointToRect(rect.x, rect.y, rect.width, rect.height, pt.x, pt.y, tmpPt); + out.set(tmpPt[0], tmpPt[1]); + return dist; + } + /** + * Calculate min distance corresponding point. + * This method won't evaluate if point is in the path. + */ + + + function nearestPointOnPath(pt, path, out) { + var xi = 0; + var yi = 0; + var x0 = 0; + var y0 = 0; + var x1; + var y1; + var minDist = Infinity; + var data = path.data; + var x = pt.x; + var y = pt.y; + + for (var i = 0; i < data.length;) { + var cmd = data[i++]; + + if (i === 1) { + xi = data[i]; + yi = data[i + 1]; + x0 = xi; + y0 = yi; + } + + var d = minDist; + + switch (cmd) { + case CMD$3.M: + // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点 + // 在 closePath 的时候使用 + x0 = data[i++]; + y0 = data[i++]; + xi = x0; + yi = y0; + break; + + case CMD$3.L: + d = projectPointToLine(xi, yi, data[i], data[i + 1], x, y, tmpPt, true); + xi = data[i++]; + yi = data[i++]; + break; + + case CMD$3.C: + d = cubicProjectPoint(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y, tmpPt); + xi = data[i++]; + yi = data[i++]; + break; + + case CMD$3.Q: + d = quadraticProjectPoint(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y, tmpPt); + xi = data[i++]; + yi = data[i++]; + break; + + case CMD$3.A: + // TODO Arc 判断的开销比较大 + var cx = data[i++]; + var cy = data[i++]; + var rx = data[i++]; + var ry = data[i++]; + var theta = data[i++]; + var dTheta = data[i++]; // TODO Arc 旋转 + + i += 1; + var anticlockwise = !!(1 - data[i++]); + x1 = Math.cos(theta) * rx + cx; + y1 = Math.sin(theta) * ry + cy; // 不是直接使用 arc 命令 + + if (i <= 1) { + // 第一个命令起点还未定义 + x0 = x1; + y0 = y1; + } // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放 + + + var _x = (x - cx) * ry / rx + cx; + + d = projectPointToArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y, tmpPt); + xi = Math.cos(theta + dTheta) * rx + cx; + yi = Math.sin(theta + dTheta) * ry + cy; + break; + + case CMD$3.R: + x0 = xi = data[i++]; + y0 = yi = data[i++]; + var width = data[i++]; + var height = data[i++]; + d = projectPointToRect(x0, y0, width, height, x, y, tmpPt); + break; + + case CMD$3.Z: + d = projectPointToLine(xi, yi, x0, y0, x, y, tmpPt, true); + xi = x0; + yi = y0; + break; + } + + if (d < minDist) { + minDist = d; + out.set(tmpPt[0], tmpPt[1]); + } + } + + return minDist; + } // Temporal varible for intermediate usage. + + + var pt0 = new Point(); + var pt1 = new Point(); + var pt2 = new Point(); + var dir = new Point(); + var dir2 = new Point(); + /** + * Calculate a proper guide line based on the label position and graphic element definition + * @param label + * @param labelRect + * @param target + * @param targetRect + */ + + function updateLabelLinePoints(target, labelLineModel) { + if (!target) { + return; + } + + var labelLine = target.getTextGuideLine(); + var label = target.getTextContent(); // Needs to create text guide in each charts. + + if (!(label && labelLine)) { + return; + } + + var labelGuideConfig = target.textGuideLineConfig || {}; + var points = [[0, 0], [0, 0], [0, 0]]; + var searchSpace = labelGuideConfig.candidates || DEFAULT_SEARCH_SPACE; + var labelRect = label.getBoundingRect().clone(); + labelRect.applyTransform(label.getComputedTransform()); + var minDist = Infinity; + var anchorPoint = labelGuideConfig.anchor; + var targetTransform = target.getComputedTransform(); + var targetInversedTransform = targetTransform && invert([], targetTransform); + var len = labelLineModel.get('length2') || 0; + + if (anchorPoint) { + pt2.copy(anchorPoint); + } + + for (var i = 0; i < searchSpace.length; i++) { + var candidate = searchSpace[i]; + getCandidateAnchor(candidate, 0, labelRect, pt0, dir); + Point.scaleAndAdd(pt1, pt0, dir, len); // Transform to target coord space. + + pt1.transform(targetInversedTransform); // Note: getBoundingRect will ensure the `path` being created. + + var boundingRect = target.getBoundingRect(); + var dist = anchorPoint ? anchorPoint.distance(pt1) : target instanceof Path ? nearestPointOnPath(pt1, target.path, pt2) : nearestPointOnRect(pt1, boundingRect, pt2); // TODO pt2 is in the path + + if (dist < minDist) { + minDist = dist; // Transform back to global space. + + pt1.transform(targetTransform); + pt2.transform(targetTransform); + pt2.toArray(points[0]); + pt1.toArray(points[1]); + pt0.toArray(points[2]); + } + } + + limitTurnAngle(points, labelLineModel.get('minTurnAngle')); + labelLine.setShape({ + points: points + }); + } // Temporal variable for the limitTurnAngle function + + var tmpArr = []; + var tmpProjPoint = new Point(); + /** + * Reduce the line segment attached to the label to limit the turn angle between two segments. + * @param linePoints + * @param minTurnAngle Radian of minimum turn angle. 0 - 180 + */ + + function limitTurnAngle(linePoints, minTurnAngle) { + if (!(minTurnAngle <= 180 && minTurnAngle > 0)) { + return; + } + + minTurnAngle = minTurnAngle / 180 * Math.PI; // The line points can be + // /pt1----pt2 (label) + // / + // pt0/ + + pt0.fromArray(linePoints[0]); + pt1.fromArray(linePoints[1]); + pt2.fromArray(linePoints[2]); + Point.sub(dir, pt0, pt1); + Point.sub(dir2, pt2, pt1); + var len1 = dir.len(); + var len2 = dir2.len(); + + if (len1 < 1e-3 || len2 < 1e-3) { + return; + } + + dir.scale(1 / len1); + dir2.scale(1 / len2); + var angleCos = dir.dot(dir2); + var minTurnAngleCos = Math.cos(minTurnAngle); + + if (minTurnAngleCos < angleCos) { + // Smaller than minTurnAngle + // Calculate project point of pt0 on pt1-pt2 + var d = projectPointToLine(pt1.x, pt1.y, pt2.x, pt2.y, pt0.x, pt0.y, tmpArr, false); + tmpProjPoint.fromArray(tmpArr); // Calculate new projected length with limited minTurnAngle and get the new connect point + + tmpProjPoint.scaleAndAdd(dir2, d / Math.tan(Math.PI - minTurnAngle)); // Limit the new calculated connect point between pt1 and pt2. + + var t = pt2.x !== pt1.x ? (tmpProjPoint.x - pt1.x) / (pt2.x - pt1.x) : (tmpProjPoint.y - pt1.y) / (pt2.y - pt1.y); + + if (isNaN(t)) { + return; + } + + if (t < 0) { + Point.copy(tmpProjPoint, pt1); + } else if (t > 1) { + Point.copy(tmpProjPoint, pt2); + } + + tmpProjPoint.toArray(linePoints[1]); + } + } + /** + * Limit the angle of line and the surface + * @param maxSurfaceAngle Radian of minimum turn angle. 0 - 180. 0 is same direction to normal. 180 is opposite + */ + + function limitSurfaceAngle(linePoints, surfaceNormal, maxSurfaceAngle) { + if (!(maxSurfaceAngle <= 180 && maxSurfaceAngle > 0)) { + return; + } + + maxSurfaceAngle = maxSurfaceAngle / 180 * Math.PI; + pt0.fromArray(linePoints[0]); + pt1.fromArray(linePoints[1]); + pt2.fromArray(linePoints[2]); + Point.sub(dir, pt1, pt0); + Point.sub(dir2, pt2, pt1); + var len1 = dir.len(); + var len2 = dir2.len(); + + if (len1 < 1e-3 || len2 < 1e-3) { + return; + } + + dir.scale(1 / len1); + dir2.scale(1 / len2); + var angleCos = dir.dot(surfaceNormal); + var maxSurfaceAngleCos = Math.cos(maxSurfaceAngle); + + if (angleCos < maxSurfaceAngleCos) { + // Calculate project point of pt0 on pt1-pt2 + var d = projectPointToLine(pt1.x, pt1.y, pt2.x, pt2.y, pt0.x, pt0.y, tmpArr, false); + tmpProjPoint.fromArray(tmpArr); + var HALF_PI = Math.PI / 2; + var angle2 = Math.acos(dir2.dot(surfaceNormal)); + var newAngle = HALF_PI + angle2 - maxSurfaceAngle; + + if (newAngle >= HALF_PI) { + // parallel + Point.copy(tmpProjPoint, pt2); + } else { + // Calculate new projected length with limited minTurnAngle and get the new connect point + tmpProjPoint.scaleAndAdd(dir2, d / Math.tan(Math.PI / 2 - newAngle)); // Limit the new calculated connect point between pt1 and pt2. + + var t = pt2.x !== pt1.x ? (tmpProjPoint.x - pt1.x) / (pt2.x - pt1.x) : (tmpProjPoint.y - pt1.y) / (pt2.y - pt1.y); + + if (isNaN(t)) { + return; + } + + if (t < 0) { + Point.copy(tmpProjPoint, pt1); + } else if (t > 1) { + Point.copy(tmpProjPoint, pt2); + } + } + + tmpProjPoint.toArray(linePoints[1]); + } + } + + function setLabelLineState(labelLine, ignore, stateName, stateModel) { + var isNormal = stateName === 'normal'; + var stateObj = isNormal ? labelLine : labelLine.ensureState(stateName); // Make sure display. + + stateObj.ignore = ignore; // Set smooth + + var smooth = stateModel.get('smooth'); + + if (smooth && smooth === true) { + smooth = 0.3; + } + + stateObj.shape = stateObj.shape || {}; + + if (smooth > 0) { + stateObj.shape.smooth = smooth; + } + + var styleObj = stateModel.getModel('lineStyle').getLineStyle(); + isNormal ? labelLine.useStyle(styleObj) : stateObj.style = styleObj; + } + + function buildLabelLinePath(path, shape) { + var smooth = shape.smooth; + var points = shape.points; + + if (!points) { + return; + } + + path.moveTo(points[0][0], points[0][1]); + + if (smooth > 0 && points.length >= 3) { + var len1 = dist(points[0], points[1]); + var len2 = dist(points[1], points[2]); + + if (!len1 || !len2) { + path.lineTo(points[1][0], points[1][1]); + path.lineTo(points[2][0], points[2][1]); + return; + } + + var moveLen = Math.min(len1, len2) * smooth; + var midPoint0 = lerp([], points[1], points[0], moveLen / len1); + var midPoint2 = lerp([], points[1], points[2], moveLen / len2); + var midPoint1 = lerp([], midPoint0, midPoint2, 0.5); + path.bezierCurveTo(midPoint0[0], midPoint0[1], midPoint0[0], midPoint0[1], midPoint1[0], midPoint1[1]); + path.bezierCurveTo(midPoint2[0], midPoint2[1], midPoint2[0], midPoint2[1], points[2][0], points[2][1]); + } else { + for (var i = 1; i < points.length; i++) { + path.lineTo(points[i][0], points[i][1]); + } + } + } + /** + * Create a label line if necessary and set it's style. + */ + + + function setLabelLineStyle(targetEl, statesModels, defaultStyle) { + var labelLine = targetEl.getTextGuideLine(); + var label = targetEl.getTextContent(); + + if (!label) { + // Not show label line if there is no label. + if (labelLine) { + targetEl.removeTextGuideLine(); + } + + return; + } + + var normalModel = statesModels.normal; + var showNormal = normalModel.get('show'); + var labelIgnoreNormal = label.ignore; + + for (var i = 0; i < DISPLAY_STATES.length; i++) { + var stateName = DISPLAY_STATES[i]; + var stateModel = statesModels[stateName]; + var isNormal = stateName === 'normal'; + + if (stateModel) { + var stateShow = stateModel.get('show'); + var isLabelIgnored = isNormal ? labelIgnoreNormal : retrieve2(label.states[stateName] && label.states[stateName].ignore, labelIgnoreNormal); + + if (isLabelIgnored // Not show when label is not shown in this state. + || !retrieve2(stateShow, showNormal) // Use normal state by default if not set. + ) { + var stateObj = isNormal ? labelLine : labelLine && labelLine.states[stateName]; + + if (stateObj) { + stateObj.ignore = true; + } + + continue; + } // Create labelLine if not exists + + + if (!labelLine) { + labelLine = new Polyline(); + targetEl.setTextGuideLine(labelLine); // Reset state of normal because it's new created. + // NOTE: NORMAL should always been the first! + + if (!isNormal && (labelIgnoreNormal || !showNormal)) { + setLabelLineState(labelLine, true, 'normal', statesModels.normal); + } // Use same state proxy. + + + if (targetEl.stateProxy) { + labelLine.stateProxy = targetEl.stateProxy; + } + } + + setLabelLineState(labelLine, false, stateName, stateModel); + } + } + + if (labelLine) { + defaults(labelLine.style, defaultStyle); // Not fill. + + labelLine.style.fill = null; + var showAbove = normalModel.get('showAbove'); + var labelLineConfig = targetEl.textGuideLineConfig = targetEl.textGuideLineConfig || {}; + labelLineConfig.showAbove = showAbove || false; // Custom the buildPath. + + labelLine.buildPath = buildLabelLinePath; + } + } + function getLabelLineStatesModels(itemModel, labelLineName) { + labelLineName = labelLineName || 'labelLine'; + var statesModels = { + normal: itemModel.getModel(labelLineName) + }; + + for (var i = 0; i < SPECIAL_STATES.length; i++) { + var stateName = SPECIAL_STATES[i]; + statesModels[stateName] = itemModel.getModel([stateName, labelLineName]); + } + + return statesModels; + } + + function prepareLayoutList(input) { + var list = []; + + for (var i = 0; i < input.length; i++) { + var rawItem = input[i]; + + if (rawItem.defaultAttr.ignore) { + continue; + } + + var label = rawItem.label; + var transform = label.getComputedTransform(); // NOTE: Get bounding rect after getComputedTransform, or label may not been updated by the host el. + + var localRect = label.getBoundingRect(); + var isAxisAligned = !transform || transform[1] < 1e-5 && transform[2] < 1e-5; + var minMargin = label.style.margin || 0; + var globalRect = localRect.clone(); + globalRect.applyTransform(transform); + globalRect.x -= minMargin / 2; + globalRect.y -= minMargin / 2; + globalRect.width += minMargin; + globalRect.height += minMargin; + var obb = isAxisAligned ? new OrientedBoundingRect(localRect, transform) : null; + list.push({ + label: label, + labelLine: rawItem.labelLine, + rect: globalRect, + localRect: localRect, + obb: obb, + priority: rawItem.priority, + defaultAttr: rawItem.defaultAttr, + layoutOption: rawItem.computedLayoutOption, + axisAligned: isAxisAligned, + transform: transform + }); + } + + return list; + } + + function shiftLayout(list, xyDim, sizeDim, minBound, maxBound, balanceShift) { + var len = list.length; + + if (len < 2) { + return; + } + + list.sort(function (a, b) { + return a.rect[xyDim] - b.rect[xyDim]; + }); + var lastPos = 0; + var delta; + var adjusted = false; + var totalShifts = 0; + + for (var i = 0; i < len; i++) { + var item = list[i]; + var rect = item.rect; + delta = rect[xyDim] - lastPos; + + if (delta < 0) { + // shiftForward(i, len, -delta); + rect[xyDim] -= delta; + item.label[xyDim] -= delta; + adjusted = true; + } + + var shift = Math.max(-delta, 0); + totalShifts += shift; + lastPos = rect[xyDim] + rect[sizeDim]; + } + + if (totalShifts > 0 && balanceShift) { + // Shift back to make the distribution more equally. + shiftList(-totalShifts / len, 0, len); + } // TODO bleedMargin? + + + var first = list[0]; + var last = list[len - 1]; + var minGap; + var maxGap; + updateMinMaxGap(); // If ends exceed two bounds, squeeze at most 80%, then take the gap of two bounds. + + minGap < 0 && squeezeGaps(-minGap, 0.8); + maxGap < 0 && squeezeGaps(maxGap, 0.8); + updateMinMaxGap(); + takeBoundsGap(minGap, maxGap, 1); + takeBoundsGap(maxGap, minGap, -1); // Handle bailout when there is not enough space. + + updateMinMaxGap(); + + if (minGap < 0) { + squeezeWhenBailout(-minGap); + } + + if (maxGap < 0) { + squeezeWhenBailout(maxGap); + } + + function updateMinMaxGap() { + minGap = first.rect[xyDim] - minBound; + maxGap = maxBound - last.rect[xyDim] - last.rect[sizeDim]; + } + + function takeBoundsGap(gapThisBound, gapOtherBound, moveDir) { + if (gapThisBound < 0) { + // Move from other gap if can. + var moveFromMaxGap = Math.min(gapOtherBound, -gapThisBound); + + if (moveFromMaxGap > 0) { + shiftList(moveFromMaxGap * moveDir, 0, len); + var remained = moveFromMaxGap + gapThisBound; + + if (remained < 0) { + squeezeGaps(-remained * moveDir, 1); + } + } else { + squeezeGaps(-gapThisBound * moveDir, 1); + } + } + } + + function shiftList(delta, start, end) { + if (delta !== 0) { + adjusted = true; + } + + for (var i = start; i < end; i++) { + var item = list[i]; + var rect = item.rect; + rect[xyDim] += delta; + item.label[xyDim] += delta; + } + } // Squeeze gaps if the labels exceed margin. + + + function squeezeGaps(delta, maxSqeezePercent) { + var gaps = []; + var totalGaps = 0; + + for (var i = 1; i < len; i++) { + var prevItemRect = list[i - 1].rect; + var gap = Math.max(list[i].rect[xyDim] - prevItemRect[xyDim] - prevItemRect[sizeDim], 0); + gaps.push(gap); + totalGaps += gap; + } + + if (!totalGaps) { + return; + } + + var squeezePercent = Math.min(Math.abs(delta) / totalGaps, maxSqeezePercent); + + if (delta > 0) { + for (var i = 0; i < len - 1; i++) { + // Distribute the shift delta to all gaps. + var movement = gaps[i] * squeezePercent; // Forward + + shiftList(movement, 0, i + 1); + } + } else { + // Backward + for (var i = len - 1; i > 0; i--) { + // Distribute the shift delta to all gaps. + var movement = gaps[i - 1] * squeezePercent; + shiftList(-movement, i, len); + } + } + } + /** + * Squeeze to allow overlap if there is no more space available. + * Let other overlapping strategy like hideOverlap do the job instead of keep exceeding the bounds. + */ + + + function squeezeWhenBailout(delta) { + var dir = delta < 0 ? -1 : 1; + delta = Math.abs(delta); + var moveForEachLabel = Math.ceil(delta / (len - 1)); + + for (var i = 0; i < len - 1; i++) { + if (dir > 0) { + // Forward + shiftList(moveForEachLabel, 0, i + 1); + } else { + // Backward + shiftList(-moveForEachLabel, len - i - 1, len); + } + + delta -= moveForEachLabel; + + if (delta <= 0) { + return; + } + } + } + + return adjusted; + } + /** + * Adjust labels on x direction to avoid overlap. + */ + + + function shiftLayoutOnX(list, leftBound, rightBound, // If average the shifts on all labels and add them to 0 + // TODO: Not sure if should enable it. + // Pros: The angle of lines will distribute more equally + // Cons: In some layout. It may not what user wanted. like in pie. the label of last sector is usually changed unexpectedly. + balanceShift) { + return shiftLayout(list, 'x', 'width', leftBound, rightBound, balanceShift); + } + /** + * Adjust labels on y direction to avoid overlap. + */ + + function shiftLayoutOnY(list, topBound, bottomBound, // If average the shifts on all labels and add them to 0 + balanceShift) { + return shiftLayout(list, 'y', 'height', topBound, bottomBound, balanceShift); + } + function hideOverlap(labelList) { + var displayedLabels = []; // TODO, render overflow visible first, put in the displayedLabels. + + labelList.sort(function (a, b) { + return b.priority - a.priority; + }); + var globalRect = new BoundingRect(0, 0, 0, 0); + + function hideEl(el) { + if (!el.ignore) { + // Show on emphasis. + var emphasisState = el.ensureState('emphasis'); + + if (emphasisState.ignore == null) { + emphasisState.ignore = false; + } + } + + el.ignore = true; + } + + for (var i = 0; i < labelList.length; i++) { + var labelItem = labelList[i]; + var isAxisAligned = labelItem.axisAligned; + var localRect = labelItem.localRect; + var transform = labelItem.transform; + var label = labelItem.label; + var labelLine = labelItem.labelLine; + globalRect.copy(labelItem.rect); // Add a threshold because layout may be aligned precisely. + + globalRect.width -= 0.1; + globalRect.height -= 0.1; + globalRect.x += 0.05; + globalRect.y += 0.05; + var obb = labelItem.obb; + var overlapped = false; + + for (var j = 0; j < displayedLabels.length; j++) { + var existsTextCfg = displayedLabels[j]; // Fast rejection. + + if (!globalRect.intersect(existsTextCfg.rect)) { + continue; + } + + if (isAxisAligned && existsTextCfg.axisAligned) { + // Is overlapped + overlapped = true; + break; + } + + if (!existsTextCfg.obb) { + // If self is not axis aligned. But other is. + existsTextCfg.obb = new OrientedBoundingRect(existsTextCfg.localRect, existsTextCfg.transform); + } + + if (!obb) { + // If self is axis aligned. But other is not. + obb = new OrientedBoundingRect(localRect, transform); + } + + if (obb.intersect(existsTextCfg.obb)) { + overlapped = true; + break; + } + } // TODO Callback to determine if this overlap should be handled? + + + if (overlapped) { + hideEl(label); + labelLine && hideEl(labelLine); + } else { + label.attr('ignore', labelItem.defaultAttr.ignore); + labelLine && labelLine.attr('ignore', labelItem.defaultAttr.labelGuideIgnore); + displayedLabels.push(labelItem); + } + } + } + + function cloneArr(points) { + if (points) { + var newPoints = []; + + for (var i = 0; i < points.length; i++) { + newPoints.push(points[i].slice()); + } + + return newPoints; + } + } + + function prepareLayoutCallbackParams(labelItem, hostEl) { + var label = labelItem.label; + var labelLine = hostEl && hostEl.getTextGuideLine(); + return { + dataIndex: labelItem.dataIndex, + dataType: labelItem.dataType, + seriesIndex: labelItem.seriesModel.seriesIndex, + text: labelItem.label.style.text, + rect: labelItem.hostRect, + labelRect: labelItem.rect, + // x: labelAttr.x, + // y: labelAttr.y, + align: label.style.align, + verticalAlign: label.style.verticalAlign, + labelLinePoints: cloneArr(labelLine && labelLine.shape.points) + }; + } + + var LABEL_OPTION_TO_STYLE_KEYS = ['align', 'verticalAlign', 'width', 'height', 'fontSize']; + var dummyTransformable = new Transformable(); + var labelLayoutInnerStore = makeInner(); + var labelLineAnimationStore = makeInner(); + + function extendWithKeys(target, source, keys) { + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + + if (source[key] != null) { + target[key] = source[key]; + } + } + } + + var LABEL_LAYOUT_PROPS = ['x', 'y', 'rotation']; + + var LabelManager = + /** @class */ + function () { + function LabelManager() { + this._labelList = []; + this._chartViewList = []; + } + + LabelManager.prototype.clearLabels = function () { + this._labelList = []; + this._chartViewList = []; + }; + /** + * Add label to manager + */ + + + LabelManager.prototype._addLabel = function (dataIndex, dataType, seriesModel, label, layoutOption) { + var labelStyle = label.style; + var hostEl = label.__hostTarget; + var textConfig = hostEl.textConfig || {}; // TODO: If label is in other state. + + var labelTransform = label.getComputedTransform(); + var labelRect = label.getBoundingRect().plain(); + BoundingRect.applyTransform(labelRect, labelRect, labelTransform); + + if (labelTransform) { + dummyTransformable.setLocalTransform(labelTransform); + } else { + // Identity transform. + dummyTransformable.x = dummyTransformable.y = dummyTransformable.rotation = dummyTransformable.originX = dummyTransformable.originY = 0; + dummyTransformable.scaleX = dummyTransformable.scaleY = 1; + } + + var host = label.__hostTarget; + var hostRect; + + if (host) { + hostRect = host.getBoundingRect().plain(); + var transform = host.getComputedTransform(); + BoundingRect.applyTransform(hostRect, hostRect, transform); + } + + var labelGuide = hostRect && host.getTextGuideLine(); + + this._labelList.push({ + label: label, + labelLine: labelGuide, + seriesModel: seriesModel, + dataIndex: dataIndex, + dataType: dataType, + layoutOption: layoutOption, + computedLayoutOption: null, + rect: labelRect, + hostRect: hostRect, + // Label with lower priority will be hidden when overlapped + // Use rect size as default priority + priority: hostRect ? hostRect.width * hostRect.height : 0, + // Save default label attributes. + // For restore if developers want get back to default value in callback. + defaultAttr: { + ignore: label.ignore, + labelGuideIgnore: labelGuide && labelGuide.ignore, + x: dummyTransformable.x, + y: dummyTransformable.y, + scaleX: dummyTransformable.scaleX, + scaleY: dummyTransformable.scaleY, + rotation: dummyTransformable.rotation, + style: { + x: labelStyle.x, + y: labelStyle.y, + align: labelStyle.align, + verticalAlign: labelStyle.verticalAlign, + width: labelStyle.width, + height: labelStyle.height, + fontSize: labelStyle.fontSize + }, + cursor: label.cursor, + attachedPos: textConfig.position, + attachedRot: textConfig.rotation + } + }); + }; + + LabelManager.prototype.addLabelsOfSeries = function (chartView) { + var _this = this; + + this._chartViewList.push(chartView); + + var seriesModel = chartView.__model; + var layoutOption = seriesModel.get('labelLayout'); + /** + * Ignore layouting if it's not specified anything. + */ + + if (!(isFunction(layoutOption) || keys(layoutOption).length)) { + return; + } + + chartView.group.traverse(function (child) { + if (child.ignore) { + return true; // Stop traverse descendants. + } // Only support label being hosted on graphic elements. + + + var textEl = child.getTextContent(); + var ecData = getECData(child); // Can only attach the text on the element with dataIndex + + if (textEl && !textEl.disableLabelLayout) { + _this._addLabel(ecData.dataIndex, ecData.dataType, seriesModel, textEl, layoutOption); + } + }); + }; + + LabelManager.prototype.updateLayoutConfig = function (api) { + var width = api.getWidth(); + var height = api.getHeight(); + + function createDragHandler(el, labelLineModel) { + return function () { + updateLabelLinePoints(el, labelLineModel); + }; + } + + for (var i = 0; i < this._labelList.length; i++) { + var labelItem = this._labelList[i]; + var label = labelItem.label; + var hostEl = label.__hostTarget; + var defaultLabelAttr = labelItem.defaultAttr; + var layoutOption = void 0; // TODO A global layout option? + + if (isFunction(labelItem.layoutOption)) { + layoutOption = labelItem.layoutOption(prepareLayoutCallbackParams(labelItem, hostEl)); + } else { + layoutOption = labelItem.layoutOption; + } + + layoutOption = layoutOption || {}; + labelItem.computedLayoutOption = layoutOption; + var degreeToRadian = Math.PI / 180; // TODO hostEl should always exists. + // Or label should not have parent because the x, y is all in global space. + + if (hostEl) { + hostEl.setTextConfig({ + // Force to set local false. + local: false, + // Ignore position and rotation config on the host el if x or y is changed. + position: layoutOption.x != null || layoutOption.y != null ? null : defaultLabelAttr.attachedPos, + // Ignore rotation config on the host el if rotation is changed. + rotation: layoutOption.rotate != null ? layoutOption.rotate * degreeToRadian : defaultLabelAttr.attachedRot, + offset: [layoutOption.dx || 0, layoutOption.dy || 0] + }); + } + + var needsUpdateLabelLine = false; + + if (layoutOption.x != null) { + // TODO width of chart view. + label.x = parsePercent$1(layoutOption.x, width); + label.setStyle('x', 0); // Ignore movement in style. TODO: origin. + + needsUpdateLabelLine = true; + } else { + label.x = defaultLabelAttr.x; + label.setStyle('x', defaultLabelAttr.style.x); + } + + if (layoutOption.y != null) { + // TODO height of chart view. + label.y = parsePercent$1(layoutOption.y, height); + label.setStyle('y', 0); // Ignore movement in style. + + needsUpdateLabelLine = true; + } else { + label.y = defaultLabelAttr.y; + label.setStyle('y', defaultLabelAttr.style.y); + } + + if (layoutOption.labelLinePoints) { + var guideLine = hostEl.getTextGuideLine(); + + if (guideLine) { + guideLine.setShape({ + points: layoutOption.labelLinePoints + }); // Not update + + needsUpdateLabelLine = false; + } + } + + var labelLayoutStore = labelLayoutInnerStore(label); + labelLayoutStore.needsUpdateLabelLine = needsUpdateLabelLine; + label.rotation = layoutOption.rotate != null ? layoutOption.rotate * degreeToRadian : defaultLabelAttr.rotation; + label.scaleX = defaultLabelAttr.scaleX; + label.scaleY = defaultLabelAttr.scaleY; + + for (var k = 0; k < LABEL_OPTION_TO_STYLE_KEYS.length; k++) { + var key = LABEL_OPTION_TO_STYLE_KEYS[k]; + label.setStyle(key, layoutOption[key] != null ? layoutOption[key] : defaultLabelAttr.style[key]); + } + + if (layoutOption.draggable) { + label.draggable = true; + label.cursor = 'move'; + + if (hostEl) { + var hostModel = labelItem.seriesModel; + + if (labelItem.dataIndex != null) { + var data = labelItem.seriesModel.getData(labelItem.dataType); + hostModel = data.getItemModel(labelItem.dataIndex); + } + + label.on('drag', createDragHandler(hostEl, hostModel.getModel('labelLine'))); + } + } else { + // TODO Other drag functions? + label.off('drag'); + label.cursor = defaultLabelAttr.cursor; + } + } + }; + + LabelManager.prototype.layout = function (api) { + var width = api.getWidth(); + var height = api.getHeight(); + var labelList = prepareLayoutList(this._labelList); + var labelsNeedsAdjustOnX = filter(labelList, function (item) { + return item.layoutOption.moveOverlap === 'shiftX'; + }); + var labelsNeedsAdjustOnY = filter(labelList, function (item) { + return item.layoutOption.moveOverlap === 'shiftY'; + }); + shiftLayoutOnX(labelsNeedsAdjustOnX, 0, width); + shiftLayoutOnY(labelsNeedsAdjustOnY, 0, height); + var labelsNeedsHideOverlap = filter(labelList, function (item) { + return item.layoutOption.hideOverlap; + }); + hideOverlap(labelsNeedsHideOverlap); + }; + /** + * Process all labels. Not only labels with layoutOption. + */ + + + LabelManager.prototype.processLabelsOverall = function () { + var _this = this; + + each(this._chartViewList, function (chartView) { + var seriesModel = chartView.__model; + var ignoreLabelLineUpdate = chartView.ignoreLabelLineUpdate; + var animationEnabled = seriesModel.isAnimationEnabled(); + chartView.group.traverse(function (child) { + if (child.ignore && !child.forceLabelAnimation) { + return true; // Stop traverse descendants. + } + + var needsUpdateLabelLine = !ignoreLabelLineUpdate; + var label = child.getTextContent(); + + if (!needsUpdateLabelLine && label) { + needsUpdateLabelLine = labelLayoutInnerStore(label).needsUpdateLabelLine; + } + + if (needsUpdateLabelLine) { + _this._updateLabelLine(child, seriesModel); + } + + if (animationEnabled) { + _this._animateLabels(child, seriesModel); + } + }); + }); + }; + + LabelManager.prototype._updateLabelLine = function (el, seriesModel) { + // Only support label being hosted on graphic elements. + var textEl = el.getTextContent(); // Update label line style. + + var ecData = getECData(el); + var dataIndex = ecData.dataIndex; // Only support labelLine on the labels represent data. + + if (textEl && dataIndex != null) { + var data = seriesModel.getData(ecData.dataType); + var itemModel = data.getItemModel(dataIndex); + var defaultStyle = {}; + var visualStyle = data.getItemVisual(dataIndex, 'style'); + var visualType = data.getVisual('drawType'); // Default to be same with main color + + defaultStyle.stroke = visualStyle[visualType]; + var labelLineModel = itemModel.getModel('labelLine'); + setLabelLineStyle(el, getLabelLineStatesModels(itemModel), defaultStyle); + updateLabelLinePoints(el, labelLineModel); + } + }; + + LabelManager.prototype._animateLabels = function (el, seriesModel) { + var textEl = el.getTextContent(); + var guideLine = el.getTextGuideLine(); // Animate + + if (textEl // `forceLabelAnimation` has the highest priority + && (el.forceLabelAnimation || !textEl.ignore && !textEl.invisible && !el.disableLabelAnimation && !isElementRemoved(el))) { + var layoutStore = labelLayoutInnerStore(textEl); + var oldLayout = layoutStore.oldLayout; + var ecData = getECData(el); + var dataIndex = ecData.dataIndex; + var newProps = { + x: textEl.x, + y: textEl.y, + rotation: textEl.rotation + }; + var data = seriesModel.getData(ecData.dataType); + + if (!oldLayout) { + textEl.attr(newProps); // Disable fade in animation if value animation is enabled. + + if (!labelInner(textEl).valueAnimation) { + var oldOpacity = retrieve2(textEl.style.opacity, 1); // Fade in animation + + textEl.style.opacity = 0; + initProps(textEl, { + style: { + opacity: oldOpacity + } + }, seriesModel, dataIndex); + } + } else { + textEl.attr(oldLayout); // Make sure the animation from is in the right status. + + var prevStates = el.prevStates; + + if (prevStates) { + if (indexOf(prevStates, 'select') >= 0) { + textEl.attr(layoutStore.oldLayoutSelect); + } + + if (indexOf(prevStates, 'emphasis') >= 0) { + textEl.attr(layoutStore.oldLayoutEmphasis); + } + } + + updateProps(textEl, newProps, seriesModel, dataIndex); + } + + layoutStore.oldLayout = newProps; + + if (textEl.states.select) { + var layoutSelect = layoutStore.oldLayoutSelect = {}; + extendWithKeys(layoutSelect, newProps, LABEL_LAYOUT_PROPS); + extendWithKeys(layoutSelect, textEl.states.select, LABEL_LAYOUT_PROPS); + } + + if (textEl.states.emphasis) { + var layoutEmphasis = layoutStore.oldLayoutEmphasis = {}; + extendWithKeys(layoutEmphasis, newProps, LABEL_LAYOUT_PROPS); + extendWithKeys(layoutEmphasis, textEl.states.emphasis, LABEL_LAYOUT_PROPS); + } + + animateLabelValue(textEl, dataIndex, data, seriesModel, seriesModel); + } + + if (guideLine && !guideLine.ignore && !guideLine.invisible) { + var layoutStore = labelLineAnimationStore(guideLine); + var oldLayout = layoutStore.oldLayout; + var newLayout = { + points: guideLine.shape.points + }; + + if (!oldLayout) { + guideLine.setShape(newLayout); + guideLine.style.strokePercent = 0; + initProps(guideLine, { + style: { + strokePercent: 1 + } + }, seriesModel); + } else { + guideLine.attr({ + shape: oldLayout + }); + updateProps(guideLine, { + shape: newLayout + }, seriesModel); + } + + layoutStore.oldLayout = newLayout; + } + }; + + return LabelManager; + }(); + + var getLabelManager = makeInner(); + function installLabelLayout(registers) { + registers.registerUpdateLifecycle('series:beforeupdate', function (ecModel, api, params) { + // TODO api provide an namespace that can save stuff per instance + var labelManager = getLabelManager(api).labelManager; + + if (!labelManager) { + labelManager = getLabelManager(api).labelManager = new LabelManager(); + } + + labelManager.clearLabels(); + }); + registers.registerUpdateLifecycle('series:layoutlabels', function (ecModel, api, params) { + var labelManager = getLabelManager(api).labelManager; + params.updatedSeries.forEach(function (series) { + labelManager.addLabelsOfSeries(api.getViewOfSeriesModel(series)); + }); + labelManager.updateLayoutConfig(api); + labelManager.layout(api); + labelManager.processLabelsOverall(); + }); + } + + var mathSin$4 = Math.sin; + var mathCos$4 = Math.cos; + var PI$4 = Math.PI; + var PI2$7 = Math.PI * 2; + var degree = 180 / PI$4; + var SVGPathRebuilder = (function () { + function SVGPathRebuilder() { + } + SVGPathRebuilder.prototype.reset = function (precision) { + this._start = true; + this._d = []; + this._str = ''; + this._p = Math.pow(10, precision || 4); + }; + SVGPathRebuilder.prototype.moveTo = function (x, y) { + this._add('M', x, y); + }; + SVGPathRebuilder.prototype.lineTo = function (x, y) { + this._add('L', x, y); + }; + SVGPathRebuilder.prototype.bezierCurveTo = function (x, y, x2, y2, x3, y3) { + this._add('C', x, y, x2, y2, x3, y3); + }; + SVGPathRebuilder.prototype.quadraticCurveTo = function (x, y, x2, y2) { + this._add('Q', x, y, x2, y2); + }; + SVGPathRebuilder.prototype.arc = function (cx, cy, r, startAngle, endAngle, anticlockwise) { + this.ellipse(cx, cy, r, r, 0, startAngle, endAngle, anticlockwise); + }; + SVGPathRebuilder.prototype.ellipse = function (cx, cy, rx, ry, psi, startAngle, endAngle, anticlockwise) { + var dTheta = endAngle - startAngle; + var clockwise = !anticlockwise; + var dThetaPositive = Math.abs(dTheta); + var isCircle = isAroundZero$1(dThetaPositive - PI2$7) + || (clockwise ? dTheta >= PI2$7 : -dTheta >= PI2$7); + var unifiedTheta = dTheta > 0 ? dTheta % PI2$7 : (dTheta % PI2$7 + PI2$7); + var large = false; + if (isCircle) { + large = true; + } + else if (isAroundZero$1(dThetaPositive)) { + large = false; + } + else { + large = (unifiedTheta >= PI$4) === !!clockwise; + } + var x0 = cx + rx * mathCos$4(startAngle); + var y0 = cy + ry * mathSin$4(startAngle); + if (this._start) { + this._add('M', x0, y0); + } + var xRot = Math.round(psi * degree); + if (isCircle) { + var p = 1 / this._p; + var dTheta_1 = (clockwise ? 1 : -1) * (PI2$7 - p); + this._add('A', rx, ry, xRot, 1, +clockwise, cx + rx * mathCos$4(startAngle + dTheta_1), cy + ry * mathSin$4(startAngle + dTheta_1)); + if (p > 1e-2) { + this._add('A', rx, ry, xRot, 0, +clockwise, x0, y0); + } + } + else { + var x = cx + rx * mathCos$4(endAngle); + var y = cy + ry * mathSin$4(endAngle); + this._add('A', rx, ry, xRot, +large, +clockwise, x, y); + } + }; + SVGPathRebuilder.prototype.rect = function (x, y, w, h) { + this._add('M', x, y); + this._add('l', w, 0); + this._add('l', 0, h); + this._add('l', -w, 0); + this._add('Z'); + }; + SVGPathRebuilder.prototype.closePath = function () { + if (this._d.length > 0) { + this._add('Z'); + } + }; + SVGPathRebuilder.prototype._add = function (cmd, a, b, c, d, e, f, g, h) { + var vals = []; + var p = this._p; + for (var i = 1; i < arguments.length; i++) { + var val = arguments[i]; + if (isNaN(val)) { + this._invalid = true; + return; + } + vals.push(Math.round(val * p) / p); + } + this._d.push(cmd + vals.join(' ')); + this._start = cmd === 'Z'; + }; + SVGPathRebuilder.prototype.generateStr = function () { + this._str = this._invalid ? '' : this._d.join(''); + this._d = []; + }; + SVGPathRebuilder.prototype.getStr = function () { + return this._str; + }; + return SVGPathRebuilder; + }()); + + var NONE = 'none'; + var mathRound$1 = Math.round; + function pathHasFill(style) { + var fill = style.fill; + return fill != null && fill !== NONE; + } + function pathHasStroke(style) { + var stroke = style.stroke; + return stroke != null && stroke !== NONE; + } + var strokeProps = ['lineCap', 'miterLimit', 'lineJoin']; + var svgStrokeProps = map(strokeProps, function (prop) { return "stroke-" + prop.toLowerCase(); }); + function mapStyleToAttrs(updateAttr, style, el, forceUpdate) { + var opacity = style.opacity == null ? 1 : style.opacity; + if (el instanceof ZRImage) { + updateAttr('opacity', opacity); + return; + } + if (pathHasFill(style)) { + var fill = normalizeColor(style.fill); + updateAttr('fill', fill.color); + var fillOpacity = style.fillOpacity != null + ? style.fillOpacity * fill.opacity * opacity + : fill.opacity * opacity; + if (forceUpdate || fillOpacity < 1) { + updateAttr('fill-opacity', fillOpacity); + } + } + else { + updateAttr('fill', NONE); + } + if (pathHasStroke(style)) { + var stroke = normalizeColor(style.stroke); + updateAttr('stroke', stroke.color); + var strokeScale = style.strokeNoScale + ? el.getLineScale() + : 1; + var strokeWidth = (strokeScale ? (style.lineWidth || 0) / strokeScale : 0); + var strokeOpacity = style.strokeOpacity != null + ? style.strokeOpacity * stroke.opacity * opacity + : stroke.opacity * opacity; + var strokeFirst = style.strokeFirst; + if (forceUpdate || strokeWidth !== 1) { + updateAttr('stroke-width', strokeWidth); + } + if (forceUpdate || strokeFirst) { + updateAttr('paint-order', strokeFirst ? 'stroke' : 'fill'); + } + if (forceUpdate || strokeOpacity < 1) { + updateAttr('stroke-opacity', strokeOpacity); + } + if (style.lineDash) { + var _a = getLineDash(el), lineDash = _a[0], lineDashOffset = _a[1]; + if (lineDash) { + lineDashOffset = mathRound$1(lineDashOffset || 0); + updateAttr('stroke-dasharray', lineDash.join(',')); + if (lineDashOffset || forceUpdate) { + updateAttr('stroke-dashoffset', lineDashOffset); + } + } + } + else if (forceUpdate) { + updateAttr('stroke-dasharray', NONE); + } + for (var i = 0; i < strokeProps.length; i++) { + var propName = strokeProps[i]; + if (forceUpdate || style[propName] !== DEFAULT_PATH_STYLE[propName]) { + var val = style[propName] || DEFAULT_PATH_STYLE[propName]; + val && updateAttr(svgStrokeProps[i], val); + } + } + } + else if (forceUpdate) { + updateAttr('stroke', NONE); + } + } + + var SVGNS = 'http://www.w3.org/2000/svg'; + var XLINKNS = 'http://www.w3.org/1999/xlink'; + var XMLNS = 'http://www.w3.org/2000/xmlns/'; + var XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace'; + function createElement(name) { + return document.createElementNS(SVGNS, name); + } + function createVNode(tag, key, attrs, children, text) { + return { + tag: tag, + attrs: attrs || {}, + children: children, + text: text, + key: key + }; + } + function createElementOpen(name, attrs) { + var attrsStr = []; + if (attrs) { + for (var key in attrs) { + var val = attrs[key]; + var part = key; + if (val === false) { + continue; + } + else if (val !== true && val != null) { + part += "=\"" + val + "\""; + } + attrsStr.push(part); + } + } + return "<" + name + " " + attrsStr.join(' ') + ">"; + } + function createElementClose(name) { + return ""; + } + function vNodeToString(el, opts) { + opts = opts || {}; + var S = opts.newline ? '\n' : ''; + function convertElToString(el) { + var children = el.children, tag = el.tag, attrs = el.attrs; + return createElementOpen(tag, attrs) + + (el.text || '') + + (children ? "" + S + map(children, function (child) { return convertElToString(child); }).join(S) + S : '') + + createElementClose(tag); + } + return convertElToString(el); + } + function getCssString(selectorNodes, animationNodes, opts) { + opts = opts || {}; + var S = opts.newline ? '\n' : ''; + var bracketBegin = " {" + S; + var bracketEnd = S + "}"; + var selectors = map(keys(selectorNodes), function (className) { + return className + bracketBegin + map(keys(selectorNodes[className]), function (attrName) { + return attrName + ":" + selectorNodes[className][attrName] + ";"; + }).join(S) + bracketEnd; + }).join(S); + var animations = map(keys(animationNodes), function (animationName) { + return "@keyframes " + animationName + bracketBegin + map(keys(animationNodes[animationName]), function (percent) { + return percent + bracketBegin + map(keys(animationNodes[animationName][percent]), function (attrName) { + var val = animationNodes[animationName][percent][attrName]; + if (attrName === 'd') { + val = "path(\"" + val + "\")"; + } + return attrName + ":" + val + ";"; + }).join(S) + bracketEnd; + }).join(S) + bracketEnd; + }).join(S); + if (!selectors && !animations) { + return ''; + } + return [''].join(S); + } + function createBrushScope(zrId) { + return { + zrId: zrId, + shadowCache: {}, + patternCache: {}, + gradientCache: {}, + clipPathCache: {}, + defs: {}, + cssNodes: {}, + cssAnims: {}, + cssClassIdx: 0, + cssAnimIdx: 0, + shadowIdx: 0, + gradientIdx: 0, + patternIdx: 0, + clipPathIdx: 0 + }; + } + function createSVGVNode(width, height, children, useViewBox) { + return createVNode('svg', 'root', { + 'width': width, + 'height': height, + 'xmlns': SVGNS, + 'xmlns:xlink': XLINKNS, + 'version': '1.1', + 'baseProfile': 'full', + 'viewBox': useViewBox ? "0 0 " + width + " " + height : false + }, children); + } + + var EASING_MAP = { + cubicIn: '0.32,0,0.67,0', + cubicOut: '0.33,1,0.68,1', + cubicInOut: '0.65,0,0.35,1', + quadraticIn: '0.11,0,0.5,0', + quadraticOut: '0.5,1,0.89,1', + quadraticInOut: '0.45,0,0.55,1', + quarticIn: '0.5,0,0.75,0', + quarticOut: '0.25,1,0.5,1', + quarticInOut: '0.76,0,0.24,1', + quinticIn: '0.64,0,0.78,0', + quinticOut: '0.22,1,0.36,1', + quinticInOut: '0.83,0,0.17,1', + sinusoidalIn: '0.12,0,0.39,0', + sinusoidalOut: '0.61,1,0.88,1', + sinusoidalInOut: '0.37,0,0.63,1', + exponentialIn: '0.7,0,0.84,0', + exponentialOut: '0.16,1,0.3,1', + exponentialInOut: '0.87,0,0.13,1', + circularIn: '0.55,0,1,0.45', + circularOut: '0,0.55,0.45,1', + circularInOut: '0.85,0,0.15,1' + }; + var transformOriginKey = 'transform-origin'; + function buildPathString(el, kfShape, path) { + var shape = extend({}, el.shape); + extend(shape, kfShape); + el.buildPath(path, shape); + var svgPathBuilder = new SVGPathRebuilder(); + svgPathBuilder.reset(getPathPrecision(el)); + path.rebuildPath(svgPathBuilder, 1); + svgPathBuilder.generateStr(); + return svgPathBuilder.getStr(); + } + function setTransformOrigin(target, transform) { + var originX = transform.originX, originY = transform.originY; + if (originX || originY) { + target[transformOriginKey] = originX + "px " + originY + "px"; + } + } + var ANIMATE_STYLE_MAP = { + fill: 'fill', + opacity: 'opacity', + lineWidth: 'stroke-width', + lineDashOffset: 'stroke-dashoffset' + }; + function addAnimation(cssAnim, scope) { + var animationName = scope.zrId + '-ani-' + scope.cssAnimIdx++; + scope.cssAnims[animationName] = cssAnim; + return animationName; + } + function createCompoundPathCSSAnimation(el, attrs, scope) { + var paths = el.shape.paths; + var composedAnim = {}; + var cssAnimationCfg; + var cssAnimationName; + each(paths, function (path) { + var subScope = createBrushScope(scope.zrId); + subScope.animation = true; + createCSSAnimation(path, {}, subScope, true); + var cssAnims = subScope.cssAnims; + var cssNodes = subScope.cssNodes; + var animNames = keys(cssAnims); + var len = animNames.length; + if (!len) { + return; + } + cssAnimationName = animNames[len - 1]; + var lastAnim = cssAnims[cssAnimationName]; + for (var percent in lastAnim) { + var kf = lastAnim[percent]; + composedAnim[percent] = composedAnim[percent] || { d: '' }; + composedAnim[percent].d += kf.d || ''; + } + for (var className in cssNodes) { + var val = cssNodes[className].animation; + if (val.indexOf(cssAnimationName) >= 0) { + cssAnimationCfg = val; + } + } + }); + if (!cssAnimationCfg) { + return; + } + attrs.d = false; + var animationName = addAnimation(composedAnim, scope); + return cssAnimationCfg.replace(cssAnimationName, animationName); + } + function getEasingFunc(easing) { + return isString(easing) + ? EASING_MAP[easing] + ? "cubic-bezier(" + EASING_MAP[easing] + ")" + : createCubicEasingFunc(easing) ? easing : '' + : ''; + } + function createCSSAnimation(el, attrs, scope, onlyShape) { + var animators = el.animators; + var len = animators.length; + var cssAnimations = []; + if (el instanceof CompoundPath) { + var animationCfg = createCompoundPathCSSAnimation(el, attrs, scope); + if (animationCfg) { + cssAnimations.push(animationCfg); + } + else if (!len) { + return; + } + } + else if (!len) { + return; + } + var groupAnimators = {}; + for (var i = 0; i < len; i++) { + var animator = animators[i]; + var cfgArr = [animator.getMaxTime() / 1000 + 's']; + var easing = getEasingFunc(animator.getClip().easing); + var delay = animator.getDelay(); + if (easing) { + cfgArr.push(easing); + } + else { + cfgArr.push('linear'); + } + if (delay) { + cfgArr.push(delay / 1000 + 's'); + } + if (animator.getLoop()) { + cfgArr.push('infinite'); + } + var cfg = cfgArr.join(' '); + groupAnimators[cfg] = groupAnimators[cfg] || [cfg, []]; + groupAnimators[cfg][1].push(animator); + } + function createSingleCSSAnimation(groupAnimator) { + var animators = groupAnimator[1]; + var len = animators.length; + var transformKfs = {}; + var shapeKfs = {}; + var finalKfs = {}; + var animationTimingFunctionAttrName = 'animation-timing-function'; + function saveAnimatorTrackToCssKfs(animator, cssKfs, toCssAttrName) { + var tracks = animator.getTracks(); + var maxTime = animator.getMaxTime(); + for (var k = 0; k < tracks.length; k++) { + var track = tracks[k]; + if (track.needsAnimate()) { + var kfs = track.keyframes; + var attrName = track.propName; + toCssAttrName && (attrName = toCssAttrName(attrName)); + if (attrName) { + for (var i = 0; i < kfs.length; i++) { + var kf = kfs[i]; + var percent = Math.round(kf.time / maxTime * 100) + '%'; + var kfEasing = getEasingFunc(kf.easing); + var rawValue = kf.rawValue; + if (isString(rawValue) || isNumber(rawValue)) { + cssKfs[percent] = cssKfs[percent] || {}; + cssKfs[percent][attrName] = kf.rawValue; + if (kfEasing) { + cssKfs[percent][animationTimingFunctionAttrName] = kfEasing; + } + } + } + } + } + } + } + for (var i = 0; i < len; i++) { + var animator = animators[i]; + var targetProp = animator.targetName; + if (!targetProp) { + !onlyShape && saveAnimatorTrackToCssKfs(animator, transformKfs); + } + else if (targetProp === 'shape') { + saveAnimatorTrackToCssKfs(animator, shapeKfs); + } + } + for (var percent in transformKfs) { + var transform = {}; + copyTransform(transform, el); + extend(transform, transformKfs[percent]); + var str = getSRTTransformString(transform); + var timingFunction = transformKfs[percent][animationTimingFunctionAttrName]; + finalKfs[percent] = str ? { + transform: str + } : {}; + setTransformOrigin(finalKfs[percent], transform); + if (timingFunction) { + finalKfs[percent][animationTimingFunctionAttrName] = timingFunction; + } + } + var path; + var canAnimateShape = true; + for (var percent in shapeKfs) { + finalKfs[percent] = finalKfs[percent] || {}; + var isFirst = !path; + var timingFunction = shapeKfs[percent][animationTimingFunctionAttrName]; + if (isFirst) { + path = new PathProxy(); + } + var len_1 = path.len(); + path.reset(); + finalKfs[percent].d = buildPathString(el, shapeKfs[percent], path); + var newLen = path.len(); + if (!isFirst && len_1 !== newLen) { + canAnimateShape = false; + break; + } + if (timingFunction) { + finalKfs[percent][animationTimingFunctionAttrName] = timingFunction; + } + } + if (!canAnimateShape) { + for (var percent in finalKfs) { + delete finalKfs[percent].d; + } + } + if (!onlyShape) { + for (var i = 0; i < len; i++) { + var animator = animators[i]; + var targetProp = animator.targetName; + if (targetProp === 'style') { + saveAnimatorTrackToCssKfs(animator, finalKfs, function (propName) { return ANIMATE_STYLE_MAP[propName]; }); + } + } + } + var percents = keys(finalKfs); + var allTransformOriginSame = true; + var transformOrigin; + for (var i = 1; i < percents.length; i++) { + var p0 = percents[i - 1]; + var p1 = percents[i]; + if (finalKfs[p0][transformOriginKey] !== finalKfs[p1][transformOriginKey]) { + allTransformOriginSame = false; + break; + } + transformOrigin = finalKfs[p0][transformOriginKey]; + } + if (allTransformOriginSame && transformOrigin) { + for (var percent in finalKfs) { + if (finalKfs[percent][transformOriginKey]) { + delete finalKfs[percent][transformOriginKey]; + } + } + attrs[transformOriginKey] = transformOrigin; + } + if (filter(percents, function (percent) { return keys(finalKfs[percent]).length > 0; }).length) { + var animationName = addAnimation(finalKfs, scope); + return animationName + " " + groupAnimator[0] + " both"; + } + } + for (var key in groupAnimators) { + var animationCfg = createSingleCSSAnimation(groupAnimators[key]); + if (animationCfg) { + cssAnimations.push(animationCfg); + } + } + if (cssAnimations.length) { + var className = scope.zrId + '-cls-' + scope.cssClassIdx++; + scope.cssNodes['.' + className] = { + animation: cssAnimations.join(',') + }; + attrs["class"] = className; + } + } + + var round$2 = Math.round; + function isImageLike$1(val) { + return val && isString(val.src); + } + function isCanvasLike(val) { + return val && isFunction(val.toDataURL); + } + function setStyleAttrs(attrs, style, el, scope) { + mapStyleToAttrs(function (key, val) { + var isFillStroke = key === 'fill' || key === 'stroke'; + if (isFillStroke && isGradient(val)) { + setGradient(style, attrs, key, scope); + } + else if (isFillStroke && isPattern(val)) { + setPattern(el, attrs, key, scope); + } + else { + attrs[key] = val; + } + }, style, el, false); + setShadow(el, attrs, scope); + } + function noRotateScale(m) { + return isAroundZero$1(m[0] - 1) + && isAroundZero$1(m[1]) + && isAroundZero$1(m[2]) + && isAroundZero$1(m[3] - 1); + } + function noTranslate(m) { + return isAroundZero$1(m[4]) && isAroundZero$1(m[5]); + } + function setTransform(attrs, m, compress) { + if (m && !(noTranslate(m) && noRotateScale(m))) { + var mul = compress ? 10 : 1e4; + attrs.transform = noRotateScale(m) + ? "translate(" + round$2(m[4] * mul) / mul + " " + round$2(m[5] * mul) / mul + ")" : getMatrixStr(m); + } + } + function convertPolyShape(shape, attrs, mul) { + var points = shape.points; + var strArr = []; + for (var i = 0; i < points.length; i++) { + strArr.push(round$2(points[i][0] * mul) / mul); + strArr.push(round$2(points[i][1] * mul) / mul); + } + attrs.points = strArr.join(' '); + } + function validatePolyShape(shape) { + return !shape.smooth; + } + function createAttrsConvert(desc) { + var normalizedDesc = map(desc, function (item) { + return (typeof item === 'string' ? [item, item] : item); + }); + return function (shape, attrs, mul) { + for (var i = 0; i < normalizedDesc.length; i++) { + var item = normalizedDesc[i]; + var val = shape[item[0]]; + if (val != null) { + attrs[item[1]] = round$2(val * mul) / mul; + } + } + }; + } + var buitinShapesDef = { + circle: [createAttrsConvert(['cx', 'cy', 'r'])], + polyline: [convertPolyShape, validatePolyShape], + polygon: [convertPolyShape, validatePolyShape] + }; + function hasShapeAnimation(el) { + var animators = el.animators; + for (var i = 0; i < animators.length; i++) { + if (animators[i].targetName === 'shape') { + return true; + } + } + return false; + } + function brushSVGPath(el, scope) { + var style = el.style; + var shape = el.shape; + var builtinShpDef = buitinShapesDef[el.type]; + var attrs = {}; + var needsAnimate = scope.animation; + var svgElType = 'path'; + var strokePercent = el.style.strokePercent; + var precision = (scope.compress && getPathPrecision(el)) || 4; + if (builtinShpDef + && !scope.willUpdate + && !(builtinShpDef[1] && !builtinShpDef[1](shape)) + && !(needsAnimate && hasShapeAnimation(el)) + && !(strokePercent < 1)) { + svgElType = el.type; + var mul = Math.pow(10, precision); + builtinShpDef[0](shape, attrs, mul); + } + else { + if (!el.path) { + el.createPathProxy(); + } + var path = el.path; + if (el.shapeChanged()) { + path.beginPath(); + el.buildPath(path, el.shape); + el.pathUpdated(); + } + var pathVersion = path.getVersion(); + var elExt = el; + var svgPathBuilder = elExt.__svgPathBuilder; + if (elExt.__svgPathVersion !== pathVersion + || !svgPathBuilder + || strokePercent !== elExt.__svgPathStrokePercent) { + if (!svgPathBuilder) { + svgPathBuilder = elExt.__svgPathBuilder = new SVGPathRebuilder(); + } + svgPathBuilder.reset(precision); + path.rebuildPath(svgPathBuilder, strokePercent); + svgPathBuilder.generateStr(); + elExt.__svgPathVersion = pathVersion; + elExt.__svgPathStrokePercent = strokePercent; + } + attrs.d = svgPathBuilder.getStr(); + } + setTransform(attrs, el.transform); + setStyleAttrs(attrs, style, el, scope); + scope.animation && createCSSAnimation(el, attrs, scope); + return createVNode(svgElType, el.id + '', attrs); + } + function brushSVGImage(el, scope) { + var style = el.style; + var image = style.image; + if (image && !isString(image)) { + if (isImageLike$1(image)) { + image = image.src; + } + else if (isCanvasLike(image)) { + image = image.toDataURL(); + } + } + if (!image) { + return; + } + var x = style.x || 0; + var y = style.y || 0; + var dw = style.width; + var dh = style.height; + var attrs = { + href: image, + width: dw, + height: dh + }; + if (x) { + attrs.x = x; + } + if (y) { + attrs.y = y; + } + setTransform(attrs, el.transform); + setStyleAttrs(attrs, style, el, scope); + scope.animation && createCSSAnimation(el, attrs, scope); + return createVNode('image', el.id + '', attrs); + } + function brushSVGTSpan(el, scope) { + var style = el.style; + var text = style.text; + text != null && (text += ''); + if (!text || isNaN(style.x) || isNaN(style.y)) { + return; + } + var font = style.font || DEFAULT_FONT; + var x = style.x || 0; + var y = adjustTextY(style.y || 0, getLineHeight(font), style.textBaseline); + var textAlign = TEXT_ALIGN_TO_ANCHOR[style.textAlign] + || style.textAlign; + var attrs = { + 'dominant-baseline': 'central', + 'text-anchor': textAlign + }; + if (hasSeparateFont(style)) { + var separatedFontStr = ''; + var fontStyle = style.fontStyle; + var fontSize = parseFontSize(style.fontSize); + if (!parseFloat(fontSize)) { + return; + } + var fontFamily = style.fontFamily || DEFAULT_FONT_FAMILY; + var fontWeight = style.fontWeight; + separatedFontStr += "font-size:" + fontSize + ";font-family:" + fontFamily + ";"; + if (fontStyle && fontStyle !== 'normal') { + separatedFontStr += "font-style:" + fontStyle + ";"; + } + if (fontWeight && fontWeight !== 'normal') { + separatedFontStr += "font-weight:" + fontWeight + ";"; + } + attrs.style = separatedFontStr; + } + else { + attrs.style = "font: " + font; + } + if (text.match(/\s/)) { + attrs['xml:space'] = 'preserve'; + } + if (x) { + attrs.x = x; + } + if (y) { + attrs.y = y; + } + setTransform(attrs, el.transform); + setStyleAttrs(attrs, style, el, scope); + scope.animation && createCSSAnimation(el, attrs, scope); + return createVNode('text', el.id + '', attrs, undefined, text); + } + function brush$1(el, scope) { + if (el instanceof Path) { + return brushSVGPath(el, scope); + } + else if (el instanceof ZRImage) { + return brushSVGImage(el, scope); + } + else if (el instanceof TSpan) { + return brushSVGTSpan(el, scope); + } + } + function setShadow(el, attrs, scope) { + var style = el.style; + if (hasShadow(style)) { + var shadowKey = getShadowKey(el); + var shadowCache = scope.shadowCache; + var shadowId = shadowCache[shadowKey]; + if (!shadowId) { + var globalScale = el.getGlobalScale(); + var scaleX = globalScale[0]; + var scaleY = globalScale[1]; + if (!scaleX || !scaleY) { + return; + } + var offsetX = style.shadowOffsetX || 0; + var offsetY = style.shadowOffsetY || 0; + var blur_1 = style.shadowBlur; + var _a = normalizeColor(style.shadowColor), opacity = _a.opacity, color = _a.color; + var stdDx = blur_1 / 2 / scaleX; + var stdDy = blur_1 / 2 / scaleY; + var stdDeviation = stdDx + ' ' + stdDy; + shadowId = scope.zrId + '-s' + scope.shadowIdx++; + scope.defs[shadowId] = createVNode('filter', shadowId, { + 'id': shadowId, + 'x': '-100%', + 'y': '-100%', + 'width': '300%', + 'height': '300%' + }, [ + createVNode('feDropShadow', '', { + 'dx': offsetX / scaleX, + 'dy': offsetY / scaleY, + 'stdDeviation': stdDeviation, + 'flood-color': color, + 'flood-opacity': opacity + }) + ]); + shadowCache[shadowKey] = shadowId; + } + attrs.filter = getIdURL(shadowId); + } + } + function setGradient(style, attrs, target, scope) { + var val = style[target]; + var gradientTag; + var gradientAttrs = { + 'gradientUnits': val.global + ? 'userSpaceOnUse' + : 'objectBoundingBox' + }; + if (isLinearGradient(val)) { + gradientTag = 'linearGradient'; + gradientAttrs.x1 = val.x; + gradientAttrs.y1 = val.y; + gradientAttrs.x2 = val.x2; + gradientAttrs.y2 = val.y2; + } + else if (isRadialGradient(val)) { + gradientTag = 'radialGradient'; + gradientAttrs.cx = retrieve2(val.x, 0.5); + gradientAttrs.cy = retrieve2(val.y, 0.5); + gradientAttrs.r = retrieve2(val.r, 0.5); + } + else { + if ("development" !== 'production') { + logError('Illegal gradient type.'); + } + return; + } + var colors = val.colorStops; + var colorStops = []; + for (var i = 0, len = colors.length; i < len; ++i) { + var offset = round4(colors[i].offset) * 100 + '%'; + var stopColor = colors[i].color; + var _a = normalizeColor(stopColor), color = _a.color, opacity = _a.opacity; + var stopsAttrs = { + 'offset': offset + }; + stopsAttrs['stop-color'] = color; + if (opacity < 1) { + stopsAttrs['stop-opacity'] = opacity; + } + colorStops.push(createVNode('stop', i + '', stopsAttrs)); + } + var gradientVNode = createVNode(gradientTag, '', gradientAttrs, colorStops); + var gradientKey = vNodeToString(gradientVNode); + var gradientCache = scope.gradientCache; + var gradientId = gradientCache[gradientKey]; + if (!gradientId) { + gradientId = scope.zrId + '-g' + scope.gradientIdx++; + gradientCache[gradientKey] = gradientId; + gradientAttrs.id = gradientId; + scope.defs[gradientId] = createVNode(gradientTag, gradientId, gradientAttrs, colorStops); + } + attrs[target] = getIdURL(gradientId); + } + function setPattern(el, attrs, target, scope) { + var val = el.style[target]; + var patternAttrs = { + 'patternUnits': 'userSpaceOnUse' + }; + var child; + if (isImagePattern(val)) { + var imageWidth_1 = val.imageWidth; + var imageHeight_1 = val.imageHeight; + var imageSrc = void 0; + var patternImage = val.image; + if (isString(patternImage)) { + imageSrc = patternImage; + } + else if (isImageLike$1(patternImage)) { + imageSrc = patternImage.src; + } + else if (isCanvasLike(patternImage)) { + imageSrc = patternImage.toDataURL(); + } + if (typeof Image === 'undefined') { + var errMsg = 'Image width/height must been given explictly in svg-ssr renderer.'; + assert(imageWidth_1, errMsg); + assert(imageHeight_1, errMsg); + } + else if (imageWidth_1 == null || imageHeight_1 == null) { + var setSizeToVNode_1 = function (vNode, img) { + if (vNode) { + var svgEl = vNode.elm; + var width = (vNode.attrs.width = imageWidth_1 || img.width); + var height = (vNode.attrs.height = imageHeight_1 || img.height); + if (svgEl) { + svgEl.setAttribute('width', width); + svgEl.setAttribute('height', height); + } + } + }; + var createdImage = createOrUpdateImage(imageSrc, null, el, function (img) { + setSizeToVNode_1(patternVNode, img); + setSizeToVNode_1(child, img); + }); + if (createdImage && createdImage.width && createdImage.height) { + imageWidth_1 = imageWidth_1 || createdImage.width; + imageHeight_1 = imageHeight_1 || createdImage.height; + } + } + child = createVNode('image', 'img', { + href: imageSrc, + width: imageWidth_1, + height: imageHeight_1 + }); + patternAttrs.width = imageWidth_1; + patternAttrs.height = imageHeight_1; + } + else if (val.svgElement) { + child = clone(val.svgElement); + patternAttrs.width = val.svgWidth; + patternAttrs.height = val.svgHeight; + } + if (!child) { + return; + } + patternAttrs.patternTransform = getSRTTransformString(val); + var patternVNode = createVNode('pattern', '', patternAttrs, [child]); + var patternKey = vNodeToString(patternVNode); + var patternCache = scope.patternCache; + var patternId = patternCache[patternKey]; + if (!patternId) { + patternId = scope.zrId + '-p' + scope.patternIdx++; + patternCache[patternKey] = patternId; + patternAttrs.id = patternId; + patternVNode = scope.defs[patternId] = createVNode('pattern', patternId, patternAttrs, [child]); + } + attrs[target] = getIdURL(patternId); + } + function setClipPath(clipPath, attrs, scope) { + var clipPathCache = scope.clipPathCache, defs = scope.defs; + var clipPathId = clipPathCache[clipPath.id]; + if (!clipPathId) { + clipPathId = scope.zrId + '-c' + scope.clipPathIdx++; + var clipPathAttrs = { + id: clipPathId + }; + clipPathCache[clipPath.id] = clipPathId; + defs[clipPathId] = createVNode('clipPath', clipPathId, clipPathAttrs, [brushSVGPath(clipPath, scope)]); + } + attrs['clip-path'] = getIdURL(clipPathId); + } + + function createTextNode(text) { + return document.createTextNode(text); + } + function insertBefore(parentNode, newNode, referenceNode) { + parentNode.insertBefore(newNode, referenceNode); + } + function removeChild(node, child) { + node.removeChild(child); + } + function appendChild(node, child) { + node.appendChild(child); + } + function parentNode(node) { + return node.parentNode; + } + function nextSibling(node) { + return node.nextSibling; + } + function setTextContent(node, text) { + node.textContent = text; + } + + var colonChar = 58; + var xChar = 120; + var emptyNode = createVNode('', ''); + function isUndef(s) { + return s === undefined; + } + function isDef(s) { + return s !== undefined; + } + function createKeyToOldIdx(children, beginIdx, endIdx) { + var map = {}; + for (var i = beginIdx; i <= endIdx; ++i) { + var key = children[i].key; + if (key !== undefined) { + if ("development" !== 'production') { + if (map[key] != null) { + console.error("Duplicate key " + key); + } + } + map[key] = i; + } + } + return map; + } + function sameVnode(vnode1, vnode2) { + var isSameKey = vnode1.key === vnode2.key; + var isSameTag = vnode1.tag === vnode2.tag; + return isSameTag && isSameKey; + } + function createElm(vnode) { + var i; + var children = vnode.children; + var tag = vnode.tag; + if (isDef(tag)) { + var elm = (vnode.elm = createElement(tag)); + updateAttrs(emptyNode, vnode); + if (isArray(children)) { + for (i = 0; i < children.length; ++i) { + var ch = children[i]; + if (ch != null) { + appendChild(elm, createElm(ch)); + } + } + } + else if (isDef(vnode.text) && !isObject(vnode.text)) { + appendChild(elm, createTextNode(vnode.text)); + } + } + else { + vnode.elm = createTextNode(vnode.text); + } + return vnode.elm; + } + function addVnodes(parentElm, before, vnodes, startIdx, endIdx) { + for (; startIdx <= endIdx; ++startIdx) { + var ch = vnodes[startIdx]; + if (ch != null) { + insertBefore(parentElm, createElm(ch), before); + } + } + } + function removeVnodes(parentElm, vnodes, startIdx, endIdx) { + for (; startIdx <= endIdx; ++startIdx) { + var ch = vnodes[startIdx]; + if (ch != null) { + if (isDef(ch.tag)) { + var parent_1 = parentNode(ch.elm); + removeChild(parent_1, ch.elm); + } + else { + removeChild(parentElm, ch.elm); + } + } + } + } + function updateAttrs(oldVnode, vnode) { + var key; + var elm = vnode.elm; + var oldAttrs = oldVnode && oldVnode.attrs || {}; + var attrs = vnode.attrs || {}; + if (oldAttrs === attrs) { + return; + } + for (key in attrs) { + var cur = attrs[key]; + var old = oldAttrs[key]; + if (old !== cur) { + if (cur === true) { + elm.setAttribute(key, ''); + } + else if (cur === false) { + elm.removeAttribute(key); + } + else { + if (key.charCodeAt(0) !== xChar) { + elm.setAttribute(key, cur); + } + else if (key === 'xmlns:xlink' || key === 'xmlns') { + elm.setAttributeNS(XMLNS, key, cur); + } + else if (key.charCodeAt(3) === colonChar) { + elm.setAttributeNS(XML_NAMESPACE, key, cur); + } + else if (key.charCodeAt(5) === colonChar) { + elm.setAttributeNS(XLINKNS, key, cur); + } + else { + elm.setAttribute(key, cur); + } + } + } + } + for (key in oldAttrs) { + if (!(key in attrs)) { + elm.removeAttribute(key); + } + } + } + function updateChildren(parentElm, oldCh, newCh) { + var oldStartIdx = 0; + var newStartIdx = 0; + var oldEndIdx = oldCh.length - 1; + var oldStartVnode = oldCh[0]; + var oldEndVnode = oldCh[oldEndIdx]; + var newEndIdx = newCh.length - 1; + var newStartVnode = newCh[0]; + var newEndVnode = newCh[newEndIdx]; + var oldKeyToIdx; + var idxInOld; + var elmToMove; + var before; + while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) { + if (oldStartVnode == null) { + oldStartVnode = oldCh[++oldStartIdx]; + } + else if (oldEndVnode == null) { + oldEndVnode = oldCh[--oldEndIdx]; + } + else if (newStartVnode == null) { + newStartVnode = newCh[++newStartIdx]; + } + else if (newEndVnode == null) { + newEndVnode = newCh[--newEndIdx]; + } + else if (sameVnode(oldStartVnode, newStartVnode)) { + patchVnode(oldStartVnode, newStartVnode); + oldStartVnode = oldCh[++oldStartIdx]; + newStartVnode = newCh[++newStartIdx]; + } + else if (sameVnode(oldEndVnode, newEndVnode)) { + patchVnode(oldEndVnode, newEndVnode); + oldEndVnode = oldCh[--oldEndIdx]; + newEndVnode = newCh[--newEndIdx]; + } + else if (sameVnode(oldStartVnode, newEndVnode)) { + patchVnode(oldStartVnode, newEndVnode); + insertBefore(parentElm, oldStartVnode.elm, nextSibling(oldEndVnode.elm)); + oldStartVnode = oldCh[++oldStartIdx]; + newEndVnode = newCh[--newEndIdx]; + } + else if (sameVnode(oldEndVnode, newStartVnode)) { + patchVnode(oldEndVnode, newStartVnode); + insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm); + oldEndVnode = oldCh[--oldEndIdx]; + newStartVnode = newCh[++newStartIdx]; + } + else { + if (isUndef(oldKeyToIdx)) { + oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx); + } + idxInOld = oldKeyToIdx[newStartVnode.key]; + if (isUndef(idxInOld)) { + insertBefore(parentElm, createElm(newStartVnode), oldStartVnode.elm); + } + else { + elmToMove = oldCh[idxInOld]; + if (elmToMove.tag !== newStartVnode.tag) { + insertBefore(parentElm, createElm(newStartVnode), oldStartVnode.elm); + } + else { + patchVnode(elmToMove, newStartVnode); + oldCh[idxInOld] = undefined; + insertBefore(parentElm, elmToMove.elm, oldStartVnode.elm); + } + } + newStartVnode = newCh[++newStartIdx]; + } + } + if (oldStartIdx <= oldEndIdx || newStartIdx <= newEndIdx) { + if (oldStartIdx > oldEndIdx) { + before = newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].elm; + addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx); + } + else { + removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx); + } + } + } + function patchVnode(oldVnode, vnode) { + var elm = (vnode.elm = oldVnode.elm); + var oldCh = oldVnode.children; + var ch = vnode.children; + if (oldVnode === vnode) { + return; + } + updateAttrs(oldVnode, vnode); + if (isUndef(vnode.text)) { + if (isDef(oldCh) && isDef(ch)) { + if (oldCh !== ch) { + updateChildren(elm, oldCh, ch); + } + } + else if (isDef(ch)) { + if (isDef(oldVnode.text)) { + setTextContent(elm, ''); + } + addVnodes(elm, null, ch, 0, ch.length - 1); + } + else if (isDef(oldCh)) { + removeVnodes(elm, oldCh, 0, oldCh.length - 1); + } + else if (isDef(oldVnode.text)) { + setTextContent(elm, ''); + } + } + else if (oldVnode.text !== vnode.text) { + if (isDef(oldCh)) { + removeVnodes(elm, oldCh, 0, oldCh.length - 1); + } + setTextContent(elm, vnode.text); + } + } + function patch(oldVnode, vnode) { + if (sameVnode(oldVnode, vnode)) { + patchVnode(oldVnode, vnode); + } + else { + var elm = oldVnode.elm; + var parent_2 = parentNode(elm); + createElm(vnode); + if (parent_2 !== null) { + insertBefore(parent_2, vnode.elm, nextSibling(elm)); + removeVnodes(parent_2, [oldVnode], 0, 0); + } + } + return vnode; + } + + var svgId = 0; + var SVGPainter = (function () { + function SVGPainter(root, storage, opts) { + this.type = 'svg'; + this.refreshHover = createMethodNotSupport('refreshHover'); + this.configLayer = createMethodNotSupport('configLayer'); + this.storage = storage; + this._opts = opts = extend({}, opts); + this.root = root; + this._id = 'zr' + svgId++; + this._oldVNode = createSVGVNode(opts.width, opts.height); + if (root && !opts.ssr) { + var viewport = this._viewport = document.createElement('div'); + viewport.style.cssText = 'position:relative;overflow:hidden'; + var svgDom = this._svgDom = this._oldVNode.elm = createElement('svg'); + updateAttrs(null, this._oldVNode); + viewport.appendChild(svgDom); + root.appendChild(viewport); + } + this.resize(opts.width, opts.height); + } + SVGPainter.prototype.getType = function () { + return this.type; + }; + SVGPainter.prototype.getViewportRoot = function () { + return this._viewport; + }; + SVGPainter.prototype.getViewportRootOffset = function () { + var viewportRoot = this.getViewportRoot(); + if (viewportRoot) { + return { + offsetLeft: viewportRoot.offsetLeft || 0, + offsetTop: viewportRoot.offsetTop || 0 + }; + } + }; + SVGPainter.prototype.getSvgDom = function () { + return this._svgDom; + }; + SVGPainter.prototype.refresh = function () { + if (this.root) { + var vnode = this.renderToVNode({ + willUpdate: true + }); + vnode.attrs.style = 'position:absolute;left:0;top:0;user-select:none'; + patch(this._oldVNode, vnode); + this._oldVNode = vnode; + } + }; + SVGPainter.prototype.renderOneToVNode = function (el) { + return brush$1(el, createBrushScope(this._id)); + }; + SVGPainter.prototype.renderToVNode = function (opts) { + opts = opts || {}; + var list = this.storage.getDisplayList(true); + var bgColor = this._backgroundColor; + var width = this._width; + var height = this._height; + var scope = createBrushScope(this._id); + scope.animation = opts.animation; + scope.willUpdate = opts.willUpdate; + scope.compress = opts.compress; + var children = []; + if (bgColor && bgColor !== 'none') { + var _a = normalizeColor(bgColor), color = _a.color, opacity = _a.opacity; + this._bgVNode = createVNode('rect', 'bg', { + width: width, + height: height, + x: '0', + y: '0', + id: '0', + fill: color, + 'fill-opacity': opacity + }); + children.push(this._bgVNode); + } + else { + this._bgVNode = null; + } + var mainVNode = !opts.compress + ? (this._mainVNode = createVNode('g', 'main', {}, [])) : null; + this._paintList(list, scope, mainVNode ? mainVNode.children : children); + mainVNode && children.push(mainVNode); + var defs = map(keys(scope.defs), function (id) { return scope.defs[id]; }); + if (defs.length) { + children.push(createVNode('defs', 'defs', {}, defs)); + } + if (opts.animation) { + var animationCssStr = getCssString(scope.cssNodes, scope.cssAnims, { newline: true }); + if (animationCssStr) { + var styleNode = createVNode('style', 'stl', {}, [], animationCssStr); + children.push(styleNode); + } + } + return createSVGVNode(width, height, children, opts.useViewBox); + }; + SVGPainter.prototype.renderToString = function (opts) { + opts = opts || {}; + return vNodeToString(this.renderToVNode({ + animation: retrieve2(opts.cssAnimation, true), + willUpdate: false, + compress: true, + useViewBox: retrieve2(opts.useViewBox, true) + }), { newline: true }); + }; + SVGPainter.prototype.setBackgroundColor = function (backgroundColor) { + this._backgroundColor = backgroundColor; + var bgVNode = this._bgVNode; + if (bgVNode && bgVNode.elm) { + var _a = normalizeColor(backgroundColor), color = _a.color, opacity = _a.opacity; + bgVNode.elm.setAttribute('fill', color); + if (opacity < 1) { + bgVNode.elm.setAttribute('fill-opacity', opacity); + } + } + }; + SVGPainter.prototype.getSvgRoot = function () { + return this._mainVNode && this._mainVNode.elm; + }; + SVGPainter.prototype._paintList = function (list, scope, out) { + var listLen = list.length; + var clipPathsGroupsStack = []; + var clipPathsGroupsStackDepth = 0; + var currentClipPathGroup; + var prevClipPaths; + var clipGroupNodeIdx = 0; + for (var i = 0; i < listLen; i++) { + var displayable = list[i]; + if (!displayable.invisible) { + var clipPaths = displayable.__clipPaths; + var len = clipPaths && clipPaths.length || 0; + var prevLen = prevClipPaths && prevClipPaths.length || 0; + var lca = void 0; + for (lca = Math.max(len - 1, prevLen - 1); lca >= 0; lca--) { + if (clipPaths && prevClipPaths + && clipPaths[lca] === prevClipPaths[lca]) { + break; + } + } + for (var i_1 = prevLen - 1; i_1 > lca; i_1--) { + clipPathsGroupsStackDepth--; + currentClipPathGroup = clipPathsGroupsStack[clipPathsGroupsStackDepth - 1]; + } + for (var i_2 = lca + 1; i_2 < len; i_2++) { + var groupAttrs = {}; + setClipPath(clipPaths[i_2], groupAttrs, scope); + var g = createVNode('g', 'clip-g-' + clipGroupNodeIdx++, groupAttrs, []); + (currentClipPathGroup ? currentClipPathGroup.children : out).push(g); + clipPathsGroupsStack[clipPathsGroupsStackDepth++] = g; + currentClipPathGroup = g; + } + prevClipPaths = clipPaths; + var ret = brush$1(displayable, scope); + if (ret) { + (currentClipPathGroup ? currentClipPathGroup.children : out).push(ret); + } + } + } + }; + SVGPainter.prototype.resize = function (width, height) { + var opts = this._opts; + var root = this.root; + var viewport = this._viewport; + width != null && (opts.width = width); + height != null && (opts.height = height); + if (root && viewport) { + viewport.style.display = 'none'; + width = getSize(root, 0, opts); + height = getSize(root, 1, opts); + viewport.style.display = ''; + } + if (this._width !== width || this._height !== height) { + this._width = width; + this._height = height; + if (viewport) { + var viewportStyle = viewport.style; + viewportStyle.width = width + 'px'; + viewportStyle.height = height + 'px'; + } + var svgDom = this._svgDom; + if (svgDom) { + svgDom.setAttribute('width', width); + svgDom.setAttribute('height', height); + } + } + }; + SVGPainter.prototype.getWidth = function () { + return this._width; + }; + SVGPainter.prototype.getHeight = function () { + return this._height; + }; + SVGPainter.prototype.dispose = function () { + if (this.root) { + this.root.innerHTML = ''; + } + this._svgDom = + this._viewport = + this.storage = + this._oldVNode = + this._bgVNode = + this._mainVNode = null; + }; + SVGPainter.prototype.clear = function () { + if (this._svgDom) { + this._svgDom.innerHTML = null; + } + this._oldVNode = null; + }; + SVGPainter.prototype.toDataURL = function (base64) { + var str = encodeURIComponent(this.renderToString()); + var prefix = 'data:image/svg+xml;'; + if (base64) { + str = encodeBase64(str); + return str && prefix + 'base64,' + str; + } + return prefix + 'charset=UTF-8,' + str; + }; + return SVGPainter; + }()); + function createMethodNotSupport(method) { + return function () { + if ("development" !== 'production') { + logError('In SVG mode painter not support method "' + method + '"'); + } + }; + } + + function install(registers) { + registers.registerPainter('svg', SVGPainter); + } + + function createDom(id, painter, dpr) { + var newDom = platformApi.createCanvas(); + var width = painter.getWidth(); + var height = painter.getHeight(); + var newDomStyle = newDom.style; + if (newDomStyle) { + newDomStyle.position = 'absolute'; + newDomStyle.left = '0'; + newDomStyle.top = '0'; + newDomStyle.width = width + 'px'; + newDomStyle.height = height + 'px'; + newDom.setAttribute('data-zr-dom-id', id); + } + newDom.width = width * dpr; + newDom.height = height * dpr; + return newDom; + } + var Layer = (function (_super) { + __extends(Layer, _super); + function Layer(id, painter, dpr) { + var _this = _super.call(this) || this; + _this.motionBlur = false; + _this.lastFrameAlpha = 0.7; + _this.dpr = 1; + _this.virtual = false; + _this.config = {}; + _this.incremental = false; + _this.zlevel = 0; + _this.maxRepaintRectCount = 5; + _this.__dirty = true; + _this.__firstTimePaint = true; + _this.__used = false; + _this.__drawIndex = 0; + _this.__startIndex = 0; + _this.__endIndex = 0; + _this.__prevStartIndex = null; + _this.__prevEndIndex = null; + var dom; + dpr = dpr || devicePixelRatio; + if (typeof id === 'string') { + dom = createDom(id, painter, dpr); + } + else if (isObject(id)) { + dom = id; + id = dom.id; + } + _this.id = id; + _this.dom = dom; + var domStyle = dom.style; + if (domStyle) { + disableUserSelect(dom); + dom.onselectstart = function () { return false; }; + domStyle.padding = '0'; + domStyle.margin = '0'; + domStyle.borderWidth = '0'; + } + _this.painter = painter; + _this.dpr = dpr; + return _this; + } + Layer.prototype.getElementCount = function () { + return this.__endIndex - this.__startIndex; + }; + Layer.prototype.afterBrush = function () { + this.__prevStartIndex = this.__startIndex; + this.__prevEndIndex = this.__endIndex; + }; + Layer.prototype.initContext = function () { + this.ctx = this.dom.getContext('2d'); + this.ctx.dpr = this.dpr; + }; + Layer.prototype.setUnpainted = function () { + this.__firstTimePaint = true; + }; + Layer.prototype.createBackBuffer = function () { + var dpr = this.dpr; + this.domBack = createDom('back-' + this.id, this.painter, dpr); + this.ctxBack = this.domBack.getContext('2d'); + if (dpr !== 1) { + this.ctxBack.scale(dpr, dpr); + } + }; + Layer.prototype.createRepaintRects = function (displayList, prevList, viewWidth, viewHeight) { + if (this.__firstTimePaint) { + this.__firstTimePaint = false; + return null; + } + var mergedRepaintRects = []; + var maxRepaintRectCount = this.maxRepaintRectCount; + var full = false; + var pendingRect = new BoundingRect(0, 0, 0, 0); + function addRectToMergePool(rect) { + if (!rect.isFinite() || rect.isZero()) { + return; + } + if (mergedRepaintRects.length === 0) { + var boundingRect = new BoundingRect(0, 0, 0, 0); + boundingRect.copy(rect); + mergedRepaintRects.push(boundingRect); + } + else { + var isMerged = false; + var minDeltaArea = Infinity; + var bestRectToMergeIdx = 0; + for (var i = 0; i < mergedRepaintRects.length; ++i) { + var mergedRect = mergedRepaintRects[i]; + if (mergedRect.intersect(rect)) { + var pendingRect_1 = new BoundingRect(0, 0, 0, 0); + pendingRect_1.copy(mergedRect); + pendingRect_1.union(rect); + mergedRepaintRects[i] = pendingRect_1; + isMerged = true; + break; + } + else if (full) { + pendingRect.copy(rect); + pendingRect.union(mergedRect); + var aArea = rect.width * rect.height; + var bArea = mergedRect.width * mergedRect.height; + var pendingArea = pendingRect.width * pendingRect.height; + var deltaArea = pendingArea - aArea - bArea; + if (deltaArea < minDeltaArea) { + minDeltaArea = deltaArea; + bestRectToMergeIdx = i; + } + } + } + if (full) { + mergedRepaintRects[bestRectToMergeIdx].union(rect); + isMerged = true; + } + if (!isMerged) { + var boundingRect = new BoundingRect(0, 0, 0, 0); + boundingRect.copy(rect); + mergedRepaintRects.push(boundingRect); + } + if (!full) { + full = mergedRepaintRects.length >= maxRepaintRectCount; + } + } + } + for (var i = this.__startIndex; i < this.__endIndex; ++i) { + var el = displayList[i]; + if (el) { + var shouldPaint = el.shouldBePainted(viewWidth, viewHeight, true, true); + var prevRect = el.__isRendered && ((el.__dirty & REDRAW_BIT) || !shouldPaint) + ? el.getPrevPaintRect() + : null; + if (prevRect) { + addRectToMergePool(prevRect); + } + var curRect = shouldPaint && ((el.__dirty & REDRAW_BIT) || !el.__isRendered) + ? el.getPaintRect() + : null; + if (curRect) { + addRectToMergePool(curRect); + } + } + } + for (var i = this.__prevStartIndex; i < this.__prevEndIndex; ++i) { + var el = prevList[i]; + var shouldPaint = el.shouldBePainted(viewWidth, viewHeight, true, true); + if (el && (!shouldPaint || !el.__zr) && el.__isRendered) { + var prevRect = el.getPrevPaintRect(); + if (prevRect) { + addRectToMergePool(prevRect); + } + } + } + var hasIntersections; + do { + hasIntersections = false; + for (var i = 0; i < mergedRepaintRects.length;) { + if (mergedRepaintRects[i].isZero()) { + mergedRepaintRects.splice(i, 1); + continue; + } + for (var j = i + 1; j < mergedRepaintRects.length;) { + if (mergedRepaintRects[i].intersect(mergedRepaintRects[j])) { + hasIntersections = true; + mergedRepaintRects[i].union(mergedRepaintRects[j]); + mergedRepaintRects.splice(j, 1); + } + else { + j++; + } + } + i++; + } + } while (hasIntersections); + this._paintRects = mergedRepaintRects; + return mergedRepaintRects; + }; + Layer.prototype.debugGetPaintRects = function () { + return (this._paintRects || []).slice(); + }; + Layer.prototype.resize = function (width, height) { + var dpr = this.dpr; + var dom = this.dom; + var domStyle = dom.style; + var domBack = this.domBack; + if (domStyle) { + domStyle.width = width + 'px'; + domStyle.height = height + 'px'; + } + dom.width = width * dpr; + dom.height = height * dpr; + if (domBack) { + domBack.width = width * dpr; + domBack.height = height * dpr; + if (dpr !== 1) { + this.ctxBack.scale(dpr, dpr); + } + } + }; + Layer.prototype.clear = function (clearAll, clearColor, repaintRects) { + var dom = this.dom; + var ctx = this.ctx; + var width = dom.width; + var height = dom.height; + clearColor = clearColor || this.clearColor; + var haveMotionBLur = this.motionBlur && !clearAll; + var lastFrameAlpha = this.lastFrameAlpha; + var dpr = this.dpr; + var self = this; + if (haveMotionBLur) { + if (!this.domBack) { + this.createBackBuffer(); + } + this.ctxBack.globalCompositeOperation = 'copy'; + this.ctxBack.drawImage(dom, 0, 0, width / dpr, height / dpr); + } + var domBack = this.domBack; + function doClear(x, y, width, height) { + ctx.clearRect(x, y, width, height); + if (clearColor && clearColor !== 'transparent') { + var clearColorGradientOrPattern = void 0; + if (isGradientObject(clearColor)) { + clearColorGradientOrPattern = clearColor.__canvasGradient + || getCanvasGradient(ctx, clearColor, { + x: 0, + y: 0, + width: width, + height: height + }); + clearColor.__canvasGradient = clearColorGradientOrPattern; + } + else if (isImagePatternObject(clearColor)) { + clearColorGradientOrPattern = createCanvasPattern(ctx, clearColor, { + dirty: function () { + self.setUnpainted(); + self.__painter.refresh(); + } + }); + } + ctx.save(); + ctx.fillStyle = clearColorGradientOrPattern || clearColor; + ctx.fillRect(x, y, width, height); + ctx.restore(); + } + if (haveMotionBLur) { + ctx.save(); + ctx.globalAlpha = lastFrameAlpha; + ctx.drawImage(domBack, x, y, width, height); + ctx.restore(); + } + } + if (!repaintRects || haveMotionBLur) { + doClear(0, 0, width, height); + } + else if (repaintRects.length) { + each(repaintRects, function (rect) { + doClear(rect.x * dpr, rect.y * dpr, rect.width * dpr, rect.height * dpr); + }); + } + }; + return Layer; + }(Eventful)); + + var HOVER_LAYER_ZLEVEL = 1e5; + var CANVAS_ZLEVEL = 314159; + var EL_AFTER_INCREMENTAL_INC = 0.01; + var INCREMENTAL_INC = 0.001; + function isLayerValid(layer) { + if (!layer) { + return false; + } + if (layer.__builtin__) { + return true; + } + if (typeof (layer.resize) !== 'function' + || typeof (layer.refresh) !== 'function') { + return false; + } + return true; + } + function createRoot(width, height) { + var domRoot = document.createElement('div'); + domRoot.style.cssText = [ + 'position:relative', + 'width:' + width + 'px', + 'height:' + height + 'px', + 'padding:0', + 'margin:0', + 'border-width:0' + ].join(';') + ';'; + return domRoot; + } + var CanvasPainter = (function () { + function CanvasPainter(root, storage, opts, id) { + this.type = 'canvas'; + this._zlevelList = []; + this._prevDisplayList = []; + this._layers = {}; + this._layerConfig = {}; + this._needsManuallyCompositing = false; + this.type = 'canvas'; + var singleCanvas = !root.nodeName + || root.nodeName.toUpperCase() === 'CANVAS'; + this._opts = opts = extend({}, opts || {}); + this.dpr = opts.devicePixelRatio || devicePixelRatio; + this._singleCanvas = singleCanvas; + this.root = root; + var rootStyle = root.style; + if (rootStyle) { + disableUserSelect(root); + root.innerHTML = ''; + } + this.storage = storage; + var zlevelList = this._zlevelList; + this._prevDisplayList = []; + var layers = this._layers; + if (!singleCanvas) { + this._width = getSize(root, 0, opts); + this._height = getSize(root, 1, opts); + var domRoot = this._domRoot = createRoot(this._width, this._height); + root.appendChild(domRoot); + } + else { + var rootCanvas = root; + var width = rootCanvas.width; + var height = rootCanvas.height; + if (opts.width != null) { + width = opts.width; + } + if (opts.height != null) { + height = opts.height; + } + this.dpr = opts.devicePixelRatio || 1; + rootCanvas.width = width * this.dpr; + rootCanvas.height = height * this.dpr; + this._width = width; + this._height = height; + var mainLayer = new Layer(rootCanvas, this, this.dpr); + mainLayer.__builtin__ = true; + mainLayer.initContext(); + layers[CANVAS_ZLEVEL] = mainLayer; + mainLayer.zlevel = CANVAS_ZLEVEL; + zlevelList.push(CANVAS_ZLEVEL); + this._domRoot = root; + } + } + CanvasPainter.prototype.getType = function () { + return 'canvas'; + }; + CanvasPainter.prototype.isSingleCanvas = function () { + return this._singleCanvas; + }; + CanvasPainter.prototype.getViewportRoot = function () { + return this._domRoot; + }; + CanvasPainter.prototype.getViewportRootOffset = function () { + var viewportRoot = this.getViewportRoot(); + if (viewportRoot) { + return { + offsetLeft: viewportRoot.offsetLeft || 0, + offsetTop: viewportRoot.offsetTop || 0 + }; + } + }; + CanvasPainter.prototype.refresh = function (paintAll) { + var list = this.storage.getDisplayList(true); + var prevList = this._prevDisplayList; + var zlevelList = this._zlevelList; + this._redrawId = Math.random(); + this._paintList(list, prevList, paintAll, this._redrawId); + for (var i = 0; i < zlevelList.length; i++) { + var z = zlevelList[i]; + var layer = this._layers[z]; + if (!layer.__builtin__ && layer.refresh) { + var clearColor = i === 0 ? this._backgroundColor : null; + layer.refresh(clearColor); + } + } + if (this._opts.useDirtyRect) { + this._prevDisplayList = list.slice(); + } + return this; + }; + CanvasPainter.prototype.refreshHover = function () { + this._paintHoverList(this.storage.getDisplayList(false)); + }; + CanvasPainter.prototype._paintHoverList = function (list) { + var len = list.length; + var hoverLayer = this._hoverlayer; + hoverLayer && hoverLayer.clear(); + if (!len) { + return; + } + var scope = { + inHover: true, + viewWidth: this._width, + viewHeight: this._height + }; + var ctx; + for (var i = 0; i < len; i++) { + var el = list[i]; + if (el.__inHover) { + if (!hoverLayer) { + hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL); + } + if (!ctx) { + ctx = hoverLayer.ctx; + ctx.save(); + } + brush(ctx, el, scope, i === len - 1); + } + } + if (ctx) { + ctx.restore(); + } + }; + CanvasPainter.prototype.getHoverLayer = function () { + return this.getLayer(HOVER_LAYER_ZLEVEL); + }; + CanvasPainter.prototype.paintOne = function (ctx, el) { + brushSingle(ctx, el); + }; + CanvasPainter.prototype._paintList = function (list, prevList, paintAll, redrawId) { + if (this._redrawId !== redrawId) { + return; + } + paintAll = paintAll || false; + this._updateLayerStatus(list); + var _a = this._doPaintList(list, prevList, paintAll), finished = _a.finished, needsRefreshHover = _a.needsRefreshHover; + if (this._needsManuallyCompositing) { + this._compositeManually(); + } + if (needsRefreshHover) { + this._paintHoverList(list); + } + if (!finished) { + var self_1 = this; + requestAnimationFrame$1(function () { + self_1._paintList(list, prevList, paintAll, redrawId); + }); + } + else { + this.eachLayer(function (layer) { + layer.afterBrush && layer.afterBrush(); + }); + } + }; + CanvasPainter.prototype._compositeManually = function () { + var ctx = this.getLayer(CANVAS_ZLEVEL).ctx; + var width = this._domRoot.width; + var height = this._domRoot.height; + ctx.clearRect(0, 0, width, height); + this.eachBuiltinLayer(function (layer) { + if (layer.virtual) { + ctx.drawImage(layer.dom, 0, 0, width, height); + } + }); + }; + CanvasPainter.prototype._doPaintList = function (list, prevList, paintAll) { + var _this = this; + var layerList = []; + var useDirtyRect = this._opts.useDirtyRect; + for (var zi = 0; zi < this._zlevelList.length; zi++) { + var zlevel = this._zlevelList[zi]; + var layer = this._layers[zlevel]; + if (layer.__builtin__ + && layer !== this._hoverlayer + && (layer.__dirty || paintAll)) { + layerList.push(layer); + } + } + var finished = true; + var needsRefreshHover = false; + var _loop_1 = function (k) { + var layer = layerList[k]; + var ctx = layer.ctx; + var repaintRects = useDirtyRect + && layer.createRepaintRects(list, prevList, this_1._width, this_1._height); + var start = paintAll ? layer.__startIndex : layer.__drawIndex; + var useTimer = !paintAll && layer.incremental && Date.now; + var startTime = useTimer && Date.now(); + var clearColor = layer.zlevel === this_1._zlevelList[0] + ? this_1._backgroundColor : null; + if (layer.__startIndex === layer.__endIndex) { + layer.clear(false, clearColor, repaintRects); + } + else if (start === layer.__startIndex) { + var firstEl = list[start]; + if (!firstEl.incremental || !firstEl.notClear || paintAll) { + layer.clear(false, clearColor, repaintRects); + } + } + if (start === -1) { + console.error('For some unknown reason. drawIndex is -1'); + start = layer.__startIndex; + } + var i; + var repaint = function (repaintRect) { + var scope = { + inHover: false, + allClipped: false, + prevEl: null, + viewWidth: _this._width, + viewHeight: _this._height + }; + for (i = start; i < layer.__endIndex; i++) { + var el = list[i]; + if (el.__inHover) { + needsRefreshHover = true; + } + _this._doPaintEl(el, layer, useDirtyRect, repaintRect, scope, i === layer.__endIndex - 1); + if (useTimer) { + var dTime = Date.now() - startTime; + if (dTime > 15) { + break; + } + } + } + if (scope.prevElClipPaths) { + ctx.restore(); + } + }; + if (repaintRects) { + if (repaintRects.length === 0) { + i = layer.__endIndex; + } + else { + var dpr = this_1.dpr; + for (var r = 0; r < repaintRects.length; ++r) { + var rect = repaintRects[r]; + ctx.save(); + ctx.beginPath(); + ctx.rect(rect.x * dpr, rect.y * dpr, rect.width * dpr, rect.height * dpr); + ctx.clip(); + repaint(rect); + ctx.restore(); + } + } + } + else { + ctx.save(); + repaint(); + ctx.restore(); + } + layer.__drawIndex = i; + if (layer.__drawIndex < layer.__endIndex) { + finished = false; + } + }; + var this_1 = this; + for (var k = 0; k < layerList.length; k++) { + _loop_1(k); + } + if (env.wxa) { + each(this._layers, function (layer) { + if (layer && layer.ctx && layer.ctx.draw) { + layer.ctx.draw(); + } + }); + } + return { + finished: finished, + needsRefreshHover: needsRefreshHover + }; + }; + CanvasPainter.prototype._doPaintEl = function (el, currentLayer, useDirtyRect, repaintRect, scope, isLast) { + var ctx = currentLayer.ctx; + if (useDirtyRect) { + var paintRect = el.getPaintRect(); + if (!repaintRect || paintRect && paintRect.intersect(repaintRect)) { + brush(ctx, el, scope, isLast); + el.setPrevPaintRect(paintRect); + } + } + else { + brush(ctx, el, scope, isLast); + } + }; + CanvasPainter.prototype.getLayer = function (zlevel, virtual) { + if (this._singleCanvas && !this._needsManuallyCompositing) { + zlevel = CANVAS_ZLEVEL; + } + var layer = this._layers[zlevel]; + if (!layer) { + layer = new Layer('zr_' + zlevel, this, this.dpr); + layer.zlevel = zlevel; + layer.__builtin__ = true; + if (this._layerConfig[zlevel]) { + merge(layer, this._layerConfig[zlevel], true); + } + else if (this._layerConfig[zlevel - EL_AFTER_INCREMENTAL_INC]) { + merge(layer, this._layerConfig[zlevel - EL_AFTER_INCREMENTAL_INC], true); + } + if (virtual) { + layer.virtual = virtual; + } + this.insertLayer(zlevel, layer); + layer.initContext(); + } + return layer; + }; + CanvasPainter.prototype.insertLayer = function (zlevel, layer) { + var layersMap = this._layers; + var zlevelList = this._zlevelList; + var len = zlevelList.length; + var domRoot = this._domRoot; + var prevLayer = null; + var i = -1; + if (layersMap[zlevel]) { + if ("development" !== 'production') { + logError('ZLevel ' + zlevel + ' has been used already'); + } + return; + } + if (!isLayerValid(layer)) { + if ("development" !== 'production') { + logError('Layer of zlevel ' + zlevel + ' is not valid'); + } + return; + } + if (len > 0 && zlevel > zlevelList[0]) { + for (i = 0; i < len - 1; i++) { + if (zlevelList[i] < zlevel + && zlevelList[i + 1] > zlevel) { + break; + } + } + prevLayer = layersMap[zlevelList[i]]; + } + zlevelList.splice(i + 1, 0, zlevel); + layersMap[zlevel] = layer; + if (!layer.virtual) { + if (prevLayer) { + var prevDom = prevLayer.dom; + if (prevDom.nextSibling) { + domRoot.insertBefore(layer.dom, prevDom.nextSibling); + } + else { + domRoot.appendChild(layer.dom); + } + } + else { + if (domRoot.firstChild) { + domRoot.insertBefore(layer.dom, domRoot.firstChild); + } + else { + domRoot.appendChild(layer.dom); + } + } + } + layer.__painter = this; + }; + CanvasPainter.prototype.eachLayer = function (cb, context) { + var zlevelList = this._zlevelList; + for (var i = 0; i < zlevelList.length; i++) { + var z = zlevelList[i]; + cb.call(context, this._layers[z], z); + } + }; + CanvasPainter.prototype.eachBuiltinLayer = function (cb, context) { + var zlevelList = this._zlevelList; + for (var i = 0; i < zlevelList.length; i++) { + var z = zlevelList[i]; + var layer = this._layers[z]; + if (layer.__builtin__) { + cb.call(context, layer, z); + } + } + }; + CanvasPainter.prototype.eachOtherLayer = function (cb, context) { + var zlevelList = this._zlevelList; + for (var i = 0; i < zlevelList.length; i++) { + var z = zlevelList[i]; + var layer = this._layers[z]; + if (!layer.__builtin__) { + cb.call(context, layer, z); + } + } + }; + CanvasPainter.prototype.getLayers = function () { + return this._layers; + }; + CanvasPainter.prototype._updateLayerStatus = function (list) { + this.eachBuiltinLayer(function (layer, z) { + layer.__dirty = layer.__used = false; + }); + function updatePrevLayer(idx) { + if (prevLayer) { + if (prevLayer.__endIndex !== idx) { + prevLayer.__dirty = true; + } + prevLayer.__endIndex = idx; + } + } + if (this._singleCanvas) { + for (var i_1 = 1; i_1 < list.length; i_1++) { + var el = list[i_1]; + if (el.zlevel !== list[i_1 - 1].zlevel || el.incremental) { + this._needsManuallyCompositing = true; + break; + } + } + } + var prevLayer = null; + var incrementalLayerCount = 0; + var prevZlevel; + var i; + for (i = 0; i < list.length; i++) { + var el = list[i]; + var zlevel = el.zlevel; + var layer = void 0; + if (prevZlevel !== zlevel) { + prevZlevel = zlevel; + incrementalLayerCount = 0; + } + if (el.incremental) { + layer = this.getLayer(zlevel + INCREMENTAL_INC, this._needsManuallyCompositing); + layer.incremental = true; + incrementalLayerCount = 1; + } + else { + layer = this.getLayer(zlevel + (incrementalLayerCount > 0 ? EL_AFTER_INCREMENTAL_INC : 0), this._needsManuallyCompositing); + } + if (!layer.__builtin__) { + logError('ZLevel ' + zlevel + ' has been used by unkown layer ' + layer.id); + } + if (layer !== prevLayer) { + layer.__used = true; + if (layer.__startIndex !== i) { + layer.__dirty = true; + } + layer.__startIndex = i; + if (!layer.incremental) { + layer.__drawIndex = i; + } + else { + layer.__drawIndex = -1; + } + updatePrevLayer(i); + prevLayer = layer; + } + if ((el.__dirty & REDRAW_BIT) && !el.__inHover) { + layer.__dirty = true; + if (layer.incremental && layer.__drawIndex < 0) { + layer.__drawIndex = i; + } + } + } + updatePrevLayer(i); + this.eachBuiltinLayer(function (layer, z) { + if (!layer.__used && layer.getElementCount() > 0) { + layer.__dirty = true; + layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0; + } + if (layer.__dirty && layer.__drawIndex < 0) { + layer.__drawIndex = layer.__startIndex; + } + }); + }; + CanvasPainter.prototype.clear = function () { + this.eachBuiltinLayer(this._clearLayer); + return this; + }; + CanvasPainter.prototype._clearLayer = function (layer) { + layer.clear(); + }; + CanvasPainter.prototype.setBackgroundColor = function (backgroundColor) { + this._backgroundColor = backgroundColor; + each(this._layers, function (layer) { + layer.setUnpainted(); + }); + }; + CanvasPainter.prototype.configLayer = function (zlevel, config) { + if (config) { + var layerConfig = this._layerConfig; + if (!layerConfig[zlevel]) { + layerConfig[zlevel] = config; + } + else { + merge(layerConfig[zlevel], config, true); + } + for (var i = 0; i < this._zlevelList.length; i++) { + var _zlevel = this._zlevelList[i]; + if (_zlevel === zlevel || _zlevel === zlevel + EL_AFTER_INCREMENTAL_INC) { + var layer = this._layers[_zlevel]; + merge(layer, layerConfig[zlevel], true); + } + } + } + }; + CanvasPainter.prototype.delLayer = function (zlevel) { + var layers = this._layers; + var zlevelList = this._zlevelList; + var layer = layers[zlevel]; + if (!layer) { + return; + } + layer.dom.parentNode.removeChild(layer.dom); + delete layers[zlevel]; + zlevelList.splice(indexOf(zlevelList, zlevel), 1); + }; + CanvasPainter.prototype.resize = function (width, height) { + if (!this._domRoot.style) { + if (width == null || height == null) { + return; + } + this._width = width; + this._height = height; + this.getLayer(CANVAS_ZLEVEL).resize(width, height); + } + else { + var domRoot = this._domRoot; + domRoot.style.display = 'none'; + var opts = this._opts; + var root = this.root; + width != null && (opts.width = width); + height != null && (opts.height = height); + width = getSize(root, 0, opts); + height = getSize(root, 1, opts); + domRoot.style.display = ''; + if (this._width !== width || height !== this._height) { + domRoot.style.width = width + 'px'; + domRoot.style.height = height + 'px'; + for (var id in this._layers) { + if (this._layers.hasOwnProperty(id)) { + this._layers[id].resize(width, height); + } + } + this.refresh(true); + } + this._width = width; + this._height = height; + } + return this; + }; + CanvasPainter.prototype.clearLayer = function (zlevel) { + var layer = this._layers[zlevel]; + if (layer) { + layer.clear(); + } + }; + CanvasPainter.prototype.dispose = function () { + this.root.innerHTML = ''; + this.root = + this.storage = + this._domRoot = + this._layers = null; + }; + CanvasPainter.prototype.getRenderedCanvas = function (opts) { + opts = opts || {}; + if (this._singleCanvas && !this._compositeManually) { + return this._layers[CANVAS_ZLEVEL].dom; + } + var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr); + imageLayer.initContext(); + imageLayer.clear(false, opts.backgroundColor || this._backgroundColor); + var ctx = imageLayer.ctx; + if (opts.pixelRatio <= this.dpr) { + this.refresh(); + var width_1 = imageLayer.dom.width; + var height_1 = imageLayer.dom.height; + this.eachLayer(function (layer) { + if (layer.__builtin__) { + ctx.drawImage(layer.dom, 0, 0, width_1, height_1); + } + else if (layer.renderToCanvas) { + ctx.save(); + layer.renderToCanvas(ctx); + ctx.restore(); + } + }); + } + else { + var scope = { + inHover: false, + viewWidth: this._width, + viewHeight: this._height + }; + var displayList = this.storage.getDisplayList(true); + for (var i = 0, len = displayList.length; i < len; i++) { + var el = displayList[i]; + brush(ctx, el, scope, i === len - 1); + } + } + return imageLayer.dom; + }; + CanvasPainter.prototype.getWidth = function () { + return this._width; + }; + CanvasPainter.prototype.getHeight = function () { + return this._height; + }; + return CanvasPainter; + }()); + + function install$1(registers) { + registers.registerPainter('canvas', CanvasPainter); + } + + var LineSeriesModel = + /** @class */ + function (_super) { + __extends(LineSeriesModel, _super); + + function LineSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = LineSeriesModel.type; + _this.hasSymbolVisual = true; + return _this; + } + + LineSeriesModel.prototype.getInitialData = function (option) { + if ("development" !== 'production') { + var coordSys = option.coordinateSystem; + + if (coordSys !== 'polar' && coordSys !== 'cartesian2d') { + throw new Error('Line not support coordinateSystem besides cartesian and polar'); + } + } + + return createSeriesData(null, this, { + useEncodeDefaulter: true + }); + }; + + LineSeriesModel.prototype.getLegendIcon = function (opt) { + var group = new Group(); + var line = createSymbol('line', 0, opt.itemHeight / 2, opt.itemWidth, 0, opt.lineStyle.stroke, false); + group.add(line); + line.setStyle(opt.lineStyle); + var visualType = this.getData().getVisual('symbol'); + var visualRotate = this.getData().getVisual('symbolRotate'); + var symbolType = visualType === 'none' ? 'circle' : visualType; // Symbol size is 80% when there is a line + + var size = opt.itemHeight * 0.8; + var symbol = createSymbol(symbolType, (opt.itemWidth - size) / 2, (opt.itemHeight - size) / 2, size, size, opt.itemStyle.fill); + group.add(symbol); + symbol.setStyle(opt.itemStyle); + var symbolRotate = opt.iconRotate === 'inherit' ? visualRotate : opt.iconRotate || 0; + symbol.rotation = symbolRotate * Math.PI / 180; + symbol.setOrigin([opt.itemWidth / 2, opt.itemHeight / 2]); + + if (symbolType.indexOf('empty') > -1) { + symbol.style.stroke = symbol.style.fill; + symbol.style.fill = '#fff'; + symbol.style.lineWidth = 2; + } + + return group; + }; + + LineSeriesModel.type = 'series.line'; + LineSeriesModel.dependencies = ['grid', 'polar']; + LineSeriesModel.defaultOption = { + // zlevel: 0, + z: 3, + coordinateSystem: 'cartesian2d', + legendHoverLink: true, + clip: true, + label: { + position: 'top' + }, + // itemStyle: { + // }, + endLabel: { + show: false, + valueAnimation: true, + distance: 8 + }, + lineStyle: { + width: 2, + type: 'solid' + }, + emphasis: { + scale: true + }, + // areaStyle: { + // origin of areaStyle. Valid values: + // `'auto'/null/undefined`: from axisLine to data + // `'start'`: from min to data + // `'end'`: from data to max + // origin: 'auto' + // }, + // false, 'start', 'end', 'middle' + step: false, + // Disabled if step is true + smooth: false, + smoothMonotone: null, + symbol: 'emptyCircle', + symbolSize: 4, + symbolRotate: null, + showSymbol: true, + // `false`: follow the label interval strategy. + // `true`: show all symbols. + // `'auto'`: If possible, show all symbols, otherwise + // follow the label interval strategy. + showAllSymbol: 'auto', + // Whether to connect break point. + connectNulls: false, + // Sampling for large data. Can be: 'average', 'max', 'min', 'sum', 'lttb'. + sampling: 'none', + animationEasing: 'linear', + // Disable progressive + progressive: 0, + hoverLayerThreshold: Infinity, + universalTransition: { + divideShape: 'clone' + }, + triggerLineEvent: false + }; + return LineSeriesModel; + }(SeriesModel); + + /** + * @return label string. Not null/undefined + */ + + function getDefaultLabel(data, dataIndex) { + var labelDims = data.mapDimensionsAll('defaultedLabel'); + var len = labelDims.length; // Simple optimization (in lots of cases, label dims length is 1) + + if (len === 1) { + var rawVal = retrieveRawValue(data, dataIndex, labelDims[0]); + return rawVal != null ? rawVal + '' : null; + } else if (len) { + var vals = []; + + for (var i = 0; i < labelDims.length; i++) { + vals.push(retrieveRawValue(data, dataIndex, labelDims[i])); + } + + return vals.join(' '); + } + } + function getDefaultInterpolatedLabel(data, interpolatedValue) { + var labelDims = data.mapDimensionsAll('defaultedLabel'); + + if (!isArray(interpolatedValue)) { + return interpolatedValue + ''; + } + + var vals = []; + + for (var i = 0; i < labelDims.length; i++) { + var dimIndex = data.getDimensionIndex(labelDims[i]); + + if (dimIndex >= 0) { + vals.push(interpolatedValue[dimIndex]); + } + } + + return vals.join(' '); + } + + var Symbol = + /** @class */ + function (_super) { + __extends(Symbol, _super); + + function Symbol(data, idx, seriesScope, opts) { + var _this = _super.call(this) || this; + + _this.updateData(data, idx, seriesScope, opts); + + return _this; + } + + Symbol.prototype._createSymbol = function (symbolType, data, idx, symbolSize, keepAspect) { + // Remove paths created before + this.removeAll(); // let symbolPath = createSymbol( + // symbolType, -0.5, -0.5, 1, 1, color + // ); + // If width/height are set too small (e.g., set to 1) on ios10 + // and macOS Sierra, a circle stroke become a rect, no matter what + // the scale is set. So we set width/height as 2. See #4150. + + var symbolPath = createSymbol(symbolType, -1, -1, 2, 2, null, keepAspect); + symbolPath.attr({ + z2: 100, + culling: true, + scaleX: symbolSize[0] / 2, + scaleY: symbolSize[1] / 2 + }); // Rewrite drift method + + symbolPath.drift = driftSymbol; + this._symbolType = symbolType; + this.add(symbolPath); + }; + /** + * Stop animation + * @param {boolean} toLastFrame + */ + + + Symbol.prototype.stopSymbolAnimation = function (toLastFrame) { + this.childAt(0).stopAnimation(null, toLastFrame); + }; + + Symbol.prototype.getSymbolType = function () { + return this._symbolType; + }; + /** + * FIXME: + * Caution: This method breaks the encapsulation of this module, + * but it indeed brings convenience. So do not use the method + * unless you detailedly know all the implements of `Symbol`, + * especially animation. + * + * Get symbol path element. + */ + + + Symbol.prototype.getSymbolPath = function () { + return this.childAt(0); + }; + /** + * Highlight symbol + */ + + + Symbol.prototype.highlight = function () { + enterEmphasis(this.childAt(0)); + }; + /** + * Downplay symbol + */ + + + Symbol.prototype.downplay = function () { + leaveEmphasis(this.childAt(0)); + }; + /** + * @param {number} zlevel + * @param {number} z + */ + + + Symbol.prototype.setZ = function (zlevel, z) { + var symbolPath = this.childAt(0); + symbolPath.zlevel = zlevel; + symbolPath.z = z; + }; + + Symbol.prototype.setDraggable = function (draggable) { + var symbolPath = this.childAt(0); + symbolPath.draggable = draggable; + symbolPath.cursor = draggable ? 'move' : symbolPath.cursor; + }; + /** + * Update symbol properties + */ + + + Symbol.prototype.updateData = function (data, idx, seriesScope, opts) { + this.silent = false; + var symbolType = data.getItemVisual(idx, 'symbol') || 'circle'; + var seriesModel = data.hostModel; + var symbolSize = Symbol.getSymbolSize(data, idx); + var isInit = symbolType !== this._symbolType; + var disableAnimation = opts && opts.disableAnimation; + + if (isInit) { + var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect'); + + this._createSymbol(symbolType, data, idx, symbolSize, keepAspect); + } else { + var symbolPath = this.childAt(0); + symbolPath.silent = false; + var target = { + scaleX: symbolSize[0] / 2, + scaleY: symbolSize[1] / 2 + }; + disableAnimation ? symbolPath.attr(target) : updateProps(symbolPath, target, seriesModel, idx); + saveOldStyle(symbolPath); + } + + this._updateCommon(data, idx, symbolSize, seriesScope, opts); + + if (isInit) { + var symbolPath = this.childAt(0); + + if (!disableAnimation) { + var target = { + scaleX: this._sizeX, + scaleY: this._sizeY, + style: { + // Always fadeIn. Because it has fadeOut animation when symbol is removed.. + opacity: symbolPath.style.opacity + } + }; + symbolPath.scaleX = symbolPath.scaleY = 0; + symbolPath.style.opacity = 0; + initProps(symbolPath, target, seriesModel, idx); + } + } + + if (disableAnimation) { + // Must stop leave transition manually if don't call initProps or updateProps. + this.childAt(0).stopAnimation('leave'); + } + }; + + Symbol.prototype._updateCommon = function (data, idx, symbolSize, seriesScope, opts) { + var symbolPath = this.childAt(0); + var seriesModel = data.hostModel; + var emphasisItemStyle; + var blurItemStyle; + var selectItemStyle; + var focus; + var blurScope; + var emphasisDisabled; + var labelStatesModels; + var hoverScale; + var cursorStyle; + + if (seriesScope) { + emphasisItemStyle = seriesScope.emphasisItemStyle; + blurItemStyle = seriesScope.blurItemStyle; + selectItemStyle = seriesScope.selectItemStyle; + focus = seriesScope.focus; + blurScope = seriesScope.blurScope; + labelStatesModels = seriesScope.labelStatesModels; + hoverScale = seriesScope.hoverScale; + cursorStyle = seriesScope.cursorStyle; + emphasisDisabled = seriesScope.emphasisDisabled; + } + + if (!seriesScope || data.hasItemOption) { + var itemModel = seriesScope && seriesScope.itemModel ? seriesScope.itemModel : data.getItemModel(idx); + var emphasisModel = itemModel.getModel('emphasis'); + emphasisItemStyle = emphasisModel.getModel('itemStyle').getItemStyle(); + selectItemStyle = itemModel.getModel(['select', 'itemStyle']).getItemStyle(); + blurItemStyle = itemModel.getModel(['blur', 'itemStyle']).getItemStyle(); + focus = emphasisModel.get('focus'); + blurScope = emphasisModel.get('blurScope'); + emphasisDisabled = emphasisModel.get('disabled'); + labelStatesModels = getLabelStatesModels(itemModel); + hoverScale = emphasisModel.getShallow('scale'); + cursorStyle = itemModel.getShallow('cursor'); + } + + var symbolRotate = data.getItemVisual(idx, 'symbolRotate'); + symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0); + var symbolOffset = normalizeSymbolOffset(data.getItemVisual(idx, 'symbolOffset'), symbolSize); + + if (symbolOffset) { + symbolPath.x = symbolOffset[0]; + symbolPath.y = symbolOffset[1]; + } + + cursorStyle && symbolPath.attr('cursor', cursorStyle); + var symbolStyle = data.getItemVisual(idx, 'style'); + var visualColor = symbolStyle.fill; + + if (symbolPath instanceof ZRImage) { + var pathStyle = symbolPath.style; + symbolPath.useStyle(extend({ + // TODO other properties like x, y ? + image: pathStyle.image, + x: pathStyle.x, + y: pathStyle.y, + width: pathStyle.width, + height: pathStyle.height + }, symbolStyle)); + } else { + if (symbolPath.__isEmptyBrush) { + // fill and stroke will be swapped if it's empty. + // So we cloned a new style to avoid it affecting the original style in visual storage. + // TODO Better implementation. No empty logic! + symbolPath.useStyle(extend({}, symbolStyle)); + } else { + symbolPath.useStyle(symbolStyle); + } // Disable decal because symbol scale will been applied on the decal. + + + symbolPath.style.decal = null; + symbolPath.setColor(visualColor, opts && opts.symbolInnerColor); + symbolPath.style.strokeNoScale = true; + } + + var liftZ = data.getItemVisual(idx, 'liftZ'); + var z2Origin = this._z2; + + if (liftZ != null) { + if (z2Origin == null) { + this._z2 = symbolPath.z2; + symbolPath.z2 += liftZ; + } + } else if (z2Origin != null) { + symbolPath.z2 = z2Origin; + this._z2 = null; + } + + var useNameLabel = opts && opts.useNameLabel; + setLabelStyle(symbolPath, labelStatesModels, { + labelFetcher: seriesModel, + labelDataIndex: idx, + defaultText: getLabelDefaultText, + inheritColor: visualColor, + defaultOpacity: symbolStyle.opacity + }); // Do not execute util needed. + + function getLabelDefaultText(idx) { + return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx); + } + + this._sizeX = symbolSize[0] / 2; + this._sizeY = symbolSize[1] / 2; + var emphasisState = symbolPath.ensureState('emphasis'); + emphasisState.style = emphasisItemStyle; + symbolPath.ensureState('select').style = selectItemStyle; + symbolPath.ensureState('blur').style = blurItemStyle; + + if (hoverScale) { + var scaleRatio = Math.max(isNumber(hoverScale) ? hoverScale : 1.1, 3 / this._sizeY); + emphasisState.scaleX = this._sizeX * scaleRatio; + emphasisState.scaleY = this._sizeY * scaleRatio; + } + + this.setSymbolScale(1); + toggleHoverEmphasis(this, focus, blurScope, emphasisDisabled); + }; + + Symbol.prototype.setSymbolScale = function (scale) { + this.scaleX = this.scaleY = scale; + }; + + Symbol.prototype.fadeOut = function (cb, seriesModel, opt) { + var symbolPath = this.childAt(0); + var dataIndex = getECData(this).dataIndex; + var animationOpt = opt && opt.animation; // Avoid mistaken hover when fading out + + this.silent = symbolPath.silent = true; // Not show text when animating + + if (opt && opt.fadeLabel) { + var textContent = symbolPath.getTextContent(); + + if (textContent) { + removeElement(textContent, { + style: { + opacity: 0 + } + }, seriesModel, { + dataIndex: dataIndex, + removeOpt: animationOpt, + cb: function () { + symbolPath.removeTextContent(); + } + }); + } + } else { + symbolPath.removeTextContent(); + } + + removeElement(symbolPath, { + style: { + opacity: 0 + }, + scaleX: 0, + scaleY: 0 + }, seriesModel, { + dataIndex: dataIndex, + cb: cb, + removeOpt: animationOpt + }); + }; + + Symbol.getSymbolSize = function (data, idx) { + return normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize')); + }; + + return Symbol; + }(Group); + + function driftSymbol(dx, dy) { + this.parent.drift(dx, dy); + } + + function symbolNeedsDraw(data, point, idx, opt) { + return point && !isNaN(point[0]) && !isNaN(point[1]) && !(opt.isIgnore && opt.isIgnore(idx)) // We do not set clipShape on group, because it will cut part of + // the symbol element shape. We use the same clip shape here as + // the line clip. + && !(opt.clipShape && !opt.clipShape.contain(point[0], point[1])) && data.getItemVisual(idx, 'symbol') !== 'none'; + } + + function normalizeUpdateOpt(opt) { + if (opt != null && !isObject(opt)) { + opt = { + isIgnore: opt + }; + } + + return opt || {}; + } + + function makeSeriesScope(data) { + var seriesModel = data.hostModel; + var emphasisModel = seriesModel.getModel('emphasis'); + return { + emphasisItemStyle: emphasisModel.getModel('itemStyle').getItemStyle(), + blurItemStyle: seriesModel.getModel(['blur', 'itemStyle']).getItemStyle(), + selectItemStyle: seriesModel.getModel(['select', 'itemStyle']).getItemStyle(), + focus: emphasisModel.get('focus'), + blurScope: emphasisModel.get('blurScope'), + emphasisDisabled: emphasisModel.get('disabled'), + hoverScale: emphasisModel.get('scale'), + labelStatesModels: getLabelStatesModels(seriesModel), + cursorStyle: seriesModel.get('cursor') + }; + } + + var SymbolDraw = + /** @class */ + function () { + function SymbolDraw(SymbolCtor) { + this.group = new Group(); + this._SymbolCtor = SymbolCtor || Symbol; + } + /** + * Update symbols draw by new data + */ + + + SymbolDraw.prototype.updateData = function (data, opt) { + // Remove progressive els. + this._progressiveEls = null; + opt = normalizeUpdateOpt(opt); + var group = this.group; + var seriesModel = data.hostModel; + var oldData = this._data; + var SymbolCtor = this._SymbolCtor; + var disableAnimation = opt.disableAnimation; + var seriesScope = makeSeriesScope(data); + var symbolUpdateOpt = { + disableAnimation: disableAnimation + }; + + var getSymbolPoint = opt.getSymbolPoint || function (idx) { + return data.getItemLayout(idx); + }; // There is no oldLineData only when first rendering or switching from + // stream mode to normal mode, where previous elements should be removed. + + + if (!oldData) { + group.removeAll(); + } + + data.diff(oldData).add(function (newIdx) { + var point = getSymbolPoint(newIdx); + + if (symbolNeedsDraw(data, point, newIdx, opt)) { + var symbolEl = new SymbolCtor(data, newIdx, seriesScope, symbolUpdateOpt); + symbolEl.setPosition(point); + data.setItemGraphicEl(newIdx, symbolEl); + group.add(symbolEl); + } + }).update(function (newIdx, oldIdx) { + var symbolEl = oldData.getItemGraphicEl(oldIdx); + var point = getSymbolPoint(newIdx); + + if (!symbolNeedsDraw(data, point, newIdx, opt)) { + group.remove(symbolEl); + return; + } + + var newSymbolType = data.getItemVisual(newIdx, 'symbol') || 'circle'; + var oldSymbolType = symbolEl && symbolEl.getSymbolType && symbolEl.getSymbolType(); + + if (!symbolEl // Create a new if symbol type changed. + || oldSymbolType && oldSymbolType !== newSymbolType) { + group.remove(symbolEl); + symbolEl = new SymbolCtor(data, newIdx, seriesScope, symbolUpdateOpt); + symbolEl.setPosition(point); + } else { + symbolEl.updateData(data, newIdx, seriesScope, symbolUpdateOpt); + var target = { + x: point[0], + y: point[1] + }; + disableAnimation ? symbolEl.attr(target) : updateProps(symbolEl, target, seriesModel); + } // Add back + + + group.add(symbolEl); + data.setItemGraphicEl(newIdx, symbolEl); + }).remove(function (oldIdx) { + var el = oldData.getItemGraphicEl(oldIdx); + el && el.fadeOut(function () { + group.remove(el); + }, seriesModel); + }).execute(); + this._getSymbolPoint = getSymbolPoint; + this._data = data; + }; + + SymbolDraw.prototype.updateLayout = function () { + var _this = this; + + var data = this._data; + + if (data) { + // Not use animation + data.eachItemGraphicEl(function (el, idx) { + var point = _this._getSymbolPoint(idx); + + el.setPosition(point); + el.markRedraw(); + }); + } + }; + + SymbolDraw.prototype.incrementalPrepareUpdate = function (data) { + this._seriesScope = makeSeriesScope(data); + this._data = null; + this.group.removeAll(); + }; + /** + * Update symbols draw by new data + */ + + SymbolDraw.prototype.incrementalUpdate = function (taskParams, data, opt) { + // Clear + this._progressiveEls = []; + opt = normalizeUpdateOpt(opt); + + function updateIncrementalAndHover(el) { + if (!el.isGroup) { + el.incremental = true; + el.ensureState('emphasis').hoverLayer = true; + } + } + + for (var idx = taskParams.start; idx < taskParams.end; idx++) { + var point = data.getItemLayout(idx); + + if (symbolNeedsDraw(data, point, idx, opt)) { + var el = new this._SymbolCtor(data, idx, this._seriesScope); + el.traverse(updateIncrementalAndHover); + el.setPosition(point); + this.group.add(el); + data.setItemGraphicEl(idx, el); + + this._progressiveEls.push(el); + } + } + }; + + SymbolDraw.prototype.eachRendered = function (cb) { + traverseElements(this._progressiveEls || this.group, cb); + }; + + SymbolDraw.prototype.remove = function (enableAnimation) { + var group = this.group; + var data = this._data; // Incremental model do not have this._data. + + if (data && enableAnimation) { + data.eachItemGraphicEl(function (el) { + el.fadeOut(function () { + group.remove(el); + }, data.hostModel); + }); + } else { + group.removeAll(); + } + }; + return SymbolDraw; + }(); + + function prepareDataCoordInfo(coordSys, data, valueOrigin) { + var baseAxis = coordSys.getBaseAxis(); + var valueAxis = coordSys.getOtherAxis(baseAxis); + var valueStart = getValueStart(valueAxis, valueOrigin); + var baseAxisDim = baseAxis.dim; + var valueAxisDim = valueAxis.dim; + var valueDim = data.mapDimension(valueAxisDim); + var baseDim = data.mapDimension(baseAxisDim); + var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0; + var dims = map(coordSys.dimensions, function (coordDim) { + return data.mapDimension(coordDim); + }); + var stacked = false; + var stackResultDim = data.getCalculationInfo('stackResultDimension'); + + if (isDimensionStacked(data, dims[0] + /*, dims[1]*/ + )) { + // jshint ignore:line + stacked = true; + dims[0] = stackResultDim; + } + + if (isDimensionStacked(data, dims[1] + /*, dims[0]*/ + )) { + // jshint ignore:line + stacked = true; + dims[1] = stackResultDim; + } + + return { + dataDimsForPoint: dims, + valueStart: valueStart, + valueAxisDim: valueAxisDim, + baseAxisDim: baseAxisDim, + stacked: !!stacked, + valueDim: valueDim, + baseDim: baseDim, + baseDataOffset: baseDataOffset, + stackedOverDimension: data.getCalculationInfo('stackedOverDimension') + }; + } + + function getValueStart(valueAxis, valueOrigin) { + var valueStart = 0; + var extent = valueAxis.scale.getExtent(); + + if (valueOrigin === 'start') { + valueStart = extent[0]; + } else if (valueOrigin === 'end') { + valueStart = extent[1]; + } // If origin is specified as a number, use it as + // valueStart directly + else if (isNumber(valueOrigin) && !isNaN(valueOrigin)) { + valueStart = valueOrigin; + } // auto + else { + // Both positive + if (extent[0] > 0) { + valueStart = extent[0]; + } // Both negative + else if (extent[1] < 0) { + valueStart = extent[1]; + } // If is one positive, and one negative, onZero shall be true + + } + + return valueStart; + } + + function getStackedOnPoint(dataCoordInfo, coordSys, data, idx) { + var value = NaN; + + if (dataCoordInfo.stacked) { + value = data.get(data.getCalculationInfo('stackedOverDimension'), idx); + } + + if (isNaN(value)) { + value = dataCoordInfo.valueStart; + } + + var baseDataOffset = dataCoordInfo.baseDataOffset; + var stackedData = []; + stackedData[baseDataOffset] = data.get(dataCoordInfo.baseDim, idx); + stackedData[1 - baseDataOffset] = value; + return coordSys.dataToPoint(stackedData); + } + + function diffData(oldData, newData) { + var diffResult = []; + newData.diff(oldData).add(function (idx) { + diffResult.push({ + cmd: '+', + idx: idx + }); + }).update(function (newIdx, oldIdx) { + diffResult.push({ + cmd: '=', + idx: oldIdx, + idx1: newIdx + }); + }).remove(function (idx) { + diffResult.push({ + cmd: '-', + idx: idx + }); + }).execute(); + return diffResult; + } + + function lineAnimationDiff(oldData, newData, oldStackedOnPoints, newStackedOnPoints, oldCoordSys, newCoordSys, oldValueOrigin, newValueOrigin) { + var diff = diffData(oldData, newData); // let newIdList = newData.mapArray(newData.getId); + // let oldIdList = oldData.mapArray(oldData.getId); + // convertToIntId(newIdList, oldIdList); + // // FIXME One data ? + // diff = arrayDiff(oldIdList, newIdList); + + var currPoints = []; + var nextPoints = []; // Points for stacking base line + + var currStackedPoints = []; + var nextStackedPoints = []; + var status = []; + var sortedIndices = []; + var rawIndices = []; + var newDataOldCoordInfo = prepareDataCoordInfo(oldCoordSys, newData, oldValueOrigin); // const oldDataNewCoordInfo = prepareDataCoordInfo(newCoordSys, oldData, newValueOrigin); + + var oldPoints = oldData.getLayout('points') || []; + var newPoints = newData.getLayout('points') || []; + + for (var i = 0; i < diff.length; i++) { + var diffItem = diff[i]; + var pointAdded = true; + var oldIdx2 = void 0; + var newIdx2 = void 0; // FIXME, animation is not so perfect when dataZoom window moves fast + // Which is in case remvoing or add more than one data in the tail or head + + switch (diffItem.cmd) { + case '=': + oldIdx2 = diffItem.idx * 2; + newIdx2 = diffItem.idx1 * 2; + var currentX = oldPoints[oldIdx2]; + var currentY = oldPoints[oldIdx2 + 1]; + var nextX = newPoints[newIdx2]; + var nextY = newPoints[newIdx2 + 1]; // If previous data is NaN, use next point directly + + if (isNaN(currentX) || isNaN(currentY)) { + currentX = nextX; + currentY = nextY; + } + + currPoints.push(currentX, currentY); + nextPoints.push(nextX, nextY); + currStackedPoints.push(oldStackedOnPoints[oldIdx2], oldStackedOnPoints[oldIdx2 + 1]); + nextStackedPoints.push(newStackedOnPoints[newIdx2], newStackedOnPoints[newIdx2 + 1]); + rawIndices.push(newData.getRawIndex(diffItem.idx1)); + break; + + case '+': + var newIdx = diffItem.idx; + var newDataDimsForPoint = newDataOldCoordInfo.dataDimsForPoint; + var oldPt = oldCoordSys.dataToPoint([newData.get(newDataDimsForPoint[0], newIdx), newData.get(newDataDimsForPoint[1], newIdx)]); + newIdx2 = newIdx * 2; + currPoints.push(oldPt[0], oldPt[1]); + nextPoints.push(newPoints[newIdx2], newPoints[newIdx2 + 1]); + var stackedOnPoint = getStackedOnPoint(newDataOldCoordInfo, oldCoordSys, newData, newIdx); + currStackedPoints.push(stackedOnPoint[0], stackedOnPoint[1]); + nextStackedPoints.push(newStackedOnPoints[newIdx2], newStackedOnPoints[newIdx2 + 1]); + rawIndices.push(newData.getRawIndex(newIdx)); + break; + + case '-': + pointAdded = false; + } // Original indices + + + if (pointAdded) { + status.push(diffItem); + sortedIndices.push(sortedIndices.length); + } + } // Diff result may be crossed if all items are changed + // Sort by data index + + + sortedIndices.sort(function (a, b) { + return rawIndices[a] - rawIndices[b]; + }); + var len = currPoints.length; + var sortedCurrPoints = createFloat32Array(len); + var sortedNextPoints = createFloat32Array(len); + var sortedCurrStackedPoints = createFloat32Array(len); + var sortedNextStackedPoints = createFloat32Array(len); + var sortedStatus = []; + + for (var i = 0; i < sortedIndices.length; i++) { + var idx = sortedIndices[i]; + var i2 = i * 2; + var idx2 = idx * 2; + sortedCurrPoints[i2] = currPoints[idx2]; + sortedCurrPoints[i2 + 1] = currPoints[idx2 + 1]; + sortedNextPoints[i2] = nextPoints[idx2]; + sortedNextPoints[i2 + 1] = nextPoints[idx2 + 1]; + sortedCurrStackedPoints[i2] = currStackedPoints[idx2]; + sortedCurrStackedPoints[i2 + 1] = currStackedPoints[idx2 + 1]; + sortedNextStackedPoints[i2] = nextStackedPoints[idx2]; + sortedNextStackedPoints[i2 + 1] = nextStackedPoints[idx2 + 1]; + sortedStatus[i] = status[idx]; + } + + return { + current: sortedCurrPoints, + next: sortedNextPoints, + stackedOnCurrent: sortedCurrStackedPoints, + stackedOnNext: sortedNextStackedPoints, + status: sortedStatus + }; + } + + var mathMin$5 = Math.min; + var mathMax$5 = Math.max; + + function isPointNull(x, y) { + return isNaN(x) || isNaN(y); + } + /** + * Draw smoothed line in non-monotone, in may cause undesired curve in extreme + * situations. This should be used when points are non-monotone neither in x or + * y dimension. + */ + + + function drawSegment(ctx, points, start, segLen, allLen, dir, smooth, smoothMonotone, connectNulls) { + var prevX; + var prevY; + var cpx0; + var cpy0; + var cpx1; + var cpy1; + var idx = start; + var k = 0; + + for (; k < segLen; k++) { + var x = points[idx * 2]; + var y = points[idx * 2 + 1]; + + if (idx >= allLen || idx < 0) { + break; + } + + if (isPointNull(x, y)) { + if (connectNulls) { + idx += dir; + continue; + } + + break; + } + + if (idx === start) { + ctx[dir > 0 ? 'moveTo' : 'lineTo'](x, y); + cpx0 = x; + cpy0 = y; + } else { + var dx = x - prevX; + var dy = y - prevY; // Ignore tiny segment. + + if (dx * dx + dy * dy < 0.5) { + idx += dir; + continue; + } + + if (smooth > 0) { + var nextIdx = idx + dir; + var nextX = points[nextIdx * 2]; + var nextY = points[nextIdx * 2 + 1]; // Ignore duplicate point + + while (nextX === x && nextY === y && k < segLen) { + k++; + nextIdx += dir; + idx += dir; + nextX = points[nextIdx * 2]; + nextY = points[nextIdx * 2 + 1]; + x = points[idx * 2]; + y = points[idx * 2 + 1]; + dx = x - prevX; + dy = y - prevY; + } + + var tmpK = k + 1; + + if (connectNulls) { + // Find next point not null + while (isPointNull(nextX, nextY) && tmpK < segLen) { + tmpK++; + nextIdx += dir; + nextX = points[nextIdx * 2]; + nextY = points[nextIdx * 2 + 1]; + } + } + + var ratioNextSeg = 0.5; + var vx = 0; + var vy = 0; + var nextCpx0 = void 0; + var nextCpy0 = void 0; // Is last point + + if (tmpK >= segLen || isPointNull(nextX, nextY)) { + cpx1 = x; + cpy1 = y; + } else { + vx = nextX - prevX; + vy = nextY - prevY; + var dx0 = x - prevX; + var dx1 = nextX - x; + var dy0 = y - prevY; + var dy1 = nextY - y; + var lenPrevSeg = void 0; + var lenNextSeg = void 0; + + if (smoothMonotone === 'x') { + lenPrevSeg = Math.abs(dx0); + lenNextSeg = Math.abs(dx1); + var dir_1 = vx > 0 ? 1 : -1; + cpx1 = x - dir_1 * lenPrevSeg * smooth; + cpy1 = y; + nextCpx0 = x + dir_1 * lenNextSeg * smooth; + nextCpy0 = y; + } else if (smoothMonotone === 'y') { + lenPrevSeg = Math.abs(dy0); + lenNextSeg = Math.abs(dy1); + var dir_2 = vy > 0 ? 1 : -1; + cpx1 = x; + cpy1 = y - dir_2 * lenPrevSeg * smooth; + nextCpx0 = x; + nextCpy0 = y + dir_2 * lenNextSeg * smooth; + } else { + lenPrevSeg = Math.sqrt(dx0 * dx0 + dy0 * dy0); + lenNextSeg = Math.sqrt(dx1 * dx1 + dy1 * dy1); // Use ratio of seg length + + ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg); + cpx1 = x - vx * smooth * (1 - ratioNextSeg); + cpy1 = y - vy * smooth * (1 - ratioNextSeg); // cp0 of next segment + + nextCpx0 = x + vx * smooth * ratioNextSeg; + nextCpy0 = y + vy * smooth * ratioNextSeg; // Smooth constraint between point and next point. + // Avoid exceeding extreme after smoothing. + + nextCpx0 = mathMin$5(nextCpx0, mathMax$5(nextX, x)); + nextCpy0 = mathMin$5(nextCpy0, mathMax$5(nextY, y)); + nextCpx0 = mathMax$5(nextCpx0, mathMin$5(nextX, x)); + nextCpy0 = mathMax$5(nextCpy0, mathMin$5(nextY, y)); // Reclaculate cp1 based on the adjusted cp0 of next seg. + + vx = nextCpx0 - x; + vy = nextCpy0 - y; + cpx1 = x - vx * lenPrevSeg / lenNextSeg; + cpy1 = y - vy * lenPrevSeg / lenNextSeg; // Smooth constraint between point and prev point. + // Avoid exceeding extreme after smoothing. + + cpx1 = mathMin$5(cpx1, mathMax$5(prevX, x)); + cpy1 = mathMin$5(cpy1, mathMax$5(prevY, y)); + cpx1 = mathMax$5(cpx1, mathMin$5(prevX, x)); + cpy1 = mathMax$5(cpy1, mathMin$5(prevY, y)); // Adjust next cp0 again. + + vx = x - cpx1; + vy = y - cpy1; + nextCpx0 = x + vx * lenNextSeg / lenPrevSeg; + nextCpy0 = y + vy * lenNextSeg / lenPrevSeg; + } + } + + ctx.bezierCurveTo(cpx0, cpy0, cpx1, cpy1, x, y); + cpx0 = nextCpx0; + cpy0 = nextCpy0; + } else { + ctx.lineTo(x, y); + } + } + + prevX = x; + prevY = y; + idx += dir; + } + + return k; + } + + var ECPolylineShape = + /** @class */ + function () { + function ECPolylineShape() { + this.smooth = 0; + this.smoothConstraint = true; + } + + return ECPolylineShape; + }(); + + var ECPolyline = + /** @class */ + function (_super) { + __extends(ECPolyline, _super); + + function ECPolyline(opts) { + var _this = _super.call(this, opts) || this; + + _this.type = 'ec-polyline'; + return _this; + } + + ECPolyline.prototype.getDefaultStyle = function () { + return { + stroke: '#000', + fill: null + }; + }; + + ECPolyline.prototype.getDefaultShape = function () { + return new ECPolylineShape(); + }; + + ECPolyline.prototype.buildPath = function (ctx, shape) { + var points = shape.points; + var i = 0; + var len = points.length / 2; // const result = getBoundingBox(points, shape.smoothConstraint); + + if (shape.connectNulls) { + // Must remove first and last null values avoid draw error in polygon + for (; len > 0; len--) { + if (!isPointNull(points[len * 2 - 2], points[len * 2 - 1])) { + break; + } + } + + for (; i < len; i++) { + if (!isPointNull(points[i * 2], points[i * 2 + 1])) { + break; + } + } + } + + while (i < len) { + i += drawSegment(ctx, points, i, len, len, 1, shape.smooth, shape.smoothMonotone, shape.connectNulls) + 1; + } + }; + + ECPolyline.prototype.getPointOn = function (xOrY, dim) { + if (!this.path) { + this.createPathProxy(); + this.buildPath(this.path, this.shape); + } + + var path = this.path; + var data = path.data; + var CMD = PathProxy.CMD; + var x0; + var y0; + var isDimX = dim === 'x'; + var roots = []; + + for (var i = 0; i < data.length;) { + var cmd = data[i++]; + var x = void 0; + var y = void 0; + var x2 = void 0; + var y2 = void 0; + var x3 = void 0; + var y3 = void 0; + var t = void 0; + + switch (cmd) { + case CMD.M: + x0 = data[i++]; + y0 = data[i++]; + break; + + case CMD.L: + x = data[i++]; + y = data[i++]; + t = isDimX ? (xOrY - x0) / (x - x0) : (xOrY - y0) / (y - y0); + + if (t <= 1 && t >= 0) { + var val = isDimX ? (y - y0) * t + y0 : (x - x0) * t + x0; + return isDimX ? [xOrY, val] : [val, xOrY]; + } + + x0 = x; + y0 = y; + break; + + case CMD.C: + x = data[i++]; + y = data[i++]; + x2 = data[i++]; + y2 = data[i++]; + x3 = data[i++]; + y3 = data[i++]; + var nRoot = isDimX ? cubicRootAt(x0, x, x2, x3, xOrY, roots) : cubicRootAt(y0, y, y2, y3, xOrY, roots); + + if (nRoot > 0) { + for (var i_1 = 0; i_1 < nRoot; i_1++) { + var t_1 = roots[i_1]; + + if (t_1 <= 1 && t_1 >= 0) { + var val = isDimX ? cubicAt(y0, y, y2, y3, t_1) : cubicAt(x0, x, x2, x3, t_1); + return isDimX ? [xOrY, val] : [val, xOrY]; + } + } + } + + x0 = x3; + y0 = y3; + break; + } + } + }; + + return ECPolyline; + }(Path); + + var ECPolygonShape = + /** @class */ + function (_super) { + __extends(ECPolygonShape, _super); + + function ECPolygonShape() { + return _super !== null && _super.apply(this, arguments) || this; + } + + return ECPolygonShape; + }(ECPolylineShape); + + var ECPolygon = + /** @class */ + function (_super) { + __extends(ECPolygon, _super); + + function ECPolygon(opts) { + var _this = _super.call(this, opts) || this; + + _this.type = 'ec-polygon'; + return _this; + } + + ECPolygon.prototype.getDefaultShape = function () { + return new ECPolygonShape(); + }; + + ECPolygon.prototype.buildPath = function (ctx, shape) { + var points = shape.points; + var stackedOnPoints = shape.stackedOnPoints; + var i = 0; + var len = points.length / 2; + var smoothMonotone = shape.smoothMonotone; + + if (shape.connectNulls) { + // Must remove first and last null values avoid draw error in polygon + for (; len > 0; len--) { + if (!isPointNull(points[len * 2 - 2], points[len * 2 - 1])) { + break; + } + } + + for (; i < len; i++) { + if (!isPointNull(points[i * 2], points[i * 2 + 1])) { + break; + } + } + } + + while (i < len) { + var k = drawSegment(ctx, points, i, len, len, 1, shape.smooth, smoothMonotone, shape.connectNulls); + drawSegment(ctx, stackedOnPoints, i + k - 1, k, len, -1, shape.stackedOnSmooth, smoothMonotone, shape.connectNulls); + i += k + 1; + ctx.closePath(); + } + }; + + return ECPolygon; + }(Path); + + function createGridClipPath(cartesian, hasAnimation, seriesModel, done, during) { + var rect = cartesian.getArea(); + var x = rect.x; + var y = rect.y; + var width = rect.width; + var height = rect.height; + var lineWidth = seriesModel.get(['lineStyle', 'width']) || 2; // Expand the clip path a bit to avoid the border is clipped and looks thinner + + x -= lineWidth / 2; + y -= lineWidth / 2; + width += lineWidth; + height += lineWidth; // fix: https://github.com/apache/incubator-echarts/issues/11369 + + x = Math.floor(x); + width = Math.round(width); + var clipPath = new Rect({ + shape: { + x: x, + y: y, + width: width, + height: height + } + }); + + if (hasAnimation) { + var baseAxis = cartesian.getBaseAxis(); + var isHorizontal = baseAxis.isHorizontal(); + var isAxisInversed = baseAxis.inverse; + + if (isHorizontal) { + if (isAxisInversed) { + clipPath.shape.x += width; + } + + clipPath.shape.width = 0; + } else { + if (!isAxisInversed) { + clipPath.shape.y += height; + } + + clipPath.shape.height = 0; + } + + var duringCb = isFunction(during) ? function (percent) { + during(percent, clipPath); + } : null; + initProps(clipPath, { + shape: { + width: width, + height: height, + x: x, + y: y + } + }, seriesModel, null, done, duringCb); + } + + return clipPath; + } + + function createPolarClipPath(polar, hasAnimation, seriesModel) { + var sectorArea = polar.getArea(); // Avoid float number rounding error for symbol on the edge of axis extent. + + var r0 = round(sectorArea.r0, 1); + var r = round(sectorArea.r, 1); + var clipPath = new Sector({ + shape: { + cx: round(polar.cx, 1), + cy: round(polar.cy, 1), + r0: r0, + r: r, + startAngle: sectorArea.startAngle, + endAngle: sectorArea.endAngle, + clockwise: sectorArea.clockwise + } + }); + + if (hasAnimation) { + var isRadial = polar.getBaseAxis().dim === 'angle'; + + if (isRadial) { + clipPath.shape.endAngle = sectorArea.startAngle; + } else { + clipPath.shape.r = r0; + } + + initProps(clipPath, { + shape: { + endAngle: sectorArea.endAngle, + r: r + } + }, seriesModel); + } + + return clipPath; + } + + function createClipPath(coordSys, hasAnimation, seriesModel, done, during) { + if (!coordSys) { + return null; + } else if (coordSys.type === 'polar') { + return createPolarClipPath(coordSys, hasAnimation, seriesModel); + } else if (coordSys.type === 'cartesian2d') { + return createGridClipPath(coordSys, hasAnimation, seriesModel, done, during); + } + + return null; + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + function isCoordinateSystemType(coordSys, type) { + return coordSys.type === type; + } + + function isPointsSame(points1, points2) { + if (points1.length !== points2.length) { + return; + } + + for (var i = 0; i < points1.length; i++) { + if (points1[i] !== points2[i]) { + return; + } + } + + return true; + } + + function bboxFromPoints(points) { + var minX = Infinity; + var minY = Infinity; + var maxX = -Infinity; + var maxY = -Infinity; + + for (var i = 0; i < points.length;) { + var x = points[i++]; + var y = points[i++]; + + if (!isNaN(x)) { + minX = Math.min(x, minX); + maxX = Math.max(x, maxX); + } + + if (!isNaN(y)) { + minY = Math.min(y, minY); + maxY = Math.max(y, maxY); + } + } + + return [[minX, minY], [maxX, maxY]]; + } + + function getBoundingDiff(points1, points2) { + var _a = bboxFromPoints(points1), + min1 = _a[0], + max1 = _a[1]; + + var _b = bboxFromPoints(points2), + min2 = _b[0], + max2 = _b[1]; // Get a max value from each corner of two boundings. + + + return Math.max(Math.abs(min1[0] - min2[0]), Math.abs(min1[1] - min2[1]), Math.abs(max1[0] - max2[0]), Math.abs(max1[1] - max2[1])); + } + + function getSmooth(smooth) { + return isNumber(smooth) ? smooth : smooth ? 0.5 : 0; + } + + function getStackedOnPoints(coordSys, data, dataCoordInfo) { + if (!dataCoordInfo.valueDim) { + return []; + } + + var len = data.count(); + var points = createFloat32Array(len * 2); + + for (var idx = 0; idx < len; idx++) { + var pt = getStackedOnPoint(dataCoordInfo, coordSys, data, idx); + points[idx * 2] = pt[0]; + points[idx * 2 + 1] = pt[1]; + } + + return points; + } + + function turnPointsIntoStep(points, coordSys, stepTurnAt, connectNulls) { + var baseAxis = coordSys.getBaseAxis(); + var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1; + var stepPoints = []; + var i = 0; + var stepPt = []; + var pt = []; + var nextPt = []; + var filteredPoints = []; + + if (connectNulls) { + for (i = 0; i < points.length; i += 2) { + if (!isNaN(points[i]) && !isNaN(points[i + 1])) { + filteredPoints.push(points[i], points[i + 1]); + } + } + + points = filteredPoints; + } + + for (i = 0; i < points.length - 2; i += 2) { + nextPt[0] = points[i + 2]; + nextPt[1] = points[i + 3]; + pt[0] = points[i]; + pt[1] = points[i + 1]; + stepPoints.push(pt[0], pt[1]); + + switch (stepTurnAt) { + case 'end': + stepPt[baseIndex] = nextPt[baseIndex]; + stepPt[1 - baseIndex] = pt[1 - baseIndex]; + stepPoints.push(stepPt[0], stepPt[1]); + break; + + case 'middle': + var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2; + var stepPt2 = []; + stepPt[baseIndex] = stepPt2[baseIndex] = middle; + stepPt[1 - baseIndex] = pt[1 - baseIndex]; + stepPt2[1 - baseIndex] = nextPt[1 - baseIndex]; + stepPoints.push(stepPt[0], stepPt[1]); + stepPoints.push(stepPt2[0], stepPt2[1]); + break; + + default: + // default is start + stepPt[baseIndex] = pt[baseIndex]; + stepPt[1 - baseIndex] = nextPt[1 - baseIndex]; + stepPoints.push(stepPt[0], stepPt[1]); + } + } // Last points + + + stepPoints.push(points[i++], points[i++]); + return stepPoints; + } + /** + * Clip color stops to edge. Avoid creating too large gradients. + * Which may lead to blurry when GPU acceleration is enabled. See #15680 + * + * The stops has been sorted from small to large. + */ + + + function clipColorStops(colorStops, maxSize) { + var newColorStops = []; + var len = colorStops.length; // coord will always < 0 in prevOutOfRangeColorStop. + + var prevOutOfRangeColorStop; + var prevInRangeColorStop; + + function lerpStop(stop0, stop1, clippedCoord) { + var coord0 = stop0.coord; + var p = (clippedCoord - coord0) / (stop1.coord - coord0); + var color = lerp$1(p, [stop0.color, stop1.color]); + return { + coord: clippedCoord, + color: color + }; + } + + for (var i = 0; i < len; i++) { + var stop_1 = colorStops[i]; + var coord = stop_1.coord; + + if (coord < 0) { + prevOutOfRangeColorStop = stop_1; + } else if (coord > maxSize) { + if (prevInRangeColorStop) { + newColorStops.push(lerpStop(prevInRangeColorStop, stop_1, maxSize)); + } else if (prevOutOfRangeColorStop) { + // If there are two stops and coord range is between these two stops + newColorStops.push(lerpStop(prevOutOfRangeColorStop, stop_1, 0), lerpStop(prevOutOfRangeColorStop, stop_1, maxSize)); + } // All following stop will be out of range. So just ignore them. + + + break; + } else { + if (prevOutOfRangeColorStop) { + newColorStops.push(lerpStop(prevOutOfRangeColorStop, stop_1, 0)); // Reset + + prevOutOfRangeColorStop = null; + } + + newColorStops.push(stop_1); + prevInRangeColorStop = stop_1; + } + } + + return newColorStops; + } + + function getVisualGradient(data, coordSys, api) { + var visualMetaList = data.getVisual('visualMeta'); + + if (!visualMetaList || !visualMetaList.length || !data.count()) { + // When data.count() is 0, gradient range can not be calculated. + return; + } + + if (coordSys.type !== 'cartesian2d') { + if ("development" !== 'production') { + console.warn('Visual map on line style is only supported on cartesian2d.'); + } + + return; + } + + var coordDim; + var visualMeta; + + for (var i = visualMetaList.length - 1; i >= 0; i--) { + var dimInfo = data.getDimensionInfo(visualMetaList[i].dimension); + coordDim = dimInfo && dimInfo.coordDim; // Can only be x or y + + if (coordDim === 'x' || coordDim === 'y') { + visualMeta = visualMetaList[i]; + break; + } + } + + if (!visualMeta) { + if ("development" !== 'production') { + console.warn('Visual map on line style only support x or y dimension.'); + } + + return; + } // If the area to be rendered is bigger than area defined by LinearGradient, + // the canvas spec prescribes that the color of the first stop and the last + // stop should be used. But if two stops are added at offset 0, in effect + // browsers use the color of the second stop to render area outside + // LinearGradient. So we can only infinitesimally extend area defined in + // LinearGradient to render `outerColors`. + + + var axis = coordSys.getAxis(coordDim); // dataToCoord mapping may not be linear, but must be monotonic. + + var colorStops = map(visualMeta.stops, function (stop) { + // offset will be calculated later. + return { + coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)), + color: stop.color + }; + }); + var stopLen = colorStops.length; + var outerColors = visualMeta.outerColors.slice(); + + if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) { + colorStops.reverse(); + outerColors.reverse(); + } + + var colorStopsInRange = clipColorStops(colorStops, coordDim === 'x' ? api.getWidth() : api.getHeight()); + var inRangeStopLen = colorStopsInRange.length; + + if (!inRangeStopLen && stopLen) { + // All stops are out of range. All will be the same color. + return colorStops[0].coord < 0 ? outerColors[1] ? outerColors[1] : colorStops[stopLen - 1].color : outerColors[0] ? outerColors[0] : colorStops[0].color; + } + + var tinyExtent = 10; // Arbitrary value: 10px + + var minCoord = colorStopsInRange[0].coord - tinyExtent; + var maxCoord = colorStopsInRange[inRangeStopLen - 1].coord + tinyExtent; + var coordSpan = maxCoord - minCoord; + + if (coordSpan < 1e-3) { + return 'transparent'; + } + + each(colorStopsInRange, function (stop) { + stop.offset = (stop.coord - minCoord) / coordSpan; + }); + colorStopsInRange.push({ + // NOTE: inRangeStopLen may still be 0 if stoplen is zero. + offset: inRangeStopLen ? colorStopsInRange[inRangeStopLen - 1].offset : 0.5, + color: outerColors[1] || 'transparent' + }); + colorStopsInRange.unshift({ + offset: inRangeStopLen ? colorStopsInRange[0].offset : 0.5, + color: outerColors[0] || 'transparent' + }); + var gradient = new LinearGradient(0, 0, 0, 0, colorStopsInRange, true); + gradient[coordDim] = minCoord; + gradient[coordDim + '2'] = maxCoord; + return gradient; + } + + function getIsIgnoreFunc(seriesModel, data, coordSys) { + var showAllSymbol = seriesModel.get('showAllSymbol'); + var isAuto = showAllSymbol === 'auto'; + + if (showAllSymbol && !isAuto) { + return; + } + + var categoryAxis = coordSys.getAxesByScale('ordinal')[0]; + + if (!categoryAxis) { + return; + } // Note that category label interval strategy might bring some weird effect + // in some scenario: users may wonder why some of the symbols are not + // displayed. So we show all symbols as possible as we can. + + + if (isAuto // Simplify the logic, do not determine label overlap here. + && canShowAllSymbolForCategory(categoryAxis, data)) { + return; + } // Otherwise follow the label interval strategy on category axis. + + + var categoryDataDim = data.mapDimension(categoryAxis.dim); + var labelMap = {}; + each(categoryAxis.getViewLabels(), function (labelItem) { + var ordinalNumber = categoryAxis.scale.getRawOrdinalNumber(labelItem.tickValue); + labelMap[ordinalNumber] = 1; + }); + return function (dataIndex) { + return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex)); + }; + } + + function canShowAllSymbolForCategory(categoryAxis, data) { + // In mose cases, line is monotonous on category axis, and the label size + // is close with each other. So we check the symbol size and some of the + // label size alone with the category axis to estimate whether all symbol + // can be shown without overlap. + var axisExtent = categoryAxis.getExtent(); + var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count(); + isNaN(availSize) && (availSize = 0); // 0/0 is NaN. + // Sampling some points, max 5. + + var dataLen = data.count(); + var step = Math.max(1, Math.round(dataLen / 5)); + + for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) { + if (Symbol.getSymbolSize(data, dataIndex // Only for cartesian, where `isHorizontal` exists. + )[categoryAxis.isHorizontal() ? 1 : 0] // Empirical number + * 1.5 > availSize) { + return false; + } + } + + return true; + } + + function isPointNull$1(x, y) { + return isNaN(x) || isNaN(y); + } + + function getLastIndexNotNull(points) { + var len = points.length / 2; + + for (; len > 0; len--) { + if (!isPointNull$1(points[len * 2 - 2], points[len * 2 - 1])) { + break; + } + } + + return len - 1; + } + + function getPointAtIndex(points, idx) { + return [points[idx * 2], points[idx * 2 + 1]]; + } + + function getIndexRange(points, xOrY, dim) { + var len = points.length / 2; + var dimIdx = dim === 'x' ? 0 : 1; + var a; + var b; + var prevIndex = 0; + var nextIndex = -1; + + for (var i = 0; i < len; i++) { + b = points[i * 2 + dimIdx]; + + if (isNaN(b) || isNaN(points[i * 2 + 1 - dimIdx])) { + continue; + } + + if (i === 0) { + a = b; + continue; + } + + if (a <= xOrY && b >= xOrY || a >= xOrY && b <= xOrY) { + nextIndex = i; + break; + } + + prevIndex = i; + a = b; + } + + return { + range: [prevIndex, nextIndex], + t: (xOrY - a) / (b - a) + }; + } + + function anyStateShowEndLabel(seriesModel) { + if (seriesModel.get(['endLabel', 'show'])) { + return true; + } + + for (var i = 0; i < SPECIAL_STATES.length; i++) { + if (seriesModel.get([SPECIAL_STATES[i], 'endLabel', 'show'])) { + return true; + } + } + + return false; + } + + function createLineClipPath(lineView, coordSys, hasAnimation, seriesModel) { + if (isCoordinateSystemType(coordSys, 'cartesian2d')) { + var endLabelModel_1 = seriesModel.getModel('endLabel'); + var valueAnimation_1 = endLabelModel_1.get('valueAnimation'); + var data_1 = seriesModel.getData(); + var labelAnimationRecord_1 = { + lastFrameIndex: 0 + }; + var during = anyStateShowEndLabel(seriesModel) ? function (percent, clipRect) { + lineView._endLabelOnDuring(percent, clipRect, data_1, labelAnimationRecord_1, valueAnimation_1, endLabelModel_1, coordSys); + } : null; + var isHorizontal = coordSys.getBaseAxis().isHorizontal(); + var clipPath = createGridClipPath(coordSys, hasAnimation, seriesModel, function () { + var endLabel = lineView._endLabel; + + if (endLabel && hasAnimation) { + if (labelAnimationRecord_1.originalX != null) { + endLabel.attr({ + x: labelAnimationRecord_1.originalX, + y: labelAnimationRecord_1.originalY + }); + } + } + }, during); // Expand clip shape to avoid clipping when line value exceeds axis + + if (!seriesModel.get('clip', true)) { + var rectShape = clipPath.shape; + var expandSize = Math.max(rectShape.width, rectShape.height); + + if (isHorizontal) { + rectShape.y -= expandSize; + rectShape.height += expandSize * 2; + } else { + rectShape.x -= expandSize; + rectShape.width += expandSize * 2; + } + } // Set to the final frame. To make sure label layout is right. + + + if (during) { + during(1, clipPath); + } + + return clipPath; + } else { + if ("development" !== 'production') { + if (seriesModel.get(['endLabel', 'show'])) { + console.warn('endLabel is not supported for lines in polar systems.'); + } + } + + return createPolarClipPath(coordSys, hasAnimation, seriesModel); + } + } + + function getEndLabelStateSpecified(endLabelModel, coordSys) { + var baseAxis = coordSys.getBaseAxis(); + var isHorizontal = baseAxis.isHorizontal(); + var isBaseInversed = baseAxis.inverse; + var align = isHorizontal ? isBaseInversed ? 'right' : 'left' : 'center'; + var verticalAlign = isHorizontal ? 'middle' : isBaseInversed ? 'top' : 'bottom'; + return { + normal: { + align: endLabelModel.get('align') || align, + verticalAlign: endLabelModel.get('verticalAlign') || verticalAlign + } + }; + } + + var LineView = + /** @class */ + function (_super) { + __extends(LineView, _super); + + function LineView() { + return _super !== null && _super.apply(this, arguments) || this; + } + + LineView.prototype.init = function () { + var lineGroup = new Group(); + var symbolDraw = new SymbolDraw(); + this.group.add(symbolDraw.group); + this._symbolDraw = symbolDraw; + this._lineGroup = lineGroup; + }; + + LineView.prototype.render = function (seriesModel, ecModel, api) { + var _this = this; + + var coordSys = seriesModel.coordinateSystem; + var group = this.group; + var data = seriesModel.getData(); + var lineStyleModel = seriesModel.getModel('lineStyle'); + var areaStyleModel = seriesModel.getModel('areaStyle'); + var points = data.getLayout('points') || []; + var isCoordSysPolar = coordSys.type === 'polar'; + var prevCoordSys = this._coordSys; + var symbolDraw = this._symbolDraw; + var polyline = this._polyline; + var polygon = this._polygon; + var lineGroup = this._lineGroup; + var hasAnimation = seriesModel.get('animation'); + var isAreaChart = !areaStyleModel.isEmpty(); + var valueOrigin = areaStyleModel.get('origin'); + var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin); + var stackedOnPoints = isAreaChart && getStackedOnPoints(coordSys, data, dataCoordInfo); + var showSymbol = seriesModel.get('showSymbol'); + var connectNulls = seriesModel.get('connectNulls'); + var isIgnoreFunc = showSymbol && !isCoordSysPolar && getIsIgnoreFunc(seriesModel, data, coordSys); // Remove temporary symbols + + var oldData = this._data; + oldData && oldData.eachItemGraphicEl(function (el, idx) { + if (el.__temp) { + group.remove(el); + oldData.setItemGraphicEl(idx, null); + } + }); // Remove previous created symbols if showSymbol changed to false + + if (!showSymbol) { + symbolDraw.remove(); + } + + group.add(lineGroup); // FIXME step not support polar + + var step = !isCoordSysPolar ? seriesModel.get('step') : false; + var clipShapeForSymbol; + + if (coordSys && coordSys.getArea && seriesModel.get('clip', true)) { + clipShapeForSymbol = coordSys.getArea(); // Avoid float number rounding error for symbol on the edge of axis extent. + // See #7913 and `test/dataZoom-clip.html`. + + if (clipShapeForSymbol.width != null) { + clipShapeForSymbol.x -= 0.1; + clipShapeForSymbol.y -= 0.1; + clipShapeForSymbol.width += 0.2; + clipShapeForSymbol.height += 0.2; + } else if (clipShapeForSymbol.r0) { + clipShapeForSymbol.r0 -= 0.5; + clipShapeForSymbol.r += 0.5; + } + } + + this._clipShapeForSymbol = clipShapeForSymbol; + var visualColor = getVisualGradient(data, coordSys, api) || data.getVisual('style')[data.getVisual('drawType')]; // Initialization animation or coordinate system changed + + if (!(polyline && prevCoordSys.type === coordSys.type && step === this._step)) { + showSymbol && symbolDraw.updateData(data, { + isIgnore: isIgnoreFunc, + clipShape: clipShapeForSymbol, + disableAnimation: true, + getSymbolPoint: function (idx) { + return [points[idx * 2], points[idx * 2 + 1]]; + } + }); + hasAnimation && this._initSymbolLabelAnimation(data, coordSys, clipShapeForSymbol); + + if (step) { + // TODO If stacked series is not step + points = turnPointsIntoStep(points, coordSys, step, connectNulls); + + if (stackedOnPoints) { + stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step, connectNulls); + } + } + + polyline = this._newPolyline(points); + + if (isAreaChart) { + polygon = this._newPolygon(points, stackedOnPoints); + } // NOTE: Must update _endLabel before setClipPath. + + + if (!isCoordSysPolar) { + this._initOrUpdateEndLabel(seriesModel, coordSys, convertToColorString(visualColor)); + } + + lineGroup.setClipPath(createLineClipPath(this, coordSys, true, seriesModel)); + } else { + if (isAreaChart && !polygon) { + // If areaStyle is added + polygon = this._newPolygon(points, stackedOnPoints); + } else if (polygon && !isAreaChart) { + // If areaStyle is removed + lineGroup.remove(polygon); + polygon = this._polygon = null; + } // NOTE: Must update _endLabel before setClipPath. + + + if (!isCoordSysPolar) { + this._initOrUpdateEndLabel(seriesModel, coordSys, convertToColorString(visualColor)); + } // Update clipPath + + + var oldClipPath = lineGroup.getClipPath(); + + if (oldClipPath) { + var newClipPath = createLineClipPath(this, coordSys, false, seriesModel); + initProps(oldClipPath, { + shape: newClipPath.shape + }, seriesModel); + } else { + lineGroup.setClipPath(createLineClipPath(this, coordSys, true, seriesModel)); + } // Always update, or it is wrong in the case turning on legend + // because points are not changed + + + showSymbol && symbolDraw.updateData(data, { + isIgnore: isIgnoreFunc, + clipShape: clipShapeForSymbol, + disableAnimation: true, + getSymbolPoint: function (idx) { + return [points[idx * 2], points[idx * 2 + 1]]; + } + }); // In the case data zoom triggerred refreshing frequently + // Data may not change if line has a category axis. So it should animate nothing + + if (!isPointsSame(this._stackedOnPoints, stackedOnPoints) || !isPointsSame(this._points, points)) { + if (hasAnimation) { + this._doUpdateAnimation(data, stackedOnPoints, coordSys, api, step, valueOrigin, connectNulls); + } else { + // Not do it in update with animation + if (step) { + // TODO If stacked series is not step + points = turnPointsIntoStep(points, coordSys, step, connectNulls); + + if (stackedOnPoints) { + stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step, connectNulls); + } + } + + polyline.setShape({ + points: points + }); + polygon && polygon.setShape({ + points: points, + stackedOnPoints: stackedOnPoints + }); + } + } + } + + var emphasisModel = seriesModel.getModel('emphasis'); + var focus = emphasisModel.get('focus'); + var blurScope = emphasisModel.get('blurScope'); + var emphasisDisabled = emphasisModel.get('disabled'); + polyline.useStyle(defaults( // Use color in lineStyle first + lineStyleModel.getLineStyle(), { + fill: 'none', + stroke: visualColor, + lineJoin: 'bevel' + })); + setStatesStylesFromModel(polyline, seriesModel, 'lineStyle'); + + if (polyline.style.lineWidth > 0 && seriesModel.get(['emphasis', 'lineStyle', 'width']) === 'bolder') { + var emphasisLineStyle = polyline.getState('emphasis').style; + emphasisLineStyle.lineWidth = +polyline.style.lineWidth + 1; + } // Needs seriesIndex for focus + + + getECData(polyline).seriesIndex = seriesModel.seriesIndex; + toggleHoverEmphasis(polyline, focus, blurScope, emphasisDisabled); + var smooth = getSmooth(seriesModel.get('smooth')); + var smoothMonotone = seriesModel.get('smoothMonotone'); + polyline.setShape({ + smooth: smooth, + smoothMonotone: smoothMonotone, + connectNulls: connectNulls + }); + + if (polygon) { + var stackedOnSeries = data.getCalculationInfo('stackedOnSeries'); + var stackedOnSmooth = 0; + polygon.useStyle(defaults(areaStyleModel.getAreaStyle(), { + fill: visualColor, + opacity: 0.7, + lineJoin: 'bevel', + decal: data.getVisual('style').decal + })); + + if (stackedOnSeries) { + stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth')); + } + + polygon.setShape({ + smooth: smooth, + stackedOnSmooth: stackedOnSmooth, + smoothMonotone: smoothMonotone, + connectNulls: connectNulls + }); + setStatesStylesFromModel(polygon, seriesModel, 'areaStyle'); // Needs seriesIndex for focus + + getECData(polygon).seriesIndex = seriesModel.seriesIndex; + toggleHoverEmphasis(polygon, focus, blurScope, emphasisDisabled); + } + + var changePolyState = function (toState) { + _this._changePolyState(toState); + }; + + data.eachItemGraphicEl(function (el) { + // Switch polyline / polygon state if element changed its state. + el && (el.onHoverStateChange = changePolyState); + }); + this._polyline.onHoverStateChange = changePolyState; + this._data = data; // Save the coordinate system for transition animation when data changed + + this._coordSys = coordSys; + this._stackedOnPoints = stackedOnPoints; + this._points = points; + this._step = step; + this._valueOrigin = valueOrigin; + + if (seriesModel.get('triggerLineEvent')) { + this.packEventData(seriesModel, polyline); + polygon && this.packEventData(seriesModel, polygon); + } + }; + + LineView.prototype.packEventData = function (seriesModel, el) { + getECData(el).eventData = { + componentType: 'series', + componentSubType: 'line', + componentIndex: seriesModel.componentIndex, + seriesIndex: seriesModel.seriesIndex, + seriesName: seriesModel.name, + seriesType: 'line' + }; + }; + + LineView.prototype.highlight = function (seriesModel, ecModel, api, payload) { + var data = seriesModel.getData(); + var dataIndex = queryDataIndex(data, payload); + + this._changePolyState('emphasis'); + + if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) { + var points = data.getLayout('points'); + var symbol = data.getItemGraphicEl(dataIndex); + + if (!symbol) { + // Create a temporary symbol if it is not exists + var x = points[dataIndex * 2]; + var y = points[dataIndex * 2 + 1]; + + if (isNaN(x) || isNaN(y)) { + // Null data + return; + } // fix #11360: should't draw symbol outside clipShapeForSymbol + + + if (this._clipShapeForSymbol && !this._clipShapeForSymbol.contain(x, y)) { + return; + } + + var zlevel = seriesModel.get('zlevel'); + var z = seriesModel.get('z'); + symbol = new Symbol(data, dataIndex); + symbol.x = x; + symbol.y = y; + symbol.setZ(zlevel, z); // ensure label text of the temporary symbol is in front of line and area polygon + + var symbolLabel = symbol.getSymbolPath().getTextContent(); + + if (symbolLabel) { + symbolLabel.zlevel = zlevel; + symbolLabel.z = z; + symbolLabel.z2 = this._polyline.z2 + 1; + } + + symbol.__temp = true; + data.setItemGraphicEl(dataIndex, symbol); // Stop scale animation + + symbol.stopSymbolAnimation(true); + this.group.add(symbol); + } + + symbol.highlight(); + } else { + // Highlight whole series + ChartView.prototype.highlight.call(this, seriesModel, ecModel, api, payload); + } + }; + + LineView.prototype.downplay = function (seriesModel, ecModel, api, payload) { + var data = seriesModel.getData(); + var dataIndex = queryDataIndex(data, payload); + + this._changePolyState('normal'); + + if (dataIndex != null && dataIndex >= 0) { + var symbol = data.getItemGraphicEl(dataIndex); + + if (symbol) { + if (symbol.__temp) { + data.setItemGraphicEl(dataIndex, null); + this.group.remove(symbol); + } else { + symbol.downplay(); + } + } + } else { + // FIXME + // can not downplay completely. + // Downplay whole series + ChartView.prototype.downplay.call(this, seriesModel, ecModel, api, payload); + } + }; + + LineView.prototype._changePolyState = function (toState) { + var polygon = this._polygon; + setStatesFlag(this._polyline, toState); + polygon && setStatesFlag(polygon, toState); + }; + + LineView.prototype._newPolyline = function (points) { + var polyline = this._polyline; // Remove previous created polyline + + if (polyline) { + this._lineGroup.remove(polyline); + } + + polyline = new ECPolyline({ + shape: { + points: points + }, + segmentIgnoreThreshold: 2, + z2: 10 + }); + + this._lineGroup.add(polyline); + + this._polyline = polyline; + return polyline; + }; + + LineView.prototype._newPolygon = function (points, stackedOnPoints) { + var polygon = this._polygon; // Remove previous created polygon + + if (polygon) { + this._lineGroup.remove(polygon); + } + + polygon = new ECPolygon({ + shape: { + points: points, + stackedOnPoints: stackedOnPoints + }, + segmentIgnoreThreshold: 2 + }); + + this._lineGroup.add(polygon); + + this._polygon = polygon; + return polygon; + }; + + LineView.prototype._initSymbolLabelAnimation = function (data, coordSys, clipShape) { + var isHorizontalOrRadial; + var isCoordSysPolar; + var baseAxis = coordSys.getBaseAxis(); + var isAxisInverse = baseAxis.inverse; + + if (coordSys.type === 'cartesian2d') { + isHorizontalOrRadial = baseAxis.isHorizontal(); + isCoordSysPolar = false; + } else if (coordSys.type === 'polar') { + isHorizontalOrRadial = baseAxis.dim === 'angle'; + isCoordSysPolar = true; + } + + var seriesModel = data.hostModel; + var seriesDuration = seriesModel.get('animationDuration'); + + if (isFunction(seriesDuration)) { + seriesDuration = seriesDuration(null); + } + + var seriesDalay = seriesModel.get('animationDelay') || 0; + var seriesDalayValue = isFunction(seriesDalay) ? seriesDalay(null) : seriesDalay; + data.eachItemGraphicEl(function (symbol, idx) { + var el = symbol; + + if (el) { + var point = [symbol.x, symbol.y]; + var start = void 0; + var end = void 0; + var current = void 0; + + if (clipShape) { + if (isCoordSysPolar) { + var polarClip = clipShape; + var coord = coordSys.pointToCoord(point); + + if (isHorizontalOrRadial) { + start = polarClip.startAngle; + end = polarClip.endAngle; + current = -coord[1] / 180 * Math.PI; + } else { + start = polarClip.r0; + end = polarClip.r; + current = coord[0]; + } + } else { + var gridClip = clipShape; + + if (isHorizontalOrRadial) { + start = gridClip.x; + end = gridClip.x + gridClip.width; + current = symbol.x; + } else { + start = gridClip.y + gridClip.height; + end = gridClip.y; + current = symbol.y; + } + } + } + + var ratio = end === start ? 0 : (current - start) / (end - start); + + if (isAxisInverse) { + ratio = 1 - ratio; + } + + var delay = isFunction(seriesDalay) ? seriesDalay(idx) : seriesDuration * ratio + seriesDalayValue; + var symbolPath = el.getSymbolPath(); + var text = symbolPath.getTextContent(); + el.attr({ + scaleX: 0, + scaleY: 0 + }); + el.animateTo({ + scaleX: 1, + scaleY: 1 + }, { + duration: 200, + setToFinal: true, + delay: delay + }); + + if (text) { + text.animateFrom({ + style: { + opacity: 0 + } + }, { + duration: 300, + delay: delay + }); + } + + symbolPath.disableLabelAnimation = true; + } + }); + }; + + LineView.prototype._initOrUpdateEndLabel = function (seriesModel, coordSys, inheritColor) { + var endLabelModel = seriesModel.getModel('endLabel'); + + if (anyStateShowEndLabel(seriesModel)) { + var data_2 = seriesModel.getData(); + var polyline = this._polyline; // series may be filtered. + + var points = data_2.getLayout('points'); + + if (!points) { + polyline.removeTextContent(); + this._endLabel = null; + return; + } + + var endLabel = this._endLabel; + + if (!endLabel) { + endLabel = this._endLabel = new ZRText({ + z2: 200 // should be higher than item symbol + + }); + endLabel.ignoreClip = true; + polyline.setTextContent(this._endLabel); + polyline.disableLabelAnimation = true; + } // Find last non-NaN data to display data + + + var dataIndex = getLastIndexNotNull(points); + + if (dataIndex >= 0) { + setLabelStyle(polyline, getLabelStatesModels(seriesModel, 'endLabel'), { + inheritColor: inheritColor, + labelFetcher: seriesModel, + labelDataIndex: dataIndex, + defaultText: function (dataIndex, opt, interpolatedValue) { + return interpolatedValue != null ? getDefaultInterpolatedLabel(data_2, interpolatedValue) : getDefaultLabel(data_2, dataIndex); + }, + enableTextSetter: true + }, getEndLabelStateSpecified(endLabelModel, coordSys)); + polyline.textConfig.position = null; + } + } else if (this._endLabel) { + this._polyline.removeTextContent(); + + this._endLabel = null; + } + }; + + LineView.prototype._endLabelOnDuring = function (percent, clipRect, data, animationRecord, valueAnimation, endLabelModel, coordSys) { + var endLabel = this._endLabel; + var polyline = this._polyline; + + if (endLabel) { + // NOTE: Don't remove percent < 1. percent === 1 means the first frame during render. + // The label is not prepared at this time. + if (percent < 1 && animationRecord.originalX == null) { + animationRecord.originalX = endLabel.x; + animationRecord.originalY = endLabel.y; + } + + var points = data.getLayout('points'); + var seriesModel = data.hostModel; + var connectNulls = seriesModel.get('connectNulls'); + var precision = endLabelModel.get('precision'); + var distance = endLabelModel.get('distance') || 0; + var baseAxis = coordSys.getBaseAxis(); + var isHorizontal = baseAxis.isHorizontal(); + var isBaseInversed = baseAxis.inverse; + var clipShape = clipRect.shape; + var xOrY = isBaseInversed ? isHorizontal ? clipShape.x : clipShape.y + clipShape.height : isHorizontal ? clipShape.x + clipShape.width : clipShape.y; + var distanceX = (isHorizontal ? distance : 0) * (isBaseInversed ? -1 : 1); + var distanceY = (isHorizontal ? 0 : -distance) * (isBaseInversed ? -1 : 1); + var dim = isHorizontal ? 'x' : 'y'; + var dataIndexRange = getIndexRange(points, xOrY, dim); + var indices = dataIndexRange.range; + var diff = indices[1] - indices[0]; + var value = void 0; + + if (diff >= 1) { + // diff > 1 && connectNulls, which is on the null data. + if (diff > 1 && !connectNulls) { + var pt = getPointAtIndex(points, indices[0]); + endLabel.attr({ + x: pt[0] + distanceX, + y: pt[1] + distanceY + }); + valueAnimation && (value = seriesModel.getRawValue(indices[0])); + } else { + var pt = polyline.getPointOn(xOrY, dim); + pt && endLabel.attr({ + x: pt[0] + distanceX, + y: pt[1] + distanceY + }); + var startValue = seriesModel.getRawValue(indices[0]); + var endValue = seriesModel.getRawValue(indices[1]); + valueAnimation && (value = interpolateRawValues(data, precision, startValue, endValue, dataIndexRange.t)); + } + + animationRecord.lastFrameIndex = indices[0]; + } else { + // If diff <= 0, which is the range is not found(Include NaN) + // Choose the first point or last point. + var idx = percent === 1 || animationRecord.lastFrameIndex > 0 ? indices[0] : 0; + var pt = getPointAtIndex(points, idx); + valueAnimation && (value = seriesModel.getRawValue(idx)); + endLabel.attr({ + x: pt[0] + distanceX, + y: pt[1] + distanceY + }); + } + + if (valueAnimation) { + labelInner(endLabel).setLabelText(value); + } + } + }; + /** + * @private + */ + // FIXME Two value axis + + + LineView.prototype._doUpdateAnimation = function (data, stackedOnPoints, coordSys, api, step, valueOrigin, connectNulls) { + var polyline = this._polyline; + var polygon = this._polygon; + var seriesModel = data.hostModel; + var diff = lineAnimationDiff(this._data, data, this._stackedOnPoints, stackedOnPoints, this._coordSys, coordSys, this._valueOrigin); + var current = diff.current; + var stackedOnCurrent = diff.stackedOnCurrent; + var next = diff.next; + var stackedOnNext = diff.stackedOnNext; + + if (step) { + // TODO If stacked series is not step + current = turnPointsIntoStep(diff.current, coordSys, step, connectNulls); + stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step, connectNulls); + next = turnPointsIntoStep(diff.next, coordSys, step, connectNulls); + stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step, connectNulls); + } // Don't apply animation if diff is large. + // For better result and avoid memory explosion problems like + // https://github.com/apache/incubator-echarts/issues/12229 + + + if (getBoundingDiff(current, next) > 3000 || polygon && getBoundingDiff(stackedOnCurrent, stackedOnNext) > 3000) { + polyline.stopAnimation(); + polyline.setShape({ + points: next + }); + + if (polygon) { + polygon.stopAnimation(); + polygon.setShape({ + points: next, + stackedOnPoints: stackedOnNext + }); + } + + return; + } + + polyline.shape.__points = diff.current; + polyline.shape.points = current; + var target = { + shape: { + points: next + } + }; // Also animate the original points. + // If points reference is changed when turning into step line. + + if (diff.current !== current) { + target.shape.__points = diff.next; + } // Stop previous animation. + + + polyline.stopAnimation(); + updateProps(polyline, target, seriesModel); + + if (polygon) { + polygon.setShape({ + // Reuse the points with polyline. + points: current, + stackedOnPoints: stackedOnCurrent + }); + polygon.stopAnimation(); + updateProps(polygon, { + shape: { + stackedOnPoints: stackedOnNext + } + }, seriesModel); // If use attr directly in updateProps. + + if (polyline.shape.points !== polygon.shape.points) { + polygon.shape.points = polyline.shape.points; + } + } + + var updatedDataInfo = []; + var diffStatus = diff.status; + + for (var i = 0; i < diffStatus.length; i++) { + var cmd = diffStatus[i].cmd; + + if (cmd === '=') { + var el = data.getItemGraphicEl(diffStatus[i].idx1); + + if (el) { + updatedDataInfo.push({ + el: el, + ptIdx: i // Index of points + + }); + } + } + } + + if (polyline.animators && polyline.animators.length) { + polyline.animators[0].during(function () { + polygon && polygon.dirtyShape(); + var points = polyline.shape.__points; + + for (var i = 0; i < updatedDataInfo.length; i++) { + var el = updatedDataInfo[i].el; + var offset = updatedDataInfo[i].ptIdx * 2; + el.x = points[offset]; + el.y = points[offset + 1]; + el.markRedraw(); + } + }); + } + }; + + LineView.prototype.remove = function (ecModel) { + var group = this.group; + var oldData = this._data; + + this._lineGroup.removeAll(); + + this._symbolDraw.remove(true); // Remove temporary created elements when highlighting + + + oldData && oldData.eachItemGraphicEl(function (el, idx) { + if (el.__temp) { + group.remove(el); + oldData.setItemGraphicEl(idx, null); + } + }); + this._polyline = this._polygon = this._coordSys = this._points = this._stackedOnPoints = this._endLabel = this._data = null; + }; + + LineView.type = 'line'; + return LineView; + }(ChartView); + + function pointsLayout(seriesType, forceStoreInTypedArray) { + return { + seriesType: seriesType, + plan: createRenderPlanner(), + reset: function (seriesModel) { + var data = seriesModel.getData(); + var coordSys = seriesModel.coordinateSystem; + var pipelineContext = seriesModel.pipelineContext; + var useTypedArray = forceStoreInTypedArray || pipelineContext.large; + + if (!coordSys) { + return; + } + + var dims = map(coordSys.dimensions, function (dim) { + return data.mapDimension(dim); + }).slice(0, 2); + var dimLen = dims.length; + var stackResultDim = data.getCalculationInfo('stackResultDimension'); + + if (isDimensionStacked(data, dims[0])) { + dims[0] = stackResultDim; + } + + if (isDimensionStacked(data, dims[1])) { + dims[1] = stackResultDim; + } + + var store = data.getStore(); + var dimIdx0 = data.getDimensionIndex(dims[0]); + var dimIdx1 = data.getDimensionIndex(dims[1]); + return dimLen && { + progress: function (params, data) { + var segCount = params.end - params.start; + var points = useTypedArray && createFloat32Array(segCount * dimLen); + var tmpIn = []; + var tmpOut = []; + + for (var i = params.start, offset = 0; i < params.end; i++) { + var point = void 0; + + if (dimLen === 1) { + var x = store.get(dimIdx0, i); // NOTE: Make sure the second parameter is null to use default strategy. + + point = coordSys.dataToPoint(x, null, tmpOut); + } else { + tmpIn[0] = store.get(dimIdx0, i); + tmpIn[1] = store.get(dimIdx1, i); // Let coordinate system to handle the NaN data. + + point = coordSys.dataToPoint(tmpIn, null, tmpOut); + } + + if (useTypedArray) { + points[offset++] = point[0]; + points[offset++] = point[1]; + } else { + data.setItemLayout(i, point.slice()); + } + } + + useTypedArray && data.setLayout('points', points); + } + }; + } + }; + } + + var samplers = { + average: function (frame) { + var sum = 0; + var count = 0; + + for (var i = 0; i < frame.length; i++) { + if (!isNaN(frame[i])) { + sum += frame[i]; + count++; + } + } // Return NaN if count is 0 + + + return count === 0 ? NaN : sum / count; + }, + sum: function (frame) { + var sum = 0; + + for (var i = 0; i < frame.length; i++) { + // Ignore NaN + sum += frame[i] || 0; + } + + return sum; + }, + max: function (frame) { + var max = -Infinity; + + for (var i = 0; i < frame.length; i++) { + frame[i] > max && (max = frame[i]); + } // NaN will cause illegal axis extent. + + + return isFinite(max) ? max : NaN; + }, + min: function (frame) { + var min = Infinity; + + for (var i = 0; i < frame.length; i++) { + frame[i] < min && (min = frame[i]); + } // NaN will cause illegal axis extent. + + + return isFinite(min) ? min : NaN; + }, + // TODO + // Median + nearest: function (frame) { + return frame[0]; + } + }; + + var indexSampler = function (frame) { + return Math.round(frame.length / 2); + }; + + function dataSample(seriesType) { + return { + seriesType: seriesType, + // FIXME:TS never used, so comment it + // modifyOutputEnd: true, + reset: function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + var sampling = seriesModel.get('sampling'); + var coordSys = seriesModel.coordinateSystem; + var count = data.count(); // Only cartesian2d support down sampling. Disable it when there is few data. + + if (count > 10 && coordSys.type === 'cartesian2d' && sampling) { + var baseAxis = coordSys.getBaseAxis(); + var valueAxis = coordSys.getOtherAxis(baseAxis); + var extent = baseAxis.getExtent(); + var dpr = api.getDevicePixelRatio(); // Coordinste system has been resized + + var size = Math.abs(extent[1] - extent[0]) * (dpr || 1); + var rate = Math.round(count / size); + + if (isFinite(rate) && rate > 1) { + if (sampling === 'lttb') { + seriesModel.setData(data.lttbDownSample(data.mapDimension(valueAxis.dim), 1 / rate)); + } + + var sampler = void 0; + + if (isString(sampling)) { + sampler = samplers[sampling]; + } else if (isFunction(sampling)) { + sampler = sampling; + } + + if (sampler) { + // Only support sample the first dim mapped from value axis. + seriesModel.setData(data.downSample(data.mapDimension(valueAxis.dim), 1 / rate, sampler, indexSampler)); + } + } + } + } + }; + } + + function install$2(registers) { + registers.registerChartView(LineView); + registers.registerSeriesModel(LineSeriesModel); + registers.registerLayout(pointsLayout('line', true)); + registers.registerVisual({ + seriesType: 'line', + reset: function (seriesModel) { + var data = seriesModel.getData(); // Visual coding for legend + + var lineStyle = seriesModel.getModel('lineStyle').getLineStyle(); + + if (lineStyle && !lineStyle.stroke) { + // Fill in visual should be palette color if + // has color callback + lineStyle.stroke = data.getVisual('style').fill; + } + + data.setVisual('legendLineStyle', lineStyle); + } + }); // Down sample after filter + + registers.registerProcessor(registers.PRIORITY.PROCESSOR.STATISTIC, dataSample('line')); + } + + var BaseBarSeriesModel = + /** @class */ + function (_super) { + __extends(BaseBarSeriesModel, _super); + + function BaseBarSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = BaseBarSeriesModel.type; + return _this; + } + + BaseBarSeriesModel.prototype.getInitialData = function (option, ecModel) { + return createSeriesData(null, this, { + useEncodeDefaulter: true + }); + }; + + BaseBarSeriesModel.prototype.getMarkerPosition = function (value) { + var coordSys = this.coordinateSystem; + + if (coordSys && coordSys.clampData) { + // PENDING if clamp ? + var pt = coordSys.dataToPoint(coordSys.clampData(value)); + var data = this.getData(); + var offset = data.getLayout('offset'); + var size = data.getLayout('size'); + var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1; + pt[offsetIndex] += offset + size / 2; + return pt; + } + + return [NaN, NaN]; + }; + + BaseBarSeriesModel.type = 'series.__base_bar__'; + BaseBarSeriesModel.defaultOption = { + // zlevel: 0, + z: 2, + coordinateSystem: 'cartesian2d', + legendHoverLink: true, + // stack: null + // Cartesian coordinate system + // xAxisIndex: 0, + // yAxisIndex: 0, + barMinHeight: 0, + barMinAngle: 0, + // cursor: null, + large: false, + largeThreshold: 400, + progressive: 3e3, + progressiveChunkMode: 'mod' + }; + return BaseBarSeriesModel; + }(SeriesModel); + + SeriesModel.registerClass(BaseBarSeriesModel); + + var BarSeriesModel = + /** @class */ + function (_super) { + __extends(BarSeriesModel, _super); + + function BarSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = BarSeriesModel.type; + return _this; + } + + BarSeriesModel.prototype.getInitialData = function () { + return createSeriesData(null, this, { + useEncodeDefaulter: true, + createInvertedIndices: !!this.get('realtimeSort', true) || null + }); + }; + /** + * @override + */ + + + BarSeriesModel.prototype.getProgressive = function () { + // Do not support progressive in normal mode. + return this.get('large') ? this.get('progressive') : false; + }; + /** + * @override + */ + + + BarSeriesModel.prototype.getProgressiveThreshold = function () { + // Do not support progressive in normal mode. + var progressiveThreshold = this.get('progressiveThreshold'); + var largeThreshold = this.get('largeThreshold'); + + if (largeThreshold > progressiveThreshold) { + progressiveThreshold = largeThreshold; + } + + return progressiveThreshold; + }; + + BarSeriesModel.prototype.brushSelector = function (dataIndex, data, selectors) { + return selectors.rect(data.getItemLayout(dataIndex)); + }; + + BarSeriesModel.type = 'series.bar'; + BarSeriesModel.dependencies = ['grid', 'polar']; + BarSeriesModel.defaultOption = inheritDefaultOption(BaseBarSeriesModel.defaultOption, { + // If clipped + // Only available on cartesian2d + clip: true, + roundCap: false, + showBackground: false, + backgroundStyle: { + color: 'rgba(180, 180, 180, 0.2)', + borderColor: null, + borderWidth: 0, + borderType: 'solid', + borderRadius: 0, + shadowBlur: 0, + shadowColor: null, + shadowOffsetX: 0, + shadowOffsetY: 0, + opacity: 1 + }, + select: { + itemStyle: { + borderColor: '#212121' + } + }, + realtimeSort: false + }); + return BarSeriesModel; + }(BaseBarSeriesModel); + + /** + * Sausage: similar to sector, but have half circle on both sides + */ + + var SausageShape = + /** @class */ + function () { + function SausageShape() { + this.cx = 0; + this.cy = 0; + this.r0 = 0; + this.r = 0; + this.startAngle = 0; + this.endAngle = Math.PI * 2; + this.clockwise = true; + } + + return SausageShape; + }(); + + var SausagePath = + /** @class */ + function (_super) { + __extends(SausagePath, _super); + + function SausagePath(opts) { + var _this = _super.call(this, opts) || this; + + _this.type = 'sausage'; + return _this; + } + + SausagePath.prototype.getDefaultShape = function () { + return new SausageShape(); + }; + + SausagePath.prototype.buildPath = function (ctx, shape) { + var cx = shape.cx; + var cy = shape.cy; + var r0 = Math.max(shape.r0 || 0, 0); + var r = Math.max(shape.r, 0); + var dr = (r - r0) * 0.5; + var rCenter = r0 + dr; + var startAngle = shape.startAngle; + var endAngle = shape.endAngle; + var clockwise = shape.clockwise; + var PI2 = Math.PI * 2; + var lessThanCircle = clockwise ? endAngle - startAngle < PI2 : startAngle - endAngle < PI2; + + if (!lessThanCircle) { + // Normalize angles + startAngle = endAngle - (clockwise ? PI2 : -PI2); + } + + var unitStartX = Math.cos(startAngle); + var unitStartY = Math.sin(startAngle); + var unitEndX = Math.cos(endAngle); + var unitEndY = Math.sin(endAngle); + + if (lessThanCircle) { + ctx.moveTo(unitStartX * r0 + cx, unitStartY * r0 + cy); + ctx.arc(unitStartX * rCenter + cx, unitStartY * rCenter + cy, dr, -Math.PI + startAngle, startAngle, !clockwise); + } else { + ctx.moveTo(unitStartX * r + cx, unitStartY * r + cy); + } + + ctx.arc(cx, cy, r, startAngle, endAngle, !clockwise); + ctx.arc(unitEndX * rCenter + cx, unitEndY * rCenter + cy, dr, endAngle - Math.PI * 2, endAngle - Math.PI, !clockwise); + + if (r0 !== 0) { + ctx.arc(cx, cy, r0, endAngle, startAngle, clockwise); + } // ctx.closePath(); + + }; + + return SausagePath; + }(Path); + + function createSectorCalculateTextPosition(positionMapping, opts) { + opts = opts || {}; + var isRoundCap = opts.isRoundCap; + return function (out, opts, boundingRect) { + var textPosition = opts.position; + + if (!textPosition || textPosition instanceof Array) { + return calculateTextPosition(out, opts, boundingRect); + } + + var mappedSectorPosition = positionMapping(textPosition); + var distance = opts.distance != null ? opts.distance : 5; + var sector = this.shape; + var cx = sector.cx; + var cy = sector.cy; + var r = sector.r; + var r0 = sector.r0; + var middleR = (r + r0) / 2; + var startAngle = sector.startAngle; + var endAngle = sector.endAngle; + var middleAngle = (startAngle + endAngle) / 2; + var extraDist = isRoundCap ? Math.abs(r - r0) / 2 : 0; + var mathCos = Math.cos; + var mathSin = Math.sin; // base position: top-left + + var x = cx + r * mathCos(startAngle); + var y = cy + r * mathSin(startAngle); + var textAlign = 'left'; + var textVerticalAlign = 'top'; + + switch (mappedSectorPosition) { + case 'startArc': + x = cx + (r0 - distance) * mathCos(middleAngle); + y = cy + (r0 - distance) * mathSin(middleAngle); + textAlign = 'center'; + textVerticalAlign = 'top'; + break; + + case 'insideStartArc': + x = cx + (r0 + distance) * mathCos(middleAngle); + y = cy + (r0 + distance) * mathSin(middleAngle); + textAlign = 'center'; + textVerticalAlign = 'bottom'; + break; + + case 'startAngle': + x = cx + middleR * mathCos(startAngle) + adjustAngleDistanceX(startAngle, distance + extraDist, false); + y = cy + middleR * mathSin(startAngle) + adjustAngleDistanceY(startAngle, distance + extraDist, false); + textAlign = 'right'; + textVerticalAlign = 'middle'; + break; + + case 'insideStartAngle': + x = cx + middleR * mathCos(startAngle) + adjustAngleDistanceX(startAngle, -distance + extraDist, false); + y = cy + middleR * mathSin(startAngle) + adjustAngleDistanceY(startAngle, -distance + extraDist, false); + textAlign = 'left'; + textVerticalAlign = 'middle'; + break; + + case 'middle': + x = cx + middleR * mathCos(middleAngle); + y = cy + middleR * mathSin(middleAngle); + textAlign = 'center'; + textVerticalAlign = 'middle'; + break; + + case 'endArc': + x = cx + (r + distance) * mathCos(middleAngle); + y = cy + (r + distance) * mathSin(middleAngle); + textAlign = 'center'; + textVerticalAlign = 'bottom'; + break; + + case 'insideEndArc': + x = cx + (r - distance) * mathCos(middleAngle); + y = cy + (r - distance) * mathSin(middleAngle); + textAlign = 'center'; + textVerticalAlign = 'top'; + break; + + case 'endAngle': + x = cx + middleR * mathCos(endAngle) + adjustAngleDistanceX(endAngle, distance + extraDist, true); + y = cy + middleR * mathSin(endAngle) + adjustAngleDistanceY(endAngle, distance + extraDist, true); + textAlign = 'left'; + textVerticalAlign = 'middle'; + break; + + case 'insideEndAngle': + x = cx + middleR * mathCos(endAngle) + adjustAngleDistanceX(endAngle, -distance + extraDist, true); + y = cy + middleR * mathSin(endAngle) + adjustAngleDistanceY(endAngle, -distance + extraDist, true); + textAlign = 'right'; + textVerticalAlign = 'middle'; + break; + + default: + return calculateTextPosition(out, opts, boundingRect); + } + + out = out || {}; + out.x = x; + out.y = y; + out.align = textAlign; + out.verticalAlign = textVerticalAlign; + return out; + }; + } + function setSectorTextRotation(sector, textPosition, positionMapping, rotateType) { + if (isNumber(rotateType)) { + // user-set rotation + sector.setTextConfig({ + rotation: rotateType + }); + return; + } else if (isArray(textPosition)) { + // user-set position, use 0 as auto rotation + sector.setTextConfig({ + rotation: 0 + }); + return; + } + + var shape = sector.shape; + var startAngle = shape.clockwise ? shape.startAngle : shape.endAngle; + var endAngle = shape.clockwise ? shape.endAngle : shape.startAngle; + var middleAngle = (startAngle + endAngle) / 2; + var anchorAngle; + var mappedSectorPosition = positionMapping(textPosition); + + switch (mappedSectorPosition) { + case 'startArc': + case 'insideStartArc': + case 'middle': + case 'insideEndArc': + case 'endArc': + anchorAngle = middleAngle; + break; + + case 'startAngle': + case 'insideStartAngle': + anchorAngle = startAngle; + break; + + case 'endAngle': + case 'insideEndAngle': + anchorAngle = endAngle; + break; + + default: + sector.setTextConfig({ + rotation: 0 + }); + return; + } + + var rotate = Math.PI * 1.5 - anchorAngle; + /** + * TODO: labels with rotate > Math.PI / 2 should be rotate another + * half round flipped to increase readability. However, only middle + * position supports this for now, because in other positions, the + * anchor point is not at the center of the text, so the positions + * after rotating is not as expected. + */ + + if (mappedSectorPosition === 'middle' && rotate > Math.PI / 2 && rotate < Math.PI * 1.5) { + rotate -= Math.PI; + } + + sector.setTextConfig({ + rotation: rotate + }); + } + + function adjustAngleDistanceX(angle, distance, isEnd) { + return distance * Math.sin(angle) * (isEnd ? -1 : 1); + } + + function adjustAngleDistanceY(angle, distance, isEnd) { + return distance * Math.cos(angle) * (isEnd ? 1 : -1); + } + + var mathMax$6 = Math.max; + var mathMin$6 = Math.min; + + function getClipArea(coord, data) { + var coordSysClipArea = coord.getArea && coord.getArea(); + + if (isCoordinateSystemType(coord, 'cartesian2d')) { + var baseAxis = coord.getBaseAxis(); // When boundaryGap is false or using time axis. bar may exceed the grid. + // We should not clip this part. + // See test/bar2.html + + if (baseAxis.type !== 'category' || !baseAxis.onBand) { + var expandWidth = data.getLayout('bandWidth'); + + if (baseAxis.isHorizontal()) { + coordSysClipArea.x -= expandWidth; + coordSysClipArea.width += expandWidth * 2; + } else { + coordSysClipArea.y -= expandWidth; + coordSysClipArea.height += expandWidth * 2; + } + } + } + + return coordSysClipArea; + } + + var BarView = + /** @class */ + function (_super) { + __extends(BarView, _super); + + function BarView() { + var _this = _super.call(this) || this; + + _this.type = BarView.type; + _this._isFirstFrame = true; + return _this; + } + + BarView.prototype.render = function (seriesModel, ecModel, api, payload) { + this._model = seriesModel; + + this._removeOnRenderedListener(api); + + this._updateDrawMode(seriesModel); + + var coordinateSystemType = seriesModel.get('coordinateSystem'); + + if (coordinateSystemType === 'cartesian2d' || coordinateSystemType === 'polar') { + // Clear previously rendered progressive elements. + this._progressiveEls = null; + this._isLargeDraw ? this._renderLarge(seriesModel, ecModel, api) : this._renderNormal(seriesModel, ecModel, api, payload); + } else if ("development" !== 'production') { + warn('Only cartesian2d and polar supported for bar.'); + } + }; + + BarView.prototype.incrementalPrepareRender = function (seriesModel) { + this._clear(); + + this._updateDrawMode(seriesModel); // incremental also need to clip, otherwise might be overlow. + // But must not set clip in each frame, otherwise all of the children will be marked redraw. + + + this._updateLargeClip(seriesModel); + }; + + BarView.prototype.incrementalRender = function (params, seriesModel) { + // Reset + this._progressiveEls = []; // Do not support progressive in normal mode. + + this._incrementalRenderLarge(params, seriesModel); + }; + + BarView.prototype.eachRendered = function (cb) { + traverseElements(this._progressiveEls || this.group, cb); + }; + + BarView.prototype._updateDrawMode = function (seriesModel) { + var isLargeDraw = seriesModel.pipelineContext.large; + + if (this._isLargeDraw == null || isLargeDraw !== this._isLargeDraw) { + this._isLargeDraw = isLargeDraw; + + this._clear(); + } + }; + + BarView.prototype._renderNormal = function (seriesModel, ecModel, api, payload) { + var group = this.group; + var data = seriesModel.getData(); + var oldData = this._data; + var coord = seriesModel.coordinateSystem; + var baseAxis = coord.getBaseAxis(); + var isHorizontalOrRadial; + + if (coord.type === 'cartesian2d') { + isHorizontalOrRadial = baseAxis.isHorizontal(); + } else if (coord.type === 'polar') { + isHorizontalOrRadial = baseAxis.dim === 'angle'; + } + + var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null; + var realtimeSortCfg = shouldRealtimeSort(seriesModel, coord); + + if (realtimeSortCfg) { + this._enableRealtimeSort(realtimeSortCfg, data, api); + } + + var needsClip = seriesModel.get('clip', true) || realtimeSortCfg; + var coordSysClipArea = getClipArea(coord, data); // If there is clipPath created in large mode. Remove it. + + group.removeClipPath(); // We don't use clipPath in normal mode because we needs a perfect animation + // And don't want the label are clipped. + + var roundCap = seriesModel.get('roundCap', true); + var drawBackground = seriesModel.get('showBackground', true); + var backgroundModel = seriesModel.getModel('backgroundStyle'); + var barBorderRadius = backgroundModel.get('borderRadius') || 0; + var bgEls = []; + var oldBgEls = this._backgroundEls; + var isInitSort = payload && payload.isInitSort; + var isChangeOrder = payload && payload.type === 'changeAxisOrder'; + + function createBackground(dataIndex) { + var bgLayout = getLayout[coord.type](data, dataIndex); + var bgEl = createBackgroundEl(coord, isHorizontalOrRadial, bgLayout); + bgEl.useStyle(backgroundModel.getItemStyle()); // Only cartesian2d support borderRadius. + + if (coord.type === 'cartesian2d') { + bgEl.setShape('r', barBorderRadius); + } + + bgEls[dataIndex] = bgEl; + return bgEl; + } + data.diff(oldData).add(function (dataIndex) { + var itemModel = data.getItemModel(dataIndex); + var layout = getLayout[coord.type](data, dataIndex, itemModel); + + if (drawBackground) { + createBackground(dataIndex); + } // If dataZoom in filteMode: 'empty', the baseValue can be set as NaN in "axisProxy". + + + if (!data.hasValue(dataIndex) || !isValidLayout[coord.type](layout)) { + return; + } + + var isClipped = false; + + if (needsClip) { + // Clip will modify the layout params. + // And return a boolean to determine if the shape are fully clipped. + isClipped = clip[coord.type](coordSysClipArea, layout); + } + + var el = elementCreator[coord.type](seriesModel, data, dataIndex, layout, isHorizontalOrRadial, animationModel, baseAxis.model, false, roundCap); + + if (realtimeSortCfg) { + /** + * Force label animation because even if the element is + * ignored because it's clipped, it may not be clipped after + * changing order. Then, if not using forceLabelAnimation, + * the label animation was never started, in which case, + * the label will be the final value and doesn't have label + * animation. + */ + el.forceLabelAnimation = true; + } + + updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar'); + + if (isInitSort) { + el.attr({ + shape: layout + }); + } else if (realtimeSortCfg) { + updateRealtimeAnimation(realtimeSortCfg, animationModel, el, layout, dataIndex, isHorizontalOrRadial, false, false); + } else { + initProps(el, { + shape: layout + }, seriesModel, dataIndex); + } + + data.setItemGraphicEl(dataIndex, el); + group.add(el); + el.ignore = isClipped; + }).update(function (newIndex, oldIndex) { + var itemModel = data.getItemModel(newIndex); + var layout = getLayout[coord.type](data, newIndex, itemModel); + + if (drawBackground) { + var bgEl = void 0; + + if (oldBgEls.length === 0) { + bgEl = createBackground(oldIndex); + } else { + bgEl = oldBgEls[oldIndex]; + bgEl.useStyle(backgroundModel.getItemStyle()); // Only cartesian2d support borderRadius. + + if (coord.type === 'cartesian2d') { + bgEl.setShape('r', barBorderRadius); + } + + bgEls[newIndex] = bgEl; + } + + var bgLayout = getLayout[coord.type](data, newIndex); + var shape = createBackgroundShape(isHorizontalOrRadial, bgLayout, coord); + updateProps(bgEl, { + shape: shape + }, animationModel, newIndex); + } + + var el = oldData.getItemGraphicEl(oldIndex); + + if (!data.hasValue(newIndex) || !isValidLayout[coord.type](layout)) { + group.remove(el); + return; + } + + var isClipped = false; + + if (needsClip) { + isClipped = clip[coord.type](coordSysClipArea, layout); + + if (isClipped) { + group.remove(el); + } + } + + if (!el) { + el = elementCreator[coord.type](seriesModel, data, newIndex, layout, isHorizontalOrRadial, animationModel, baseAxis.model, !!el, roundCap); + } else { + saveOldStyle(el); + } + + if (realtimeSortCfg) { + el.forceLabelAnimation = true; + } + + if (isChangeOrder) { + var textEl = el.getTextContent(); + + if (textEl) { + var labelInnerStore = labelInner(textEl); + + if (labelInnerStore.prevValue != null) { + /** + * Set preValue to be value so that no new label + * should be started, otherwise, it will take a full + * `animationDurationUpdate` time to finish the + * animation, which is not expected. + */ + labelInnerStore.prevValue = labelInnerStore.value; + } + } + } // Not change anything if only order changed. + // Especially not change label. + else { + updateStyle(el, data, newIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar'); + } + + if (isInitSort) { + el.attr({ + shape: layout + }); + } else if (realtimeSortCfg) { + updateRealtimeAnimation(realtimeSortCfg, animationModel, el, layout, newIndex, isHorizontalOrRadial, true, isChangeOrder); + } else { + updateProps(el, { + shape: layout + }, seriesModel, newIndex, null); + } + + data.setItemGraphicEl(newIndex, el); + el.ignore = isClipped; + group.add(el); + }).remove(function (dataIndex) { + var el = oldData.getItemGraphicEl(dataIndex); + el && removeElementWithFadeOut(el, seriesModel, dataIndex); + }).execute(); + var bgGroup = this._backgroundGroup || (this._backgroundGroup = new Group()); + bgGroup.removeAll(); + + for (var i = 0; i < bgEls.length; ++i) { + bgGroup.add(bgEls[i]); + } + + group.add(bgGroup); + this._backgroundEls = bgEls; + this._data = data; + }; + + BarView.prototype._renderLarge = function (seriesModel, ecModel, api) { + this._clear(); + + createLarge(seriesModel, this.group); + + this._updateLargeClip(seriesModel); + }; + + BarView.prototype._incrementalRenderLarge = function (params, seriesModel) { + this._removeBackground(); + + createLarge(seriesModel, this.group, this._progressiveEls, true); + }; + + BarView.prototype._updateLargeClip = function (seriesModel) { + // Use clipPath in large mode. + var clipPath = seriesModel.get('clip', true) && createClipPath(seriesModel.coordinateSystem, false, seriesModel); + var group = this.group; + + if (clipPath) { + group.setClipPath(clipPath); + } else { + group.removeClipPath(); + } + }; + + BarView.prototype._enableRealtimeSort = function (realtimeSortCfg, data, api) { + var _this = this; // If no data in the first frame, wait for data to initSort + + + if (!data.count()) { + return; + } + + var baseAxis = realtimeSortCfg.baseAxis; + + if (this._isFirstFrame) { + this._dispatchInitSort(data, realtimeSortCfg, api); + + this._isFirstFrame = false; + } else { + var orderMapping_1 = function (idx) { + var el = data.getItemGraphicEl(idx); + var shape = el && el.shape; + return shape && // The result should be consistent with the initial sort by data value. + // Do not support the case that both positive and negative exist. + Math.abs(baseAxis.isHorizontal() ? shape.height : shape.width) // If data is NaN, shape.xxx may be NaN, so use || 0 here in case + || 0; + }; + + this._onRendered = function () { + _this._updateSortWithinSameData(data, orderMapping_1, baseAxis, api); + }; + + api.getZr().on('rendered', this._onRendered); + } + }; + + BarView.prototype._dataSort = function (data, baseAxis, orderMapping) { + var info = []; + data.each(data.mapDimension(baseAxis.dim), function (ordinalNumber, dataIdx) { + var mappedValue = orderMapping(dataIdx); + mappedValue = mappedValue == null ? NaN : mappedValue; + info.push({ + dataIndex: dataIdx, + mappedValue: mappedValue, + ordinalNumber: ordinalNumber + }); + }); + info.sort(function (a, b) { + // If NaN, it will be treated as min val. + return b.mappedValue - a.mappedValue; + }); + return { + ordinalNumbers: map(info, function (item) { + return item.ordinalNumber; + }) + }; + }; + + BarView.prototype._isOrderChangedWithinSameData = function (data, orderMapping, baseAxis) { + var scale = baseAxis.scale; + var ordinalDataDim = data.mapDimension(baseAxis.dim); + var lastValue = Number.MAX_VALUE; + + for (var tickNum = 0, len = scale.getOrdinalMeta().categories.length; tickNum < len; ++tickNum) { + var rawIdx = data.rawIndexOf(ordinalDataDim, scale.getRawOrdinalNumber(tickNum)); + var value = rawIdx < 0 // If some tick have no bar, the tick will be treated as min. + ? Number.MIN_VALUE // PENDING: if dataZoom on baseAxis exits, is it a performance issue? + : orderMapping(data.indexOfRawIndex(rawIdx)); + + if (value > lastValue) { + return true; + } + + lastValue = value; + } + + return false; + }; + /* + * Consider the case when A and B changed order, whose representing + * bars are both out of sight, we don't wish to trigger reorder action + * as long as the order in the view doesn't change. + */ + + + BarView.prototype._isOrderDifferentInView = function (orderInfo, baseAxis) { + var scale = baseAxis.scale; + var extent = scale.getExtent(); + var tickNum = Math.max(0, extent[0]); + var tickMax = Math.min(extent[1], scale.getOrdinalMeta().categories.length - 1); + + for (; tickNum <= tickMax; ++tickNum) { + if (orderInfo.ordinalNumbers[tickNum] !== scale.getRawOrdinalNumber(tickNum)) { + return true; + } + } + }; + + BarView.prototype._updateSortWithinSameData = function (data, orderMapping, baseAxis, api) { + if (!this._isOrderChangedWithinSameData(data, orderMapping, baseAxis)) { + return; + } + + var sortInfo = this._dataSort(data, baseAxis, orderMapping); + + if (this._isOrderDifferentInView(sortInfo, baseAxis)) { + this._removeOnRenderedListener(api); + + api.dispatchAction({ + type: 'changeAxisOrder', + componentType: baseAxis.dim + 'Axis', + axisId: baseAxis.index, + sortInfo: sortInfo + }); + } + }; + + BarView.prototype._dispatchInitSort = function (data, realtimeSortCfg, api) { + var baseAxis = realtimeSortCfg.baseAxis; + + var sortResult = this._dataSort(data, baseAxis, function (dataIdx) { + return data.get(data.mapDimension(realtimeSortCfg.otherAxis.dim), dataIdx); + }); + + api.dispatchAction({ + type: 'changeAxisOrder', + componentType: baseAxis.dim + 'Axis', + isInitSort: true, + axisId: baseAxis.index, + sortInfo: sortResult + }); + }; + + BarView.prototype.remove = function (ecModel, api) { + this._clear(this._model); + + this._removeOnRenderedListener(api); + }; + + BarView.prototype.dispose = function (ecModel, api) { + this._removeOnRenderedListener(api); + }; + + BarView.prototype._removeOnRenderedListener = function (api) { + if (this._onRendered) { + api.getZr().off('rendered', this._onRendered); + this._onRendered = null; + } + }; + + BarView.prototype._clear = function (model) { + var group = this.group; + var data = this._data; + + if (model && model.isAnimationEnabled() && data && !this._isLargeDraw) { + this._removeBackground(); + + this._backgroundEls = []; + data.eachItemGraphicEl(function (el) { + removeElementWithFadeOut(el, model, getECData(el).dataIndex); + }); + } else { + group.removeAll(); + } + + this._data = null; + this._isFirstFrame = true; + }; + + BarView.prototype._removeBackground = function () { + this.group.remove(this._backgroundGroup); + this._backgroundGroup = null; + }; + + BarView.type = 'bar'; + return BarView; + }(ChartView); + + var clip = { + cartesian2d: function (coordSysBoundingRect, layout) { + var signWidth = layout.width < 0 ? -1 : 1; + var signHeight = layout.height < 0 ? -1 : 1; // Needs positive width and height + + if (signWidth < 0) { + layout.x += layout.width; + layout.width = -layout.width; + } + + if (signHeight < 0) { + layout.y += layout.height; + layout.height = -layout.height; + } + + var coordSysX2 = coordSysBoundingRect.x + coordSysBoundingRect.width; + var coordSysY2 = coordSysBoundingRect.y + coordSysBoundingRect.height; + var x = mathMax$6(layout.x, coordSysBoundingRect.x); + var x2 = mathMin$6(layout.x + layout.width, coordSysX2); + var y = mathMax$6(layout.y, coordSysBoundingRect.y); + var y2 = mathMin$6(layout.y + layout.height, coordSysY2); + var xClipped = x2 < x; + var yClipped = y2 < y; // When xClipped or yClipped, the element will be marked as `ignore`. + // But we should also place the element at the edge of the coord sys bounding rect. + // Beause if data changed and the bar show again, its transition animaiton + // will begin at this place. + + layout.x = xClipped && x > coordSysX2 ? x2 : x; + layout.y = yClipped && y > coordSysY2 ? y2 : y; + layout.width = xClipped ? 0 : x2 - x; + layout.height = yClipped ? 0 : y2 - y; // Reverse back + + if (signWidth < 0) { + layout.x += layout.width; + layout.width = -layout.width; + } + + if (signHeight < 0) { + layout.y += layout.height; + layout.height = -layout.height; + } + + return xClipped || yClipped; + }, + polar: function (coordSysClipArea, layout) { + var signR = layout.r0 <= layout.r ? 1 : -1; // Make sure r is larger than r0 + + if (signR < 0) { + var tmp = layout.r; + layout.r = layout.r0; + layout.r0 = tmp; + } + + var r = mathMin$6(layout.r, coordSysClipArea.r); + var r0 = mathMax$6(layout.r0, coordSysClipArea.r0); + layout.r = r; + layout.r0 = r0; + var clipped = r - r0 < 0; // Reverse back + + if (signR < 0) { + var tmp = layout.r; + layout.r = layout.r0; + layout.r0 = tmp; + } + + return clipped; + } + }; + var elementCreator = { + cartesian2d: function (seriesModel, data, newIndex, layout, isHorizontal, animationModel, axisModel, isUpdate, roundCap) { + var rect = new Rect({ + shape: extend({}, layout), + z2: 1 + }); + rect.__dataIndex = newIndex; + rect.name = 'item'; + + if (animationModel) { + var rectShape = rect.shape; + var animateProperty = isHorizontal ? 'height' : 'width'; + rectShape[animateProperty] = 0; + } + + return rect; + }, + polar: function (seriesModel, data, newIndex, layout, isRadial, animationModel, axisModel, isUpdate, roundCap) { + var ShapeClass = !isRadial && roundCap ? SausagePath : Sector; + var sector = new ShapeClass({ + shape: layout, + z2: 1 + }); + sector.name = 'item'; + var positionMap = createPolarPositionMapping(isRadial); + sector.calculateTextPosition = createSectorCalculateTextPosition(positionMap, { + isRoundCap: ShapeClass === SausagePath + }); // Animation + + if (animationModel) { + var sectorShape = sector.shape; + var animateProperty = isRadial ? 'r' : 'endAngle'; + var animateTarget = {}; + sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle; + animateTarget[animateProperty] = layout[animateProperty]; + (isUpdate ? updateProps : initProps)(sector, { + shape: animateTarget // __value: typeof dataValue === 'string' ? parseInt(dataValue, 10) : dataValue + + }, animationModel); + } + + return sector; + } + }; + + function shouldRealtimeSort(seriesModel, coordSys) { + var realtimeSortOption = seriesModel.get('realtimeSort', true); + var baseAxis = coordSys.getBaseAxis(); + + if ("development" !== 'production') { + if (realtimeSortOption) { + if (baseAxis.type !== 'category') { + warn('`realtimeSort` will not work because this bar series is not based on a category axis.'); + } + + if (coordSys.type !== 'cartesian2d') { + warn('`realtimeSort` will not work because this bar series is not on cartesian2d.'); + } + } + } + + if (realtimeSortOption && baseAxis.type === 'category' && coordSys.type === 'cartesian2d') { + return { + baseAxis: baseAxis, + otherAxis: coordSys.getOtherAxis(baseAxis) + }; + } + } + + function updateRealtimeAnimation(realtimeSortCfg, seriesAnimationModel, el, layout, newIndex, isHorizontal, isUpdate, isChangeOrder) { + var seriesTarget; + var axisTarget; + + if (isHorizontal) { + axisTarget = { + x: layout.x, + width: layout.width + }; + seriesTarget = { + y: layout.y, + height: layout.height + }; + } else { + axisTarget = { + y: layout.y, + height: layout.height + }; + seriesTarget = { + x: layout.x, + width: layout.width + }; + } + + if (!isChangeOrder) { + // Keep the original growth animation if only axis order changed. + // Not start a new animation. + (isUpdate ? updateProps : initProps)(el, { + shape: seriesTarget + }, seriesAnimationModel, newIndex, null); + } + + var axisAnimationModel = seriesAnimationModel ? realtimeSortCfg.baseAxis.model : null; + (isUpdate ? updateProps : initProps)(el, { + shape: axisTarget + }, axisAnimationModel, newIndex); + } + + function checkPropertiesNotValid(obj, props) { + for (var i = 0; i < props.length; i++) { + if (!isFinite(obj[props[i]])) { + return true; + } + } + + return false; + } + + var rectPropties = ['x', 'y', 'width', 'height']; + var polarPropties = ['cx', 'cy', 'r', 'startAngle', 'endAngle']; + var isValidLayout = { + cartesian2d: function (layout) { + return !checkPropertiesNotValid(layout, rectPropties); + }, + polar: function (layout) { + return !checkPropertiesNotValid(layout, polarPropties); + } + }; + var getLayout = { + // itemModel is only used to get borderWidth, which is not needed + // when calculating bar background layout. + cartesian2d: function (data, dataIndex, itemModel) { + var layout = data.getItemLayout(dataIndex); + var fixedLineWidth = itemModel ? getLineWidth(itemModel, layout) : 0; // fix layout with lineWidth + + var signX = layout.width > 0 ? 1 : -1; + var signY = layout.height > 0 ? 1 : -1; + return { + x: layout.x + signX * fixedLineWidth / 2, + y: layout.y + signY * fixedLineWidth / 2, + width: layout.width - signX * fixedLineWidth, + height: layout.height - signY * fixedLineWidth + }; + }, + polar: function (data, dataIndex, itemModel) { + var layout = data.getItemLayout(dataIndex); + return { + cx: layout.cx, + cy: layout.cy, + r0: layout.r0, + r: layout.r, + startAngle: layout.startAngle, + endAngle: layout.endAngle, + clockwise: layout.clockwise + }; + } + }; + + function isZeroOnPolar(layout) { + return layout.startAngle != null && layout.endAngle != null && layout.startAngle === layout.endAngle; + } + + function createPolarPositionMapping(isRadial) { + return function (isRadial) { + var arcOrAngle = isRadial ? 'Arc' : 'Angle'; + return function (position) { + switch (position) { + case 'start': + case 'insideStart': + case 'end': + case 'insideEnd': + return position + arcOrAngle; + + default: + return position; + } + }; + }(isRadial); + } + + function updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, isPolar) { + var style = data.getItemVisual(dataIndex, 'style'); + + if (!isPolar) { + el.setShape('r', itemModel.get(['itemStyle', 'borderRadius']) || 0); + } + + el.useStyle(style); + var cursorStyle = itemModel.getShallow('cursor'); + cursorStyle && el.attr('cursor', cursorStyle); + var labelPositionOutside = isPolar ? isHorizontalOrRadial ? layout.r >= layout.r0 ? 'endArc' : 'startArc' : layout.endAngle >= layout.startAngle ? 'endAngle' : 'startAngle' : isHorizontalOrRadial ? layout.height >= 0 ? 'bottom' : 'top' : layout.width >= 0 ? 'right' : 'left'; + var labelStatesModels = getLabelStatesModels(itemModel); + setLabelStyle(el, labelStatesModels, { + labelFetcher: seriesModel, + labelDataIndex: dataIndex, + defaultText: getDefaultLabel(seriesModel.getData(), dataIndex), + inheritColor: style.fill, + defaultOpacity: style.opacity, + defaultOutsidePosition: labelPositionOutside + }); + var label = el.getTextContent(); + + if (isPolar && label) { + var position = itemModel.get(['label', 'position']); + el.textConfig.inside = position === 'middle' ? true : null; + setSectorTextRotation(el, position === 'outside' ? labelPositionOutside : position, createPolarPositionMapping(isHorizontalOrRadial), itemModel.get(['label', 'rotate'])); + } + + setLabelValueAnimation(label, labelStatesModels, seriesModel.getRawValue(dataIndex), function (value) { + return getDefaultInterpolatedLabel(data, value); + }); + var emphasisModel = itemModel.getModel(['emphasis']); + toggleHoverEmphasis(el, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled')); + setStatesStylesFromModel(el, itemModel); + + if (isZeroOnPolar(layout)) { + el.style.fill = 'none'; + el.style.stroke = 'none'; + each(el.states, function (state) { + if (state.style) { + state.style.fill = state.style.stroke = 'none'; + } + }); + } + } // In case width or height are too small. + + + function getLineWidth(itemModel, rawLayout) { + // Has no border. + var borderColor = itemModel.get(['itemStyle', 'borderColor']); + + if (!borderColor || borderColor === 'none') { + return 0; + } + + var lineWidth = itemModel.get(['itemStyle', 'borderWidth']) || 0; // width or height may be NaN for empty data + + var width = isNaN(rawLayout.width) ? Number.MAX_VALUE : Math.abs(rawLayout.width); + var height = isNaN(rawLayout.height) ? Number.MAX_VALUE : Math.abs(rawLayout.height); + return Math.min(lineWidth, width, height); + } + + var LagePathShape = + /** @class */ + function () { + function LagePathShape() {} + + return LagePathShape; + }(); + + var LargePath = + /** @class */ + function (_super) { + __extends(LargePath, _super); + + function LargePath(opts) { + var _this = _super.call(this, opts) || this; + + _this.type = 'largeBar'; + return _this; + } + + LargePath.prototype.getDefaultShape = function () { + return new LagePathShape(); + }; + + LargePath.prototype.buildPath = function (ctx, shape) { + // Drawing lines is more efficient than drawing + // a whole line or drawing rects. + var points = shape.points; + var baseDimIdx = this.baseDimIdx; + var valueDimIdx = 1 - this.baseDimIdx; + var startPoint = []; + var size = []; + var barWidth = this.barWidth; + + for (var i = 0; i < points.length; i += 3) { + size[baseDimIdx] = barWidth; + size[valueDimIdx] = points[i + 2]; + startPoint[baseDimIdx] = points[i + baseDimIdx]; + startPoint[valueDimIdx] = points[i + valueDimIdx]; + ctx.rect(startPoint[0], startPoint[1], size[0], size[1]); + } + }; + + return LargePath; + }(Path); + + function createLarge(seriesModel, group, progressiveEls, incremental) { + // TODO support polar + var data = seriesModel.getData(); + var baseDimIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0; + var largeDataIndices = data.getLayout('largeDataIndices'); + var barWidth = data.getLayout('size'); + var backgroundModel = seriesModel.getModel('backgroundStyle'); + var bgPoints = data.getLayout('largeBackgroundPoints'); + + if (bgPoints) { + var bgEl = new LargePath({ + shape: { + points: bgPoints + }, + incremental: !!incremental, + silent: true, + z2: 0 + }); + bgEl.baseDimIdx = baseDimIdx; + bgEl.largeDataIndices = largeDataIndices; + bgEl.barWidth = barWidth; + bgEl.useStyle(backgroundModel.getItemStyle()); + group.add(bgEl); + progressiveEls && progressiveEls.push(bgEl); + } + + var el = new LargePath({ + shape: { + points: data.getLayout('largePoints') + }, + incremental: !!incremental, + z2: 1 + }); + el.baseDimIdx = baseDimIdx; + el.largeDataIndices = largeDataIndices; + el.barWidth = barWidth; + group.add(el); + el.useStyle(data.getVisual('style')); // Enable tooltip and user mouse/touch event handlers. + + getECData(el).seriesIndex = seriesModel.seriesIndex; + + if (!seriesModel.get('silent')) { + el.on('mousedown', largePathUpdateDataIndex); + el.on('mousemove', largePathUpdateDataIndex); + } + + progressiveEls && progressiveEls.push(el); + } // Use throttle to avoid frequently traverse to find dataIndex. + + + var largePathUpdateDataIndex = throttle(function (event) { + var largePath = this; + var dataIndex = largePathFindDataIndex(largePath, event.offsetX, event.offsetY); + getECData(largePath).dataIndex = dataIndex >= 0 ? dataIndex : null; + }, 30, false); + + function largePathFindDataIndex(largePath, x, y) { + var baseDimIdx = largePath.baseDimIdx; + var valueDimIdx = 1 - baseDimIdx; + var points = largePath.shape.points; + var largeDataIndices = largePath.largeDataIndices; + var startPoint = []; + var size = []; + var barWidth = largePath.barWidth; + + for (var i = 0, len = points.length / 3; i < len; i++) { + var ii = i * 3; + size[baseDimIdx] = barWidth; + size[valueDimIdx] = points[ii + 2]; + startPoint[baseDimIdx] = points[ii + baseDimIdx]; + startPoint[valueDimIdx] = points[ii + valueDimIdx]; + + if (size[valueDimIdx] < 0) { + startPoint[valueDimIdx] += size[valueDimIdx]; + size[valueDimIdx] = -size[valueDimIdx]; + } + + if (x >= startPoint[0] && x <= startPoint[0] + size[0] && y >= startPoint[1] && y <= startPoint[1] + size[1]) { + return largeDataIndices[i]; + } + } + + return -1; + } + + function createBackgroundShape(isHorizontalOrRadial, layout, coord) { + if (isCoordinateSystemType(coord, 'cartesian2d')) { + var rectShape = layout; + var coordLayout = coord.getArea(); + return { + x: isHorizontalOrRadial ? rectShape.x : coordLayout.x, + y: isHorizontalOrRadial ? coordLayout.y : rectShape.y, + width: isHorizontalOrRadial ? rectShape.width : coordLayout.width, + height: isHorizontalOrRadial ? coordLayout.height : rectShape.height + }; + } else { + var coordLayout = coord.getArea(); + var sectorShape = layout; + return { + cx: coordLayout.cx, + cy: coordLayout.cy, + r0: isHorizontalOrRadial ? coordLayout.r0 : sectorShape.r0, + r: isHorizontalOrRadial ? coordLayout.r : sectorShape.r, + startAngle: isHorizontalOrRadial ? sectorShape.startAngle : 0, + endAngle: isHorizontalOrRadial ? sectorShape.endAngle : Math.PI * 2 + }; + } + } + + function createBackgroundEl(coord, isHorizontalOrRadial, layout) { + var ElementClz = coord.type === 'polar' ? Sector : Rect; + return new ElementClz({ + shape: createBackgroundShape(isHorizontalOrRadial, layout, coord), + silent: true, + z2: 0 + }); + } + + function install$3(registers) { + registers.registerChartView(BarView); + registers.registerSeriesModel(BarSeriesModel); + registers.registerLayout(registers.PRIORITY.VISUAL.LAYOUT, curry(layout, 'bar')); // Do layout after other overall layout, which can preapre some informations. + + registers.registerLayout(registers.PRIORITY.VISUAL.PROGRESSIVE_LAYOUT, createProgressiveLayout('bar')); // Down sample after filter + + registers.registerProcessor(registers.PRIORITY.PROCESSOR.STATISTIC, dataSample('bar')); + /** + * @payload + * @property {string} [componentType=series] + * @property {number} [dx] + * @property {number} [dy] + * @property {number} [zoom] + * @property {number} [originX] + * @property {number} [originY] + */ + + registers.registerAction({ + type: 'changeAxisOrder', + event: 'changeAxisOrder', + update: 'update' + }, function (payload, ecModel) { + var componentType = payload.componentType || 'series'; + ecModel.eachComponent({ + mainType: componentType, + query: payload + }, function (componentModel) { + if (payload.sortInfo) { + componentModel.axis.setCategorySortInfo(payload.sortInfo); + } + }); + }); + } + + var PI2$8 = Math.PI * 2; + var RADIAN = Math.PI / 180; + + function getViewRect(seriesModel, api) { + return getLayoutRect(seriesModel.getBoxLayoutParams(), { + width: api.getWidth(), + height: api.getHeight() + }); + } + + function getBasicPieLayout(seriesModel, api) { + var viewRect = getViewRect(seriesModel, api); + var center = seriesModel.get('center'); + var radius = seriesModel.get('radius'); + + if (!isArray(radius)) { + radius = [0, radius]; + } + + if (!isArray(center)) { + center = [center, center]; + } + + var width = parsePercent$1(viewRect.width, api.getWidth()); + var height = parsePercent$1(viewRect.height, api.getHeight()); + var size = Math.min(width, height); + var cx = parsePercent$1(center[0], width) + viewRect.x; + var cy = parsePercent$1(center[1], height) + viewRect.y; + var r0 = parsePercent$1(radius[0], size / 2); + var r = parsePercent$1(radius[1], size / 2); + return { + cx: cx, + cy: cy, + r0: r0, + r: r + }; + } + function pieLayout(seriesType, ecModel, api) { + ecModel.eachSeriesByType(seriesType, function (seriesModel) { + var data = seriesModel.getData(); + var valueDim = data.mapDimension('value'); + var viewRect = getViewRect(seriesModel, api); + + var _a = getBasicPieLayout(seriesModel, api), + cx = _a.cx, + cy = _a.cy, + r = _a.r, + r0 = _a.r0; + + var startAngle = -seriesModel.get('startAngle') * RADIAN; + var minAngle = seriesModel.get('minAngle') * RADIAN; + var validDataCount = 0; + data.each(valueDim, function (value) { + !isNaN(value) && validDataCount++; + }); + var sum = data.getSum(valueDim); // Sum may be 0 + + var unitRadian = Math.PI / (sum || validDataCount) * 2; + var clockwise = seriesModel.get('clockwise'); + var roseType = seriesModel.get('roseType'); + var stillShowZeroSum = seriesModel.get('stillShowZeroSum'); // [0...max] + + var extent = data.getDataExtent(valueDim); + extent[0] = 0; // In the case some sector angle is smaller than minAngle + + var restAngle = PI2$8; + var valueSumLargerThanMinAngle = 0; + var currentAngle = startAngle; + var dir = clockwise ? 1 : -1; + data.setLayout({ + viewRect: viewRect, + r: r + }); + data.each(valueDim, function (value, idx) { + var angle; + + if (isNaN(value)) { + data.setItemLayout(idx, { + angle: NaN, + startAngle: NaN, + endAngle: NaN, + clockwise: clockwise, + cx: cx, + cy: cy, + r0: r0, + r: roseType ? NaN : r + }); + return; + } // FIXME 兼容 2.0 但是 roseType 是 area 的时候才是这样? + + + if (roseType !== 'area') { + angle = sum === 0 && stillShowZeroSum ? unitRadian : value * unitRadian; + } else { + angle = PI2$8 / validDataCount; + } + + if (angle < minAngle) { + angle = minAngle; + restAngle -= minAngle; + } else { + valueSumLargerThanMinAngle += value; + } + + var endAngle = currentAngle + dir * angle; + data.setItemLayout(idx, { + angle: angle, + startAngle: currentAngle, + endAngle: endAngle, + clockwise: clockwise, + cx: cx, + cy: cy, + r0: r0, + r: roseType ? linearMap(value, extent, [r0, r]) : r + }); + currentAngle = endAngle; + }); // Some sector is constrained by minAngle + // Rest sectors needs recalculate angle + + if (restAngle < PI2$8 && validDataCount) { + // Average the angle if rest angle is not enough after all angles is + // Constrained by minAngle + if (restAngle <= 1e-3) { + var angle_1 = PI2$8 / validDataCount; + data.each(valueDim, function (value, idx) { + if (!isNaN(value)) { + var layout_1 = data.getItemLayout(idx); + layout_1.angle = angle_1; + layout_1.startAngle = startAngle + dir * idx * angle_1; + layout_1.endAngle = startAngle + dir * (idx + 1) * angle_1; + } + }); + } else { + unitRadian = restAngle / valueSumLargerThanMinAngle; + currentAngle = startAngle; + data.each(valueDim, function (value, idx) { + if (!isNaN(value)) { + var layout_2 = data.getItemLayout(idx); + var angle = layout_2.angle === minAngle ? minAngle : value * unitRadian; + layout_2.startAngle = currentAngle; + layout_2.endAngle = currentAngle + dir * angle; + currentAngle += dir * angle; + } + }); + } + } + }); + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + function dataFilter(seriesType) { + return { + seriesType: seriesType, + reset: function (seriesModel, ecModel) { + var legendModels = ecModel.findComponents({ + mainType: 'legend' + }); + + if (!legendModels || !legendModels.length) { + return; + } + + var data = seriesModel.getData(); + data.filterSelf(function (idx) { + var name = data.getName(idx); // If in any legend component the status is not selected. + + for (var i = 0; i < legendModels.length; i++) { + // @ts-ignore FIXME: LegendModel + if (!legendModels[i].isSelected(name)) { + return false; + } + } + + return true; + }); + } + }; + } + + var RADIAN$1 = Math.PI / 180; + + function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight, viewLeft, viewTop, farthestX) { + if (list.length < 2) { + return; + } + + function recalculateXOnSemiToAlignOnEllipseCurve(semi) { + var rB = semi.rB; + var rB2 = rB * rB; + + for (var i = 0; i < semi.list.length; i++) { + var item = semi.list[i]; + var dy = Math.abs(item.label.y - cy); // horizontal r is always same with original r because x is not changed. + + var rA = r + item.len; + var rA2 = rA * rA; // Use ellipse implicit function to calculate x + + var dx = Math.sqrt((1 - Math.abs(dy * dy / rB2)) * rA2); + var newX = cx + (dx + item.len2) * dir; + var deltaX = newX - item.label.x; + var newTargetWidth = item.targetTextWidth - deltaX * dir; // text x is changed, so need to recalculate width. + + constrainTextWidth(item, newTargetWidth, true); + item.label.x = newX; + } + } // Adjust X based on the shifted y. Make tight labels aligned on an ellipse curve. + + + function recalculateX(items) { + // Extremes of + var topSemi = { + list: [], + maxY: 0 + }; + var bottomSemi = { + list: [], + maxY: 0 + }; + + for (var i = 0; i < items.length; i++) { + if (items[i].labelAlignTo !== 'none') { + continue; + } + + var item = items[i]; + var semi = item.label.y > cy ? bottomSemi : topSemi; + var dy = Math.abs(item.label.y - cy); + + if (dy >= semi.maxY) { + var dx = item.label.x - cx - item.len2 * dir; // horizontal r is always same with original r because x is not changed. + + var rA = r + item.len; // Canculate rB based on the topest / bottemest label. + + var rB = Math.abs(dx) < rA ? Math.sqrt(dy * dy / (1 - dx * dx / rA / rA)) : rA; + semi.rB = rB; + semi.maxY = dy; + } + + semi.list.push(item); + } + + recalculateXOnSemiToAlignOnEllipseCurve(topSemi); + recalculateXOnSemiToAlignOnEllipseCurve(bottomSemi); + } + + var len = list.length; + + for (var i = 0; i < len; i++) { + if (list[i].position === 'outer' && list[i].labelAlignTo === 'labelLine') { + var dx = list[i].label.x - farthestX; + list[i].linePoints[1][0] += dx; + list[i].label.x = farthestX; + } + } + + if (shiftLayoutOnY(list, viewTop, viewTop + viewHeight)) { + recalculateX(list); + } + } + + function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, viewLeft, viewTop) { + var leftList = []; + var rightList = []; + var leftmostX = Number.MAX_VALUE; + var rightmostX = -Number.MAX_VALUE; + + for (var i = 0; i < labelLayoutList.length; i++) { + var label = labelLayoutList[i].label; + + if (isPositionCenter(labelLayoutList[i])) { + continue; + } + + if (label.x < cx) { + leftmostX = Math.min(leftmostX, label.x); + leftList.push(labelLayoutList[i]); + } else { + rightmostX = Math.max(rightmostX, label.x); + rightList.push(labelLayoutList[i]); + } + } + + for (var i = 0; i < labelLayoutList.length; i++) { + var layout = labelLayoutList[i]; + + if (!isPositionCenter(layout) && layout.linePoints) { + if (layout.labelStyleWidth != null) { + continue; + } + + var label = layout.label; + var linePoints = layout.linePoints; + var targetTextWidth = void 0; + + if (layout.labelAlignTo === 'edge') { + if (label.x < cx) { + targetTextWidth = linePoints[2][0] - layout.labelDistance - viewLeft - layout.edgeDistance; + } else { + targetTextWidth = viewLeft + viewWidth - layout.edgeDistance - linePoints[2][0] - layout.labelDistance; + } + } else if (layout.labelAlignTo === 'labelLine') { + if (label.x < cx) { + targetTextWidth = leftmostX - viewLeft - layout.bleedMargin; + } else { + targetTextWidth = viewLeft + viewWidth - rightmostX - layout.bleedMargin; + } + } else { + if (label.x < cx) { + targetTextWidth = label.x - viewLeft - layout.bleedMargin; + } else { + targetTextWidth = viewLeft + viewWidth - label.x - layout.bleedMargin; + } + } + + layout.targetTextWidth = targetTextWidth; + constrainTextWidth(layout, targetTextWidth); + } + } + + adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight, viewLeft, viewTop, rightmostX); + adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight, viewLeft, viewTop, leftmostX); + + for (var i = 0; i < labelLayoutList.length; i++) { + var layout = labelLayoutList[i]; + + if (!isPositionCenter(layout) && layout.linePoints) { + var label = layout.label; + var linePoints = layout.linePoints; + var isAlignToEdge = layout.labelAlignTo === 'edge'; + var padding = label.style.padding; + var paddingH = padding ? padding[1] + padding[3] : 0; // textRect.width already contains paddingH if bgColor is set + + var extraPaddingH = label.style.backgroundColor ? 0 : paddingH; + var realTextWidth = layout.rect.width + extraPaddingH; + var dist = linePoints[1][0] - linePoints[2][0]; + + if (isAlignToEdge) { + if (label.x < cx) { + linePoints[2][0] = viewLeft + layout.edgeDistance + realTextWidth + layout.labelDistance; + } else { + linePoints[2][0] = viewLeft + viewWidth - layout.edgeDistance - realTextWidth - layout.labelDistance; + } + } else { + if (label.x < cx) { + linePoints[2][0] = label.x + layout.labelDistance; + } else { + linePoints[2][0] = label.x - layout.labelDistance; + } + + linePoints[1][0] = linePoints[2][0] + dist; + } + + linePoints[1][1] = linePoints[2][1] = label.y; + } + } + } + /** + * Set max width of each label, and then wrap each label to the max width. + * + * @param layout label layout + * @param availableWidth max width for the label to display + * @param forceRecalculate recaculate the text layout even if the current width + * is smaller than `availableWidth`. This is useful when the text was previously + * wrapped by calling `constrainTextWidth` but now `availableWidth` changed, in + * which case, previous wrapping should be redo. + */ + + + function constrainTextWidth(layout, availableWidth, forceRecalculate) { + if (forceRecalculate === void 0) { + forceRecalculate = false; + } + + if (layout.labelStyleWidth != null) { + // User-defined style.width has the highest priority. + return; + } + + var label = layout.label; + var style = label.style; + var textRect = layout.rect; + var bgColor = style.backgroundColor; + var padding = style.padding; + var paddingH = padding ? padding[1] + padding[3] : 0; + var overflow = style.overflow; // textRect.width already contains paddingH if bgColor is set + + var oldOuterWidth = textRect.width + (bgColor ? 0 : paddingH); + + if (availableWidth < oldOuterWidth || forceRecalculate) { + var oldHeight = textRect.height; + + if (overflow && overflow.match('break')) { + // Temporarily set background to be null to calculate + // the bounding box without backgroud. + label.setStyle('backgroundColor', null); // Set constraining width + + label.setStyle('width', availableWidth - paddingH); // This is the real bounding box of the text without padding + + var innerRect = label.getBoundingRect(); + label.setStyle('width', Math.ceil(innerRect.width)); + label.setStyle('backgroundColor', bgColor); + } else { + var availableInnerWidth = availableWidth - paddingH; + var newWidth = availableWidth < oldOuterWidth // Current text is too wide, use `availableWidth` as max width. + ? availableInnerWidth : // Current available width is enough, but the text may have + // already been wrapped with a smaller available width. + forceRecalculate ? availableInnerWidth > layout.unconstrainedWidth // Current available is larger than text width, + // so don't constrain width (otherwise it may have + // empty space in the background). + ? null // Current available is smaller than text width, so + // use the current available width as constraining + // width. + : availableInnerWidth : // Current available width is enough, so no need to + // constrain. + null; + label.setStyle('width', newWidth); + } + + var newRect = label.getBoundingRect(); + textRect.width = newRect.width; + var margin = (label.style.margin || 0) + 2.1; + textRect.height = newRect.height + margin; + textRect.y -= (textRect.height - oldHeight) / 2; + } + } + + function isPositionCenter(sectorShape) { + // Not change x for center label + return sectorShape.position === 'center'; + } + + function pieLabelLayout(seriesModel) { + var data = seriesModel.getData(); + var labelLayoutList = []; + var cx; + var cy; + var hasLabelRotate = false; + var minShowLabelRadian = (seriesModel.get('minShowLabelAngle') || 0) * RADIAN$1; + var viewRect = data.getLayout('viewRect'); + var r = data.getLayout('r'); + var viewWidth = viewRect.width; + var viewLeft = viewRect.x; + var viewTop = viewRect.y; + var viewHeight = viewRect.height; + + function setNotShow(el) { + el.ignore = true; + } + + function isLabelShown(label) { + if (!label.ignore) { + return true; + } + + for (var key in label.states) { + if (label.states[key].ignore === false) { + return true; + } + } + + return false; + } + + data.each(function (idx) { + var sector = data.getItemGraphicEl(idx); + var sectorShape = sector.shape; + var label = sector.getTextContent(); + var labelLine = sector.getTextGuideLine(); + var itemModel = data.getItemModel(idx); + var labelModel = itemModel.getModel('label'); // Use position in normal or emphasis + + var labelPosition = labelModel.get('position') || itemModel.get(['emphasis', 'label', 'position']); + var labelDistance = labelModel.get('distanceToLabelLine'); + var labelAlignTo = labelModel.get('alignTo'); + var edgeDistance = parsePercent$1(labelModel.get('edgeDistance'), viewWidth); + var bleedMargin = labelModel.get('bleedMargin'); + var labelLineModel = itemModel.getModel('labelLine'); + var labelLineLen = labelLineModel.get('length'); + labelLineLen = parsePercent$1(labelLineLen, viewWidth); + var labelLineLen2 = labelLineModel.get('length2'); + labelLineLen2 = parsePercent$1(labelLineLen2, viewWidth); + + if (Math.abs(sectorShape.endAngle - sectorShape.startAngle) < minShowLabelRadian) { + each(label.states, setNotShow); + label.ignore = true; + return; + } + + if (!isLabelShown(label)) { + return; + } + + var midAngle = (sectorShape.startAngle + sectorShape.endAngle) / 2; + var nx = Math.cos(midAngle); + var ny = Math.sin(midAngle); + var textX; + var textY; + var linePoints; + var textAlign; + cx = sectorShape.cx; + cy = sectorShape.cy; + var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner'; + + if (labelPosition === 'center') { + textX = sectorShape.cx; + textY = sectorShape.cy; + textAlign = 'center'; + } else { + var x1 = (isLabelInside ? (sectorShape.r + sectorShape.r0) / 2 * nx : sectorShape.r * nx) + cx; + var y1 = (isLabelInside ? (sectorShape.r + sectorShape.r0) / 2 * ny : sectorShape.r * ny) + cy; + textX = x1 + nx * 3; + textY = y1 + ny * 3; + + if (!isLabelInside) { + // For roseType + var x2 = x1 + nx * (labelLineLen + r - sectorShape.r); + var y2 = y1 + ny * (labelLineLen + r - sectorShape.r); + var x3 = x2 + (nx < 0 ? -1 : 1) * labelLineLen2; + var y3 = y2; + + if (labelAlignTo === 'edge') { + // Adjust textX because text align of edge is opposite + textX = nx < 0 ? viewLeft + edgeDistance : viewLeft + viewWidth - edgeDistance; + } else { + textX = x3 + (nx < 0 ? -labelDistance : labelDistance); + } + + textY = y3; + linePoints = [[x1, y1], [x2, y2], [x3, y3]]; + } + + textAlign = isLabelInside ? 'center' : labelAlignTo === 'edge' ? nx > 0 ? 'right' : 'left' : nx > 0 ? 'left' : 'right'; + } + + var PI = Math.PI; + var labelRotate = 0; + var rotate = labelModel.get('rotate'); + + if (isNumber(rotate)) { + labelRotate = rotate * (PI / 180); + } else if (labelPosition === 'center') { + labelRotate = 0; + } else if (rotate === 'radial' || rotate === true) { + var radialAngle = nx < 0 ? -midAngle + PI : -midAngle; + labelRotate = radialAngle; + } else if (rotate === 'tangential' && labelPosition !== 'outside' && labelPosition !== 'outer') { + var rad = Math.atan2(nx, ny); + + if (rad < 0) { + rad = PI * 2 + rad; + } + + var isDown = ny > 0; + + if (isDown) { + rad = PI + rad; + } + + labelRotate = rad - PI; + } + + hasLabelRotate = !!labelRotate; + label.x = textX; + label.y = textY; + label.rotation = labelRotate; + label.setStyle({ + verticalAlign: 'middle' + }); // Not sectorShape the inside label + + if (!isLabelInside) { + var textRect = label.getBoundingRect().clone(); + textRect.applyTransform(label.getComputedTransform()); // Text has a default 1px stroke. Exclude this. + + var margin = (label.style.margin || 0) + 2.1; + textRect.y -= margin / 2; + textRect.height += margin; + labelLayoutList.push({ + label: label, + labelLine: labelLine, + position: labelPosition, + len: labelLineLen, + len2: labelLineLen2, + minTurnAngle: labelLineModel.get('minTurnAngle'), + maxSurfaceAngle: labelLineModel.get('maxSurfaceAngle'), + surfaceNormal: new Point(nx, ny), + linePoints: linePoints, + textAlign: textAlign, + labelDistance: labelDistance, + labelAlignTo: labelAlignTo, + edgeDistance: edgeDistance, + bleedMargin: bleedMargin, + rect: textRect, + unconstrainedWidth: textRect.width, + labelStyleWidth: label.style.width + }); + } else { + label.setStyle({ + align: textAlign + }); + var selectState = label.states.select; + + if (selectState) { + selectState.x += label.x; + selectState.y += label.y; + } + } + + sector.setTextConfig({ + inside: isLabelInside + }); + }); + + if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) { + avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, viewLeft, viewTop); + } + + for (var i = 0; i < labelLayoutList.length; i++) { + var layout = labelLayoutList[i]; + var label = layout.label; + var labelLine = layout.labelLine; + var notShowLabel = isNaN(label.x) || isNaN(label.y); + + if (label) { + label.setStyle({ + align: layout.textAlign + }); + + if (notShowLabel) { + each(label.states, setNotShow); + label.ignore = true; + } + + var selectState = label.states.select; + + if (selectState) { + selectState.x += label.x; + selectState.y += label.y; + } + } + + if (labelLine) { + var linePoints = layout.linePoints; + + if (notShowLabel || !linePoints) { + each(labelLine.states, setNotShow); + labelLine.ignore = true; + } else { + limitTurnAngle(linePoints, layout.minTurnAngle); + limitSurfaceAngle(linePoints, layout.surfaceNormal, layout.maxSurfaceAngle); + labelLine.setShape({ + points: linePoints + }); // Set the anchor to the midpoint of sector + + label.__hostTarget.textGuideLineConfig = { + anchor: new Point(linePoints[0][0], linePoints[0][1]) + }; + } + } + } + } + + function getSectorCornerRadius(model, shape, zeroIfNull) { + var cornerRadius = model.get('borderRadius'); + + if (cornerRadius == null) { + return zeroIfNull ? { + cornerRadius: 0 + } : null; + } + + if (!isArray(cornerRadius)) { + cornerRadius = [cornerRadius, cornerRadius, cornerRadius, cornerRadius]; + } + + var dr = Math.abs(shape.r || 0 - shape.r0 || 0); + return { + cornerRadius: map(cornerRadius, function (cr) { + return parsePercent(cr, dr); + }) + }; + } + + /** + * Piece of pie including Sector, Label, LabelLine + */ + + var PiePiece = + /** @class */ + function (_super) { + __extends(PiePiece, _super); + + function PiePiece(data, idx, startAngle) { + var _this = _super.call(this) || this; + + _this.z2 = 2; + var text = new ZRText(); + + _this.setTextContent(text); + + _this.updateData(data, idx, startAngle, true); + + return _this; + } + + PiePiece.prototype.updateData = function (data, idx, startAngle, firstCreate) { + var sector = this; + var seriesModel = data.hostModel; + var itemModel = data.getItemModel(idx); + var emphasisModel = itemModel.getModel('emphasis'); + var layout = data.getItemLayout(idx); // cornerRadius & innerCornerRadius doesn't exist in the item layout. Use `0` if null value is specified. + // see `setItemLayout` in `pieLayout.ts`. + + var sectorShape = extend(getSectorCornerRadius(itemModel.getModel('itemStyle'), layout, true), layout); // Ignore NaN data. + + if (isNaN(sectorShape.startAngle)) { + // Use NaN shape to avoid drawing shape. + sector.setShape(sectorShape); + return; + } + + if (firstCreate) { + sector.setShape(sectorShape); + var animationType = seriesModel.getShallow('animationType'); + + if (seriesModel.ecModel.ssr) { + // Use scale animation in SSR mode(opacity?) + // Because CSS SVG animation doesn't support very customized shape animation. + initProps(sector, { + scaleX: 0, + scaleY: 0 + }, seriesModel, { + dataIndex: idx, + isFrom: true + }); + sector.originX = sectorShape.cx; + sector.originY = sectorShape.cy; + } else if (animationType === 'scale') { + sector.shape.r = layout.r0; + initProps(sector, { + shape: { + r: layout.r + } + }, seriesModel, idx); + } // Expansion + else { + if (startAngle != null) { + sector.setShape({ + startAngle: startAngle, + endAngle: startAngle + }); + initProps(sector, { + shape: { + startAngle: layout.startAngle, + endAngle: layout.endAngle + } + }, seriesModel, idx); + } else { + sector.shape.endAngle = layout.startAngle; + updateProps(sector, { + shape: { + endAngle: layout.endAngle + } + }, seriesModel, idx); + } + } + } else { + saveOldStyle(sector); // Transition animation from the old shape + + updateProps(sector, { + shape: sectorShape + }, seriesModel, idx); + } + + sector.useStyle(data.getItemVisual(idx, 'style')); + setStatesStylesFromModel(sector, itemModel); + var midAngle = (layout.startAngle + layout.endAngle) / 2; + var offset = seriesModel.get('selectedOffset'); + var dx = Math.cos(midAngle) * offset; + var dy = Math.sin(midAngle) * offset; + var cursorStyle = itemModel.getShallow('cursor'); + cursorStyle && sector.attr('cursor', cursorStyle); + + this._updateLabel(seriesModel, data, idx); + + sector.ensureState('emphasis').shape = extend({ + r: layout.r + (emphasisModel.get('scale') ? emphasisModel.get('scaleSize') || 0 : 0) + }, getSectorCornerRadius(emphasisModel.getModel('itemStyle'), layout)); + extend(sector.ensureState('select'), { + x: dx, + y: dy, + shape: getSectorCornerRadius(itemModel.getModel(['select', 'itemStyle']), layout) + }); + extend(sector.ensureState('blur'), { + shape: getSectorCornerRadius(itemModel.getModel(['blur', 'itemStyle']), layout) + }); + var labelLine = sector.getTextGuideLine(); + var labelText = sector.getTextContent(); + labelLine && extend(labelLine.ensureState('select'), { + x: dx, + y: dy + }); // TODO: needs dx, dy in zrender? + + extend(labelText.ensureState('select'), { + x: dx, + y: dy + }); + toggleHoverEmphasis(this, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled')); + }; + + PiePiece.prototype._updateLabel = function (seriesModel, data, idx) { + var sector = this; + var itemModel = data.getItemModel(idx); + var labelLineModel = itemModel.getModel('labelLine'); + var style = data.getItemVisual(idx, 'style'); + var visualColor = style && style.fill; + var visualOpacity = style && style.opacity; + setLabelStyle(sector, getLabelStatesModels(itemModel), { + labelFetcher: data.hostModel, + labelDataIndex: idx, + inheritColor: visualColor, + defaultOpacity: visualOpacity, + defaultText: seriesModel.getFormattedLabel(idx, 'normal') || data.getName(idx) + }); + var labelText = sector.getTextContent(); // Set textConfig on sector. + + sector.setTextConfig({ + // reset position, rotation + position: null, + rotation: null + }); // Make sure update style on labelText after setLabelStyle. + // Because setLabelStyle will replace a new style on it. + + labelText.attr({ + z2: 10 + }); + var labelPosition = seriesModel.get(['label', 'position']); + + if (labelPosition !== 'outside' && labelPosition !== 'outer') { + sector.removeTextGuideLine(); + } else { + var polyline = this.getTextGuideLine(); + + if (!polyline) { + polyline = new Polyline(); + this.setTextGuideLine(polyline); + } // Default use item visual color + + + setLabelLineStyle(this, getLabelLineStatesModels(itemModel), { + stroke: visualColor, + opacity: retrieve3(labelLineModel.get(['lineStyle', 'opacity']), visualOpacity, 1) + }); + } + }; + + return PiePiece; + }(Sector); // Pie view + + + var PieView = + /** @class */ + function (_super) { + __extends(PieView, _super); + + function PieView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.ignoreLabelLineUpdate = true; + return _this; + } + + PieView.prototype.render = function (seriesModel, ecModel, api, payload) { + var data = seriesModel.getData(); + var oldData = this._data; + var group = this.group; + var startAngle; // First render + + if (!oldData && data.count() > 0) { + var shape = data.getItemLayout(0); + + for (var s = 1; isNaN(shape && shape.startAngle) && s < data.count(); ++s) { + shape = data.getItemLayout(s); + } + + if (shape) { + startAngle = shape.startAngle; + } + } // remove empty-circle if it exists + + + if (this._emptyCircleSector) { + group.remove(this._emptyCircleSector); + } // when all data are filtered, show lightgray empty circle + + + if (data.count() === 0 && seriesModel.get('showEmptyCircle')) { + var sector = new Sector({ + shape: getBasicPieLayout(seriesModel, api) + }); + sector.useStyle(seriesModel.getModel('emptyCircleStyle').getItemStyle()); + this._emptyCircleSector = sector; + group.add(sector); + } + + data.diff(oldData).add(function (idx) { + var piePiece = new PiePiece(data, idx, startAngle); + data.setItemGraphicEl(idx, piePiece); + group.add(piePiece); + }).update(function (newIdx, oldIdx) { + var piePiece = oldData.getItemGraphicEl(oldIdx); + piePiece.updateData(data, newIdx, startAngle); + piePiece.off('click'); + group.add(piePiece); + data.setItemGraphicEl(newIdx, piePiece); + }).remove(function (idx) { + var piePiece = oldData.getItemGraphicEl(idx); + removeElementWithFadeOut(piePiece, seriesModel, idx); + }).execute(); + pieLabelLayout(seriesModel); // Always use initial animation. + + if (seriesModel.get('animationTypeUpdate') !== 'expansion') { + this._data = data; + } + }; + + PieView.prototype.dispose = function () {}; + + PieView.prototype.containPoint = function (point, seriesModel) { + var data = seriesModel.getData(); + var itemLayout = data.getItemLayout(0); + + if (itemLayout) { + var dx = point[0] - itemLayout.cx; + var dy = point[1] - itemLayout.cy; + var radius = Math.sqrt(dx * dx + dy * dy); + return radius <= itemLayout.r && radius >= itemLayout.r0; + } + }; + + PieView.type = 'pie'; + return PieView; + }(ChartView); + + /** + * [Usage]: + * (1) + * createListSimply(seriesModel, ['value']); + * (2) + * createListSimply(seriesModel, { + * coordDimensions: ['value'], + * dimensionsCount: 5 + * }); + */ + + function createSeriesDataSimply(seriesModel, opt, nameList) { + opt = isArray(opt) && { + coordDimensions: opt + } || extend({ + encodeDefine: seriesModel.getEncode() + }, opt); + var source = seriesModel.getSource(); + var dimensions = prepareSeriesDataSchema(source, opt).dimensions; + var list = new SeriesData(dimensions, seriesModel); + list.initData(source, nameList); + return list; + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * LegendVisualProvider is an bridge that pick encoded color from data and + * provide to the legend component. + */ + var LegendVisualProvider = + /** @class */ + function () { + function LegendVisualProvider( // Function to get data after filtered. It stores all the encoding info + getDataWithEncodedVisual, // Function to get raw data before filtered. + getRawData) { + this._getDataWithEncodedVisual = getDataWithEncodedVisual; + this._getRawData = getRawData; + } + + LegendVisualProvider.prototype.getAllNames = function () { + var rawData = this._getRawData(); // We find the name from the raw data. In case it's filtered by the legend component. + // Normally, the name can be found in rawData, but can't be found in filtered data will display as gray. + + + return rawData.mapArray(rawData.getName); + }; + + LegendVisualProvider.prototype.containName = function (name) { + var rawData = this._getRawData(); + + return rawData.indexOfName(name) >= 0; + }; + + LegendVisualProvider.prototype.indexOfName = function (name) { + // Only get data when necessary. + // Because LegendVisualProvider constructor may be new in the stage that data is not prepared yet. + // Invoking Series#getData immediately will throw an error. + var dataWithEncodedVisual = this._getDataWithEncodedVisual(); + + return dataWithEncodedVisual.indexOfName(name); + }; + + LegendVisualProvider.prototype.getItemVisual = function (dataIndex, key) { + // Get encoded visual properties from final filtered data. + var dataWithEncodedVisual = this._getDataWithEncodedVisual(); + + return dataWithEncodedVisual.getItemVisual(dataIndex, key); + }; + + return LegendVisualProvider; + }(); + + var PieSeriesModel = + /** @class */ + function (_super) { + __extends(PieSeriesModel, _super); + + function PieSeriesModel() { + return _super !== null && _super.apply(this, arguments) || this; + } + /** + * @overwrite + */ + + + PieSeriesModel.prototype.init = function (option) { + _super.prototype.init.apply(this, arguments); // Enable legend selection for each data item + // Use a function instead of direct access because data reference may changed + + + this.legendVisualProvider = new LegendVisualProvider(bind(this.getData, this), bind(this.getRawData, this)); + + this._defaultLabelLine(option); + }; + /** + * @overwrite + */ + + + PieSeriesModel.prototype.mergeOption = function () { + _super.prototype.mergeOption.apply(this, arguments); + }; + /** + * @overwrite + */ + + + PieSeriesModel.prototype.getInitialData = function () { + return createSeriesDataSimply(this, { + coordDimensions: ['value'], + encodeDefaulter: curry(makeSeriesEncodeForNameBased, this) + }); + }; + /** + * @overwrite + */ + + + PieSeriesModel.prototype.getDataParams = function (dataIndex) { + var data = this.getData(); + + var params = _super.prototype.getDataParams.call(this, dataIndex); // FIXME toFixed? + + + var valueList = []; + data.each(data.mapDimension('value'), function (value) { + valueList.push(value); + }); + params.percent = getPercentWithPrecision(valueList, dataIndex, data.hostModel.get('percentPrecision')); + params.$vars.push('percent'); + return params; + }; + + PieSeriesModel.prototype._defaultLabelLine = function (option) { + // Extend labelLine emphasis + defaultEmphasis(option, 'labelLine', ['show']); + var labelLineNormalOpt = option.labelLine; + var labelLineEmphasisOpt = option.emphasis.labelLine; // Not show label line if `label.normal.show = false` + + labelLineNormalOpt.show = labelLineNormalOpt.show && option.label.show; + labelLineEmphasisOpt.show = labelLineEmphasisOpt.show && option.emphasis.label.show; + }; + + PieSeriesModel.type = 'series.pie'; + PieSeriesModel.defaultOption = { + // zlevel: 0, + z: 2, + legendHoverLink: true, + colorBy: 'data', + // 默认全局居中 + center: ['50%', '50%'], + radius: [0, '75%'], + // 默认顺时针 + clockwise: true, + startAngle: 90, + // 最小角度改为0 + minAngle: 0, + // If the angle of a sector less than `minShowLabelAngle`, + // the label will not be displayed. + minShowLabelAngle: 0, + // 选中时扇区偏移量 + selectedOffset: 10, + // 选择模式,默认关闭,可选single,multiple + // selectedMode: false, + // 南丁格尔玫瑰图模式,'radius'(半径) | 'area'(面积) + // roseType: null, + percentPrecision: 2, + // If still show when all data zero. + stillShowZeroSum: true, + // cursor: null, + left: 0, + top: 0, + right: 0, + bottom: 0, + width: null, + height: null, + label: { + // color: 'inherit', + // If rotate around circle + rotate: 0, + show: true, + overflow: 'truncate', + // 'outer', 'inside', 'center' + position: 'outer', + // 'none', 'labelLine', 'edge'. Works only when position is 'outer' + alignTo: 'none', + // Closest distance between label and chart edge. + // Works only position is 'outer' and alignTo is 'edge'. + edgeDistance: '25%', + // Works only position is 'outer' and alignTo is not 'edge'. + bleedMargin: 10, + // Distance between text and label line. + distanceToLabelLine: 5 // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调 + // 默认使用全局文本样式,详见TEXTSTYLE + // distance: 当position为inner时有效,为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数 + + }, + // Enabled when label.normal.position is 'outer' + labelLine: { + show: true, + // 引导线两段中的第一段长度 + length: 15, + // 引导线两段中的第二段长度 + length2: 15, + smooth: false, + minTurnAngle: 90, + maxSurfaceAngle: 90, + lineStyle: { + // color: 各异, + width: 1, + type: 'solid' + } + }, + itemStyle: { + borderWidth: 1, + borderJoin: 'round' + }, + showEmptyCircle: true, + emptyCircleStyle: { + color: 'lightgray', + opacity: 1 + }, + labelLayout: { + // Hide the overlapped label. + hideOverlap: true + }, + emphasis: { + scale: true, + scaleSize: 5 + }, + // If use strategy to avoid label overlapping + avoidLabelOverlap: true, + // Animation type. Valid values: expansion, scale + animationType: 'expansion', + animationDuration: 1000, + // Animation type when update. Valid values: transition, expansion + animationTypeUpdate: 'transition', + animationEasingUpdate: 'cubicInOut', + animationDurationUpdate: 500, + animationEasing: 'cubicInOut' + }; + return PieSeriesModel; + }(SeriesModel); + + function negativeDataFilter(seriesType) { + return { + seriesType: seriesType, + reset: function (seriesModel, ecModel) { + var data = seriesModel.getData(); + data.filterSelf(function (idx) { + // handle negative value condition + var valueDim = data.mapDimension('value'); + var curValue = data.get(valueDim, idx); + + if (isNumber(curValue) && !isNaN(curValue) && curValue < 0) { + return false; + } + + return true; + }); + } + }; + } + + function install$4(registers) { + registers.registerChartView(PieView); + registers.registerSeriesModel(PieSeriesModel); + createLegacyDataSelectAction('pie', registers.registerAction); + registers.registerLayout(curry(pieLayout, 'pie')); + registers.registerProcessor(dataFilter('pie')); + registers.registerProcessor(negativeDataFilter('pie')); + } + + var ScatterSeriesModel = + /** @class */ + function (_super) { + __extends(ScatterSeriesModel, _super); + + function ScatterSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ScatterSeriesModel.type; + _this.hasSymbolVisual = true; + return _this; + } + + ScatterSeriesModel.prototype.getInitialData = function (option, ecModel) { + return createSeriesData(null, this, { + useEncodeDefaulter: true + }); + }; + + ScatterSeriesModel.prototype.getProgressive = function () { + var progressive = this.option.progressive; + + if (progressive == null) { + // PENDING + return this.option.large ? 5e3 : this.get('progressive'); + } + + return progressive; + }; + + ScatterSeriesModel.prototype.getProgressiveThreshold = function () { + var progressiveThreshold = this.option.progressiveThreshold; + + if (progressiveThreshold == null) { + // PENDING + return this.option.large ? 1e4 : this.get('progressiveThreshold'); + } + + return progressiveThreshold; + }; + + ScatterSeriesModel.prototype.brushSelector = function (dataIndex, data, selectors) { + return selectors.point(data.getItemLayout(dataIndex)); + }; + + ScatterSeriesModel.prototype.getZLevelKey = function () { + // Each progressive series has individual key. + return this.getData().count() > this.getProgressiveThreshold() ? this.id : ''; + }; + + ScatterSeriesModel.type = 'series.scatter'; + ScatterSeriesModel.dependencies = ['grid', 'polar', 'geo', 'singleAxis', 'calendar']; + ScatterSeriesModel.defaultOption = { + coordinateSystem: 'cartesian2d', + // zlevel: 0, + z: 2, + legendHoverLink: true, + symbolSize: 10, + // symbolRotate: null, // 图形旋转控制 + large: false, + // Available when large is true + largeThreshold: 2000, + // cursor: null, + itemStyle: { + opacity: 0.8 // color: 各异 + + }, + emphasis: { + scale: true + }, + // If clip the overflow graphics + // Works on cartesian / polar series + clip: true, + select: { + itemStyle: { + borderColor: '#212121' + } + }, + universalTransition: { + divideShape: 'clone' + } // progressive: null + + }; + return ScatterSeriesModel; + }(SeriesModel); + + var BOOST_SIZE_THRESHOLD = 4; + + var LargeSymbolPathShape = + /** @class */ + function () { + function LargeSymbolPathShape() {} + + return LargeSymbolPathShape; + }(); + + var LargeSymbolPath = + /** @class */ + function (_super) { + __extends(LargeSymbolPath, _super); + + function LargeSymbolPath(opts) { + var _this = _super.call(this, opts) || this; + + _this._off = 0; + _this.hoverDataIdx = -1; + return _this; + } + + LargeSymbolPath.prototype.getDefaultShape = function () { + return new LargeSymbolPathShape(); + }; + + LargeSymbolPath.prototype.reset = function () { + this.notClear = false; + this._off = 0; + }; + + LargeSymbolPath.prototype.buildPath = function (path, shape) { + var points = shape.points; + var size = shape.size; + var symbolProxy = this.symbolProxy; + var symbolProxyShape = symbolProxy.shape; + var ctx = path.getContext ? path.getContext() : path; + var canBoost = ctx && size[0] < BOOST_SIZE_THRESHOLD; + var softClipShape = this.softClipShape; + var i; // Do draw in afterBrush. + + if (canBoost) { + this._ctx = ctx; + return; + } + + this._ctx = null; + + for (i = this._off; i < points.length;) { + var x = points[i++]; + var y = points[i++]; + + if (isNaN(x) || isNaN(y)) { + continue; + } + + if (softClipShape && !softClipShape.contain(x, y)) { + continue; + } + + symbolProxyShape.x = x - size[0] / 2; + symbolProxyShape.y = y - size[1] / 2; + symbolProxyShape.width = size[0]; + symbolProxyShape.height = size[1]; + symbolProxy.buildPath(path, symbolProxyShape, true); + } + + if (this.incremental) { + this._off = i; + this.notClear = true; + } + }; + + LargeSymbolPath.prototype.afterBrush = function () { + var shape = this.shape; + var points = shape.points; + var size = shape.size; + var ctx = this._ctx; + var softClipShape = this.softClipShape; + var i; + + if (!ctx) { + return; + } // PENDING If style or other canvas status changed? + + + for (i = this._off; i < points.length;) { + var x = points[i++]; + var y = points[i++]; + + if (isNaN(x) || isNaN(y)) { + continue; + } + + if (softClipShape && !softClipShape.contain(x, y)) { + continue; + } // fillRect is faster than building a rect path and draw. + // And it support light globalCompositeOperation. + + + ctx.fillRect(x - size[0] / 2, y - size[1] / 2, size[0], size[1]); + } + + if (this.incremental) { + this._off = i; + this.notClear = true; + } + }; + + LargeSymbolPath.prototype.findDataIndex = function (x, y) { + // TODO ??? + // Consider transform + var shape = this.shape; + var points = shape.points; + var size = shape.size; + var w = Math.max(size[0], 4); + var h = Math.max(size[1], 4); // Not consider transform + // Treat each element as a rect + // top down traverse + + for (var idx = points.length / 2 - 1; idx >= 0; idx--) { + var i = idx * 2; + var x0 = points[i] - w / 2; + var y0 = points[i + 1] - h / 2; + + if (x >= x0 && y >= y0 && x <= x0 + w && y <= y0 + h) { + return idx; + } + } + + return -1; + }; + + LargeSymbolPath.prototype.contain = function (x, y) { + var localPos = this.transformCoordToLocal(x, y); + var rect = this.getBoundingRect(); + x = localPos[0]; + y = localPos[1]; + + if (rect.contain(x, y)) { + // Cache found data index. + var dataIdx = this.hoverDataIdx = this.findDataIndex(x, y); + return dataIdx >= 0; + } + + this.hoverDataIdx = -1; + return false; + }; + + LargeSymbolPath.prototype.getBoundingRect = function () { + // Ignore stroke for large symbol draw. + var rect = this._rect; + + if (!rect) { + var shape = this.shape; + var points = shape.points; + var size = shape.size; + var w = size[0]; + var h = size[1]; + var minX = Infinity; + var minY = Infinity; + var maxX = -Infinity; + var maxY = -Infinity; + + for (var i = 0; i < points.length;) { + var x = points[i++]; + var y = points[i++]; + minX = Math.min(x, minX); + maxX = Math.max(x, maxX); + minY = Math.min(y, minY); + maxY = Math.max(y, maxY); + } + + rect = this._rect = new BoundingRect(minX - w / 2, minY - h / 2, maxX - minX + w, maxY - minY + h); + } + + return rect; + }; + + return LargeSymbolPath; + }(Path); + + var LargeSymbolDraw = + /** @class */ + function () { + function LargeSymbolDraw() { + this.group = new Group(); + } + /** + * Update symbols draw by new data + */ + + + LargeSymbolDraw.prototype.updateData = function (data, opt) { + this._clear(); + + var symbolEl = this._create(); + + symbolEl.setShape({ + points: data.getLayout('points') + }); + + this._setCommon(symbolEl, data, opt); + }; + + LargeSymbolDraw.prototype.updateLayout = function (data) { + var points = data.getLayout('points'); + this.group.eachChild(function (child) { + if (child.startIndex != null) { + var len = (child.endIndex - child.startIndex) * 2; + var byteOffset = child.startIndex * 4 * 2; + points = new Float32Array(points.buffer, byteOffset, len); + } + + child.setShape('points', points); // Reset draw cursor. + + child.reset(); + }); + }; + + LargeSymbolDraw.prototype.incrementalPrepareUpdate = function (data) { + this._clear(); + }; + + LargeSymbolDraw.prototype.incrementalUpdate = function (taskParams, data, opt) { + var lastAdded = this._newAdded[0]; + var points = data.getLayout('points'); + var oldPoints = lastAdded && lastAdded.shape.points; // Merging the exists. Each element has 1e4 points. + // Consider the performance balance between too much elements and too much points in one shape(may affect hover optimization) + + if (oldPoints && oldPoints.length < 2e4) { + var oldLen = oldPoints.length; + var newPoints = new Float32Array(oldLen + points.length); // Concat two array + + newPoints.set(oldPoints); + newPoints.set(points, oldLen); // Update endIndex + + lastAdded.endIndex = taskParams.end; + lastAdded.setShape({ + points: newPoints + }); + } else { + // Clear + this._newAdded = []; + + var symbolEl = this._create(); + + symbolEl.startIndex = taskParams.start; + symbolEl.endIndex = taskParams.end; + symbolEl.incremental = true; + symbolEl.setShape({ + points: points + }); + + this._setCommon(symbolEl, data, opt); + } + }; + + LargeSymbolDraw.prototype.eachRendered = function (cb) { + this._newAdded[0] && cb(this._newAdded[0]); + }; + + LargeSymbolDraw.prototype._create = function () { + var symbolEl = new LargeSymbolPath({ + cursor: 'default' + }); + this.group.add(symbolEl); + + this._newAdded.push(symbolEl); + + return symbolEl; + }; + + LargeSymbolDraw.prototype._setCommon = function (symbolEl, data, opt) { + var hostModel = data.hostModel; + opt = opt || {}; + var size = data.getVisual('symbolSize'); + symbolEl.setShape('size', size instanceof Array ? size : [size, size]); + symbolEl.softClipShape = opt.clipShape || null; // Create symbolProxy to build path for each data + + symbolEl.symbolProxy = createSymbol(data.getVisual('symbol'), 0, 0, 0, 0); // Use symbolProxy setColor method + + symbolEl.setColor = symbolEl.symbolProxy.setColor; + var extrudeShadow = symbolEl.shape.size[0] < BOOST_SIZE_THRESHOLD; + symbolEl.useStyle( // Draw shadow when doing fillRect is extremely slow. + hostModel.getModel('itemStyle').getItemStyle(extrudeShadow ? ['color', 'shadowBlur', 'shadowColor'] : ['color'])); + var globalStyle = data.getVisual('style'); + var visualColor = globalStyle && globalStyle.fill; + + if (visualColor) { + symbolEl.setColor(visualColor); + } + + var ecData = getECData(symbolEl); // Enable tooltip + // PENDING May have performance issue when path is extremely large + + ecData.seriesIndex = hostModel.seriesIndex; + symbolEl.on('mousemove', function (e) { + ecData.dataIndex = null; + var dataIndex = symbolEl.hoverDataIdx; + + if (dataIndex >= 0) { + // Provide dataIndex for tooltip + ecData.dataIndex = dataIndex + (symbolEl.startIndex || 0); + } + }); + }; + + LargeSymbolDraw.prototype.remove = function () { + this._clear(); + }; + + LargeSymbolDraw.prototype._clear = function () { + this._newAdded = []; + this.group.removeAll(); + }; + + return LargeSymbolDraw; + }(); + + var ScatterView = + /** @class */ + function (_super) { + __extends(ScatterView, _super); + + function ScatterView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ScatterView.type; + return _this; + } + + ScatterView.prototype.render = function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + + var symbolDraw = this._updateSymbolDraw(data, seriesModel); + + symbolDraw.updateData(data, { + // TODO + // If this parameter should be a shape or a bounding volume + // shape will be more general. + // But bounding volume like bounding rect will be much faster in the contain calculation + clipShape: this._getClipShape(seriesModel) + }); + this._finished = true; + }; + + ScatterView.prototype.incrementalPrepareRender = function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + + var symbolDraw = this._updateSymbolDraw(data, seriesModel); + + symbolDraw.incrementalPrepareUpdate(data); + this._finished = false; + }; + + ScatterView.prototype.incrementalRender = function (taskParams, seriesModel, ecModel) { + this._symbolDraw.incrementalUpdate(taskParams, seriesModel.getData(), { + clipShape: this._getClipShape(seriesModel) + }); + + this._finished = taskParams.end === seriesModel.getData().count(); + }; + + ScatterView.prototype.updateTransform = function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); // Must mark group dirty and make sure the incremental layer will be cleared + // PENDING + + this.group.dirty(); + + if (!this._finished || data.count() > 1e4) { + return { + update: true + }; + } else { + var res = pointsLayout('').reset(seriesModel, ecModel, api); + + if (res.progress) { + res.progress({ + start: 0, + end: data.count(), + count: data.count() + }, data); + } + + this._symbolDraw.updateLayout(data); + } + }; + + ScatterView.prototype.eachRendered = function (cb) { + this._symbolDraw && this._symbolDraw.eachRendered(cb); + }; + + ScatterView.prototype._getClipShape = function (seriesModel) { + var coordSys = seriesModel.coordinateSystem; + var clipArea = coordSys && coordSys.getArea && coordSys.getArea(); + return seriesModel.get('clip', true) ? clipArea : null; + }; + + ScatterView.prototype._updateSymbolDraw = function (data, seriesModel) { + var symbolDraw = this._symbolDraw; + var pipelineContext = seriesModel.pipelineContext; + var isLargeDraw = pipelineContext.large; + + if (!symbolDraw || isLargeDraw !== this._isLargeDraw) { + symbolDraw && symbolDraw.remove(); + symbolDraw = this._symbolDraw = isLargeDraw ? new LargeSymbolDraw() : new SymbolDraw(); + this._isLargeDraw = isLargeDraw; + this.group.removeAll(); + } + + this.group.add(symbolDraw.group); + return symbolDraw; + }; + + ScatterView.prototype.remove = function (ecModel, api) { + this._symbolDraw && this._symbolDraw.remove(true); + this._symbolDraw = null; + }; + + ScatterView.prototype.dispose = function () {}; + + ScatterView.type = 'scatter'; + return ScatterView; + }(ChartView); + + var GridModel = + /** @class */ + function (_super) { + __extends(GridModel, _super); + + function GridModel() { + return _super !== null && _super.apply(this, arguments) || this; + } + + GridModel.type = 'grid'; + GridModel.dependencies = ['xAxis', 'yAxis']; + GridModel.layoutMode = 'box'; + GridModel.defaultOption = { + show: false, + // zlevel: 0, + z: 0, + left: '10%', + top: 60, + right: '10%', + bottom: 70, + // If grid size contain label + containLabel: false, + // width: {totalWidth} - left - right, + // height: {totalHeight} - top - bottom, + backgroundColor: 'rgba(0,0,0,0)', + borderWidth: 1, + borderColor: '#ccc' + }; + return GridModel; + }(ComponentModel); + + var CartesianAxisModel = + /** @class */ + function (_super) { + __extends(CartesianAxisModel, _super); + + function CartesianAxisModel() { + return _super !== null && _super.apply(this, arguments) || this; + } + + CartesianAxisModel.prototype.getCoordSysModel = function () { + return this.getReferringComponents('grid', SINGLE_REFERRING).models[0]; + }; + + CartesianAxisModel.type = 'cartesian2dAxis'; + return CartesianAxisModel; + }(ComponentModel); + mixin(CartesianAxisModel, AxisModelCommonMixin); + + var defaultOption = { + show: true, + // zlevel: 0, + z: 0, + // Inverse the axis. + inverse: false, + // Axis name displayed. + name: '', + // 'start' | 'middle' | 'end' + nameLocation: 'end', + // By degree. By default auto rotate by nameLocation. + nameRotate: null, + nameTruncate: { + maxWidth: null, + ellipsis: '...', + placeholder: '.' + }, + // Use global text style by default. + nameTextStyle: {}, + // The gap between axisName and axisLine. + nameGap: 15, + // Default `false` to support tooltip. + silent: false, + // Default `false` to avoid legacy user event listener fail. + triggerEvent: false, + tooltip: { + show: false + }, + axisPointer: {}, + axisLine: { + show: true, + onZero: true, + onZeroAxisIndex: null, + lineStyle: { + color: '#6E7079', + width: 1, + type: 'solid' + }, + // The arrow at both ends the the axis. + symbol: ['none', 'none'], + symbolSize: [10, 15] + }, + axisTick: { + show: true, + // Whether axisTick is inside the grid or outside the grid. + inside: false, + // The length of axisTick. + length: 5, + lineStyle: { + width: 1 + } + }, + axisLabel: { + show: true, + // Whether axisLabel is inside the grid or outside the grid. + inside: false, + rotate: 0, + // true | false | null/undefined (auto) + showMinLabel: null, + // true | false | null/undefined (auto) + showMaxLabel: null, + margin: 8, + // formatter: null, + fontSize: 12 + }, + splitLine: { + show: true, + lineStyle: { + color: ['#E0E6F1'], + width: 1, + type: 'solid' + } + }, + splitArea: { + show: false, + areaStyle: { + color: ['rgba(250,250,250,0.2)', 'rgba(210,219,238,0.2)'] + } + } + }; + var categoryAxis = merge({ + // The gap at both ends of the axis. For categoryAxis, boolean. + boundaryGap: true, + // Set false to faster category collection. + deduplication: null, + // splitArea: { + // show: false + // }, + splitLine: { + show: false + }, + axisTick: { + // If tick is align with label when boundaryGap is true + alignWithLabel: false, + interval: 'auto' + }, + axisLabel: { + interval: 'auto' + } + }, defaultOption); + var valueAxis = merge({ + boundaryGap: [0, 0], + axisLine: { + // Not shown when other axis is categoryAxis in cartesian + show: 'auto' + }, + axisTick: { + // Not shown when other axis is categoryAxis in cartesian + show: 'auto' + }, + // TODO + // min/max: [30, datamin, 60] or [20, datamin] or [datamin, 60] + splitNumber: 5, + minorTick: { + // Minor tick, not available for cateogry axis. + show: false, + // Split number of minor ticks. The value should be in range of (0, 100) + splitNumber: 5, + // Lenght of minor tick + length: 3, + // Line style + lineStyle: {// Default to be same with axisTick + } + }, + minorSplitLine: { + show: false, + lineStyle: { + color: '#F4F7FD', + width: 1 + } + } + }, defaultOption); + var timeAxis = merge({ + splitNumber: 6, + axisLabel: { + // To eliminate labels that are not nice + showMinLabel: false, + showMaxLabel: false, + rich: { + primary: { + fontWeight: 'bold' + } + } + }, + splitLine: { + show: false + } + }, valueAxis); + var logAxis = defaults({ + logBase: 10 + }, valueAxis); + var axisDefault = { + category: categoryAxis, + value: valueAxis, + time: timeAxis, + log: logAxis + }; + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + var AXIS_TYPES = { + value: 1, + category: 1, + time: 1, + log: 1 + }; + + /** + * Generate sub axis model class + * @param axisName 'x' 'y' 'radius' 'angle' 'parallel' ... + */ + + function axisModelCreator(registers, axisName, BaseAxisModelClass, extraDefaultOption) { + each(AXIS_TYPES, function (v, axisType) { + var defaultOption = merge(merge({}, axisDefault[axisType], true), extraDefaultOption, true); + + var AxisModel = + /** @class */ + function (_super) { + __extends(AxisModel, _super); + + function AxisModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = axisName + 'Axis.' + axisType; + return _this; + } + + AxisModel.prototype.mergeDefaultAndTheme = function (option, ecModel) { + var layoutMode = fetchLayoutMode(this); + var inputPositionParams = layoutMode ? getLayoutParams(option) : {}; + var themeModel = ecModel.getTheme(); + merge(option, themeModel.get(axisType + 'Axis')); + merge(option, this.getDefaultOption()); + option.type = getAxisType(option); + + if (layoutMode) { + mergeLayoutParam(option, inputPositionParams, layoutMode); + } + }; + + AxisModel.prototype.optionUpdated = function () { + var thisOption = this.option; + + if (thisOption.type === 'category') { + this.__ordinalMeta = OrdinalMeta.createByAxisModel(this); + } + }; + /** + * Should not be called before all of 'getInitailData' finished. + * Because categories are collected during initializing data. + */ + + + AxisModel.prototype.getCategories = function (rawData) { + var option = this.option; // FIXME + // warning if called before all of 'getInitailData' finished. + + if (option.type === 'category') { + if (rawData) { + return option.data; + } + + return this.__ordinalMeta.categories; + } + }; + + AxisModel.prototype.getOrdinalMeta = function () { + return this.__ordinalMeta; + }; + + AxisModel.type = axisName + 'Axis.' + axisType; + AxisModel.defaultOption = defaultOption; + return AxisModel; + }(BaseAxisModelClass); + + registers.registerComponentModel(AxisModel); + }); + registers.registerSubTypeDefaulter(axisName + 'Axis', getAxisType); + } + + function getAxisType(option) { + // Default axis with data is category axis + return option.type || (option.data ? 'category' : 'value'); + } + + var Cartesian = + /** @class */ + function () { + function Cartesian(name) { + this.type = 'cartesian'; + this._dimList = []; + this._axes = {}; + this.name = name || ''; + } + + Cartesian.prototype.getAxis = function (dim) { + return this._axes[dim]; + }; + + Cartesian.prototype.getAxes = function () { + return map(this._dimList, function (dim) { + return this._axes[dim]; + }, this); + }; + + Cartesian.prototype.getAxesByScale = function (scaleType) { + scaleType = scaleType.toLowerCase(); + return filter(this.getAxes(), function (axis) { + return axis.scale.type === scaleType; + }); + }; + + Cartesian.prototype.addAxis = function (axis) { + var dim = axis.dim; + this._axes[dim] = axis; + + this._dimList.push(dim); + }; + + return Cartesian; + }(); + + var cartesian2DDimensions = ['x', 'y']; + + function canCalculateAffineTransform(scale) { + return scale.type === 'interval' || scale.type === 'time'; + } + + var Cartesian2D = + /** @class */ + function (_super) { + __extends(Cartesian2D, _super); + + function Cartesian2D() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'cartesian2d'; + _this.dimensions = cartesian2DDimensions; + return _this; + } + /** + * Calculate an affine transform matrix if two axes are time or value. + * It's mainly for accelartion on the large time series data. + */ + + + Cartesian2D.prototype.calcAffineTransform = function () { + this._transform = this._invTransform = null; + var xAxisScale = this.getAxis('x').scale; + var yAxisScale = this.getAxis('y').scale; + + if (!canCalculateAffineTransform(xAxisScale) || !canCalculateAffineTransform(yAxisScale)) { + return; + } + + var xScaleExtent = xAxisScale.getExtent(); + var yScaleExtent = yAxisScale.getExtent(); + var start = this.dataToPoint([xScaleExtent[0], yScaleExtent[0]]); + var end = this.dataToPoint([xScaleExtent[1], yScaleExtent[1]]); + var xScaleSpan = xScaleExtent[1] - xScaleExtent[0]; + var yScaleSpan = yScaleExtent[1] - yScaleExtent[0]; + + if (!xScaleSpan || !yScaleSpan) { + return; + } // Accelerate data to point calculation on the special large time series data. + + + var scaleX = (end[0] - start[0]) / xScaleSpan; + var scaleY = (end[1] - start[1]) / yScaleSpan; + var translateX = start[0] - xScaleExtent[0] * scaleX; + var translateY = start[1] - yScaleExtent[0] * scaleY; + var m = this._transform = [scaleX, 0, 0, scaleY, translateX, translateY]; + this._invTransform = invert([], m); + }; + /** + * Base axis will be used on stacking. + */ + + + Cartesian2D.prototype.getBaseAxis = function () { + return this.getAxesByScale('ordinal')[0] || this.getAxesByScale('time')[0] || this.getAxis('x'); + }; + + Cartesian2D.prototype.containPoint = function (point) { + var axisX = this.getAxis('x'); + var axisY = this.getAxis('y'); + return axisX.contain(axisX.toLocalCoord(point[0])) && axisY.contain(axisY.toLocalCoord(point[1])); + }; + + Cartesian2D.prototype.containData = function (data) { + return this.getAxis('x').containData(data[0]) && this.getAxis('y').containData(data[1]); + }; + + Cartesian2D.prototype.dataToPoint = function (data, clamp, out) { + out = out || []; + var xVal = data[0]; + var yVal = data[1]; // Fast path + + if (this._transform // It's supported that if data is like `[Inifity, 123]`, where only Y pixel calculated. + && xVal != null && isFinite(xVal) && yVal != null && isFinite(yVal)) { + return applyTransform(out, data, this._transform); + } + + var xAxis = this.getAxis('x'); + var yAxis = this.getAxis('y'); + out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(xVal, clamp)); + out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(yVal, clamp)); + return out; + }; + + Cartesian2D.prototype.clampData = function (data, out) { + var xScale = this.getAxis('x').scale; + var yScale = this.getAxis('y').scale; + var xAxisExtent = xScale.getExtent(); + var yAxisExtent = yScale.getExtent(); + var x = xScale.parse(data[0]); + var y = yScale.parse(data[1]); + out = out || []; + out[0] = Math.min(Math.max(Math.min(xAxisExtent[0], xAxisExtent[1]), x), Math.max(xAxisExtent[0], xAxisExtent[1])); + out[1] = Math.min(Math.max(Math.min(yAxisExtent[0], yAxisExtent[1]), y), Math.max(yAxisExtent[0], yAxisExtent[1])); + return out; + }; + + Cartesian2D.prototype.pointToData = function (point, clamp) { + var out = []; + + if (this._invTransform) { + return applyTransform(out, point, this._invTransform); + } + + var xAxis = this.getAxis('x'); + var yAxis = this.getAxis('y'); + out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0]), clamp); + out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1]), clamp); + return out; + }; + + Cartesian2D.prototype.getOtherAxis = function (axis) { + return this.getAxis(axis.dim === 'x' ? 'y' : 'x'); + }; + /** + * Get rect area of cartesian. + * Area will have a contain function to determine if a point is in the coordinate system. + */ + + + Cartesian2D.prototype.getArea = function () { + var xExtent = this.getAxis('x').getGlobalExtent(); + var yExtent = this.getAxis('y').getGlobalExtent(); + var x = Math.min(xExtent[0], xExtent[1]); + var y = Math.min(yExtent[0], yExtent[1]); + var width = Math.max(xExtent[0], xExtent[1]) - x; + var height = Math.max(yExtent[0], yExtent[1]) - y; + return new BoundingRect(x, y, width, height); + }; + + return Cartesian2D; + }(Cartesian); + + var Axis2D = + /** @class */ + function (_super) { + __extends(Axis2D, _super); + + function Axis2D(dim, scale, coordExtent, axisType, position) { + var _this = _super.call(this, dim, scale, coordExtent) || this; + /** + * Index of axis, can be used as key + * Injected outside. + */ + + + _this.index = 0; + _this.type = axisType || 'value'; + _this.position = position || 'bottom'; + return _this; + } + + Axis2D.prototype.isHorizontal = function () { + var position = this.position; + return position === 'top' || position === 'bottom'; + }; + /** + * Each item cooresponds to this.getExtent(), which + * means globalExtent[0] may greater than globalExtent[1], + * unless `asc` is input. + * + * @param {boolean} [asc] + * @return {Array.} + */ + + + Axis2D.prototype.getGlobalExtent = function (asc) { + var ret = this.getExtent(); + ret[0] = this.toGlobalCoord(ret[0]); + ret[1] = this.toGlobalCoord(ret[1]); + asc && ret[0] > ret[1] && ret.reverse(); + return ret; + }; + + Axis2D.prototype.pointToData = function (point, clamp) { + return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp); + }; + /** + * Set ordinalSortInfo + * @param info new OrdinalSortInfo + */ + + + Axis2D.prototype.setCategorySortInfo = function (info) { + if (this.type !== 'category') { + return false; + } + + this.model.option.categorySortInfo = info; + this.scale.setSortInfo(info); + }; + + return Axis2D; + }(Axis); + + /** + * Can only be called after coordinate system creation stage. + * (Can be called before coordinate system update stage). + */ + + function layout$1(gridModel, axisModel, opt) { + opt = opt || {}; + var grid = gridModel.coordinateSystem; + var axis = axisModel.axis; + var layout = {}; + var otherAxisOnZeroOf = axis.getAxesOnZeroOf()[0]; + var rawAxisPosition = axis.position; + var axisPosition = otherAxisOnZeroOf ? 'onZero' : rawAxisPosition; + var axisDim = axis.dim; + var rect = grid.getRect(); + var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height]; + var idx = { + left: 0, + right: 1, + top: 0, + bottom: 1, + onZero: 2 + }; + var axisOffset = axisModel.get('offset') || 0; + var posBound = axisDim === 'x' ? [rectBound[2] - axisOffset, rectBound[3] + axisOffset] : [rectBound[0] - axisOffset, rectBound[1] + axisOffset]; + + if (otherAxisOnZeroOf) { + var onZeroCoord = otherAxisOnZeroOf.toGlobalCoord(otherAxisOnZeroOf.dataToCoord(0)); + posBound[idx.onZero] = Math.max(Math.min(onZeroCoord, posBound[1]), posBound[0]); + } // Axis position + + + layout.position = [axisDim === 'y' ? posBound[idx[axisPosition]] : rectBound[0], axisDim === 'x' ? posBound[idx[axisPosition]] : rectBound[3]]; // Axis rotation + + layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1); // Tick and label direction, x y is axisDim + + var dirMap = { + top: -1, + bottom: 1, + left: -1, + right: 1 + }; + layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition]; + layout.labelOffset = otherAxisOnZeroOf ? posBound[idx[rawAxisPosition]] - posBound[idx.onZero] : 0; + + if (axisModel.get(['axisTick', 'inside'])) { + layout.tickDirection = -layout.tickDirection; + } + + if (retrieve(opt.labelInside, axisModel.get(['axisLabel', 'inside']))) { + layout.labelDirection = -layout.labelDirection; + } // Special label rotation + + + var labelRotate = axisModel.get(['axisLabel', 'rotate']); + layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate; // Over splitLine and splitArea + + layout.z2 = 1; + return layout; + } + function isCartesian2DSeries(seriesModel) { + return seriesModel.get('coordinateSystem') === 'cartesian2d'; + } + function findAxisModels(seriesModel) { + var axisModelMap = { + xAxisModel: null, + yAxisModel: null + }; + each(axisModelMap, function (v, key) { + var axisType = key.replace(/Model$/, ''); + var axisModel = seriesModel.getReferringComponents(axisType, SINGLE_REFERRING).models[0]; + + if ("development" !== 'production') { + if (!axisModel) { + throw new Error(axisType + ' "' + retrieve3(seriesModel.get(axisType + 'Index'), seriesModel.get(axisType + 'Id'), 0) + '" not found'); + } + } + + axisModelMap[key] = axisModel; + }); + return axisModelMap; + } + + var mathLog$1 = Math.log; + function alignScaleTicks(scale, axisModel, alignToScale) { + var intervalScaleProto = IntervalScale.prototype; // NOTE: There is a precondition for log scale here: + // In log scale we store _interval and _extent of exponent value. + // So if we use the method of InternalScale to set/get these data. + // It process the exponent value, which is linear and what we want here. + + var alignToTicks = intervalScaleProto.getTicks.call(alignToScale); + var alignToNicedTicks = intervalScaleProto.getTicks.call(alignToScale, true); + var alignToSplitNumber = alignToTicks.length - 1; + var alignToInterval = intervalScaleProto.getInterval.call(alignToScale); + var scaleExtent = getScaleExtent(scale, axisModel); + var rawExtent = scaleExtent.extent; + var isMinFixed = scaleExtent.fixMin; + var isMaxFixed = scaleExtent.fixMax; + + if (scale.type === 'log') { + var logBase = mathLog$1(scale.base); + rawExtent = [mathLog$1(rawExtent[0]) / logBase, mathLog$1(rawExtent[1]) / logBase]; + } + + scale.setExtent(rawExtent[0], rawExtent[1]); + scale.calcNiceExtent({ + splitNumber: alignToSplitNumber, + fixMin: isMinFixed, + fixMax: isMaxFixed + }); + var extent = intervalScaleProto.getExtent.call(scale); // Need to update the rawExtent. + // Because value in rawExtent may be not parsed. e.g. 'dataMin', 'dataMax' + + if (isMinFixed) { + rawExtent[0] = extent[0]; + } + + if (isMaxFixed) { + rawExtent[1] = extent[1]; + } + + var interval = intervalScaleProto.getInterval.call(scale); + var min = rawExtent[0]; + var max = rawExtent[1]; + + if (isMinFixed && isMaxFixed) { + // User set min, max, divide to get new interval + interval = (max - min) / alignToSplitNumber; + } else if (isMinFixed) { + max = rawExtent[0] + interval * alignToSplitNumber; // User set min, expand extent on the other side + + while (max < rawExtent[1] && isFinite(max) && isFinite(rawExtent[1])) { + interval = increaseInterval(interval); + max = rawExtent[0] + interval * alignToSplitNumber; + } + } else if (isMaxFixed) { + // User set max, expand extent on the other side + min = rawExtent[1] - interval * alignToSplitNumber; + + while (min > rawExtent[0] && isFinite(min) && isFinite(rawExtent[0])) { + interval = increaseInterval(interval); + min = rawExtent[1] - interval * alignToSplitNumber; + } + } else { + var nicedSplitNumber = scale.getTicks().length - 1; + + if (nicedSplitNumber > alignToSplitNumber) { + interval = increaseInterval(interval); + } + + var range = interval * alignToSplitNumber; + max = Math.ceil(rawExtent[1] / interval) * interval; + min = round(max - range); // Not change the result that crossing zero. + + if (min < 0 && rawExtent[0] >= 0) { + min = 0; + max = round(range); + } else if (max > 0 && rawExtent[1] <= 0) { + max = 0; + min = -round(range); + } + } // Adjust min, max based on the extent of alignTo. When min or max is set in alignTo scale + + + var t0 = (alignToTicks[0].value - alignToNicedTicks[0].value) / alignToInterval; + var t1 = (alignToTicks[alignToSplitNumber].value - alignToNicedTicks[alignToSplitNumber].value) / alignToInterval; // NOTE: Must in setExtent -> setInterval -> setNiceExtent order. + + intervalScaleProto.setExtent.call(scale, min + interval * t0, max + interval * t1); + intervalScaleProto.setInterval.call(scale, interval); + + if (t0 || t1) { + intervalScaleProto.setNiceExtent.call(scale, min + interval, max - interval); + } + + if ("development" !== 'production') { + var ticks = intervalScaleProto.getTicks.call(scale); + + if (ticks[1] && (!isValueNice(interval) || getPrecisionSafe(ticks[1].value) > getPrecisionSafe(interval))) { + warn( // eslint-disable-next-line + "The ticks may be not readable when set min: " + axisModel.get('min') + ", max: " + axisModel.get('max') + " and alignTicks: true"); + } + } + } + + var Grid = + /** @class */ + function () { + function Grid(gridModel, ecModel, api) { + // FIXME:TS where used (different from registered type 'cartesian2d')? + this.type = 'grid'; + this._coordsMap = {}; + this._coordsList = []; + this._axesMap = {}; + this._axesList = []; + this.axisPointerEnabled = true; + this.dimensions = cartesian2DDimensions; + + this._initCartesian(gridModel, ecModel, api); + + this.model = gridModel; + } + + Grid.prototype.getRect = function () { + return this._rect; + }; + + Grid.prototype.update = function (ecModel, api) { + var axesMap = this._axesMap; + + this._updateScale(ecModel, this.model); + + function updateAxisTicks(axes) { + var alignTo; // Axis is added in order of axisIndex. + + var axesIndices = keys(axes); + var len = axesIndices.length; + + if (!len) { + return; + } + + var axisNeedsAlign = []; // Process once and calculate the ticks for those don't use alignTicks. + + for (var i = len - 1; i >= 0; i--) { + var idx = +axesIndices[i]; // Convert to number. + + var axis = axes[idx]; + var model = axis.model; + var scale = axis.scale; + + if ( // Only value and log axis without interval support alignTicks. + isIntervalOrLogScale(scale) && model.get('alignTicks') && model.get('interval') == null) { + axisNeedsAlign.push(axis); + } else { + niceScaleExtent(scale, model); + + if (isIntervalOrLogScale(scale)) { + // Can only align to interval or log axis. + alignTo = axis; + } + } + } + // PENDING. Should we find the axis that both set interval, min, max and align to this one? + + if (axisNeedsAlign.length) { + if (!alignTo) { + alignTo = axisNeedsAlign.pop(); + niceScaleExtent(alignTo.scale, alignTo.model); + } + + each(axisNeedsAlign, function (axis) { + alignScaleTicks(axis.scale, axis.model, alignTo.scale); + }); + } + } + + updateAxisTicks(axesMap.x); + updateAxisTicks(axesMap.y); // Key: axisDim_axisIndex, value: boolean, whether onZero target. + + var onZeroRecords = {}; + each(axesMap.x, function (xAxis) { + fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords); + }); + each(axesMap.y, function (yAxis) { + fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords); + }); // Resize again if containLabel is enabled + // FIXME It may cause getting wrong grid size in data processing stage + + this.resize(this.model, api); + }; + /** + * Resize the grid + */ + + + Grid.prototype.resize = function (gridModel, api, ignoreContainLabel) { + var boxLayoutParams = gridModel.getBoxLayoutParams(); + var isContainLabel = !ignoreContainLabel && gridModel.get('containLabel'); + var gridRect = getLayoutRect(boxLayoutParams, { + width: api.getWidth(), + height: api.getHeight() + }); + this._rect = gridRect; + var axesList = this._axesList; + adjustAxes(); // Minus label size + + if (isContainLabel) { + each(axesList, function (axis) { + if (!axis.model.get(['axisLabel', 'inside'])) { + var labelUnionRect = estimateLabelUnionRect(axis); + + if (labelUnionRect) { + var dim = axis.isHorizontal() ? 'height' : 'width'; + var margin = axis.model.get(['axisLabel', 'margin']); + gridRect[dim] -= labelUnionRect[dim] + margin; + + if (axis.position === 'top') { + gridRect.y += labelUnionRect.height + margin; + } else if (axis.position === 'left') { + gridRect.x += labelUnionRect.width + margin; + } + } + } + }); + adjustAxes(); + } + + each(this._coordsList, function (coord) { + // Calculate affine matrix to accelerate the data to point transform. + // If all the axes scales are time or value. + coord.calcAffineTransform(); + }); + + function adjustAxes() { + each(axesList, function (axis) { + var isHorizontal = axis.isHorizontal(); + var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height]; + var idx = axis.inverse ? 1 : 0; + axis.setExtent(extent[idx], extent[1 - idx]); + updateAxisTransform(axis, isHorizontal ? gridRect.x : gridRect.y); + }); + } + }; + + Grid.prototype.getAxis = function (dim, axisIndex) { + var axesMapOnDim = this._axesMap[dim]; + + if (axesMapOnDim != null) { + return axesMapOnDim[axisIndex || 0]; + } + }; + + Grid.prototype.getAxes = function () { + return this._axesList.slice(); + }; + + Grid.prototype.getCartesian = function (xAxisIndex, yAxisIndex) { + if (xAxisIndex != null && yAxisIndex != null) { + var key = 'x' + xAxisIndex + 'y' + yAxisIndex; + return this._coordsMap[key]; + } + + if (isObject(xAxisIndex)) { + yAxisIndex = xAxisIndex.yAxisIndex; + xAxisIndex = xAxisIndex.xAxisIndex; + } + + for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) { + if (coordList[i].getAxis('x').index === xAxisIndex || coordList[i].getAxis('y').index === yAxisIndex) { + return coordList[i]; + } + } + }; + + Grid.prototype.getCartesians = function () { + return this._coordsList.slice(); + }; + /** + * @implements + */ + + + Grid.prototype.convertToPixel = function (ecModel, finder, value) { + var target = this._findConvertTarget(finder); + + return target.cartesian ? target.cartesian.dataToPoint(value) : target.axis ? target.axis.toGlobalCoord(target.axis.dataToCoord(value)) : null; + }; + /** + * @implements + */ + + + Grid.prototype.convertFromPixel = function (ecModel, finder, value) { + var target = this._findConvertTarget(finder); + + return target.cartesian ? target.cartesian.pointToData(value) : target.axis ? target.axis.coordToData(target.axis.toLocalCoord(value)) : null; + }; + + Grid.prototype._findConvertTarget = function (finder) { + var seriesModel = finder.seriesModel; + var xAxisModel = finder.xAxisModel || seriesModel && seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0]; + var yAxisModel = finder.yAxisModel || seriesModel && seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[0]; + var gridModel = finder.gridModel; + var coordsList = this._coordsList; + var cartesian; + var axis; + + if (seriesModel) { + cartesian = seriesModel.coordinateSystem; + indexOf(coordsList, cartesian) < 0 && (cartesian = null); + } else if (xAxisModel && yAxisModel) { + cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex); + } else if (xAxisModel) { + axis = this.getAxis('x', xAxisModel.componentIndex); + } else if (yAxisModel) { + axis = this.getAxis('y', yAxisModel.componentIndex); + } // Lowest priority. + else if (gridModel) { + var grid = gridModel.coordinateSystem; + + if (grid === this) { + cartesian = this._coordsList[0]; + } + } + + return { + cartesian: cartesian, + axis: axis + }; + }; + /** + * @implements + */ + + + Grid.prototype.containPoint = function (point) { + var coord = this._coordsList[0]; + + if (coord) { + return coord.containPoint(point); + } + }; + /** + * Initialize cartesian coordinate systems + */ + + + Grid.prototype._initCartesian = function (gridModel, ecModel, api) { + var _this = this; + + var grid = this; + var axisPositionUsed = { + left: false, + right: false, + top: false, + bottom: false + }; + var axesMap = { + x: {}, + y: {} + }; + var axesCount = { + x: 0, + y: 0 + }; /// Create axis + + ecModel.eachComponent('xAxis', createAxisCreator('x'), this); + ecModel.eachComponent('yAxis', createAxisCreator('y'), this); + + if (!axesCount.x || !axesCount.y) { + // Roll back when there no either x or y axis + this._axesMap = {}; + this._axesList = []; + return; + } + + this._axesMap = axesMap; /// Create cartesian2d + + each(axesMap.x, function (xAxis, xAxisIndex) { + each(axesMap.y, function (yAxis, yAxisIndex) { + var key = 'x' + xAxisIndex + 'y' + yAxisIndex; + var cartesian = new Cartesian2D(key); + cartesian.master = _this; + cartesian.model = gridModel; + _this._coordsMap[key] = cartesian; + + _this._coordsList.push(cartesian); + + cartesian.addAxis(xAxis); + cartesian.addAxis(yAxis); + }); + }); + + function createAxisCreator(dimName) { + return function (axisModel, idx) { + if (!isAxisUsedInTheGrid(axisModel, gridModel)) { + return; + } + + var axisPosition = axisModel.get('position'); + + if (dimName === 'x') { + // Fix position + if (axisPosition !== 'top' && axisPosition !== 'bottom') { + // Default bottom of X + axisPosition = axisPositionUsed.bottom ? 'top' : 'bottom'; + } + } else { + // Fix position + if (axisPosition !== 'left' && axisPosition !== 'right') { + // Default left of Y + axisPosition = axisPositionUsed.left ? 'right' : 'left'; + } + } + + axisPositionUsed[axisPosition] = true; + var axis = new Axis2D(dimName, createScaleByModel(axisModel), [0, 0], axisModel.get('type'), axisPosition); + var isCategory = axis.type === 'category'; + axis.onBand = isCategory && axisModel.get('boundaryGap'); + axis.inverse = axisModel.get('inverse'); // Inject axis into axisModel + + axisModel.axis = axis; // Inject axisModel into axis + + axis.model = axisModel; // Inject grid info axis + + axis.grid = grid; // Index of axis, can be used as key + + axis.index = idx; + + grid._axesList.push(axis); + + axesMap[dimName][idx] = axis; + axesCount[dimName]++; + }; + } + }; + /** + * Update cartesian properties from series. + */ + + + Grid.prototype._updateScale = function (ecModel, gridModel) { + // Reset scale + each(this._axesList, function (axis) { + axis.scale.setExtent(Infinity, -Infinity); + + if (axis.type === 'category') { + var categorySortInfo = axis.model.get('categorySortInfo'); + axis.scale.setSortInfo(categorySortInfo); + } + }); + ecModel.eachSeries(function (seriesModel) { + if (isCartesian2DSeries(seriesModel)) { + var axesModelMap = findAxisModels(seriesModel); + var xAxisModel = axesModelMap.xAxisModel; + var yAxisModel = axesModelMap.yAxisModel; + + if (!isAxisUsedInTheGrid(xAxisModel, gridModel) || !isAxisUsedInTheGrid(yAxisModel, gridModel)) { + return; + } + + var cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex); + var data = seriesModel.getData(); + var xAxis = cartesian.getAxis('x'); + var yAxis = cartesian.getAxis('y'); + unionExtent(data, xAxis); + unionExtent(data, yAxis); + } + }, this); + + function unionExtent(data, axis) { + each(getDataDimensionsOnAxis(data, axis.dim), function (dim) { + axis.scale.unionExtentFromData(data, dim); + }); + } + }; + /** + * @param dim 'x' or 'y' or 'auto' or null/undefined + */ + + + Grid.prototype.getTooltipAxes = function (dim) { + var baseAxes = []; + var otherAxes = []; + each(this.getCartesians(), function (cartesian) { + var baseAxis = dim != null && dim !== 'auto' ? cartesian.getAxis(dim) : cartesian.getBaseAxis(); + var otherAxis = cartesian.getOtherAxis(baseAxis); + indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis); + indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis); + }); + return { + baseAxes: baseAxes, + otherAxes: otherAxes + }; + }; + + Grid.create = function (ecModel, api) { + var grids = []; + ecModel.eachComponent('grid', function (gridModel, idx) { + var grid = new Grid(gridModel, ecModel, api); + grid.name = 'grid_' + idx; // dataSampling requires axis extent, so resize + // should be performed in create stage. + + grid.resize(gridModel, api, true); + gridModel.coordinateSystem = grid; + grids.push(grid); + }); // Inject the coordinateSystems into seriesModel + + ecModel.eachSeries(function (seriesModel) { + if (!isCartesian2DSeries(seriesModel)) { + return; + } + + var axesModelMap = findAxisModels(seriesModel); + var xAxisModel = axesModelMap.xAxisModel; + var yAxisModel = axesModelMap.yAxisModel; + var gridModel = xAxisModel.getCoordSysModel(); + + if ("development" !== 'production') { + if (!gridModel) { + throw new Error('Grid "' + retrieve3(xAxisModel.get('gridIndex'), xAxisModel.get('gridId'), 0) + '" not found'); + } + + if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) { + throw new Error('xAxis and yAxis must use the same grid'); + } + } + + var grid = gridModel.coordinateSystem; + seriesModel.coordinateSystem = grid.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex); + }); + return grids; + }; // For deciding which dimensions to use when creating list data + + + Grid.dimensions = cartesian2DDimensions; + return Grid; + }(); + /** + * Check if the axis is used in the specified grid. + */ + + + function isAxisUsedInTheGrid(axisModel, gridModel) { + return axisModel.getCoordSysModel() === gridModel; + } + + function fixAxisOnZero(axesMap, otherAxisDim, axis, // Key: see `getOnZeroRecordKey` + onZeroRecords) { + axis.getAxesOnZeroOf = function () { + // TODO: onZero of multiple axes. + return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : []; + }; // onZero can not be enabled in these two situations: + // 1. When any other axis is a category axis. + // 2. When no axis is cross 0 point. + + + var otherAxes = axesMap[otherAxisDim]; + var otherAxisOnZeroOf; + var axisModel = axis.model; + var onZero = axisModel.get(['axisLine', 'onZero']); + var onZeroAxisIndex = axisModel.get(['axisLine', 'onZeroAxisIndex']); + + if (!onZero) { + return; + } // If target axis is specified. + + + if (onZeroAxisIndex != null) { + if (canOnZeroToAxis(otherAxes[onZeroAxisIndex])) { + otherAxisOnZeroOf = otherAxes[onZeroAxisIndex]; + } + } else { + // Find the first available other axis. + for (var idx in otherAxes) { + if (otherAxes.hasOwnProperty(idx) && canOnZeroToAxis(otherAxes[idx]) // Consider that two Y axes on one value axis, + // if both onZero, the two Y axes overlap. + && !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]) { + otherAxisOnZeroOf = otherAxes[idx]; + break; + } + } + } + + if (otherAxisOnZeroOf) { + onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true; + } + + function getOnZeroRecordKey(axis) { + return axis.dim + '_' + axis.index; + } + } + + function canOnZeroToAxis(axis) { + return axis && axis.type !== 'category' && axis.type !== 'time' && ifAxisCrossZero(axis); + } + + function updateAxisTransform(axis, coordBase) { + var axisExtent = axis.getExtent(); + var axisExtentSum = axisExtent[0] + axisExtent[1]; // Fast transform + + axis.toGlobalCoord = axis.dim === 'x' ? function (coord) { + return coord + coordBase; + } : function (coord) { + return axisExtentSum - coord + coordBase; + }; + axis.toLocalCoord = axis.dim === 'x' ? function (coord) { + return coord - coordBase; + } : function (coord) { + return axisExtentSum - coord + coordBase; + }; + } + + var PI$5 = Math.PI; + /** + * A final axis is translated and rotated from a "standard axis". + * So opt.position and opt.rotation is required. + * + * A standard axis is and axis from [0, 0] to [0, axisExtent[1]], + * for example: (0, 0) ------------> (0, 50) + * + * nameDirection or tickDirection or labelDirection is 1 means tick + * or label is below the standard axis, whereas is -1 means above + * the standard axis. labelOffset means offset between label and axis, + * which is useful when 'onZero', where axisLabel is in the grid and + * label in outside grid. + * + * Tips: like always, + * positive rotation represents anticlockwise, and negative rotation + * represents clockwise. + * The direction of position coordinate is the same as the direction + * of screen coordinate. + * + * Do not need to consider axis 'inverse', which is auto processed by + * axis extent. + */ + + var AxisBuilder = + /** @class */ + function () { + function AxisBuilder(axisModel, opt) { + this.group = new Group(); + this.opt = opt; + this.axisModel = axisModel; // Default value + + defaults(opt, { + labelOffset: 0, + nameDirection: 1, + tickDirection: 1, + labelDirection: 1, + silent: true, + handleAutoShown: function () { + return true; + } + }); // FIXME Not use a seperate text group? + + var transformGroup = new Group({ + x: opt.position[0], + y: opt.position[1], + rotation: opt.rotation + }); // this.group.add(transformGroup); + // this._transformGroup = transformGroup; + + transformGroup.updateTransform(); + this._transformGroup = transformGroup; + } + + AxisBuilder.prototype.hasBuilder = function (name) { + return !!builders[name]; + }; + + AxisBuilder.prototype.add = function (name) { + builders[name](this.opt, this.axisModel, this.group, this._transformGroup); + }; + + AxisBuilder.prototype.getGroup = function () { + return this.group; + }; + + AxisBuilder.innerTextLayout = function (axisRotation, textRotation, direction) { + var rotationDiff = remRadian(textRotation - axisRotation); + var textAlign; + var textVerticalAlign; + + if (isRadianAroundZero(rotationDiff)) { + // Label is parallel with axis line. + textVerticalAlign = direction > 0 ? 'top' : 'bottom'; + textAlign = 'center'; + } else if (isRadianAroundZero(rotationDiff - PI$5)) { + // Label is inverse parallel with axis line. + textVerticalAlign = direction > 0 ? 'bottom' : 'top'; + textAlign = 'center'; + } else { + textVerticalAlign = 'middle'; + + if (rotationDiff > 0 && rotationDiff < PI$5) { + textAlign = direction > 0 ? 'right' : 'left'; + } else { + textAlign = direction > 0 ? 'left' : 'right'; + } + } + + return { + rotation: rotationDiff, + textAlign: textAlign, + textVerticalAlign: textVerticalAlign + }; + }; + + AxisBuilder.makeAxisEventDataBase = function (axisModel) { + var eventData = { + componentType: axisModel.mainType, + componentIndex: axisModel.componentIndex + }; + eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex; + return eventData; + }; + + AxisBuilder.isLabelSilent = function (axisModel) { + var tooltipOpt = axisModel.get('tooltip'); + return axisModel.get('silent') // Consider mouse cursor, add these restrictions. + || !(axisModel.get('triggerEvent') || tooltipOpt && tooltipOpt.show); + }; + + return AxisBuilder; + }(); + var builders = { + axisLine: function (opt, axisModel, group, transformGroup) { + var shown = axisModel.get(['axisLine', 'show']); + + if (shown === 'auto' && opt.handleAutoShown) { + shown = opt.handleAutoShown('axisLine'); + } + + if (!shown) { + return; + } + + var extent = axisModel.axis.getExtent(); + var matrix = transformGroup.transform; + var pt1 = [extent[0], 0]; + var pt2 = [extent[1], 0]; + + if (matrix) { + applyTransform(pt1, pt1, matrix); + applyTransform(pt2, pt2, matrix); + } + + var lineStyle = extend({ + lineCap: 'round' + }, axisModel.getModel(['axisLine', 'lineStyle']).getLineStyle()); + var line = new Line({ + // Id for animation + subPixelOptimize: true, + shape: { + x1: pt1[0], + y1: pt1[1], + x2: pt2[0], + y2: pt2[1] + }, + style: lineStyle, + strokeContainThreshold: opt.strokeContainThreshold || 5, + silent: true, + z2: 1 + }); + line.anid = 'line'; + group.add(line); + var arrows = axisModel.get(['axisLine', 'symbol']); + + if (arrows != null) { + var arrowSize = axisModel.get(['axisLine', 'symbolSize']); + + if (isString(arrows)) { + // Use the same arrow for start and end point + arrows = [arrows, arrows]; + } + + if (isString(arrowSize) || isNumber(arrowSize)) { + // Use the same size for width and height + arrowSize = [arrowSize, arrowSize]; + } + + var arrowOffset = normalizeSymbolOffset(axisModel.get(['axisLine', 'symbolOffset']) || 0, arrowSize); + var symbolWidth_1 = arrowSize[0]; + var symbolHeight_1 = arrowSize[1]; + each([{ + rotate: opt.rotation + Math.PI / 2, + offset: arrowOffset[0], + r: 0 + }, { + rotate: opt.rotation - Math.PI / 2, + offset: arrowOffset[1], + r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0]) + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1])) + }], function (point, index) { + if (arrows[index] !== 'none' && arrows[index] != null) { + var symbol = createSymbol(arrows[index], -symbolWidth_1 / 2, -symbolHeight_1 / 2, symbolWidth_1, symbolHeight_1, lineStyle.stroke, true); // Calculate arrow position with offset + + var r = point.r + point.offset; + symbol.attr({ + rotation: point.rotate, + x: pt1[0] + r * Math.cos(opt.rotation), + y: pt1[1] - r * Math.sin(opt.rotation), + silent: true, + z2: 11 + }); + group.add(symbol); + } + }); + } + }, + axisTickLabel: function (opt, axisModel, group, transformGroup) { + var ticksEls = buildAxisMajorTicks(group, transformGroup, axisModel, opt); + var labelEls = buildAxisLabel(group, transformGroup, axisModel, opt); + fixMinMaxLabelShow(axisModel, labelEls, ticksEls); + buildAxisMinorTicks(group, transformGroup, axisModel, opt.tickDirection); // This bit fixes the label overlap issue for the time chart. + // See https://github.com/apache/echarts/issues/14266 for more. + + if (axisModel.get(['axisLabel', 'hideOverlap'])) { + var labelList = prepareLayoutList(map(labelEls, function (label) { + return { + label: label, + priority: label.z2, + defaultAttr: { + ignore: label.ignore + } + }; + })); + hideOverlap(labelList); + } + }, + axisName: function (opt, axisModel, group, transformGroup) { + var name = retrieve(opt.axisName, axisModel.get('name')); + + if (!name) { + return; + } + + var nameLocation = axisModel.get('nameLocation'); + var nameDirection = opt.nameDirection; + var textStyleModel = axisModel.getModel('nameTextStyle'); + var gap = axisModel.get('nameGap') || 0; + var extent = axisModel.axis.getExtent(); + var gapSignal = extent[0] > extent[1] ? -1 : 1; + var pos = [nameLocation === 'start' ? extent[0] - gapSignal * gap : nameLocation === 'end' ? extent[1] + gapSignal * gap : (extent[0] + extent[1]) / 2, // Reuse labelOffset. + isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * gap : 0]; + var labelLayout; + var nameRotation = axisModel.get('nameRotate'); + + if (nameRotation != null) { + nameRotation = nameRotation * PI$5 / 180; // To radian. + } + + var axisNameAvailableWidth; + + if (isNameLocationCenter(nameLocation)) { + labelLayout = AxisBuilder.innerTextLayout(opt.rotation, nameRotation != null ? nameRotation : opt.rotation, // Adapt to axis. + nameDirection); + } else { + labelLayout = endTextLayout(opt.rotation, nameLocation, nameRotation || 0, extent); + axisNameAvailableWidth = opt.axisNameAvailableWidth; + + if (axisNameAvailableWidth != null) { + axisNameAvailableWidth = Math.abs(axisNameAvailableWidth / Math.sin(labelLayout.rotation)); + !isFinite(axisNameAvailableWidth) && (axisNameAvailableWidth = null); + } + } + + var textFont = textStyleModel.getFont(); + var truncateOpt = axisModel.get('nameTruncate', true) || {}; + var ellipsis = truncateOpt.ellipsis; + var maxWidth = retrieve(opt.nameTruncateMaxWidth, truncateOpt.maxWidth, axisNameAvailableWidth); + var textEl = new ZRText({ + x: pos[0], + y: pos[1], + rotation: labelLayout.rotation, + silent: AxisBuilder.isLabelSilent(axisModel), + style: createTextStyle(textStyleModel, { + text: name, + font: textFont, + overflow: 'truncate', + width: maxWidth, + ellipsis: ellipsis, + fill: textStyleModel.getTextColor() || axisModel.get(['axisLine', 'lineStyle', 'color']), + align: textStyleModel.get('align') || labelLayout.textAlign, + verticalAlign: textStyleModel.get('verticalAlign') || labelLayout.textVerticalAlign + }), + z2: 1 + }); + setTooltipConfig({ + el: textEl, + componentModel: axisModel, + itemName: name + }); + textEl.__fullText = name; // Id for animation + + textEl.anid = 'name'; + + if (axisModel.get('triggerEvent')) { + var eventData = AxisBuilder.makeAxisEventDataBase(axisModel); + eventData.targetType = 'axisName'; + eventData.name = name; + getECData(textEl).eventData = eventData; + } // FIXME + + + transformGroup.add(textEl); + textEl.updateTransform(); + group.add(textEl); + textEl.decomposeTransform(); + } + }; + + function endTextLayout(rotation, textPosition, textRotate, extent) { + var rotationDiff = remRadian(textRotate - rotation); + var textAlign; + var textVerticalAlign; + var inverse = extent[0] > extent[1]; + var onLeft = textPosition === 'start' && !inverse || textPosition !== 'start' && inverse; + + if (isRadianAroundZero(rotationDiff - PI$5 / 2)) { + textVerticalAlign = onLeft ? 'bottom' : 'top'; + textAlign = 'center'; + } else if (isRadianAroundZero(rotationDiff - PI$5 * 1.5)) { + textVerticalAlign = onLeft ? 'top' : 'bottom'; + textAlign = 'center'; + } else { + textVerticalAlign = 'middle'; + + if (rotationDiff < PI$5 * 1.5 && rotationDiff > PI$5 / 2) { + textAlign = onLeft ? 'left' : 'right'; + } else { + textAlign = onLeft ? 'right' : 'left'; + } + } + + return { + rotation: rotationDiff, + textAlign: textAlign, + textVerticalAlign: textVerticalAlign + }; + } + + function fixMinMaxLabelShow(axisModel, labelEls, tickEls) { + if (shouldShowAllLabels(axisModel.axis)) { + return; + } // If min or max are user set, we need to check + // If the tick on min(max) are overlap on their neighbour tick + // If they are overlapped, we need to hide the min(max) tick label + + + var showMinLabel = axisModel.get(['axisLabel', 'showMinLabel']); + var showMaxLabel = axisModel.get(['axisLabel', 'showMaxLabel']); // FIXME + // Have not consider onBand yet, where tick els is more than label els. + + labelEls = labelEls || []; + tickEls = tickEls || []; + var firstLabel = labelEls[0]; + var nextLabel = labelEls[1]; + var lastLabel = labelEls[labelEls.length - 1]; + var prevLabel = labelEls[labelEls.length - 2]; + var firstTick = tickEls[0]; + var nextTick = tickEls[1]; + var lastTick = tickEls[tickEls.length - 1]; + var prevTick = tickEls[tickEls.length - 2]; + + if (showMinLabel === false) { + ignoreEl(firstLabel); + ignoreEl(firstTick); + } else if (isTwoLabelOverlapped(firstLabel, nextLabel)) { + if (showMinLabel) { + ignoreEl(nextLabel); + ignoreEl(nextTick); + } else { + ignoreEl(firstLabel); + ignoreEl(firstTick); + } + } + + if (showMaxLabel === false) { + ignoreEl(lastLabel); + ignoreEl(lastTick); + } else if (isTwoLabelOverlapped(prevLabel, lastLabel)) { + if (showMaxLabel) { + ignoreEl(prevLabel); + ignoreEl(prevTick); + } else { + ignoreEl(lastLabel); + ignoreEl(lastTick); + } + } + } + + function ignoreEl(el) { + el && (el.ignore = true); + } + + function isTwoLabelOverlapped(current, next) { + // current and next has the same rotation. + var firstRect = current && current.getBoundingRect().clone(); + var nextRect = next && next.getBoundingRect().clone(); + + if (!firstRect || !nextRect) { + return; + } // When checking intersect of two rotated labels, we use mRotationBack + // to avoid that boundingRect is enlarge when using `boundingRect.applyTransform`. + + + var mRotationBack = identity([]); + rotate(mRotationBack, mRotationBack, -current.rotation); + firstRect.applyTransform(mul$1([], mRotationBack, current.getLocalTransform())); + nextRect.applyTransform(mul$1([], mRotationBack, next.getLocalTransform())); + return firstRect.intersect(nextRect); + } + + function isNameLocationCenter(nameLocation) { + return nameLocation === 'middle' || nameLocation === 'center'; + } + + function createTicks(ticksCoords, tickTransform, tickEndCoord, tickLineStyle, anidPrefix) { + var tickEls = []; + var pt1 = []; + var pt2 = []; + + for (var i = 0; i < ticksCoords.length; i++) { + var tickCoord = ticksCoords[i].coord; + pt1[0] = tickCoord; + pt1[1] = 0; + pt2[0] = tickCoord; + pt2[1] = tickEndCoord; + + if (tickTransform) { + applyTransform(pt1, pt1, tickTransform); + applyTransform(pt2, pt2, tickTransform); + } // Tick line, Not use group transform to have better line draw + + + var tickEl = new Line({ + subPixelOptimize: true, + shape: { + x1: pt1[0], + y1: pt1[1], + x2: pt2[0], + y2: pt2[1] + }, + style: tickLineStyle, + z2: 2, + autoBatch: true, + silent: true + }); + tickEl.anid = anidPrefix + '_' + ticksCoords[i].tickValue; + tickEls.push(tickEl); + } + + return tickEls; + } + + function buildAxisMajorTicks(group, transformGroup, axisModel, opt) { + var axis = axisModel.axis; + var tickModel = axisModel.getModel('axisTick'); + var shown = tickModel.get('show'); + + if (shown === 'auto' && opt.handleAutoShown) { + shown = opt.handleAutoShown('axisTick'); + } + + if (!shown || axis.scale.isBlank()) { + return; + } + + var lineStyleModel = tickModel.getModel('lineStyle'); + var tickEndCoord = opt.tickDirection * tickModel.get('length'); + var ticksCoords = axis.getTicksCoords(); + var ticksEls = createTicks(ticksCoords, transformGroup.transform, tickEndCoord, defaults(lineStyleModel.getLineStyle(), { + stroke: axisModel.get(['axisLine', 'lineStyle', 'color']) + }), 'ticks'); + + for (var i = 0; i < ticksEls.length; i++) { + group.add(ticksEls[i]); + } + + return ticksEls; + } + + function buildAxisMinorTicks(group, transformGroup, axisModel, tickDirection) { + var axis = axisModel.axis; + var minorTickModel = axisModel.getModel('minorTick'); + + if (!minorTickModel.get('show') || axis.scale.isBlank()) { + return; + } + + var minorTicksCoords = axis.getMinorTicksCoords(); + + if (!minorTicksCoords.length) { + return; + } + + var lineStyleModel = minorTickModel.getModel('lineStyle'); + var tickEndCoord = tickDirection * minorTickModel.get('length'); + var minorTickLineStyle = defaults(lineStyleModel.getLineStyle(), defaults(axisModel.getModel('axisTick').getLineStyle(), { + stroke: axisModel.get(['axisLine', 'lineStyle', 'color']) + })); + + for (var i = 0; i < minorTicksCoords.length; i++) { + var minorTicksEls = createTicks(minorTicksCoords[i], transformGroup.transform, tickEndCoord, minorTickLineStyle, 'minorticks_' + i); + + for (var k = 0; k < minorTicksEls.length; k++) { + group.add(minorTicksEls[k]); + } + } + } + + function buildAxisLabel(group, transformGroup, axisModel, opt) { + var axis = axisModel.axis; + var show = retrieve(opt.axisLabelShow, axisModel.get(['axisLabel', 'show'])); + + if (!show || axis.scale.isBlank()) { + return; + } + + var labelModel = axisModel.getModel('axisLabel'); + var labelMargin = labelModel.get('margin'); + var labels = axis.getViewLabels(); // Special label rotate. + + var labelRotation = (retrieve(opt.labelRotate, labelModel.get('rotate')) || 0) * PI$5 / 180; + var labelLayout = AxisBuilder.innerTextLayout(opt.rotation, labelRotation, opt.labelDirection); + var rawCategoryData = axisModel.getCategories && axisModel.getCategories(true); + var labelEls = []; + var silent = AxisBuilder.isLabelSilent(axisModel); + var triggerEvent = axisModel.get('triggerEvent'); + each(labels, function (labelItem, index) { + var tickValue = axis.scale.type === 'ordinal' ? axis.scale.getRawOrdinalNumber(labelItem.tickValue) : labelItem.tickValue; + var formattedLabel = labelItem.formattedLabel; + var rawLabel = labelItem.rawLabel; + var itemLabelModel = labelModel; + + if (rawCategoryData && rawCategoryData[tickValue]) { + var rawCategoryItem = rawCategoryData[tickValue]; + + if (isObject(rawCategoryItem) && rawCategoryItem.textStyle) { + itemLabelModel = new Model(rawCategoryItem.textStyle, labelModel, axisModel.ecModel); + } + } + + var textColor = itemLabelModel.getTextColor() || axisModel.get(['axisLine', 'lineStyle', 'color']); + var tickCoord = axis.dataToCoord(tickValue); + var textEl = new ZRText({ + x: tickCoord, + y: opt.labelOffset + opt.labelDirection * labelMargin, + rotation: labelLayout.rotation, + silent: silent, + z2: 10 + (labelItem.level || 0), + style: createTextStyle(itemLabelModel, { + text: formattedLabel, + align: itemLabelModel.getShallow('align', true) || labelLayout.textAlign, + verticalAlign: itemLabelModel.getShallow('verticalAlign', true) || itemLabelModel.getShallow('baseline', true) || labelLayout.textVerticalAlign, + fill: isFunction(textColor) ? textColor( // (1) In category axis with data zoom, tick is not the original + // index of axis.data. So tick should not be exposed to user + // in category axis. + // (2) Compatible with previous version, which always use formatted label as + // input. But in interval scale the formatted label is like '223,445', which + // maked user repalce ','. So we modify it to return original val but remain + // it as 'string' to avoid error in replacing. + axis.type === 'category' ? rawLabel : axis.type === 'value' ? tickValue + '' : tickValue, index) : textColor + }) + }); + textEl.anid = 'label_' + tickValue; // Pack data for mouse event + + if (triggerEvent) { + var eventData = AxisBuilder.makeAxisEventDataBase(axisModel); + eventData.targetType = 'axisLabel'; + eventData.value = rawLabel; + eventData.tickIndex = index; + + if (axis.type === 'category') { + eventData.dataIndex = tickValue; + } + + getECData(textEl).eventData = eventData; + } // FIXME + + + transformGroup.add(textEl); + textEl.updateTransform(); + labelEls.push(textEl); + group.add(textEl); + textEl.decomposeTransform(); + }); + return labelEls; + } + + // allAxesInfo should be updated when setOption performed. + + function collect(ecModel, api) { + var result = { + /** + * key: makeKey(axis.model) + * value: { + * axis, + * coordSys, + * axisPointerModel, + * triggerTooltip, + * involveSeries, + * snap, + * seriesModels, + * seriesDataCount + * } + */ + axesInfo: {}, + seriesInvolved: false, + + /** + * key: makeKey(coordSys.model) + * value: Object: key makeKey(axis.model), value: axisInfo + */ + coordSysAxesInfo: {}, + coordSysMap: {} + }; + collectAxesInfo(result, ecModel, api); // Check seriesInvolved for performance, in case too many series in some chart. + + result.seriesInvolved && collectSeriesInfo(result, ecModel); + return result; + } + + function collectAxesInfo(result, ecModel, api) { + var globalTooltipModel = ecModel.getComponent('tooltip'); + var globalAxisPointerModel = ecModel.getComponent('axisPointer'); // links can only be set on global. + + var linksOption = globalAxisPointerModel.get('link', true) || []; + var linkGroups = []; // Collect axes info. + + each(api.getCoordinateSystems(), function (coordSys) { + // Some coordinate system do not support axes, like geo. + if (!coordSys.axisPointerEnabled) { + return; + } + + var coordSysKey = makeKey(coordSys.model); + var axesInfoInCoordSys = result.coordSysAxesInfo[coordSysKey] = {}; + result.coordSysMap[coordSysKey] = coordSys; // Set tooltip (like 'cross') is a convienent way to show axisPointer + // for user. So we enable seting tooltip on coordSys model. + + var coordSysModel = coordSys.model; + var baseTooltipModel = coordSysModel.getModel('tooltip', globalTooltipModel); + each(coordSys.getAxes(), curry(saveTooltipAxisInfo, false, null)); // If axis tooltip used, choose tooltip axis for each coordSys. + // Notice this case: coordSys is `grid` but not `cartesian2D` here. + + if (coordSys.getTooltipAxes && globalTooltipModel // If tooltip.showContent is set as false, tooltip will not + // show but axisPointer will show as normal. + && baseTooltipModel.get('show')) { + // Compatible with previous logic. But series.tooltip.trigger: 'axis' + // or series.data[n].tooltip.trigger: 'axis' are not support any more. + var triggerAxis = baseTooltipModel.get('trigger') === 'axis'; + var cross = baseTooltipModel.get(['axisPointer', 'type']) === 'cross'; + var tooltipAxes = coordSys.getTooltipAxes(baseTooltipModel.get(['axisPointer', 'axis'])); + + if (triggerAxis || cross) { + each(tooltipAxes.baseAxes, curry(saveTooltipAxisInfo, cross ? 'cross' : true, triggerAxis)); + } + + if (cross) { + each(tooltipAxes.otherAxes, curry(saveTooltipAxisInfo, 'cross', false)); + } + } // fromTooltip: true | false | 'cross' + // triggerTooltip: true | false | null + + + function saveTooltipAxisInfo(fromTooltip, triggerTooltip, axis) { + var axisPointerModel = axis.model.getModel('axisPointer', globalAxisPointerModel); + var axisPointerShow = axisPointerModel.get('show'); + + if (!axisPointerShow || axisPointerShow === 'auto' && !fromTooltip && !isHandleTrigger(axisPointerModel)) { + return; + } + + if (triggerTooltip == null) { + triggerTooltip = axisPointerModel.get('triggerTooltip'); + } + + axisPointerModel = fromTooltip ? makeAxisPointerModel(axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip) : axisPointerModel; + var snap = axisPointerModel.get('snap'); + var axisKey = makeKey(axis.model); + var involveSeries = triggerTooltip || snap || axis.type === 'category'; // If result.axesInfo[key] exist, override it (tooltip has higher priority). + + var axisInfo = result.axesInfo[axisKey] = { + key: axisKey, + axis: axis, + coordSys: coordSys, + axisPointerModel: axisPointerModel, + triggerTooltip: triggerTooltip, + involveSeries: involveSeries, + snap: snap, + useHandle: isHandleTrigger(axisPointerModel), + seriesModels: [], + linkGroup: null + }; + axesInfoInCoordSys[axisKey] = axisInfo; + result.seriesInvolved = result.seriesInvolved || involveSeries; + var groupIndex = getLinkGroupIndex(linksOption, axis); + + if (groupIndex != null) { + var linkGroup = linkGroups[groupIndex] || (linkGroups[groupIndex] = { + axesInfo: {} + }); + linkGroup.axesInfo[axisKey] = axisInfo; + linkGroup.mapper = linksOption[groupIndex].mapper; + axisInfo.linkGroup = linkGroup; + } + } + }); + } + + function makeAxisPointerModel(axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip) { + var tooltipAxisPointerModel = baseTooltipModel.getModel('axisPointer'); + var fields = ['type', 'snap', 'lineStyle', 'shadowStyle', 'label', 'animation', 'animationDurationUpdate', 'animationEasingUpdate', 'z']; + var volatileOption = {}; + each(fields, function (field) { + volatileOption[field] = clone(tooltipAxisPointerModel.get(field)); + }); // category axis do not auto snap, otherwise some tick that do not + // has value can not be hovered. value/time/log axis default snap if + // triggered from tooltip and trigger tooltip. + + volatileOption.snap = axis.type !== 'category' && !!triggerTooltip; // Compatibel with previous behavior, tooltip axis do not show label by default. + // Only these properties can be overrided from tooltip to axisPointer. + + if (tooltipAxisPointerModel.get('type') === 'cross') { + volatileOption.type = 'line'; + } + + var labelOption = volatileOption.label || (volatileOption.label = {}); // Follow the convention, do not show label when triggered by tooltip by default. + + labelOption.show == null && (labelOption.show = false); + + if (fromTooltip === 'cross') { + // When 'cross', both axes show labels. + var tooltipAxisPointerLabelShow = tooltipAxisPointerModel.get(['label', 'show']); + labelOption.show = tooltipAxisPointerLabelShow != null ? tooltipAxisPointerLabelShow : true; // If triggerTooltip, this is a base axis, which should better not use cross style + // (cross style is dashed by default) + + if (!triggerTooltip) { + var crossStyle = volatileOption.lineStyle = tooltipAxisPointerModel.get('crossStyle'); + crossStyle && defaults(labelOption, crossStyle.textStyle); + } + } + + return axis.model.getModel('axisPointer', new Model(volatileOption, globalAxisPointerModel, ecModel)); + } + + function collectSeriesInfo(result, ecModel) { + // Prepare data for axis trigger + ecModel.eachSeries(function (seriesModel) { + // Notice this case: this coordSys is `cartesian2D` but not `grid`. + var coordSys = seriesModel.coordinateSystem; + var seriesTooltipTrigger = seriesModel.get(['tooltip', 'trigger'], true); + var seriesTooltipShow = seriesModel.get(['tooltip', 'show'], true); + + if (!coordSys || seriesTooltipTrigger === 'none' || seriesTooltipTrigger === false || seriesTooltipTrigger === 'item' || seriesTooltipShow === false || seriesModel.get(['axisPointer', 'show'], true) === false) { + return; + } + + each(result.coordSysAxesInfo[makeKey(coordSys.model)], function (axisInfo) { + var axis = axisInfo.axis; + + if (coordSys.getAxis(axis.dim) === axis) { + axisInfo.seriesModels.push(seriesModel); + axisInfo.seriesDataCount == null && (axisInfo.seriesDataCount = 0); + axisInfo.seriesDataCount += seriesModel.getData().count(); + } + }); + }); + } + /** + * For example: + * { + * axisPointer: { + * links: [{ + * xAxisIndex: [2, 4], + * yAxisIndex: 'all' + * }, { + * xAxisId: ['a5', 'a7'], + * xAxisName: 'xxx' + * }] + * } + * } + */ + + + function getLinkGroupIndex(linksOption, axis) { + var axisModel = axis.model; + var dim = axis.dim; + + for (var i = 0; i < linksOption.length; i++) { + var linkOption = linksOption[i] || {}; + + if (checkPropInLink(linkOption[dim + 'AxisId'], axisModel.id) || checkPropInLink(linkOption[dim + 'AxisIndex'], axisModel.componentIndex) || checkPropInLink(linkOption[dim + 'AxisName'], axisModel.name)) { + return i; + } + } + } + + function checkPropInLink(linkPropValue, axisPropValue) { + return linkPropValue === 'all' || isArray(linkPropValue) && indexOf(linkPropValue, axisPropValue) >= 0 || linkPropValue === axisPropValue; + } + + function fixValue(axisModel) { + var axisInfo = getAxisInfo(axisModel); + + if (!axisInfo) { + return; + } + + var axisPointerModel = axisInfo.axisPointerModel; + var scale = axisInfo.axis.scale; + var option = axisPointerModel.option; + var status = axisPointerModel.get('status'); + var value = axisPointerModel.get('value'); // Parse init value for category and time axis. + + if (value != null) { + value = scale.parse(value); + } + + var useHandle = isHandleTrigger(axisPointerModel); // If `handle` used, `axisPointer` will always be displayed, so value + // and status should be initialized. + + if (status == null) { + option.status = useHandle ? 'show' : 'hide'; + } + + var extent = scale.getExtent().slice(); + extent[0] > extent[1] && extent.reverse(); + + if ( // Pick a value on axis when initializing. + value == null // If both `handle` and `dataZoom` are used, value may be out of axis extent, + // where we should re-pick a value to keep `handle` displaying normally. + || value > extent[1]) { + // Make handle displayed on the end of the axis when init, which looks better. + value = extent[1]; + } + + if (value < extent[0]) { + value = extent[0]; + } + + option.value = value; + + if (useHandle) { + option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show'; + } + } + function getAxisInfo(axisModel) { + var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo; + return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)]; + } + function getAxisPointerModel(axisModel) { + var axisInfo = getAxisInfo(axisModel); + return axisInfo && axisInfo.axisPointerModel; + } + + function isHandleTrigger(axisPointerModel) { + return !!axisPointerModel.get(['handle', 'show']); + } + /** + * @param {module:echarts/model/Model} model + * @return {string} unique key + */ + + + function makeKey(model) { + return model.type + '||' + model.id; + } + + var axisPointerClazz = {}; + /** + * Base class of AxisView. + */ + + var AxisView = + /** @class */ + function (_super) { + __extends(AxisView, _super); + + function AxisView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = AxisView.type; + return _this; + } + /** + * @override + */ + + + AxisView.prototype.render = function (axisModel, ecModel, api, payload) { + // FIXME + // This process should proformed after coordinate systems updated + // (axis scale updated), and should be performed each time update. + // So put it here temporarily, although it is not appropriate to + // put a model-writing procedure in `view`. + this.axisPointerClass && fixValue(axisModel); + + _super.prototype.render.apply(this, arguments); + + this._doUpdateAxisPointerClass(axisModel, api, true); + }; + /** + * Action handler. + */ + + + AxisView.prototype.updateAxisPointer = function (axisModel, ecModel, api, payload) { + this._doUpdateAxisPointerClass(axisModel, api, false); + }; + /** + * @override + */ + + + AxisView.prototype.remove = function (ecModel, api) { + var axisPointer = this._axisPointer; + axisPointer && axisPointer.remove(api); + }; + /** + * @override + */ + + + AxisView.prototype.dispose = function (ecModel, api) { + this._disposeAxisPointer(api); + + _super.prototype.dispose.apply(this, arguments); + }; + + AxisView.prototype._doUpdateAxisPointerClass = function (axisModel, api, forceRender) { + var Clazz = AxisView.getAxisPointerClass(this.axisPointerClass); + + if (!Clazz) { + return; + } + + var axisPointerModel = getAxisPointerModel(axisModel); + axisPointerModel ? (this._axisPointer || (this._axisPointer = new Clazz())).render(axisModel, axisPointerModel, api, forceRender) : this._disposeAxisPointer(api); + }; + + AxisView.prototype._disposeAxisPointer = function (api) { + this._axisPointer && this._axisPointer.dispose(api); + this._axisPointer = null; + }; + + AxisView.registerAxisPointerClass = function (type, clazz) { + if ("development" !== 'production') { + if (axisPointerClazz[type]) { + throw new Error('axisPointer ' + type + ' exists'); + } + } + + axisPointerClazz[type] = clazz; + }; + + AxisView.getAxisPointerClass = function (type) { + return type && axisPointerClazz[type]; + }; + AxisView.type = 'axis'; + return AxisView; + }(ComponentView); + + var inner$6 = makeInner(); + function rectCoordAxisBuildSplitArea(axisView, axisGroup, axisModel, gridModel) { + var axis = axisModel.axis; + + if (axis.scale.isBlank()) { + return; + } // TODO: TYPE + + + var splitAreaModel = axisModel.getModel('splitArea'); + var areaStyleModel = splitAreaModel.getModel('areaStyle'); + var areaColors = areaStyleModel.get('color'); + var gridRect = gridModel.coordinateSystem.getRect(); + var ticksCoords = axis.getTicksCoords({ + tickModel: splitAreaModel, + clamp: true + }); + + if (!ticksCoords.length) { + return; + } // For Making appropriate splitArea animation, the color and anid + // should be corresponding to previous one if possible. + + + var areaColorsLen = areaColors.length; + var lastSplitAreaColors = inner$6(axisView).splitAreaColors; + var newSplitAreaColors = createHashMap(); + var colorIndex = 0; + + if (lastSplitAreaColors) { + for (var i = 0; i < ticksCoords.length; i++) { + var cIndex = lastSplitAreaColors.get(ticksCoords[i].tickValue); + + if (cIndex != null) { + colorIndex = (cIndex + (areaColorsLen - 1) * i) % areaColorsLen; + break; + } + } + } + + var prev = axis.toGlobalCoord(ticksCoords[0].coord); + var areaStyle = areaStyleModel.getAreaStyle(); + areaColors = isArray(areaColors) ? areaColors : [areaColors]; + + for (var i = 1; i < ticksCoords.length; i++) { + var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord); + var x = void 0; + var y = void 0; + var width = void 0; + var height = void 0; + + if (axis.isHorizontal()) { + x = prev; + y = gridRect.y; + width = tickCoord - x; + height = gridRect.height; + prev = x + width; + } else { + x = gridRect.x; + y = prev; + width = gridRect.width; + height = tickCoord - y; + prev = y + height; + } + + var tickValue = ticksCoords[i - 1].tickValue; + tickValue != null && newSplitAreaColors.set(tickValue, colorIndex); + axisGroup.add(new Rect({ + anid: tickValue != null ? 'area_' + tickValue : null, + shape: { + x: x, + y: y, + width: width, + height: height + }, + style: defaults({ + fill: areaColors[colorIndex] + }, areaStyle), + autoBatch: true, + silent: true + })); + colorIndex = (colorIndex + 1) % areaColorsLen; + } + + inner$6(axisView).splitAreaColors = newSplitAreaColors; + } + function rectCoordAxisHandleRemove(axisView) { + inner$6(axisView).splitAreaColors = null; + } + + var axisBuilderAttrs = ['axisLine', 'axisTickLabel', 'axisName']; + var selfBuilderAttrs = ['splitArea', 'splitLine', 'minorSplitLine']; + + var CartesianAxisView = + /** @class */ + function (_super) { + __extends(CartesianAxisView, _super); + + function CartesianAxisView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = CartesianAxisView.type; + _this.axisPointerClass = 'CartesianAxisPointer'; + return _this; + } + /** + * @override + */ + + + CartesianAxisView.prototype.render = function (axisModel, ecModel, api, payload) { + this.group.removeAll(); + var oldAxisGroup = this._axisGroup; + this._axisGroup = new Group(); + this.group.add(this._axisGroup); + + if (!axisModel.get('show')) { + return; + } + + var gridModel = axisModel.getCoordSysModel(); + var layout = layout$1(gridModel, axisModel); + var axisBuilder = new AxisBuilder(axisModel, extend({ + handleAutoShown: function (elementType) { + var cartesians = gridModel.coordinateSystem.getCartesians(); + + for (var i = 0; i < cartesians.length; i++) { + if (isIntervalOrLogScale(cartesians[i].getOtherAxis(axisModel.axis).scale)) { + // Still show axis tick or axisLine if other axis is value / log + return true; + } + } // Not show axisTick or axisLine if other axis is category / time + + + return false; + } + }, layout)); + each(axisBuilderAttrs, axisBuilder.add, axisBuilder); + + this._axisGroup.add(axisBuilder.getGroup()); + + each(selfBuilderAttrs, function (name) { + if (axisModel.get([name, 'show'])) { + axisElementBuilders[name](this, this._axisGroup, axisModel, gridModel); + } + }, this); // THIS is a special case for bar racing chart. + // Update the axis label from the natural initial layout to + // sorted layout should has no animation. + + var isInitialSortFromBarRacing = payload && payload.type === 'changeAxisOrder' && payload.isInitSort; + + if (!isInitialSortFromBarRacing) { + groupTransition(oldAxisGroup, this._axisGroup, axisModel); + } + + _super.prototype.render.call(this, axisModel, ecModel, api, payload); + }; + + CartesianAxisView.prototype.remove = function () { + rectCoordAxisHandleRemove(this); + }; + + CartesianAxisView.type = 'cartesianAxis'; + return CartesianAxisView; + }(AxisView); + + var axisElementBuilders = { + splitLine: function (axisView, axisGroup, axisModel, gridModel) { + var axis = axisModel.axis; + + if (axis.scale.isBlank()) { + return; + } + + var splitLineModel = axisModel.getModel('splitLine'); + var lineStyleModel = splitLineModel.getModel('lineStyle'); + var lineColors = lineStyleModel.get('color'); + lineColors = isArray(lineColors) ? lineColors : [lineColors]; + var gridRect = gridModel.coordinateSystem.getRect(); + var isHorizontal = axis.isHorizontal(); + var lineCount = 0; + var ticksCoords = axis.getTicksCoords({ + tickModel: splitLineModel + }); + var p1 = []; + var p2 = []; + var lineStyle = lineStyleModel.getLineStyle(); + + for (var i = 0; i < ticksCoords.length; i++) { + var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord); + + if (isHorizontal) { + p1[0] = tickCoord; + p1[1] = gridRect.y; + p2[0] = tickCoord; + p2[1] = gridRect.y + gridRect.height; + } else { + p1[0] = gridRect.x; + p1[1] = tickCoord; + p2[0] = gridRect.x + gridRect.width; + p2[1] = tickCoord; + } + + var colorIndex = lineCount++ % lineColors.length; + var tickValue = ticksCoords[i].tickValue; + axisGroup.add(new Line({ + anid: tickValue != null ? 'line_' + ticksCoords[i].tickValue : null, + subPixelOptimize: true, + autoBatch: true, + shape: { + x1: p1[0], + y1: p1[1], + x2: p2[0], + y2: p2[1] + }, + style: defaults({ + stroke: lineColors[colorIndex] + }, lineStyle), + silent: true + })); + } + }, + minorSplitLine: function (axisView, axisGroup, axisModel, gridModel) { + var axis = axisModel.axis; + var minorSplitLineModel = axisModel.getModel('minorSplitLine'); + var lineStyleModel = minorSplitLineModel.getModel('lineStyle'); + var gridRect = gridModel.coordinateSystem.getRect(); + var isHorizontal = axis.isHorizontal(); + var minorTicksCoords = axis.getMinorTicksCoords(); + + if (!minorTicksCoords.length) { + return; + } + + var p1 = []; + var p2 = []; + var lineStyle = lineStyleModel.getLineStyle(); + + for (var i = 0; i < minorTicksCoords.length; i++) { + for (var k = 0; k < minorTicksCoords[i].length; k++) { + var tickCoord = axis.toGlobalCoord(minorTicksCoords[i][k].coord); + + if (isHorizontal) { + p1[0] = tickCoord; + p1[1] = gridRect.y; + p2[0] = tickCoord; + p2[1] = gridRect.y + gridRect.height; + } else { + p1[0] = gridRect.x; + p1[1] = tickCoord; + p2[0] = gridRect.x + gridRect.width; + p2[1] = tickCoord; + } + + axisGroup.add(new Line({ + anid: 'minor_line_' + minorTicksCoords[i][k].tickValue, + subPixelOptimize: true, + autoBatch: true, + shape: { + x1: p1[0], + y1: p1[1], + x2: p2[0], + y2: p2[1] + }, + style: lineStyle, + silent: true + })); + } + } + }, + splitArea: function (axisView, axisGroup, axisModel, gridModel) { + rectCoordAxisBuildSplitArea(axisView, axisGroup, axisModel, gridModel); + } + }; + + var CartesianXAxisView = + /** @class */ + function (_super) { + __extends(CartesianXAxisView, _super); + + function CartesianXAxisView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = CartesianXAxisView.type; + return _this; + } + + CartesianXAxisView.type = 'xAxis'; + return CartesianXAxisView; + }(CartesianAxisView); + + var CartesianYAxisView = + /** @class */ + function (_super) { + __extends(CartesianYAxisView, _super); + + function CartesianYAxisView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = CartesianXAxisView.type; + return _this; + } + + CartesianYAxisView.type = 'yAxis'; + return CartesianYAxisView; + }(CartesianAxisView); + + var GridView = + /** @class */ + function (_super) { + __extends(GridView, _super); + + function GridView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'grid'; + return _this; + } + + GridView.prototype.render = function (gridModel, ecModel) { + this.group.removeAll(); + + if (gridModel.get('show')) { + this.group.add(new Rect({ + shape: gridModel.coordinateSystem.getRect(), + style: defaults({ + fill: gridModel.get('backgroundColor') + }, gridModel.getItemStyle()), + silent: true, + z2: -1 + })); + } + }; + + GridView.type = 'grid'; + return GridView; + }(ComponentView); + + var extraOption = { + // gridIndex: 0, + // gridId: '', + offset: 0 + }; + function install$5(registers) { + registers.registerComponentView(GridView); + registers.registerComponentModel(GridModel); + registers.registerCoordinateSystem('cartesian2d', Grid); + axisModelCreator(registers, 'x', CartesianAxisModel, extraOption); + axisModelCreator(registers, 'y', CartesianAxisModel, extraOption); + registers.registerComponentView(CartesianXAxisView); + registers.registerComponentView(CartesianYAxisView); + registers.registerPreprocessor(function (option) { + // Only create grid when need + if (option.xAxis && option.yAxis && !option.grid) { + option.grid = {}; + } + }); + } + + function install$6(registers) { + // In case developer forget to include grid component + use(install$5); + registers.registerSeriesModel(ScatterSeriesModel); + registers.registerChartView(ScatterView); + registers.registerLayout(pointsLayout('scatter')); + } + + function radarLayout(ecModel) { + ecModel.eachSeriesByType('radar', function (seriesModel) { + var data = seriesModel.getData(); + var points = []; + var coordSys = seriesModel.coordinateSystem; + + if (!coordSys) { + return; + } + + var axes = coordSys.getIndicatorAxes(); + each(axes, function (axis, axisIndex) { + data.each(data.mapDimension(axes[axisIndex].dim), function (val, dataIndex) { + points[dataIndex] = points[dataIndex] || []; + var point = coordSys.dataToPoint(val, axisIndex); + points[dataIndex][axisIndex] = isValidPoint(point) ? point : getValueMissingPoint(coordSys); + }); + }); // Close polygon + + data.each(function (idx) { + // TODO + // Is it appropriate to connect to the next data when some data is missing? + // Or, should trade it like `connectNull` in line chart? + var firstPoint = find(points[idx], function (point) { + return isValidPoint(point); + }) || getValueMissingPoint(coordSys); // Copy the first actual point to the end of the array + + points[idx].push(firstPoint.slice()); + data.setItemLayout(idx, points[idx]); + }); + }); + } + + function isValidPoint(point) { + return !isNaN(point[0]) && !isNaN(point[1]); + } + + function getValueMissingPoint(coordSys) { + // It is error-prone to input [NaN, NaN] into polygon, polygon. + // (probably cause problem when refreshing or animating) + return [coordSys.cx, coordSys.cy]; + } + + function radarBackwardCompat(option) { + var polarOptArr = option.polar; + + if (polarOptArr) { + if (!isArray(polarOptArr)) { + polarOptArr = [polarOptArr]; + } + + var polarNotRadar_1 = []; + each(polarOptArr, function (polarOpt, idx) { + if (polarOpt.indicator) { + if (polarOpt.type && !polarOpt.shape) { + polarOpt.shape = polarOpt.type; + } + + option.radar = option.radar || []; + + if (!isArray(option.radar)) { + option.radar = [option.radar]; + } + + option.radar.push(polarOpt); + } else { + polarNotRadar_1.push(polarOpt); + } + }); + option.polar = polarNotRadar_1; + } + + each(option.series, function (seriesOpt) { + if (seriesOpt && seriesOpt.type === 'radar' && seriesOpt.polarIndex) { + seriesOpt.radarIndex = seriesOpt.polarIndex; + } + }); + } + + var RadarView = + /** @class */ + function (_super) { + __extends(RadarView, _super); + + function RadarView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = RadarView.type; + return _this; + } + + RadarView.prototype.render = function (seriesModel, ecModel, api) { + var polar = seriesModel.coordinateSystem; + var group = this.group; + var data = seriesModel.getData(); + var oldData = this._data; + + function createSymbol$1(data, idx) { + var symbolType = data.getItemVisual(idx, 'symbol') || 'circle'; + + if (symbolType === 'none') { + return; + } + + var symbolSize = normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize')); + var symbolPath = createSymbol(symbolType, -1, -1, 2, 2); + var symbolRotate = data.getItemVisual(idx, 'symbolRotate') || 0; + symbolPath.attr({ + style: { + strokeNoScale: true + }, + z2: 100, + scaleX: symbolSize[0] / 2, + scaleY: symbolSize[1] / 2, + rotation: symbolRotate * Math.PI / 180 || 0 + }); + return symbolPath; + } + + function updateSymbols(oldPoints, newPoints, symbolGroup, data, idx, isInit) { + // Simply rerender all + symbolGroup.removeAll(); + + for (var i = 0; i < newPoints.length - 1; i++) { + var symbolPath = createSymbol$1(data, idx); + + if (symbolPath) { + symbolPath.__dimIdx = i; + + if (oldPoints[i]) { + symbolPath.setPosition(oldPoints[i]); + graphic[isInit ? 'initProps' : 'updateProps'](symbolPath, { + x: newPoints[i][0], + y: newPoints[i][1] + }, seriesModel, idx); + } else { + symbolPath.setPosition(newPoints[i]); + } + + symbolGroup.add(symbolPath); + } + } + } + + function getInitialPoints(points) { + return map(points, function (pt) { + return [polar.cx, polar.cy]; + }); + } + + data.diff(oldData).add(function (idx) { + var points = data.getItemLayout(idx); + + if (!points) { + return; + } + + var polygon = new Polygon(); + var polyline = new Polyline(); + var target = { + shape: { + points: points + } + }; + polygon.shape.points = getInitialPoints(points); + polyline.shape.points = getInitialPoints(points); + initProps(polygon, target, seriesModel, idx); + initProps(polyline, target, seriesModel, idx); + var itemGroup = new Group(); + var symbolGroup = new Group(); + itemGroup.add(polyline); + itemGroup.add(polygon); + itemGroup.add(symbolGroup); + updateSymbols(polyline.shape.points, points, symbolGroup, data, idx, true); + data.setItemGraphicEl(idx, itemGroup); + }).update(function (newIdx, oldIdx) { + var itemGroup = oldData.getItemGraphicEl(oldIdx); + var polyline = itemGroup.childAt(0); + var polygon = itemGroup.childAt(1); + var symbolGroup = itemGroup.childAt(2); + var target = { + shape: { + points: data.getItemLayout(newIdx) + } + }; + + if (!target.shape.points) { + return; + } + + updateSymbols(polyline.shape.points, target.shape.points, symbolGroup, data, newIdx, false); + saveOldStyle(polygon); + saveOldStyle(polyline); + updateProps(polyline, target, seriesModel); + updateProps(polygon, target, seriesModel); + data.setItemGraphicEl(newIdx, itemGroup); + }).remove(function (idx) { + group.remove(oldData.getItemGraphicEl(idx)); + }).execute(); + data.eachItemGraphicEl(function (itemGroup, idx) { + var itemModel = data.getItemModel(idx); + var polyline = itemGroup.childAt(0); + var polygon = itemGroup.childAt(1); + var symbolGroup = itemGroup.childAt(2); // Radar uses the visual encoded from itemStyle. + + var itemStyle = data.getItemVisual(idx, 'style'); + var color = itemStyle.fill; + group.add(itemGroup); + polyline.useStyle(defaults(itemModel.getModel('lineStyle').getLineStyle(), { + fill: 'none', + stroke: color + })); + setStatesStylesFromModel(polyline, itemModel, 'lineStyle'); + setStatesStylesFromModel(polygon, itemModel, 'areaStyle'); + var areaStyleModel = itemModel.getModel('areaStyle'); + var polygonIgnore = areaStyleModel.isEmpty() && areaStyleModel.parentModel.isEmpty(); + polygon.ignore = polygonIgnore; + each(['emphasis', 'select', 'blur'], function (stateName) { + var stateModel = itemModel.getModel([stateName, 'areaStyle']); + var stateIgnore = stateModel.isEmpty() && stateModel.parentModel.isEmpty(); // Won't be ignore if normal state is not ignore. + + polygon.ensureState(stateName).ignore = stateIgnore && polygonIgnore; + }); + polygon.useStyle(defaults(areaStyleModel.getAreaStyle(), { + fill: color, + opacity: 0.7, + decal: itemStyle.decal + })); + var emphasisModel = itemModel.getModel('emphasis'); + var itemHoverStyle = emphasisModel.getModel('itemStyle').getItemStyle(); + symbolGroup.eachChild(function (symbolPath) { + if (symbolPath instanceof ZRImage) { + var pathStyle = symbolPath.style; + symbolPath.useStyle(extend({ + // TODO other properties like x, y ? + image: pathStyle.image, + x: pathStyle.x, + y: pathStyle.y, + width: pathStyle.width, + height: pathStyle.height + }, itemStyle)); + } else { + symbolPath.useStyle(itemStyle); + symbolPath.setColor(color); + symbolPath.style.strokeNoScale = true; + } + + var pathEmphasisState = symbolPath.ensureState('emphasis'); + pathEmphasisState.style = clone(itemHoverStyle); + var defaultText = data.getStore().get(data.getDimensionIndex(symbolPath.__dimIdx), idx); + (defaultText == null || isNaN(defaultText)) && (defaultText = ''); + setLabelStyle(symbolPath, getLabelStatesModels(itemModel), { + labelFetcher: data.hostModel, + labelDataIndex: idx, + labelDimIndex: symbolPath.__dimIdx, + defaultText: defaultText, + inheritColor: color, + defaultOpacity: itemStyle.opacity + }); + }); + toggleHoverEmphasis(itemGroup, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled')); + }); + this._data = data; + }; + + RadarView.prototype.remove = function () { + this.group.removeAll(); + this._data = null; + }; + + RadarView.type = 'radar'; + return RadarView; + }(ChartView); + + var RadarSeriesModel = + /** @class */ + function (_super) { + __extends(RadarSeriesModel, _super); + + function RadarSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = RadarSeriesModel.type; + _this.hasSymbolVisual = true; + return _this; + } // Overwrite + + + RadarSeriesModel.prototype.init = function (option) { + _super.prototype.init.apply(this, arguments); // Enable legend selection for each data item + // Use a function instead of direct access because data reference may changed + + + this.legendVisualProvider = new LegendVisualProvider(bind(this.getData, this), bind(this.getRawData, this)); + }; + + RadarSeriesModel.prototype.getInitialData = function (option, ecModel) { + return createSeriesDataSimply(this, { + generateCoord: 'indicator_', + generateCoordCount: Infinity + }); + }; + + RadarSeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + var data = this.getData(); + var coordSys = this.coordinateSystem; + var indicatorAxes = coordSys.getIndicatorAxes(); + var name = this.getData().getName(dataIndex); + var nameToDisplay = name === '' ? this.name : name; + var markerColor = retrieveVisualColorForTooltipMarker(this, dataIndex); + return createTooltipMarkup('section', { + header: nameToDisplay, + sortBlocks: true, + blocks: map(indicatorAxes, function (axis) { + var val = data.get(data.mapDimension(axis.dim), dataIndex); + return createTooltipMarkup('nameValue', { + markerType: 'subItem', + markerColor: markerColor, + name: axis.name, + value: val, + sortParam: val + }); + }) + }); + }; + + RadarSeriesModel.prototype.getTooltipPosition = function (dataIndex) { + if (dataIndex != null) { + var data_1 = this.getData(); + var coordSys = this.coordinateSystem; + var values = data_1.getValues(map(coordSys.dimensions, function (dim) { + return data_1.mapDimension(dim); + }), dataIndex); + + for (var i = 0, len = values.length; i < len; i++) { + if (!isNaN(values[i])) { + var indicatorAxes = coordSys.getIndicatorAxes(); + return coordSys.coordToPoint(indicatorAxes[i].dataToCoord(values[i]), i); + } + } + } + }; + + RadarSeriesModel.type = 'series.radar'; + RadarSeriesModel.dependencies = ['radar']; + RadarSeriesModel.defaultOption = { + // zlevel: 0, + z: 2, + colorBy: 'data', + coordinateSystem: 'radar', + legendHoverLink: true, + radarIndex: 0, + lineStyle: { + width: 2, + type: 'solid', + join: 'round' + }, + label: { + position: 'top' + }, + // areaStyle: { + // }, + // itemStyle: {} + symbolSize: 8 // symbolRotate: null + + }; + return RadarSeriesModel; + }(SeriesModel); + + var valueAxisDefault = axisDefault.value; + + function defaultsShow(opt, show) { + return defaults({ + show: show + }, opt); + } + + var RadarModel = + /** @class */ + function (_super) { + __extends(RadarModel, _super); + + function RadarModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = RadarModel.type; + return _this; + } + + RadarModel.prototype.optionUpdated = function () { + var boundaryGap = this.get('boundaryGap'); + var splitNumber = this.get('splitNumber'); + var scale = this.get('scale'); + var axisLine = this.get('axisLine'); + var axisTick = this.get('axisTick'); // let axisType = this.get('axisType'); + + var axisLabel = this.get('axisLabel'); + var nameTextStyle = this.get('axisName'); + var showName = this.get(['axisName', 'show']); + var nameFormatter = this.get(['axisName', 'formatter']); + var nameGap = this.get('axisNameGap'); + var triggerEvent = this.get('triggerEvent'); + var indicatorModels = map(this.get('indicator') || [], function (indicatorOpt) { + // PENDING + if (indicatorOpt.max != null && indicatorOpt.max > 0 && !indicatorOpt.min) { + indicatorOpt.min = 0; + } else if (indicatorOpt.min != null && indicatorOpt.min < 0 && !indicatorOpt.max) { + indicatorOpt.max = 0; + } + + var iNameTextStyle = nameTextStyle; + + if (indicatorOpt.color != null) { + iNameTextStyle = defaults({ + color: indicatorOpt.color + }, nameTextStyle); + } // Use same configuration + + + var innerIndicatorOpt = merge(clone(indicatorOpt), { + boundaryGap: boundaryGap, + splitNumber: splitNumber, + scale: scale, + axisLine: axisLine, + axisTick: axisTick, + // axisType: axisType, + axisLabel: axisLabel, + // Compatible with 2 and use text + name: indicatorOpt.text, + showName: showName, + nameLocation: 'end', + nameGap: nameGap, + // min: 0, + nameTextStyle: iNameTextStyle, + triggerEvent: triggerEvent + }, false); + + if (!showName) { + innerIndicatorOpt.name = ''; + } + + if (isString(nameFormatter)) { + var indName = innerIndicatorOpt.name; + innerIndicatorOpt.name = nameFormatter.replace('{value}', indName != null ? indName : ''); + } else if (isFunction(nameFormatter)) { + innerIndicatorOpt.name = nameFormatter(innerIndicatorOpt.name, innerIndicatorOpt); + } + + var model = new Model(innerIndicatorOpt, null, this.ecModel); + mixin(model, AxisModelCommonMixin.prototype); // For triggerEvent. + + model.mainType = 'radar'; + model.componentIndex = this.componentIndex; + return model; + }, this); + this._indicatorModels = indicatorModels; + }; + + RadarModel.prototype.getIndicatorModels = function () { + return this._indicatorModels; + }; + + RadarModel.type = 'radar'; + RadarModel.defaultOption = { + // zlevel: 0, + z: 0, + center: ['50%', '50%'], + radius: '75%', + startAngle: 90, + axisName: { + show: true // formatter: null + // textStyle: {} + + }, + boundaryGap: [0, 0], + splitNumber: 5, + axisNameGap: 15, + scale: false, + // Polygon or circle + shape: 'polygon', + axisLine: merge({ + lineStyle: { + color: '#bbb' + } + }, valueAxisDefault.axisLine), + axisLabel: defaultsShow(valueAxisDefault.axisLabel, false), + axisTick: defaultsShow(valueAxisDefault.axisTick, false), + // axisType: 'value', + splitLine: defaultsShow(valueAxisDefault.splitLine, true), + splitArea: defaultsShow(valueAxisDefault.splitArea, true), + // {text, min, max} + indicator: [] + }; + return RadarModel; + }(ComponentModel); + + var axisBuilderAttrs$1 = ['axisLine', 'axisTickLabel', 'axisName']; + + var RadarView$1 = + /** @class */ + function (_super) { + __extends(RadarView, _super); + + function RadarView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = RadarView.type; + return _this; + } + + RadarView.prototype.render = function (radarModel, ecModel, api) { + var group = this.group; + group.removeAll(); + + this._buildAxes(radarModel); + + this._buildSplitLineAndArea(radarModel); + }; + + RadarView.prototype._buildAxes = function (radarModel) { + var radar = radarModel.coordinateSystem; + var indicatorAxes = radar.getIndicatorAxes(); + var axisBuilders = map(indicatorAxes, function (indicatorAxis) { + var axisName = indicatorAxis.model.get('showName') ? indicatorAxis.name : ''; // hide name + + var axisBuilder = new AxisBuilder(indicatorAxis.model, { + axisName: axisName, + position: [radar.cx, radar.cy], + rotation: indicatorAxis.angle, + labelDirection: -1, + tickDirection: -1, + nameDirection: 1 + }); + return axisBuilder; + }); + each(axisBuilders, function (axisBuilder) { + each(axisBuilderAttrs$1, axisBuilder.add, axisBuilder); + this.group.add(axisBuilder.getGroup()); + }, this); + }; + + RadarView.prototype._buildSplitLineAndArea = function (radarModel) { + var radar = radarModel.coordinateSystem; + var indicatorAxes = radar.getIndicatorAxes(); + + if (!indicatorAxes.length) { + return; + } + + var shape = radarModel.get('shape'); + var splitLineModel = radarModel.getModel('splitLine'); + var splitAreaModel = radarModel.getModel('splitArea'); + var lineStyleModel = splitLineModel.getModel('lineStyle'); + var areaStyleModel = splitAreaModel.getModel('areaStyle'); + var showSplitLine = splitLineModel.get('show'); + var showSplitArea = splitAreaModel.get('show'); + var splitLineColors = lineStyleModel.get('color'); + var splitAreaColors = areaStyleModel.get('color'); + var splitLineColorsArr = isArray(splitLineColors) ? splitLineColors : [splitLineColors]; + var splitAreaColorsArr = isArray(splitAreaColors) ? splitAreaColors : [splitAreaColors]; + var splitLines = []; + var splitAreas = []; + + function getColorIndex(areaOrLine, areaOrLineColorList, idx) { + var colorIndex = idx % areaOrLineColorList.length; + areaOrLine[colorIndex] = areaOrLine[colorIndex] || []; + return colorIndex; + } + + if (shape === 'circle') { + var ticksRadius = indicatorAxes[0].getTicksCoords(); + var cx = radar.cx; + var cy = radar.cy; + + for (var i = 0; i < ticksRadius.length; i++) { + if (showSplitLine) { + var colorIndex = getColorIndex(splitLines, splitLineColorsArr, i); + splitLines[colorIndex].push(new Circle({ + shape: { + cx: cx, + cy: cy, + r: ticksRadius[i].coord + } + })); + } + + if (showSplitArea && i < ticksRadius.length - 1) { + var colorIndex = getColorIndex(splitAreas, splitAreaColorsArr, i); + splitAreas[colorIndex].push(new Ring({ + shape: { + cx: cx, + cy: cy, + r0: ticksRadius[i].coord, + r: ticksRadius[i + 1].coord + } + })); + } + } + } // Polyyon + else { + var realSplitNumber_1; + var axesTicksPoints = map(indicatorAxes, function (indicatorAxis, idx) { + var ticksCoords = indicatorAxis.getTicksCoords(); + realSplitNumber_1 = realSplitNumber_1 == null ? ticksCoords.length - 1 : Math.min(ticksCoords.length - 1, realSplitNumber_1); + return map(ticksCoords, function (tickCoord) { + return radar.coordToPoint(tickCoord.coord, idx); + }); + }); + var prevPoints = []; + + for (var i = 0; i <= realSplitNumber_1; i++) { + var points = []; + + for (var j = 0; j < indicatorAxes.length; j++) { + points.push(axesTicksPoints[j][i]); + } // Close + + + if (points[0]) { + points.push(points[0].slice()); + } else { + if ("development" !== 'production') { + console.error('Can\'t draw value axis ' + i); + } + } + + if (showSplitLine) { + var colorIndex = getColorIndex(splitLines, splitLineColorsArr, i); + splitLines[colorIndex].push(new Polyline({ + shape: { + points: points + } + })); + } + + if (showSplitArea && prevPoints) { + var colorIndex = getColorIndex(splitAreas, splitAreaColorsArr, i - 1); + splitAreas[colorIndex].push(new Polygon({ + shape: { + points: points.concat(prevPoints) + } + })); + } + + prevPoints = points.slice().reverse(); + } + } + + var lineStyle = lineStyleModel.getLineStyle(); + var areaStyle = areaStyleModel.getAreaStyle(); // Add splitArea before splitLine + + each(splitAreas, function (splitAreas, idx) { + this.group.add(mergePath$1(splitAreas, { + style: defaults({ + stroke: 'none', + fill: splitAreaColorsArr[idx % splitAreaColorsArr.length] + }, areaStyle), + silent: true + })); + }, this); + each(splitLines, function (splitLines, idx) { + this.group.add(mergePath$1(splitLines, { + style: defaults({ + fill: 'none', + stroke: splitLineColorsArr[idx % splitLineColorsArr.length] + }, lineStyle), + silent: true + })); + }, this); + }; + + RadarView.type = 'radar'; + return RadarView; + }(ComponentView); + + var IndicatorAxis = + /** @class */ + function (_super) { + __extends(IndicatorAxis, _super); + + function IndicatorAxis(dim, scale, radiusExtent) { + var _this = _super.call(this, dim, scale, radiusExtent) || this; + + _this.type = 'value'; + _this.angle = 0; + _this.name = ''; + return _this; + } + + return IndicatorAxis; + }(Axis); + + var Radar = + /** @class */ + function () { + function Radar(radarModel, ecModel, api) { + /** + * + * Radar dimensions + */ + this.dimensions = []; + this._model = radarModel; + this._indicatorAxes = map(radarModel.getIndicatorModels(), function (indicatorModel, idx) { + var dim = 'indicator_' + idx; + var indicatorAxis = new IndicatorAxis(dim, new IntervalScale() // (indicatorModel.get('axisType') === 'log') ? new LogScale() : new IntervalScale() + ); + indicatorAxis.name = indicatorModel.get('name'); // Inject model and axis + + indicatorAxis.model = indicatorModel; + indicatorModel.axis = indicatorAxis; + this.dimensions.push(dim); + return indicatorAxis; + }, this); + this.resize(radarModel, api); + } + + Radar.prototype.getIndicatorAxes = function () { + return this._indicatorAxes; + }; + + Radar.prototype.dataToPoint = function (value, indicatorIndex) { + var indicatorAxis = this._indicatorAxes[indicatorIndex]; + return this.coordToPoint(indicatorAxis.dataToCoord(value), indicatorIndex); + }; // TODO: API should be coordToPoint([coord, indicatorIndex]) + + + Radar.prototype.coordToPoint = function (coord, indicatorIndex) { + var indicatorAxis = this._indicatorAxes[indicatorIndex]; + var angle = indicatorAxis.angle; + var x = this.cx + coord * Math.cos(angle); + var y = this.cy - coord * Math.sin(angle); + return [x, y]; + }; + + Radar.prototype.pointToData = function (pt) { + var dx = pt[0] - this.cx; + var dy = pt[1] - this.cy; + var radius = Math.sqrt(dx * dx + dy * dy); + dx /= radius; + dy /= radius; + var radian = Math.atan2(-dy, dx); // Find the closest angle + // FIXME index can calculated directly + + var minRadianDiff = Infinity; + var closestAxis; + var closestAxisIdx = -1; + + for (var i = 0; i < this._indicatorAxes.length; i++) { + var indicatorAxis = this._indicatorAxes[i]; + var diff = Math.abs(radian - indicatorAxis.angle); + + if (diff < minRadianDiff) { + closestAxis = indicatorAxis; + closestAxisIdx = i; + minRadianDiff = diff; + } + } + + return [closestAxisIdx, +(closestAxis && closestAxis.coordToData(radius))]; + }; + + Radar.prototype.resize = function (radarModel, api) { + var center = radarModel.get('center'); + var viewWidth = api.getWidth(); + var viewHeight = api.getHeight(); + var viewSize = Math.min(viewWidth, viewHeight) / 2; + this.cx = parsePercent$1(center[0], viewWidth); + this.cy = parsePercent$1(center[1], viewHeight); + this.startAngle = radarModel.get('startAngle') * Math.PI / 180; // radius may be single value like `20`, `'80%'`, or array like `[10, '80%']` + + var radius = radarModel.get('radius'); + + if (isString(radius) || isNumber(radius)) { + radius = [0, radius]; + } + + this.r0 = parsePercent$1(radius[0], viewSize); + this.r = parsePercent$1(radius[1], viewSize); + each(this._indicatorAxes, function (indicatorAxis, idx) { + indicatorAxis.setExtent(this.r0, this.r); + var angle = this.startAngle + idx * Math.PI * 2 / this._indicatorAxes.length; // Normalize to [-PI, PI] + + angle = Math.atan2(Math.sin(angle), Math.cos(angle)); + indicatorAxis.angle = angle; + }, this); + }; + + Radar.prototype.update = function (ecModel, api) { + var indicatorAxes = this._indicatorAxes; + var radarModel = this._model; + each(indicatorAxes, function (indicatorAxis) { + indicatorAxis.scale.setExtent(Infinity, -Infinity); + }); + ecModel.eachSeriesByType('radar', function (radarSeries, idx) { + if (radarSeries.get('coordinateSystem') !== 'radar' // @ts-ignore + || ecModel.getComponent('radar', radarSeries.get('radarIndex')) !== radarModel) { + return; + } + + var data = radarSeries.getData(); + each(indicatorAxes, function (indicatorAxis) { + indicatorAxis.scale.unionExtentFromData(data, data.mapDimension(indicatorAxis.dim)); + }); + }, this); + var splitNumber = radarModel.get('splitNumber'); + var dummyScale = new IntervalScale(); + dummyScale.setExtent(0, splitNumber); + dummyScale.setInterval(1); // Force all the axis fixing the maxSplitNumber. + + each(indicatorAxes, function (indicatorAxis, idx) { + alignScaleTicks(indicatorAxis.scale, indicatorAxis.model, dummyScale); + }); + }; + + Radar.prototype.convertToPixel = function (ecModel, finder, value) { + console.warn('Not implemented.'); + return null; + }; + + Radar.prototype.convertFromPixel = function (ecModel, finder, pixel) { + console.warn('Not implemented.'); + return null; + }; + + Radar.prototype.containPoint = function (point) { + console.warn('Not implemented.'); + return false; + }; + + Radar.create = function (ecModel, api) { + var radarList = []; + ecModel.eachComponent('radar', function (radarModel) { + var radar = new Radar(radarModel, ecModel, api); + radarList.push(radar); + radarModel.coordinateSystem = radar; + }); + ecModel.eachSeriesByType('radar', function (radarSeries) { + if (radarSeries.get('coordinateSystem') === 'radar') { + // Inject coordinate system + // @ts-ignore + radarSeries.coordinateSystem = radarList[radarSeries.get('radarIndex') || 0]; + } + }); + return radarList; + }; + /** + * Radar dimensions is based on the data + */ + + + Radar.dimensions = []; + return Radar; + }(); + + function install$7(registers) { + registers.registerCoordinateSystem('radar', Radar); + registers.registerComponentModel(RadarModel); + registers.registerComponentView(RadarView$1); + registers.registerVisual({ + seriesType: 'radar', + reset: function (seriesModel) { + var data = seriesModel.getData(); // itemVisual symbol is for selected data + + data.each(function (idx) { + data.setItemVisual(idx, 'legendIcon', 'roundRect'); + }); // visual is for unselected data + + data.setVisual('legendIcon', 'roundRect'); + } + }); + } + + function install$8(registers) { + use(install$7); + registers.registerChartView(RadarView); + registers.registerSeriesModel(RadarSeriesModel); + registers.registerLayout(radarLayout); + registers.registerProcessor(dataFilter('radar')); + registers.registerPreprocessor(radarBackwardCompat); + } + + var ATTR = '\0_ec_interaction_mutex'; + function take(zr, resourceKey, userKey) { + var store = getStore(zr); + store[resourceKey] = userKey; + } + function release(zr, resourceKey, userKey) { + var store = getStore(zr); + var uKey = store[resourceKey]; + + if (uKey === userKey) { + store[resourceKey] = null; + } + } + function isTaken(zr, resourceKey) { + return !!getStore(zr)[resourceKey]; + } + + function getStore(zr) { + return zr[ATTR] || (zr[ATTR] = {}); + } + /** + * payload: { + * type: 'takeGlobalCursor', + * key: 'dataZoomSelect', or 'brush', or ..., + * If no userKey, release global cursor. + * } + */ + // TODO: SELF REGISTERED. + + + registerAction({ + type: 'takeGlobalCursor', + event: 'globalCursorTaken', + update: 'update' + }, noop); + + var RoamController = + /** @class */ + function (_super) { + __extends(RoamController, _super); + + function RoamController(zr) { + var _this = _super.call(this) || this; + + _this._zr = zr; // Avoid two roamController bind the same handler + + var mousedownHandler = bind(_this._mousedownHandler, _this); + var mousemoveHandler = bind(_this._mousemoveHandler, _this); + var mouseupHandler = bind(_this._mouseupHandler, _this); + var mousewheelHandler = bind(_this._mousewheelHandler, _this); + var pinchHandler = bind(_this._pinchHandler, _this); + /** + * Notice: only enable needed types. For example, if 'zoom' + * is not needed, 'zoom' should not be enabled, otherwise + * default mousewheel behaviour (scroll page) will be disabled. + */ + + _this.enable = function (controlType, opt) { + // Disable previous first + this.disable(); + this._opt = defaults(clone(opt) || {}, { + zoomOnMouseWheel: true, + moveOnMouseMove: true, + // By default, wheel do not trigger move. + moveOnMouseWheel: false, + preventDefaultMouseMove: true + }); + + if (controlType == null) { + controlType = true; + } + + if (controlType === true || controlType === 'move' || controlType === 'pan') { + zr.on('mousedown', mousedownHandler); + zr.on('mousemove', mousemoveHandler); + zr.on('mouseup', mouseupHandler); + } + + if (controlType === true || controlType === 'scale' || controlType === 'zoom') { + zr.on('mousewheel', mousewheelHandler); + zr.on('pinch', pinchHandler); + } + }; + + _this.disable = function () { + zr.off('mousedown', mousedownHandler); + zr.off('mousemove', mousemoveHandler); + zr.off('mouseup', mouseupHandler); + zr.off('mousewheel', mousewheelHandler); + zr.off('pinch', pinchHandler); + }; + + return _this; + } + + RoamController.prototype.isDragging = function () { + return this._dragging; + }; + + RoamController.prototype.isPinching = function () { + return this._pinching; + }; + + RoamController.prototype.setPointerChecker = function (pointerChecker) { + this.pointerChecker = pointerChecker; + }; + + RoamController.prototype.dispose = function () { + this.disable(); + }; + + RoamController.prototype._mousedownHandler = function (e) { + if (isMiddleOrRightButtonOnMouseUpDown(e) || e.target && e.target.draggable) { + return; + } + + var x = e.offsetX; + var y = e.offsetY; // Only check on mosedown, but not mousemove. + // Mouse can be out of target when mouse moving. + + if (this.pointerChecker && this.pointerChecker(e, x, y)) { + this._x = x; + this._y = y; + this._dragging = true; + } + }; + + RoamController.prototype._mousemoveHandler = function (e) { + if (!this._dragging || !isAvailableBehavior('moveOnMouseMove', e, this._opt) || e.gestureEvent === 'pinch' || isTaken(this._zr, 'globalPan')) { + return; + } + + var x = e.offsetX; + var y = e.offsetY; + var oldX = this._x; + var oldY = this._y; + var dx = x - oldX; + var dy = y - oldY; + this._x = x; + this._y = y; + this._opt.preventDefaultMouseMove && stop(e.event); + trigger(this, 'pan', 'moveOnMouseMove', e, { + dx: dx, + dy: dy, + oldX: oldX, + oldY: oldY, + newX: x, + newY: y, + isAvailableBehavior: null + }); + }; + + RoamController.prototype._mouseupHandler = function (e) { + if (!isMiddleOrRightButtonOnMouseUpDown(e)) { + this._dragging = false; + } + }; + + RoamController.prototype._mousewheelHandler = function (e) { + var shouldZoom = isAvailableBehavior('zoomOnMouseWheel', e, this._opt); + var shouldMove = isAvailableBehavior('moveOnMouseWheel', e, this._opt); + var wheelDelta = e.wheelDelta; + var absWheelDeltaDelta = Math.abs(wheelDelta); + var originX = e.offsetX; + var originY = e.offsetY; // wheelDelta maybe -0 in chrome mac. + + if (wheelDelta === 0 || !shouldZoom && !shouldMove) { + return; + } // If both `shouldZoom` and `shouldMove` is true, trigger + // their event both, and the final behavior is determined + // by event listener themselves. + + + if (shouldZoom) { + // Convenience: + // Mac and VM Windows on Mac: scroll up: zoom out. + // Windows: scroll up: zoom in. + // FIXME: Should do more test in different environment. + // wheelDelta is too complicated in difference nvironment + // (https://developer.mozilla.org/en-US/docs/Web/Events/mousewheel), + // although it has been normallized by zrender. + // wheelDelta of mouse wheel is bigger than touch pad. + var factor = absWheelDeltaDelta > 3 ? 1.4 : absWheelDeltaDelta > 1 ? 1.2 : 1.1; + var scale = wheelDelta > 0 ? factor : 1 / factor; + checkPointerAndTrigger(this, 'zoom', 'zoomOnMouseWheel', e, { + scale: scale, + originX: originX, + originY: originY, + isAvailableBehavior: null + }); + } + + if (shouldMove) { + // FIXME: Should do more test in different environment. + var absDelta = Math.abs(wheelDelta); // wheelDelta of mouse wheel is bigger than touch pad. + + var scrollDelta = (wheelDelta > 0 ? 1 : -1) * (absDelta > 3 ? 0.4 : absDelta > 1 ? 0.15 : 0.05); + checkPointerAndTrigger(this, 'scrollMove', 'moveOnMouseWheel', e, { + scrollDelta: scrollDelta, + originX: originX, + originY: originY, + isAvailableBehavior: null + }); + } + }; + + RoamController.prototype._pinchHandler = function (e) { + if (isTaken(this._zr, 'globalPan')) { + return; + } + + var scale = e.pinchScale > 1 ? 1.1 : 1 / 1.1; + checkPointerAndTrigger(this, 'zoom', null, e, { + scale: scale, + originX: e.pinchX, + originY: e.pinchY, + isAvailableBehavior: null + }); + }; + + return RoamController; + }(Eventful); + + function checkPointerAndTrigger(controller, eventName, behaviorToCheck, e, contollerEvent) { + if (controller.pointerChecker && controller.pointerChecker(e, contollerEvent.originX, contollerEvent.originY)) { + // When mouse is out of roamController rect, + // default befavoius should not be be disabled, otherwise + // page sliding is disabled, contrary to expectation. + stop(e.event); + trigger(controller, eventName, behaviorToCheck, e, contollerEvent); + } + } + + function trigger(controller, eventName, behaviorToCheck, e, contollerEvent) { + // Also provide behavior checker for event listener, for some case that + // multiple components share one listener. + contollerEvent.isAvailableBehavior = bind(isAvailableBehavior, null, behaviorToCheck, e); // TODO should not have type issue. + + controller.trigger(eventName, contollerEvent); + } // settings: { + // zoomOnMouseWheel + // moveOnMouseMove + // moveOnMouseWheel + // } + // The value can be: true / false / 'shift' / 'ctrl' / 'alt'. + + + function isAvailableBehavior(behaviorToCheck, e, settings) { + var setting = settings[behaviorToCheck]; + return !behaviorToCheck || setting && (!isString(setting) || e.event[setting + 'Key']); + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * For geo and graph. + */ + function updateViewOnPan(controllerHost, dx, dy) { + var target = controllerHost.target; + target.x += dx; + target.y += dy; + target.dirty(); + } + /** + * For geo and graph. + */ + + function updateViewOnZoom(controllerHost, zoomDelta, zoomX, zoomY) { + var target = controllerHost.target; + var zoomLimit = controllerHost.zoomLimit; + var newZoom = controllerHost.zoom = controllerHost.zoom || 1; + newZoom *= zoomDelta; + + if (zoomLimit) { + var zoomMin = zoomLimit.min || 0; + var zoomMax = zoomLimit.max || Infinity; + newZoom = Math.max(Math.min(zoomMax, newZoom), zoomMin); + } + + var zoomScale = newZoom / controllerHost.zoom; + controllerHost.zoom = newZoom; // Keep the mouse center when scaling + + target.x -= (zoomX - target.x) * (zoomScale - 1); + target.y -= (zoomY - target.y) * (zoomScale - 1); + target.scaleX *= zoomScale; + target.scaleY *= zoomScale; + target.dirty(); + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + var IRRELEVANT_EXCLUDES = { + 'axisPointer': 1, + 'tooltip': 1, + 'brush': 1 + }; + /** + * Avoid that: mouse click on a elements that is over geo or graph, + * but roam is triggered. + */ + + function onIrrelevantElement(e, api, targetCoordSysModel) { + var model = api.getComponentByElement(e.topTarget); // If model is axisModel, it works only if it is injected with coordinateSystem. + + var coordSys = model && model.coordinateSystem; + return model && model !== targetCoordSysModel && !IRRELEVANT_EXCLUDES.hasOwnProperty(model.mainType) && coordSys && coordSys.model !== targetCoordSysModel; + } + + function parseXML(svg) { + if (isString(svg)) { + var parser = new DOMParser(); + svg = parser.parseFromString(svg, 'text/xml'); + } + var svgNode = svg; + if (svgNode.nodeType === 9) { + svgNode = svgNode.firstChild; + } + while (svgNode.nodeName.toLowerCase() !== 'svg' || svgNode.nodeType !== 1) { + svgNode = svgNode.nextSibling; + } + return svgNode; + } + + var nodeParsers; + var INHERITABLE_STYLE_ATTRIBUTES_MAP = { + 'fill': 'fill', + 'stroke': 'stroke', + 'stroke-width': 'lineWidth', + 'opacity': 'opacity', + 'fill-opacity': 'fillOpacity', + 'stroke-opacity': 'strokeOpacity', + 'stroke-dasharray': 'lineDash', + 'stroke-dashoffset': 'lineDashOffset', + 'stroke-linecap': 'lineCap', + 'stroke-linejoin': 'lineJoin', + 'stroke-miterlimit': 'miterLimit', + 'font-family': 'fontFamily', + 'font-size': 'fontSize', + 'font-style': 'fontStyle', + 'font-weight': 'fontWeight', + 'text-anchor': 'textAlign', + 'visibility': 'visibility', + 'display': 'display' + }; + var INHERITABLE_STYLE_ATTRIBUTES_MAP_KEYS = keys(INHERITABLE_STYLE_ATTRIBUTES_MAP); + var SELF_STYLE_ATTRIBUTES_MAP = { + 'alignment-baseline': 'textBaseline', + 'stop-color': 'stopColor' + }; + var SELF_STYLE_ATTRIBUTES_MAP_KEYS = keys(SELF_STYLE_ATTRIBUTES_MAP); + var SVGParser = (function () { + function SVGParser() { + this._defs = {}; + this._root = null; + } + SVGParser.prototype.parse = function (xml, opt) { + opt = opt || {}; + var svg = parseXML(xml); + if ("development" !== 'production') { + if (!svg) { + throw new Error('Illegal svg'); + } + } + this._defsUsePending = []; + var root = new Group(); + this._root = root; + var named = []; + var viewBox = svg.getAttribute('viewBox') || ''; + var width = parseFloat((svg.getAttribute('width') || opt.width)); + var height = parseFloat((svg.getAttribute('height') || opt.height)); + isNaN(width) && (width = null); + isNaN(height) && (height = null); + parseAttributes(svg, root, null, true, false); + var child = svg.firstChild; + while (child) { + this._parseNode(child, root, named, null, false, false); + child = child.nextSibling; + } + applyDefs(this._defs, this._defsUsePending); + this._defsUsePending = []; + var viewBoxRect; + var viewBoxTransform; + if (viewBox) { + var viewBoxArr = splitNumberSequence(viewBox); + if (viewBoxArr.length >= 4) { + viewBoxRect = { + x: parseFloat((viewBoxArr[0] || 0)), + y: parseFloat((viewBoxArr[1] || 0)), + width: parseFloat(viewBoxArr[2]), + height: parseFloat(viewBoxArr[3]) + }; + } + } + if (viewBoxRect && width != null && height != null) { + viewBoxTransform = makeViewBoxTransform(viewBoxRect, { x: 0, y: 0, width: width, height: height }); + if (!opt.ignoreViewBox) { + var elRoot = root; + root = new Group(); + root.add(elRoot); + elRoot.scaleX = elRoot.scaleY = viewBoxTransform.scale; + elRoot.x = viewBoxTransform.x; + elRoot.y = viewBoxTransform.y; + } + } + if (!opt.ignoreRootClip && width != null && height != null) { + root.setClipPath(new Rect({ + shape: { x: 0, y: 0, width: width, height: height } + })); + } + return { + root: root, + width: width, + height: height, + viewBoxRect: viewBoxRect, + viewBoxTransform: viewBoxTransform, + named: named + }; + }; + SVGParser.prototype._parseNode = function (xmlNode, parentGroup, named, namedFrom, isInDefs, isInText) { + var nodeName = xmlNode.nodeName.toLowerCase(); + var el; + var namedFromForSub = namedFrom; + if (nodeName === 'defs') { + isInDefs = true; + } + if (nodeName === 'text') { + isInText = true; + } + if (nodeName === 'defs' || nodeName === 'switch') { + el = parentGroup; + } + else { + if (!isInDefs) { + var parser_1 = nodeParsers[nodeName]; + if (parser_1 && hasOwn(nodeParsers, nodeName)) { + el = parser_1.call(this, xmlNode, parentGroup); + var nameAttr = xmlNode.getAttribute('name'); + if (nameAttr) { + var newNamed = { + name: nameAttr, + namedFrom: null, + svgNodeTagLower: nodeName, + el: el + }; + named.push(newNamed); + if (nodeName === 'g') { + namedFromForSub = newNamed; + } + } + else if (namedFrom) { + named.push({ + name: namedFrom.name, + namedFrom: namedFrom, + svgNodeTagLower: nodeName, + el: el + }); + } + parentGroup.add(el); + } + } + var parser = paintServerParsers[nodeName]; + if (parser && hasOwn(paintServerParsers, nodeName)) { + var def = parser.call(this, xmlNode); + var id = xmlNode.getAttribute('id'); + if (id) { + this._defs[id] = def; + } + } + } + if (el && el.isGroup) { + var child = xmlNode.firstChild; + while (child) { + if (child.nodeType === 1) { + this._parseNode(child, el, named, namedFromForSub, isInDefs, isInText); + } + else if (child.nodeType === 3 && isInText) { + this._parseText(child, el); + } + child = child.nextSibling; + } + } + }; + SVGParser.prototype._parseText = function (xmlNode, parentGroup) { + var text = new TSpan({ + style: { + text: xmlNode.textContent + }, + silent: true, + x: this._textX || 0, + y: this._textY || 0 + }); + inheritStyle(parentGroup, text); + parseAttributes(xmlNode, text, this._defsUsePending, false, false); + applyTextAlignment(text, parentGroup); + var textStyle = text.style; + var fontSize = textStyle.fontSize; + if (fontSize && fontSize < 9) { + textStyle.fontSize = 9; + text.scaleX *= fontSize / 9; + text.scaleY *= fontSize / 9; + } + var font = (textStyle.fontSize || textStyle.fontFamily) && [ + textStyle.fontStyle, + textStyle.fontWeight, + (textStyle.fontSize || 12) + 'px', + textStyle.fontFamily || 'sans-serif' + ].join(' '); + textStyle.font = font; + var rect = text.getBoundingRect(); + this._textX += rect.width; + parentGroup.add(text); + return text; + }; + SVGParser.internalField = (function () { + nodeParsers = { + 'g': function (xmlNode, parentGroup) { + var g = new Group(); + inheritStyle(parentGroup, g); + parseAttributes(xmlNode, g, this._defsUsePending, false, false); + return g; + }, + 'rect': function (xmlNode, parentGroup) { + var rect = new Rect(); + inheritStyle(parentGroup, rect); + parseAttributes(xmlNode, rect, this._defsUsePending, false, false); + rect.setShape({ + x: parseFloat(xmlNode.getAttribute('x') || '0'), + y: parseFloat(xmlNode.getAttribute('y') || '0'), + width: parseFloat(xmlNode.getAttribute('width') || '0'), + height: parseFloat(xmlNode.getAttribute('height') || '0') + }); + rect.silent = true; + return rect; + }, + 'circle': function (xmlNode, parentGroup) { + var circle = new Circle(); + inheritStyle(parentGroup, circle); + parseAttributes(xmlNode, circle, this._defsUsePending, false, false); + circle.setShape({ + cx: parseFloat(xmlNode.getAttribute('cx') || '0'), + cy: parseFloat(xmlNode.getAttribute('cy') || '0'), + r: parseFloat(xmlNode.getAttribute('r') || '0') + }); + circle.silent = true; + return circle; + }, + 'line': function (xmlNode, parentGroup) { + var line = new Line(); + inheritStyle(parentGroup, line); + parseAttributes(xmlNode, line, this._defsUsePending, false, false); + line.setShape({ + x1: parseFloat(xmlNode.getAttribute('x1') || '0'), + y1: parseFloat(xmlNode.getAttribute('y1') || '0'), + x2: parseFloat(xmlNode.getAttribute('x2') || '0'), + y2: parseFloat(xmlNode.getAttribute('y2') || '0') + }); + line.silent = true; + return line; + }, + 'ellipse': function (xmlNode, parentGroup) { + var ellipse = new Ellipse(); + inheritStyle(parentGroup, ellipse); + parseAttributes(xmlNode, ellipse, this._defsUsePending, false, false); + ellipse.setShape({ + cx: parseFloat(xmlNode.getAttribute('cx') || '0'), + cy: parseFloat(xmlNode.getAttribute('cy') || '0'), + rx: parseFloat(xmlNode.getAttribute('rx') || '0'), + ry: parseFloat(xmlNode.getAttribute('ry') || '0') + }); + ellipse.silent = true; + return ellipse; + }, + 'polygon': function (xmlNode, parentGroup) { + var pointsStr = xmlNode.getAttribute('points'); + var pointsArr; + if (pointsStr) { + pointsArr = parsePoints(pointsStr); + } + var polygon = new Polygon({ + shape: { + points: pointsArr || [] + }, + silent: true + }); + inheritStyle(parentGroup, polygon); + parseAttributes(xmlNode, polygon, this._defsUsePending, false, false); + return polygon; + }, + 'polyline': function (xmlNode, parentGroup) { + var pointsStr = xmlNode.getAttribute('points'); + var pointsArr; + if (pointsStr) { + pointsArr = parsePoints(pointsStr); + } + var polyline = new Polyline({ + shape: { + points: pointsArr || [] + }, + silent: true + }); + inheritStyle(parentGroup, polyline); + parseAttributes(xmlNode, polyline, this._defsUsePending, false, false); + return polyline; + }, + 'image': function (xmlNode, parentGroup) { + var img = new ZRImage(); + inheritStyle(parentGroup, img); + parseAttributes(xmlNode, img, this._defsUsePending, false, false); + img.setStyle({ + image: xmlNode.getAttribute('xlink:href') || xmlNode.getAttribute('href'), + x: +xmlNode.getAttribute('x'), + y: +xmlNode.getAttribute('y'), + width: +xmlNode.getAttribute('width'), + height: +xmlNode.getAttribute('height') + }); + img.silent = true; + return img; + }, + 'text': function (xmlNode, parentGroup) { + var x = xmlNode.getAttribute('x') || '0'; + var y = xmlNode.getAttribute('y') || '0'; + var dx = xmlNode.getAttribute('dx') || '0'; + var dy = xmlNode.getAttribute('dy') || '0'; + this._textX = parseFloat(x) + parseFloat(dx); + this._textY = parseFloat(y) + parseFloat(dy); + var g = new Group(); + inheritStyle(parentGroup, g); + parseAttributes(xmlNode, g, this._defsUsePending, false, true); + return g; + }, + 'tspan': function (xmlNode, parentGroup) { + var x = xmlNode.getAttribute('x'); + var y = xmlNode.getAttribute('y'); + if (x != null) { + this._textX = parseFloat(x); + } + if (y != null) { + this._textY = parseFloat(y); + } + var dx = xmlNode.getAttribute('dx') || '0'; + var dy = xmlNode.getAttribute('dy') || '0'; + var g = new Group(); + inheritStyle(parentGroup, g); + parseAttributes(xmlNode, g, this._defsUsePending, false, true); + this._textX += parseFloat(dx); + this._textY += parseFloat(dy); + return g; + }, + 'path': function (xmlNode, parentGroup) { + var d = xmlNode.getAttribute('d') || ''; + var path = createFromString(d); + inheritStyle(parentGroup, path); + parseAttributes(xmlNode, path, this._defsUsePending, false, false); + path.silent = true; + return path; + } + }; + })(); + return SVGParser; + }()); + var paintServerParsers = { + 'lineargradient': function (xmlNode) { + var x1 = parseInt(xmlNode.getAttribute('x1') || '0', 10); + var y1 = parseInt(xmlNode.getAttribute('y1') || '0', 10); + var x2 = parseInt(xmlNode.getAttribute('x2') || '10', 10); + var y2 = parseInt(xmlNode.getAttribute('y2') || '0', 10); + var gradient = new LinearGradient(x1, y1, x2, y2); + parsePaintServerUnit(xmlNode, gradient); + parseGradientColorStops(xmlNode, gradient); + return gradient; + }, + 'radialgradient': function (xmlNode) { + var cx = parseInt(xmlNode.getAttribute('cx') || '0', 10); + var cy = parseInt(xmlNode.getAttribute('cy') || '0', 10); + var r = parseInt(xmlNode.getAttribute('r') || '0', 10); + var gradient = new RadialGradient(cx, cy, r); + parsePaintServerUnit(xmlNode, gradient); + parseGradientColorStops(xmlNode, gradient); + return gradient; + } + }; + function parsePaintServerUnit(xmlNode, gradient) { + var gradientUnits = xmlNode.getAttribute('gradientUnits'); + if (gradientUnits === 'userSpaceOnUse') { + gradient.global = true; + } + } + function parseGradientColorStops(xmlNode, gradient) { + var stop = xmlNode.firstChild; + while (stop) { + if (stop.nodeType === 1 + && stop.nodeName.toLocaleLowerCase() === 'stop') { + var offsetStr = stop.getAttribute('offset'); + var offset = void 0; + if (offsetStr && offsetStr.indexOf('%') > 0) { + offset = parseInt(offsetStr, 10) / 100; + } + else if (offsetStr) { + offset = parseFloat(offsetStr); + } + else { + offset = 0; + } + var styleVals = {}; + parseInlineStyle(stop, styleVals, styleVals); + var stopColor = styleVals.stopColor + || stop.getAttribute('stop-color') + || '#000000'; + gradient.colorStops.push({ + offset: offset, + color: stopColor + }); + } + stop = stop.nextSibling; + } + } + function inheritStyle(parent, child) { + if (parent && parent.__inheritedStyle) { + if (!child.__inheritedStyle) { + child.__inheritedStyle = {}; + } + defaults(child.__inheritedStyle, parent.__inheritedStyle); + } + } + function parsePoints(pointsString) { + var list = splitNumberSequence(pointsString); + var points = []; + for (var i = 0; i < list.length; i += 2) { + var x = parseFloat(list[i]); + var y = parseFloat(list[i + 1]); + points.push([x, y]); + } + return points; + } + function parseAttributes(xmlNode, el, defsUsePending, onlyInlineStyle, isTextGroup) { + var disp = el; + var inheritedStyle = disp.__inheritedStyle = disp.__inheritedStyle || {}; + var selfStyle = {}; + if (xmlNode.nodeType === 1) { + parseTransformAttribute(xmlNode, el); + parseInlineStyle(xmlNode, inheritedStyle, selfStyle); + if (!onlyInlineStyle) { + parseAttributeStyle(xmlNode, inheritedStyle, selfStyle); + } + } + disp.style = disp.style || {}; + if (inheritedStyle.fill != null) { + disp.style.fill = getFillStrokeStyle(disp, 'fill', inheritedStyle.fill, defsUsePending); + } + if (inheritedStyle.stroke != null) { + disp.style.stroke = getFillStrokeStyle(disp, 'stroke', inheritedStyle.stroke, defsUsePending); + } + each([ + 'lineWidth', 'opacity', 'fillOpacity', 'strokeOpacity', 'miterLimit', 'fontSize' + ], function (propName) { + if (inheritedStyle[propName] != null) { + disp.style[propName] = parseFloat(inheritedStyle[propName]); + } + }); + each([ + 'lineDashOffset', 'lineCap', 'lineJoin', 'fontWeight', 'fontFamily', 'fontStyle', 'textAlign' + ], function (propName) { + if (inheritedStyle[propName] != null) { + disp.style[propName] = inheritedStyle[propName]; + } + }); + if (isTextGroup) { + disp.__selfStyle = selfStyle; + } + if (inheritedStyle.lineDash) { + disp.style.lineDash = map(splitNumberSequence(inheritedStyle.lineDash), function (str) { + return parseFloat(str); + }); + } + if (inheritedStyle.visibility === 'hidden' || inheritedStyle.visibility === 'collapse') { + disp.invisible = true; + } + if (inheritedStyle.display === 'none') { + disp.ignore = true; + } + } + function applyTextAlignment(text, parentGroup) { + var parentSelfStyle = parentGroup.__selfStyle; + if (parentSelfStyle) { + var textBaseline = parentSelfStyle.textBaseline; + var zrTextBaseline = textBaseline; + if (!textBaseline || textBaseline === 'auto') { + zrTextBaseline = 'alphabetic'; + } + else if (textBaseline === 'baseline') { + zrTextBaseline = 'alphabetic'; + } + else if (textBaseline === 'before-edge' || textBaseline === 'text-before-edge') { + zrTextBaseline = 'top'; + } + else if (textBaseline === 'after-edge' || textBaseline === 'text-after-edge') { + zrTextBaseline = 'bottom'; + } + else if (textBaseline === 'central' || textBaseline === 'mathematical') { + zrTextBaseline = 'middle'; + } + text.style.textBaseline = zrTextBaseline; + } + var parentInheritedStyle = parentGroup.__inheritedStyle; + if (parentInheritedStyle) { + var textAlign = parentInheritedStyle.textAlign; + var zrTextAlign = textAlign; + if (textAlign) { + if (textAlign === 'middle') { + zrTextAlign = 'center'; + } + text.style.textAlign = zrTextAlign; + } + } + } + var urlRegex = /^url\(\s*#(.*?)\)/; + function getFillStrokeStyle(el, method, str, defsUsePending) { + var urlMatch = str && str.match(urlRegex); + if (urlMatch) { + var url = trim(urlMatch[1]); + defsUsePending.push([el, method, url]); + return; + } + if (str === 'none') { + str = null; + } + return str; + } + function applyDefs(defs, defsUsePending) { + for (var i = 0; i < defsUsePending.length; i++) { + var item = defsUsePending[i]; + item[0].style[item[1]] = defs[item[2]]; + } + } + var numberReg$1 = /-?([0-9]*\.)?[0-9]+([eE]-?[0-9]+)?/g; + function splitNumberSequence(rawStr) { + return rawStr.match(numberReg$1) || []; + } + var transformRegex = /(translate|scale|rotate|skewX|skewY|matrix)\(([\-\s0-9\.eE,]*)\)/g; + var DEGREE_TO_ANGLE = Math.PI / 180; + function parseTransformAttribute(xmlNode, node) { + var transform = xmlNode.getAttribute('transform'); + if (transform) { + transform = transform.replace(/,/g, ' '); + var transformOps_1 = []; + var mt = null; + transform.replace(transformRegex, function (str, type, value) { + transformOps_1.push(type, value); + return ''; + }); + for (var i = transformOps_1.length - 1; i > 0; i -= 2) { + var value = transformOps_1[i]; + var type = transformOps_1[i - 1]; + var valueArr = splitNumberSequence(value); + mt = mt || create$1(); + switch (type) { + case 'translate': + translate(mt, mt, [parseFloat(valueArr[0]), parseFloat(valueArr[1] || '0')]); + break; + case 'scale': + scale$1(mt, mt, [parseFloat(valueArr[0]), parseFloat(valueArr[1] || valueArr[0])]); + break; + case 'rotate': + rotate(mt, mt, -parseFloat(valueArr[0]) * DEGREE_TO_ANGLE); + break; + case 'skewX': + var sx = Math.tan(parseFloat(valueArr[0]) * DEGREE_TO_ANGLE); + mul$1(mt, [1, 0, sx, 1, 0, 0], mt); + break; + case 'skewY': + var sy = Math.tan(parseFloat(valueArr[0]) * DEGREE_TO_ANGLE); + mul$1(mt, [1, sy, 0, 1, 0, 0], mt); + break; + case 'matrix': + mt[0] = parseFloat(valueArr[0]); + mt[1] = parseFloat(valueArr[1]); + mt[2] = parseFloat(valueArr[2]); + mt[3] = parseFloat(valueArr[3]); + mt[4] = parseFloat(valueArr[4]); + mt[5] = parseFloat(valueArr[5]); + break; + } + } + node.setLocalTransform(mt); + } + } + var styleRegex = /([^\s:;]+)\s*:\s*([^:;]+)/g; + function parseInlineStyle(xmlNode, inheritableStyleResult, selfStyleResult) { + var style = xmlNode.getAttribute('style'); + if (!style) { + return; + } + styleRegex.lastIndex = 0; + var styleRegResult; + while ((styleRegResult = styleRegex.exec(style)) != null) { + var svgStlAttr = styleRegResult[1]; + var zrInheritableStlAttr = hasOwn(INHERITABLE_STYLE_ATTRIBUTES_MAP, svgStlAttr) + ? INHERITABLE_STYLE_ATTRIBUTES_MAP[svgStlAttr] + : null; + if (zrInheritableStlAttr) { + inheritableStyleResult[zrInheritableStlAttr] = styleRegResult[2]; + } + var zrSelfStlAttr = hasOwn(SELF_STYLE_ATTRIBUTES_MAP, svgStlAttr) + ? SELF_STYLE_ATTRIBUTES_MAP[svgStlAttr] + : null; + if (zrSelfStlAttr) { + selfStyleResult[zrSelfStlAttr] = styleRegResult[2]; + } + } + } + function parseAttributeStyle(xmlNode, inheritableStyleResult, selfStyleResult) { + for (var i = 0; i < INHERITABLE_STYLE_ATTRIBUTES_MAP_KEYS.length; i++) { + var svgAttrName = INHERITABLE_STYLE_ATTRIBUTES_MAP_KEYS[i]; + var attrValue = xmlNode.getAttribute(svgAttrName); + if (attrValue != null) { + inheritableStyleResult[INHERITABLE_STYLE_ATTRIBUTES_MAP[svgAttrName]] = attrValue; + } + } + for (var i = 0; i < SELF_STYLE_ATTRIBUTES_MAP_KEYS.length; i++) { + var svgAttrName = SELF_STYLE_ATTRIBUTES_MAP_KEYS[i]; + var attrValue = xmlNode.getAttribute(svgAttrName); + if (attrValue != null) { + selfStyleResult[SELF_STYLE_ATTRIBUTES_MAP[svgAttrName]] = attrValue; + } + } + } + function makeViewBoxTransform(viewBoxRect, boundingRect) { + var scaleX = boundingRect.width / viewBoxRect.width; + var scaleY = boundingRect.height / viewBoxRect.height; + var scale = Math.min(scaleX, scaleY); + return { + scale: scale, + x: -(viewBoxRect.x + viewBoxRect.width / 2) * scale + (boundingRect.x + boundingRect.width / 2), + y: -(viewBoxRect.y + viewBoxRect.height / 2) * scale + (boundingRect.y + boundingRect.height / 2) + }; + } + function parseSVG(xml, opt) { + var parser = new SVGParser(); + return parser.parse(xml, opt); + } + + /** + * "region available" means that: enable users to set attribute `name="xxx"` on those tags + * to make it be a region. + * 1. region styles and its label styles can be defined in echarts opton: + * ```js + * geo: { + * regions: [{ + * name: 'xxx', + * itemStyle: { ... }, + * label: { ... } + * }, { + * ... + * }, + * ...] + * }; + * ``` + * 2. name can be duplicated in different SVG tag. All of the tags with the same name share + * a region option. For exampel if there are two representing two lung lobes. They have + * no common parents but both of them need to display label "lung" inside. + */ + + var REGION_AVAILABLE_SVG_TAG_MAP = createHashMap(['rect', 'circle', 'line', 'ellipse', 'polygon', 'polyline', 'path', // are also enabled becuase some SVG might paint text itself, + // but still need to trigger events or tooltip. + 'text', 'tspan', // is also enabled because this case: if multiple tags share one name + // and need label displayed, every tags will display the name, which is not + // expected. So we can put them into a . Thereby only one label + // displayed and located based on the bounding rect of the . + 'g']); + + var GeoSVGResource = + /** @class */ + function () { + function GeoSVGResource(mapName, svg) { + this.type = 'geoSVG'; // All used graphics. key: hostKey, value: root + + this._usedGraphicMap = createHashMap(); // All unused graphics. + + this._freedGraphics = []; + this._mapName = mapName; // Only perform parse to XML object here, which might be time + // consiming for large SVG. + // Although convert XML to zrender element is also time consiming, + // if we do it here, the clone of zrender elements has to be + // required. So we do it once for each geo instance, util real + // performance issues call for optimizing it. + + this._parsedXML = parseXML(svg); + } + + GeoSVGResource.prototype.load = function () + /* nameMap: NameMap */ + { + // In the "load" stage, graphic need to be built to + // get boundingRect for geo coordinate system. + var firstGraphic = this._firstGraphic; // Create the return data structure only when first graphic created. + // Because they will be used in geo coordinate system update stage, + // and `regions` will be mounted at `geo` coordinate system, + // in which there is no "view" info, so that it should better not to + // make references to graphic elements. + + if (!firstGraphic) { + firstGraphic = this._firstGraphic = this._buildGraphic(this._parsedXML); + + this._freedGraphics.push(firstGraphic); + + this._boundingRect = this._firstGraphic.boundingRect.clone(); // PENDING: `nameMap` will not be supported until some real requirement come. + // if (nameMap) { + // named = applyNameMap(named, nameMap); + // } + + var _a = createRegions(firstGraphic.named), + regions = _a.regions, + regionsMap = _a.regionsMap; + + this._regions = regions; + this._regionsMap = regionsMap; + } + + return { + boundingRect: this._boundingRect, + regions: this._regions, + regionsMap: this._regionsMap + }; + }; + + GeoSVGResource.prototype._buildGraphic = function (svgXML) { + var result; + var rootFromParse; + + try { + result = svgXML && parseSVG(svgXML, { + ignoreViewBox: true, + ignoreRootClip: true + }) || {}; + rootFromParse = result.root; + assert(rootFromParse != null); + } catch (e) { + throw new Error('Invalid svg format\n' + e.message); + } // Note: we keep the covenant that the root has no transform. So always add an extra root. + + + var root = new Group(); + root.add(rootFromParse); + root.isGeoSVGGraphicRoot = true; // [THE_RULE_OF_VIEWPORT_AND_VIEWBOX] + // + // Consider: `` + // - the `width/height` we call it `svgWidth/svgHeight` for short. + // - `(0, 0, svgWidth, svgHeight)` defines the viewport of the SVG, or say, + // "viewport boundingRect", or `boundingRect` for short. + // - `viewBox` defines the transform from the real content ot the viewport. + // `viewBox` has the same unit as the content of SVG. + // If `viewBox` exists, a transform is defined, so the unit of `svgWidth/svgHeight` become + // different from the content of SVG. Otherwise, they are the same. + // + // If both `svgWidth/svgHeight/viewBox` are specified in a SVG file, the transform rule will be: + // 0. `boundingRect` is `(0, 0, svgWidth, svgHeight)`. Set it to Geo['_rect'] (View['_rect']). + // 1. Make a transform from `viewBox` to `boundingRect`. + // Note: only suport `preserveAspectRatio 'xMidYMid'` here. That is, this transform will preserve + // the aspect ratio. + // 2. Make a transform from boundingRect to Geo['_viewRect'] (View['_viewRect']) + // (`Geo`/`View` will do this job). + // Note: this transform might not preserve aspect radio, which depending on how users specify + // viewRect in echarts option (e.g., `geo.left/top/width/height` will not preserve aspect ratio, + // but `geo.layoutCenter/layoutSize` will preserve aspect ratio). + // + // If `svgWidth/svgHeight` not specified, we use `viewBox` as the `boundingRect` to make the SVG + // layout look good. + // + // If neither `svgWidth/svgHeight` nor `viewBox` are not specified, we calculate the boundingRect + // of the SVG content and use them to make SVG layout look good. + + var svgWidth = result.width; + var svgHeight = result.height; + var viewBoxRect = result.viewBoxRect; + var boundingRect = this._boundingRect; + + if (!boundingRect) { + var bRectX = void 0; + var bRectY = void 0; + var bRectWidth = void 0; + var bRectHeight = void 0; + + if (svgWidth != null) { + bRectX = 0; + bRectWidth = svgWidth; + } else if (viewBoxRect) { + bRectX = viewBoxRect.x; + bRectWidth = viewBoxRect.width; + } + + if (svgHeight != null) { + bRectY = 0; + bRectHeight = svgHeight; + } else if (viewBoxRect) { + bRectY = viewBoxRect.y; + bRectHeight = viewBoxRect.height; + } // If both viewBox and svgWidth/svgHeight not specified, + // we have to determine how to layout those element to make them look good. + + + if (bRectX == null || bRectY == null) { + var calculatedBoundingRect = rootFromParse.getBoundingRect(); + + if (bRectX == null) { + bRectX = calculatedBoundingRect.x; + bRectWidth = calculatedBoundingRect.width; + } + + if (bRectY == null) { + bRectY = calculatedBoundingRect.y; + bRectHeight = calculatedBoundingRect.height; + } + } + + boundingRect = this._boundingRect = new BoundingRect(bRectX, bRectY, bRectWidth, bRectHeight); + } + + if (viewBoxRect) { + var viewBoxTransform = makeViewBoxTransform(viewBoxRect, boundingRect); // Only support `preserveAspectRatio 'xMidYMid'` + + rootFromParse.scaleX = rootFromParse.scaleY = viewBoxTransform.scale; + rootFromParse.x = viewBoxTransform.x; + rootFromParse.y = viewBoxTransform.y; + } // SVG needs to clip based on `viewBox`. And some SVG files really rely on this feature. + // They do not strictly confine all of the content inside a display rect, but deliberately + // use a `viewBox` to define a displayable rect. + // PENDING: + // The drawback of the `setClipPath` here is: the region label (genereted by echarts) near the + // edge might also be clipped, because region labels are put as `textContent` of the SVG path. + + + root.setClipPath(new Rect({ + shape: boundingRect.plain() + })); + var named = []; + each(result.named, function (namedItem) { + if (REGION_AVAILABLE_SVG_TAG_MAP.get(namedItem.svgNodeTagLower) != null) { + named.push(namedItem); + setSilent(namedItem.el); + } + }); + return { + root: root, + boundingRect: boundingRect, + named: named + }; + }; + /** + * Consider: + * (1) One graphic element can not be shared by different `geoView` running simultaneously. + * Notice, also need to consider multiple echarts instances share a `mapRecord`. + * (2) Converting SVG to graphic elements is time consuming. + * (3) In the current architecture, `load` should be called frequently to get boundingRect, + * and it is called without view info. + * So we maintain graphic elements in this module, and enables `view` to use/return these + * graphics from/to the pool with it's uid. + */ + + + GeoSVGResource.prototype.useGraphic = function (hostKey + /*, nameMap: NameMap */ + ) { + var usedRootMap = this._usedGraphicMap; + var svgGraphic = usedRootMap.get(hostKey); + + if (svgGraphic) { + return svgGraphic; + } + + svgGraphic = this._freedGraphics.pop() // use the first boundingRect to avoid duplicated boundingRect calculation. + || this._buildGraphic(this._parsedXML); + usedRootMap.set(hostKey, svgGraphic); // PENDING: `nameMap` will not be supported until some real requirement come. + // `nameMap` can only be obtained from echarts option. + // The original `named` must not be modified. + // if (nameMap) { + // svgGraphic = extend({}, svgGraphic); + // svgGraphic.named = applyNameMap(svgGraphic.named, nameMap); + // } + + return svgGraphic; + }; + + GeoSVGResource.prototype.freeGraphic = function (hostKey) { + var usedRootMap = this._usedGraphicMap; + var svgGraphic = usedRootMap.get(hostKey); + + if (svgGraphic) { + usedRootMap.removeKey(hostKey); + + this._freedGraphics.push(svgGraphic); + } + }; + + return GeoSVGResource; + }(); + + function setSilent(el) { + // Only named element has silent: false, other elements should + // act as background and has no user interaction. + el.silent = false; // text|tspan will be converted to group. + + if (el.isGroup) { + el.traverse(function (child) { + child.silent = false; + }); + } + } + + function createRegions(named) { + var regions = []; + var regionsMap = createHashMap(); // Create resions only for the first graphic. + + each(named, function (namedItem) { + // Region has feature to calculate center for tooltip or other features. + // If there is a , the center should be the center of the + // bounding rect of the g. + if (namedItem.namedFrom != null) { + return; + } + + var region = new GeoSVGRegion(namedItem.name, namedItem.el); // PENDING: if `nameMap` supported, this region can not be mounted on + // `this`, but can only be created each time `load()` called. + + regions.push(region); // PENDING: if multiple tag named with the same name, only one will be + // found by `_regionsMap`. `_regionsMap` is used to find a coordinate + // by name. We use `region.getCenter()` as the coordinate. + + regionsMap.set(namedItem.name, region); + }); + return { + regions: regions, + regionsMap: regionsMap + }; + } // PENDING: `nameMap` will not be supported until some real requirement come. + // /** + // * Use the alias in geoNameMap. + // * The input `named` must not be modified. + // */ + // function applyNameMap( + // named: GeoSVGGraphicRecord['named'], + // nameMap: NameMap + // ): GeoSVGGraphicRecord['named'] { + // const result = [] as GeoSVGGraphicRecord['named']; + // for (let i = 0; i < named.length; i++) { + // let regionGraphic = named[i]; + // const name = regionGraphic.name; + // if (nameMap && nameMap.hasOwnProperty(name)) { + // regionGraphic = extend({}, regionGraphic); + // regionGraphic.name = name; + // } + // result.push(regionGraphic); + // } + // return result; + // } + + var geoCoord = [126, 25]; + var nanhaiName = '南海诸岛'; + var points$1 = [[[0, 3.5], [7, 11.2], [15, 11.9], [30, 7], [42, 0.7], [52, 0.7], [56, 7.7], [59, 0.7], [64, 0.7], [64, 0], [5, 0], [0, 3.5]], [[13, 16.1], [19, 14.7], [16, 21.7], [11, 23.1], [13, 16.1]], [[12, 32.2], [14, 38.5], [15, 38.5], [13, 32.2], [12, 32.2]], [[16, 47.6], [12, 53.2], [13, 53.2], [18, 47.6], [16, 47.6]], [[6, 64.4], [8, 70], [9, 70], [8, 64.4], [6, 64.4]], [[23, 82.6], [29, 79.8], [30, 79.8], [25, 82.6], [23, 82.6]], [[37, 70.7], [43, 62.3], [44, 62.3], [39, 70.7], [37, 70.7]], [[48, 51.1], [51, 45.5], [53, 45.5], [50, 51.1], [48, 51.1]], [[51, 35], [51, 28.7], [53, 28.7], [53, 35], [51, 35]], [[52, 22.4], [55, 17.5], [56, 17.5], [53, 22.4], [52, 22.4]], [[58, 12.6], [62, 7], [63, 7], [60, 12.6], [58, 12.6]], [[0, 3.5], [0, 93.1], [64, 93.1], [64, 0], [63, 0], [63, 92.4], [1, 92.4], [1, 3.5], [0, 3.5]]]; + + for (var i = 0; i < points$1.length; i++) { + for (var k = 0; k < points$1[i].length; k++) { + points$1[i][k][0] /= 10.5; + points$1[i][k][1] /= -10.5 / 0.75; + points$1[i][k][0] += geoCoord[0]; + points$1[i][k][1] += geoCoord[1]; + } + } + + function fixNanhai(mapType, regions) { + if (mapType === 'china') { + for (var i = 0; i < regions.length; i++) { + // Already exists. + if (regions[i].name === nanhaiName) { + return; + } + } + + regions.push(new GeoJSONRegion(nanhaiName, map(points$1, function (exterior) { + return { + type: 'polygon', + exterior: exterior + }; + }), geoCoord)); + } + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + var coordsOffsetMap = { + '南海诸岛': [32, 80], + // 全国 + '广东': [0, -10], + '香港': [10, 5], + '澳门': [-10, 10], + //'北京': [-10, 0], + '天津': [5, 5] + }; + function fixTextCoords(mapType, region) { + if (mapType === 'china') { + var coordFix = coordsOffsetMap[region.name]; + + if (coordFix) { + var cp = region.getCenter(); + cp[0] += coordFix[0] / 10.5; + cp[1] += -coordFix[1] / (10.5 / 0.75); + region.setCenter(cp); + } + } + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + // Fix for 钓鱼岛 + // let Region = require('../Region'); + // let zrUtil = require('zrender/lib/core/util'); + // let geoCoord = [126, 25]; + var points$2 = [[[123.45165252685547, 25.73527164402261], [123.49731445312499, 25.73527164402261], [123.49731445312499, 25.750734064600884], [123.45165252685547, 25.750734064600884], [123.45165252685547, 25.73527164402261]]]; + function fixDiaoyuIsland(mapType, region) { + if (mapType === 'china' && region.name === '台湾') { + region.geometries.push({ + type: 'polygon', + exterior: points$2[0] + }); + } + } + + var DEFAULT_NAME_PROPERTY = 'name'; + + var GeoJSONResource = + /** @class */ + function () { + function GeoJSONResource(mapName, geoJSON, specialAreas) { + this.type = 'geoJSON'; + this._parsedMap = createHashMap(); + this._mapName = mapName; + this._specialAreas = specialAreas; // PENDING: delay the parse to the first usage to rapid up the FMP? + + this._geoJSON = parseInput(geoJSON); + } + /** + * @param nameMap can be null/undefined + * @param nameProperty can be null/undefined + */ + + + GeoJSONResource.prototype.load = function (nameMap, nameProperty) { + nameProperty = nameProperty || DEFAULT_NAME_PROPERTY; + + var parsed = this._parsedMap.get(nameProperty); + + if (!parsed) { + var rawRegions = this._parseToRegions(nameProperty); + + parsed = this._parsedMap.set(nameProperty, { + regions: rawRegions, + boundingRect: calculateBoundingRect(rawRegions) + }); + } + + var regionsMap = createHashMap(); + var finalRegions = []; + each(parsed.regions, function (region) { + var regionName = region.name; // Try use the alias in geoNameMap + + if (nameMap && hasOwn(nameMap, regionName)) { + region = region.cloneShallow(regionName = nameMap[regionName]); + } + + finalRegions.push(region); + regionsMap.set(regionName, region); + }); + return { + regions: finalRegions, + boundingRect: parsed.boundingRect || new BoundingRect(0, 0, 0, 0), + regionsMap: regionsMap + }; + }; + + GeoJSONResource.prototype._parseToRegions = function (nameProperty) { + var mapName = this._mapName; + var geoJSON = this._geoJSON; + var rawRegions; // https://jsperf.com/try-catch-performance-overhead + + try { + rawRegions = geoJSON ? parseGeoJSON(geoJSON, nameProperty) : []; + } catch (e) { + throw new Error('Invalid geoJson format\n' + e.message); + } + + fixNanhai(mapName, rawRegions); + each(rawRegions, function (region) { + var regionName = region.name; + fixTextCoords(mapName, region); + fixDiaoyuIsland(mapName, region); // Some area like Alaska in USA map needs to be tansformed + // to look better + + var specialArea = this._specialAreas && this._specialAreas[regionName]; + + if (specialArea) { + region.transformTo(specialArea.left, specialArea.top, specialArea.width, specialArea.height); + } + }, this); + return rawRegions; + }; + /** + * Only for exporting to users. + * **MUST NOT** used internally. + */ + + + GeoJSONResource.prototype.getMapForUser = function () { + return { + // For backward compatibility, use geoJson + // PENDING: it has been returning them without clone. + // do we need to avoid outsite modification? + geoJson: this._geoJSON, + geoJSON: this._geoJSON, + specialAreas: this._specialAreas + }; + }; + + return GeoJSONResource; + }(); + + function calculateBoundingRect(regions) { + var rect; + + for (var i = 0; i < regions.length; i++) { + var regionRect = regions[i].getBoundingRect(); + rect = rect || regionRect.clone(); + rect.union(regionRect); + } + + return rect; + } + + function parseInput(source) { + return !isString(source) ? source : typeof JSON !== 'undefined' && JSON.parse ? JSON.parse(source) : new Function('return (' + source + ');')(); + } + + var storage = createHashMap(); + var geoSourceManager = { + /** + * Compatible with previous `echarts.registerMap`. + * + * @usage + * ```js + * + * echarts.registerMap('USA', geoJson, specialAreas); + * + * echarts.registerMap('USA', { + * geoJson: geoJson, + * specialAreas: {...} + * }); + * echarts.registerMap('USA', { + * geoJSON: geoJson, + * specialAreas: {...} + * }); + * + * echarts.registerMap('airport', { + * svg: svg + * } + * ``` + * + * Note: + * Do not support that register multiple geoJSON or SVG + * one map name. Because different geoJSON and SVG have + * different unit. It's not easy to make sure how those + * units are mapping/normalize. + * If intending to use multiple geoJSON or SVG, we can + * use multiple geo coordinate system. + */ + registerMap: function (mapName, rawDef, rawSpecialAreas) { + if (rawDef.svg) { + var resource = new GeoSVGResource(mapName, rawDef.svg); + storage.set(mapName, resource); + } else { + // Recommend: + // echarts.registerMap('eu', { geoJSON: xxx, specialAreas: xxx }); + // Backward compatibility: + // echarts.registerMap('eu', geoJSON, specialAreas); + // echarts.registerMap('eu', { geoJson: xxx, specialAreas: xxx }); + var geoJSON = rawDef.geoJson || rawDef.geoJSON; + + if (geoJSON && !rawDef.features) { + rawSpecialAreas = rawDef.specialAreas; + } else { + geoJSON = rawDef; + } + + var resource = new GeoJSONResource(mapName, geoJSON, rawSpecialAreas); + storage.set(mapName, resource); + } + }, + getGeoResource: function (mapName) { + return storage.get(mapName); + }, + + /** + * Only for exporting to users. + * **MUST NOT** used internally. + */ + getMapForUser: function (mapName) { + var resource = storage.get(mapName); // Do not support return SVG until some real requirement come. + + return resource && resource.type === 'geoJSON' && resource.getMapForUser(); + }, + load: function (mapName, nameMap, nameProperty) { + var resource = storage.get(mapName); + + if (!resource) { + if ("development" !== 'production') { + console.error('Map ' + mapName + ' not exists. The GeoJSON of the map must be provided.'); + } + + return; + } + + return resource.load(nameMap, nameProperty); + } + }; + + /** + * Only these tags enable use `itemStyle` if they are named in SVG. + * Other tags like might not suitable for `itemStyle`. + * They will not be considered to be styled until some requirements come. + */ + + var OPTION_STYLE_ENABLED_TAGS = ['rect', 'circle', 'line', 'ellipse', 'polygon', 'polyline', 'path']; + var OPTION_STYLE_ENABLED_TAG_MAP = createHashMap(OPTION_STYLE_ENABLED_TAGS); + var STATE_TRIGGER_TAG_MAP = createHashMap(OPTION_STYLE_ENABLED_TAGS.concat(['g'])); + var LABEL_HOST_MAP = createHashMap(OPTION_STYLE_ENABLED_TAGS.concat(['g'])); + var mapLabelRaw = makeInner(); + + function getFixedItemStyle(model) { + var itemStyle = model.getItemStyle(); + var areaColor = model.get('areaColor'); // If user want the color not to be changed when hover, + // they should both set areaColor and color to be null. + + if (areaColor != null) { + itemStyle.fill = areaColor; + } + + return itemStyle; + } // Only stroke can be used for line. + // Using fill in style if stroke not exits. + // TODO Not sure yet. Perhaps a separate `lineStyle`? + + + function fixLineStyle(styleHost) { + var style = styleHost.style; + + if (style) { + style.stroke = style.stroke || style.fill; + style.fill = null; + } + } + + var MapDraw = + /** @class */ + function () { + function MapDraw(api) { + var group = new Group(); + this.uid = getUID('ec_map_draw'); + this._controller = new RoamController(api.getZr()); + this._controllerHost = { + target: group + }; + this.group = group; + group.add(this._regionsGroup = new Group()); + group.add(this._svgGroup = new Group()); + } + + MapDraw.prototype.draw = function (mapOrGeoModel, ecModel, api, fromView, payload) { + var isGeo = mapOrGeoModel.mainType === 'geo'; // Map series has data. GEO model that controlled by map series + // will be assigned with map data. Other GEO model has no data. + + var data = mapOrGeoModel.getData && mapOrGeoModel.getData(); + isGeo && ecModel.eachComponent({ + mainType: 'series', + subType: 'map' + }, function (mapSeries) { + if (!data && mapSeries.getHostGeoModel() === mapOrGeoModel) { + data = mapSeries.getData(); + } + }); + var geo = mapOrGeoModel.coordinateSystem; + var regionsGroup = this._regionsGroup; + var group = this.group; + var transformInfo = geo.getTransformInfo(); + var transformInfoRaw = transformInfo.raw; + var transformInfoRoam = transformInfo.roam; // No animation when first draw or in action + + var isFirstDraw = !regionsGroup.childAt(0) || payload; + + if (isFirstDraw) { + group.x = transformInfoRoam.x; + group.y = transformInfoRoam.y; + group.scaleX = transformInfoRoam.scaleX; + group.scaleY = transformInfoRoam.scaleY; + group.dirty(); + } else { + updateProps(group, transformInfoRoam, mapOrGeoModel); + } + + var isVisualEncodedByVisualMap = data && data.getVisual('visualMeta') && data.getVisual('visualMeta').length > 0; + var viewBuildCtx = { + api: api, + geo: geo, + mapOrGeoModel: mapOrGeoModel, + data: data, + isVisualEncodedByVisualMap: isVisualEncodedByVisualMap, + isGeo: isGeo, + transformInfoRaw: transformInfoRaw + }; + + if (geo.resourceType === 'geoJSON') { + this._buildGeoJSON(viewBuildCtx); + } else if (geo.resourceType === 'geoSVG') { + this._buildSVG(viewBuildCtx); + } + + this._updateController(mapOrGeoModel, ecModel, api); + + this._updateMapSelectHandler(mapOrGeoModel, regionsGroup, api, fromView); + }; + + MapDraw.prototype._buildGeoJSON = function (viewBuildCtx) { + var regionsGroupByName = this._regionsGroupByName = createHashMap(); + var regionsInfoByName = createHashMap(); + var regionsGroup = this._regionsGroup; + var transformInfoRaw = viewBuildCtx.transformInfoRaw; + var mapOrGeoModel = viewBuildCtx.mapOrGeoModel; + var data = viewBuildCtx.data; + var projection = viewBuildCtx.geo.projection; + var projectionStream = projection && projection.stream; + + function transformPoint(point, project) { + if (project) { + // projection may return null point. + point = project(point); + } + + return point && [point[0] * transformInfoRaw.scaleX + transformInfoRaw.x, point[1] * transformInfoRaw.scaleY + transformInfoRaw.y]; + } + + function transformPolygonPoints(inPoints) { + var outPoints = []; // If projectionStream is provided. Use it instead of single point project. + + var project = !projectionStream && projection && projection.project; + + for (var i = 0; i < inPoints.length; ++i) { + var newPt = transformPoint(inPoints[i], project); + newPt && outPoints.push(newPt); + } + + return outPoints; + } + + function getPolyShape(points) { + return { + shape: { + points: transformPolygonPoints(points) + } + }; + } + + regionsGroup.removeAll(); // Only when the resource is GeoJSON, there is `geo.regions`. + + each(viewBuildCtx.geo.regions, function (region) { + var regionName = region.name; // Consider in GeoJson properties.name may be duplicated, for example, + // there is multiple region named "United Kindom" or "France" (so many + // colonies). And it is not appropriate to merge them in geo, which + // will make them share the same label and bring trouble in label + // location calculation. + + var regionGroup = regionsGroupByName.get(regionName); + + var _a = regionsInfoByName.get(regionName) || {}, + dataIdx = _a.dataIdx, + regionModel = _a.regionModel; + + if (!regionGroup) { + regionGroup = regionsGroupByName.set(regionName, new Group()); + regionsGroup.add(regionGroup); + dataIdx = data ? data.indexOfName(regionName) : null; + regionModel = viewBuildCtx.isGeo ? mapOrGeoModel.getRegionModel(regionName) : data ? data.getItemModel(dataIdx) : null; + regionsInfoByName.set(regionName, { + dataIdx: dataIdx, + regionModel: regionModel + }); + } + + var polygonSubpaths = []; + var polylineSubpaths = []; + each(region.geometries, function (geometry) { + // Polygon and MultiPolygon + if (geometry.type === 'polygon') { + var polys = [geometry.exterior].concat(geometry.interiors || []); + + if (projectionStream) { + polys = projectPolys(polys, projectionStream); + } + + each(polys, function (poly) { + polygonSubpaths.push(new Polygon(getPolyShape(poly))); + }); + } // LineString and MultiLineString + else { + var points = geometry.points; + + if (projectionStream) { + points = projectPolys(points, projectionStream, true); + } + + each(points, function (points) { + polylineSubpaths.push(new Polyline(getPolyShape(points))); + }); + } + }); + var centerPt = transformPoint(region.getCenter(), projection && projection.project); + + function createCompoundPath(subpaths, isLine) { + if (!subpaths.length) { + return; + } + + var compoundPath = new CompoundPath({ + culling: true, + segmentIgnoreThreshold: 1, + shape: { + paths: subpaths + } + }); + regionGroup.add(compoundPath); + applyOptionStyleForRegion(viewBuildCtx, compoundPath, dataIdx, regionModel); + resetLabelForRegion(viewBuildCtx, compoundPath, regionName, regionModel, mapOrGeoModel, dataIdx, centerPt); + + if (isLine) { + fixLineStyle(compoundPath); + each(compoundPath.states, fixLineStyle); + } + } + + createCompoundPath(polygonSubpaths); + createCompoundPath(polylineSubpaths, true); + }); // Ensure children have been added to `regionGroup` before calling them. + + regionsGroupByName.each(function (regionGroup, regionName) { + var _a = regionsInfoByName.get(regionName), + dataIdx = _a.dataIdx, + regionModel = _a.regionModel; + + resetEventTriggerForRegion(viewBuildCtx, regionGroup, regionName, regionModel, mapOrGeoModel, dataIdx); + resetTooltipForRegion(viewBuildCtx, regionGroup, regionName, regionModel, mapOrGeoModel); + resetStateTriggerForRegion(viewBuildCtx, regionGroup, regionName, regionModel, mapOrGeoModel); + }, this); + }; + + MapDraw.prototype._buildSVG = function (viewBuildCtx) { + var mapName = viewBuildCtx.geo.map; + var transformInfoRaw = viewBuildCtx.transformInfoRaw; + this._svgGroup.x = transformInfoRaw.x; + this._svgGroup.y = transformInfoRaw.y; + this._svgGroup.scaleX = transformInfoRaw.scaleX; + this._svgGroup.scaleY = transformInfoRaw.scaleY; + + if (this._svgResourceChanged(mapName)) { + this._freeSVG(); + + this._useSVG(mapName); + } + + var svgDispatcherMap = this._svgDispatcherMap = createHashMap(); + var focusSelf = false; + each(this._svgGraphicRecord.named, function (namedItem) { + // Note that we also allow different elements have the same name. + // For example, a glyph of a city and the label of the city have + // the same name and their tooltip info can be defined in a single + // region option. + var regionName = namedItem.name; + var mapOrGeoModel = viewBuildCtx.mapOrGeoModel; + var data = viewBuildCtx.data; + var svgNodeTagLower = namedItem.svgNodeTagLower; + var el = namedItem.el; + var dataIdx = data ? data.indexOfName(regionName) : null; + var regionModel = mapOrGeoModel.getRegionModel(regionName); + + if (OPTION_STYLE_ENABLED_TAG_MAP.get(svgNodeTagLower) != null && el instanceof Displayable) { + applyOptionStyleForRegion(viewBuildCtx, el, dataIdx, regionModel); + } + + if (el instanceof Displayable) { + el.culling = true; + } // We do not know how the SVG like so we'd better not to change z2. + // Otherwise it might bring some unexpected result. For example, + // an area hovered that make some inner city can not be clicked. + + + el.z2EmphasisLift = 0; // If self named: + + if (!namedItem.namedFrom) { + // label should batter to be displayed based on the center of + // if it is named rather than displayed on each child. + if (LABEL_HOST_MAP.get(svgNodeTagLower) != null) { + resetLabelForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel, dataIdx, null); + } + + resetEventTriggerForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel, dataIdx); + resetTooltipForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel); + + if (STATE_TRIGGER_TAG_MAP.get(svgNodeTagLower) != null) { + var focus_1 = resetStateTriggerForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel); + + if (focus_1 === 'self') { + focusSelf = true; + } + + var els = svgDispatcherMap.get(regionName) || svgDispatcherMap.set(regionName, []); + els.push(el); + } + } + }, this); + + this._enableBlurEntireSVG(focusSelf, viewBuildCtx); + }; + + MapDraw.prototype._enableBlurEntireSVG = function (focusSelf, viewBuildCtx) { + // It's a little complicated to support blurring the entire geoSVG in series-map. + // So do not suport it until some requirements come. + // At present, in series-map, only regions can be blurred. + if (focusSelf && viewBuildCtx.isGeo) { + var blurStyle = viewBuildCtx.mapOrGeoModel.getModel(['blur', 'itemStyle']).getItemStyle(); // Only suport `opacity` here. Because not sure that other props are suitable for + // all of the elements generated by SVG (especially for Text/TSpan/Image/... ). + + var opacity_1 = blurStyle.opacity; + + this._svgGraphicRecord.root.traverse(function (el) { + if (!el.isGroup) { + // PENDING: clear those settings to SVG elements when `_freeSVG`. + // (Currently it happen not to be needed.) + setDefaultStateProxy(el); + var style = el.ensureState('blur').style || {}; // Do not overwrite the region style that already set from region option. + + if (style.opacity == null && opacity_1 != null) { + style.opacity = opacity_1; + } // If `ensureState('blur').style = {}`, there will be default opacity. + // Enable `stateTransition` (animation). + + + el.ensureState('emphasis'); + } + }); + } + }; + + MapDraw.prototype.remove = function () { + this._regionsGroup.removeAll(); + + this._regionsGroupByName = null; + + this._svgGroup.removeAll(); + + this._freeSVG(); + + this._controller.dispose(); + + this._controllerHost = null; + }; + + MapDraw.prototype.findHighDownDispatchers = function (name, geoModel) { + if (name == null) { + return []; + } + + var geo = geoModel.coordinateSystem; + + if (geo.resourceType === 'geoJSON') { + var regionsGroupByName = this._regionsGroupByName; + + if (regionsGroupByName) { + var regionGroup = regionsGroupByName.get(name); + return regionGroup ? [regionGroup] : []; + } + } else if (geo.resourceType === 'geoSVG') { + return this._svgDispatcherMap && this._svgDispatcherMap.get(name) || []; + } + }; + + MapDraw.prototype._svgResourceChanged = function (mapName) { + return this._svgMapName !== mapName; + }; + + MapDraw.prototype._useSVG = function (mapName) { + var resource = geoSourceManager.getGeoResource(mapName); + + if (resource && resource.type === 'geoSVG') { + var svgGraphic = resource.useGraphic(this.uid); + + this._svgGroup.add(svgGraphic.root); + + this._svgGraphicRecord = svgGraphic; + this._svgMapName = mapName; + } + }; + + MapDraw.prototype._freeSVG = function () { + var mapName = this._svgMapName; + + if (mapName == null) { + return; + } + + var resource = geoSourceManager.getGeoResource(mapName); + + if (resource && resource.type === 'geoSVG') { + resource.freeGraphic(this.uid); + } + + this._svgGraphicRecord = null; + this._svgDispatcherMap = null; + + this._svgGroup.removeAll(); + + this._svgMapName = null; + }; + + MapDraw.prototype._updateController = function (mapOrGeoModel, ecModel, api) { + var geo = mapOrGeoModel.coordinateSystem; + var controller = this._controller; + var controllerHost = this._controllerHost; // @ts-ignore FIXME:TS + + controllerHost.zoomLimit = mapOrGeoModel.get('scaleLimit'); + controllerHost.zoom = geo.getZoom(); // roamType is will be set default true if it is null + // @ts-ignore FIXME:TS + + controller.enable(mapOrGeoModel.get('roam') || false); + var mainType = mapOrGeoModel.mainType; + + function makeActionBase() { + var action = { + type: 'geoRoam', + componentType: mainType + }; + action[mainType + 'Id'] = mapOrGeoModel.id; + return action; + } + + controller.off('pan').on('pan', function (e) { + this._mouseDownFlag = false; + updateViewOnPan(controllerHost, e.dx, e.dy); + api.dispatchAction(extend(makeActionBase(), { + dx: e.dx, + dy: e.dy, + animation: { + duration: 0 + } + })); + }, this); + controller.off('zoom').on('zoom', function (e) { + this._mouseDownFlag = false; + updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY); + api.dispatchAction(extend(makeActionBase(), { + zoom: e.scale, + originX: e.originX, + originY: e.originY, + animation: { + duration: 0 + } + })); + }, this); + controller.setPointerChecker(function (e, x, y) { + return geo.containPoint([x, y]) && !onIrrelevantElement(e, api, mapOrGeoModel); + }); + }; + /** + * FIXME: this is a temporarily workaround. + * When `geoRoam` the elements need to be reset in `MapView['render']`, because the props like + * `ignore` might have been modified by `LabelManager`, and `LabelManager#addLabelsOfSeries` + * will subsequently cache `defaultAttr` like `ignore`. If do not do this reset, the modified + * props will have no chance to be restored. + * Note: this reset should be after `clearStates` in `renderSeries` becuase `useStates` in + * `renderSeries` will cache the modified `ignore` to `el._normalState`. + * TODO: + * Use clone/immutable in `LabelManager`? + */ + + + MapDraw.prototype.resetForLabelLayout = function () { + this.group.traverse(function (el) { + var label = el.getTextContent(); + + if (label) { + label.ignore = mapLabelRaw(label).ignore; + } + }); + }; + + MapDraw.prototype._updateMapSelectHandler = function (mapOrGeoModel, regionsGroup, api, fromView) { + var mapDraw = this; + regionsGroup.off('mousedown'); + regionsGroup.off('click'); // @ts-ignore FIXME:TS resolve type conflict + + if (mapOrGeoModel.get('selectedMode')) { + regionsGroup.on('mousedown', function () { + mapDraw._mouseDownFlag = true; + }); + regionsGroup.on('click', function (e) { + if (!mapDraw._mouseDownFlag) { + return; + } + + mapDraw._mouseDownFlag = false; + }); + } + }; + + return MapDraw; + }(); + + function applyOptionStyleForRegion(viewBuildCtx, el, dataIndex, regionModel) { + // All of the path are using `itemStyle`, becuase + // (1) Some SVG also use fill on polyline (The different between + // polyline and polygon is "open" or "close" but not fill or not). + // (2) For the common props like opacity, if some use itemStyle + // and some use `lineStyle`, it might confuse users. + // (3) Most SVG use , where can not detect wether draw a "line" + // or a filled shape, so use `itemStyle` for . + var normalStyleModel = regionModel.getModel('itemStyle'); + var emphasisStyleModel = regionModel.getModel(['emphasis', 'itemStyle']); + var blurStyleModel = regionModel.getModel(['blur', 'itemStyle']); + var selectStyleModel = regionModel.getModel(['select', 'itemStyle']); // NOTE: DONT use 'style' in visual when drawing map. + // This component is used for drawing underlying map for both geo component and map series. + + var normalStyle = getFixedItemStyle(normalStyleModel); + var emphasisStyle = getFixedItemStyle(emphasisStyleModel); + var selectStyle = getFixedItemStyle(selectStyleModel); + var blurStyle = getFixedItemStyle(blurStyleModel); // Update the itemStyle if has data visual + + var data = viewBuildCtx.data; + + if (data) { + // Only visual color of each item will be used. It can be encoded by visualMap + // But visual color of series is used in symbol drawing + // Visual color for each series is for the symbol draw + var style = data.getItemVisual(dataIndex, 'style'); + var decal = data.getItemVisual(dataIndex, 'decal'); + + if (viewBuildCtx.isVisualEncodedByVisualMap && style.fill) { + normalStyle.fill = style.fill; + } + + if (decal) { + normalStyle.decal = createOrUpdatePatternFromDecal(decal, viewBuildCtx.api); + } + } // SVG text, tspan and image can be named but not supporeted + // to be styled by region option yet. + + + el.setStyle(normalStyle); + el.style.strokeNoScale = true; + el.ensureState('emphasis').style = emphasisStyle; + el.ensureState('select').style = selectStyle; + el.ensureState('blur').style = blurStyle; // Enable blur + + setDefaultStateProxy(el); + } + + function resetLabelForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel, // Exist only if `viewBuildCtx.data` exists. + dataIdx, // If labelXY not provided, use `textConfig.position: 'inside'` + labelXY) { + var data = viewBuildCtx.data; + var isGeo = viewBuildCtx.isGeo; + var isDataNaN = data && isNaN(data.get(data.mapDimension('value'), dataIdx)); + var itemLayout = data && data.getItemLayout(dataIdx); // In the following cases label will be drawn + // 1. In map series and data value is NaN + // 2. In geo component + // 3. Region has no series legendIcon, which will be add a showLabel flag in mapSymbolLayout + + if (isGeo || isDataNaN || itemLayout && itemLayout.showLabel) { + var query = !isGeo ? dataIdx : regionName; + var labelFetcher = void 0; // Consider dataIdx not found. + + if (!data || dataIdx >= 0) { + labelFetcher = mapOrGeoModel; + } + + var specifiedTextOpt = labelXY ? { + normal: { + align: 'center', + verticalAlign: 'middle' + } + } : null; // Caveat: must be called after `setDefaultStateProxy(el);` called. + // because textContent will be assign with `el.stateProxy` inside. + + setLabelStyle(el, getLabelStatesModels(regionModel), { + labelFetcher: labelFetcher, + labelDataIndex: query, + defaultText: regionName + }, specifiedTextOpt); + var textEl = el.getTextContent(); + + if (textEl) { + mapLabelRaw(textEl).ignore = textEl.ignore; + + if (el.textConfig && labelXY) { + // Compute a relative offset based on the el bounding rect. + var rect = el.getBoundingRect().clone(); // Need to make sure the percent position base on the same rect in normal and + // emphasis state. Otherwise if using boundingRect of el, but the emphasis state + // has borderWidth (even 0.5px), the text position will be changed obviously + // if the position is very big like ['1234%', '1345%']. + + el.textConfig.layoutRect = rect; + el.textConfig.position = [(labelXY[0] - rect.x) / rect.width * 100 + '%', (labelXY[1] - rect.y) / rect.height * 100 + '%']; + } + } // PENDING: + // If labelLayout is enabled (test/label-layout.html), el.dataIndex should be specified. + // But el.dataIndex is also used to determine whether user event should be triggered, + // where el.seriesIndex or el.dataModel must be specified. At present for a single el + // there is not case that "only label layout enabled but user event disabled", so here + // we depends `resetEventTriggerForRegion` to do the job of setting `el.dataIndex`. + + + el.disableLabelAnimation = true; + } else { + el.removeTextContent(); + el.removeTextConfig(); + el.disableLabelAnimation = null; + } + } + + function resetEventTriggerForRegion(viewBuildCtx, eventTrigger, regionName, regionModel, mapOrGeoModel, // Exist only if `viewBuildCtx.data` exists. + dataIdx) { + // setItemGraphicEl, setHoverStyle after all polygons and labels + // are added to the rigionGroup + if (viewBuildCtx.data) { + // FIXME: when series-map use a SVG map, and there are duplicated name specified + // on different SVG elements, after `data.setItemGraphicEl(...)`: + // (1) all of them will be mounted with `dataIndex`, `seriesIndex`, so that tooltip + // can be triggered only mouse hover. That's correct. + // (2) only the last element will be kept in `data`, so that if trigger tooltip + // by `dispatchAction`, only the last one can be found and triggered. That might be + // not correct. We will fix it in future if anyone demanding that. + viewBuildCtx.data.setItemGraphicEl(dataIdx, eventTrigger); + } // series-map will not trigger "geoselectchange" no matter it is + // based on a declared geo component. Becuause series-map will + // trigger "selectchange". If it trigger both the two events, + // If users call `chart.dispatchAction({type: 'toggleSelect'})`, + // it not easy to also fire event "geoselectchanged". + else { + // Package custom mouse event for geo component + getECData(eventTrigger).eventData = { + componentType: 'geo', + componentIndex: mapOrGeoModel.componentIndex, + geoIndex: mapOrGeoModel.componentIndex, + name: regionName, + region: regionModel && regionModel.option || {} + }; + } + } + + function resetTooltipForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel) { + if (!viewBuildCtx.data) { + setTooltipConfig({ + el: el, + componentModel: mapOrGeoModel, + itemName: regionName, + // @ts-ignore FIXME:TS fix the "compatible with each other"? + itemTooltipOption: regionModel.get('tooltip') + }); + } + } + + function resetStateTriggerForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel) { + // @ts-ignore FIXME:TS fix the "compatible with each other"? + el.highDownSilentOnTouch = !!mapOrGeoModel.get('selectedMode'); // @ts-ignore FIXME:TS fix the "compatible with each other"? + + var emphasisModel = regionModel.getModel('emphasis'); + var focus = emphasisModel.get('focus'); + toggleHoverEmphasis(el, focus, emphasisModel.get('blurScope'), emphasisModel.get('disabled')); + + if (viewBuildCtx.isGeo) { + enableComponentHighDownFeatures(el, mapOrGeoModel, regionName); + } + + return focus; + } + + function projectPolys(rings, // Polygons include exterior and interiors. Or polylines. + createStream, isLine) { + var polygons = []; + var curPoly; + + function startPolygon() { + curPoly = []; + } + + function endPolygon() { + if (curPoly.length) { + polygons.push(curPoly); + curPoly = []; + } + } + + var stream = createStream({ + polygonStart: startPolygon, + polygonEnd: endPolygon, + lineStart: startPolygon, + lineEnd: endPolygon, + point: function (x, y) { + // May have NaN values from stream. + if (isFinite(x) && isFinite(y)) { + curPoly.push([x, y]); + } + }, + sphere: function () {} + }); + !isLine && stream.polygonStart(); + each(rings, function (ring) { + stream.lineStart(); + + for (var i = 0; i < ring.length; i++) { + stream.point(ring[i][0], ring[i][1]); + } + + stream.lineEnd(); + }); + !isLine && stream.polygonEnd(); + return polygons; + } + // @ts-ignore FIXME:TS fix the "compatible with each other"? + + var MapView = + /** @class */ + function (_super) { + __extends(MapView, _super); + + function MapView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MapView.type; + return _this; + } + + MapView.prototype.render = function (mapModel, ecModel, api, payload) { + // Not render if it is an toggleSelect action from self + if (payload && payload.type === 'mapToggleSelect' && payload.from === this.uid) { + return; + } + + var group = this.group; + group.removeAll(); + + if (mapModel.getHostGeoModel()) { + return; + } + + if (this._mapDraw && payload && payload.type === 'geoRoam') { + this._mapDraw.resetForLabelLayout(); + } // Not update map if it is an roam action from self + + + if (!(payload && payload.type === 'geoRoam' && payload.componentType === 'series' && payload.seriesId === mapModel.id)) { + if (mapModel.needsDrawMap) { + var mapDraw = this._mapDraw || new MapDraw(api); + group.add(mapDraw.group); + mapDraw.draw(mapModel, ecModel, api, this, payload); + this._mapDraw = mapDraw; + } else { + // Remove drawed map + this._mapDraw && this._mapDraw.remove(); + this._mapDraw = null; + } + } else { + var mapDraw = this._mapDraw; + mapDraw && group.add(mapDraw.group); + } + + mapModel.get('showLegendSymbol') && ecModel.getComponent('legend') && this._renderSymbols(mapModel, ecModel, api); + }; + + MapView.prototype.remove = function () { + this._mapDraw && this._mapDraw.remove(); + this._mapDraw = null; + this.group.removeAll(); + }; + + MapView.prototype.dispose = function () { + this._mapDraw && this._mapDraw.remove(); + this._mapDraw = null; + }; + + MapView.prototype._renderSymbols = function (mapModel, ecModel, api) { + var originalData = mapModel.originalData; + var group = this.group; + originalData.each(originalData.mapDimension('value'), function (value, originalDataIndex) { + if (isNaN(value)) { + return; + } + + var layout = originalData.getItemLayout(originalDataIndex); + + if (!layout || !layout.point) { + // Not exists in map + return; + } + + var point = layout.point; + var offset = layout.offset; + var circle = new Circle({ + style: { + // Because the special of map draw. + // Which needs statistic of multiple series and draw on one map. + // And each series also need a symbol with legend color + // + // Layout and visual are put one the different data + // TODO + fill: mapModel.getData().getVisual('style').fill + }, + shape: { + cx: point[0] + offset * 9, + cy: point[1], + r: 3 + }, + silent: true, + // Do not overlap the first series, on which labels are displayed. + z2: 8 + (!offset ? Z2_EMPHASIS_LIFT + 1 : 0) + }); // Only the series that has the first value on the same region is in charge of rendering the label. + // But consider the case: + // series: [ + // {id: 'X', type: 'map', map: 'm', {data: [{name: 'A', value: 11}, {name: 'B', {value: 22}]}, + // {id: 'Y', type: 'map', map: 'm', {data: [{name: 'A', value: 21}, {name: 'C', {value: 33}]} + // ] + // The offset `0` of item `A` is at series `X`, but of item `C` is at series `Y`. + // For backward compatibility, we follow the rule that render label `A` by the + // settings on series `X` but render label `C` by the settings on series `Y`. + + if (!offset) { + var fullData = mapModel.mainSeries.getData(); + var name_1 = originalData.getName(originalDataIndex); + var fullIndex_1 = fullData.indexOfName(name_1); + var itemModel = originalData.getItemModel(originalDataIndex); + var labelModel = itemModel.getModel('label'); + var regionGroup = fullData.getItemGraphicEl(fullIndex_1); // `getFormattedLabel` needs to use `getData` inside. Here + // `mapModel.getData()` is shallow cloned from `mainSeries.getData()`. + // FIXME + // If this is not the `mainSeries`, the item model (like label formatter) + // set on original data item will never get. But it has been working + // like that from the begining, and this scenario is rarely encountered. + // So it won't be fixed until have to. + + setLabelStyle(circle, getLabelStatesModels(itemModel), { + labelFetcher: { + getFormattedLabel: function (idx, state) { + return mapModel.getFormattedLabel(fullIndex_1, state); + } + }, + defaultText: name_1 + }); + circle.disableLabelAnimation = true; + + if (!labelModel.get('position')) { + circle.setTextConfig({ + position: 'bottom' + }); + } + + regionGroup.onHoverStateChange = function (toState) { + setStatesFlag(circle, toState); + }; + } + + group.add(circle); + }); + }; + + MapView.type = 'map'; + return MapView; + }(ChartView); + + var MapSeries = + /** @class */ + function (_super) { + __extends(MapSeries, _super); + + function MapSeries() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MapSeries.type; // Only first map series of same mapType will drawMap. + + _this.needsDrawMap = false; // Group of all map series with same mapType + + _this.seriesGroup = []; + + _this.getTooltipPosition = function (dataIndex) { + if (dataIndex != null) { + var name_1 = this.getData().getName(dataIndex); + var geo = this.coordinateSystem; + var region = geo.getRegion(name_1); + return region && geo.dataToPoint(region.getCenter()); + } + }; + + return _this; + } + + MapSeries.prototype.getInitialData = function (option) { + var data = createSeriesDataSimply(this, { + coordDimensions: ['value'], + encodeDefaulter: curry(makeSeriesEncodeForNameBased, this) + }); + var dataNameMap = createHashMap(); + var toAppendNames = []; + + for (var i = 0, len = data.count(); i < len; i++) { + var name_2 = data.getName(i); + dataNameMap.set(name_2, true); + } + + var geoSource = geoSourceManager.load(this.getMapType(), this.option.nameMap, this.option.nameProperty); + each(geoSource.regions, function (region) { + var name = region.name; + + if (!dataNameMap.get(name)) { + toAppendNames.push(name); + } + }); // Complete data with missing regions. The consequent processes (like visual + // map and render) can not be performed without a "full data". For example, + // find `dataIndex` by name. + + data.appendValues([], toAppendNames); + return data; + }; + /** + * If no host geo model, return null, which means using a + * inner exclusive geo model. + */ + + + MapSeries.prototype.getHostGeoModel = function () { + var geoIndex = this.option.geoIndex; + return geoIndex != null ? this.ecModel.getComponent('geo', geoIndex) : null; + }; + + MapSeries.prototype.getMapType = function () { + return (this.getHostGeoModel() || this).option.map; + }; // _fillOption(option, mapName) { + // Shallow clone + // option = zrUtil.extend({}, option); + // option.data = geoCreator.getFilledRegions(option.data, mapName, option.nameMap); + // return option; + // } + + + MapSeries.prototype.getRawValue = function (dataIndex) { + // Use value stored in data instead because it is calculated from multiple series + // FIXME Provide all value of multiple series ? + var data = this.getData(); + return data.get(data.mapDimension('value'), dataIndex); + }; + /** + * Get model of region + */ + + + MapSeries.prototype.getRegionModel = function (regionName) { + var data = this.getData(); + return data.getItemModel(data.indexOfName(regionName)); + }; + /** + * Map tooltip formatter + */ + + + MapSeries.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + // FIXME orignalData and data is a bit confusing + var data = this.getData(); + var value = this.getRawValue(dataIndex); + var name = data.getName(dataIndex); + var seriesGroup = this.seriesGroup; + var seriesNames = []; + + for (var i = 0; i < seriesGroup.length; i++) { + var otherIndex = seriesGroup[i].originalData.indexOfName(name); + var valueDim = data.mapDimension('value'); + + if (!isNaN(seriesGroup[i].originalData.get(valueDim, otherIndex))) { + seriesNames.push(seriesGroup[i].name); + } + } + + return createTooltipMarkup('section', { + header: seriesNames.join(', '), + noHeader: !seriesNames.length, + blocks: [createTooltipMarkup('nameValue', { + name: name, + value: value + })] + }); + }; + + MapSeries.prototype.setZoom = function (zoom) { + this.option.zoom = zoom; + }; + + MapSeries.prototype.setCenter = function (center) { + this.option.center = center; + }; + + MapSeries.prototype.getLegendIcon = function (opt) { + var iconType = opt.icon || 'roundRect'; + var icon = createSymbol(iconType, 0, 0, opt.itemWidth, opt.itemHeight, opt.itemStyle.fill); + icon.setStyle(opt.itemStyle); // Map do not use itemStyle.borderWidth as border width + + icon.style.stroke = 'none'; // No rotation because no series visual symbol for map + + if (iconType.indexOf('empty') > -1) { + icon.style.stroke = icon.style.fill; + icon.style.fill = '#fff'; + icon.style.lineWidth = 2; + } + + return icon; + }; + + MapSeries.type = 'series.map'; + MapSeries.dependencies = ['geo']; + MapSeries.layoutMode = 'box'; + MapSeries.defaultOption = { + // 一级层叠 + // zlevel: 0, + // 二级层叠 + z: 2, + coordinateSystem: 'geo', + // map should be explicitly specified since ec3. + map: '', + // If `geoIndex` is not specified, a exclusive geo will be + // created. Otherwise use the specified geo component, and + // `map` and `mapType` are ignored. + // geoIndex: 0, + // 'center' | 'left' | 'right' | 'x%' | {number} + left: 'center', + // 'center' | 'top' | 'bottom' | 'x%' | {number} + top: 'center', + // right + // bottom + // width: + // height + // Aspect is width / height. Inited to be geoJson bbox aspect + // This parameter is used for scale this aspect + // Default value: + // for geoSVG source: 1, + // for geoJSON source: 0.75. + aspectScale: null, + ///// Layout with center and size + // If you wan't to put map in a fixed size box with right aspect ratio + // This two properties may more conveninet + // layoutCenter: [50%, 50%] + // layoutSize: 100 + showLegendSymbol: true, + // Define left-top, right-bottom coords to control view + // For example, [ [180, 90], [-180, -90] ], + // higher priority than center and zoom + boundingCoords: null, + // Default on center of map + center: null, + zoom: 1, + scaleLimit: null, + selectedMode: true, + label: { + show: false, + color: '#000' + }, + // scaleLimit: null, + itemStyle: { + borderWidth: 0.5, + borderColor: '#444', + areaColor: '#eee' + }, + emphasis: { + label: { + show: true, + color: 'rgb(100,0,0)' + }, + itemStyle: { + areaColor: 'rgba(255,215,0,0.8)' + } + }, + select: { + label: { + show: true, + color: 'rgb(100,0,0)' + }, + itemStyle: { + color: 'rgba(255,215,0,0.8)' + } + }, + nameProperty: 'name' + }; + return MapSeries; + }(SeriesModel); + + function dataStatistics(datas, statisticType) { + var dataNameMap = {}; + each(datas, function (data) { + data.each(data.mapDimension('value'), function (value, idx) { + // Add prefix to avoid conflict with Object.prototype. + var mapKey = 'ec-' + data.getName(idx); + dataNameMap[mapKey] = dataNameMap[mapKey] || []; + + if (!isNaN(value)) { + dataNameMap[mapKey].push(value); + } + }); + }); + return datas[0].map(datas[0].mapDimension('value'), function (value, idx) { + var mapKey = 'ec-' + datas[0].getName(idx); + var sum = 0; + var min = Infinity; + var max = -Infinity; + var len = dataNameMap[mapKey].length; + + for (var i = 0; i < len; i++) { + min = Math.min(min, dataNameMap[mapKey][i]); + max = Math.max(max, dataNameMap[mapKey][i]); + sum += dataNameMap[mapKey][i]; + } + + var result; + + if (statisticType === 'min') { + result = min; + } else if (statisticType === 'max') { + result = max; + } else if (statisticType === 'average') { + result = sum / len; + } else { + result = sum; + } + + return len === 0 ? NaN : result; + }); + } + + function mapDataStatistic(ecModel) { + var seriesGroups = {}; + ecModel.eachSeriesByType('map', function (seriesModel) { + var hostGeoModel = seriesModel.getHostGeoModel(); + var key = hostGeoModel ? 'o' + hostGeoModel.id : 'i' + seriesModel.getMapType(); + (seriesGroups[key] = seriesGroups[key] || []).push(seriesModel); + }); + each(seriesGroups, function (seriesList, key) { + var data = dataStatistics(map(seriesList, function (seriesModel) { + return seriesModel.getData(); + }), seriesList[0].get('mapValueCalculation')); + + for (var i = 0; i < seriesList.length; i++) { + seriesList[i].originalData = seriesList[i].getData(); + } // FIXME Put where? + + + for (var i = 0; i < seriesList.length; i++) { + seriesList[i].seriesGroup = seriesList; + seriesList[i].needsDrawMap = i === 0 && !seriesList[i].getHostGeoModel(); + seriesList[i].setData(data.cloneShallow()); + seriesList[i].mainSeries = seriesList[0]; + } + }); + } + + function mapSymbolLayout(ecModel) { + var processedMapType = {}; + ecModel.eachSeriesByType('map', function (mapSeries) { + var mapType = mapSeries.getMapType(); + + if (mapSeries.getHostGeoModel() || processedMapType[mapType]) { + return; + } + + var mapSymbolOffsets = {}; + each(mapSeries.seriesGroup, function (subMapSeries) { + var geo = subMapSeries.coordinateSystem; + var data = subMapSeries.originalData; + + if (subMapSeries.get('showLegendSymbol') && ecModel.getComponent('legend')) { + data.each(data.mapDimension('value'), function (value, idx) { + var name = data.getName(idx); + var region = geo.getRegion(name); // If input series.data is [11, 22, '-'/null/undefined, 44], + // it will be filled with NaN: [11, 22, NaN, 44] and NaN will + // not be drawn. So here must validate if value is NaN. + + if (!region || isNaN(value)) { + return; + } + + var offset = mapSymbolOffsets[name] || 0; + var point = geo.dataToPoint(region.getCenter()); + mapSymbolOffsets[name] = offset + 1; + data.setItemLayout(idx, { + point: point, + offset: offset + }); + }); + } + }); // Show label of those region not has legendIcon (which is offset 0) + + var data = mapSeries.getData(); + data.each(function (idx) { + var name = data.getName(idx); + var layout = data.getItemLayout(idx) || {}; + layout.showLabel = !mapSymbolOffsets[name]; + data.setItemLayout(idx, layout); + }); + processedMapType[mapType] = true; + }); + } + + var v2ApplyTransform = applyTransform; + + var View = + /** @class */ + function (_super) { + __extends(View, _super); + + function View(name) { + var _this = _super.call(this) || this; + + _this.type = 'view'; + _this.dimensions = ['x', 'y']; + /** + * Represents the transform brought by roam/zoom. + * If `View['_viewRect']` applies roam transform, + * we can get the final displayed rect. + */ + + _this._roamTransformable = new Transformable(); + /** + * Represents the transform from `View['_rect']` to `View['_viewRect']`. + */ + + _this._rawTransformable = new Transformable(); + _this.name = name; + return _this; + } + + View.prototype.setBoundingRect = function (x, y, width, height) { + this._rect = new BoundingRect(x, y, width, height); + return this._rect; + }; + /** + * @return {module:zrender/core/BoundingRect} + */ + + + View.prototype.getBoundingRect = function () { + return this._rect; + }; + + View.prototype.setViewRect = function (x, y, width, height) { + this._transformTo(x, y, width, height); + + this._viewRect = new BoundingRect(x, y, width, height); + }; + /** + * Transformed to particular position and size + */ + + + View.prototype._transformTo = function (x, y, width, height) { + var rect = this.getBoundingRect(); + var rawTransform = this._rawTransformable; + rawTransform.transform = rect.calculateTransform(new BoundingRect(x, y, width, height)); + var rawParent = rawTransform.parent; + rawTransform.parent = null; + rawTransform.decomposeTransform(); + rawTransform.parent = rawParent; + + this._updateTransform(); + }; + /** + * Set center of view + */ + + + View.prototype.setCenter = function (centerCoord) { + if (!centerCoord) { + return; + } + + this._center = centerCoord; + + this._updateCenterAndZoom(); + }; + + View.prototype.setZoom = function (zoom) { + zoom = zoom || 1; + var zoomLimit = this.zoomLimit; + + if (zoomLimit) { + if (zoomLimit.max != null) { + zoom = Math.min(zoomLimit.max, zoom); + } + + if (zoomLimit.min != null) { + zoom = Math.max(zoomLimit.min, zoom); + } + } + + this._zoom = zoom; + + this._updateCenterAndZoom(); + }; + /** + * Get default center without roam + */ + + + View.prototype.getDefaultCenter = function () { + // Rect before any transform + var rawRect = this.getBoundingRect(); + var cx = rawRect.x + rawRect.width / 2; + var cy = rawRect.y + rawRect.height / 2; + return [cx, cy]; + }; + + View.prototype.getCenter = function () { + return this._center || this.getDefaultCenter(); + }; + + View.prototype.getZoom = function () { + return this._zoom || 1; + }; + + View.prototype.getRoamTransform = function () { + return this._roamTransformable.getLocalTransform(); + }; + /** + * Remove roam + */ + + + View.prototype._updateCenterAndZoom = function () { + // Must update after view transform updated + var rawTransformMatrix = this._rawTransformable.getLocalTransform(); + + var roamTransform = this._roamTransformable; + var defaultCenter = this.getDefaultCenter(); + var center = this.getCenter(); + var zoom = this.getZoom(); + center = applyTransform([], center, rawTransformMatrix); + defaultCenter = applyTransform([], defaultCenter, rawTransformMatrix); + roamTransform.originX = center[0]; + roamTransform.originY = center[1]; + roamTransform.x = defaultCenter[0] - center[0]; + roamTransform.y = defaultCenter[1] - center[1]; + roamTransform.scaleX = roamTransform.scaleY = zoom; + + this._updateTransform(); + }; + /** + * Update transform props on `this` based on the current + * `this._roamTransformable` and `this._rawTransformable`. + */ + + + View.prototype._updateTransform = function () { + var roamTransformable = this._roamTransformable; + var rawTransformable = this._rawTransformable; + rawTransformable.parent = roamTransformable; + roamTransformable.updateTransform(); + rawTransformable.updateTransform(); + copy$1(this.transform || (this.transform = []), rawTransformable.transform || create$1()); + this._rawTransform = rawTransformable.getLocalTransform(); + this.invTransform = this.invTransform || []; + invert(this.invTransform, this.transform); + this.decomposeTransform(); + }; + + View.prototype.getTransformInfo = function () { + var rawTransformable = this._rawTransformable; + var roamTransformable = this._roamTransformable; // Becuase roamTransformabel has `originX/originY` modified, + // but the caller of `getTransformInfo` can not handle `originX/originY`, + // so need to recalcualte them. + + var dummyTransformable = new Transformable(); + dummyTransformable.transform = roamTransformable.transform; + dummyTransformable.decomposeTransform(); + return { + roam: { + x: dummyTransformable.x, + y: dummyTransformable.y, + scaleX: dummyTransformable.scaleX, + scaleY: dummyTransformable.scaleY + }, + raw: { + x: rawTransformable.x, + y: rawTransformable.y, + scaleX: rawTransformable.scaleX, + scaleY: rawTransformable.scaleY + } + }; + }; + + View.prototype.getViewRect = function () { + return this._viewRect; + }; + /** + * Get view rect after roam transform + */ + + + View.prototype.getViewRectAfterRoam = function () { + var rect = this.getBoundingRect().clone(); + rect.applyTransform(this.transform); + return rect; + }; + /** + * Convert a single (lon, lat) data item to (x, y) point. + */ + + + View.prototype.dataToPoint = function (data, noRoam, out) { + var transform = noRoam ? this._rawTransform : this.transform; + out = out || []; + return transform ? v2ApplyTransform(out, data, transform) : copy(out, data); + }; + /** + * Convert a (x, y) point to (lon, lat) data + */ + + + View.prototype.pointToData = function (point) { + var invTransform = this.invTransform; + return invTransform ? v2ApplyTransform([], point, invTransform) : [point[0], point[1]]; + }; + + View.prototype.convertToPixel = function (ecModel, finder, value) { + var coordSys = getCoordSys(finder); + return coordSys === this ? coordSys.dataToPoint(value) : null; + }; + + View.prototype.convertFromPixel = function (ecModel, finder, pixel) { + var coordSys = getCoordSys(finder); + return coordSys === this ? coordSys.pointToData(pixel) : null; + }; + /** + * @implements + */ + + + View.prototype.containPoint = function (point) { + return this.getViewRectAfterRoam().contain(point[0], point[1]); + }; + + View.dimensions = ['x', 'y']; + return View; + }(Transformable); + + function getCoordSys(finder) { + var seriesModel = finder.seriesModel; + return seriesModel ? seriesModel.coordinateSystem : null; // e.g., graph. + } + + var GEO_DEFAULT_PARAMS = { + 'geoJSON': { + aspectScale: 0.75, + invertLongitute: true + }, + 'geoSVG': { + aspectScale: 1, + invertLongitute: false + } + }; + var geo2DDimensions = ['lng', 'lat']; + + var Geo = + /** @class */ + function (_super) { + __extends(Geo, _super); + + function Geo(name, map, opt) { + var _this = _super.call(this, name) || this; + + _this.dimensions = geo2DDimensions; + _this.type = 'geo'; // Only store specified name coord via `addGeoCoord`. + + _this._nameCoordMap = createHashMap(); + _this.map = map; + var projection = opt.projection; + var source = geoSourceManager.load(map, opt.nameMap, opt.nameProperty); + var resource = geoSourceManager.getGeoResource(map); + var resourceType = _this.resourceType = resource ? resource.type : null; + var regions = _this.regions = source.regions; + var defaultParams = GEO_DEFAULT_PARAMS[resource.type]; + _this._regionsMap = source.regionsMap; + _this.regions = source.regions; + + if ("development" !== 'production' && projection) { + // Do some check + if (resourceType === 'geoSVG') { + if ("development" !== 'production') { + warn("Map " + map + " with SVG source can't use projection. Only GeoJSON source supports projection."); + } + + projection = null; + } + + if (!(projection.project && projection.unproject)) { + if ("development" !== 'production') { + warn('project and unproject must be both provided in the projeciton.'); + } + + projection = null; + } + } + + _this.projection = projection; + var boundingRect; + + if (projection) { + // Can't reuse the raw bounding rect + for (var i = 0; i < regions.length; i++) { + var regionRect = regions[i].getBoundingRect(projection); + boundingRect = boundingRect || regionRect.clone(); + boundingRect.union(regionRect); + } + } else { + boundingRect = source.boundingRect; + } + + _this.setBoundingRect(boundingRect.x, boundingRect.y, boundingRect.width, boundingRect.height); // aspectScale and invertLongitute actually is the parameters default raw projection. + // So we ignore them if projection is given. + // Ignore default aspect scale if projection exits. + + + _this.aspectScale = projection ? 1 : retrieve2(opt.aspectScale, defaultParams.aspectScale); // Not invert longitute if projection exits. + + _this._invertLongitute = projection ? false : defaultParams.invertLongitute; + return _this; + } + + Geo.prototype._transformTo = function (x, y, width, height) { + var rect = this.getBoundingRect(); + var invertLongitute = this._invertLongitute; + rect = rect.clone(); + + if (invertLongitute) { + // Longitute is inverted + rect.y = -rect.y - rect.height; + } + + var rawTransformable = this._rawTransformable; + rawTransformable.transform = rect.calculateTransform(new BoundingRect(x, y, width, height)); + var rawParent = rawTransformable.parent; + rawTransformable.parent = null; + rawTransformable.decomposeTransform(); + rawTransformable.parent = rawParent; + + if (invertLongitute) { + rawTransformable.scaleY = -rawTransformable.scaleY; + } + + this._updateTransform(); + }; + + Geo.prototype.getRegion = function (name) { + return this._regionsMap.get(name); + }; + + Geo.prototype.getRegionByCoord = function (coord) { + var regions = this.regions; + + for (var i = 0; i < regions.length; i++) { + var region = regions[i]; + + if (region.type === 'geoJSON' && region.contain(coord)) { + return regions[i]; + } + } + }; + /** + * Add geoCoord for indexing by name + */ + + + Geo.prototype.addGeoCoord = function (name, geoCoord) { + this._nameCoordMap.set(name, geoCoord); + }; + /** + * Get geoCoord by name + */ + + + Geo.prototype.getGeoCoord = function (name) { + var region = this._regionsMap.get(name); // calcualte center only on demand. + + + return this._nameCoordMap.get(name) || region && region.getCenter(); + }; + + Geo.prototype.dataToPoint = function (data, noRoam, out) { + if (isString(data)) { + // Map area name to geoCoord + data = this.getGeoCoord(data); + } + + if (data) { + var projection = this.projection; + + if (projection) { + // projection may return null point. + data = projection.project(data); + } + + return data && this.projectedToPoint(data); + } + }; + + Geo.prototype.pointToData = function (point) { + var projection = this.projection; + + if (projection) { + // projection may return null point. + point = projection.unproject(point); + } + + return point && this.pointToProjected(point); + }; + /** + * Point to projected data. Same with pointToData when projection is used. + */ + + + Geo.prototype.pointToProjected = function (point) { + return _super.prototype.pointToData.call(this, point); + }; + + Geo.prototype.projectedToPoint = function (projected, noRoam, out) { + return _super.prototype.dataToPoint.call(this, projected, noRoam, out); + }; + + Geo.prototype.convertToPixel = function (ecModel, finder, value) { + var coordSys = getCoordSys$1(finder); + return coordSys === this ? coordSys.dataToPoint(value) : null; + }; + + Geo.prototype.convertFromPixel = function (ecModel, finder, pixel) { + var coordSys = getCoordSys$1(finder); + return coordSys === this ? coordSys.pointToData(pixel) : null; + }; + + return Geo; + }(View); + mixin(Geo, View); + + function getCoordSys$1(finder) { + var geoModel = finder.geoModel; + var seriesModel = finder.seriesModel; + return geoModel ? geoModel.coordinateSystem : seriesModel ? seriesModel.coordinateSystem // For map series. + || (seriesModel.getReferringComponents('geo', SINGLE_REFERRING).models[0] || {}).coordinateSystem : null; + } + + /** + * Resize method bound to the geo + */ + + function resizeGeo(geoModel, api) { + var boundingCoords = geoModel.get('boundingCoords'); + + if (boundingCoords != null) { + var leftTop_1 = boundingCoords[0]; + var rightBottom_1 = boundingCoords[1]; + + if (!(isFinite(leftTop_1[0]) && isFinite(leftTop_1[1]) && isFinite(rightBottom_1[0]) && isFinite(rightBottom_1[1]))) { + if ("development" !== 'production') { + console.error('Invalid boundingCoords'); + } + } else { + // Sample around the lng/lat rect and use projection to calculate actual bounding rect. + var projection_1 = this.projection; + + if (projection_1) { + var xMin = leftTop_1[0]; + var yMin = leftTop_1[1]; + var xMax = rightBottom_1[0]; + var yMax = rightBottom_1[1]; + leftTop_1 = [Infinity, Infinity]; + rightBottom_1 = [-Infinity, -Infinity]; // TODO better way? + + var sampleLine = function (x0, y0, x1, y1) { + var dx = x1 - x0; + var dy = y1 - y0; + + for (var i = 0; i <= 100; i++) { + var p = i / 100; + var pt = projection_1.project([x0 + dx * p, y0 + dy * p]); + min(leftTop_1, leftTop_1, pt); + max(rightBottom_1, rightBottom_1, pt); + } + }; // Top + + + sampleLine(xMin, yMin, xMax, yMin); // Right + + sampleLine(xMax, yMin, xMax, yMax); // Bottom + + sampleLine(xMax, yMax, xMin, yMax); // Left + + sampleLine(xMin, yMax, xMax, yMin); + } + + this.setBoundingRect(leftTop_1[0], leftTop_1[1], rightBottom_1[0] - leftTop_1[0], rightBottom_1[1] - leftTop_1[1]); + } + } + + var rect = this.getBoundingRect(); + var centerOption = geoModel.get('layoutCenter'); + var sizeOption = geoModel.get('layoutSize'); + var viewWidth = api.getWidth(); + var viewHeight = api.getHeight(); + var aspect = rect.width / rect.height * this.aspectScale; + var useCenterAndSize = false; + var center; + var size; + + if (centerOption && sizeOption) { + center = [parsePercent$1(centerOption[0], viewWidth), parsePercent$1(centerOption[1], viewHeight)]; + size = parsePercent$1(sizeOption, Math.min(viewWidth, viewHeight)); + + if (!isNaN(center[0]) && !isNaN(center[1]) && !isNaN(size)) { + useCenterAndSize = true; + } else { + if ("development" !== 'production') { + console.warn('Given layoutCenter or layoutSize data are invalid. Use left/top/width/height instead.'); + } + } + } + + var viewRect; + + if (useCenterAndSize) { + viewRect = {}; + + if (aspect > 1) { + // Width is same with size + viewRect.width = size; + viewRect.height = size / aspect; + } else { + viewRect.height = size; + viewRect.width = size * aspect; + } + + viewRect.y = center[1] - viewRect.height / 2; + viewRect.x = center[0] - viewRect.width / 2; + } else { + // Use left/top/width/height + var boxLayoutOption = geoModel.getBoxLayoutParams(); + boxLayoutOption.aspect = aspect; + viewRect = getLayoutRect(boxLayoutOption, { + width: viewWidth, + height: viewHeight + }); + } + + this.setViewRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height); + this.setCenter(geoModel.get('center')); + this.setZoom(geoModel.get('zoom')); + } // Back compat for ECharts2, where the coord map is set on map series: + // {type: 'map', geoCoord: {'cityA': [116.46,39.92], 'cityA': [119.12,24.61]}}, + + + function setGeoCoords(geo, model) { + each(model.get('geoCoord'), function (geoCoord, name) { + geo.addGeoCoord(name, geoCoord); + }); + } + + var GeoCreator = + /** @class */ + function () { + function GeoCreator() { + // For deciding which dimensions to use when creating list data + this.dimensions = geo2DDimensions; + } + + GeoCreator.prototype.create = function (ecModel, api) { + var geoList = []; + + function getCommonGeoProperties(model) { + return { + nameProperty: model.get('nameProperty'), + aspectScale: model.get('aspectScale'), + projection: model.get('projection') + }; + } // FIXME Create each time may be slow + + + ecModel.eachComponent('geo', function (geoModel, idx) { + var mapName = geoModel.get('map'); + var geo = new Geo(mapName + idx, mapName, extend({ + nameMap: geoModel.get('nameMap') + }, getCommonGeoProperties(geoModel))); + geo.zoomLimit = geoModel.get('scaleLimit'); + geoList.push(geo); // setGeoCoords(geo, geoModel); + + geoModel.coordinateSystem = geo; + geo.model = geoModel; // Inject resize method + + geo.resize = resizeGeo; + geo.resize(geoModel, api); + }); + ecModel.eachSeries(function (seriesModel) { + var coordSys = seriesModel.get('coordinateSystem'); + + if (coordSys === 'geo') { + var geoIndex = seriesModel.get('geoIndex') || 0; + seriesModel.coordinateSystem = geoList[geoIndex]; + } + }); // If has map series + + var mapModelGroupBySeries = {}; + ecModel.eachSeriesByType('map', function (seriesModel) { + if (!seriesModel.getHostGeoModel()) { + var mapType = seriesModel.getMapType(); + mapModelGroupBySeries[mapType] = mapModelGroupBySeries[mapType] || []; + mapModelGroupBySeries[mapType].push(seriesModel); + } + }); + each(mapModelGroupBySeries, function (mapSeries, mapType) { + var nameMapList = map(mapSeries, function (singleMapSeries) { + return singleMapSeries.get('nameMap'); + }); + var geo = new Geo(mapType, mapType, extend({ + nameMap: mergeAll(nameMapList) + }, getCommonGeoProperties(mapSeries[0]))); + geo.zoomLimit = retrieve.apply(null, map(mapSeries, function (singleMapSeries) { + return singleMapSeries.get('scaleLimit'); + })); + geoList.push(geo); // Inject resize method + + geo.resize = resizeGeo; + geo.resize(mapSeries[0], api); + each(mapSeries, function (singleMapSeries) { + singleMapSeries.coordinateSystem = geo; + setGeoCoords(geo, singleMapSeries); + }); + }); + return geoList; + }; + /** + * Fill given regions array + */ + + + GeoCreator.prototype.getFilledRegions = function (originRegionArr, mapName, nameMap, nameProperty) { + // Not use the original + var regionsArr = (originRegionArr || []).slice(); + var dataNameMap = createHashMap(); + + for (var i = 0; i < regionsArr.length; i++) { + dataNameMap.set(regionsArr[i].name, regionsArr[i]); + } + + var source = geoSourceManager.load(mapName, nameMap, nameProperty); + each(source.regions, function (region) { + var name = region.name; + !dataNameMap.get(name) && regionsArr.push({ + name: name + }); + }); + return regionsArr; + }; + + return GeoCreator; + }(); + + var geoCreator = new GeoCreator(); + + var GeoModel = + /** @class */ + function (_super) { + __extends(GeoModel, _super); + + function GeoModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = GeoModel.type; + return _this; + } + + GeoModel.prototype.init = function (option, parentModel, ecModel) { + var source = geoSourceManager.getGeoResource(option.map); + + if (source && source.type === 'geoJSON') { + var itemStyle = option.itemStyle = option.itemStyle || {}; + + if (!('color' in itemStyle)) { + itemStyle.color = '#eee'; + } + } + + this.mergeDefaultAndTheme(option, ecModel); // Default label emphasis `show` + + defaultEmphasis(option, 'label', ['show']); + }; + + GeoModel.prototype.optionUpdated = function () { + var _this = this; + + var option = this.option; + option.regions = geoCreator.getFilledRegions(option.regions, option.map, option.nameMap, option.nameProperty); + var selectedMap = {}; + this._optionModelMap = reduce(option.regions || [], function (optionModelMap, regionOpt) { + var regionName = regionOpt.name; + + if (regionName) { + optionModelMap.set(regionName, new Model(regionOpt, _this, _this.ecModel)); + + if (regionOpt.selected) { + selectedMap[regionName] = true; + } + } + + return optionModelMap; + }, createHashMap()); + + if (!option.selectedMap) { + option.selectedMap = selectedMap; + } + }; + /** + * Get model of region. + */ + + + GeoModel.prototype.getRegionModel = function (name) { + return this._optionModelMap.get(name) || new Model(null, this, this.ecModel); + }; + /** + * Format label + * @param name Region name + */ + + + GeoModel.prototype.getFormattedLabel = function (name, status) { + var regionModel = this.getRegionModel(name); + var formatter = status === 'normal' ? regionModel.get(['label', 'formatter']) : regionModel.get(['emphasis', 'label', 'formatter']); + var params = { + name: name + }; + + if (isFunction(formatter)) { + params.status = status; + return formatter(params); + } else if (isString(formatter)) { + return formatter.replace('{a}', name != null ? name : ''); + } + }; + + GeoModel.prototype.setZoom = function (zoom) { + this.option.zoom = zoom; + }; + + GeoModel.prototype.setCenter = function (center) { + this.option.center = center; + }; // PENGING If selectedMode is null ? + + + GeoModel.prototype.select = function (name) { + var option = this.option; + var selectedMode = option.selectedMode; + + if (!selectedMode) { + return; + } + + if (selectedMode !== 'multiple') { + option.selectedMap = null; + } + + var selectedMap = option.selectedMap || (option.selectedMap = {}); + selectedMap[name] = true; + }; + + GeoModel.prototype.unSelect = function (name) { + var selectedMap = this.option.selectedMap; + + if (selectedMap) { + selectedMap[name] = false; + } + }; + + GeoModel.prototype.toggleSelected = function (name) { + this[this.isSelected(name) ? 'unSelect' : 'select'](name); + }; + + GeoModel.prototype.isSelected = function (name) { + var selectedMap = this.option.selectedMap; + return !!(selectedMap && selectedMap[name]); + }; + + GeoModel.type = 'geo'; + GeoModel.layoutMode = 'box'; + GeoModel.defaultOption = { + // zlevel: 0, + z: 0, + show: true, + left: 'center', + top: 'center', + // Default value: + // for geoSVG source: 1, + // for geoJSON source: 0.75. + aspectScale: null, + ///// Layout with center and size + // If you wan't to put map in a fixed size box with right aspect ratio + // This two properties may more conveninet + // layoutCenter: [50%, 50%] + // layoutSize: 100 + silent: false, + // Map type + map: '', + // Define left-top, right-bottom coords to control view + // For example, [ [180, 90], [-180, -90] ] + boundingCoords: null, + // Default on center of map + center: null, + zoom: 1, + scaleLimit: null, + // selectedMode: false + label: { + show: false, + color: '#000' + }, + itemStyle: { + borderWidth: 0.5, + borderColor: '#444' // Default color: + // + geoJSON: #eee + // + geoSVG: null (use SVG original `fill`) + // color: '#eee' + + }, + emphasis: { + label: { + show: true, + color: 'rgb(100,0,0)' + }, + itemStyle: { + color: 'rgba(255,215,0,0.8)' + } + }, + select: { + label: { + show: true, + color: 'rgb(100,0,0)' + }, + itemStyle: { + color: 'rgba(255,215,0,0.8)' + } + }, + regions: [] // tooltip: { + // show: false + // } + + }; + return GeoModel; + }(ComponentModel); + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + function getCenterCoord(view, point) { + // Use projected coord as center because it's linear. + return view.pointToProjected ? view.pointToProjected(point) : view.pointToData(point); + } + + function updateCenterAndZoom(view, payload, zoomLimit) { + var previousZoom = view.getZoom(); + var center = view.getCenter(); + var zoom = payload.zoom; + var point = view.projectedToPoint ? view.projectedToPoint(center) : view.dataToPoint(center); + + if (payload.dx != null && payload.dy != null) { + point[0] -= payload.dx; + point[1] -= payload.dy; + view.setCenter(getCenterCoord(view, point)); + } + + if (zoom != null) { + if (zoomLimit) { + var zoomMin = zoomLimit.min || 0; + var zoomMax = zoomLimit.max || Infinity; + zoom = Math.max(Math.min(previousZoom * zoom, zoomMax), zoomMin) / previousZoom; + } // Zoom on given point(originX, originY) + + + view.scaleX *= zoom; + view.scaleY *= zoom; + var fixX = (payload.originX - view.x) * (zoom - 1); + var fixY = (payload.originY - view.y) * (zoom - 1); + view.x -= fixX; + view.y -= fixY; + view.updateTransform(); // Get the new center + + view.setCenter(getCenterCoord(view, point)); + view.setZoom(zoom * previousZoom); + } + + return { + center: view.getCenter(), + zoom: view.getZoom() + }; + } + + var GeoView = + /** @class */ + function (_super) { + __extends(GeoView, _super); + + function GeoView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = GeoView.type; + _this.focusBlurEnabled = true; + return _this; + } + + GeoView.prototype.init = function (ecModel, api) { + this._api = api; + }; + + GeoView.prototype.render = function (geoModel, ecModel, api, payload) { + this._model = geoModel; + + if (!geoModel.get('show')) { + this._mapDraw && this._mapDraw.remove(); + this._mapDraw = null; + return; + } + + if (!this._mapDraw) { + this._mapDraw = new MapDraw(api); + } + + var mapDraw = this._mapDraw; + mapDraw.draw(geoModel, ecModel, api, this, payload); + mapDraw.group.on('click', this._handleRegionClick, this); + mapDraw.group.silent = geoModel.get('silent'); + this.group.add(mapDraw.group); + this.updateSelectStatus(geoModel, ecModel, api); + }; + + GeoView.prototype._handleRegionClick = function (e) { + var eventData; + findEventDispatcher(e.target, function (current) { + return (eventData = getECData(current).eventData) != null; + }, true); + + if (eventData) { + this._api.dispatchAction({ + type: 'geoToggleSelect', + geoId: this._model.id, + name: eventData.name + }); + } + }; + + GeoView.prototype.updateSelectStatus = function (model, ecModel, api) { + var _this = this; + + this._mapDraw.group.traverse(function (node) { + var eventData = getECData(node).eventData; + + if (eventData) { + _this._model.isSelected(eventData.name) ? api.enterSelect(node) : api.leaveSelect(node); // No need to traverse children. + + return true; + } + }); + }; + + GeoView.prototype.findHighDownDispatchers = function (name) { + return this._mapDraw && this._mapDraw.findHighDownDispatchers(name, this._model); + }; + + GeoView.prototype.dispose = function () { + this._mapDraw && this._mapDraw.remove(); + }; + + GeoView.type = 'geo'; + return GeoView; + }(ComponentView); + + function registerMap$1(mapName, geoJson, specialAreas) { + geoSourceManager.registerMap(mapName, geoJson, specialAreas); + } + + function install$9(registers) { + registers.registerCoordinateSystem('geo', geoCreator); + registers.registerComponentModel(GeoModel); + registers.registerComponentView(GeoView); + registers.registerImpl('registerMap', registerMap$1); + registers.registerImpl('getMap', function (mapName) { + return geoSourceManager.getMapForUser(mapName); + }); + + function makeAction(method, actionInfo) { + actionInfo.update = 'geo:updateSelectStatus'; + registers.registerAction(actionInfo, function (payload, ecModel) { + var selected = {}; + var allSelected = []; + ecModel.eachComponent({ + mainType: 'geo', + query: payload + }, function (geoModel) { + geoModel[method](payload.name); + var geo = geoModel.coordinateSystem; + each(geo.regions, function (region) { + selected[region.name] = geoModel.isSelected(region.name) || false; + }); // Notice: there might be duplicated name in different regions. + + var names = []; + each(selected, function (v, name) { + selected[name] && names.push(name); + }); + allSelected.push({ + geoIndex: geoModel.componentIndex, + // Use singular, the same naming convention as the event `selectchanged`. + name: names + }); + }); + return { + selected: selected, + allSelected: allSelected, + name: payload.name + }; + }); + } + + makeAction('toggleSelected', { + type: 'geoToggleSelect', + event: 'geoselectchanged' + }); + makeAction('select', { + type: 'geoSelect', + event: 'geoselected' + }); + makeAction('unSelect', { + type: 'geoUnSelect', + event: 'geounselected' + }); + /** + * @payload + * @property {string} [componentType=series] + * @property {number} [dx] + * @property {number} [dy] + * @property {number} [zoom] + * @property {number} [originX] + * @property {number} [originY] + */ + + registers.registerAction({ + type: 'geoRoam', + event: 'geoRoam', + update: 'updateTransform' + }, function (payload, ecModel) { + var componentType = payload.componentType || 'series'; + ecModel.eachComponent({ + mainType: componentType, + query: payload + }, function (componentModel) { + var geo = componentModel.coordinateSystem; + + if (geo.type !== 'geo') { + return; + } + + var res = updateCenterAndZoom(geo, payload, componentModel.get('scaleLimit')); + componentModel.setCenter && componentModel.setCenter(res.center); + componentModel.setZoom && componentModel.setZoom(res.zoom); // All map series with same `map` use the same geo coordinate system + // So the center and zoom must be in sync. Include the series not selected by legend + + if (componentType === 'series') { + each(componentModel.seriesGroup, function (seriesModel) { + seriesModel.setCenter(res.center); + seriesModel.setZoom(res.zoom); + }); + } + }); + }); + } + + function install$a(registers) { + use(install$9); + registers.registerChartView(MapView); + registers.registerSeriesModel(MapSeries); + registers.registerLayout(mapSymbolLayout); + registers.registerProcessor(registers.PRIORITY.PROCESSOR.STATISTIC, mapDataStatistic); + createLegacyDataSelectAction('map', registers.registerAction); + } + + /** + * Initialize all computational message for following algorithm. + */ + + function init$2(inRoot) { + var root = inRoot; + root.hierNode = { + defaultAncestor: null, + ancestor: root, + prelim: 0, + modifier: 0, + change: 0, + shift: 0, + i: 0, + thread: null + }; + var nodes = [root]; + var node; + var children; + + while (node = nodes.pop()) { + // jshint ignore:line + children = node.children; + + if (node.isExpand && children.length) { + var n = children.length; + + for (var i = n - 1; i >= 0; i--) { + var child = children[i]; + child.hierNode = { + defaultAncestor: null, + ancestor: child, + prelim: 0, + modifier: 0, + change: 0, + shift: 0, + i: i, + thread: null + }; + nodes.push(child); + } + } + } + } + /** + * The implementation of this function was originally copied from "d3.js" + * + * with some modifications made for this program. + * See the license statement at the head of this file. + * + * Computes a preliminary x coordinate for node. Before that, this function is + * applied recursively to the children of node, as well as the function + * apportion(). After spacing out the children by calling executeShifts(), the + * node is placed to the midpoint of its outermost children. + */ + + function firstWalk(node, separation) { + var children = node.isExpand ? node.children : []; + var siblings = node.parentNode.children; + var subtreeW = node.hierNode.i ? siblings[node.hierNode.i - 1] : null; + + if (children.length) { + executeShifts(node); + var midPoint = (children[0].hierNode.prelim + children[children.length - 1].hierNode.prelim) / 2; + + if (subtreeW) { + node.hierNode.prelim = subtreeW.hierNode.prelim + separation(node, subtreeW); + node.hierNode.modifier = node.hierNode.prelim - midPoint; + } else { + node.hierNode.prelim = midPoint; + } + } else if (subtreeW) { + node.hierNode.prelim = subtreeW.hierNode.prelim + separation(node, subtreeW); + } + + node.parentNode.hierNode.defaultAncestor = apportion(node, subtreeW, node.parentNode.hierNode.defaultAncestor || siblings[0], separation); + } + /** + * The implementation of this function was originally copied from "d3.js" + * + * with some modifications made for this program. + * See the license statement at the head of this file. + * + * Computes all real x-coordinates by summing up the modifiers recursively. + */ + + function secondWalk(node) { + var nodeX = node.hierNode.prelim + node.parentNode.hierNode.modifier; + node.setLayout({ + x: nodeX + }, true); + node.hierNode.modifier += node.parentNode.hierNode.modifier; + } + function separation(cb) { + return arguments.length ? cb : defaultSeparation; + } + /** + * Transform the common coordinate to radial coordinate. + */ + + function radialCoordinate(rad, r) { + rad -= Math.PI / 2; + return { + x: r * Math.cos(rad), + y: r * Math.sin(rad) + }; + } + /** + * Get the layout position of the whole view. + */ + + function getViewRect$1(seriesModel, api) { + return getLayoutRect(seriesModel.getBoxLayoutParams(), { + width: api.getWidth(), + height: api.getHeight() + }); + } + /** + * All other shifts, applied to the smaller subtrees between w- and w+, are + * performed by this function. + * + * The implementation of this function was originally copied from "d3.js" + * + * with some modifications made for this program. + * See the license statement at the head of this file. + */ + + function executeShifts(node) { + var children = node.children; + var n = children.length; + var shift = 0; + var change = 0; + + while (--n >= 0) { + var child = children[n]; + child.hierNode.prelim += shift; + child.hierNode.modifier += shift; + change += child.hierNode.change; + shift += child.hierNode.shift + change; + } + } + /** + * The implementation of this function was originally copied from "d3.js" + * + * with some modifications made for this program. + * See the license statement at the head of this file. + * + * The core of the algorithm. Here, a new subtree is combined with the + * previous subtrees. Threads are used to traverse the inside and outside + * contours of the left and right subtree up to the highest common level. + * Whenever two nodes of the inside contours conflict, we compute the left + * one of the greatest uncommon ancestors using the function nextAncestor() + * and call moveSubtree() to shift the subtree and prepare the shifts of + * smaller subtrees. Finally, we add a new thread (if necessary). + */ + + + function apportion(subtreeV, subtreeW, ancestor, separation) { + if (subtreeW) { + var nodeOutRight = subtreeV; + var nodeInRight = subtreeV; + var nodeOutLeft = nodeInRight.parentNode.children[0]; + var nodeInLeft = subtreeW; + var sumOutRight = nodeOutRight.hierNode.modifier; + var sumInRight = nodeInRight.hierNode.modifier; + var sumOutLeft = nodeOutLeft.hierNode.modifier; + var sumInLeft = nodeInLeft.hierNode.modifier; + + while (nodeInLeft = nextRight(nodeInLeft), nodeInRight = nextLeft(nodeInRight), nodeInLeft && nodeInRight) { + nodeOutRight = nextRight(nodeOutRight); + nodeOutLeft = nextLeft(nodeOutLeft); + nodeOutRight.hierNode.ancestor = subtreeV; + var shift = nodeInLeft.hierNode.prelim + sumInLeft - nodeInRight.hierNode.prelim - sumInRight + separation(nodeInLeft, nodeInRight); + + if (shift > 0) { + moveSubtree(nextAncestor(nodeInLeft, subtreeV, ancestor), subtreeV, shift); + sumInRight += shift; + sumOutRight += shift; + } + + sumInLeft += nodeInLeft.hierNode.modifier; + sumInRight += nodeInRight.hierNode.modifier; + sumOutRight += nodeOutRight.hierNode.modifier; + sumOutLeft += nodeOutLeft.hierNode.modifier; + } + + if (nodeInLeft && !nextRight(nodeOutRight)) { + nodeOutRight.hierNode.thread = nodeInLeft; + nodeOutRight.hierNode.modifier += sumInLeft - sumOutRight; + } + + if (nodeInRight && !nextLeft(nodeOutLeft)) { + nodeOutLeft.hierNode.thread = nodeInRight; + nodeOutLeft.hierNode.modifier += sumInRight - sumOutLeft; + ancestor = subtreeV; + } + } + + return ancestor; + } + /** + * This function is used to traverse the right contour of a subtree. + * It returns the rightmost child of node or the thread of node. The function + * returns null if and only if node is on the highest depth of its subtree. + */ + + + function nextRight(node) { + var children = node.children; + return children.length && node.isExpand ? children[children.length - 1] : node.hierNode.thread; + } + /** + * This function is used to traverse the left contour of a subtree (or a subforest). + * It returns the leftmost child of node or the thread of node. The function + * returns null if and only if node is on the highest depth of its subtree. + */ + + + function nextLeft(node) { + var children = node.children; + return children.length && node.isExpand ? children[0] : node.hierNode.thread; + } + /** + * If nodeInLeft’s ancestor is a sibling of node, returns nodeInLeft’s ancestor. + * Otherwise, returns the specified ancestor. + */ + + + function nextAncestor(nodeInLeft, node, ancestor) { + return nodeInLeft.hierNode.ancestor.parentNode === node.parentNode ? nodeInLeft.hierNode.ancestor : ancestor; + } + /** + * The implementation of this function was originally copied from "d3.js" + * + * with some modifications made for this program. + * See the license statement at the head of this file. + * + * Shifts the current subtree rooted at wr. + * This is done by increasing prelim(w+) and modifier(w+) by shift. + */ + + + function moveSubtree(wl, wr, shift) { + var change = shift / (wr.hierNode.i - wl.hierNode.i); + wr.hierNode.change -= change; + wr.hierNode.shift += shift; + wr.hierNode.modifier += shift; + wr.hierNode.prelim += shift; + wl.hierNode.change += change; + } + /** + * The implementation of this function was originally copied from "d3.js" + * + * with some modifications made for this program. + * See the license statement at the head of this file. + */ + + + function defaultSeparation(node1, node2) { + return node1.parentNode === node2.parentNode ? 1 : 2; + } + + var TreeEdgeShape = + /** @class */ + function () { + function TreeEdgeShape() { + this.parentPoint = []; + this.childPoints = []; + } + + return TreeEdgeShape; + }(); + + var TreePath = + /** @class */ + function (_super) { + __extends(TreePath, _super); + + function TreePath(opts) { + return _super.call(this, opts) || this; + } + + TreePath.prototype.getDefaultStyle = function () { + return { + stroke: '#000', + fill: null + }; + }; + + TreePath.prototype.getDefaultShape = function () { + return new TreeEdgeShape(); + }; + + TreePath.prototype.buildPath = function (ctx, shape) { + var childPoints = shape.childPoints; + var childLen = childPoints.length; + var parentPoint = shape.parentPoint; + var firstChildPos = childPoints[0]; + var lastChildPos = childPoints[childLen - 1]; + + if (childLen === 1) { + ctx.moveTo(parentPoint[0], parentPoint[1]); + ctx.lineTo(firstChildPos[0], firstChildPos[1]); + return; + } + + var orient = shape.orient; + var forkDim = orient === 'TB' || orient === 'BT' ? 0 : 1; + var otherDim = 1 - forkDim; + var forkPosition = parsePercent$1(shape.forkPosition, 1); + var tmpPoint = []; + tmpPoint[forkDim] = parentPoint[forkDim]; + tmpPoint[otherDim] = parentPoint[otherDim] + (lastChildPos[otherDim] - parentPoint[otherDim]) * forkPosition; + ctx.moveTo(parentPoint[0], parentPoint[1]); + ctx.lineTo(tmpPoint[0], tmpPoint[1]); + ctx.moveTo(firstChildPos[0], firstChildPos[1]); + tmpPoint[forkDim] = firstChildPos[forkDim]; + ctx.lineTo(tmpPoint[0], tmpPoint[1]); + tmpPoint[forkDim] = lastChildPos[forkDim]; + ctx.lineTo(tmpPoint[0], tmpPoint[1]); + ctx.lineTo(lastChildPos[0], lastChildPos[1]); + + for (var i = 1; i < childLen - 1; i++) { + var point = childPoints[i]; + ctx.moveTo(point[0], point[1]); + tmpPoint[forkDim] = point[forkDim]; + ctx.lineTo(tmpPoint[0], tmpPoint[1]); + } + }; + + return TreePath; + }(Path); + + var TreeView = + /** @class */ + function (_super) { + __extends(TreeView, _super); + + function TreeView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = TreeView.type; + _this._mainGroup = new Group(); + return _this; + } + + TreeView.prototype.init = function (ecModel, api) { + this._controller = new RoamController(api.getZr()); + this._controllerHost = { + target: this.group + }; + this.group.add(this._mainGroup); + }; + + TreeView.prototype.render = function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + var layoutInfo = seriesModel.layoutInfo; + var group = this._mainGroup; + var layout = seriesModel.get('layout'); + + if (layout === 'radial') { + group.x = layoutInfo.x + layoutInfo.width / 2; + group.y = layoutInfo.y + layoutInfo.height / 2; + } else { + group.x = layoutInfo.x; + group.y = layoutInfo.y; + } + + this._updateViewCoordSys(seriesModel); + + this._updateController(seriesModel, ecModel, api); + + var oldData = this._data; + data.diff(oldData).add(function (newIdx) { + if (symbolNeedsDraw$1(data, newIdx)) { + // Create node and edge + updateNode(data, newIdx, null, group, seriesModel); + } + }).update(function (newIdx, oldIdx) { + var symbolEl = oldData.getItemGraphicEl(oldIdx); + + if (!symbolNeedsDraw$1(data, newIdx)) { + symbolEl && removeNode(oldData, oldIdx, symbolEl, group, seriesModel); + return; + } // Update node and edge + + + updateNode(data, newIdx, symbolEl, group, seriesModel); + }).remove(function (oldIdx) { + var symbolEl = oldData.getItemGraphicEl(oldIdx); // When remove a collapsed node of subtree, since the collapsed + // node haven't been initialized with a symbol element, + // you can't found it's symbol element through index. + // so if we want to remove the symbol element we should insure + // that the symbol element is not null. + + if (symbolEl) { + removeNode(oldData, oldIdx, symbolEl, group, seriesModel); + } + }).execute(); + this._nodeScaleRatio = seriesModel.get('nodeScaleRatio'); + + this._updateNodeAndLinkScale(seriesModel); + + if (seriesModel.get('expandAndCollapse') === true) { + data.eachItemGraphicEl(function (el, dataIndex) { + el.off('click').on('click', function () { + api.dispatchAction({ + type: 'treeExpandAndCollapse', + seriesId: seriesModel.id, + dataIndex: dataIndex + }); + }); + }); + } + + this._data = data; + }; + + TreeView.prototype._updateViewCoordSys = function (seriesModel) { + var data = seriesModel.getData(); + var points = []; + data.each(function (idx) { + var layout = data.getItemLayout(idx); + + if (layout && !isNaN(layout.x) && !isNaN(layout.y)) { + points.push([+layout.x, +layout.y]); + } + }); + var min = []; + var max = []; + fromPoints(points, min, max); // If don't Store min max when collapse the root node after roam, + // the root node will disappear. + + var oldMin = this._min; + var oldMax = this._max; // If width or height is 0 + + if (max[0] - min[0] === 0) { + min[0] = oldMin ? oldMin[0] : min[0] - 1; + max[0] = oldMax ? oldMax[0] : max[0] + 1; + } + + if (max[1] - min[1] === 0) { + min[1] = oldMin ? oldMin[1] : min[1] - 1; + max[1] = oldMax ? oldMax[1] : max[1] + 1; + } + + var viewCoordSys = seriesModel.coordinateSystem = new View(); + viewCoordSys.zoomLimit = seriesModel.get('scaleLimit'); + viewCoordSys.setBoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]); + viewCoordSys.setCenter(seriesModel.get('center')); + viewCoordSys.setZoom(seriesModel.get('zoom')); // Here we use viewCoordSys just for computing the 'position' and 'scale' of the group + + this.group.attr({ + x: viewCoordSys.x, + y: viewCoordSys.y, + scaleX: viewCoordSys.scaleX, + scaleY: viewCoordSys.scaleY + }); + this._min = min; + this._max = max; + }; + + TreeView.prototype._updateController = function (seriesModel, ecModel, api) { + var _this = this; + + var controller = this._controller; + var controllerHost = this._controllerHost; + var group = this.group; + controller.setPointerChecker(function (e, x, y) { + var rect = group.getBoundingRect(); + rect.applyTransform(group.transform); + return rect.contain(x, y) && !onIrrelevantElement(e, api, seriesModel); + }); + controller.enable(seriesModel.get('roam')); + controllerHost.zoomLimit = seriesModel.get('scaleLimit'); + controllerHost.zoom = seriesModel.coordinateSystem.getZoom(); + controller.off('pan').off('zoom').on('pan', function (e) { + updateViewOnPan(controllerHost, e.dx, e.dy); + api.dispatchAction({ + seriesId: seriesModel.id, + type: 'treeRoam', + dx: e.dx, + dy: e.dy + }); + }).on('zoom', function (e) { + updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY); + api.dispatchAction({ + seriesId: seriesModel.id, + type: 'treeRoam', + zoom: e.scale, + originX: e.originX, + originY: e.originY + }); + + _this._updateNodeAndLinkScale(seriesModel); // Only update label layout on zoom + + + api.updateLabelLayout(); + }); + }; + + TreeView.prototype._updateNodeAndLinkScale = function (seriesModel) { + var data = seriesModel.getData(); + + var nodeScale = this._getNodeGlobalScale(seriesModel); + + data.eachItemGraphicEl(function (el, idx) { + el.setSymbolScale(nodeScale); + }); + }; + + TreeView.prototype._getNodeGlobalScale = function (seriesModel) { + var coordSys = seriesModel.coordinateSystem; + + if (coordSys.type !== 'view') { + return 1; + } + + var nodeScaleRatio = this._nodeScaleRatio; + var groupZoom = coordSys.scaleX || 1; // Scale node when zoom changes + + var roamZoom = coordSys.getZoom(); + var nodeScale = (roamZoom - 1) * nodeScaleRatio + 1; + return nodeScale / groupZoom; + }; + + TreeView.prototype.dispose = function () { + this._controller && this._controller.dispose(); + this._controllerHost = null; + }; + + TreeView.prototype.remove = function () { + this._mainGroup.removeAll(); + + this._data = null; + }; + + TreeView.type = 'tree'; + return TreeView; + }(ChartView); + + function symbolNeedsDraw$1(data, dataIndex) { + var layout = data.getItemLayout(dataIndex); + return layout && !isNaN(layout.x) && !isNaN(layout.y); + } + + function updateNode(data, dataIndex, symbolEl, group, seriesModel) { + var isInit = !symbolEl; + var node = data.tree.getNodeByDataIndex(dataIndex); + var itemModel = node.getModel(); + var visualColor = node.getVisual('style').fill; + var symbolInnerColor = node.isExpand === false && node.children.length !== 0 ? visualColor : '#fff'; + var virtualRoot = data.tree.root; + var source = node.parentNode === virtualRoot ? node : node.parentNode || node; + var sourceSymbolEl = data.getItemGraphicEl(source.dataIndex); + var sourceLayout = source.getLayout(); + var sourceOldLayout = sourceSymbolEl ? { + x: sourceSymbolEl.__oldX, + y: sourceSymbolEl.__oldY, + rawX: sourceSymbolEl.__radialOldRawX, + rawY: sourceSymbolEl.__radialOldRawY + } : sourceLayout; + var targetLayout = node.getLayout(); + + if (isInit) { + symbolEl = new Symbol(data, dataIndex, null, { + symbolInnerColor: symbolInnerColor, + useNameLabel: true + }); + symbolEl.x = sourceOldLayout.x; + symbolEl.y = sourceOldLayout.y; + } else { + symbolEl.updateData(data, dataIndex, null, { + symbolInnerColor: symbolInnerColor, + useNameLabel: true + }); + } + + symbolEl.__radialOldRawX = symbolEl.__radialRawX; + symbolEl.__radialOldRawY = symbolEl.__radialRawY; + symbolEl.__radialRawX = targetLayout.rawX; + symbolEl.__radialRawY = targetLayout.rawY; + group.add(symbolEl); + data.setItemGraphicEl(dataIndex, symbolEl); + symbolEl.__oldX = symbolEl.x; + symbolEl.__oldY = symbolEl.y; + updateProps(symbolEl, { + x: targetLayout.x, + y: targetLayout.y + }, seriesModel); + var symbolPath = symbolEl.getSymbolPath(); + + if (seriesModel.get('layout') === 'radial') { + var realRoot = virtualRoot.children[0]; + var rootLayout = realRoot.getLayout(); + var length_1 = realRoot.children.length; + var rad = void 0; + var isLeft = void 0; + + if (targetLayout.x === rootLayout.x && node.isExpand === true) { + var center = { + x: (realRoot.children[0].getLayout().x + realRoot.children[length_1 - 1].getLayout().x) / 2, + y: (realRoot.children[0].getLayout().y + realRoot.children[length_1 - 1].getLayout().y) / 2 + }; + rad = Math.atan2(center.y - rootLayout.y, center.x - rootLayout.x); + + if (rad < 0) { + rad = Math.PI * 2 + rad; + } + + isLeft = center.x < rootLayout.x; + + if (isLeft) { + rad = rad - Math.PI; + } + } else { + rad = Math.atan2(targetLayout.y - rootLayout.y, targetLayout.x - rootLayout.x); + + if (rad < 0) { + rad = Math.PI * 2 + rad; + } + + if (node.children.length === 0 || node.children.length !== 0 && node.isExpand === false) { + isLeft = targetLayout.x < rootLayout.x; + + if (isLeft) { + rad = rad - Math.PI; + } + } else { + isLeft = targetLayout.x > rootLayout.x; + + if (!isLeft) { + rad = rad - Math.PI; + } + } + } + + var textPosition = isLeft ? 'left' : 'right'; + var normalLabelModel = itemModel.getModel('label'); + var rotate = normalLabelModel.get('rotate'); + var labelRotateRadian = rotate * (Math.PI / 180); + var textContent = symbolPath.getTextContent(); + + if (textContent) { + symbolPath.setTextConfig({ + position: normalLabelModel.get('position') || textPosition, + rotation: rotate == null ? -rad : labelRotateRadian, + origin: 'center' + }); + textContent.setStyle('verticalAlign', 'middle'); + } + } // Handle status + + + var focus = itemModel.get(['emphasis', 'focus']); + var focusDataIndices = focus === 'ancestor' ? node.getAncestorsIndices() : focus === 'descendant' ? node.getDescendantIndices() : null; + + if (focusDataIndices) { + // Modify the focus to data indices. + getECData(symbolEl).focus = focusDataIndices; + } + + drawEdge(seriesModel, node, virtualRoot, symbolEl, sourceOldLayout, sourceLayout, targetLayout, group); + + if (symbolEl.__edge) { + symbolEl.onHoverStateChange = function (toState) { + if (toState !== 'blur') { + // NOTE: Ensure the parent elements will been blurred firstly. + // According to the return of getAncestorsIndices and getDescendantIndices + // TODO: A bit tricky. + var parentEl = node.parentNode && data.getItemGraphicEl(node.parentNode.dataIndex); + + if (!(parentEl && parentEl.hoverState === HOVER_STATE_BLUR)) { + setStatesFlag(symbolEl.__edge, toState); + } + } + }; + } + } + + function drawEdge(seriesModel, node, virtualRoot, symbolEl, sourceOldLayout, sourceLayout, targetLayout, group) { + var itemModel = node.getModel(); + var edgeShape = seriesModel.get('edgeShape'); + var layout = seriesModel.get('layout'); + var orient = seriesModel.getOrient(); + var curvature = seriesModel.get(['lineStyle', 'curveness']); + var edgeForkPosition = seriesModel.get('edgeForkPosition'); + var lineStyle = itemModel.getModel('lineStyle').getLineStyle(); + var edge = symbolEl.__edge; + + if (edgeShape === 'curve') { + if (node.parentNode && node.parentNode !== virtualRoot) { + if (!edge) { + edge = symbolEl.__edge = new BezierCurve({ + shape: getEdgeShape(layout, orient, curvature, sourceOldLayout, sourceOldLayout) + }); + } + + updateProps(edge, { + shape: getEdgeShape(layout, orient, curvature, sourceLayout, targetLayout) + }, seriesModel); + } + } else if (edgeShape === 'polyline') { + if (layout === 'orthogonal') { + if (node !== virtualRoot && node.children && node.children.length !== 0 && node.isExpand === true) { + var children = node.children; + var childPoints = []; + + for (var i = 0; i < children.length; i++) { + var childLayout = children[i].getLayout(); + childPoints.push([childLayout.x, childLayout.y]); + } + + if (!edge) { + edge = symbolEl.__edge = new TreePath({ + shape: { + parentPoint: [targetLayout.x, targetLayout.y], + childPoints: [[targetLayout.x, targetLayout.y]], + orient: orient, + forkPosition: edgeForkPosition + } + }); + } + + updateProps(edge, { + shape: { + parentPoint: [targetLayout.x, targetLayout.y], + childPoints: childPoints + } + }, seriesModel); + } + } else { + if ("development" !== 'production') { + throw new Error('The polyline edgeShape can only be used in orthogonal layout'); + } + } + } + + if (edge) { + edge.useStyle(defaults({ + strokeNoScale: true, + fill: null + }, lineStyle)); + setStatesStylesFromModel(edge, itemModel, 'lineStyle'); + setDefaultStateProxy(edge); + group.add(edge); + } + } + + function removeNodeEdge(node, data, group, seriesModel, removeAnimationOpt) { + var virtualRoot = data.tree.root; + + var _a = getSourceNode(virtualRoot, node), + source = _a.source, + sourceLayout = _a.sourceLayout; + + var symbolEl = data.getItemGraphicEl(node.dataIndex); + + if (!symbolEl) { + return; + } + + var sourceSymbolEl = data.getItemGraphicEl(source.dataIndex); + var sourceEdge = sourceSymbolEl.__edge; // 1. when expand the sub tree, delete the children node should delete the edge of + // the source at the same time. because the polyline edge shape is only owned by the source. + // 2.when the node is the only children of the source, delete the node should delete the edge of + // the source at the same time. the same reason as above. + + var edge = symbolEl.__edge || (source.isExpand === false || source.children.length === 1 ? sourceEdge : undefined); + var edgeShape = seriesModel.get('edgeShape'); + var layoutOpt = seriesModel.get('layout'); + var orient = seriesModel.get('orient'); + var curvature = seriesModel.get(['lineStyle', 'curveness']); + + if (edge) { + if (edgeShape === 'curve') { + removeElement(edge, { + shape: getEdgeShape(layoutOpt, orient, curvature, sourceLayout, sourceLayout), + style: { + opacity: 0 + } + }, seriesModel, { + cb: function () { + group.remove(edge); + }, + removeOpt: removeAnimationOpt + }); + } else if (edgeShape === 'polyline' && seriesModel.get('layout') === 'orthogonal') { + removeElement(edge, { + shape: { + parentPoint: [sourceLayout.x, sourceLayout.y], + childPoints: [[sourceLayout.x, sourceLayout.y]] + }, + style: { + opacity: 0 + } + }, seriesModel, { + cb: function () { + group.remove(edge); + }, + removeOpt: removeAnimationOpt + }); + } + } + } + + function getSourceNode(virtualRoot, node) { + var source = node.parentNode === virtualRoot ? node : node.parentNode || node; + var sourceLayout; + + while (sourceLayout = source.getLayout(), sourceLayout == null) { + source = source.parentNode === virtualRoot ? source : source.parentNode || source; + } + + return { + source: source, + sourceLayout: sourceLayout + }; + } + + function removeNode(data, dataIndex, symbolEl, group, seriesModel) { + var node = data.tree.getNodeByDataIndex(dataIndex); + var virtualRoot = data.tree.root; + var sourceLayout = getSourceNode(virtualRoot, node).sourceLayout; // Use same duration and easing with update to have more consistent animation. + + var removeAnimationOpt = { + duration: seriesModel.get('animationDurationUpdate'), + easing: seriesModel.get('animationEasingUpdate') + }; + removeElement(symbolEl, { + x: sourceLayout.x + 1, + y: sourceLayout.y + 1 + }, seriesModel, { + cb: function () { + group.remove(symbolEl); + data.setItemGraphicEl(dataIndex, null); + }, + removeOpt: removeAnimationOpt + }); + symbolEl.fadeOut(null, data.hostModel, { + fadeLabel: true, + animation: removeAnimationOpt + }); // remove edge as parent node + + node.children.forEach(function (childNode) { + removeNodeEdge(childNode, data, group, seriesModel, removeAnimationOpt); + }); // remove edge as child node + + removeNodeEdge(node, data, group, seriesModel, removeAnimationOpt); + } + + function getEdgeShape(layoutOpt, orient, curvature, sourceLayout, targetLayout) { + var cpx1; + var cpy1; + var cpx2; + var cpy2; + var x1; + var x2; + var y1; + var y2; + + if (layoutOpt === 'radial') { + x1 = sourceLayout.rawX; + y1 = sourceLayout.rawY; + x2 = targetLayout.rawX; + y2 = targetLayout.rawY; + var radialCoor1 = radialCoordinate(x1, y1); + var radialCoor2 = radialCoordinate(x1, y1 + (y2 - y1) * curvature); + var radialCoor3 = radialCoordinate(x2, y2 + (y1 - y2) * curvature); + var radialCoor4 = radialCoordinate(x2, y2); + return { + x1: radialCoor1.x || 0, + y1: radialCoor1.y || 0, + x2: radialCoor4.x || 0, + y2: radialCoor4.y || 0, + cpx1: radialCoor2.x || 0, + cpy1: radialCoor2.y || 0, + cpx2: radialCoor3.x || 0, + cpy2: radialCoor3.y || 0 + }; + } else { + x1 = sourceLayout.x; + y1 = sourceLayout.y; + x2 = targetLayout.x; + y2 = targetLayout.y; + + if (orient === 'LR' || orient === 'RL') { + cpx1 = x1 + (x2 - x1) * curvature; + cpy1 = y1; + cpx2 = x2 + (x1 - x2) * curvature; + cpy2 = y2; + } + + if (orient === 'TB' || orient === 'BT') { + cpx1 = x1; + cpy1 = y1 + (y2 - y1) * curvature; + cpx2 = x2; + cpy2 = y2 + (y1 - y2) * curvature; + } + } + + return { + x1: x1, + y1: y1, + x2: x2, + y2: y2, + cpx1: cpx1, + cpy1: cpy1, + cpx2: cpx2, + cpy2: cpy2 + }; + } + + var inner$7 = makeInner(); + + function linkSeriesData(opt) { + var mainData = opt.mainData; + var datas = opt.datas; + + if (!datas) { + datas = { + main: mainData + }; + opt.datasAttr = { + main: 'data' + }; + } + + opt.datas = opt.mainData = null; + linkAll(mainData, datas, opt); // Porxy data original methods. + + each(datas, function (data) { + each(mainData.TRANSFERABLE_METHODS, function (methodName) { + data.wrapMethod(methodName, curry(transferInjection, opt)); + }); + }); // Beyond transfer, additional features should be added to `cloneShallow`. + + mainData.wrapMethod('cloneShallow', curry(cloneShallowInjection, opt)); // Only mainData trigger change, because struct.update may trigger + // another changable methods, which may bring about dead lock. + + each(mainData.CHANGABLE_METHODS, function (methodName) { + mainData.wrapMethod(methodName, curry(changeInjection, opt)); + }); // Make sure datas contains mainData. + + assert(datas[mainData.dataType] === mainData); + } + + function transferInjection(opt, res) { + if (isMainData(this)) { + // Transfer datas to new main data. + var datas = extend({}, inner$7(this).datas); + datas[this.dataType] = res; + linkAll(res, datas, opt); + } else { + // Modify the reference in main data to point newData. + linkSingle(res, this.dataType, inner$7(this).mainData, opt); + } + + return res; + } + + function changeInjection(opt, res) { + opt.struct && opt.struct.update(); + return res; + } + + function cloneShallowInjection(opt, res) { + // cloneShallow, which brings about some fragilities, may be inappropriate + // to be exposed as an API. So for implementation simplicity we can make + // the restriction that cloneShallow of not-mainData should not be invoked + // outside, but only be invoked here. + each(inner$7(res).datas, function (data, dataType) { + data !== res && linkSingle(data.cloneShallow(), dataType, res, opt); + }); + return res; + } + /** + * Supplement method to List. + * + * @public + * @param [dataType] If not specified, return mainData. + */ + + + function getLinkedData(dataType) { + var mainData = inner$7(this).mainData; + return dataType == null || mainData == null ? mainData : inner$7(mainData).datas[dataType]; + } + /** + * Get list of all linked data + */ + + + function getLinkedDataAll() { + var mainData = inner$7(this).mainData; + return mainData == null ? [{ + data: mainData + }] : map(keys(inner$7(mainData).datas), function (type) { + return { + type: type, + data: inner$7(mainData).datas[type] + }; + }); + } + + function isMainData(data) { + return inner$7(data).mainData === data; + } + + function linkAll(mainData, datas, opt) { + inner$7(mainData).datas = {}; + each(datas, function (data, dataType) { + linkSingle(data, dataType, mainData, opt); + }); + } + + function linkSingle(data, dataType, mainData, opt) { + inner$7(mainData).datas[dataType] = data; + inner$7(data).mainData = mainData; + data.dataType = dataType; + + if (opt.struct) { + data[opt.structAttr] = opt.struct; + opt.struct[opt.datasAttr[dataType]] = data; + } // Supplement method. + + + data.getLinkedData = getLinkedData; + data.getLinkedDataAll = getLinkedDataAll; + } + + var TreeNode = + /** @class */ + function () { + function TreeNode(name, hostTree) { + this.depth = 0; + this.height = 0; + /** + * Reference to list item. + * Do not persistent dataIndex outside, + * besause it may be changed by list. + * If dataIndex -1, + * this node is logical deleted (filtered) in list. + */ + + this.dataIndex = -1; + this.children = []; + this.viewChildren = []; + this.isExpand = false; + this.name = name || ''; + this.hostTree = hostTree; + } + /** + * The node is removed. + */ + + + TreeNode.prototype.isRemoved = function () { + return this.dataIndex < 0; + }; + + TreeNode.prototype.eachNode = function (options, cb, context) { + if (isFunction(options)) { + context = cb; + cb = options; + options = null; + } + + options = options || {}; + + if (isString(options)) { + options = { + order: options + }; + } + + var order = options.order || 'preorder'; + var children = this[options.attr || 'children']; + var suppressVisitSub; + order === 'preorder' && (suppressVisitSub = cb.call(context, this)); + + for (var i = 0; !suppressVisitSub && i < children.length; i++) { + children[i].eachNode(options, cb, context); + } + + order === 'postorder' && cb.call(context, this); + }; + /** + * Update depth and height of this subtree. + */ + + + TreeNode.prototype.updateDepthAndHeight = function (depth) { + var height = 0; + this.depth = depth; + + for (var i = 0; i < this.children.length; i++) { + var child = this.children[i]; + child.updateDepthAndHeight(depth + 1); + + if (child.height > height) { + height = child.height; + } + } + + this.height = height + 1; + }; + + TreeNode.prototype.getNodeById = function (id) { + if (this.getId() === id) { + return this; + } + + for (var i = 0, children = this.children, len = children.length; i < len; i++) { + var res = children[i].getNodeById(id); + + if (res) { + return res; + } + } + }; + + TreeNode.prototype.contains = function (node) { + if (node === this) { + return true; + } + + for (var i = 0, children = this.children, len = children.length; i < len; i++) { + var res = children[i].contains(node); + + if (res) { + return res; + } + } + }; + /** + * @param includeSelf Default false. + * @return order: [root, child, grandchild, ...] + */ + + + TreeNode.prototype.getAncestors = function (includeSelf) { + var ancestors = []; + var node = includeSelf ? this : this.parentNode; + + while (node) { + ancestors.push(node); + node = node.parentNode; + } + + ancestors.reverse(); + return ancestors; + }; + + TreeNode.prototype.getAncestorsIndices = function () { + var indices = []; + var currNode = this; + + while (currNode) { + indices.push(currNode.dataIndex); + currNode = currNode.parentNode; + } + + indices.reverse(); + return indices; + }; + + TreeNode.prototype.getDescendantIndices = function () { + var indices = []; + this.eachNode(function (childNode) { + indices.push(childNode.dataIndex); + }); + return indices; + }; + + TreeNode.prototype.getValue = function (dimension) { + var data = this.hostTree.data; + return data.getStore().get(data.getDimensionIndex(dimension || 'value'), this.dataIndex); + }; + + TreeNode.prototype.setLayout = function (layout, merge) { + this.dataIndex >= 0 && this.hostTree.data.setItemLayout(this.dataIndex, layout, merge); + }; + /** + * @return {Object} layout + */ + + + TreeNode.prototype.getLayout = function () { + return this.hostTree.data.getItemLayout(this.dataIndex); + }; // @depcrecated + // getModel(path: S): Model + // eslint-disable-next-line @typescript-eslint/no-unused-vars + + + TreeNode.prototype.getModel = function (path) { + if (this.dataIndex < 0) { + return; + } + + var hostTree = this.hostTree; + var itemModel = hostTree.data.getItemModel(this.dataIndex); + return itemModel.getModel(path); + }; // TODO: TYPE More specific model + + + TreeNode.prototype.getLevelModel = function () { + return (this.hostTree.levelModels || [])[this.depth]; + }; + + TreeNode.prototype.setVisual = function (key, value) { + this.dataIndex >= 0 && this.hostTree.data.setItemVisual(this.dataIndex, key, value); + }; + /** + * Get item visual + * FIXME: make return type better + */ + + + TreeNode.prototype.getVisual = function (key) { + return this.hostTree.data.getItemVisual(this.dataIndex, key); + }; + + TreeNode.prototype.getRawIndex = function () { + return this.hostTree.data.getRawIndex(this.dataIndex); + }; + + TreeNode.prototype.getId = function () { + return this.hostTree.data.getId(this.dataIndex); + }; + /** + * index in parent's children + */ + + + TreeNode.prototype.getChildIndex = function () { + if (this.parentNode) { + var children = this.parentNode.children; + + for (var i = 0; i < children.length; ++i) { + if (children[i] === this) { + return i; + } + } + + return -1; + } + + return -1; + }; + /** + * if this is an ancestor of another node + * + * @param node another node + * @return if is ancestor + */ + + + TreeNode.prototype.isAncestorOf = function (node) { + var parent = node.parentNode; + + while (parent) { + if (parent === this) { + return true; + } + + parent = parent.parentNode; + } + + return false; + }; + /** + * if this is an descendant of another node + * + * @param node another node + * @return if is descendant + */ + + + TreeNode.prototype.isDescendantOf = function (node) { + return node !== this && node.isAncestorOf(this); + }; + + return TreeNode; + }(); + + var Tree = + /** @class */ + function () { + function Tree(hostModel) { + this.type = 'tree'; + this._nodes = []; + this.hostModel = hostModel; + } + + Tree.prototype.eachNode = function (options, cb, context) { + this.root.eachNode(options, cb, context); + }; + + Tree.prototype.getNodeByDataIndex = function (dataIndex) { + var rawIndex = this.data.getRawIndex(dataIndex); + return this._nodes[rawIndex]; + }; + + Tree.prototype.getNodeById = function (name) { + return this.root.getNodeById(name); + }; + /** + * Update item available by list, + * when list has been performed options like 'filterSelf' or 'map'. + */ + + + Tree.prototype.update = function () { + var data = this.data; + var nodes = this._nodes; + + for (var i = 0, len = nodes.length; i < len; i++) { + nodes[i].dataIndex = -1; + } + + for (var i = 0, len = data.count(); i < len; i++) { + nodes[data.getRawIndex(i)].dataIndex = i; + } + }; + /** + * Clear all layouts + */ + + + Tree.prototype.clearLayouts = function () { + this.data.clearItemLayouts(); + }; + /** + * data node format: + * { + * name: ... + * value: ... + * children: [ + * { + * name: ... + * value: ... + * children: ... + * }, + * ... + * ] + * } + */ + + + Tree.createTree = function (dataRoot, hostModel, beforeLink) { + var tree = new Tree(hostModel); + var listData = []; + var dimMax = 1; + buildHierarchy(dataRoot); + + function buildHierarchy(dataNode, parentNode) { + var value = dataNode.value; + dimMax = Math.max(dimMax, isArray(value) ? value.length : 1); + listData.push(dataNode); + var node = new TreeNode(convertOptionIdName(dataNode.name, ''), tree); + parentNode ? addChild(node, parentNode) : tree.root = node; + + tree._nodes.push(node); + + var children = dataNode.children; + + if (children) { + for (var i = 0; i < children.length; i++) { + buildHierarchy(children[i], node); + } + } + } + + tree.root.updateDepthAndHeight(0); + var dimensions = prepareSeriesDataSchema(listData, { + coordDimensions: ['value'], + dimensionsCount: dimMax + }).dimensions; + var list = new SeriesData(dimensions, hostModel); + list.initData(listData); + beforeLink && beforeLink(list); + linkSeriesData({ + mainData: list, + struct: tree, + structAttr: 'tree' + }); + tree.update(); + return tree; + }; + + return Tree; + }(); + /** + * It is needed to consider the mess of 'list', 'hostModel' when creating a TreeNote, + * so this function is not ready and not necessary to be public. + */ + + + function addChild(child, node) { + var children = node.children; + + if (child.parentNode === node) { + return; + } + + children.push(child); + child.parentNode = node; + } + + function retrieveTargetInfo(payload, validPayloadTypes, seriesModel) { + if (payload && indexOf(validPayloadTypes, payload.type) >= 0) { + var root = seriesModel.getData().tree.root; + var targetNode = payload.targetNode; + + if (isString(targetNode)) { + targetNode = root.getNodeById(targetNode); + } + + if (targetNode && root.contains(targetNode)) { + return { + node: targetNode + }; + } + + var targetNodeId = payload.targetNodeId; + + if (targetNodeId != null && (targetNode = root.getNodeById(targetNodeId))) { + return { + node: targetNode + }; + } + } + } // Not includes the given node at the last item. + + function getPathToRoot(node) { + var path = []; + + while (node) { + node = node.parentNode; + node && path.push(node); + } + + return path.reverse(); + } + function aboveViewRoot(viewRoot, node) { + var viewPath = getPathToRoot(viewRoot); + return indexOf(viewPath, node) >= 0; + } // From root to the input node (the input node will be included). + + function wrapTreePathInfo(node, seriesModel) { + var treePathInfo = []; + + while (node) { + var nodeDataIndex = node.dataIndex; + treePathInfo.push({ + name: node.name, + dataIndex: nodeDataIndex, + value: seriesModel.getRawValue(nodeDataIndex) + }); + node = node.parentNode; + } + + treePathInfo.reverse(); + return treePathInfo; + } + + var TreeSeriesModel = + /** @class */ + function (_super) { + __extends(TreeSeriesModel, _super); + + function TreeSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.hasSymbolVisual = true; // Do it self. + + _this.ignoreStyleOnData = true; + return _this; + } + /** + * Init a tree data structure from data in option series + */ + + + TreeSeriesModel.prototype.getInitialData = function (option) { + //create an virtual root + var root = { + name: option.name, + children: option.data + }; + var leaves = option.leaves || {}; + var leavesModel = new Model(leaves, this, this.ecModel); + var tree = Tree.createTree(root, this, beforeLink); + + function beforeLink(nodeData) { + nodeData.wrapMethod('getItemModel', function (model, idx) { + var node = tree.getNodeByDataIndex(idx); + + if (!(node && node.children.length && node.isExpand)) { + model.parentModel = leavesModel; + } + + return model; + }); + } + + var treeDepth = 0; + tree.eachNode('preorder', function (node) { + if (node.depth > treeDepth) { + treeDepth = node.depth; + } + }); + var expandAndCollapse = option.expandAndCollapse; + var expandTreeDepth = expandAndCollapse && option.initialTreeDepth >= 0 ? option.initialTreeDepth : treeDepth; + tree.root.eachNode('preorder', function (node) { + var item = node.hostTree.data.getRawDataItem(node.dataIndex); // Add item.collapsed != null, because users can collapse node original in the series.data. + + node.isExpand = item && item.collapsed != null ? !item.collapsed : node.depth <= expandTreeDepth; + }); + return tree.data; + }; + /** + * Make the configuration 'orient' backward compatibly, with 'horizontal = LR', 'vertical = TB'. + * @returns {string} orient + */ + + + TreeSeriesModel.prototype.getOrient = function () { + var orient = this.get('orient'); + + if (orient === 'horizontal') { + orient = 'LR'; + } else if (orient === 'vertical') { + orient = 'TB'; + } + + return orient; + }; + + TreeSeriesModel.prototype.setZoom = function (zoom) { + this.option.zoom = zoom; + }; + + TreeSeriesModel.prototype.setCenter = function (center) { + this.option.center = center; + }; + + TreeSeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + var tree = this.getData().tree; + var realRoot = tree.root.children[0]; + var node = tree.getNodeByDataIndex(dataIndex); + var value = node.getValue(); + var name = node.name; + + while (node && node !== realRoot) { + name = node.parentNode.name + '.' + name; + node = node.parentNode; + } + + return createTooltipMarkup('nameValue', { + name: name, + value: value, + noValue: isNaN(value) || value == null + }); + }; // Add tree path to tooltip param + + + TreeSeriesModel.prototype.getDataParams = function (dataIndex) { + var params = _super.prototype.getDataParams.apply(this, arguments); + + var node = this.getData().tree.getNodeByDataIndex(dataIndex); + params.treeAncestors = wrapTreePathInfo(node, this); + params.collapsed = !node.isExpand; + return params; + }; + + TreeSeriesModel.type = 'series.tree'; // can support the position parameters 'left', 'top','right','bottom', 'width', + // 'height' in the setOption() with 'merge' mode normal. + + TreeSeriesModel.layoutMode = 'box'; + TreeSeriesModel.defaultOption = { + // zlevel: 0, + z: 2, + coordinateSystem: 'view', + // the position of the whole view + left: '12%', + top: '12%', + right: '12%', + bottom: '12%', + // the layout of the tree, two value can be selected, 'orthogonal' or 'radial' + layout: 'orthogonal', + // value can be 'polyline' + edgeShape: 'curve', + edgeForkPosition: '50%', + // true | false | 'move' | 'scale', see module:component/helper/RoamController. + roam: false, + // Symbol size scale ratio in roam + nodeScaleRatio: 0.4, + // Default on center of graph + center: null, + zoom: 1, + orient: 'LR', + symbol: 'emptyCircle', + symbolSize: 7, + expandAndCollapse: true, + initialTreeDepth: 2, + lineStyle: { + color: '#ccc', + width: 1.5, + curveness: 0.5 + }, + itemStyle: { + color: 'lightsteelblue', + // borderColor: '#c23531', + borderWidth: 1.5 + }, + label: { + show: true + }, + animationEasing: 'linear', + animationDuration: 700, + animationDurationUpdate: 500 + }; + return TreeSeriesModel; + }(SeriesModel); + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * Traverse the tree from bottom to top and do something + */ + function eachAfter(root, callback, separation) { + var nodes = [root]; + var next = []; + var node; + + while (node = nodes.pop()) { + // jshint ignore:line + next.push(node); + + if (node.isExpand) { + var children = node.children; + + if (children.length) { + for (var i = 0; i < children.length; i++) { + nodes.push(children[i]); + } + } + } + } + + while (node = next.pop()) { + // jshint ignore:line + callback(node, separation); + } + } + /** + * Traverse the tree from top to bottom and do something + */ + + + function eachBefore(root, callback) { + var nodes = [root]; + var node; + + while (node = nodes.pop()) { + // jshint ignore:line + callback(node); + + if (node.isExpand) { + var children = node.children; + + if (children.length) { + for (var i = children.length - 1; i >= 0; i--) { + nodes.push(children[i]); + } + } + } + } + } + + function treeLayout(ecModel, api) { + ecModel.eachSeriesByType('tree', function (seriesModel) { + commonLayout(seriesModel, api); + }); + } + + function commonLayout(seriesModel, api) { + var layoutInfo = getViewRect$1(seriesModel, api); + seriesModel.layoutInfo = layoutInfo; + var layout = seriesModel.get('layout'); + var width = 0; + var height = 0; + var separation$1 = null; + + if (layout === 'radial') { + width = 2 * Math.PI; + height = Math.min(layoutInfo.height, layoutInfo.width) / 2; + separation$1 = separation(function (node1, node2) { + return (node1.parentNode === node2.parentNode ? 1 : 2) / node1.depth; + }); + } else { + width = layoutInfo.width; + height = layoutInfo.height; + separation$1 = separation(); + } + + var virtualRoot = seriesModel.getData().tree.root; + var realRoot = virtualRoot.children[0]; + + if (realRoot) { + init$2(virtualRoot); + eachAfter(realRoot, firstWalk, separation$1); + virtualRoot.hierNode.modifier = -realRoot.hierNode.prelim; + eachBefore(realRoot, secondWalk); + var left_1 = realRoot; + var right_1 = realRoot; + var bottom_1 = realRoot; + eachBefore(realRoot, function (node) { + var x = node.getLayout().x; + + if (x < left_1.getLayout().x) { + left_1 = node; + } + + if (x > right_1.getLayout().x) { + right_1 = node; + } + + if (node.depth > bottom_1.depth) { + bottom_1 = node; + } + }); + var delta = left_1 === right_1 ? 1 : separation$1(left_1, right_1) / 2; + var tx_1 = delta - left_1.getLayout().x; + var kx_1 = 0; + var ky_1 = 0; + var coorX_1 = 0; + var coorY_1 = 0; + + if (layout === 'radial') { + kx_1 = width / (right_1.getLayout().x + delta + tx_1); // here we use (node.depth - 1), bucause the real root's depth is 1 + + ky_1 = height / (bottom_1.depth - 1 || 1); + eachBefore(realRoot, function (node) { + coorX_1 = (node.getLayout().x + tx_1) * kx_1; + coorY_1 = (node.depth - 1) * ky_1; + var finalCoor = radialCoordinate(coorX_1, coorY_1); + node.setLayout({ + x: finalCoor.x, + y: finalCoor.y, + rawX: coorX_1, + rawY: coorY_1 + }, true); + }); + } else { + var orient_1 = seriesModel.getOrient(); + + if (orient_1 === 'RL' || orient_1 === 'LR') { + ky_1 = height / (right_1.getLayout().x + delta + tx_1); + kx_1 = width / (bottom_1.depth - 1 || 1); + eachBefore(realRoot, function (node) { + coorY_1 = (node.getLayout().x + tx_1) * ky_1; + coorX_1 = orient_1 === 'LR' ? (node.depth - 1) * kx_1 : width - (node.depth - 1) * kx_1; + node.setLayout({ + x: coorX_1, + y: coorY_1 + }, true); + }); + } else if (orient_1 === 'TB' || orient_1 === 'BT') { + kx_1 = width / (right_1.getLayout().x + delta + tx_1); + ky_1 = height / (bottom_1.depth - 1 || 1); + eachBefore(realRoot, function (node) { + coorX_1 = (node.getLayout().x + tx_1) * kx_1; + coorY_1 = orient_1 === 'TB' ? (node.depth - 1) * ky_1 : height - (node.depth - 1) * ky_1; + node.setLayout({ + x: coorX_1, + y: coorY_1 + }, true); + }); + } + } + } + } + + function treeVisual(ecModel) { + ecModel.eachSeriesByType('tree', function (seriesModel) { + var data = seriesModel.getData(); + var tree = data.tree; + tree.eachNode(function (node) { + var model = node.getModel(); // TODO Optimize + + var style = model.getModel('itemStyle').getItemStyle(); + var existsStyle = data.ensureUniqueItemVisual(node.dataIndex, 'style'); + extend(existsStyle, style); + }); + }); + } + + function installTreeAction(registers) { + registers.registerAction({ + type: 'treeExpandAndCollapse', + event: 'treeExpandAndCollapse', + update: 'update' + }, function (payload, ecModel) { + ecModel.eachComponent({ + mainType: 'series', + subType: 'tree', + query: payload + }, function (seriesModel) { + var dataIndex = payload.dataIndex; + var tree = seriesModel.getData().tree; + var node = tree.getNodeByDataIndex(dataIndex); + node.isExpand = !node.isExpand; + }); + }); + registers.registerAction({ + type: 'treeRoam', + event: 'treeRoam', + // Here we set 'none' instead of 'update', because roam action + // just need to update the transform matrix without having to recalculate + // the layout. So don't need to go through the whole update process, such + // as 'dataPrcocess', 'coordSystemUpdate', 'layout' and so on. + update: 'none' + }, function (payload, ecModel) { + ecModel.eachComponent({ + mainType: 'series', + subType: 'tree', + query: payload + }, function (seriesModel) { + var coordSys = seriesModel.coordinateSystem; + var res = updateCenterAndZoom(coordSys, payload); + seriesModel.setCenter && seriesModel.setCenter(res.center); + seriesModel.setZoom && seriesModel.setZoom(res.zoom); + }); + }); + } + + function install$b(registers) { + registers.registerChartView(TreeView); + registers.registerSeriesModel(TreeSeriesModel); + registers.registerLayout(treeLayout); + registers.registerVisual(treeVisual); + installTreeAction(registers); + } + + var actionTypes = ['treemapZoomToNode', 'treemapRender', 'treemapMove']; + function installTreemapAction(registers) { + for (var i = 0; i < actionTypes.length; i++) { + registers.registerAction({ + type: actionTypes[i], + update: 'updateView' + }, noop); + } + + registers.registerAction({ + type: 'treemapRootToNode', + update: 'updateView' + }, function (payload, ecModel) { + ecModel.eachComponent({ + mainType: 'series', + subType: 'treemap', + query: payload + }, handleRootToNode); + + function handleRootToNode(model, index) { + var types = ['treemapZoomToNode', 'treemapRootToNode']; + var targetInfo = retrieveTargetInfo(payload, types, model); + + if (targetInfo) { + var originViewRoot = model.getViewRoot(); + + if (originViewRoot) { + payload.direction = aboveViewRoot(originViewRoot, targetInfo.node) ? 'rollUp' : 'drillDown'; + } + + model.resetViewRoot(targetInfo.node); + } + } + }); + } + + function enableAriaDecalForTree(seriesModel) { + var data = seriesModel.getData(); + var tree = data.tree; + var decalPaletteScope = {}; + tree.eachNode(function (node) { + // Use decal of level 1 node + var current = node; + + while (current && current.depth > 1) { + current = current.parentNode; + } + + var decal = getDecalFromPalette(seriesModel.ecModel, current.name || current.dataIndex + '', decalPaletteScope); + node.setVisual('decal', decal); + }); + } + + var TreemapSeriesModel = + /** @class */ + function (_super) { + __extends(TreemapSeriesModel, _super); + + function TreemapSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = TreemapSeriesModel.type; + _this.preventUsingHoverLayer = true; + return _this; + } + /** + * @override + */ + + + TreemapSeriesModel.prototype.getInitialData = function (option, ecModel) { + // Create a virtual root. + var root = { + name: option.name, + children: option.data + }; + completeTreeValue(root); + var levels = option.levels || []; // Used in "visual priority" in `treemapVisual.js`. + // This way is a little tricky, must satisfy the precondition: + // 1. There is no `treeNode.getModel('itemStyle.xxx')` used. + // 2. The `Model.prototype.getModel()` will not use any clone-like way. + + var designatedVisualItemStyle = this.designatedVisualItemStyle = {}; + var designatedVisualModel = new Model({ + itemStyle: designatedVisualItemStyle + }, this, ecModel); + levels = option.levels = setDefault(levels, ecModel); + var levelModels = map(levels || [], function (levelDefine) { + return new Model(levelDefine, designatedVisualModel, ecModel); + }, this); // Make sure always a new tree is created when setOption, + // in TreemapView, we check whether oldTree === newTree + // to choose mappings approach among old shapes and new shapes. + + var tree = Tree.createTree(root, this, beforeLink); + + function beforeLink(nodeData) { + nodeData.wrapMethod('getItemModel', function (model, idx) { + var node = tree.getNodeByDataIndex(idx); + var levelModel = node ? levelModels[node.depth] : null; // If no levelModel, we also need `designatedVisualModel`. + + model.parentModel = levelModel || designatedVisualModel; + return model; + }); + } + + return tree.data; + }; + + TreemapSeriesModel.prototype.optionUpdated = function () { + this.resetViewRoot(); + }; + /** + * @override + * @param {number} dataIndex + * @param {boolean} [mutipleSeries=false] + */ + + + TreemapSeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + var data = this.getData(); + var value = this.getRawValue(dataIndex); + var name = data.getName(dataIndex); + return createTooltipMarkup('nameValue', { + name: name, + value: value + }); + }; + /** + * Add tree path to tooltip param + * + * @override + * @param {number} dataIndex + * @return {Object} + */ + + + TreemapSeriesModel.prototype.getDataParams = function (dataIndex) { + var params = _super.prototype.getDataParams.apply(this, arguments); + + var node = this.getData().tree.getNodeByDataIndex(dataIndex); + params.treeAncestors = wrapTreePathInfo(node, this); // compatitable the previous code. + + params.treePathInfo = params.treeAncestors; + return params; + }; + /** + * @public + * @param {Object} layoutInfo { + * x: containerGroup x + * y: containerGroup y + * width: containerGroup width + * height: containerGroup height + * } + */ + + + TreemapSeriesModel.prototype.setLayoutInfo = function (layoutInfo) { + /** + * @readOnly + * @type {Object} + */ + this.layoutInfo = this.layoutInfo || {}; + extend(this.layoutInfo, layoutInfo); + }; + /** + * @param {string} id + * @return {number} index + */ + + + TreemapSeriesModel.prototype.mapIdToIndex = function (id) { + // A feature is implemented: + // index is monotone increasing with the sequence of + // input id at the first time. + // This feature can make sure that each data item and its + // mapped color have the same index between data list and + // color list at the beginning, which is useful for user + // to adjust data-color mapping. + + /** + * @private + * @type {Object} + */ + var idIndexMap = this._idIndexMap; + + if (!idIndexMap) { + idIndexMap = this._idIndexMap = createHashMap(); + /** + * @private + * @type {number} + */ + + this._idIndexMapCount = 0; + } + + var index = idIndexMap.get(id); + + if (index == null) { + idIndexMap.set(id, index = this._idIndexMapCount++); + } + + return index; + }; + + TreemapSeriesModel.prototype.getViewRoot = function () { + return this._viewRoot; + }; + + TreemapSeriesModel.prototype.resetViewRoot = function (viewRoot) { + viewRoot ? this._viewRoot = viewRoot : viewRoot = this._viewRoot; + var root = this.getRawData().tree.root; + + if (!viewRoot || viewRoot !== root && !root.contains(viewRoot)) { + this._viewRoot = root; + } + }; + + TreemapSeriesModel.prototype.enableAriaDecal = function () { + enableAriaDecalForTree(this); + }; + + TreemapSeriesModel.type = 'series.treemap'; + TreemapSeriesModel.layoutMode = 'box'; + TreemapSeriesModel.defaultOption = { + // Disable progressive rendering + progressive: 0, + // size: ['80%', '80%'], // deprecated, compatible with ec2. + left: 'center', + top: 'middle', + width: '80%', + height: '80%', + sort: true, + clipWindow: 'origin', + squareRatio: 0.5 * (1 + Math.sqrt(5)), + leafDepth: null, + drillDownIcon: '▶', + // to align specialized icon. ▷▶❒❐▼✚ + zoomToNodeRatio: 0.32 * 0.32, + roam: true, + nodeClick: 'zoomToNode', + animation: true, + animationDurationUpdate: 900, + animationEasing: 'quinticInOut', + breadcrumb: { + show: true, + height: 22, + left: 'center', + top: 'bottom', + // right + // bottom + emptyItemWidth: 25, + itemStyle: { + color: 'rgba(0,0,0,0.7)', + textStyle: { + color: '#fff' + } + } + }, + label: { + show: true, + // Do not use textDistance, for ellipsis rect just the same as treemap node rect. + distance: 0, + padding: 5, + position: 'inside', + // formatter: null, + color: '#fff', + overflow: 'truncate' // align + // verticalAlign + + }, + upperLabel: { + show: false, + position: [0, '50%'], + height: 20, + // formatter: null, + // color: '#fff', + overflow: 'truncate', + // align: null, + verticalAlign: 'middle' + }, + itemStyle: { + color: null, + colorAlpha: null, + colorSaturation: null, + borderWidth: 0, + gapWidth: 0, + borderColor: '#fff', + borderColorSaturation: null // If specified, borderColor will be ineffective, and the + // border color is evaluated by color of current node and + // borderColorSaturation. + + }, + emphasis: { + upperLabel: { + show: true, + position: [0, '50%'], + overflow: 'truncate', + verticalAlign: 'middle' + } + }, + visualDimension: 0, + visualMin: null, + visualMax: null, + color: [], + // level[n].color (if necessary). + // + Specify color list of each level. level[0].color would be global + // color list if not specified. (see method `setDefault`). + // + But set as a empty array to forbid fetch color from global palette + // when using nodeModel.get('color'), otherwise nodes on deep level + // will always has color palette set and are not able to inherit color + // from parent node. + // + TreemapSeries.color can not be set as 'none', otherwise effect + // legend color fetching (see seriesColor.js). + colorAlpha: null, + colorSaturation: null, + colorMappingBy: 'index', + visibleMin: 10, + // be rendered. Only works when sort is 'asc' or 'desc'. + childrenVisibleMin: null, + // grandchildren will not show. + // Why grandchildren? If not grandchildren but children, + // some siblings show children and some not, + // the appearance may be mess and not consistent, + levels: [] // Each item: { + // visibleMin, itemStyle, visualDimension, label + // } + // data: { + // value: [], + // children: [], + // link: 'http://xxx.xxx.xxx', + // target: 'blank' or 'self' + // } + + }; + return TreemapSeriesModel; + }(SeriesModel); + /** + * @param {Object} dataNode + */ + + + function completeTreeValue(dataNode) { + // Postorder travel tree. + // If value of none-leaf node is not set, + // calculate it by suming up the value of all children. + var sum = 0; + each(dataNode.children, function (child) { + completeTreeValue(child); + var childValue = child.value; + isArray(childValue) && (childValue = childValue[0]); + sum += childValue; + }); + var thisValue = dataNode.value; + + if (isArray(thisValue)) { + thisValue = thisValue[0]; + } + + if (thisValue == null || isNaN(thisValue)) { + thisValue = sum; + } // Value should not less than 0. + + + if (thisValue < 0) { + thisValue = 0; + } + + isArray(dataNode.value) ? dataNode.value[0] = thisValue : dataNode.value = thisValue; + } + /** + * set default to level configuration + */ + + + function setDefault(levels, ecModel) { + var globalColorList = normalizeToArray(ecModel.get('color')); + var globalDecalList = normalizeToArray(ecModel.get(['aria', 'decal', 'decals'])); + + if (!globalColorList) { + return; + } + + levels = levels || []; + var hasColorDefine; + var hasDecalDefine; + each(levels, function (levelDefine) { + var model = new Model(levelDefine); + var modelColor = model.get('color'); + var modelDecal = model.get('decal'); + + if (model.get(['itemStyle', 'color']) || modelColor && modelColor !== 'none') { + hasColorDefine = true; + } + + if (model.get(['itemStyle', 'decal']) || modelDecal && modelDecal !== 'none') { + hasDecalDefine = true; + } + }); + var level0 = levels[0] || (levels[0] = {}); + + if (!hasColorDefine) { + level0.color = globalColorList.slice(); + } + + if (!hasDecalDefine && globalDecalList) { + level0.decal = globalDecalList.slice(); + } + + return levels; + } + + var TEXT_PADDING = 8; + var ITEM_GAP = 8; + var ARRAY_LENGTH = 5; + + var Breadcrumb = + /** @class */ + function () { + function Breadcrumb(containerGroup) { + this.group = new Group(); + containerGroup.add(this.group); + } + + Breadcrumb.prototype.render = function (seriesModel, api, targetNode, onSelect) { + var model = seriesModel.getModel('breadcrumb'); + var thisGroup = this.group; + thisGroup.removeAll(); + + if (!model.get('show') || !targetNode) { + return; + } + + var normalStyleModel = model.getModel('itemStyle'); // let emphasisStyleModel = model.getModel('emphasis.itemStyle'); + + var textStyleModel = normalStyleModel.getModel('textStyle'); + var layoutParam = { + pos: { + left: model.get('left'), + right: model.get('right'), + top: model.get('top'), + bottom: model.get('bottom') + }, + box: { + width: api.getWidth(), + height: api.getHeight() + }, + emptyItemWidth: model.get('emptyItemWidth'), + totalWidth: 0, + renderList: [] + }; + + this._prepare(targetNode, layoutParam, textStyleModel); + + this._renderContent(seriesModel, layoutParam, normalStyleModel, textStyleModel, onSelect); + + positionElement(thisGroup, layoutParam.pos, layoutParam.box); + }; + /** + * Prepare render list and total width + * @private + */ + + + Breadcrumb.prototype._prepare = function (targetNode, layoutParam, textStyleModel) { + for (var node = targetNode; node; node = node.parentNode) { + var text = convertOptionIdName(node.getModel().get('name'), ''); + var textRect = textStyleModel.getTextRect(text); + var itemWidth = Math.max(textRect.width + TEXT_PADDING * 2, layoutParam.emptyItemWidth); + layoutParam.totalWidth += itemWidth + ITEM_GAP; + layoutParam.renderList.push({ + node: node, + text: text, + width: itemWidth + }); + } + }; + /** + * @private + */ + + + Breadcrumb.prototype._renderContent = function (seriesModel, layoutParam, normalStyleModel, textStyleModel, onSelect) { + // Start rendering. + var lastX = 0; + var emptyItemWidth = layoutParam.emptyItemWidth; + var height = seriesModel.get(['breadcrumb', 'height']); + var availableSize = getAvailableSize(layoutParam.pos, layoutParam.box); + var totalWidth = layoutParam.totalWidth; + var renderList = layoutParam.renderList; + + for (var i = renderList.length - 1; i >= 0; i--) { + var item = renderList[i]; + var itemNode = item.node; + var itemWidth = item.width; + var text = item.text; // Hdie text and shorten width if necessary. + + if (totalWidth > availableSize.width) { + totalWidth -= itemWidth - emptyItemWidth; + itemWidth = emptyItemWidth; + text = null; + } + + var el = new Polygon({ + shape: { + points: makeItemPoints(lastX, 0, itemWidth, height, i === renderList.length - 1, i === 0) + }, + style: defaults(normalStyleModel.getItemStyle(), { + lineJoin: 'bevel' + }), + textContent: new ZRText({ + style: { + text: text, + fill: textStyleModel.getTextColor(), + font: textStyleModel.getFont() + } + }), + textConfig: { + position: 'inside' + }, + z2: Z2_EMPHASIS_LIFT * 1e4, + onclick: curry(onSelect, itemNode) + }); + el.disableLabelAnimation = true; + this.group.add(el); + packEventData(el, seriesModel, itemNode); + lastX += itemWidth + ITEM_GAP; + } + }; + + Breadcrumb.prototype.remove = function () { + this.group.removeAll(); + }; + + return Breadcrumb; + }(); + + function makeItemPoints(x, y, itemWidth, itemHeight, head, tail) { + var points = [[head ? x : x - ARRAY_LENGTH, y], [x + itemWidth, y], [x + itemWidth, y + itemHeight], [head ? x : x - ARRAY_LENGTH, y + itemHeight]]; + !tail && points.splice(2, 0, [x + itemWidth + ARRAY_LENGTH, y + itemHeight / 2]); + !head && points.push([x, y + itemHeight / 2]); + return points; + } // Package custom mouse event. + + + function packEventData(el, seriesModel, itemNode) { + getECData(el).eventData = { + componentType: 'series', + componentSubType: 'treemap', + componentIndex: seriesModel.componentIndex, + seriesIndex: seriesModel.seriesIndex, + seriesName: seriesModel.name, + seriesType: 'treemap', + selfType: 'breadcrumb', + nodeData: { + dataIndex: itemNode && itemNode.dataIndex, + name: itemNode && itemNode.name + }, + treePathInfo: itemNode && wrapTreePathInfo(itemNode, seriesModel) + }; + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * Animate multiple elements with a single done-callback. + * + * @example + * animation + * .createWrap() + * .add(el1, {x: 10, y: 10}) + * .add(el2, {shape: {width: 500}, style: {fill: 'red'}}, 400) + * .done(function () { // done }) + * .start('cubicOut'); + */ + var AnimationWrap = + /** @class */ + function () { + function AnimationWrap() { + this._storage = []; + this._elExistsMap = {}; + } + /** + * Caution: a el can only be added once, otherwise 'done' + * might not be called. This method checks this (by el.id), + * suppresses adding and returns false when existing el found. + * + * @return Whether adding succeeded. + */ + + + AnimationWrap.prototype.add = function (el, target, duration, delay, easing) { + if (this._elExistsMap[el.id]) { + return false; + } + + this._elExistsMap[el.id] = true; + + this._storage.push({ + el: el, + target: target, + duration: duration, + delay: delay, + easing: easing + }); + + return true; + }; + /** + * Only execute when animation done/aborted. + */ + + + AnimationWrap.prototype.finished = function (callback) { + this._finishedCallback = callback; + return this; + }; + /** + * Will stop exist animation firstly. + */ + + + AnimationWrap.prototype.start = function () { + var _this = this; + + var count = this._storage.length; + + var checkTerminate = function () { + count--; + + if (count <= 0) { + // Guard. + _this._storage.length = 0; + _this._elExistsMap = {}; + _this._finishedCallback && _this._finishedCallback(); + } + }; + + for (var i = 0, len = this._storage.length; i < len; i++) { + var item = this._storage[i]; + item.el.animateTo(item.target, { + duration: item.duration, + delay: item.delay, + easing: item.easing, + setToFinal: true, + done: checkTerminate, + aborted: checkTerminate + }); + } + + return this; + }; + + return AnimationWrap; + }(); + + function createWrap() { + return new AnimationWrap(); + } + + var Group$1 = Group; + var Rect$1 = Rect; + var DRAG_THRESHOLD = 3; + var PATH_LABEL_NOAMAL = 'label'; + var PATH_UPPERLABEL_NORMAL = 'upperLabel'; // Should larger than emphasis states lift z + + var Z2_BASE = Z2_EMPHASIS_LIFT * 10; // Should bigger than every z2. + + var Z2_BG = Z2_EMPHASIS_LIFT * 2; + var Z2_CONTENT = Z2_EMPHASIS_LIFT * 3; + var getStateItemStyle = makeStyleMapper([['fill', 'color'], // `borderColor` and `borderWidth` has been occupied, + // so use `stroke` to indicate the stroke of the rect. + ['stroke', 'strokeColor'], ['lineWidth', 'strokeWidth'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`. + // So do not transfer decal directly. + ]); + + var getItemStyleNormal = function (model) { + // Normal style props should include emphasis style props. + var itemStyle = getStateItemStyle(model); // Clear styles set by emphasis. + + itemStyle.stroke = itemStyle.fill = itemStyle.lineWidth = null; + return itemStyle; + }; + + var inner$8 = makeInner(); + + var TreemapView = + /** @class */ + function (_super) { + __extends(TreemapView, _super); + + function TreemapView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = TreemapView.type; + _this._state = 'ready'; + _this._storage = createStorage(); + return _this; + } + /** + * @override + */ + + + TreemapView.prototype.render = function (seriesModel, ecModel, api, payload) { + var models = ecModel.findComponents({ + mainType: 'series', + subType: 'treemap', + query: payload + }); + + if (indexOf(models, seriesModel) < 0) { + return; + } + + this.seriesModel = seriesModel; + this.api = api; + this.ecModel = ecModel; + var types = ['treemapZoomToNode', 'treemapRootToNode']; + var targetInfo = retrieveTargetInfo(payload, types, seriesModel); + var payloadType = payload && payload.type; + var layoutInfo = seriesModel.layoutInfo; + var isInit = !this._oldTree; + var thisStorage = this._storage; // Mark new root when action is treemapRootToNode. + + var reRoot = payloadType === 'treemapRootToNode' && targetInfo && thisStorage ? { + rootNodeGroup: thisStorage.nodeGroup[targetInfo.node.getRawIndex()], + direction: payload.direction + } : null; + + var containerGroup = this._giveContainerGroup(layoutInfo); + + var hasAnimation = seriesModel.get('animation'); + + var renderResult = this._doRender(containerGroup, seriesModel, reRoot); + + hasAnimation && !isInit && (!payloadType || payloadType === 'treemapZoomToNode' || payloadType === 'treemapRootToNode') ? this._doAnimation(containerGroup, renderResult, seriesModel, reRoot) : renderResult.renderFinally(); + + this._resetController(api); + + this._renderBreadcrumb(seriesModel, api, targetInfo); + }; + + TreemapView.prototype._giveContainerGroup = function (layoutInfo) { + var containerGroup = this._containerGroup; + + if (!containerGroup) { + // FIXME + // 加一层containerGroup是为了clip,但是现在clip功能并没有实现。 + containerGroup = this._containerGroup = new Group$1(); + + this._initEvents(containerGroup); + + this.group.add(containerGroup); + } + + containerGroup.x = layoutInfo.x; + containerGroup.y = layoutInfo.y; + return containerGroup; + }; + + TreemapView.prototype._doRender = function (containerGroup, seriesModel, reRoot) { + var thisTree = seriesModel.getData().tree; + var oldTree = this._oldTree; // Clear last shape records. + + var lastsForAnimation = createStorage(); + var thisStorage = createStorage(); + var oldStorage = this._storage; + var willInvisibleEls = []; + + function doRenderNode(thisNode, oldNode, parentGroup, depth) { + return renderNode(seriesModel, thisStorage, oldStorage, reRoot, lastsForAnimation, willInvisibleEls, thisNode, oldNode, parentGroup, depth); + } // Notice: when thisTree and oldTree are the same tree (see list.cloneShallow), + // the oldTree is actually losted, so we can not find all of the old graphic + // elements from tree. So we use this stragegy: make element storage, move + // from old storage to new storage, clear old storage. + + + dualTravel(thisTree.root ? [thisTree.root] : [], oldTree && oldTree.root ? [oldTree.root] : [], containerGroup, thisTree === oldTree || !oldTree, 0); // Process all removing. + + var willDeleteEls = clearStorage(oldStorage); + this._oldTree = thisTree; + this._storage = thisStorage; + return { + lastsForAnimation: lastsForAnimation, + willDeleteEls: willDeleteEls, + renderFinally: renderFinally + }; + + function dualTravel(thisViewChildren, oldViewChildren, parentGroup, sameTree, depth) { + // When 'render' is triggered by action, + // 'this' and 'old' may be the same tree, + // we use rawIndex in that case. + if (sameTree) { + oldViewChildren = thisViewChildren; + each(thisViewChildren, function (child, index) { + !child.isRemoved() && processNode(index, index); + }); + } // Diff hierarchically (diff only in each subtree, but not whole). + // because, consistency of view is important. + else { + new DataDiffer(oldViewChildren, thisViewChildren, getKey, getKey).add(processNode).update(processNode).remove(curry(processNode, null)).execute(); + } + + function getKey(node) { + // Identify by name or raw index. + return node.getId(); + } + + function processNode(newIndex, oldIndex) { + var thisNode = newIndex != null ? thisViewChildren[newIndex] : null; + var oldNode = oldIndex != null ? oldViewChildren[oldIndex] : null; + var group = doRenderNode(thisNode, oldNode, parentGroup, depth); + group && dualTravel(thisNode && thisNode.viewChildren || [], oldNode && oldNode.viewChildren || [], group, sameTree, depth + 1); + } + } + + function clearStorage(storage) { + var willDeleteEls = createStorage(); + storage && each(storage, function (store, storageName) { + var delEls = willDeleteEls[storageName]; + each(store, function (el) { + el && (delEls.push(el), inner$8(el).willDelete = true); + }); + }); + return willDeleteEls; + } + + function renderFinally() { + each(willDeleteEls, function (els) { + each(els, function (el) { + el.parent && el.parent.remove(el); + }); + }); + each(willInvisibleEls, function (el) { + el.invisible = true; // Setting invisible is for optimizing, so no need to set dirty, + // just mark as invisible. + + el.dirty(); + }); + } + }; + + TreemapView.prototype._doAnimation = function (containerGroup, renderResult, seriesModel, reRoot) { + var durationOption = seriesModel.get('animationDurationUpdate'); + var easingOption = seriesModel.get('animationEasing'); // TODO: do not support function until necessary. + + var duration = (isFunction(durationOption) ? 0 : durationOption) || 0; + var easing = (isFunction(easingOption) ? null : easingOption) || 'cubicOut'; + var animationWrap = createWrap(); // Make delete animations. + + each(renderResult.willDeleteEls, function (store, storageName) { + each(store, function (el, rawIndex) { + if (el.invisible) { + return; + } + + var parent = el.parent; // Always has parent, and parent is nodeGroup. + + var target; + var innerStore = inner$8(parent); + + if (reRoot && reRoot.direction === 'drillDown') { + target = parent === reRoot.rootNodeGroup // This is the content element of view root. + // Only `content` will enter this branch, because + // `background` and `nodeGroup` will not be deleted. + ? { + shape: { + x: 0, + y: 0, + width: innerStore.nodeWidth, + height: innerStore.nodeHeight + }, + style: { + opacity: 0 + } + } // Others. + : { + style: { + opacity: 0 + } + }; + } else { + var targetX = 0; + var targetY = 0; + + if (!innerStore.willDelete) { + // Let node animate to right-bottom corner, cooperating with fadeout, + // which is appropriate for user understanding. + // Divided by 2 for reRoot rolling up effect. + targetX = innerStore.nodeWidth / 2; + targetY = innerStore.nodeHeight / 2; + } + + target = storageName === 'nodeGroup' ? { + x: targetX, + y: targetY, + style: { + opacity: 0 + } + } : { + shape: { + x: targetX, + y: targetY, + width: 0, + height: 0 + }, + style: { + opacity: 0 + } + }; + } // TODO: do not support delay until necessary. + + + target && animationWrap.add(el, target, duration, 0, easing); + }); + }); // Make other animations + + each(this._storage, function (store, storageName) { + each(store, function (el, rawIndex) { + var last = renderResult.lastsForAnimation[storageName][rawIndex]; + var target = {}; + + if (!last) { + return; + } + + if (el instanceof Group) { + if (last.oldX != null) { + target.x = el.x; + target.y = el.y; + el.x = last.oldX; + el.y = last.oldY; + } + } else { + if (last.oldShape) { + target.shape = extend({}, el.shape); + el.setShape(last.oldShape); + } + + if (last.fadein) { + el.setStyle('opacity', 0); + target.style = { + opacity: 1 + }; + } // When animation is stopped for succedent animation starting, + // el.style.opacity might not be 1 + else if (el.style.opacity !== 1) { + target.style = { + opacity: 1 + }; + } + } + + animationWrap.add(el, target, duration, 0, easing); + }); + }, this); + this._state = 'animating'; + animationWrap.finished(bind(function () { + this._state = 'ready'; + renderResult.renderFinally(); + }, this)).start(); + }; + + TreemapView.prototype._resetController = function (api) { + var controller = this._controller; // Init controller. + + if (!controller) { + controller = this._controller = new RoamController(api.getZr()); + controller.enable(this.seriesModel.get('roam')); + controller.on('pan', bind(this._onPan, this)); + controller.on('zoom', bind(this._onZoom, this)); + } + + var rect = new BoundingRect(0, 0, api.getWidth(), api.getHeight()); + controller.setPointerChecker(function (e, x, y) { + return rect.contain(x, y); + }); + }; + + TreemapView.prototype._clearController = function () { + var controller = this._controller; + + if (controller) { + controller.dispose(); + controller = null; + } + }; + + TreemapView.prototype._onPan = function (e) { + if (this._state !== 'animating' && (Math.abs(e.dx) > DRAG_THRESHOLD || Math.abs(e.dy) > DRAG_THRESHOLD)) { + // These param must not be cached. + var root = this.seriesModel.getData().tree.root; + + if (!root) { + return; + } + + var rootLayout = root.getLayout(); + + if (!rootLayout) { + return; + } + + this.api.dispatchAction({ + type: 'treemapMove', + from: this.uid, + seriesId: this.seriesModel.id, + rootRect: { + x: rootLayout.x + e.dx, + y: rootLayout.y + e.dy, + width: rootLayout.width, + height: rootLayout.height + } + }); + } + }; + + TreemapView.prototype._onZoom = function (e) { + var mouseX = e.originX; + var mouseY = e.originY; + + if (this._state !== 'animating') { + // These param must not be cached. + var root = this.seriesModel.getData().tree.root; + + if (!root) { + return; + } + + var rootLayout = root.getLayout(); + + if (!rootLayout) { + return; + } + + var rect = new BoundingRect(rootLayout.x, rootLayout.y, rootLayout.width, rootLayout.height); + var layoutInfo = this.seriesModel.layoutInfo; // Transform mouse coord from global to containerGroup. + + mouseX -= layoutInfo.x; + mouseY -= layoutInfo.y; // Scale root bounding rect. + + var m = create$1(); + translate(m, m, [-mouseX, -mouseY]); + scale$1(m, m, [e.scale, e.scale]); + translate(m, m, [mouseX, mouseY]); + rect.applyTransform(m); + this.api.dispatchAction({ + type: 'treemapRender', + from: this.uid, + seriesId: this.seriesModel.id, + rootRect: { + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height + } + }); + } + }; + + TreemapView.prototype._initEvents = function (containerGroup) { + var _this = this; + + containerGroup.on('click', function (e) { + if (_this._state !== 'ready') { + return; + } + + var nodeClick = _this.seriesModel.get('nodeClick', true); + + if (!nodeClick) { + return; + } + + var targetInfo = _this.findTarget(e.offsetX, e.offsetY); + + if (!targetInfo) { + return; + } + + var node = targetInfo.node; + + if (node.getLayout().isLeafRoot) { + _this._rootToNode(targetInfo); + } else { + if (nodeClick === 'zoomToNode') { + _this._zoomToNode(targetInfo); + } else if (nodeClick === 'link') { + var itemModel = node.hostTree.data.getItemModel(node.dataIndex); + var link = itemModel.get('link', true); + var linkTarget = itemModel.get('target', true) || 'blank'; + link && windowOpen(link, linkTarget); + } + } + }, this); + }; + + TreemapView.prototype._renderBreadcrumb = function (seriesModel, api, targetInfo) { + var _this = this; + + if (!targetInfo) { + targetInfo = seriesModel.get('leafDepth', true) != null ? { + node: seriesModel.getViewRoot() + } // FIXME + // better way? + // Find breadcrumb tail on center of containerGroup. + : this.findTarget(api.getWidth() / 2, api.getHeight() / 2); + + if (!targetInfo) { + targetInfo = { + node: seriesModel.getData().tree.root + }; + } + } + + (this._breadcrumb || (this._breadcrumb = new Breadcrumb(this.group))).render(seriesModel, api, targetInfo.node, function (node) { + if (_this._state !== 'animating') { + aboveViewRoot(seriesModel.getViewRoot(), node) ? _this._rootToNode({ + node: node + }) : _this._zoomToNode({ + node: node + }); + } + }); + }; + /** + * @override + */ + + + TreemapView.prototype.remove = function () { + this._clearController(); + + this._containerGroup && this._containerGroup.removeAll(); + this._storage = createStorage(); + this._state = 'ready'; + this._breadcrumb && this._breadcrumb.remove(); + }; + + TreemapView.prototype.dispose = function () { + this._clearController(); + }; + + TreemapView.prototype._zoomToNode = function (targetInfo) { + this.api.dispatchAction({ + type: 'treemapZoomToNode', + from: this.uid, + seriesId: this.seriesModel.id, + targetNode: targetInfo.node + }); + }; + + TreemapView.prototype._rootToNode = function (targetInfo) { + this.api.dispatchAction({ + type: 'treemapRootToNode', + from: this.uid, + seriesId: this.seriesModel.id, + targetNode: targetInfo.node + }); + }; + /** + * @public + * @param {number} x Global coord x. + * @param {number} y Global coord y. + * @return {Object} info If not found, return undefined; + * @return {number} info.node Target node. + * @return {number} info.offsetX x refer to target node. + * @return {number} info.offsetY y refer to target node. + */ + + + TreemapView.prototype.findTarget = function (x, y) { + var targetInfo; + var viewRoot = this.seriesModel.getViewRoot(); + viewRoot.eachNode({ + attr: 'viewChildren', + order: 'preorder' + }, function (node) { + var bgEl = this._storage.background[node.getRawIndex()]; // If invisible, there might be no element. + + + if (bgEl) { + var point = bgEl.transformCoordToLocal(x, y); + var shape = bgEl.shape; // For performance consideration, dont use 'getBoundingRect'. + + if (shape.x <= point[0] && point[0] <= shape.x + shape.width && shape.y <= point[1] && point[1] <= shape.y + shape.height) { + targetInfo = { + node: node, + offsetX: point[0], + offsetY: point[1] + }; + } else { + return false; // Suppress visit subtree. + } + } + }, this); + return targetInfo; + }; + + TreemapView.type = 'treemap'; + return TreemapView; + }(ChartView); + /** + * @inner + */ + + + function createStorage() { + return { + nodeGroup: [], + background: [], + content: [] + }; + } + /** + * @inner + * @return Return undefined means do not travel further. + */ + + + function renderNode(seriesModel, thisStorage, oldStorage, reRoot, lastsForAnimation, willInvisibleEls, thisNode, oldNode, parentGroup, depth) { + // Whether under viewRoot. + if (!thisNode) { + // Deleting nodes will be performed finally. This method just find + // element from old storage, or create new element, set them to new + // storage, and set styles. + return; + } // ------------------------------------------------------------------- + // Start of closure variables available in "Procedures in renderNode". + + + var thisLayout = thisNode.getLayout(); + var data = seriesModel.getData(); + var nodeModel = thisNode.getModel(); // Only for enabling highlight/downplay. Clear firstly. + // Because some node will not be rendered. + + data.setItemGraphicEl(thisNode.dataIndex, null); + + if (!thisLayout || !thisLayout.isInView) { + return; + } + + var thisWidth = thisLayout.width; + var thisHeight = thisLayout.height; + var borderWidth = thisLayout.borderWidth; + var thisInvisible = thisLayout.invisible; + var thisRawIndex = thisNode.getRawIndex(); + var oldRawIndex = oldNode && oldNode.getRawIndex(); + var thisViewChildren = thisNode.viewChildren; + var upperHeight = thisLayout.upperHeight; + var isParent = thisViewChildren && thisViewChildren.length; + var itemStyleNormalModel = nodeModel.getModel('itemStyle'); + var itemStyleEmphasisModel = nodeModel.getModel(['emphasis', 'itemStyle']); + var itemStyleBlurModel = nodeModel.getModel(['blur', 'itemStyle']); + var itemStyleSelectModel = nodeModel.getModel(['select', 'itemStyle']); + var borderRadius = itemStyleNormalModel.get('borderRadius') || 0; // End of closure ariables available in "Procedures in renderNode". + // ----------------------------------------------------------------- + // Node group + + var group = giveGraphic('nodeGroup', Group$1); + + if (!group) { + return; + } + + parentGroup.add(group); // x,y are not set when el is above view root. + + group.x = thisLayout.x || 0; + group.y = thisLayout.y || 0; + group.markRedraw(); + inner$8(group).nodeWidth = thisWidth; + inner$8(group).nodeHeight = thisHeight; + + if (thisLayout.isAboveViewRoot) { + return group; + } // Background + + + var bg = giveGraphic('background', Rect$1, depth, Z2_BG); + bg && renderBackground(group, bg, isParent && thisLayout.upperLabelHeight); + var emphasisModel = nodeModel.getModel('emphasis'); + var focus = emphasisModel.get('focus'); + var blurScope = emphasisModel.get('blurScope'); + var isDisabled = emphasisModel.get('disabled'); + var focusOrIndices = focus === 'ancestor' ? thisNode.getAncestorsIndices() : focus === 'descendant' ? thisNode.getDescendantIndices() : focus; // No children, render content. + + if (isParent) { + // Because of the implementation about "traverse" in graphic hover style, we + // can not set hover listener on the "group" of non-leaf node. Otherwise the + // hover event from the descendents will be listenered. + if (isHighDownDispatcher(group)) { + setAsHighDownDispatcher(group, false); + } + + if (bg) { + setAsHighDownDispatcher(bg, !isDisabled); // Only for enabling highlight/downplay. + + data.setItemGraphicEl(thisNode.dataIndex, bg); + enableHoverFocus(bg, focusOrIndices, blurScope); + } + } else { + var content = giveGraphic('content', Rect$1, depth, Z2_CONTENT); + content && renderContent(group, content); + bg.disableMorphing = true; + + if (bg && isHighDownDispatcher(bg)) { + setAsHighDownDispatcher(bg, false); + } + + setAsHighDownDispatcher(group, !isDisabled); // Only for enabling highlight/downplay. + + data.setItemGraphicEl(thisNode.dataIndex, group); + enableHoverFocus(group, focusOrIndices, blurScope); + } + + return group; // ---------------------------- + // | Procedures in renderNode | + // ---------------------------- + + function renderBackground(group, bg, useUpperLabel) { + var ecData = getECData(bg); // For tooltip. + + ecData.dataIndex = thisNode.dataIndex; + ecData.seriesIndex = seriesModel.seriesIndex; + bg.setShape({ + x: 0, + y: 0, + width: thisWidth, + height: thisHeight, + r: borderRadius + }); + + if (thisInvisible) { + // If invisible, do not set visual, otherwise the element will + // change immediately before animation. We think it is OK to + // remain its origin color when moving out of the view window. + processInvisible(bg); + } else { + bg.invisible = false; + var style = thisNode.getVisual('style'); + var visualBorderColor = style.stroke; + var normalStyle = getItemStyleNormal(itemStyleNormalModel); + normalStyle.fill = visualBorderColor; + var emphasisStyle = getStateItemStyle(itemStyleEmphasisModel); + emphasisStyle.fill = itemStyleEmphasisModel.get('borderColor'); + var blurStyle = getStateItemStyle(itemStyleBlurModel); + blurStyle.fill = itemStyleBlurModel.get('borderColor'); + var selectStyle = getStateItemStyle(itemStyleSelectModel); + selectStyle.fill = itemStyleSelectModel.get('borderColor'); + + if (useUpperLabel) { + var upperLabelWidth = thisWidth - 2 * borderWidth; + prepareText( // PENDING: convert ZRColor to ColorString for text. + bg, visualBorderColor, style.opacity, { + x: borderWidth, + y: 0, + width: upperLabelWidth, + height: upperHeight + }); + } // For old bg. + else { + bg.removeTextContent(); + } + + bg.setStyle(normalStyle); + bg.ensureState('emphasis').style = emphasisStyle; + bg.ensureState('blur').style = blurStyle; + bg.ensureState('select').style = selectStyle; + setDefaultStateProxy(bg); + } + + group.add(bg); + } + + function renderContent(group, content) { + var ecData = getECData(content); // For tooltip. + + ecData.dataIndex = thisNode.dataIndex; + ecData.seriesIndex = seriesModel.seriesIndex; + var contentWidth = Math.max(thisWidth - 2 * borderWidth, 0); + var contentHeight = Math.max(thisHeight - 2 * borderWidth, 0); + content.culling = true; + content.setShape({ + x: borderWidth, + y: borderWidth, + width: contentWidth, + height: contentHeight, + r: borderRadius + }); + + if (thisInvisible) { + // If invisible, do not set visual, otherwise the element will + // change immediately before animation. We think it is OK to + // remain its origin color when moving out of the view window. + processInvisible(content); + } else { + content.invisible = false; + var nodeStyle = thisNode.getVisual('style'); + var visualColor = nodeStyle.fill; + var normalStyle = getItemStyleNormal(itemStyleNormalModel); + normalStyle.fill = visualColor; + normalStyle.decal = nodeStyle.decal; + var emphasisStyle = getStateItemStyle(itemStyleEmphasisModel); + var blurStyle = getStateItemStyle(itemStyleBlurModel); + var selectStyle = getStateItemStyle(itemStyleSelectModel); // PENDING: convert ZRColor to ColorString for text. + + prepareText(content, visualColor, nodeStyle.opacity, null); + content.setStyle(normalStyle); + content.ensureState('emphasis').style = emphasisStyle; + content.ensureState('blur').style = blurStyle; + content.ensureState('select').style = selectStyle; + setDefaultStateProxy(content); + } + + group.add(content); + } + + function processInvisible(element) { + // Delay invisible setting utill animation finished, + // avoid element vanish suddenly before animation. + !element.invisible && willInvisibleEls.push(element); + } + + function prepareText(rectEl, visualColor, visualOpacity, // Can be null/undefined + upperLabelRect) { + var normalLabelModel = nodeModel.getModel(upperLabelRect ? PATH_UPPERLABEL_NORMAL : PATH_LABEL_NOAMAL); + var defaultText = convertOptionIdName(nodeModel.get('name'), null); + var isShow = normalLabelModel.getShallow('show'); + setLabelStyle(rectEl, getLabelStatesModels(nodeModel, upperLabelRect ? PATH_UPPERLABEL_NORMAL : PATH_LABEL_NOAMAL), { + defaultText: isShow ? defaultText : null, + inheritColor: visualColor, + defaultOpacity: visualOpacity, + labelFetcher: seriesModel, + labelDataIndex: thisNode.dataIndex + }); + var textEl = rectEl.getTextContent(); + + if (!textEl) { + return; + } + + var textStyle = textEl.style; + var textPadding = normalizeCssArray(textStyle.padding || 0); + + if (upperLabelRect) { + rectEl.setTextConfig({ + layoutRect: upperLabelRect + }); + textEl.disableLabelLayout = true; + } + + textEl.beforeUpdate = function () { + var width = Math.max((upperLabelRect ? upperLabelRect.width : rectEl.shape.width) - textPadding[1] - textPadding[3], 0); + var height = Math.max((upperLabelRect ? upperLabelRect.height : rectEl.shape.height) - textPadding[0] - textPadding[2], 0); + + if (textStyle.width !== width || textStyle.height !== height) { + textEl.setStyle({ + width: width, + height: height + }); + } + }; + + textStyle.truncateMinChar = 2; + textStyle.lineOverflow = 'truncate'; + addDrillDownIcon(textStyle, upperLabelRect, thisLayout); + var textEmphasisState = textEl.getState('emphasis'); + addDrillDownIcon(textEmphasisState ? textEmphasisState.style : null, upperLabelRect, thisLayout); + } + + function addDrillDownIcon(style, upperLabelRect, thisLayout) { + var text = style ? style.text : null; + + if (!upperLabelRect && thisLayout.isLeafRoot && text != null) { + var iconChar = seriesModel.get('drillDownIcon', true); + style.text = iconChar ? iconChar + ' ' + text : text; + } + } + + function giveGraphic(storageName, Ctor, depth, z) { + var element = oldRawIndex != null && oldStorage[storageName][oldRawIndex]; + var lasts = lastsForAnimation[storageName]; + + if (element) { + // Remove from oldStorage + oldStorage[storageName][oldRawIndex] = null; + prepareAnimationWhenHasOld(lasts, element); + } // If invisible and no old element, do not create new element (for optimizing). + else if (!thisInvisible) { + element = new Ctor(); + + if (element instanceof Displayable) { + element.z2 = calculateZ2(depth, z); + } + + prepareAnimationWhenNoOld(lasts, element); + } // Set to thisStorage + + + return thisStorage[storageName][thisRawIndex] = element; + } + + function prepareAnimationWhenHasOld(lasts, element) { + var lastCfg = lasts[thisRawIndex] = {}; + + if (element instanceof Group$1) { + lastCfg.oldX = element.x; + lastCfg.oldY = element.y; + } else { + lastCfg.oldShape = extend({}, element.shape); + } + } // If a element is new, we need to find the animation start point carefully, + // otherwise it will looks strange when 'zoomToNode'. + + + function prepareAnimationWhenNoOld(lasts, element) { + var lastCfg = lasts[thisRawIndex] = {}; + var parentNode = thisNode.parentNode; + var isGroup = element instanceof Group; + + if (parentNode && (!reRoot || reRoot.direction === 'drillDown')) { + var parentOldX = 0; + var parentOldY = 0; // New nodes appear from right-bottom corner in 'zoomToNode' animation. + // For convenience, get old bounding rect from background. + + var parentOldBg = lastsForAnimation.background[parentNode.getRawIndex()]; + + if (!reRoot && parentOldBg && parentOldBg.oldShape) { + parentOldX = parentOldBg.oldShape.width; + parentOldY = parentOldBg.oldShape.height; + } // When no parent old shape found, its parent is new too, + // so we can just use {x:0, y:0}. + + + if (isGroup) { + lastCfg.oldX = 0; + lastCfg.oldY = parentOldY; + } else { + lastCfg.oldShape = { + x: parentOldX, + y: parentOldY, + width: 0, + height: 0 + }; + } + } // Fade in, user can be aware that these nodes are new. + + + lastCfg.fadein = !isGroup; + } + } // We can not set all backgroud with the same z, Because the behaviour of + // drill down and roll up differ background creation sequence from tree + // hierarchy sequence, which cause that lowser background element overlap + // upper ones. So we calculate z based on depth. + // Moreover, we try to shrink down z interval to [0, 1] to avoid that + // treemap with large z overlaps other components. + + + function calculateZ2(depth, z2InLevel) { + return depth * Z2_BASE + z2InLevel; + } + + var each$3 = each; + var isObject$3 = isObject; + var CATEGORY_DEFAULT_VISUAL_INDEX = -1; + + var VisualMapping = + /** @class */ + function () { + function VisualMapping(option) { + var mappingMethod = option.mappingMethod; + var visualType = option.type; + var thisOption = this.option = clone(option); + this.type = visualType; + this.mappingMethod = mappingMethod; + this._normalizeData = normalizers[mappingMethod]; + var visualHandler = VisualMapping.visualHandlers[visualType]; + this.applyVisual = visualHandler.applyVisual; + this.getColorMapper = visualHandler.getColorMapper; + this._normalizedToVisual = visualHandler._normalizedToVisual[mappingMethod]; + + if (mappingMethod === 'piecewise') { + normalizeVisualRange(thisOption); + preprocessForPiecewise(thisOption); + } else if (mappingMethod === 'category') { + thisOption.categories ? preprocessForSpecifiedCategory(thisOption) // categories is ordinal when thisOption.categories not specified, + // which need no more preprocess except normalize visual. + : normalizeVisualRange(thisOption, true); + } else { + // mappingMethod === 'linear' or 'fixed' + assert(mappingMethod !== 'linear' || thisOption.dataExtent); + normalizeVisualRange(thisOption); + } + } + + VisualMapping.prototype.mapValueToVisual = function (value) { + var normalized = this._normalizeData(value); + + return this._normalizedToVisual(normalized, value); + }; + + VisualMapping.prototype.getNormalizer = function () { + return bind(this._normalizeData, this); + }; + /** + * List available visual types. + * + * @public + * @return {Array.} + */ + + + VisualMapping.listVisualTypes = function () { + return keys(VisualMapping.visualHandlers); + }; // /** + // * @public + // */ + // static addVisualHandler(name, handler) { + // visualHandlers[name] = handler; + // } + + /** + * @public + */ + + + VisualMapping.isValidType = function (visualType) { + return VisualMapping.visualHandlers.hasOwnProperty(visualType); + }; + /** + * Convinent method. + * Visual can be Object or Array or primary type. + */ + + + VisualMapping.eachVisual = function (visual, callback, context) { + if (isObject(visual)) { + each(visual, callback, context); + } else { + callback.call(context, visual); + } + }; + + VisualMapping.mapVisual = function (visual, callback, context) { + var isPrimary; + var newVisual = isArray(visual) ? [] : isObject(visual) ? {} : (isPrimary = true, null); + VisualMapping.eachVisual(visual, function (v, key) { + var newVal = callback.call(context, v, key); + isPrimary ? newVisual = newVal : newVisual[key] = newVal; + }); + return newVisual; + }; + /** + * Retrieve visual properties from given object. + */ + + + VisualMapping.retrieveVisuals = function (obj) { + var ret = {}; + var hasVisual; + obj && each$3(VisualMapping.visualHandlers, function (h, visualType) { + if (obj.hasOwnProperty(visualType)) { + ret[visualType] = obj[visualType]; + hasVisual = true; + } + }); + return hasVisual ? ret : null; + }; + /** + * Give order to visual types, considering colorSaturation, colorAlpha depends on color. + * + * @public + * @param {(Object|Array)} visualTypes If Object, like: {color: ..., colorSaturation: ...} + * IF Array, like: ['color', 'symbol', 'colorSaturation'] + * @return {Array.} Sorted visual types. + */ + + + VisualMapping.prepareVisualTypes = function (visualTypes) { + if (isArray(visualTypes)) { + visualTypes = visualTypes.slice(); + } else if (isObject$3(visualTypes)) { + var types_1 = []; + each$3(visualTypes, function (item, type) { + types_1.push(type); + }); + visualTypes = types_1; + } else { + return []; + } + + visualTypes.sort(function (type1, type2) { + // color should be front of colorSaturation, colorAlpha, ... + // symbol and symbolSize do not matter. + return type2 === 'color' && type1 !== 'color' && type1.indexOf('color') === 0 ? 1 : -1; + }); + return visualTypes; + }; + /** + * 'color', 'colorSaturation', 'colorAlpha', ... are depends on 'color'. + * Other visuals are only depends on themself. + */ + + + VisualMapping.dependsOn = function (visualType1, visualType2) { + return visualType2 === 'color' ? !!(visualType1 && visualType1.indexOf(visualType2) === 0) : visualType1 === visualType2; + }; + /** + * @param value + * @param pieceList [{value: ..., interval: [min, max]}, ...] + * Always from small to big. + * @param findClosestWhenOutside Default to be false + * @return index + */ + + + VisualMapping.findPieceIndex = function (value, pieceList, findClosestWhenOutside) { + var possibleI; + var abs = Infinity; // value has the higher priority. + + for (var i = 0, len = pieceList.length; i < len; i++) { + var pieceValue = pieceList[i].value; + + if (pieceValue != null) { + if (pieceValue === value // FIXME + // It is supposed to compare value according to value type of dimension, + // but currently value type can exactly be string or number. + // Compromise for numeric-like string (like '12'), especially + // in the case that visualMap.categories is ['22', '33']. + || isString(pieceValue) && pieceValue === value + '') { + return i; + } + + findClosestWhenOutside && updatePossible(pieceValue, i); + } + } + + for (var i = 0, len = pieceList.length; i < len; i++) { + var piece = pieceList[i]; + var interval = piece.interval; + var close_1 = piece.close; + + if (interval) { + if (interval[0] === -Infinity) { + if (littleThan(close_1[1], value, interval[1])) { + return i; + } + } else if (interval[1] === Infinity) { + if (littleThan(close_1[0], interval[0], value)) { + return i; + } + } else if (littleThan(close_1[0], interval[0], value) && littleThan(close_1[1], value, interval[1])) { + return i; + } + + findClosestWhenOutside && updatePossible(interval[0], i); + findClosestWhenOutside && updatePossible(interval[1], i); + } + } + + if (findClosestWhenOutside) { + return value === Infinity ? pieceList.length - 1 : value === -Infinity ? 0 : possibleI; + } + + function updatePossible(val, index) { + var newAbs = Math.abs(val - value); + + if (newAbs < abs) { + abs = newAbs; + possibleI = index; + } + } + }; + + VisualMapping.visualHandlers = { + color: { + applyVisual: makeApplyVisual('color'), + getColorMapper: function () { + var thisOption = this.option; + return bind(thisOption.mappingMethod === 'category' ? function (value, isNormalized) { + !isNormalized && (value = this._normalizeData(value)); + return doMapCategory.call(this, value); + } : function (value, isNormalized, out) { + // If output rgb array + // which will be much faster and useful in pixel manipulation + var returnRGBArray = !!out; + !isNormalized && (value = this._normalizeData(value)); + out = fastLerp(value, thisOption.parsedVisual, out); + return returnRGBArray ? out : stringify(out, 'rgba'); + }, this); + }, + _normalizedToVisual: { + linear: function (normalized) { + return stringify(fastLerp(normalized, this.option.parsedVisual), 'rgba'); + }, + category: doMapCategory, + piecewise: function (normalized, value) { + var result = getSpecifiedVisual.call(this, value); + + if (result == null) { + result = stringify(fastLerp(normalized, this.option.parsedVisual), 'rgba'); + } + + return result; + }, + fixed: doMapFixed + } + }, + colorHue: makePartialColorVisualHandler(function (color$1, value) { + return modifyHSL(color$1, value); + }), + colorSaturation: makePartialColorVisualHandler(function (color$1, value) { + return modifyHSL(color$1, null, value); + }), + colorLightness: makePartialColorVisualHandler(function (color$1, value) { + return modifyHSL(color$1, null, null, value); + }), + colorAlpha: makePartialColorVisualHandler(function (color$1, value) { + return modifyAlpha(color$1, value); + }), + decal: { + applyVisual: makeApplyVisual('decal'), + _normalizedToVisual: { + linear: null, + category: doMapCategory, + piecewise: null, + fixed: null + } + }, + opacity: { + applyVisual: makeApplyVisual('opacity'), + _normalizedToVisual: createNormalizedToNumericVisual([0, 1]) + }, + liftZ: { + applyVisual: makeApplyVisual('liftZ'), + _normalizedToVisual: { + linear: doMapFixed, + category: doMapFixed, + piecewise: doMapFixed, + fixed: doMapFixed + } + }, + symbol: { + applyVisual: function (value, getter, setter) { + var symbolCfg = this.mapValueToVisual(value); + setter('symbol', symbolCfg); + }, + _normalizedToVisual: { + linear: doMapToArray, + category: doMapCategory, + piecewise: function (normalized, value) { + var result = getSpecifiedVisual.call(this, value); + + if (result == null) { + result = doMapToArray.call(this, normalized); + } + + return result; + }, + fixed: doMapFixed + } + }, + symbolSize: { + applyVisual: makeApplyVisual('symbolSize'), + _normalizedToVisual: createNormalizedToNumericVisual([0, 1]) + } + }; + return VisualMapping; + }(); + + function preprocessForPiecewise(thisOption) { + var pieceList = thisOption.pieceList; + thisOption.hasSpecialVisual = false; + each(pieceList, function (piece, index) { + piece.originIndex = index; // piece.visual is "result visual value" but not + // a visual range, so it does not need to be normalized. + + if (piece.visual != null) { + thisOption.hasSpecialVisual = true; + } + }); + } + + function preprocessForSpecifiedCategory(thisOption) { + // Hash categories. + var categories = thisOption.categories; + var categoryMap = thisOption.categoryMap = {}; + var visual = thisOption.visual; + each$3(categories, function (cate, index) { + categoryMap[cate] = index; + }); // Process visual map input. + + if (!isArray(visual)) { + var visualArr_1 = []; + + if (isObject(visual)) { + each$3(visual, function (v, cate) { + var index = categoryMap[cate]; + visualArr_1[index != null ? index : CATEGORY_DEFAULT_VISUAL_INDEX] = v; + }); + } else { + // Is primary type, represents default visual. + visualArr_1[CATEGORY_DEFAULT_VISUAL_INDEX] = visual; + } + + visual = setVisualToOption(thisOption, visualArr_1); + } // Remove categories that has no visual, + // then we can mapping them to CATEGORY_DEFAULT_VISUAL_INDEX. + + + for (var i = categories.length - 1; i >= 0; i--) { + if (visual[i] == null) { + delete categoryMap[categories[i]]; + categories.pop(); + } + } + } + + function normalizeVisualRange(thisOption, isCategory) { + var visual = thisOption.visual; + var visualArr = []; + + if (isObject(visual)) { + each$3(visual, function (v) { + visualArr.push(v); + }); + } else if (visual != null) { + visualArr.push(visual); + } + + var doNotNeedPair = { + color: 1, + symbol: 1 + }; + + if (!isCategory && visualArr.length === 1 && !doNotNeedPair.hasOwnProperty(thisOption.type)) { + // Do not care visualArr.length === 0, which is illegal. + visualArr[1] = visualArr[0]; + } + + setVisualToOption(thisOption, visualArr); + } + + function makePartialColorVisualHandler(applyValue) { + return { + applyVisual: function (value, getter, setter) { + // Only used in HSL + var colorChannel = this.mapValueToVisual(value); // Must not be array value + + setter('color', applyValue(getter('color'), colorChannel)); + }, + _normalizedToVisual: createNormalizedToNumericVisual([0, 1]) + }; + } + + function doMapToArray(normalized) { + var visual = this.option.visual; + return visual[Math.round(linearMap(normalized, [0, 1], [0, visual.length - 1], true))] || {}; // TODO {}? + } + + function makeApplyVisual(visualType) { + return function (value, getter, setter) { + setter(visualType, this.mapValueToVisual(value)); + }; + } + + function doMapCategory(normalized) { + var visual = this.option.visual; + return visual[this.option.loop && normalized !== CATEGORY_DEFAULT_VISUAL_INDEX ? normalized % visual.length : normalized]; + } + + function doMapFixed() { + // visual will be convert to array. + return this.option.visual[0]; + } + /** + * Create mapped to numeric visual + */ + + + function createNormalizedToNumericVisual(sourceExtent) { + return { + linear: function (normalized) { + return linearMap(normalized, sourceExtent, this.option.visual, true); + }, + category: doMapCategory, + piecewise: function (normalized, value) { + var result = getSpecifiedVisual.call(this, value); + + if (result == null) { + result = linearMap(normalized, sourceExtent, this.option.visual, true); + } + + return result; + }, + fixed: doMapFixed + }; + } + + function getSpecifiedVisual(value) { + var thisOption = this.option; + var pieceList = thisOption.pieceList; + + if (thisOption.hasSpecialVisual) { + var pieceIndex = VisualMapping.findPieceIndex(value, pieceList); + var piece = pieceList[pieceIndex]; + + if (piece && piece.visual) { + return piece.visual[this.type]; + } + } + } + + function setVisualToOption(thisOption, visualArr) { + thisOption.visual = visualArr; + + if (thisOption.type === 'color') { + thisOption.parsedVisual = map(visualArr, function (item) { + var color$1 = parse(item); + + if (!color$1 && "development" !== 'production') { + warn("'" + item + "' is an illegal color, fallback to '#000000'", true); + } + + return color$1 || [0, 0, 0, 1]; + }); + } + + return visualArr; + } + /** + * Normalizers by mapping methods. + */ + + + var normalizers = { + linear: function (value) { + return linearMap(value, this.option.dataExtent, [0, 1], true); + }, + piecewise: function (value) { + var pieceList = this.option.pieceList; + var pieceIndex = VisualMapping.findPieceIndex(value, pieceList, true); + + if (pieceIndex != null) { + return linearMap(pieceIndex, [0, pieceList.length - 1], [0, 1], true); + } + }, + category: function (value) { + var index = this.option.categories ? this.option.categoryMap[value] : value; // ordinal value + + return index == null ? CATEGORY_DEFAULT_VISUAL_INDEX : index; + }, + fixed: noop + }; + + function littleThan(close, a, b) { + return close ? a <= b : a < b; + } + + var ITEM_STYLE_NORMAL = 'itemStyle'; + var inner$9 = makeInner(); + var treemapVisual = { + seriesType: 'treemap', + reset: function (seriesModel) { + var tree = seriesModel.getData().tree; + var root = tree.root; + + if (root.isRemoved()) { + return; + } + + travelTree(root, // Visual should calculate from tree root but not view root. + {}, seriesModel.getViewRoot().getAncestors(), seriesModel); + } + }; + + function travelTree(node, designatedVisual, viewRootAncestors, seriesModel) { + var nodeModel = node.getModel(); + var nodeLayout = node.getLayout(); + var data = node.hostTree.data; // Optimize + + if (!nodeLayout || nodeLayout.invisible || !nodeLayout.isInView) { + return; + } + + var nodeItemStyleModel = nodeModel.getModel(ITEM_STYLE_NORMAL); + var visuals = buildVisuals(nodeItemStyleModel, designatedVisual, seriesModel); + var existsStyle = data.ensureUniqueItemVisual(node.dataIndex, 'style'); // calculate border color + + var borderColor = nodeItemStyleModel.get('borderColor'); + var borderColorSaturation = nodeItemStyleModel.get('borderColorSaturation'); + var thisNodeColor; + + if (borderColorSaturation != null) { + // For performance, do not always execute 'calculateColor'. + thisNodeColor = calculateColor(visuals); + borderColor = calculateBorderColor(borderColorSaturation, thisNodeColor); + } + + existsStyle.stroke = borderColor; + var viewChildren = node.viewChildren; + + if (!viewChildren || !viewChildren.length) { + thisNodeColor = calculateColor(visuals); // Apply visual to this node. + + existsStyle.fill = thisNodeColor; + } else { + var mapping_1 = buildVisualMapping(node, nodeModel, nodeLayout, nodeItemStyleModel, visuals, viewChildren); // Designate visual to children. + + each(viewChildren, function (child, index) { + // If higher than viewRoot, only ancestors of viewRoot is needed to visit. + if (child.depth >= viewRootAncestors.length || child === viewRootAncestors[child.depth]) { + var childVisual = mapVisual(nodeModel, visuals, child, index, mapping_1, seriesModel); + travelTree(child, childVisual, viewRootAncestors, seriesModel); + } + }); + } + } + + function buildVisuals(nodeItemStyleModel, designatedVisual, seriesModel) { + var visuals = extend({}, designatedVisual); + var designatedVisualItemStyle = seriesModel.designatedVisualItemStyle; + each(['color', 'colorAlpha', 'colorSaturation'], function (visualName) { + // Priority: thisNode > thisLevel > parentNodeDesignated > seriesModel + designatedVisualItemStyle[visualName] = designatedVisual[visualName]; + var val = nodeItemStyleModel.get(visualName); + designatedVisualItemStyle[visualName] = null; + val != null && (visuals[visualName] = val); + }); + return visuals; + } + + function calculateColor(visuals) { + var color = getValueVisualDefine(visuals, 'color'); + + if (color) { + var colorAlpha = getValueVisualDefine(visuals, 'colorAlpha'); + var colorSaturation = getValueVisualDefine(visuals, 'colorSaturation'); + + if (colorSaturation) { + color = modifyHSL(color, null, null, colorSaturation); + } + + if (colorAlpha) { + color = modifyAlpha(color, colorAlpha); + } + + return color; + } + } + + function calculateBorderColor(borderColorSaturation, thisNodeColor) { + return thisNodeColor != null // Can only be string + ? modifyHSL(thisNodeColor, null, null, borderColorSaturation) : null; + } + + function getValueVisualDefine(visuals, name) { + var value = visuals[name]; + + if (value != null && value !== 'none') { + return value; + } + } + + function buildVisualMapping(node, nodeModel, nodeLayout, nodeItemStyleModel, visuals, viewChildren) { + if (!viewChildren || !viewChildren.length) { + return; + } + + var rangeVisual = getRangeVisual(nodeModel, 'color') || visuals.color != null && visuals.color !== 'none' && (getRangeVisual(nodeModel, 'colorAlpha') || getRangeVisual(nodeModel, 'colorSaturation')); + + if (!rangeVisual) { + return; + } + + var visualMin = nodeModel.get('visualMin'); + var visualMax = nodeModel.get('visualMax'); + var dataExtent = nodeLayout.dataExtent.slice(); + visualMin != null && visualMin < dataExtent[0] && (dataExtent[0] = visualMin); + visualMax != null && visualMax > dataExtent[1] && (dataExtent[1] = visualMax); + var colorMappingBy = nodeModel.get('colorMappingBy'); + var opt = { + type: rangeVisual.name, + dataExtent: dataExtent, + visual: rangeVisual.range + }; + + if (opt.type === 'color' && (colorMappingBy === 'index' || colorMappingBy === 'id')) { + opt.mappingMethod = 'category'; + opt.loop = true; // categories is ordinal, so do not set opt.categories. + } else { + opt.mappingMethod = 'linear'; + } + + var mapping = new VisualMapping(opt); + inner$9(mapping).drColorMappingBy = colorMappingBy; + return mapping; + } // Notice: If we dont have the attribute 'colorRange', but only use + // attribute 'color' to represent both concepts of 'colorRange' and 'color', + // (It means 'colorRange' when 'color' is Array, means 'color' when not array), + // this problem will be encountered: + // If a level-1 node dont have children, and its siblings has children, + // and colorRange is set on level-1, then the node can not be colored. + // So we separate 'colorRange' and 'color' to different attributes. + + + function getRangeVisual(nodeModel, name) { + // 'colorRange', 'colorARange', 'colorSRange'. + // If not exsits on this node, fetch from levels and series. + var range = nodeModel.get(name); + return isArray(range) && range.length ? { + name: name, + range: range + } : null; + } + + function mapVisual(nodeModel, visuals, child, index, mapping, seriesModel) { + var childVisuals = extend({}, visuals); + + if (mapping) { + // Only support color, colorAlpha, colorSaturation. + var mappingType = mapping.type; + var colorMappingBy = mappingType === 'color' && inner$9(mapping).drColorMappingBy; + var value = colorMappingBy === 'index' ? index : colorMappingBy === 'id' ? seriesModel.mapIdToIndex(child.getId()) : child.getValue(nodeModel.get('visualDimension')); + childVisuals[mappingType] = mapping.mapValueToVisual(value); + } + + return childVisuals; + } + + var mathMax$7 = Math.max; + var mathMin$7 = Math.min; + var retrieveValue = retrieve; + var each$4 = each; + var PATH_BORDER_WIDTH = ['itemStyle', 'borderWidth']; + var PATH_GAP_WIDTH = ['itemStyle', 'gapWidth']; + var PATH_UPPER_LABEL_SHOW = ['upperLabel', 'show']; + var PATH_UPPER_LABEL_HEIGHT = ['upperLabel', 'height']; + /** + * @public + */ + + var treemapLayout = { + seriesType: 'treemap', + reset: function (seriesModel, ecModel, api, payload) { + // Layout result in each node: + // {x, y, width, height, area, borderWidth} + var ecWidth = api.getWidth(); + var ecHeight = api.getHeight(); + var seriesOption = seriesModel.option; + var layoutInfo = getLayoutRect(seriesModel.getBoxLayoutParams(), { + width: api.getWidth(), + height: api.getHeight() + }); + var size = seriesOption.size || []; // Compatible with ec2. + + var containerWidth = parsePercent$1(retrieveValue(layoutInfo.width, size[0]), ecWidth); + var containerHeight = parsePercent$1(retrieveValue(layoutInfo.height, size[1]), ecHeight); // Fetch payload info. + + var payloadType = payload && payload.type; + var types = ['treemapZoomToNode', 'treemapRootToNode']; + var targetInfo = retrieveTargetInfo(payload, types, seriesModel); + var rootRect = payloadType === 'treemapRender' || payloadType === 'treemapMove' ? payload.rootRect : null; + var viewRoot = seriesModel.getViewRoot(); + var viewAbovePath = getPathToRoot(viewRoot); + + if (payloadType !== 'treemapMove') { + var rootSize = payloadType === 'treemapZoomToNode' ? estimateRootSize(seriesModel, targetInfo, viewRoot, containerWidth, containerHeight) : rootRect ? [rootRect.width, rootRect.height] : [containerWidth, containerHeight]; + var sort_1 = seriesOption.sort; + + if (sort_1 && sort_1 !== 'asc' && sort_1 !== 'desc') { + // Default to be desc order. + sort_1 = 'desc'; + } + + var options = { + squareRatio: seriesOption.squareRatio, + sort: sort_1, + leafDepth: seriesOption.leafDepth + }; // layout should be cleared because using updateView but not update. + + viewRoot.hostTree.clearLayouts(); // TODO + // optimize: if out of view clip, do not layout. + // But take care that if do not render node out of view clip, + // how to calculate start po + + var viewRootLayout_1 = { + x: 0, + y: 0, + width: rootSize[0], + height: rootSize[1], + area: rootSize[0] * rootSize[1] + }; + viewRoot.setLayout(viewRootLayout_1); + squarify(viewRoot, options, false, 0); // Supplement layout. + + viewRootLayout_1 = viewRoot.getLayout(); + each$4(viewAbovePath, function (node, index) { + var childValue = (viewAbovePath[index + 1] || viewRoot).getValue(); + node.setLayout(extend({ + dataExtent: [childValue, childValue], + borderWidth: 0, + upperHeight: 0 + }, viewRootLayout_1)); + }); + } + + var treeRoot = seriesModel.getData().tree.root; + treeRoot.setLayout(calculateRootPosition(layoutInfo, rootRect, targetInfo), true); + seriesModel.setLayoutInfo(layoutInfo); // FIXME + // 现在没有clip功能,暂时取ec高宽。 + + prunning(treeRoot, // Transform to base element coordinate system. + new BoundingRect(-layoutInfo.x, -layoutInfo.y, ecWidth, ecHeight), viewAbovePath, viewRoot, 0); + } + }; + /** + * Layout treemap with squarify algorithm. + * The original presentation of this algorithm + * was made by Mark Bruls, Kees Huizing, and Jarke J. van Wijk + * . + * The implementation of this algorithm was originally copied from "d3.js" + * + * with some modifications made for this program. + * See the license statement at the head of this file. + * + * @protected + * @param {module:echarts/data/Tree~TreeNode} node + * @param {Object} options + * @param {string} options.sort 'asc' or 'desc' + * @param {number} options.squareRatio + * @param {boolean} hideChildren + * @param {number} depth + */ + + function squarify(node, options, hideChildren, depth) { + var width; + var height; + + if (node.isRemoved()) { + return; + } + + var thisLayout = node.getLayout(); + width = thisLayout.width; + height = thisLayout.height; // Considering border and gap + + var nodeModel = node.getModel(); + var borderWidth = nodeModel.get(PATH_BORDER_WIDTH); + var halfGapWidth = nodeModel.get(PATH_GAP_WIDTH) / 2; + var upperLabelHeight = getUpperLabelHeight(nodeModel); + var upperHeight = Math.max(borderWidth, upperLabelHeight); + var layoutOffset = borderWidth - halfGapWidth; + var layoutOffsetUpper = upperHeight - halfGapWidth; + node.setLayout({ + borderWidth: borderWidth, + upperHeight: upperHeight, + upperLabelHeight: upperLabelHeight + }, true); + width = mathMax$7(width - 2 * layoutOffset, 0); + height = mathMax$7(height - layoutOffset - layoutOffsetUpper, 0); + var totalArea = width * height; + var viewChildren = initChildren(node, nodeModel, totalArea, options, hideChildren, depth); + + if (!viewChildren.length) { + return; + } + + var rect = { + x: layoutOffset, + y: layoutOffsetUpper, + width: width, + height: height + }; + var rowFixedLength = mathMin$7(width, height); + var best = Infinity; // the best row score so far + + var row = []; + row.area = 0; + + for (var i = 0, len = viewChildren.length; i < len;) { + var child = viewChildren[i]; + row.push(child); + row.area += child.getLayout().area; + var score = worst(row, rowFixedLength, options.squareRatio); // continue with this orientation + + if (score <= best) { + i++; + best = score; + } // abort, and try a different orientation + else { + row.area -= row.pop().getLayout().area; + position(row, rowFixedLength, rect, halfGapWidth, false); + rowFixedLength = mathMin$7(rect.width, rect.height); + row.length = row.area = 0; + best = Infinity; + } + } + + if (row.length) { + position(row, rowFixedLength, rect, halfGapWidth, true); + } + + if (!hideChildren) { + var childrenVisibleMin = nodeModel.get('childrenVisibleMin'); + + if (childrenVisibleMin != null && totalArea < childrenVisibleMin) { + hideChildren = true; + } + } + + for (var i = 0, len = viewChildren.length; i < len; i++) { + squarify(viewChildren[i], options, hideChildren, depth + 1); + } + } + /** + * Set area to each child, and calculate data extent for visual coding. + */ + + + function initChildren(node, nodeModel, totalArea, options, hideChildren, depth) { + var viewChildren = node.children || []; + var orderBy = options.sort; + orderBy !== 'asc' && orderBy !== 'desc' && (orderBy = null); + var overLeafDepth = options.leafDepth != null && options.leafDepth <= depth; // leafDepth has higher priority. + + if (hideChildren && !overLeafDepth) { + return node.viewChildren = []; + } // Sort children, order by desc. + + + viewChildren = filter(viewChildren, function (child) { + return !child.isRemoved(); + }); + sort$1(viewChildren, orderBy); + var info = statistic(nodeModel, viewChildren, orderBy); + + if (info.sum === 0) { + return node.viewChildren = []; + } + + info.sum = filterByThreshold(nodeModel, totalArea, info.sum, orderBy, viewChildren); + + if (info.sum === 0) { + return node.viewChildren = []; + } // Set area to each child. + + + for (var i = 0, len = viewChildren.length; i < len; i++) { + var area = viewChildren[i].getValue() / info.sum * totalArea; // Do not use setLayout({...}, true), because it is needed to clear last layout. + + viewChildren[i].setLayout({ + area: area + }); + } + + if (overLeafDepth) { + viewChildren.length && node.setLayout({ + isLeafRoot: true + }, true); + viewChildren.length = 0; + } + + node.viewChildren = viewChildren; + node.setLayout({ + dataExtent: info.dataExtent + }, true); + return viewChildren; + } + /** + * Consider 'visibleMin'. Modify viewChildren and get new sum. + */ + + + function filterByThreshold(nodeModel, totalArea, sum, orderBy, orderedChildren) { + // visibleMin is not supported yet when no option.sort. + if (!orderBy) { + return sum; + } + + var visibleMin = nodeModel.get('visibleMin'); + var len = orderedChildren.length; + var deletePoint = len; // Always travel from little value to big value. + + for (var i = len - 1; i >= 0; i--) { + var value = orderedChildren[orderBy === 'asc' ? len - i - 1 : i].getValue(); + + if (value / sum * totalArea < visibleMin) { + deletePoint = i; + sum -= value; + } + } + + orderBy === 'asc' ? orderedChildren.splice(0, len - deletePoint) : orderedChildren.splice(deletePoint, len - deletePoint); + return sum; + } + /** + * Sort + */ + + + function sort$1(viewChildren, orderBy) { + if (orderBy) { + viewChildren.sort(function (a, b) { + var diff = orderBy === 'asc' ? a.getValue() - b.getValue() : b.getValue() - a.getValue(); + return diff === 0 ? orderBy === 'asc' ? a.dataIndex - b.dataIndex : b.dataIndex - a.dataIndex : diff; + }); + } + + return viewChildren; + } + /** + * Statistic + */ + + + function statistic(nodeModel, children, orderBy) { + // Calculate sum. + var sum = 0; + + for (var i = 0, len = children.length; i < len; i++) { + sum += children[i].getValue(); + } // Statistic data extent for latter visual coding. + // Notice: data extent should be calculate based on raw children + // but not filtered view children, otherwise visual mapping will not + // be stable when zoom (where children is filtered by visibleMin). + + + var dimension = nodeModel.get('visualDimension'); + var dataExtent; // The same as area dimension. + + if (!children || !children.length) { + dataExtent = [NaN, NaN]; + } else if (dimension === 'value' && orderBy) { + dataExtent = [children[children.length - 1].getValue(), children[0].getValue()]; + orderBy === 'asc' && dataExtent.reverse(); + } // Other dimension. + else { + dataExtent = [Infinity, -Infinity]; + each$4(children, function (child) { + var value = child.getValue(dimension); + value < dataExtent[0] && (dataExtent[0] = value); + value > dataExtent[1] && (dataExtent[1] = value); + }); + } + + return { + sum: sum, + dataExtent: dataExtent + }; + } + /** + * Computes the score for the specified row, + * as the worst aspect ratio. + */ + + + function worst(row, rowFixedLength, ratio) { + var areaMax = 0; + var areaMin = Infinity; + + for (var i = 0, area = void 0, len = row.length; i < len; i++) { + area = row[i].getLayout().area; + + if (area) { + area < areaMin && (areaMin = area); + area > areaMax && (areaMax = area); + } + } + + var squareArea = row.area * row.area; + var f = rowFixedLength * rowFixedLength * ratio; + return squareArea ? mathMax$7(f * areaMax / squareArea, squareArea / (f * areaMin)) : Infinity; + } + /** + * Positions the specified row of nodes. Modifies `rect`. + */ + + + function position(row, rowFixedLength, rect, halfGapWidth, flush) { + // When rowFixedLength === rect.width, + // it is horizontal subdivision, + // rowFixedLength is the width of the subdivision, + // rowOtherLength is the height of the subdivision, + // and nodes will be positioned from left to right. + // wh[idx0WhenH] means: when horizontal, + // wh[idx0WhenH] => wh[0] => 'width'. + // xy[idx1WhenH] => xy[1] => 'y'. + var idx0WhenH = rowFixedLength === rect.width ? 0 : 1; + var idx1WhenH = 1 - idx0WhenH; + var xy = ['x', 'y']; + var wh = ['width', 'height']; + var last = rect[xy[idx0WhenH]]; + var rowOtherLength = rowFixedLength ? row.area / rowFixedLength : 0; + + if (flush || rowOtherLength > rect[wh[idx1WhenH]]) { + rowOtherLength = rect[wh[idx1WhenH]]; // over+underflow + } + + for (var i = 0, rowLen = row.length; i < rowLen; i++) { + var node = row[i]; + var nodeLayout = {}; + var step = rowOtherLength ? node.getLayout().area / rowOtherLength : 0; + var wh1 = nodeLayout[wh[idx1WhenH]] = mathMax$7(rowOtherLength - 2 * halfGapWidth, 0); // We use Math.max/min to avoid negative width/height when considering gap width. + + var remain = rect[xy[idx0WhenH]] + rect[wh[idx0WhenH]] - last; + var modWH = i === rowLen - 1 || remain < step ? remain : step; + var wh0 = nodeLayout[wh[idx0WhenH]] = mathMax$7(modWH - 2 * halfGapWidth, 0); + nodeLayout[xy[idx1WhenH]] = rect[xy[idx1WhenH]] + mathMin$7(halfGapWidth, wh1 / 2); + nodeLayout[xy[idx0WhenH]] = last + mathMin$7(halfGapWidth, wh0 / 2); + last += modWH; + node.setLayout(nodeLayout, true); + } + + rect[xy[idx1WhenH]] += rowOtherLength; + rect[wh[idx1WhenH]] -= rowOtherLength; + } // Return [containerWidth, containerHeight] as default. + + + function estimateRootSize(seriesModel, targetInfo, viewRoot, containerWidth, containerHeight) { + // If targetInfo.node exists, we zoom to the node, + // so estimate whold width and heigth by target node. + var currNode = (targetInfo || {}).node; + var defaultSize = [containerWidth, containerHeight]; + + if (!currNode || currNode === viewRoot) { + return defaultSize; + } + + var parent; + var viewArea = containerWidth * containerHeight; + var area = viewArea * seriesModel.option.zoomToNodeRatio; + + while (parent = currNode.parentNode) { + // jshint ignore:line + var sum = 0; + var siblings = parent.children; + + for (var i = 0, len = siblings.length; i < len; i++) { + sum += siblings[i].getValue(); + } + + var currNodeValue = currNode.getValue(); + + if (currNodeValue === 0) { + return defaultSize; + } + + area *= sum / currNodeValue; // Considering border, suppose aspect ratio is 1. + + var parentModel = parent.getModel(); + var borderWidth = parentModel.get(PATH_BORDER_WIDTH); + var upperHeight = Math.max(borderWidth, getUpperLabelHeight(parentModel)); + area += 4 * borderWidth * borderWidth + (3 * borderWidth + upperHeight) * Math.pow(area, 0.5); + area > MAX_SAFE_INTEGER && (area = MAX_SAFE_INTEGER); + currNode = parent; + } + + area < viewArea && (area = viewArea); + var scale = Math.pow(area / viewArea, 0.5); + return [containerWidth * scale, containerHeight * scale]; + } // Root postion base on coord of containerGroup + + + function calculateRootPosition(layoutInfo, rootRect, targetInfo) { + if (rootRect) { + return { + x: rootRect.x, + y: rootRect.y + }; + } + + var defaultPosition = { + x: 0, + y: 0 + }; + + if (!targetInfo) { + return defaultPosition; + } // If targetInfo is fetched by 'retrieveTargetInfo', + // old tree and new tree are the same tree, + // so the node still exists and we can visit it. + + + var targetNode = targetInfo.node; + var layout = targetNode.getLayout(); + + if (!layout) { + return defaultPosition; + } // Transform coord from local to container. + + + var targetCenter = [layout.width / 2, layout.height / 2]; + var node = targetNode; + + while (node) { + var nodeLayout = node.getLayout(); + targetCenter[0] += nodeLayout.x; + targetCenter[1] += nodeLayout.y; + node = node.parentNode; + } + + return { + x: layoutInfo.width / 2 - targetCenter[0], + y: layoutInfo.height / 2 - targetCenter[1] + }; + } // Mark nodes visible for prunning when visual coding and rendering. + // Prunning depends on layout and root position, so we have to do it after layout. + + + function prunning(node, clipRect, viewAbovePath, viewRoot, depth) { + var nodeLayout = node.getLayout(); + var nodeInViewAbovePath = viewAbovePath[depth]; + var isAboveViewRoot = nodeInViewAbovePath && nodeInViewAbovePath === node; + + if (nodeInViewAbovePath && !isAboveViewRoot || depth === viewAbovePath.length && node !== viewRoot) { + return; + } + + node.setLayout({ + // isInView means: viewRoot sub tree + viewAbovePath + isInView: true, + // invisible only means: outside view clip so that the node can not + // see but still layout for animation preparation but not render. + invisible: !isAboveViewRoot && !clipRect.intersect(nodeLayout), + isAboveViewRoot: isAboveViewRoot + }, true); // Transform to child coordinate. + + var childClipRect = new BoundingRect(clipRect.x - nodeLayout.x, clipRect.y - nodeLayout.y, clipRect.width, clipRect.height); + each$4(node.viewChildren || [], function (child) { + prunning(child, childClipRect, viewAbovePath, viewRoot, depth + 1); + }); + } + + function getUpperLabelHeight(model) { + return model.get(PATH_UPPER_LABEL_SHOW) ? model.get(PATH_UPPER_LABEL_HEIGHT) : 0; + } + + function install$c(registers) { + registers.registerSeriesModel(TreemapSeriesModel); + registers.registerChartView(TreemapView); + registers.registerVisual(treemapVisual); + registers.registerLayout(treemapLayout); + installTreemapAction(registers); + } + + function categoryFilter(ecModel) { + var legendModels = ecModel.findComponents({ + mainType: 'legend' + }); + + if (!legendModels || !legendModels.length) { + return; + } + + ecModel.eachSeriesByType('graph', function (graphSeries) { + var categoriesData = graphSeries.getCategoriesData(); + var graph = graphSeries.getGraph(); + var data = graph.data; + var categoryNames = categoriesData.mapArray(categoriesData.getName); + data.filterSelf(function (idx) { + var model = data.getItemModel(idx); + var category = model.getShallow('category'); + + if (category != null) { + if (isNumber(category)) { + category = categoryNames[category]; + } // If in any legend component the status is not selected. + + + for (var i = 0; i < legendModels.length; i++) { + if (!legendModels[i].isSelected(category)) { + return false; + } + } + } + + return true; + }); + }); + } + + function categoryVisual(ecModel) { + var paletteScope = {}; + ecModel.eachSeriesByType('graph', function (seriesModel) { + var categoriesData = seriesModel.getCategoriesData(); + var data = seriesModel.getData(); + var categoryNameIdxMap = {}; + categoriesData.each(function (idx) { + var name = categoriesData.getName(idx); // Add prefix to avoid conflict with Object.prototype. + + categoryNameIdxMap['ec-' + name] = idx; + var itemModel = categoriesData.getItemModel(idx); + var style = itemModel.getModel('itemStyle').getItemStyle(); + + if (!style.fill) { + // Get color from palette. + style.fill = seriesModel.getColorFromPalette(name, paletteScope); + } + + categoriesData.setItemVisual(idx, 'style', style); + var symbolVisualList = ['symbol', 'symbolSize', 'symbolKeepAspect']; + + for (var i = 0; i < symbolVisualList.length; i++) { + var symbolVisual = itemModel.getShallow(symbolVisualList[i], true); + + if (symbolVisual != null) { + categoriesData.setItemVisual(idx, symbolVisualList[i], symbolVisual); + } + } + }); // Assign category color to visual + + if (categoriesData.count()) { + data.each(function (idx) { + var model = data.getItemModel(idx); + var categoryIdx = model.getShallow('category'); + + if (categoryIdx != null) { + if (isString(categoryIdx)) { + categoryIdx = categoryNameIdxMap['ec-' + categoryIdx]; + } + + var categoryStyle = categoriesData.getItemVisual(categoryIdx, 'style'); + var style = data.ensureUniqueItemVisual(idx, 'style'); + extend(style, categoryStyle); + var visualList = ['symbol', 'symbolSize', 'symbolKeepAspect']; + + for (var i = 0; i < visualList.length; i++) { + data.setItemVisual(idx, visualList[i], categoriesData.getItemVisual(categoryIdx, visualList[i])); + } + } + }); + } + }); + } + + function normalize$2(a) { + if (!(a instanceof Array)) { + a = [a, a]; + } + + return a; + } + + function graphEdgeVisual(ecModel) { + ecModel.eachSeriesByType('graph', function (seriesModel) { + var graph = seriesModel.getGraph(); + var edgeData = seriesModel.getEdgeData(); + var symbolType = normalize$2(seriesModel.get('edgeSymbol')); + var symbolSize = normalize$2(seriesModel.get('edgeSymbolSize')); // const colorQuery = ['lineStyle', 'color'] as const; + // const opacityQuery = ['lineStyle', 'opacity'] as const; + + edgeData.setVisual('fromSymbol', symbolType && symbolType[0]); + edgeData.setVisual('toSymbol', symbolType && symbolType[1]); + edgeData.setVisual('fromSymbolSize', symbolSize && symbolSize[0]); + edgeData.setVisual('toSymbolSize', symbolSize && symbolSize[1]); + edgeData.setVisual('style', seriesModel.getModel('lineStyle').getLineStyle()); + edgeData.each(function (idx) { + var itemModel = edgeData.getItemModel(idx); + var edge = graph.getEdgeByIndex(idx); + var symbolType = normalize$2(itemModel.getShallow('symbol', true)); + var symbolSize = normalize$2(itemModel.getShallow('symbolSize', true)); // Edge visual must after node visual + + var style = itemModel.getModel('lineStyle').getLineStyle(); + var existsStyle = edgeData.ensureUniqueItemVisual(idx, 'style'); + extend(existsStyle, style); + + switch (existsStyle.stroke) { + case 'source': + { + var nodeStyle = edge.node1.getVisual('style'); + existsStyle.stroke = nodeStyle && nodeStyle.fill; + break; + } + + case 'target': + { + var nodeStyle = edge.node2.getVisual('style'); + existsStyle.stroke = nodeStyle && nodeStyle.fill; + break; + } + } + + symbolType[0] && edge.setVisual('fromSymbol', symbolType[0]); + symbolType[1] && edge.setVisual('toSymbol', symbolType[1]); + symbolSize[0] && edge.setVisual('fromSymbolSize', symbolSize[0]); + symbolSize[1] && edge.setVisual('toSymbolSize', symbolSize[1]); + }); + }); + } + + var KEY_DELIMITER = '-->'; + /** + * params handler + * @param {module:echarts/model/SeriesModel} seriesModel + * @returns {*} + */ + + var getAutoCurvenessParams = function (seriesModel) { + return seriesModel.get('autoCurveness') || null; + }; + /** + * Generate a list of edge curvatures, 20 is the default + * @param {module:echarts/model/SeriesModel} seriesModel + * @param {number} appendLength + * @return 20 => [0, -0.2, 0.2, -0.4, 0.4, -0.6, 0.6, -0.8, 0.8, -1, 1, -1.2, 1.2, -1.4, 1.4, -1.6, 1.6, -1.8, 1.8, -2] + */ + + + var createCurveness = function (seriesModel, appendLength) { + var autoCurvenessParmas = getAutoCurvenessParams(seriesModel); + var length = 20; + var curvenessList = []; // handler the function set + + if (isNumber(autoCurvenessParmas)) { + length = autoCurvenessParmas; + } else if (isArray(autoCurvenessParmas)) { + seriesModel.__curvenessList = autoCurvenessParmas; + return; + } // append length + + + if (appendLength > length) { + length = appendLength; + } // make sure the length is even + + + var len = length % 2 ? length + 2 : length + 3; + curvenessList = []; + + for (var i = 0; i < len; i++) { + curvenessList.push((i % 2 ? i + 1 : i) / 10 * (i % 2 ? -1 : 1)); + } + + seriesModel.__curvenessList = curvenessList; + }; + /** + * Create different cache key data in the positive and negative directions, in order to set the curvature later + * @param {number|string|module:echarts/data/Graph.Node} n1 + * @param {number|string|module:echarts/data/Graph.Node} n2 + * @param {module:echarts/model/SeriesModel} seriesModel + * @returns {string} key + */ + + + var getKeyOfEdges = function (n1, n2, seriesModel) { + var source = [n1.id, n1.dataIndex].join('.'); + var target = [n2.id, n2.dataIndex].join('.'); + return [seriesModel.uid, source, target].join(KEY_DELIMITER); + }; + /** + * get opposite key + * @param {string} key + * @returns {string} + */ + + + var getOppositeKey = function (key) { + var keys = key.split(KEY_DELIMITER); + return [keys[0], keys[2], keys[1]].join(KEY_DELIMITER); + }; + /** + * get edgeMap with key + * @param edge + * @param {module:echarts/model/SeriesModel} seriesModel + */ + + + var getEdgeFromMap = function (edge, seriesModel) { + var key = getKeyOfEdges(edge.node1, edge.node2, seriesModel); + return seriesModel.__edgeMap[key]; + }; + /** + * calculate all cases total length + * @param edge + * @param seriesModel + * @returns {number} + */ + + + var getTotalLengthBetweenNodes = function (edge, seriesModel) { + var len = getEdgeMapLengthWithKey(getKeyOfEdges(edge.node1, edge.node2, seriesModel), seriesModel); + var lenV = getEdgeMapLengthWithKey(getKeyOfEdges(edge.node2, edge.node1, seriesModel), seriesModel); + return len + lenV; + }; + /** + * + * @param key + */ + + + var getEdgeMapLengthWithKey = function (key, seriesModel) { + var edgeMap = seriesModel.__edgeMap; + return edgeMap[key] ? edgeMap[key].length : 0; + }; + /** + * Count the number of edges between the same two points, used to obtain the curvature table and the parity of the edge + * @see /graph/GraphSeries.js@getInitialData + * @param {module:echarts/model/SeriesModel} seriesModel + */ + + + function initCurvenessList(seriesModel) { + if (!getAutoCurvenessParams(seriesModel)) { + return; + } + + seriesModel.__curvenessList = []; + seriesModel.__edgeMap = {}; // calc the array of curveness List + + createCurveness(seriesModel); + } + /** + * set edgeMap with key + * @param {number|string|module:echarts/data/Graph.Node} n1 + * @param {number|string|module:echarts/data/Graph.Node} n2 + * @param {module:echarts/model/SeriesModel} seriesModel + * @param {number} index + */ + + function createEdgeMapForCurveness(n1, n2, seriesModel, index) { + if (!getAutoCurvenessParams(seriesModel)) { + return; + } + + var key = getKeyOfEdges(n1, n2, seriesModel); + var edgeMap = seriesModel.__edgeMap; + var oppositeEdges = edgeMap[getOppositeKey(key)]; // set direction + + if (edgeMap[key] && !oppositeEdges) { + edgeMap[key].isForward = true; + } else if (oppositeEdges && edgeMap[key]) { + oppositeEdges.isForward = true; + edgeMap[key].isForward = false; + } + + edgeMap[key] = edgeMap[key] || []; + edgeMap[key].push(index); + } + /** + * get curvature for edge + * @param edge + * @param {module:echarts/model/SeriesModel} seriesModel + * @param index + */ + + function getCurvenessForEdge(edge, seriesModel, index, needReverse) { + var autoCurvenessParams = getAutoCurvenessParams(seriesModel); + var isArrayParam = isArray(autoCurvenessParams); + + if (!autoCurvenessParams) { + return null; + } + + var edgeArray = getEdgeFromMap(edge, seriesModel); + + if (!edgeArray) { + return null; + } + + var edgeIndex = -1; + + for (var i = 0; i < edgeArray.length; i++) { + if (edgeArray[i] === index) { + edgeIndex = i; + break; + } + } // if totalLen is Longer createCurveness + + + var totalLen = getTotalLengthBetweenNodes(edge, seriesModel); + createCurveness(seriesModel, totalLen); + edge.lineStyle = edge.lineStyle || {}; // if is opposite edge, must set curvenss to opposite number + + var curKey = getKeyOfEdges(edge.node1, edge.node2, seriesModel); + var curvenessList = seriesModel.__curvenessList; // if pass array no need parity + + var parityCorrection = isArrayParam ? 0 : totalLen % 2 ? 0 : 1; + + if (!edgeArray.isForward) { + // the opposite edge show outside + var oppositeKey = getOppositeKey(curKey); + var len = getEdgeMapLengthWithKey(oppositeKey, seriesModel); + var resValue = curvenessList[edgeIndex + len + parityCorrection]; // isNeedReverse, simple, force type need reverse the curveness in the junction of the forword and the opposite + + if (needReverse) { + // set as array may make the parity handle with the len of opposite + if (isArrayParam) { + if (autoCurvenessParams && autoCurvenessParams[0] === 0) { + return (len + parityCorrection) % 2 ? resValue : -resValue; + } else { + return ((len % 2 ? 0 : 1) + parityCorrection) % 2 ? resValue : -resValue; + } + } else { + return (len + parityCorrection) % 2 ? resValue : -resValue; + } + } else { + return curvenessList[edgeIndex + len + parityCorrection]; + } + } else { + return curvenessList[parityCorrection + edgeIndex]; + } + } + + function simpleLayout(seriesModel) { + var coordSys = seriesModel.coordinateSystem; + + if (coordSys && coordSys.type !== 'view') { + return; + } + + var graph = seriesModel.getGraph(); + graph.eachNode(function (node) { + var model = node.getModel(); + node.setLayout([+model.get('x'), +model.get('y')]); + }); + simpleLayoutEdge(graph, seriesModel); + } + function simpleLayoutEdge(graph, seriesModel) { + graph.eachEdge(function (edge, index) { + var curveness = retrieve3(edge.getModel().get(['lineStyle', 'curveness']), -getCurvenessForEdge(edge, seriesModel, index, true), 0); + var p1 = clone$1(edge.node1.getLayout()); + var p2 = clone$1(edge.node2.getLayout()); + var points = [p1, p2]; + + if (+curveness) { + points.push([(p1[0] + p2[0]) / 2 - (p1[1] - p2[1]) * curveness, (p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * curveness]); + } + + edge.setLayout(points); + }); + } + + function graphSimpleLayout(ecModel, api) { + ecModel.eachSeriesByType('graph', function (seriesModel) { + var layout = seriesModel.get('layout'); + var coordSys = seriesModel.coordinateSystem; + + if (coordSys && coordSys.type !== 'view') { + var data_1 = seriesModel.getData(); + var dimensions_1 = []; + each(coordSys.dimensions, function (coordDim) { + dimensions_1 = dimensions_1.concat(data_1.mapDimensionsAll(coordDim)); + }); + + for (var dataIndex = 0; dataIndex < data_1.count(); dataIndex++) { + var value = []; + var hasValue = false; + + for (var i = 0; i < dimensions_1.length; i++) { + var val = data_1.get(dimensions_1[i], dataIndex); + + if (!isNaN(val)) { + hasValue = true; + } + + value.push(val); + } + + if (hasValue) { + data_1.setItemLayout(dataIndex, coordSys.dataToPoint(value)); + } else { + // Also {Array.}, not undefined to avoid if...else... statement + data_1.setItemLayout(dataIndex, [NaN, NaN]); + } + } + + simpleLayoutEdge(data_1.graph, seriesModel); + } else if (!layout || layout === 'none') { + simpleLayout(seriesModel); + } + }); + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + function getNodeGlobalScale(seriesModel) { + var coordSys = seriesModel.coordinateSystem; + + if (coordSys.type !== 'view') { + return 1; + } + + var nodeScaleRatio = seriesModel.option.nodeScaleRatio; + var groupZoom = coordSys.scaleX; // Scale node when zoom changes + + var roamZoom = coordSys.getZoom(); + var nodeScale = (roamZoom - 1) * nodeScaleRatio + 1; + return nodeScale / groupZoom; + } + function getSymbolSize(node) { + var symbolSize = node.getVisual('symbolSize'); + + if (symbolSize instanceof Array) { + symbolSize = (symbolSize[0] + symbolSize[1]) / 2; + } + + return +symbolSize; + } + + var PI$6 = Math.PI; + var _symbolRadiansHalf = []; + /** + * `basedOn` can be: + * 'value': + * This layout is not accurate and have same bad case. For example, + * if the min value is very smaller than the max value, the nodes + * with the min value probably overlap even though there is enough + * space to layout them. So we only use this approach in the as the + * init layout of the force layout. + * FIXME + * Probably we do not need this method any more but use + * `basedOn: 'symbolSize'` in force layout if + * delay its init operations to GraphView. + * 'symbolSize': + * This approach work only if all of the symbol size calculated. + * That is, the progressive rendering is not applied to graph. + * FIXME + * If progressive rendering is applied to graph some day, + * probably we have to use `basedOn: 'value'`. + */ + + function circularLayout(seriesModel, basedOn) { + var coordSys = seriesModel.coordinateSystem; + + if (coordSys && coordSys.type !== 'view') { + return; + } + + var rect = coordSys.getBoundingRect(); + var nodeData = seriesModel.getData(); + var graph = nodeData.graph; + var cx = rect.width / 2 + rect.x; + var cy = rect.height / 2 + rect.y; + var r = Math.min(rect.width, rect.height) / 2; + var count = nodeData.count(); + nodeData.setLayout({ + cx: cx, + cy: cy + }); + + if (!count) { + return; + } + + _layoutNodesBasedOn[basedOn](seriesModel, graph, nodeData, r, cx, cy, count); + + graph.eachEdge(function (edge, index) { + var curveness = retrieve3(edge.getModel().get(['lineStyle', 'curveness']), getCurvenessForEdge(edge, seriesModel, index), 0); + var p1 = clone$1(edge.node1.getLayout()); + var p2 = clone$1(edge.node2.getLayout()); + var cp1; + var x12 = (p1[0] + p2[0]) / 2; + var y12 = (p1[1] + p2[1]) / 2; + + if (+curveness) { + curveness *= 3; + cp1 = [cx * curveness + x12 * (1 - curveness), cy * curveness + y12 * (1 - curveness)]; + } + + edge.setLayout([p1, p2, cp1]); + }); + } + var _layoutNodesBasedOn = { + value: function (seriesModel, graph, nodeData, r, cx, cy, count) { + var angle = 0; + var sum = nodeData.getSum('value'); + var unitAngle = Math.PI * 2 / (sum || count); + graph.eachNode(function (node) { + var value = node.getValue('value'); + var radianHalf = unitAngle * (sum ? value : 1) / 2; + angle += radianHalf; + node.setLayout([r * Math.cos(angle) + cx, r * Math.sin(angle) + cy]); + angle += radianHalf; + }); + }, + symbolSize: function (seriesModel, graph, nodeData, r, cx, cy, count) { + var sumRadian = 0; + _symbolRadiansHalf.length = count; + var nodeScale = getNodeGlobalScale(seriesModel); + graph.eachNode(function (node) { + var symbolSize = getSymbolSize(node); // Normally this case will not happen, but we still add + // some the defensive code (2px is an arbitrary value). + + isNaN(symbolSize) && (symbolSize = 2); + symbolSize < 0 && (symbolSize = 0); + symbolSize *= nodeScale; + var symbolRadianHalf = Math.asin(symbolSize / 2 / r); // when `symbolSize / 2` is bigger than `r`. + + isNaN(symbolRadianHalf) && (symbolRadianHalf = PI$6 / 2); + _symbolRadiansHalf[node.dataIndex] = symbolRadianHalf; + sumRadian += symbolRadianHalf * 2; + }); + var halfRemainRadian = (2 * PI$6 - sumRadian) / count / 2; + var angle = 0; + graph.eachNode(function (node) { + var radianHalf = halfRemainRadian + _symbolRadiansHalf[node.dataIndex]; + angle += radianHalf; + node.setLayout([r * Math.cos(angle) + cx, r * Math.sin(angle) + cy]); + angle += radianHalf; + }); + } + }; + + function graphCircularLayout(ecModel) { + ecModel.eachSeriesByType('graph', function (seriesModel) { + if (seriesModel.get('layout') === 'circular') { + circularLayout(seriesModel, 'symbolSize'); + } + }); + } + + var scaleAndAdd$1 = scaleAndAdd; // function adjacentNode(n, e) { + // return e.n1 === n ? e.n2 : e.n1; + // } + + function forceLayout(inNodes, inEdges, opts) { + var nodes = inNodes; + var edges = inEdges; + var rect = opts.rect; + var width = rect.width; + var height = rect.height; + var center = [rect.x + width / 2, rect.y + height / 2]; // let scale = opts.scale || 1; + + var gravity = opts.gravity == null ? 0.1 : opts.gravity; // for (let i = 0; i < edges.length; i++) { + // let e = edges[i]; + // let n1 = e.n1; + // let n2 = e.n2; + // n1.edges = n1.edges || []; + // n2.edges = n2.edges || []; + // n1.edges.push(e); + // n2.edges.push(e); + // } + // Init position + + for (var i = 0; i < nodes.length; i++) { + var n = nodes[i]; + + if (!n.p) { + n.p = create(width * (Math.random() - 0.5) + center[0], height * (Math.random() - 0.5) + center[1]); + } + + n.pp = clone$1(n.p); + n.edges = null; + } // Formula in 'Graph Drawing by Force-directed Placement' + // let k = scale * Math.sqrt(width * height / nodes.length); + // let k2 = k * k; + + + var initialFriction = opts.friction == null ? 0.6 : opts.friction; + var friction = initialFriction; + var beforeStepCallback; + var afterStepCallback; + return { + warmUp: function () { + friction = initialFriction * 0.8; + }, + setFixed: function (idx) { + nodes[idx].fixed = true; + }, + setUnfixed: function (idx) { + nodes[idx].fixed = false; + }, + + /** + * Before step hook + */ + beforeStep: function (cb) { + beforeStepCallback = cb; + }, + + /** + * After step hook + */ + afterStep: function (cb) { + afterStepCallback = cb; + }, + + /** + * Some formulas were originally copied from "d3.js" + * https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/layout/force.js + * with some modifications made for this project. + * See the license statement at the head of this file. + */ + step: function (cb) { + beforeStepCallback && beforeStepCallback(nodes, edges); + var v12 = []; + var nLen = nodes.length; + + for (var i = 0; i < edges.length; i++) { + var e = edges[i]; + + if (e.ignoreForceLayout) { + continue; + } + + var n1 = e.n1; + var n2 = e.n2; + sub(v12, n2.p, n1.p); + var d = len(v12) - e.d; + var w = n2.w / (n1.w + n2.w); + + if (isNaN(w)) { + w = 0; + } + + normalize(v12, v12); + !n1.fixed && scaleAndAdd$1(n1.p, n1.p, v12, w * d * friction); + !n2.fixed && scaleAndAdd$1(n2.p, n2.p, v12, -(1 - w) * d * friction); + } // Gravity + + + for (var i = 0; i < nLen; i++) { + var n = nodes[i]; + + if (!n.fixed) { + sub(v12, center, n.p); // let d = vec2.len(v12); + // vec2.scale(v12, v12, 1 / d); + // let gravityFactor = gravity; + + scaleAndAdd$1(n.p, n.p, v12, gravity * friction); + } + } // Repulsive + // PENDING + + + for (var i = 0; i < nLen; i++) { + var n1 = nodes[i]; + + for (var j = i + 1; j < nLen; j++) { + var n2 = nodes[j]; + sub(v12, n2.p, n1.p); + var d = len(v12); + + if (d === 0) { + // Random repulse + set(v12, Math.random() - 0.5, Math.random() - 0.5); + d = 1; + } + + var repFact = (n1.rep + n2.rep) / d / d; + !n1.fixed && scaleAndAdd$1(n1.pp, n1.pp, v12, repFact); + !n2.fixed && scaleAndAdd$1(n2.pp, n2.pp, v12, -repFact); + } + } + + var v = []; + + for (var i = 0; i < nLen; i++) { + var n = nodes[i]; + + if (!n.fixed) { + sub(v, n.p, n.pp); + scaleAndAdd$1(n.p, n.p, v, friction); + copy(n.pp, n.p); + } + } + + friction = friction * 0.992; + var finished = friction < 0.01; + afterStepCallback && afterStepCallback(nodes, edges, finished); + cb && cb(finished); + } + }; + } + + function graphForceLayout(ecModel) { + ecModel.eachSeriesByType('graph', function (graphSeries) { + var coordSys = graphSeries.coordinateSystem; + + if (coordSys && coordSys.type !== 'view') { + return; + } + + if (graphSeries.get('layout') === 'force') { + var preservedPoints_1 = graphSeries.preservedPoints || {}; + var graph_1 = graphSeries.getGraph(); + var nodeData_1 = graph_1.data; + var edgeData = graph_1.edgeData; + var forceModel = graphSeries.getModel('force'); + var initLayout = forceModel.get('initLayout'); + + if (graphSeries.preservedPoints) { + nodeData_1.each(function (idx) { + var id = nodeData_1.getId(idx); + nodeData_1.setItemLayout(idx, preservedPoints_1[id] || [NaN, NaN]); + }); + } else if (!initLayout || initLayout === 'none') { + simpleLayout(graphSeries); + } else if (initLayout === 'circular') { + circularLayout(graphSeries, 'value'); + } + + var nodeDataExtent_1 = nodeData_1.getDataExtent('value'); + var edgeDataExtent_1 = edgeData.getDataExtent('value'); // let edgeDataExtent = edgeData.getDataExtent('value'); + + var repulsion = forceModel.get('repulsion'); + var edgeLength = forceModel.get('edgeLength'); + var repulsionArr_1 = isArray(repulsion) ? repulsion : [repulsion, repulsion]; + var edgeLengthArr_1 = isArray(edgeLength) ? edgeLength : [edgeLength, edgeLength]; // Larger value has smaller length + + edgeLengthArr_1 = [edgeLengthArr_1[1], edgeLengthArr_1[0]]; + var nodes_1 = nodeData_1.mapArray('value', function (value, idx) { + var point = nodeData_1.getItemLayout(idx); + var rep = linearMap(value, nodeDataExtent_1, repulsionArr_1); + + if (isNaN(rep)) { + rep = (repulsionArr_1[0] + repulsionArr_1[1]) / 2; + } + + return { + w: rep, + rep: rep, + fixed: nodeData_1.getItemModel(idx).get('fixed'), + p: !point || isNaN(point[0]) || isNaN(point[1]) ? null : point + }; + }); + var edges = edgeData.mapArray('value', function (value, idx) { + var edge = graph_1.getEdgeByIndex(idx); + var d = linearMap(value, edgeDataExtent_1, edgeLengthArr_1); + + if (isNaN(d)) { + d = (edgeLengthArr_1[0] + edgeLengthArr_1[1]) / 2; + } + + var edgeModel = edge.getModel(); + var curveness = retrieve3(edge.getModel().get(['lineStyle', 'curveness']), -getCurvenessForEdge(edge, graphSeries, idx, true), 0); + return { + n1: nodes_1[edge.node1.dataIndex], + n2: nodes_1[edge.node2.dataIndex], + d: d, + curveness: curveness, + ignoreForceLayout: edgeModel.get('ignoreForceLayout') + }; + }); // let coordSys = graphSeries.coordinateSystem; + + var rect = coordSys.getBoundingRect(); + var forceInstance = forceLayout(nodes_1, edges, { + rect: rect, + gravity: forceModel.get('gravity'), + friction: forceModel.get('friction') + }); + forceInstance.beforeStep(function (nodes, edges) { + for (var i = 0, l = nodes.length; i < l; i++) { + if (nodes[i].fixed) { + // Write back to layout instance + copy(nodes[i].p, graph_1.getNodeByIndex(i).getLayout()); + } + } + }); + forceInstance.afterStep(function (nodes, edges, stopped) { + for (var i = 0, l = nodes.length; i < l; i++) { + if (!nodes[i].fixed) { + graph_1.getNodeByIndex(i).setLayout(nodes[i].p); + } + + preservedPoints_1[nodeData_1.getId(i)] = nodes[i].p; + } + + for (var i = 0, l = edges.length; i < l; i++) { + var e = edges[i]; + var edge = graph_1.getEdgeByIndex(i); + var p1 = e.n1.p; + var p2 = e.n2.p; + var points = edge.getLayout(); + points = points ? points.slice() : []; + points[0] = points[0] || []; + points[1] = points[1] || []; + copy(points[0], p1); + copy(points[1], p2); + + if (+e.curveness) { + points[2] = [(p1[0] + p2[0]) / 2 - (p1[1] - p2[1]) * e.curveness, (p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * e.curveness]; + } + + edge.setLayout(points); + } + }); + graphSeries.forceLayout = forceInstance; + graphSeries.preservedPoints = preservedPoints_1; // Step to get the layout + + forceInstance.step(); + } else { + // Remove prev injected forceLayout instance + graphSeries.forceLayout = null; + } + }); + } + + function getViewRect$2(seriesModel, api, aspect) { + var option = extend(seriesModel.getBoxLayoutParams(), { + aspect: aspect + }); + return getLayoutRect(option, { + width: api.getWidth(), + height: api.getHeight() + }); + } + + function createViewCoordSys(ecModel, api) { + var viewList = []; + ecModel.eachSeriesByType('graph', function (seriesModel) { + var coordSysType = seriesModel.get('coordinateSystem'); + + if (!coordSysType || coordSysType === 'view') { + var data_1 = seriesModel.getData(); + var positions = data_1.mapArray(function (idx) { + var itemModel = data_1.getItemModel(idx); + return [+itemModel.get('x'), +itemModel.get('y')]; + }); + var min = []; + var max = []; + fromPoints(positions, min, max); // If width or height is 0 + + if (max[0] - min[0] === 0) { + max[0] += 1; + min[0] -= 1; + } + + if (max[1] - min[1] === 0) { + max[1] += 1; + min[1] -= 1; + } + + var aspect = (max[0] - min[0]) / (max[1] - min[1]); // FIXME If get view rect after data processed? + + var viewRect = getViewRect$2(seriesModel, api, aspect); // Position may be NaN, use view rect instead + + if (isNaN(aspect)) { + min = [viewRect.x, viewRect.y]; + max = [viewRect.x + viewRect.width, viewRect.y + viewRect.height]; + } + + var bbWidth = max[0] - min[0]; + var bbHeight = max[1] - min[1]; + var viewWidth = viewRect.width; + var viewHeight = viewRect.height; + var viewCoordSys = seriesModel.coordinateSystem = new View(); + viewCoordSys.zoomLimit = seriesModel.get('scaleLimit'); + viewCoordSys.setBoundingRect(min[0], min[1], bbWidth, bbHeight); + viewCoordSys.setViewRect(viewRect.x, viewRect.y, viewWidth, viewHeight); // Update roam info + + viewCoordSys.setCenter(seriesModel.get('center')); + viewCoordSys.setZoom(seriesModel.get('zoom')); + viewList.push(viewCoordSys); + } + }); + return viewList; + } + + var straightLineProto = Line.prototype; + var bezierCurveProto = BezierCurve.prototype; + + var StraightLineShape = + /** @class */ + function () { + function StraightLineShape() { + // Start point + this.x1 = 0; + this.y1 = 0; // End point + + this.x2 = 0; + this.y2 = 0; + this.percent = 1; + } + + return StraightLineShape; + }(); + + var CurveShape = + /** @class */ + function (_super) { + __extends(CurveShape, _super); + + function CurveShape() { + return _super !== null && _super.apply(this, arguments) || this; + } + + return CurveShape; + }(StraightLineShape); + + function isStraightLine(shape) { + return isNaN(+shape.cpx1) || isNaN(+shape.cpy1); + } + + var ECLinePath = + /** @class */ + function (_super) { + __extends(ECLinePath, _super); + + function ECLinePath(opts) { + var _this = _super.call(this, opts) || this; + + _this.type = 'ec-line'; + return _this; + } + + ECLinePath.prototype.getDefaultStyle = function () { + return { + stroke: '#000', + fill: null + }; + }; + + ECLinePath.prototype.getDefaultShape = function () { + return new StraightLineShape(); + }; + + ECLinePath.prototype.buildPath = function (ctx, shape) { + if (isStraightLine(shape)) { + straightLineProto.buildPath.call(this, ctx, shape); + } else { + bezierCurveProto.buildPath.call(this, ctx, shape); + } + }; + + ECLinePath.prototype.pointAt = function (t) { + if (isStraightLine(this.shape)) { + return straightLineProto.pointAt.call(this, t); + } else { + return bezierCurveProto.pointAt.call(this, t); + } + }; + + ECLinePath.prototype.tangentAt = function (t) { + var shape = this.shape; + var p = isStraightLine(shape) ? [shape.x2 - shape.x1, shape.y2 - shape.y1] : bezierCurveProto.tangentAt.call(this, t); + return normalize(p, p); + }; + + return ECLinePath; + }(Path); + + var SYMBOL_CATEGORIES = ['fromSymbol', 'toSymbol']; + + function makeSymbolTypeKey(symbolCategory) { + return '_' + symbolCategory + 'Type'; + } + /** + * @inner + */ + + + function createSymbol$1(name, lineData, idx) { + var symbolType = lineData.getItemVisual(idx, name); + + if (!symbolType || symbolType === 'none') { + return; + } + + var symbolSize = lineData.getItemVisual(idx, name + 'Size'); + var symbolRotate = lineData.getItemVisual(idx, name + 'Rotate'); + var symbolOffset = lineData.getItemVisual(idx, name + 'Offset'); + var symbolKeepAspect = lineData.getItemVisual(idx, name + 'KeepAspect'); + var symbolSizeArr = normalizeSymbolSize(symbolSize); + var symbolOffsetArr = normalizeSymbolOffset(symbolOffset || 0, symbolSizeArr); + var symbolPath = createSymbol(symbolType, -symbolSizeArr[0] / 2 + symbolOffsetArr[0], -symbolSizeArr[1] / 2 + symbolOffsetArr[1], symbolSizeArr[0], symbolSizeArr[1], null, symbolKeepAspect); + symbolPath.__specifiedRotation = symbolRotate == null || isNaN(symbolRotate) ? void 0 : +symbolRotate * Math.PI / 180 || 0; + symbolPath.name = name; + return symbolPath; + } + + function createLine(points) { + var line = new ECLinePath({ + name: 'line', + subPixelOptimize: true + }); + setLinePoints(line.shape, points); + return line; + } + + function setLinePoints(targetShape, points) { + targetShape.x1 = points[0][0]; + targetShape.y1 = points[0][1]; + targetShape.x2 = points[1][0]; + targetShape.y2 = points[1][1]; + targetShape.percent = 1; + var cp1 = points[2]; + + if (cp1) { + targetShape.cpx1 = cp1[0]; + targetShape.cpy1 = cp1[1]; + } else { + targetShape.cpx1 = NaN; + targetShape.cpy1 = NaN; + } + } + + var Line$1 = + /** @class */ + function (_super) { + __extends(Line, _super); + + function Line(lineData, idx, seriesScope) { + var _this = _super.call(this) || this; + + _this._createLine(lineData, idx, seriesScope); + + return _this; + } + + Line.prototype._createLine = function (lineData, idx, seriesScope) { + var seriesModel = lineData.hostModel; + var linePoints = lineData.getItemLayout(idx); + var line = createLine(linePoints); + line.shape.percent = 0; + initProps(line, { + shape: { + percent: 1 + } + }, seriesModel, idx); + this.add(line); + each(SYMBOL_CATEGORIES, function (symbolCategory) { + var symbol = createSymbol$1(symbolCategory, lineData, idx); // symbols must added after line to make sure + // it will be updated after line#update. + // Or symbol position and rotation update in line#beforeUpdate will be one frame slow + + this.add(symbol); + this[makeSymbolTypeKey(symbolCategory)] = lineData.getItemVisual(idx, symbolCategory); + }, this); + + this._updateCommonStl(lineData, idx, seriesScope); + }; // TODO More strict on the List type in parameters? + + + Line.prototype.updateData = function (lineData, idx, seriesScope) { + var seriesModel = lineData.hostModel; + var line = this.childOfName('line'); + var linePoints = lineData.getItemLayout(idx); + var target = { + shape: {} + }; + setLinePoints(target.shape, linePoints); + updateProps(line, target, seriesModel, idx); + each(SYMBOL_CATEGORIES, function (symbolCategory) { + var symbolType = lineData.getItemVisual(idx, symbolCategory); + var key = makeSymbolTypeKey(symbolCategory); // Symbol changed + + if (this[key] !== symbolType) { + this.remove(this.childOfName(symbolCategory)); + var symbol = createSymbol$1(symbolCategory, lineData, idx); + this.add(symbol); + } + + this[key] = symbolType; + }, this); + + this._updateCommonStl(lineData, idx, seriesScope); + }; + + Line.prototype.getLinePath = function () { + return this.childAt(0); + }; + + Line.prototype._updateCommonStl = function (lineData, idx, seriesScope) { + var seriesModel = lineData.hostModel; + var line = this.childOfName('line'); + var emphasisLineStyle = seriesScope && seriesScope.emphasisLineStyle; + var blurLineStyle = seriesScope && seriesScope.blurLineStyle; + var selectLineStyle = seriesScope && seriesScope.selectLineStyle; + var labelStatesModels = seriesScope && seriesScope.labelStatesModels; + var emphasisDisabled = seriesScope && seriesScope.emphasisDisabled; + var focus = seriesScope && seriesScope.focus; + var blurScope = seriesScope && seriesScope.blurScope; // Optimization for large dataset + + if (!seriesScope || lineData.hasItemOption) { + var itemModel = lineData.getItemModel(idx); + var emphasisModel = itemModel.getModel('emphasis'); + emphasisLineStyle = emphasisModel.getModel('lineStyle').getLineStyle(); + blurLineStyle = itemModel.getModel(['blur', 'lineStyle']).getLineStyle(); + selectLineStyle = itemModel.getModel(['select', 'lineStyle']).getLineStyle(); + emphasisDisabled = emphasisModel.get('disabled'); + focus = emphasisModel.get('focus'); + blurScope = emphasisModel.get('blurScope'); + labelStatesModels = getLabelStatesModels(itemModel); + } + + var lineStyle = lineData.getItemVisual(idx, 'style'); + var visualColor = lineStyle.stroke; + line.useStyle(lineStyle); + line.style.fill = null; + line.style.strokeNoScale = true; + line.ensureState('emphasis').style = emphasisLineStyle; + line.ensureState('blur').style = blurLineStyle; + line.ensureState('select').style = selectLineStyle; // Update symbol + + each(SYMBOL_CATEGORIES, function (symbolCategory) { + var symbol = this.childOfName(symbolCategory); + + if (symbol) { + // Share opacity and color with line. + symbol.setColor(visualColor); + symbol.style.opacity = lineStyle.opacity; + + for (var i = 0; i < SPECIAL_STATES.length; i++) { + var stateName = SPECIAL_STATES[i]; + var lineState = line.getState(stateName); + + if (lineState) { + var lineStateStyle = lineState.style || {}; + var state = symbol.ensureState(stateName); + var stateStyle = state.style || (state.style = {}); + + if (lineStateStyle.stroke != null) { + stateStyle[symbol.__isEmptyBrush ? 'stroke' : 'fill'] = lineStateStyle.stroke; + } + + if (lineStateStyle.opacity != null) { + stateStyle.opacity = lineStateStyle.opacity; + } + } + } + + symbol.markRedraw(); + } + }, this); + var rawVal = seriesModel.getRawValue(idx); + setLabelStyle(this, labelStatesModels, { + labelDataIndex: idx, + labelFetcher: { + getFormattedLabel: function (dataIndex, stateName) { + return seriesModel.getFormattedLabel(dataIndex, stateName, lineData.dataType); + } + }, + inheritColor: visualColor || '#000', + defaultOpacity: lineStyle.opacity, + defaultText: (rawVal == null ? lineData.getName(idx) : isFinite(rawVal) ? round(rawVal) : rawVal) + '' + }); + var label = this.getTextContent(); // Always set `textStyle` even if `normalStyle.text` is null, because default + // values have to be set on `normalStyle`. + + if (label) { + var labelNormalModel = labelStatesModels.normal; + label.__align = label.style.align; + label.__verticalAlign = label.style.verticalAlign; // 'start', 'middle', 'end' + + label.__position = labelNormalModel.get('position') || 'middle'; + var distance = labelNormalModel.get('distance'); + + if (!isArray(distance)) { + distance = [distance, distance]; + } + + label.__labelDistance = distance; + } + + this.setTextConfig({ + position: null, + local: true, + inside: false // Can't be inside for stroke element. + + }); + toggleHoverEmphasis(this, focus, blurScope, emphasisDisabled); + }; + + Line.prototype.highlight = function () { + enterEmphasis(this); + }; + + Line.prototype.downplay = function () { + leaveEmphasis(this); + }; + + Line.prototype.updateLayout = function (lineData, idx) { + this.setLinePoints(lineData.getItemLayout(idx)); + }; + + Line.prototype.setLinePoints = function (points) { + var linePath = this.childOfName('line'); + setLinePoints(linePath.shape, points); + linePath.dirty(); + }; + + Line.prototype.beforeUpdate = function () { + var lineGroup = this; + var symbolFrom = lineGroup.childOfName('fromSymbol'); + var symbolTo = lineGroup.childOfName('toSymbol'); + var label = lineGroup.getTextContent(); // Quick reject + + if (!symbolFrom && !symbolTo && (!label || label.ignore)) { + return; + } + + var invScale = 1; + var parentNode = this.parent; + + while (parentNode) { + if (parentNode.scaleX) { + invScale /= parentNode.scaleX; + } + + parentNode = parentNode.parent; + } + + var line = lineGroup.childOfName('line'); // If line not changed + // FIXME Parent scale changed + + if (!this.__dirty && !line.__dirty) { + return; + } + + var percent = line.shape.percent; + var fromPos = line.pointAt(0); + var toPos = line.pointAt(percent); + var d = sub([], toPos, fromPos); + normalize(d, d); + + function setSymbolRotation(symbol, percent) { + // Fix #12388 + // when symbol is set to be 'arrow' in markLine, + // symbolRotate value will be ignored, and compulsively use tangent angle. + // rotate by default if symbol rotation is not specified + var specifiedRotation = symbol.__specifiedRotation; + + if (specifiedRotation == null) { + var tangent = line.tangentAt(percent); + symbol.attr('rotation', (percent === 1 ? -1 : 1) * Math.PI / 2 - Math.atan2(tangent[1], tangent[0])); + } else { + symbol.attr('rotation', specifiedRotation); + } + } + + if (symbolFrom) { + symbolFrom.setPosition(fromPos); + setSymbolRotation(symbolFrom, 0); + symbolFrom.scaleX = symbolFrom.scaleY = invScale * percent; + symbolFrom.markRedraw(); + } + + if (symbolTo) { + symbolTo.setPosition(toPos); + setSymbolRotation(symbolTo, 1); + symbolTo.scaleX = symbolTo.scaleY = invScale * percent; + symbolTo.markRedraw(); + } + + if (label && !label.ignore) { + label.x = label.y = 0; + label.originX = label.originY = 0; + var textAlign = void 0; + var textVerticalAlign = void 0; + var distance = label.__labelDistance; + var distanceX = distance[0] * invScale; + var distanceY = distance[1] * invScale; + var halfPercent = percent / 2; + var tangent = line.tangentAt(halfPercent); + var n = [tangent[1], -tangent[0]]; + var cp = line.pointAt(halfPercent); + + if (n[1] > 0) { + n[0] = -n[0]; + n[1] = -n[1]; + } + + var dir = tangent[0] < 0 ? -1 : 1; + + if (label.__position !== 'start' && label.__position !== 'end') { + var rotation = -Math.atan2(tangent[1], tangent[0]); + + if (toPos[0] < fromPos[0]) { + rotation = Math.PI + rotation; + } + + label.rotation = rotation; + } + + var dy = void 0; + + switch (label.__position) { + case 'insideStartTop': + case 'insideMiddleTop': + case 'insideEndTop': + case 'middle': + dy = -distanceY; + textVerticalAlign = 'bottom'; + break; + + case 'insideStartBottom': + case 'insideMiddleBottom': + case 'insideEndBottom': + dy = distanceY; + textVerticalAlign = 'top'; + break; + + default: + dy = 0; + textVerticalAlign = 'middle'; + } + + switch (label.__position) { + case 'end': + label.x = d[0] * distanceX + toPos[0]; + label.y = d[1] * distanceY + toPos[1]; + textAlign = d[0] > 0.8 ? 'left' : d[0] < -0.8 ? 'right' : 'center'; + textVerticalAlign = d[1] > 0.8 ? 'top' : d[1] < -0.8 ? 'bottom' : 'middle'; + break; + + case 'start': + label.x = -d[0] * distanceX + fromPos[0]; + label.y = -d[1] * distanceY + fromPos[1]; + textAlign = d[0] > 0.8 ? 'right' : d[0] < -0.8 ? 'left' : 'center'; + textVerticalAlign = d[1] > 0.8 ? 'bottom' : d[1] < -0.8 ? 'top' : 'middle'; + break; + + case 'insideStartTop': + case 'insideStart': + case 'insideStartBottom': + label.x = distanceX * dir + fromPos[0]; + label.y = fromPos[1] + dy; + textAlign = tangent[0] < 0 ? 'right' : 'left'; + label.originX = -distanceX * dir; + label.originY = -dy; + break; + + case 'insideMiddleTop': + case 'insideMiddle': + case 'insideMiddleBottom': + case 'middle': + label.x = cp[0]; + label.y = cp[1] + dy; + textAlign = 'center'; + label.originY = -dy; + break; + + case 'insideEndTop': + case 'insideEnd': + case 'insideEndBottom': + label.x = -distanceX * dir + toPos[0]; + label.y = toPos[1] + dy; + textAlign = tangent[0] >= 0 ? 'right' : 'left'; + label.originX = distanceX * dir; + label.originY = -dy; + break; + } + + label.scaleX = label.scaleY = invScale; + label.setStyle({ + // Use the user specified text align and baseline first + verticalAlign: label.__verticalAlign || textVerticalAlign, + align: label.__align || textAlign + }); + } + }; + + return Line; + }(Group); + + var LineDraw = + /** @class */ + function () { + function LineDraw(LineCtor) { + this.group = new Group(); + this._LineCtor = LineCtor || Line$1; + } + + LineDraw.prototype.updateData = function (lineData) { + var _this = this; // Remove progressive els. + + + this._progressiveEls = null; + var lineDraw = this; + var group = lineDraw.group; + var oldLineData = lineDraw._lineData; + lineDraw._lineData = lineData; // There is no oldLineData only when first rendering or switching from + // stream mode to normal mode, where previous elements should be removed. + + if (!oldLineData) { + group.removeAll(); + } + + var seriesScope = makeSeriesScope$1(lineData); + lineData.diff(oldLineData).add(function (idx) { + _this._doAdd(lineData, idx, seriesScope); + }).update(function (newIdx, oldIdx) { + _this._doUpdate(oldLineData, lineData, oldIdx, newIdx, seriesScope); + }).remove(function (idx) { + group.remove(oldLineData.getItemGraphicEl(idx)); + }).execute(); + }; + + LineDraw.prototype.updateLayout = function () { + var lineData = this._lineData; // Do not support update layout in incremental mode. + + if (!lineData) { + return; + } + + lineData.eachItemGraphicEl(function (el, idx) { + el.updateLayout(lineData, idx); + }, this); + }; + + LineDraw.prototype.incrementalPrepareUpdate = function (lineData) { + this._seriesScope = makeSeriesScope$1(lineData); + this._lineData = null; + this.group.removeAll(); + }; + + LineDraw.prototype.incrementalUpdate = function (taskParams, lineData) { + this._progressiveEls = []; + + function updateIncrementalAndHover(el) { + if (!el.isGroup && !isEffectObject(el)) { + el.incremental = true; + el.ensureState('emphasis').hoverLayer = true; + } + } + + for (var idx = taskParams.start; idx < taskParams.end; idx++) { + var itemLayout = lineData.getItemLayout(idx); + + if (lineNeedsDraw(itemLayout)) { + var el = new this._LineCtor(lineData, idx, this._seriesScope); + el.traverse(updateIncrementalAndHover); + this.group.add(el); + lineData.setItemGraphicEl(idx, el); + + this._progressiveEls.push(el); + } + } + }; + + LineDraw.prototype.remove = function () { + this.group.removeAll(); + }; + + LineDraw.prototype.eachRendered = function (cb) { + traverseElements(this._progressiveEls || this.group, cb); + }; + + LineDraw.prototype._doAdd = function (lineData, idx, seriesScope) { + var itemLayout = lineData.getItemLayout(idx); + + if (!lineNeedsDraw(itemLayout)) { + return; + } + + var el = new this._LineCtor(lineData, idx, seriesScope); + lineData.setItemGraphicEl(idx, el); + this.group.add(el); + }; + + LineDraw.prototype._doUpdate = function (oldLineData, newLineData, oldIdx, newIdx, seriesScope) { + var itemEl = oldLineData.getItemGraphicEl(oldIdx); + + if (!lineNeedsDraw(newLineData.getItemLayout(newIdx))) { + this.group.remove(itemEl); + return; + } + + if (!itemEl) { + itemEl = new this._LineCtor(newLineData, newIdx, seriesScope); + } else { + itemEl.updateData(newLineData, newIdx, seriesScope); + } + + newLineData.setItemGraphicEl(newIdx, itemEl); + this.group.add(itemEl); + }; + + return LineDraw; + }(); + + function isEffectObject(el) { + return el.animators && el.animators.length > 0; + } + + function makeSeriesScope$1(lineData) { + var hostModel = lineData.hostModel; + var emphasisModel = hostModel.getModel('emphasis'); + return { + lineStyle: hostModel.getModel('lineStyle').getLineStyle(), + emphasisLineStyle: emphasisModel.getModel(['lineStyle']).getLineStyle(), + blurLineStyle: hostModel.getModel(['blur', 'lineStyle']).getLineStyle(), + selectLineStyle: hostModel.getModel(['select', 'lineStyle']).getLineStyle(), + emphasisDisabled: emphasisModel.get('disabled'), + blurScope: emphasisModel.get('blurScope'), + focus: emphasisModel.get('focus'), + labelStatesModels: getLabelStatesModels(hostModel) + }; + } + + function isPointNaN(pt) { + return isNaN(pt[0]) || isNaN(pt[1]); + } + + function lineNeedsDraw(pts) { + return pts && !isPointNaN(pts[0]) && !isPointNaN(pts[1]); + } + + var v1 = []; + var v2 = []; + var v3 = []; + var quadraticAt$1 = quadraticAt; + var v2DistSquare = distSquare; + var mathAbs$2 = Math.abs; + + function intersectCurveCircle(curvePoints, center, radius) { + var p0 = curvePoints[0]; + var p1 = curvePoints[1]; + var p2 = curvePoints[2]; + var d = Infinity; + var t; + var radiusSquare = radius * radius; + var interval = 0.1; + + for (var _t = 0.1; _t <= 0.9; _t += 0.1) { + v1[0] = quadraticAt$1(p0[0], p1[0], p2[0], _t); + v1[1] = quadraticAt$1(p0[1], p1[1], p2[1], _t); + var diff = mathAbs$2(v2DistSquare(v1, center) - radiusSquare); + + if (diff < d) { + d = diff; + t = _t; + } + } // Assume the segment is monotone,Find root through Bisection method + // At most 32 iteration + + + for (var i = 0; i < 32; i++) { + // let prev = t - interval; + var next = t + interval; // v1[0] = quadraticAt(p0[0], p1[0], p2[0], prev); + // v1[1] = quadraticAt(p0[1], p1[1], p2[1], prev); + + v2[0] = quadraticAt$1(p0[0], p1[0], p2[0], t); + v2[1] = quadraticAt$1(p0[1], p1[1], p2[1], t); + v3[0] = quadraticAt$1(p0[0], p1[0], p2[0], next); + v3[1] = quadraticAt$1(p0[1], p1[1], p2[1], next); + var diff = v2DistSquare(v2, center) - radiusSquare; + + if (mathAbs$2(diff) < 1e-2) { + break; + } // let prevDiff = v2DistSquare(v1, center) - radiusSquare; + + + var nextDiff = v2DistSquare(v3, center) - radiusSquare; + interval /= 2; + + if (diff < 0) { + if (nextDiff >= 0) { + t = t + interval; + } else { + t = t - interval; + } + } else { + if (nextDiff >= 0) { + t = t - interval; + } else { + t = t + interval; + } + } + } + + return t; + } // Adjust edge to avoid + + + function adjustEdge(graph, scale) { + var tmp0 = []; + var quadraticSubdivide$1 = quadraticSubdivide; + var pts = [[], [], []]; + var pts2 = [[], []]; + var v = []; + scale /= 2; + graph.eachEdge(function (edge, idx) { + var linePoints = edge.getLayout(); + var fromSymbol = edge.getVisual('fromSymbol'); + var toSymbol = edge.getVisual('toSymbol'); + + if (!linePoints.__original) { + linePoints.__original = [clone$1(linePoints[0]), clone$1(linePoints[1])]; + + if (linePoints[2]) { + linePoints.__original.push(clone$1(linePoints[2])); + } + } + + var originalPoints = linePoints.__original; // Quadratic curve + + if (linePoints[2] != null) { + copy(pts[0], originalPoints[0]); + copy(pts[1], originalPoints[2]); + copy(pts[2], originalPoints[1]); + + if (fromSymbol && fromSymbol !== 'none') { + var symbolSize = getSymbolSize(edge.node1); + var t = intersectCurveCircle(pts, originalPoints[0], symbolSize * scale); // Subdivide and get the second + + quadraticSubdivide$1(pts[0][0], pts[1][0], pts[2][0], t, tmp0); + pts[0][0] = tmp0[3]; + pts[1][0] = tmp0[4]; + quadraticSubdivide$1(pts[0][1], pts[1][1], pts[2][1], t, tmp0); + pts[0][1] = tmp0[3]; + pts[1][1] = tmp0[4]; + } + + if (toSymbol && toSymbol !== 'none') { + var symbolSize = getSymbolSize(edge.node2); + var t = intersectCurveCircle(pts, originalPoints[1], symbolSize * scale); // Subdivide and get the first + + quadraticSubdivide$1(pts[0][0], pts[1][0], pts[2][0], t, tmp0); + pts[1][0] = tmp0[1]; + pts[2][0] = tmp0[2]; + quadraticSubdivide$1(pts[0][1], pts[1][1], pts[2][1], t, tmp0); + pts[1][1] = tmp0[1]; + pts[2][1] = tmp0[2]; + } // Copy back to layout + + + copy(linePoints[0], pts[0]); + copy(linePoints[1], pts[2]); + copy(linePoints[2], pts[1]); + } // Line + else { + copy(pts2[0], originalPoints[0]); + copy(pts2[1], originalPoints[1]); + sub(v, pts2[1], pts2[0]); + normalize(v, v); + + if (fromSymbol && fromSymbol !== 'none') { + var symbolSize = getSymbolSize(edge.node1); + scaleAndAdd(pts2[0], pts2[0], v, symbolSize * scale); + } + + if (toSymbol && toSymbol !== 'none') { + var symbolSize = getSymbolSize(edge.node2); + scaleAndAdd(pts2[1], pts2[1], v, -symbolSize * scale); + } + + copy(linePoints[0], pts2[0]); + copy(linePoints[1], pts2[1]); + } + }); + } + + function isViewCoordSys(coordSys) { + return coordSys.type === 'view'; + } + + var GraphView = + /** @class */ + function (_super) { + __extends(GraphView, _super); + + function GraphView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = GraphView.type; + return _this; + } + + GraphView.prototype.init = function (ecModel, api) { + var symbolDraw = new SymbolDraw(); + var lineDraw = new LineDraw(); + var group = this.group; + this._controller = new RoamController(api.getZr()); + this._controllerHost = { + target: group + }; + group.add(symbolDraw.group); + group.add(lineDraw.group); + this._symbolDraw = symbolDraw; + this._lineDraw = lineDraw; + this._firstRender = true; + }; + + GraphView.prototype.render = function (seriesModel, ecModel, api) { + var _this = this; + + var coordSys = seriesModel.coordinateSystem; + this._model = seriesModel; + var symbolDraw = this._symbolDraw; + var lineDraw = this._lineDraw; + var group = this.group; + + if (isViewCoordSys(coordSys)) { + var groupNewProp = { + x: coordSys.x, + y: coordSys.y, + scaleX: coordSys.scaleX, + scaleY: coordSys.scaleY + }; + + if (this._firstRender) { + group.attr(groupNewProp); + } else { + updateProps(group, groupNewProp, seriesModel); + } + } // Fix edge contact point with node + + + adjustEdge(seriesModel.getGraph(), getNodeGlobalScale(seriesModel)); + var data = seriesModel.getData(); + symbolDraw.updateData(data); + var edgeData = seriesModel.getEdgeData(); // TODO: TYPE + + lineDraw.updateData(edgeData); + + this._updateNodeAndLinkScale(); + + this._updateController(seriesModel, ecModel, api); + + clearTimeout(this._layoutTimeout); + var forceLayout = seriesModel.forceLayout; + var layoutAnimation = seriesModel.get(['force', 'layoutAnimation']); + + if (forceLayout) { + this._startForceLayoutIteration(forceLayout, layoutAnimation); + } + + data.graph.eachNode(function (node) { + var idx = node.dataIndex; + var el = node.getGraphicEl(); + var itemModel = node.getModel(); + + if (!el) { + return; + } // Update draggable + + + el.off('drag').off('dragend'); + var draggable = itemModel.get('draggable'); + + if (draggable) { + el.on('drag', function () { + if (forceLayout) { + forceLayout.warmUp(); + !_this._layouting && _this._startForceLayoutIteration(forceLayout, layoutAnimation); + forceLayout.setFixed(idx); // Write position back to layout + + data.setItemLayout(idx, [el.x, el.y]); + } + }).on('dragend', function () { + if (forceLayout) { + forceLayout.setUnfixed(idx); + } + }); + } + + el.setDraggable(draggable && !!forceLayout); + var focus = itemModel.get(['emphasis', 'focus']); + + if (focus === 'adjacency') { + getECData(el).focus = node.getAdjacentDataIndices(); + } + }); + data.graph.eachEdge(function (edge) { + var el = edge.getGraphicEl(); + var focus = edge.getModel().get(['emphasis', 'focus']); + + if (!el) { + return; + } + + if (focus === 'adjacency') { + getECData(el).focus = { + edge: [edge.dataIndex], + node: [edge.node1.dataIndex, edge.node2.dataIndex] + }; + } + }); + var circularRotateLabel = seriesModel.get('layout') === 'circular' && seriesModel.get(['circular', 'rotateLabel']); + var cx = data.getLayout('cx'); + var cy = data.getLayout('cy'); + data.eachItemGraphicEl(function (el, idx) { + var itemModel = data.getItemModel(idx); + var labelRotate = itemModel.get(['label', 'rotate']) || 0; + var symbolPath = el.getSymbolPath(); + + if (circularRotateLabel) { + var pos = data.getItemLayout(idx); + var rad = Math.atan2(pos[1] - cy, pos[0] - cx); + + if (rad < 0) { + rad = Math.PI * 2 + rad; + } + + var isLeft = pos[0] < cx; + + if (isLeft) { + rad = rad - Math.PI; + } + + var textPosition = isLeft ? 'left' : 'right'; + symbolPath.setTextConfig({ + rotation: -rad, + position: textPosition, + origin: 'center' + }); + var emphasisState = symbolPath.ensureState('emphasis'); + extend(emphasisState.textConfig || (emphasisState.textConfig = {}), { + position: textPosition + }); + } else { + symbolPath.setTextConfig({ + rotation: labelRotate *= Math.PI / 180 + }); + } + }); + this._firstRender = false; + }; + + GraphView.prototype.dispose = function () { + this._controller && this._controller.dispose(); + this._controllerHost = null; + }; + + GraphView.prototype._startForceLayoutIteration = function (forceLayout, layoutAnimation) { + var self = this; + + (function step() { + forceLayout.step(function (stopped) { + self.updateLayout(self._model); + (self._layouting = !stopped) && (layoutAnimation ? self._layoutTimeout = setTimeout(step, 16) : step()); + }); + })(); + }; + + GraphView.prototype._updateController = function (seriesModel, ecModel, api) { + var _this = this; + + var controller = this._controller; + var controllerHost = this._controllerHost; + var group = this.group; + controller.setPointerChecker(function (e, x, y) { + var rect = group.getBoundingRect(); + rect.applyTransform(group.transform); + return rect.contain(x, y) && !onIrrelevantElement(e, api, seriesModel); + }); + + if (!isViewCoordSys(seriesModel.coordinateSystem)) { + controller.disable(); + return; + } + + controller.enable(seriesModel.get('roam')); + controllerHost.zoomLimit = seriesModel.get('scaleLimit'); + controllerHost.zoom = seriesModel.coordinateSystem.getZoom(); + controller.off('pan').off('zoom').on('pan', function (e) { + updateViewOnPan(controllerHost, e.dx, e.dy); + api.dispatchAction({ + seriesId: seriesModel.id, + type: 'graphRoam', + dx: e.dx, + dy: e.dy + }); + }).on('zoom', function (e) { + updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY); + api.dispatchAction({ + seriesId: seriesModel.id, + type: 'graphRoam', + zoom: e.scale, + originX: e.originX, + originY: e.originY + }); + + _this._updateNodeAndLinkScale(); + + adjustEdge(seriesModel.getGraph(), getNodeGlobalScale(seriesModel)); + + _this._lineDraw.updateLayout(); // Only update label layout on zoom + + + api.updateLabelLayout(); + }); + }; + + GraphView.prototype._updateNodeAndLinkScale = function () { + var seriesModel = this._model; + var data = seriesModel.getData(); + var nodeScale = getNodeGlobalScale(seriesModel); + data.eachItemGraphicEl(function (el, idx) { + el && el.setSymbolScale(nodeScale); + }); + }; + + GraphView.prototype.updateLayout = function (seriesModel) { + adjustEdge(seriesModel.getGraph(), getNodeGlobalScale(seriesModel)); + + this._symbolDraw.updateLayout(); + + this._lineDraw.updateLayout(); + }; + + GraphView.prototype.remove = function (ecModel, api) { + this._symbolDraw && this._symbolDraw.remove(); + this._lineDraw && this._lineDraw.remove(); + }; + + GraphView.type = 'graph'; + return GraphView; + }(ChartView); + + function generateNodeKey(id) { + return '_EC_' + id; + } + + var Graph = + /** @class */ + function () { + function Graph(directed) { + this.type = 'graph'; + this.nodes = []; + this.edges = []; + this._nodesMap = {}; + /** + * @type {Object.} + * @private + */ + + this._edgesMap = {}; + this._directed = directed || false; + } + /** + * If is directed graph + */ + + + Graph.prototype.isDirected = function () { + return this._directed; + }; + /** + * Add a new node + */ + + Graph.prototype.addNode = function (id, dataIndex) { + id = id == null ? '' + dataIndex : '' + id; + var nodesMap = this._nodesMap; + + if (nodesMap[generateNodeKey(id)]) { + if ("development" !== 'production') { + console.error('Graph nodes have duplicate name or id'); + } + + return; + } + + var node = new GraphNode(id, dataIndex); + node.hostGraph = this; + this.nodes.push(node); + nodesMap[generateNodeKey(id)] = node; + return node; + }; + /** + * Get node by data index + */ + + Graph.prototype.getNodeByIndex = function (dataIndex) { + var rawIdx = this.data.getRawIndex(dataIndex); + return this.nodes[rawIdx]; + }; + /** + * Get node by id + */ + + Graph.prototype.getNodeById = function (id) { + return this._nodesMap[generateNodeKey(id)]; + }; + /** + * Add a new edge + */ + + Graph.prototype.addEdge = function (n1, n2, dataIndex) { + var nodesMap = this._nodesMap; + var edgesMap = this._edgesMap; // PNEDING + + if (isNumber(n1)) { + n1 = this.nodes[n1]; + } + + if (isNumber(n2)) { + n2 = this.nodes[n2]; + } + + if (!(n1 instanceof GraphNode)) { + n1 = nodesMap[generateNodeKey(n1)]; + } + + if (!(n2 instanceof GraphNode)) { + n2 = nodesMap[generateNodeKey(n2)]; + } + + if (!n1 || !n2) { + return; + } + + var key = n1.id + '-' + n2.id; + var edge = new GraphEdge(n1, n2, dataIndex); + edge.hostGraph = this; + + if (this._directed) { + n1.outEdges.push(edge); + n2.inEdges.push(edge); + } + + n1.edges.push(edge); + + if (n1 !== n2) { + n2.edges.push(edge); + } + + this.edges.push(edge); + edgesMap[key] = edge; + return edge; + }; + /** + * Get edge by data index + */ + + Graph.prototype.getEdgeByIndex = function (dataIndex) { + var rawIdx = this.edgeData.getRawIndex(dataIndex); + return this.edges[rawIdx]; + }; + /** + * Get edge by two linked nodes + */ + + Graph.prototype.getEdge = function (n1, n2) { + if (n1 instanceof GraphNode) { + n1 = n1.id; + } + + if (n2 instanceof GraphNode) { + n2 = n2.id; + } + + var edgesMap = this._edgesMap; + + if (this._directed) { + return edgesMap[n1 + '-' + n2]; + } else { + return edgesMap[n1 + '-' + n2] || edgesMap[n2 + '-' + n1]; + } + }; + /** + * Iterate all nodes + */ + + Graph.prototype.eachNode = function (cb, context) { + var nodes = this.nodes; + var len = nodes.length; + + for (var i = 0; i < len; i++) { + if (nodes[i].dataIndex >= 0) { + cb.call(context, nodes[i], i); + } + } + }; + /** + * Iterate all edges + */ + + Graph.prototype.eachEdge = function (cb, context) { + var edges = this.edges; + var len = edges.length; + + for (var i = 0; i < len; i++) { + if (edges[i].dataIndex >= 0 && edges[i].node1.dataIndex >= 0 && edges[i].node2.dataIndex >= 0) { + cb.call(context, edges[i], i); + } + } + }; + /** + * Breadth first traverse + * Return true to stop traversing + */ + + Graph.prototype.breadthFirstTraverse = function (cb, startNode, direction, context) { + if (!(startNode instanceof GraphNode)) { + startNode = this._nodesMap[generateNodeKey(startNode)]; + } + + if (!startNode) { + return; + } + + var edgeType = direction === 'out' ? 'outEdges' : direction === 'in' ? 'inEdges' : 'edges'; + + for (var i = 0; i < this.nodes.length; i++) { + this.nodes[i].__visited = false; + } + + if (cb.call(context, startNode, null)) { + return; + } + + var queue = [startNode]; + + while (queue.length) { + var currentNode = queue.shift(); + var edges = currentNode[edgeType]; + + for (var i = 0; i < edges.length; i++) { + var e = edges[i]; + var otherNode = e.node1 === currentNode ? e.node2 : e.node1; + + if (!otherNode.__visited) { + if (cb.call(context, otherNode, currentNode)) { + // Stop traversing + return; + } + + queue.push(otherNode); + otherNode.__visited = true; + } + } + } + }; + // depthFirstTraverse( + // cb, startNode, direction, context + // ) { + // }; + // Filter update + + Graph.prototype.update = function () { + var data = this.data; + var edgeData = this.edgeData; + var nodes = this.nodes; + var edges = this.edges; + + for (var i = 0, len = nodes.length; i < len; i++) { + nodes[i].dataIndex = -1; + } + + for (var i = 0, len = data.count(); i < len; i++) { + nodes[data.getRawIndex(i)].dataIndex = i; + } + + edgeData.filterSelf(function (idx) { + var edge = edges[edgeData.getRawIndex(idx)]; + return edge.node1.dataIndex >= 0 && edge.node2.dataIndex >= 0; + }); // Update edge + + for (var i = 0, len = edges.length; i < len; i++) { + edges[i].dataIndex = -1; + } + + for (var i = 0, len = edgeData.count(); i < len; i++) { + edges[edgeData.getRawIndex(i)].dataIndex = i; + } + }; + /** + * @return {module:echarts/data/Graph} + */ + + Graph.prototype.clone = function () { + var graph = new Graph(this._directed); + var nodes = this.nodes; + var edges = this.edges; + + for (var i = 0; i < nodes.length; i++) { + graph.addNode(nodes[i].id, nodes[i].dataIndex); + } + + for (var i = 0; i < edges.length; i++) { + var e = edges[i]; + graph.addEdge(e.node1.id, e.node2.id, e.dataIndex); + } + + return graph; + }; + return Graph; + }(); + + var GraphNode = + /** @class */ + function () { + function GraphNode(id, dataIndex) { + this.inEdges = []; + this.outEdges = []; + this.edges = []; + this.dataIndex = -1; + this.id = id == null ? '' : id; + this.dataIndex = dataIndex == null ? -1 : dataIndex; + } + /** + * @return {number} + */ + + + GraphNode.prototype.degree = function () { + return this.edges.length; + }; + /** + * @return {number} + */ + + + GraphNode.prototype.inDegree = function () { + return this.inEdges.length; + }; + /** + * @return {number} + */ + + + GraphNode.prototype.outDegree = function () { + return this.outEdges.length; + }; + + GraphNode.prototype.getModel = function (path) { + if (this.dataIndex < 0) { + return; + } + + var graph = this.hostGraph; + var itemModel = graph.data.getItemModel(this.dataIndex); + return itemModel.getModel(path); + }; + + GraphNode.prototype.getAdjacentDataIndices = function () { + var dataIndices = { + edge: [], + node: [] + }; + + for (var i = 0; i < this.edges.length; i++) { + var adjacentEdge = this.edges[i]; + + if (adjacentEdge.dataIndex < 0) { + continue; + } + + dataIndices.edge.push(adjacentEdge.dataIndex); + dataIndices.node.push(adjacentEdge.node1.dataIndex, adjacentEdge.node2.dataIndex); + } + + return dataIndices; + }; + + return GraphNode; + }(); + + var GraphEdge = + /** @class */ + function () { + function GraphEdge(n1, n2, dataIndex) { + this.dataIndex = -1; + this.node1 = n1; + this.node2 = n2; + this.dataIndex = dataIndex == null ? -1 : dataIndex; + } // eslint-disable-next-line @typescript-eslint/no-unused-vars + + + GraphEdge.prototype.getModel = function (path) { + if (this.dataIndex < 0) { + return; + } + + var graph = this.hostGraph; + var itemModel = graph.edgeData.getItemModel(this.dataIndex); + return itemModel.getModel(path); + }; + + GraphEdge.prototype.getAdjacentDataIndices = function () { + return { + edge: [this.dataIndex], + node: [this.node1.dataIndex, this.node2.dataIndex] + }; + }; + + return GraphEdge; + }(); + + function createGraphDataProxyMixin(hostName, dataName) { + return { + /** + * @param Default 'value'. can be 'a', 'b', 'c', 'd', 'e'. + */ + getValue: function (dimension) { + var data = this[hostName][dataName]; + return data.getStore().get(data.getDimensionIndex(dimension || 'value'), this.dataIndex); + }, + // TODO: TYPE stricter type. + setVisual: function (key, value) { + this.dataIndex >= 0 && this[hostName][dataName].setItemVisual(this.dataIndex, key, value); + }, + getVisual: function (key) { + return this[hostName][dataName].getItemVisual(this.dataIndex, key); + }, + setLayout: function (layout, merge) { + this.dataIndex >= 0 && this[hostName][dataName].setItemLayout(this.dataIndex, layout, merge); + }, + getLayout: function () { + return this[hostName][dataName].getItemLayout(this.dataIndex); + }, + getGraphicEl: function () { + return this[hostName][dataName].getItemGraphicEl(this.dataIndex); + }, + getRawIndex: function () { + return this[hostName][dataName].getRawIndex(this.dataIndex); + } + }; + } + mixin(GraphNode, createGraphDataProxyMixin('hostGraph', 'data')); + mixin(GraphEdge, createGraphDataProxyMixin('hostGraph', 'edgeData')); + + function createGraphFromNodeEdge(nodes, edges, seriesModel, directed, beforeLink) { + // ??? TODO + // support dataset? + var graph = new Graph(directed); + + for (var i = 0; i < nodes.length; i++) { + graph.addNode(retrieve( // Id, name, dataIndex + nodes[i].id, nodes[i].name, i), i); + } + + var linkNameList = []; + var validEdges = []; + var linkCount = 0; + + for (var i = 0; i < edges.length; i++) { + var link = edges[i]; + var source = link.source; + var target = link.target; // addEdge may fail when source or target not exists + + if (graph.addEdge(source, target, linkCount)) { + validEdges.push(link); + linkNameList.push(retrieve(convertOptionIdName(link.id, null), source + ' > ' + target)); + linkCount++; + } + } + + var coordSys = seriesModel.get('coordinateSystem'); + var nodeData; + + if (coordSys === 'cartesian2d' || coordSys === 'polar') { + nodeData = createSeriesData(nodes, seriesModel); + } else { + var coordSysCtor = CoordinateSystemManager.get(coordSys); + var coordDimensions = coordSysCtor ? coordSysCtor.dimensions || [] : []; // FIXME: Some geo do not need `value` dimenson, whereas `calendar` needs + // `value` dimension, but graph need `value` dimension. It's better to + // uniform this behavior. + + if (indexOf(coordDimensions, 'value') < 0) { + coordDimensions.concat(['value']); + } + + var dimensions = prepareSeriesDataSchema(nodes, { + coordDimensions: coordDimensions, + encodeDefine: seriesModel.getEncode() + }).dimensions; + nodeData = new SeriesData(dimensions, seriesModel); + nodeData.initData(nodes); + } + + var edgeData = new SeriesData(['value'], seriesModel); + edgeData.initData(validEdges, linkNameList); + beforeLink && beforeLink(nodeData, edgeData); + linkSeriesData({ + mainData: nodeData, + struct: graph, + structAttr: 'graph', + datas: { + node: nodeData, + edge: edgeData + }, + datasAttr: { + node: 'data', + edge: 'edgeData' + } + }); // Update dataIndex of nodes and edges because invalid edge may be removed + + graph.update(); + return graph; + } + + var GraphSeriesModel = + /** @class */ + function (_super) { + __extends(GraphSeriesModel, _super); + + function GraphSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = GraphSeriesModel.type; + _this.hasSymbolVisual = true; + return _this; + } + + GraphSeriesModel.prototype.init = function (option) { + _super.prototype.init.apply(this, arguments); + + var self = this; + + function getCategoriesData() { + return self._categoriesData; + } // Provide data for legend select + + + this.legendVisualProvider = new LegendVisualProvider(getCategoriesData, getCategoriesData); + this.fillDataTextStyle(option.edges || option.links); + + this._updateCategoriesData(); + }; + + GraphSeriesModel.prototype.mergeOption = function (option) { + _super.prototype.mergeOption.apply(this, arguments); + + this.fillDataTextStyle(option.edges || option.links); + + this._updateCategoriesData(); + }; + + GraphSeriesModel.prototype.mergeDefaultAndTheme = function (option) { + _super.prototype.mergeDefaultAndTheme.apply(this, arguments); + + defaultEmphasis(option, 'edgeLabel', ['show']); + }; + + GraphSeriesModel.prototype.getInitialData = function (option, ecModel) { + var edges = option.edges || option.links || []; + var nodes = option.data || option.nodes || []; + var self = this; + + if (nodes && edges) { + // auto curveness + initCurvenessList(this); + var graph = createGraphFromNodeEdge(nodes, edges, this, true, beforeLink); + each(graph.edges, function (edge) { + createEdgeMapForCurveness(edge.node1, edge.node2, this, edge.dataIndex); + }, this); + return graph.data; + } + + function beforeLink(nodeData, edgeData) { + // Overwrite nodeData.getItemModel to + nodeData.wrapMethod('getItemModel', function (model) { + var categoriesModels = self._categoriesModels; + var categoryIdx = model.getShallow('category'); + var categoryModel = categoriesModels[categoryIdx]; + + if (categoryModel) { + categoryModel.parentModel = model.parentModel; + model.parentModel = categoryModel; + } + + return model; + }); // TODO Inherit resolveParentPath by default in Model#getModel? + + var oldGetModel = Model.prototype.getModel; + + function newGetModel(path, parentModel) { + var model = oldGetModel.call(this, path, parentModel); + model.resolveParentPath = resolveParentPath; + return model; + } + + edgeData.wrapMethod('getItemModel', function (model) { + model.resolveParentPath = resolveParentPath; + model.getModel = newGetModel; + return model; + }); + + function resolveParentPath(pathArr) { + if (pathArr && (pathArr[0] === 'label' || pathArr[1] === 'label')) { + var newPathArr = pathArr.slice(); + + if (pathArr[0] === 'label') { + newPathArr[0] = 'edgeLabel'; + } else if (pathArr[1] === 'label') { + newPathArr[1] = 'edgeLabel'; + } + + return newPathArr; + } + + return pathArr; + } + } + }; + + GraphSeriesModel.prototype.getGraph = function () { + return this.getData().graph; + }; + + GraphSeriesModel.prototype.getEdgeData = function () { + return this.getGraph().edgeData; + }; + + GraphSeriesModel.prototype.getCategoriesData = function () { + return this._categoriesData; + }; + + GraphSeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + if (dataType === 'edge') { + var nodeData = this.getData(); + var params = this.getDataParams(dataIndex, dataType); + var edge = nodeData.graph.getEdgeByIndex(dataIndex); + var sourceName = nodeData.getName(edge.node1.dataIndex); + var targetName = nodeData.getName(edge.node2.dataIndex); + var nameArr = []; + sourceName != null && nameArr.push(sourceName); + targetName != null && nameArr.push(targetName); + return createTooltipMarkup('nameValue', { + name: nameArr.join(' > '), + value: params.value, + noValue: params.value == null + }); + } // dataType === 'node' or empty + + + var nodeMarkup = defaultSeriesFormatTooltip({ + series: this, + dataIndex: dataIndex, + multipleSeries: multipleSeries + }); + return nodeMarkup; + }; + + GraphSeriesModel.prototype._updateCategoriesData = function () { + var categories = map(this.option.categories || [], function (category) { + // Data must has value + return category.value != null ? category : extend({ + value: 0 + }, category); + }); + var categoriesData = new SeriesData(['value'], this); + categoriesData.initData(categories); + this._categoriesData = categoriesData; + this._categoriesModels = categoriesData.mapArray(function (idx) { + return categoriesData.getItemModel(idx); + }); + }; + + GraphSeriesModel.prototype.setZoom = function (zoom) { + this.option.zoom = zoom; + }; + + GraphSeriesModel.prototype.setCenter = function (center) { + this.option.center = center; + }; + + GraphSeriesModel.prototype.isAnimationEnabled = function () { + return _super.prototype.isAnimationEnabled.call(this) // Not enable animation when do force layout + && !(this.get('layout') === 'force' && this.get(['force', 'layoutAnimation'])); + }; + + GraphSeriesModel.type = 'series.graph'; + GraphSeriesModel.dependencies = ['grid', 'polar', 'geo', 'singleAxis', 'calendar']; + GraphSeriesModel.defaultOption = { + // zlevel: 0, + z: 2, + coordinateSystem: 'view', + // Default option for all coordinate systems + // xAxisIndex: 0, + // yAxisIndex: 0, + // polarIndex: 0, + // geoIndex: 0, + legendHoverLink: true, + layout: null, + // Configuration of circular layout + circular: { + rotateLabel: false + }, + // Configuration of force directed layout + force: { + initLayout: null, + // Node repulsion. Can be an array to represent range. + repulsion: [0, 50], + gravity: 0.1, + // Initial friction + friction: 0.6, + // Edge length. Can be an array to represent range. + edgeLength: 30, + layoutAnimation: true + }, + left: 'center', + top: 'center', + // right: null, + // bottom: null, + // width: '80%', + // height: '80%', + symbol: 'circle', + symbolSize: 10, + edgeSymbol: ['none', 'none'], + edgeSymbolSize: 10, + edgeLabel: { + position: 'middle', + distance: 5 + }, + draggable: false, + roam: false, + // Default on center of graph + center: null, + zoom: 1, + // Symbol size scale ratio in roam + nodeScaleRatio: 0.6, + // cursor: null, + // categories: [], + // data: [] + // Or + // nodes: [] + // + // links: [] + // Or + // edges: [] + label: { + show: false, + formatter: '{b}' + }, + itemStyle: {}, + lineStyle: { + color: '#aaa', + width: 1, + opacity: 0.5 + }, + emphasis: { + scale: true, + label: { + show: true + } + }, + select: { + itemStyle: { + borderColor: '#212121' + } + } + }; + return GraphSeriesModel; + }(SeriesModel); + + var actionInfo = { + type: 'graphRoam', + event: 'graphRoam', + update: 'none' + }; + function install$d(registers) { + registers.registerChartView(GraphView); + registers.registerSeriesModel(GraphSeriesModel); + registers.registerProcessor(categoryFilter); + registers.registerVisual(categoryVisual); + registers.registerVisual(graphEdgeVisual); + registers.registerLayout(graphSimpleLayout); + registers.registerLayout(registers.PRIORITY.VISUAL.POST_CHART_LAYOUT, graphCircularLayout); + registers.registerLayout(graphForceLayout); + registers.registerCoordinateSystem('graphView', { + dimensions: View.dimensions, + create: createViewCoordSys + }); // Register legacy focus actions + + registers.registerAction({ + type: 'focusNodeAdjacency', + event: 'focusNodeAdjacency', + update: 'series:focusNodeAdjacency' + }, noop); + registers.registerAction({ + type: 'unfocusNodeAdjacency', + event: 'unfocusNodeAdjacency', + update: 'series:unfocusNodeAdjacency' + }, noop); // Register roam action. + + registers.registerAction(actionInfo, function (payload, ecModel) { + ecModel.eachComponent({ + mainType: 'series', + query: payload + }, function (seriesModel) { + var coordSys = seriesModel.coordinateSystem; + var res = updateCenterAndZoom(coordSys, payload); + seriesModel.setCenter && seriesModel.setCenter(res.center); + seriesModel.setZoom && seriesModel.setZoom(res.zoom); + }); + }); + } + + var PointerShape = + /** @class */ + function () { + function PointerShape() { + this.angle = 0; + this.width = 10; + this.r = 10; + this.x = 0; + this.y = 0; + } + + return PointerShape; + }(); + + var PointerPath = + /** @class */ + function (_super) { + __extends(PointerPath, _super); + + function PointerPath(opts) { + var _this = _super.call(this, opts) || this; + + _this.type = 'pointer'; + return _this; + } + + PointerPath.prototype.getDefaultShape = function () { + return new PointerShape(); + }; + + PointerPath.prototype.buildPath = function (ctx, shape) { + var mathCos = Math.cos; + var mathSin = Math.sin; + var r = shape.r; + var width = shape.width; + var angle = shape.angle; + var x = shape.x - mathCos(angle) * width * (width >= r / 3 ? 1 : 2); + var y = shape.y - mathSin(angle) * width * (width >= r / 3 ? 1 : 2); + angle = shape.angle - Math.PI / 2; + ctx.moveTo(x, y); + ctx.lineTo(shape.x + mathCos(angle) * width, shape.y + mathSin(angle) * width); + ctx.lineTo(shape.x + mathCos(shape.angle) * r, shape.y + mathSin(shape.angle) * r); + ctx.lineTo(shape.x - mathCos(angle) * width, shape.y - mathSin(angle) * width); + ctx.lineTo(x, y); + }; + + return PointerPath; + }(Path); + + function parsePosition(seriesModel, api) { + var center = seriesModel.get('center'); + var width = api.getWidth(); + var height = api.getHeight(); + var size = Math.min(width, height); + var cx = parsePercent$1(center[0], api.getWidth()); + var cy = parsePercent$1(center[1], api.getHeight()); + var r = parsePercent$1(seriesModel.get('radius'), size / 2); + return { + cx: cx, + cy: cy, + r: r + }; + } + + function formatLabel(value, labelFormatter) { + var label = value == null ? '' : value + ''; + + if (labelFormatter) { + if (isString(labelFormatter)) { + label = labelFormatter.replace('{value}', label); + } else if (isFunction(labelFormatter)) { + label = labelFormatter(value); + } + } + + return label; + } + + var GaugeView = + /** @class */ + function (_super) { + __extends(GaugeView, _super); + + function GaugeView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = GaugeView.type; + return _this; + } + + GaugeView.prototype.render = function (seriesModel, ecModel, api) { + this.group.removeAll(); + var colorList = seriesModel.get(['axisLine', 'lineStyle', 'color']); + var posInfo = parsePosition(seriesModel, api); + + this._renderMain(seriesModel, ecModel, api, colorList, posInfo); + + this._data = seriesModel.getData(); + }; + + GaugeView.prototype.dispose = function () {}; + + GaugeView.prototype._renderMain = function (seriesModel, ecModel, api, colorList, posInfo) { + var group = this.group; + var clockwise = seriesModel.get('clockwise'); + var startAngle = -seriesModel.get('startAngle') / 180 * Math.PI; + var endAngle = -seriesModel.get('endAngle') / 180 * Math.PI; + var axisLineModel = seriesModel.getModel('axisLine'); + var roundCap = axisLineModel.get('roundCap'); + var MainPath = roundCap ? SausagePath : Sector; + var showAxis = axisLineModel.get('show'); + var lineStyleModel = axisLineModel.getModel('lineStyle'); + var axisLineWidth = lineStyleModel.get('width'); + var angles = [startAngle, endAngle]; + normalizeArcAngles(angles, !clockwise); + startAngle = angles[0]; + endAngle = angles[1]; + var angleRangeSpan = endAngle - startAngle; + var prevEndAngle = startAngle; + + for (var i = 0; showAxis && i < colorList.length; i++) { + // Clamp + var percent = Math.min(Math.max(colorList[i][0], 0), 1); + endAngle = startAngle + angleRangeSpan * percent; + var sector = new MainPath({ + shape: { + startAngle: prevEndAngle, + endAngle: endAngle, + cx: posInfo.cx, + cy: posInfo.cy, + clockwise: clockwise, + r0: posInfo.r - axisLineWidth, + r: posInfo.r + }, + silent: true + }); + sector.setStyle({ + fill: colorList[i][1] + }); + sector.setStyle(lineStyleModel.getLineStyle( // Because we use sector to simulate arc + // so the properties for stroking are useless + ['color', 'width'])); + group.add(sector); + prevEndAngle = endAngle; + } + + var getColor = function (percent) { + // Less than 0 + if (percent <= 0) { + return colorList[0][1]; + } + + var i; + + for (i = 0; i < colorList.length; i++) { + if (colorList[i][0] >= percent && (i === 0 ? 0 : colorList[i - 1][0]) < percent) { + return colorList[i][1]; + } + } // More than 1 + + + return colorList[i - 1][1]; + }; + + this._renderTicks(seriesModel, ecModel, api, getColor, posInfo, startAngle, endAngle, clockwise, axisLineWidth); + + this._renderTitleAndDetail(seriesModel, ecModel, api, getColor, posInfo); + + this._renderAnchor(seriesModel, posInfo); + + this._renderPointer(seriesModel, ecModel, api, getColor, posInfo, startAngle, endAngle, clockwise, axisLineWidth); + }; + + GaugeView.prototype._renderTicks = function (seriesModel, ecModel, api, getColor, posInfo, startAngle, endAngle, clockwise, axisLineWidth) { + var group = this.group; + var cx = posInfo.cx; + var cy = posInfo.cy; + var r = posInfo.r; + var minVal = +seriesModel.get('min'); + var maxVal = +seriesModel.get('max'); + var splitLineModel = seriesModel.getModel('splitLine'); + var tickModel = seriesModel.getModel('axisTick'); + var labelModel = seriesModel.getModel('axisLabel'); + var splitNumber = seriesModel.get('splitNumber'); + var subSplitNumber = tickModel.get('splitNumber'); + var splitLineLen = parsePercent$1(splitLineModel.get('length'), r); + var tickLen = parsePercent$1(tickModel.get('length'), r); + var angle = startAngle; + var step = (endAngle - startAngle) / splitNumber; + var subStep = step / subSplitNumber; + var splitLineStyle = splitLineModel.getModel('lineStyle').getLineStyle(); + var tickLineStyle = tickModel.getModel('lineStyle').getLineStyle(); + var splitLineDistance = splitLineModel.get('distance'); + var unitX; + var unitY; + + for (var i = 0; i <= splitNumber; i++) { + unitX = Math.cos(angle); + unitY = Math.sin(angle); // Split line + + if (splitLineModel.get('show')) { + var distance = splitLineDistance ? splitLineDistance + axisLineWidth : axisLineWidth; + var splitLine = new Line({ + shape: { + x1: unitX * (r - distance) + cx, + y1: unitY * (r - distance) + cy, + x2: unitX * (r - splitLineLen - distance) + cx, + y2: unitY * (r - splitLineLen - distance) + cy + }, + style: splitLineStyle, + silent: true + }); + + if (splitLineStyle.stroke === 'auto') { + splitLine.setStyle({ + stroke: getColor(i / splitNumber) + }); + } + + group.add(splitLine); + } // Label + + + if (labelModel.get('show')) { + var distance = labelModel.get('distance') + splitLineDistance; + var label = formatLabel(round(i / splitNumber * (maxVal - minVal) + minVal), labelModel.get('formatter')); + var autoColor = getColor(i / splitNumber); + group.add(new ZRText({ + style: createTextStyle(labelModel, { + text: label, + x: unitX * (r - splitLineLen - distance) + cx, + y: unitY * (r - splitLineLen - distance) + cy, + verticalAlign: unitY < -0.8 ? 'top' : unitY > 0.8 ? 'bottom' : 'middle', + align: unitX < -0.4 ? 'left' : unitX > 0.4 ? 'right' : 'center' + }, { + inheritColor: autoColor + }), + silent: true + })); + } // Axis tick + + + if (tickModel.get('show') && i !== splitNumber) { + var distance = tickModel.get('distance'); + distance = distance ? distance + axisLineWidth : axisLineWidth; + + for (var j = 0; j <= subSplitNumber; j++) { + unitX = Math.cos(angle); + unitY = Math.sin(angle); + var tickLine = new Line({ + shape: { + x1: unitX * (r - distance) + cx, + y1: unitY * (r - distance) + cy, + x2: unitX * (r - tickLen - distance) + cx, + y2: unitY * (r - tickLen - distance) + cy + }, + silent: true, + style: tickLineStyle + }); + + if (tickLineStyle.stroke === 'auto') { + tickLine.setStyle({ + stroke: getColor((i + j / subSplitNumber) / splitNumber) + }); + } + + group.add(tickLine); + angle += subStep; + } + + angle -= subStep; + } else { + angle += step; + } + } + }; + + GaugeView.prototype._renderPointer = function (seriesModel, ecModel, api, getColor, posInfo, startAngle, endAngle, clockwise, axisLineWidth) { + var group = this.group; + var oldData = this._data; + var oldProgressData = this._progressEls; + var progressList = []; + var showPointer = seriesModel.get(['pointer', 'show']); + var progressModel = seriesModel.getModel('progress'); + var showProgress = progressModel.get('show'); + var data = seriesModel.getData(); + var valueDim = data.mapDimension('value'); + var minVal = +seriesModel.get('min'); + var maxVal = +seriesModel.get('max'); + var valueExtent = [minVal, maxVal]; + var angleExtent = [startAngle, endAngle]; + + function createPointer(idx, angle) { + var itemModel = data.getItemModel(idx); + var pointerModel = itemModel.getModel('pointer'); + var pointerWidth = parsePercent$1(pointerModel.get('width'), posInfo.r); + var pointerLength = parsePercent$1(pointerModel.get('length'), posInfo.r); + var pointerStr = seriesModel.get(['pointer', 'icon']); + var pointerOffset = pointerModel.get('offsetCenter'); + var pointerOffsetX = parsePercent$1(pointerOffset[0], posInfo.r); + var pointerOffsetY = parsePercent$1(pointerOffset[1], posInfo.r); + var pointerKeepAspect = pointerModel.get('keepAspect'); + var pointer; // not exist icon type will be set 'rect' + + if (pointerStr) { + pointer = createSymbol(pointerStr, pointerOffsetX - pointerWidth / 2, pointerOffsetY - pointerLength, pointerWidth, pointerLength, null, pointerKeepAspect); + } else { + pointer = new PointerPath({ + shape: { + angle: -Math.PI / 2, + width: pointerWidth, + r: pointerLength, + x: pointerOffsetX, + y: pointerOffsetY + } + }); + } + + pointer.rotation = -(angle + Math.PI / 2); + pointer.x = posInfo.cx; + pointer.y = posInfo.cy; + return pointer; + } + + function createProgress(idx, endAngle) { + var roundCap = progressModel.get('roundCap'); + var ProgressPath = roundCap ? SausagePath : Sector; + var isOverlap = progressModel.get('overlap'); + var progressWidth = isOverlap ? progressModel.get('width') : axisLineWidth / data.count(); + var r0 = isOverlap ? posInfo.r - progressWidth : posInfo.r - (idx + 1) * progressWidth; + var r = isOverlap ? posInfo.r : posInfo.r - idx * progressWidth; + var progress = new ProgressPath({ + shape: { + startAngle: startAngle, + endAngle: endAngle, + cx: posInfo.cx, + cy: posInfo.cy, + clockwise: clockwise, + r0: r0, + r: r + } + }); + isOverlap && (progress.z2 = maxVal - data.get(valueDim, idx) % maxVal); + return progress; + } + + if (showProgress || showPointer) { + data.diff(oldData).add(function (idx) { + var val = data.get(valueDim, idx); + + if (showPointer) { + var pointer = createPointer(idx, startAngle); // TODO hide pointer on NaN value? + + initProps(pointer, { + rotation: -((isNaN(+val) ? angleExtent[0] : linearMap(val, valueExtent, angleExtent, true)) + Math.PI / 2) + }, seriesModel); + group.add(pointer); + data.setItemGraphicEl(idx, pointer); + } + + if (showProgress) { + var progress = createProgress(idx, startAngle); + var isClip = progressModel.get('clip'); + initProps(progress, { + shape: { + endAngle: linearMap(val, valueExtent, angleExtent, isClip) + } + }, seriesModel); + group.add(progress); // Add data index and series index for indexing the data by element + // Useful in tooltip + + setCommonECData(seriesModel.seriesIndex, data.dataType, idx, progress); + progressList[idx] = progress; + } + }).update(function (newIdx, oldIdx) { + var val = data.get(valueDim, newIdx); + + if (showPointer) { + var previousPointer = oldData.getItemGraphicEl(oldIdx); + var previousRotate = previousPointer ? previousPointer.rotation : startAngle; + var pointer = createPointer(newIdx, previousRotate); + pointer.rotation = previousRotate; + updateProps(pointer, { + rotation: -((isNaN(+val) ? angleExtent[0] : linearMap(val, valueExtent, angleExtent, true)) + Math.PI / 2) + }, seriesModel); + group.add(pointer); + data.setItemGraphicEl(newIdx, pointer); + } + + if (showProgress) { + var previousProgress = oldProgressData[oldIdx]; + var previousEndAngle = previousProgress ? previousProgress.shape.endAngle : startAngle; + var progress = createProgress(newIdx, previousEndAngle); + var isClip = progressModel.get('clip'); + updateProps(progress, { + shape: { + endAngle: linearMap(val, valueExtent, angleExtent, isClip) + } + }, seriesModel); + group.add(progress); // Add data index and series index for indexing the data by element + // Useful in tooltip + + setCommonECData(seriesModel.seriesIndex, data.dataType, newIdx, progress); + progressList[newIdx] = progress; + } + }).execute(); + data.each(function (idx) { + var itemModel = data.getItemModel(idx); + var emphasisModel = itemModel.getModel('emphasis'); + var focus = emphasisModel.get('focus'); + var blurScope = emphasisModel.get('blurScope'); + var emphasisDisabled = emphasisModel.get('disabled'); + + if (showPointer) { + var pointer = data.getItemGraphicEl(idx); + var symbolStyle = data.getItemVisual(idx, 'style'); + var visualColor = symbolStyle.fill; + + if (pointer instanceof ZRImage) { + var pathStyle = pointer.style; + pointer.useStyle(extend({ + image: pathStyle.image, + x: pathStyle.x, + y: pathStyle.y, + width: pathStyle.width, + height: pathStyle.height + }, symbolStyle)); + } else { + pointer.useStyle(symbolStyle); + pointer.type !== 'pointer' && pointer.setColor(visualColor); + } + + pointer.setStyle(itemModel.getModel(['pointer', 'itemStyle']).getItemStyle()); + + if (pointer.style.fill === 'auto') { + pointer.setStyle('fill', getColor(linearMap(data.get(valueDim, idx), valueExtent, [0, 1], true))); + } + + pointer.z2EmphasisLift = 0; + setStatesStylesFromModel(pointer, itemModel); + toggleHoverEmphasis(pointer, focus, blurScope, emphasisDisabled); + } + + if (showProgress) { + var progress = progressList[idx]; + progress.useStyle(data.getItemVisual(idx, 'style')); + progress.setStyle(itemModel.getModel(['progress', 'itemStyle']).getItemStyle()); + progress.z2EmphasisLift = 0; + setStatesStylesFromModel(progress, itemModel); + toggleHoverEmphasis(progress, focus, blurScope, emphasisDisabled); + } + }); + this._progressEls = progressList; + } + }; + + GaugeView.prototype._renderAnchor = function (seriesModel, posInfo) { + var anchorModel = seriesModel.getModel('anchor'); + var showAnchor = anchorModel.get('show'); + + if (showAnchor) { + var anchorSize = anchorModel.get('size'); + var anchorType = anchorModel.get('icon'); + var offsetCenter = anchorModel.get('offsetCenter'); + var anchorKeepAspect = anchorModel.get('keepAspect'); + var anchor = createSymbol(anchorType, posInfo.cx - anchorSize / 2 + parsePercent$1(offsetCenter[0], posInfo.r), posInfo.cy - anchorSize / 2 + parsePercent$1(offsetCenter[1], posInfo.r), anchorSize, anchorSize, null, anchorKeepAspect); + anchor.z2 = anchorModel.get('showAbove') ? 1 : 0; + anchor.setStyle(anchorModel.getModel('itemStyle').getItemStyle()); + this.group.add(anchor); + } + }; + + GaugeView.prototype._renderTitleAndDetail = function (seriesModel, ecModel, api, getColor, posInfo) { + var _this = this; + + var data = seriesModel.getData(); + var valueDim = data.mapDimension('value'); + var minVal = +seriesModel.get('min'); + var maxVal = +seriesModel.get('max'); + var contentGroup = new Group(); + var newTitleEls = []; + var newDetailEls = []; + var hasAnimation = seriesModel.isAnimationEnabled(); + var showPointerAbove = seriesModel.get(['pointer', 'showAbove']); + data.diff(this._data).add(function (idx) { + newTitleEls[idx] = new ZRText({ + silent: true + }); + newDetailEls[idx] = new ZRText({ + silent: true + }); + }).update(function (idx, oldIdx) { + newTitleEls[idx] = _this._titleEls[oldIdx]; + newDetailEls[idx] = _this._detailEls[oldIdx]; + }).execute(); + data.each(function (idx) { + var itemModel = data.getItemModel(idx); + var value = data.get(valueDim, idx); + var itemGroup = new Group(); + var autoColor = getColor(linearMap(value, [minVal, maxVal], [0, 1], true)); + var itemTitleModel = itemModel.getModel('title'); + + if (itemTitleModel.get('show')) { + var titleOffsetCenter = itemTitleModel.get('offsetCenter'); + var titleX = posInfo.cx + parsePercent$1(titleOffsetCenter[0], posInfo.r); + var titleY = posInfo.cy + parsePercent$1(titleOffsetCenter[1], posInfo.r); + var labelEl = newTitleEls[idx]; + labelEl.attr({ + z2: showPointerAbove ? 0 : 2, + style: createTextStyle(itemTitleModel, { + x: titleX, + y: titleY, + text: data.getName(idx), + align: 'center', + verticalAlign: 'middle' + }, { + inheritColor: autoColor + }) + }); + itemGroup.add(labelEl); + } + + var itemDetailModel = itemModel.getModel('detail'); + + if (itemDetailModel.get('show')) { + var detailOffsetCenter = itemDetailModel.get('offsetCenter'); + var detailX = posInfo.cx + parsePercent$1(detailOffsetCenter[0], posInfo.r); + var detailY = posInfo.cy + parsePercent$1(detailOffsetCenter[1], posInfo.r); + var width = parsePercent$1(itemDetailModel.get('width'), posInfo.r); + var height = parsePercent$1(itemDetailModel.get('height'), posInfo.r); + var detailColor = seriesModel.get(['progress', 'show']) ? data.getItemVisual(idx, 'style').fill : autoColor; + var labelEl = newDetailEls[idx]; + var formatter_1 = itemDetailModel.get('formatter'); + labelEl.attr({ + z2: showPointerAbove ? 0 : 2, + style: createTextStyle(itemDetailModel, { + x: detailX, + y: detailY, + text: formatLabel(value, formatter_1), + width: isNaN(width) ? null : width, + height: isNaN(height) ? null : height, + align: 'center', + verticalAlign: 'middle' + }, { + inheritColor: detailColor + }) + }); + setLabelValueAnimation(labelEl, { + normal: itemDetailModel + }, value, function (value) { + return formatLabel(value, formatter_1); + }); + hasAnimation && animateLabelValue(labelEl, idx, data, seriesModel, { + getFormattedLabel: function (labelDataIndex, status, dataType, labelDimIndex, fmt, extendParams) { + return formatLabel(extendParams ? extendParams.interpolatedValue : value, formatter_1); + } + }); + itemGroup.add(labelEl); + } + + contentGroup.add(itemGroup); + }); + this.group.add(contentGroup); + this._titleEls = newTitleEls; + this._detailEls = newDetailEls; + }; + + GaugeView.type = 'gauge'; + return GaugeView; + }(ChartView); + + var GaugeSeriesModel = + /** @class */ + function (_super) { + __extends(GaugeSeriesModel, _super); + + function GaugeSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = GaugeSeriesModel.type; + _this.visualStyleAccessPath = 'itemStyle'; + return _this; + } + + GaugeSeriesModel.prototype.getInitialData = function (option, ecModel) { + return createSeriesDataSimply(this, ['value']); + }; + + GaugeSeriesModel.type = 'series.gauge'; + GaugeSeriesModel.defaultOption = { + // zlevel: 0, + z: 2, + colorBy: 'data', + // 默认全局居中 + center: ['50%', '50%'], + legendHoverLink: true, + radius: '75%', + startAngle: 225, + endAngle: -45, + clockwise: true, + // 最小值 + min: 0, + // 最大值 + max: 100, + // 分割段数,默认为10 + splitNumber: 10, + // 坐标轴线 + axisLine: { + // 默认显示,属性show控制显示与否 + show: true, + roundCap: false, + lineStyle: { + color: [[1, '#E6EBF8']], + width: 10 + } + }, + // 坐标轴线 + progress: { + // 默认显示,属性show控制显示与否 + show: false, + overlap: true, + width: 10, + roundCap: false, + clip: true + }, + // 分隔线 + splitLine: { + // 默认显示,属性show控制显示与否 + show: true, + // 属性length控制线长 + length: 10, + distance: 10, + // 属性lineStyle(详见lineStyle)控制线条样式 + lineStyle: { + color: '#63677A', + width: 3, + type: 'solid' + } + }, + // 坐标轴小标记 + axisTick: { + // 属性show控制显示与否,默认不显示 + show: true, + // 每份split细分多少段 + splitNumber: 5, + // 属性length控制线长 + length: 6, + distance: 10, + // 属性lineStyle控制线条样式 + lineStyle: { + color: '#63677A', + width: 1, + type: 'solid' + } + }, + axisLabel: { + show: true, + distance: 15, + // formatter: null, + color: '#464646', + fontSize: 12 + }, + pointer: { + icon: null, + offsetCenter: [0, 0], + show: true, + showAbove: true, + length: '60%', + width: 6, + keepAspect: false + }, + anchor: { + show: false, + showAbove: false, + size: 6, + icon: 'circle', + offsetCenter: [0, 0], + keepAspect: false, + itemStyle: { + color: '#fff', + borderWidth: 0, + borderColor: '#5470c6' + } + }, + title: { + show: true, + // x, y,单位px + offsetCenter: [0, '20%'], + // 其余属性默认使用全局文本样式,详见TEXTSTYLE + color: '#464646', + fontSize: 16, + valueAnimation: false + }, + detail: { + show: true, + backgroundColor: 'rgba(0,0,0,0)', + borderWidth: 0, + borderColor: '#ccc', + width: 100, + height: null, + padding: [5, 10], + // x, y,单位px + offsetCenter: [0, '40%'], + // formatter: null, + // 其余属性默认使用全局文本样式,详见TEXTSTYLE + color: '#464646', + fontSize: 30, + fontWeight: 'bold', + lineHeight: 30, + valueAnimation: false + } + }; + return GaugeSeriesModel; + }(SeriesModel); + + function install$e(registers) { + registers.registerChartView(GaugeView); + registers.registerSeriesModel(GaugeSeriesModel); + } + + var opacityAccessPath = ['itemStyle', 'opacity']; + /** + * Piece of pie including Sector, Label, LabelLine + */ + + var FunnelPiece = + /** @class */ + function (_super) { + __extends(FunnelPiece, _super); + + function FunnelPiece(data, idx) { + var _this = _super.call(this) || this; + + var polygon = _this; + var labelLine = new Polyline(); + var text = new ZRText(); + polygon.setTextContent(text); + + _this.setTextGuideLine(labelLine); + + _this.updateData(data, idx, true); + + return _this; + } + + FunnelPiece.prototype.updateData = function (data, idx, firstCreate) { + var polygon = this; + var seriesModel = data.hostModel; + var itemModel = data.getItemModel(idx); + var layout = data.getItemLayout(idx); + var emphasisModel = itemModel.getModel('emphasis'); + var opacity = itemModel.get(opacityAccessPath); + opacity = opacity == null ? 1 : opacity; + + if (!firstCreate) { + saveOldStyle(polygon); + } // Update common style + + + polygon.useStyle(data.getItemVisual(idx, 'style')); + polygon.style.lineJoin = 'round'; + + if (firstCreate) { + polygon.setShape({ + points: layout.points + }); + polygon.style.opacity = 0; + initProps(polygon, { + style: { + opacity: opacity + } + }, seriesModel, idx); + } else { + updateProps(polygon, { + style: { + opacity: opacity + }, + shape: { + points: layout.points + } + }, seriesModel, idx); + } + + setStatesStylesFromModel(polygon, itemModel); + + this._updateLabel(data, idx); + + toggleHoverEmphasis(this, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled')); + }; + + FunnelPiece.prototype._updateLabel = function (data, idx) { + var polygon = this; + var labelLine = this.getTextGuideLine(); + var labelText = polygon.getTextContent(); + var seriesModel = data.hostModel; + var itemModel = data.getItemModel(idx); + var layout = data.getItemLayout(idx); + var labelLayout = layout.label; + var style = data.getItemVisual(idx, 'style'); + var visualColor = style.fill; + setLabelStyle( // position will not be used in setLabelStyle + labelText, getLabelStatesModels(itemModel), { + labelFetcher: data.hostModel, + labelDataIndex: idx, + defaultOpacity: style.opacity, + defaultText: data.getName(idx) + }, { + normal: { + align: labelLayout.textAlign, + verticalAlign: labelLayout.verticalAlign + } + }); + polygon.setTextConfig({ + local: true, + inside: !!labelLayout.inside, + insideStroke: visualColor, + // insideFill: 'auto', + outsideFill: visualColor + }); + var linePoints = labelLayout.linePoints; + labelLine.setShape({ + points: linePoints + }); + polygon.textGuideLineConfig = { + anchor: linePoints ? new Point(linePoints[0][0], linePoints[0][1]) : null + }; // Make sure update style on labelText after setLabelStyle. + // Because setLabelStyle will replace a new style on it. + + updateProps(labelText, { + style: { + x: labelLayout.x, + y: labelLayout.y + } + }, seriesModel, idx); + labelText.attr({ + rotation: labelLayout.rotation, + originX: labelLayout.x, + originY: labelLayout.y, + z2: 10 + }); + setLabelLineStyle(polygon, getLabelLineStatesModels(itemModel), { + // Default use item visual color + stroke: visualColor + }); + }; + + return FunnelPiece; + }(Polygon); + + var FunnelView = + /** @class */ + function (_super) { + __extends(FunnelView, _super); + + function FunnelView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = FunnelView.type; + _this.ignoreLabelLineUpdate = true; + return _this; + } + + FunnelView.prototype.render = function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + var oldData = this._data; + var group = this.group; + data.diff(oldData).add(function (idx) { + var funnelPiece = new FunnelPiece(data, idx); + data.setItemGraphicEl(idx, funnelPiece); + group.add(funnelPiece); + }).update(function (newIdx, oldIdx) { + var piece = oldData.getItemGraphicEl(oldIdx); + piece.updateData(data, newIdx); + group.add(piece); + data.setItemGraphicEl(newIdx, piece); + }).remove(function (idx) { + var piece = oldData.getItemGraphicEl(idx); + removeElementWithFadeOut(piece, seriesModel, idx); + }).execute(); + this._data = data; + }; + + FunnelView.prototype.remove = function () { + this.group.removeAll(); + this._data = null; + }; + + FunnelView.prototype.dispose = function () {}; + + FunnelView.type = 'funnel'; + return FunnelView; + }(ChartView); + + var FunnelSeriesModel = + /** @class */ + function (_super) { + __extends(FunnelSeriesModel, _super); + + function FunnelSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = FunnelSeriesModel.type; + return _this; + } + + FunnelSeriesModel.prototype.init = function (option) { + _super.prototype.init.apply(this, arguments); // Enable legend selection for each data item + // Use a function instead of direct access because data reference may changed + + + this.legendVisualProvider = new LegendVisualProvider(bind(this.getData, this), bind(this.getRawData, this)); // Extend labelLine emphasis + + this._defaultLabelLine(option); + }; + + FunnelSeriesModel.prototype.getInitialData = function (option, ecModel) { + return createSeriesDataSimply(this, { + coordDimensions: ['value'], + encodeDefaulter: curry(makeSeriesEncodeForNameBased, this) + }); + }; + + FunnelSeriesModel.prototype._defaultLabelLine = function (option) { + // Extend labelLine emphasis + defaultEmphasis(option, 'labelLine', ['show']); + var labelLineNormalOpt = option.labelLine; + var labelLineEmphasisOpt = option.emphasis.labelLine; // Not show label line if `label.normal.show = false` + + labelLineNormalOpt.show = labelLineNormalOpt.show && option.label.show; + labelLineEmphasisOpt.show = labelLineEmphasisOpt.show && option.emphasis.label.show; + }; // Overwrite + + + FunnelSeriesModel.prototype.getDataParams = function (dataIndex) { + var data = this.getData(); + + var params = _super.prototype.getDataParams.call(this, dataIndex); + + var valueDim = data.mapDimension('value'); + var sum = data.getSum(valueDim); // Percent is 0 if sum is 0 + + params.percent = !sum ? 0 : +(data.get(valueDim, dataIndex) / sum * 100).toFixed(2); + params.$vars.push('percent'); + return params; + }; + + FunnelSeriesModel.type = 'series.funnel'; + FunnelSeriesModel.defaultOption = { + // zlevel: 0, // 一级层叠 + z: 2, + legendHoverLink: true, + colorBy: 'data', + left: 80, + top: 60, + right: 80, + bottom: 60, + // width: {totalWidth} - left - right, + // height: {totalHeight} - top - bottom, + // 默认取数据最小最大值 + // min: 0, + // max: 100, + minSize: '0%', + maxSize: '100%', + sort: 'descending', + orient: 'vertical', + gap: 0, + funnelAlign: 'center', + label: { + show: true, + position: 'outer' // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调 + + }, + labelLine: { + show: true, + length: 20, + lineStyle: { + // color: 各异, + width: 1 + } + }, + itemStyle: { + // color: 各异, + borderColor: '#fff', + borderWidth: 1 + }, + emphasis: { + label: { + show: true + } + }, + select: { + itemStyle: { + borderColor: '#212121' + } + } + }; + return FunnelSeriesModel; + }(SeriesModel); + + function getViewRect$3(seriesModel, api) { + return getLayoutRect(seriesModel.getBoxLayoutParams(), { + width: api.getWidth(), + height: api.getHeight() + }); + } + + function getSortedIndices(data, sort) { + var valueDim = data.mapDimension('value'); + var valueArr = data.mapArray(valueDim, function (val) { + return val; + }); + var indices = []; + var isAscending = sort === 'ascending'; + + for (var i = 0, len = data.count(); i < len; i++) { + indices[i] = i; + } // Add custom sortable function & none sortable opetion by "options.sort" + + + if (isFunction(sort)) { + indices.sort(sort); + } else if (sort !== 'none') { + indices.sort(function (a, b) { + return isAscending ? valueArr[a] - valueArr[b] : valueArr[b] - valueArr[a]; + }); + } + + return indices; + } + + function labelLayout(data) { + var seriesModel = data.hostModel; + var orient = seriesModel.get('orient'); + data.each(function (idx) { + var itemModel = data.getItemModel(idx); + var labelModel = itemModel.getModel('label'); + var labelPosition = labelModel.get('position'); + var labelLineModel = itemModel.getModel('labelLine'); + var layout = data.getItemLayout(idx); + var points = layout.points; + var isLabelInside = labelPosition === 'inner' || labelPosition === 'inside' || labelPosition === 'center' || labelPosition === 'insideLeft' || labelPosition === 'insideRight'; + var textAlign; + var textX; + var textY; + var linePoints; + + if (isLabelInside) { + if (labelPosition === 'insideLeft') { + textX = (points[0][0] + points[3][0]) / 2 + 5; + textY = (points[0][1] + points[3][1]) / 2; + textAlign = 'left'; + } else if (labelPosition === 'insideRight') { + textX = (points[1][0] + points[2][0]) / 2 - 5; + textY = (points[1][1] + points[2][1]) / 2; + textAlign = 'right'; + } else { + textX = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4; + textY = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4; + textAlign = 'center'; + } + + linePoints = [[textX, textY], [textX, textY]]; + } else { + var x1 = void 0; + var y1 = void 0; + var x2 = void 0; + var y2 = void 0; + var labelLineLen = labelLineModel.get('length'); + + if ("development" !== 'production') { + if (orient === 'vertical' && ['top', 'bottom'].indexOf(labelPosition) > -1) { + labelPosition = 'left'; + console.warn('Position error: Funnel chart on vertical orient dose not support top and bottom.'); + } + + if (orient === 'horizontal' && ['left', 'right'].indexOf(labelPosition) > -1) { + labelPosition = 'bottom'; + console.warn('Position error: Funnel chart on horizontal orient dose not support left and right.'); + } + } + + if (labelPosition === 'left') { + // Left side + x1 = (points[3][0] + points[0][0]) / 2; + y1 = (points[3][1] + points[0][1]) / 2; + x2 = x1 - labelLineLen; + textX = x2 - 5; + textAlign = 'right'; + } else if (labelPosition === 'right') { + // Right side + x1 = (points[1][0] + points[2][0]) / 2; + y1 = (points[1][1] + points[2][1]) / 2; + x2 = x1 + labelLineLen; + textX = x2 + 5; + textAlign = 'left'; + } else if (labelPosition === 'top') { + // Top side + x1 = (points[3][0] + points[0][0]) / 2; + y1 = (points[3][1] + points[0][1]) / 2; + y2 = y1 - labelLineLen; + textY = y2 - 5; + textAlign = 'center'; + } else if (labelPosition === 'bottom') { + // Bottom side + x1 = (points[1][0] + points[2][0]) / 2; + y1 = (points[1][1] + points[2][1]) / 2; + y2 = y1 + labelLineLen; + textY = y2 + 5; + textAlign = 'center'; + } else if (labelPosition === 'rightTop') { + // RightTop side + x1 = orient === 'horizontal' ? points[3][0] : points[1][0]; + y1 = orient === 'horizontal' ? points[3][1] : points[1][1]; + + if (orient === 'horizontal') { + y2 = y1 - labelLineLen; + textY = y2 - 5; + textAlign = 'center'; + } else { + x2 = x1 + labelLineLen; + textX = x2 + 5; + textAlign = 'top'; + } + } else if (labelPosition === 'rightBottom') { + // RightBottom side + x1 = points[2][0]; + y1 = points[2][1]; + + if (orient === 'horizontal') { + y2 = y1 + labelLineLen; + textY = y2 + 5; + textAlign = 'center'; + } else { + x2 = x1 + labelLineLen; + textX = x2 + 5; + textAlign = 'bottom'; + } + } else if (labelPosition === 'leftTop') { + // LeftTop side + x1 = points[0][0]; + y1 = orient === 'horizontal' ? points[0][1] : points[1][1]; + + if (orient === 'horizontal') { + y2 = y1 - labelLineLen; + textY = y2 - 5; + textAlign = 'center'; + } else { + x2 = x1 - labelLineLen; + textX = x2 - 5; + textAlign = 'right'; + } + } else if (labelPosition === 'leftBottom') { + // LeftBottom side + x1 = orient === 'horizontal' ? points[1][0] : points[3][0]; + y1 = orient === 'horizontal' ? points[1][1] : points[2][1]; + + if (orient === 'horizontal') { + y2 = y1 + labelLineLen; + textY = y2 + 5; + textAlign = 'center'; + } else { + x2 = x1 - labelLineLen; + textX = x2 - 5; + textAlign = 'right'; + } + } else { + // Right side or Bottom side + x1 = (points[1][0] + points[2][0]) / 2; + y1 = (points[1][1] + points[2][1]) / 2; + + if (orient === 'horizontal') { + y2 = y1 + labelLineLen; + textY = y2 + 5; + textAlign = 'center'; + } else { + x2 = x1 + labelLineLen; + textX = x2 + 5; + textAlign = 'left'; + } + } + + if (orient === 'horizontal') { + x2 = x1; + textX = x2; + } else { + y2 = y1; + textY = y2; + } + + linePoints = [[x1, y1], [x2, y2]]; + } + + layout.label = { + linePoints: linePoints, + x: textX, + y: textY, + verticalAlign: 'middle', + textAlign: textAlign, + inside: isLabelInside + }; + }); + } + + function funnelLayout(ecModel, api) { + ecModel.eachSeriesByType('funnel', function (seriesModel) { + var data = seriesModel.getData(); + var valueDim = data.mapDimension('value'); + var sort = seriesModel.get('sort'); + var viewRect = getViewRect$3(seriesModel, api); + var orient = seriesModel.get('orient'); + var viewWidth = viewRect.width; + var viewHeight = viewRect.height; + var indices = getSortedIndices(data, sort); + var x = viewRect.x; + var y = viewRect.y; + var sizeExtent = orient === 'horizontal' ? [parsePercent$1(seriesModel.get('minSize'), viewHeight), parsePercent$1(seriesModel.get('maxSize'), viewHeight)] : [parsePercent$1(seriesModel.get('minSize'), viewWidth), parsePercent$1(seriesModel.get('maxSize'), viewWidth)]; + var dataExtent = data.getDataExtent(valueDim); + var min = seriesModel.get('min'); + var max = seriesModel.get('max'); + + if (min == null) { + min = Math.min(dataExtent[0], 0); + } + + if (max == null) { + max = dataExtent[1]; + } + + var funnelAlign = seriesModel.get('funnelAlign'); + var gap = seriesModel.get('gap'); + var viewSize = orient === 'horizontal' ? viewWidth : viewHeight; + var itemSize = (viewSize - gap * (data.count() - 1)) / data.count(); + + var getLinePoints = function (idx, offset) { + // End point index is data.count() and we assign it 0 + if (orient === 'horizontal') { + var val_1 = data.get(valueDim, idx) || 0; + var itemHeight = linearMap(val_1, [min, max], sizeExtent, true); + var y0 = void 0; + + switch (funnelAlign) { + case 'top': + y0 = y; + break; + + case 'center': + y0 = y + (viewHeight - itemHeight) / 2; + break; + + case 'bottom': + y0 = y + (viewHeight - itemHeight); + break; + } + + return [[offset, y0], [offset, y0 + itemHeight]]; + } + + var val = data.get(valueDim, idx) || 0; + var itemWidth = linearMap(val, [min, max], sizeExtent, true); + var x0; + + switch (funnelAlign) { + case 'left': + x0 = x; + break; + + case 'center': + x0 = x + (viewWidth - itemWidth) / 2; + break; + + case 'right': + x0 = x + viewWidth - itemWidth; + break; + } + + return [[x0, offset], [x0 + itemWidth, offset]]; + }; + + if (sort === 'ascending') { + // From bottom to top + itemSize = -itemSize; + gap = -gap; + + if (orient === 'horizontal') { + x += viewWidth; + } else { + y += viewHeight; + } + + indices = indices.reverse(); + } + + for (var i = 0; i < indices.length; i++) { + var idx = indices[i]; + var nextIdx = indices[i + 1]; + var itemModel = data.getItemModel(idx); + + if (orient === 'horizontal') { + var width = itemModel.get(['itemStyle', 'width']); + + if (width == null) { + width = itemSize; + } else { + width = parsePercent$1(width, viewWidth); + + if (sort === 'ascending') { + width = -width; + } + } + + var start = getLinePoints(idx, x); + var end = getLinePoints(nextIdx, x + width); + x += width + gap; + data.setItemLayout(idx, { + points: start.concat(end.slice().reverse()) + }); + } else { + var height = itemModel.get(['itemStyle', 'height']); + + if (height == null) { + height = itemSize; + } else { + height = parsePercent$1(height, viewHeight); + + if (sort === 'ascending') { + height = -height; + } + } + + var start = getLinePoints(idx, y); + var end = getLinePoints(nextIdx, y + height); + y += height + gap; + data.setItemLayout(idx, { + points: start.concat(end.slice().reverse()) + }); + } + } + + labelLayout(data); + }); + } + + function install$f(registers) { + registers.registerChartView(FunnelView); + registers.registerSeriesModel(FunnelSeriesModel); + registers.registerLayout(funnelLayout); + registers.registerProcessor(dataFilter('funnel')); + } + + var DEFAULT_SMOOTH = 0.3; + + var ParallelView = + /** @class */ + function (_super) { + __extends(ParallelView, _super); + + function ParallelView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ParallelView.type; + _this._dataGroup = new Group(); + _this._initialized = false; + return _this; + } + + ParallelView.prototype.init = function () { + this.group.add(this._dataGroup); + }; + /** + * @override + */ + + + ParallelView.prototype.render = function (seriesModel, ecModel, api, payload) { + // Clear previously rendered progressive elements. + this._progressiveEls = null; + var dataGroup = this._dataGroup; + var data = seriesModel.getData(); + var oldData = this._data; + var coordSys = seriesModel.coordinateSystem; + var dimensions = coordSys.dimensions; + var seriesScope = makeSeriesScope$2(seriesModel); + data.diff(oldData).add(add).update(update).remove(remove).execute(); + + function add(newDataIndex) { + var line = addEl(data, dataGroup, newDataIndex, dimensions, coordSys); + updateElCommon(line, data, newDataIndex, seriesScope); + } + + function update(newDataIndex, oldDataIndex) { + var line = oldData.getItemGraphicEl(oldDataIndex); + var points = createLinePoints(data, newDataIndex, dimensions, coordSys); + data.setItemGraphicEl(newDataIndex, line); + updateProps(line, { + shape: { + points: points + } + }, seriesModel, newDataIndex); + saveOldStyle(line); + updateElCommon(line, data, newDataIndex, seriesScope); + } + + function remove(oldDataIndex) { + var line = oldData.getItemGraphicEl(oldDataIndex); + dataGroup.remove(line); + } // First create + + + if (!this._initialized) { + this._initialized = true; + var clipPath = createGridClipShape(coordSys, seriesModel, function () { + // Callback will be invoked immediately if there is no animation + setTimeout(function () { + dataGroup.removeClipPath(); + }); + }); + dataGroup.setClipPath(clipPath); + } + + this._data = data; + }; + + ParallelView.prototype.incrementalPrepareRender = function (seriesModel, ecModel, api) { + this._initialized = true; + this._data = null; + + this._dataGroup.removeAll(); + }; + + ParallelView.prototype.incrementalRender = function (taskParams, seriesModel, ecModel) { + var data = seriesModel.getData(); + var coordSys = seriesModel.coordinateSystem; + var dimensions = coordSys.dimensions; + var seriesScope = makeSeriesScope$2(seriesModel); + var progressiveEls = this._progressiveEls = []; + + for (var dataIndex = taskParams.start; dataIndex < taskParams.end; dataIndex++) { + var line = addEl(data, this._dataGroup, dataIndex, dimensions, coordSys); + line.incremental = true; + updateElCommon(line, data, dataIndex, seriesScope); + progressiveEls.push(line); + } + }; + + ParallelView.prototype.remove = function () { + this._dataGroup && this._dataGroup.removeAll(); + this._data = null; + }; + + ParallelView.type = 'parallel'; + return ParallelView; + }(ChartView); + + function createGridClipShape(coordSys, seriesModel, cb) { + var parallelModel = coordSys.model; + var rect = coordSys.getRect(); + var rectEl = new Rect({ + shape: { + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height + } + }); + var dim = parallelModel.get('layout') === 'horizontal' ? 'width' : 'height'; + rectEl.setShape(dim, 0); + initProps(rectEl, { + shape: { + width: rect.width, + height: rect.height + } + }, seriesModel, cb); + return rectEl; + } + + function createLinePoints(data, dataIndex, dimensions, coordSys) { + var points = []; + + for (var i = 0; i < dimensions.length; i++) { + var dimName = dimensions[i]; + var value = data.get(data.mapDimension(dimName), dataIndex); + + if (!isEmptyValue(value, coordSys.getAxis(dimName).type)) { + points.push(coordSys.dataToPoint(value, dimName)); + } + } + + return points; + } + + function addEl(data, dataGroup, dataIndex, dimensions, coordSys) { + var points = createLinePoints(data, dataIndex, dimensions, coordSys); + var line = new Polyline({ + shape: { + points: points + }, + // silent: true, + z2: 10 + }); + dataGroup.add(line); + data.setItemGraphicEl(dataIndex, line); + return line; + } + + function makeSeriesScope$2(seriesModel) { + var smooth = seriesModel.get('smooth', true); + smooth === true && (smooth = DEFAULT_SMOOTH); + smooth = numericToNumber(smooth); + eqNaN(smooth) && (smooth = 0); + return { + smooth: smooth + }; + } + + function updateElCommon(el, data, dataIndex, seriesScope) { + el.useStyle(data.getItemVisual(dataIndex, 'style')); + el.style.fill = null; + el.setShape('smooth', seriesScope.smooth); + var itemModel = data.getItemModel(dataIndex); + var emphasisModel = itemModel.getModel('emphasis'); + setStatesStylesFromModel(el, itemModel, 'lineStyle'); + toggleHoverEmphasis(el, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled')); + } // function simpleDiff(oldData, newData, dimensions) { + // let oldLen; + // if (!oldData + // || !oldData.__plProgressive + // || (oldLen = oldData.count()) !== newData.count() + // ) { + // return true; + // } + // let dimLen = dimensions.length; + // for (let i = 0; i < oldLen; i++) { + // for (let j = 0; j < dimLen; j++) { + // if (oldData.get(dimensions[j], i) !== newData.get(dimensions[j], i)) { + // return true; + // } + // } + // } + // return false; + // } + // FIXME put in common util? + + + function isEmptyValue(val, axisType) { + return axisType === 'category' ? val == null : val == null || isNaN(val); // axisType === 'value' + } + + var ParallelSeriesModel = + /** @class */ + function (_super) { + __extends(ParallelSeriesModel, _super); + + function ParallelSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ParallelSeriesModel.type; + _this.visualStyleAccessPath = 'lineStyle'; + _this.visualDrawType = 'stroke'; + return _this; + } + + ParallelSeriesModel.prototype.getInitialData = function (option, ecModel) { + return createSeriesData(null, this, { + useEncodeDefaulter: bind(makeDefaultEncode, null, this) + }); + }; + /** + * User can get data raw indices on 'axisAreaSelected' event received. + * + * @return Raw indices + */ + + + ParallelSeriesModel.prototype.getRawIndicesByActiveState = function (activeState) { + var coordSys = this.coordinateSystem; + var data = this.getData(); + var indices = []; + coordSys.eachActiveState(data, function (theActiveState, dataIndex) { + if (activeState === theActiveState) { + indices.push(data.getRawIndex(dataIndex)); + } + }); + return indices; + }; + + ParallelSeriesModel.type = 'series.parallel'; + ParallelSeriesModel.dependencies = ['parallel']; + ParallelSeriesModel.defaultOption = { + // zlevel: 0, + z: 2, + coordinateSystem: 'parallel', + parallelIndex: 0, + label: { + show: false + }, + inactiveOpacity: 0.05, + activeOpacity: 1, + lineStyle: { + width: 1, + opacity: 0.45, + type: 'solid' + }, + emphasis: { + label: { + show: false + } + }, + progressive: 500, + smooth: false, + animationEasing: 'linear' + }; + return ParallelSeriesModel; + }(SeriesModel); + + function makeDefaultEncode(seriesModel) { + // The mapping of parallelAxis dimension to data dimension can + // be specified in parallelAxis.option.dim. For example, if + // parallelAxis.option.dim is 'dim3', it mapping to the third + // dimension of data. But `data.encode` has higher priority. + // Moreover, parallelModel.dimension should not be regarded as data + // dimensions. Consider dimensions = ['dim4', 'dim2', 'dim6']; + var parallelModel = seriesModel.ecModel.getComponent('parallel', seriesModel.get('parallelIndex')); + + if (!parallelModel) { + return; + } + + var encodeDefine = {}; + each(parallelModel.dimensions, function (axisDim) { + var dataDimIndex = convertDimNameToNumber(axisDim); + encodeDefine[axisDim] = dataDimIndex; + }); + return encodeDefine; + } + + function convertDimNameToNumber(dimName) { + return +dimName.replace('dim', ''); + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + var opacityAccessPath$1 = ['lineStyle', 'opacity']; + var parallelVisual = { + seriesType: 'parallel', + reset: function (seriesModel, ecModel) { + var coordSys = seriesModel.coordinateSystem; + var opacityMap = { + normal: seriesModel.get(['lineStyle', 'opacity']), + active: seriesModel.get('activeOpacity'), + inactive: seriesModel.get('inactiveOpacity') + }; + return { + progress: function (params, data) { + coordSys.eachActiveState(data, function (activeState, dataIndex) { + var opacity = opacityMap[activeState]; + + if (activeState === 'normal' && data.hasItemOption) { + var itemOpacity = data.getItemModel(dataIndex).get(opacityAccessPath$1, true); + itemOpacity != null && (opacity = itemOpacity); + } + + var existsStyle = data.ensureUniqueItemVisual(dataIndex, 'style'); + existsStyle.opacity = opacity; + }, params.start, params.end); + } + }; + } + }; + + function parallelPreprocessor(option) { + createParallelIfNeeded(option); + mergeAxisOptionFromParallel(option); + } + /** + * Create a parallel coordinate if not exists. + * @inner + */ + + function createParallelIfNeeded(option) { + if (option.parallel) { + return; + } + + var hasParallelSeries = false; + each(option.series, function (seriesOpt) { + if (seriesOpt && seriesOpt.type === 'parallel') { + hasParallelSeries = true; + } + }); + + if (hasParallelSeries) { + option.parallel = [{}]; + } + } + /** + * Merge aixs definition from parallel option (if exists) to axis option. + * @inner + */ + + + function mergeAxisOptionFromParallel(option) { + var axes = normalizeToArray(option.parallelAxis); + each(axes, function (axisOption) { + if (!isObject(axisOption)) { + return; + } + + var parallelIndex = axisOption.parallelIndex || 0; + var parallelOption = normalizeToArray(option.parallel)[parallelIndex]; + + if (parallelOption && parallelOption.parallelAxisDefault) { + merge(axisOption, parallelOption.parallelAxisDefault, false); + } + }); + } + + var CLICK_THRESHOLD = 5; // > 4 + + var ParallelView$1 = + /** @class */ + function (_super) { + __extends(ParallelView, _super); + + function ParallelView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ParallelView.type; + return _this; + } + + ParallelView.prototype.render = function (parallelModel, ecModel, api) { + this._model = parallelModel; + this._api = api; + + if (!this._handlers) { + this._handlers = {}; + each(handlers, function (handler, eventName) { + api.getZr().on(eventName, this._handlers[eventName] = bind(handler, this)); + }, this); + } + + createOrUpdate(this, '_throttledDispatchExpand', parallelModel.get('axisExpandRate'), 'fixRate'); + }; + + ParallelView.prototype.dispose = function (ecModel, api) { + clear(this, '_throttledDispatchExpand'); + each(this._handlers, function (handler, eventName) { + api.getZr().off(eventName, handler); + }); + this._handlers = null; + }; + /** + * @internal + * @param {Object} [opt] If null, cancle the last action triggering for debounce. + */ + + + ParallelView.prototype._throttledDispatchExpand = function (opt) { + this._dispatchExpand(opt); + }; + /** + * @internal + */ + + + ParallelView.prototype._dispatchExpand = function (opt) { + opt && this._api.dispatchAction(extend({ + type: 'parallelAxisExpand' + }, opt)); + }; + + ParallelView.type = 'parallel'; + return ParallelView; + }(ComponentView); + + var handlers = { + mousedown: function (e) { + if (checkTrigger(this, 'click')) { + this._mouseDownPoint = [e.offsetX, e.offsetY]; + } + }, + mouseup: function (e) { + var mouseDownPoint = this._mouseDownPoint; + + if (checkTrigger(this, 'click') && mouseDownPoint) { + var point = [e.offsetX, e.offsetY]; + var dist = Math.pow(mouseDownPoint[0] - point[0], 2) + Math.pow(mouseDownPoint[1] - point[1], 2); + + if (dist > CLICK_THRESHOLD) { + return; + } + + var result = this._model.coordinateSystem.getSlidedAxisExpandWindow([e.offsetX, e.offsetY]); + + result.behavior !== 'none' && this._dispatchExpand({ + axisExpandWindow: result.axisExpandWindow + }); + } + + this._mouseDownPoint = null; + }, + mousemove: function (e) { + // Should do nothing when brushing. + if (this._mouseDownPoint || !checkTrigger(this, 'mousemove')) { + return; + } + + var model = this._model; + var result = model.coordinateSystem.getSlidedAxisExpandWindow([e.offsetX, e.offsetY]); + var behavior = result.behavior; + behavior === 'jump' && this._throttledDispatchExpand.debounceNextCall(model.get('axisExpandDebounce')); + + this._throttledDispatchExpand(behavior === 'none' ? null // Cancle the last trigger, in case that mouse slide out of the area quickly. + : { + axisExpandWindow: result.axisExpandWindow, + // Jumping uses animation, and sliding suppresses animation. + animation: behavior === 'jump' ? null : { + duration: 0 // Disable animation. + + } + }); + } + }; + + function checkTrigger(view, triggerOn) { + var model = view._model; + return model.get('axisExpandable') && model.get('axisExpandTriggerOn') === triggerOn; + } + + var ParallelModel = + /** @class */ + function (_super) { + __extends(ParallelModel, _super); + + function ParallelModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ParallelModel.type; + return _this; + } + + ParallelModel.prototype.init = function () { + _super.prototype.init.apply(this, arguments); + + this.mergeOption({}); + }; + + ParallelModel.prototype.mergeOption = function (newOption) { + var thisOption = this.option; + newOption && merge(thisOption, newOption, true); + + this._initDimensions(); + }; + /** + * Whether series or axis is in this coordinate system. + */ + + + ParallelModel.prototype.contains = function (model, ecModel) { + var parallelIndex = model.get('parallelIndex'); + return parallelIndex != null && ecModel.getComponent('parallel', parallelIndex) === this; + }; + + ParallelModel.prototype.setAxisExpand = function (opt) { + each(['axisExpandable', 'axisExpandCenter', 'axisExpandCount', 'axisExpandWidth', 'axisExpandWindow'], function (name) { + if (opt.hasOwnProperty(name)) { + // @ts-ignore FIXME: why "never" inferred in this.option[name]? + this.option[name] = opt[name]; + } + }, this); + }; + + ParallelModel.prototype._initDimensions = function () { + var dimensions = this.dimensions = []; + var parallelAxisIndex = this.parallelAxisIndex = []; + var axisModels = filter(this.ecModel.queryComponents({ + mainType: 'parallelAxis' + }), function (axisModel) { + // Can not use this.contains here, because + // initialization has not been completed yet. + return (axisModel.get('parallelIndex') || 0) === this.componentIndex; + }, this); + each(axisModels, function (axisModel) { + dimensions.push('dim' + axisModel.get('dim')); + parallelAxisIndex.push(axisModel.componentIndex); + }); + }; + + ParallelModel.type = 'parallel'; + ParallelModel.dependencies = ['parallelAxis']; + ParallelModel.layoutMode = 'box'; + ParallelModel.defaultOption = { + // zlevel: 0, + z: 0, + left: 80, + top: 60, + right: 80, + bottom: 60, + // width: {totalWidth} - left - right, + // height: {totalHeight} - top - bottom, + layout: 'horizontal', + // FIXME + // naming? + axisExpandable: false, + axisExpandCenter: null, + axisExpandCount: 0, + axisExpandWidth: 50, + axisExpandRate: 17, + axisExpandDebounce: 50, + // [out, in, jumpTarget]. In percentage. If use [null, 0.05], null means full. + // Do not doc to user until necessary. + axisExpandSlideTriggerArea: [-0.15, 0.05, 0.4], + axisExpandTriggerOn: 'click', + parallelAxisDefault: null + }; + return ParallelModel; + }(ComponentModel); + + var ParallelAxis = + /** @class */ + function (_super) { + __extends(ParallelAxis, _super); + + function ParallelAxis(dim, scale, coordExtent, axisType, axisIndex) { + var _this = _super.call(this, dim, scale, coordExtent) || this; + + _this.type = axisType || 'value'; + _this.axisIndex = axisIndex; + return _this; + } + + ParallelAxis.prototype.isHorizontal = function () { + return this.coordinateSystem.getModel().get('layout') !== 'horizontal'; + }; + + return ParallelAxis; + }(Axis); + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * Calculate slider move result. + * Usage: + * (1) If both handle0 and handle1 are needed to be moved, set minSpan the same as + * maxSpan and the same as `Math.abs(handleEnd[1] - handleEnds[0])`. + * (2) If handle0 is forbidden to cross handle1, set minSpan as `0`. + * + * @param delta Move length. + * @param handleEnds handleEnds[0] can be bigger then handleEnds[1]. + * handleEnds will be modified in this method. + * @param extent handleEnds is restricted by extent. + * extent[0] should less or equals than extent[1]. + * @param handleIndex Can be 'all', means that both move the two handleEnds. + * @param minSpan The range of dataZoom can not be smaller than that. + * If not set, handle0 and cross handle1. If set as a non-negative + * number (including `0`), handles will push each other when reaching + * the minSpan. + * @param maxSpan The range of dataZoom can not be larger than that. + * @return The input handleEnds. + */ + function sliderMove(delta, handleEnds, extent, handleIndex, minSpan, maxSpan) { + delta = delta || 0; + var extentSpan = extent[1] - extent[0]; // Notice maxSpan and minSpan can be null/undefined. + + if (minSpan != null) { + minSpan = restrict(minSpan, [0, extentSpan]); + } + + if (maxSpan != null) { + maxSpan = Math.max(maxSpan, minSpan != null ? minSpan : 0); + } + + if (handleIndex === 'all') { + var handleSpan = Math.abs(handleEnds[1] - handleEnds[0]); + handleSpan = restrict(handleSpan, [0, extentSpan]); + minSpan = maxSpan = restrict(handleSpan, [minSpan, maxSpan]); + handleIndex = 0; + } + + handleEnds[0] = restrict(handleEnds[0], extent); + handleEnds[1] = restrict(handleEnds[1], extent); + var originalDistSign = getSpanSign(handleEnds, handleIndex); + handleEnds[handleIndex] += delta; // Restrict in extent. + + var extentMinSpan = minSpan || 0; + var realExtent = extent.slice(); + originalDistSign.sign < 0 ? realExtent[0] += extentMinSpan : realExtent[1] -= extentMinSpan; + handleEnds[handleIndex] = restrict(handleEnds[handleIndex], realExtent); // Expand span. + + var currDistSign; + currDistSign = getSpanSign(handleEnds, handleIndex); + + if (minSpan != null && (currDistSign.sign !== originalDistSign.sign || currDistSign.span < minSpan)) { + // If minSpan exists, 'cross' is forbidden. + handleEnds[1 - handleIndex] = handleEnds[handleIndex] + originalDistSign.sign * minSpan; + } // Shrink span. + + + currDistSign = getSpanSign(handleEnds, handleIndex); + + if (maxSpan != null && currDistSign.span > maxSpan) { + handleEnds[1 - handleIndex] = handleEnds[handleIndex] + currDistSign.sign * maxSpan; + } + + return handleEnds; + } + + function getSpanSign(handleEnds, handleIndex) { + var dist = handleEnds[handleIndex] - handleEnds[1 - handleIndex]; // If `handleEnds[0] === handleEnds[1]`, always believe that handleEnd[0] + // is at left of handleEnds[1] for non-cross case. + + return { + span: Math.abs(dist), + sign: dist > 0 ? -1 : dist < 0 ? 1 : handleIndex ? -1 : 1 + }; + } + + function restrict(value, extend) { + return Math.min(extend[1] != null ? extend[1] : Infinity, Math.max(extend[0] != null ? extend[0] : -Infinity, value)); + } + + var each$5 = each; + var mathMin$8 = Math.min; + var mathMax$8 = Math.max; + var mathFloor$1 = Math.floor; + var mathCeil$1 = Math.ceil; + var round$3 = round; + var PI$7 = Math.PI; + + var Parallel = + /** @class */ + function () { + function Parallel(parallelModel, ecModel, api) { + this.type = 'parallel'; + /** + * key: dimension + */ + + this._axesMap = createHashMap(); + /** + * key: dimension + * value: {position: [], rotation, } + */ + + this._axesLayout = {}; + this.dimensions = parallelModel.dimensions; + this._model = parallelModel; + + this._init(parallelModel, ecModel, api); + } + + Parallel.prototype._init = function (parallelModel, ecModel, api) { + var dimensions = parallelModel.dimensions; + var parallelAxisIndex = parallelModel.parallelAxisIndex; + each$5(dimensions, function (dim, idx) { + var axisIndex = parallelAxisIndex[idx]; + var axisModel = ecModel.getComponent('parallelAxis', axisIndex); + + var axis = this._axesMap.set(dim, new ParallelAxis(dim, createScaleByModel(axisModel), [0, 0], axisModel.get('type'), axisIndex)); + + var isCategory = axis.type === 'category'; + axis.onBand = isCategory && axisModel.get('boundaryGap'); + axis.inverse = axisModel.get('inverse'); // Injection + + axisModel.axis = axis; + axis.model = axisModel; + axis.coordinateSystem = axisModel.coordinateSystem = this; + }, this); + }; + /** + * Update axis scale after data processed + */ + + + Parallel.prototype.update = function (ecModel, api) { + this._updateAxesFromSeries(this._model, ecModel); + }; + + Parallel.prototype.containPoint = function (point) { + var layoutInfo = this._makeLayoutInfo(); + + var axisBase = layoutInfo.axisBase; + var layoutBase = layoutInfo.layoutBase; + var pixelDimIndex = layoutInfo.pixelDimIndex; + var pAxis = point[1 - pixelDimIndex]; + var pLayout = point[pixelDimIndex]; + return pAxis >= axisBase && pAxis <= axisBase + layoutInfo.axisLength && pLayout >= layoutBase && pLayout <= layoutBase + layoutInfo.layoutLength; + }; + + Parallel.prototype.getModel = function () { + return this._model; + }; + /** + * Update properties from series + */ + + + Parallel.prototype._updateAxesFromSeries = function (parallelModel, ecModel) { + ecModel.eachSeries(function (seriesModel) { + if (!parallelModel.contains(seriesModel, ecModel)) { + return; + } + + var data = seriesModel.getData(); + each$5(this.dimensions, function (dim) { + var axis = this._axesMap.get(dim); + + axis.scale.unionExtentFromData(data, data.mapDimension(dim)); + niceScaleExtent(axis.scale, axis.model); + }, this); + }, this); + }; + /** + * Resize the parallel coordinate system. + */ + + + Parallel.prototype.resize = function (parallelModel, api) { + this._rect = getLayoutRect(parallelModel.getBoxLayoutParams(), { + width: api.getWidth(), + height: api.getHeight() + }); + + this._layoutAxes(); + }; + + Parallel.prototype.getRect = function () { + return this._rect; + }; + + Parallel.prototype._makeLayoutInfo = function () { + var parallelModel = this._model; + var rect = this._rect; + var xy = ['x', 'y']; + var wh = ['width', 'height']; + var layout = parallelModel.get('layout'); + var pixelDimIndex = layout === 'horizontal' ? 0 : 1; + var layoutLength = rect[wh[pixelDimIndex]]; + var layoutExtent = [0, layoutLength]; + var axisCount = this.dimensions.length; + var axisExpandWidth = restrict$1(parallelModel.get('axisExpandWidth'), layoutExtent); + var axisExpandCount = restrict$1(parallelModel.get('axisExpandCount') || 0, [0, axisCount]); + var axisExpandable = parallelModel.get('axisExpandable') && axisCount > 3 && axisCount > axisExpandCount && axisExpandCount > 1 && axisExpandWidth > 0 && layoutLength > 0; // `axisExpandWindow` is According to the coordinates of [0, axisExpandLength], + // for sake of consider the case that axisCollapseWidth is 0 (when screen is narrow), + // where collapsed axes should be overlapped. + + var axisExpandWindow = parallelModel.get('axisExpandWindow'); + var winSize; + + if (!axisExpandWindow) { + winSize = restrict$1(axisExpandWidth * (axisExpandCount - 1), layoutExtent); + var axisExpandCenter = parallelModel.get('axisExpandCenter') || mathFloor$1(axisCount / 2); + axisExpandWindow = [axisExpandWidth * axisExpandCenter - winSize / 2]; + axisExpandWindow[1] = axisExpandWindow[0] + winSize; + } else { + winSize = restrict$1(axisExpandWindow[1] - axisExpandWindow[0], layoutExtent); + axisExpandWindow[1] = axisExpandWindow[0] + winSize; + } + + var axisCollapseWidth = (layoutLength - winSize) / (axisCount - axisExpandCount); // Avoid axisCollapseWidth is too small. + + axisCollapseWidth < 3 && (axisCollapseWidth = 0); // Find the first and last indices > ewin[0] and < ewin[1]. + + var winInnerIndices = [mathFloor$1(round$3(axisExpandWindow[0] / axisExpandWidth, 1)) + 1, mathCeil$1(round$3(axisExpandWindow[1] / axisExpandWidth, 1)) - 1]; // Pos in ec coordinates. + + var axisExpandWindow0Pos = axisCollapseWidth / axisExpandWidth * axisExpandWindow[0]; + return { + layout: layout, + pixelDimIndex: pixelDimIndex, + layoutBase: rect[xy[pixelDimIndex]], + layoutLength: layoutLength, + axisBase: rect[xy[1 - pixelDimIndex]], + axisLength: rect[wh[1 - pixelDimIndex]], + axisExpandable: axisExpandable, + axisExpandWidth: axisExpandWidth, + axisCollapseWidth: axisCollapseWidth, + axisExpandWindow: axisExpandWindow, + axisCount: axisCount, + winInnerIndices: winInnerIndices, + axisExpandWindow0Pos: axisExpandWindow0Pos + }; + }; + + Parallel.prototype._layoutAxes = function () { + var rect = this._rect; + var axes = this._axesMap; + var dimensions = this.dimensions; + + var layoutInfo = this._makeLayoutInfo(); + + var layout = layoutInfo.layout; + axes.each(function (axis) { + var axisExtent = [0, layoutInfo.axisLength]; + var idx = axis.inverse ? 1 : 0; + axis.setExtent(axisExtent[idx], axisExtent[1 - idx]); + }); + each$5(dimensions, function (dim, idx) { + var posInfo = (layoutInfo.axisExpandable ? layoutAxisWithExpand : layoutAxisWithoutExpand)(idx, layoutInfo); + var positionTable = { + horizontal: { + x: posInfo.position, + y: layoutInfo.axisLength + }, + vertical: { + x: 0, + y: posInfo.position + } + }; + var rotationTable = { + horizontal: PI$7 / 2, + vertical: 0 + }; + var position = [positionTable[layout].x + rect.x, positionTable[layout].y + rect.y]; + var rotation = rotationTable[layout]; + var transform = create$1(); + rotate(transform, transform, rotation); + translate(transform, transform, position); // TODO + // tick layout info + // TODO + // update dimensions info based on axis order. + + this._axesLayout[dim] = { + position: position, + rotation: rotation, + transform: transform, + axisNameAvailableWidth: posInfo.axisNameAvailableWidth, + axisLabelShow: posInfo.axisLabelShow, + nameTruncateMaxWidth: posInfo.nameTruncateMaxWidth, + tickDirection: 1, + labelDirection: 1 + }; + }, this); + }; + /** + * Get axis by dim. + */ + + + Parallel.prototype.getAxis = function (dim) { + return this._axesMap.get(dim); + }; + /** + * Convert a dim value of a single item of series data to Point. + */ + + + Parallel.prototype.dataToPoint = function (value, dim) { + return this.axisCoordToPoint(this._axesMap.get(dim).dataToCoord(value), dim); + }; + /** + * Travel data for one time, get activeState of each data item. + * @param start the start dataIndex that travel from. + * @param end the next dataIndex of the last dataIndex will be travel. + */ + + + Parallel.prototype.eachActiveState = function (data, callback, start, end) { + start == null && (start = 0); + end == null && (end = data.count()); + var axesMap = this._axesMap; + var dimensions = this.dimensions; + var dataDimensions = []; + var axisModels = []; + each(dimensions, function (axisDim) { + dataDimensions.push(data.mapDimension(axisDim)); + axisModels.push(axesMap.get(axisDim).model); + }); + var hasActiveSet = this.hasAxisBrushed(); + + for (var dataIndex = start; dataIndex < end; dataIndex++) { + var activeState = void 0; + + if (!hasActiveSet) { + activeState = 'normal'; + } else { + activeState = 'active'; + var values = data.getValues(dataDimensions, dataIndex); + + for (var j = 0, lenj = dimensions.length; j < lenj; j++) { + var state = axisModels[j].getActiveState(values[j]); + + if (state === 'inactive') { + activeState = 'inactive'; + break; + } + } + } + + callback(activeState, dataIndex); + } + }; + /** + * Whether has any activeSet. + */ + + + Parallel.prototype.hasAxisBrushed = function () { + var dimensions = this.dimensions; + var axesMap = this._axesMap; + var hasActiveSet = false; + + for (var j = 0, lenj = dimensions.length; j < lenj; j++) { + if (axesMap.get(dimensions[j]).model.getActiveState() !== 'normal') { + hasActiveSet = true; + } + } + + return hasActiveSet; + }; + /** + * Convert coords of each axis to Point. + * Return point. For example: [10, 20] + */ + + + Parallel.prototype.axisCoordToPoint = function (coord, dim) { + var axisLayout = this._axesLayout[dim]; + return applyTransform$1([coord, 0], axisLayout.transform); + }; + /** + * Get axis layout. + */ + + + Parallel.prototype.getAxisLayout = function (dim) { + return clone(this._axesLayout[dim]); + }; + /** + * @return {Object} {axisExpandWindow, delta, behavior: 'jump' | 'slide' | 'none'}. + */ + + + Parallel.prototype.getSlidedAxisExpandWindow = function (point) { + var layoutInfo = this._makeLayoutInfo(); + + var pixelDimIndex = layoutInfo.pixelDimIndex; + var axisExpandWindow = layoutInfo.axisExpandWindow.slice(); + var winSize = axisExpandWindow[1] - axisExpandWindow[0]; + var extent = [0, layoutInfo.axisExpandWidth * (layoutInfo.axisCount - 1)]; // Out of the area of coordinate system. + + if (!this.containPoint(point)) { + return { + behavior: 'none', + axisExpandWindow: axisExpandWindow + }; + } // Conver the point from global to expand coordinates. + + + var pointCoord = point[pixelDimIndex] - layoutInfo.layoutBase - layoutInfo.axisExpandWindow0Pos; // For dragging operation convenience, the window should not be + // slided when mouse is the center area of the window. + + var delta; + var behavior = 'slide'; + var axisCollapseWidth = layoutInfo.axisCollapseWidth; + + var triggerArea = this._model.get('axisExpandSlideTriggerArea'); // But consider touch device, jump is necessary. + + + var useJump = triggerArea[0] != null; + + if (axisCollapseWidth) { + if (useJump && axisCollapseWidth && pointCoord < winSize * triggerArea[0]) { + behavior = 'jump'; + delta = pointCoord - winSize * triggerArea[2]; + } else if (useJump && axisCollapseWidth && pointCoord > winSize * (1 - triggerArea[0])) { + behavior = 'jump'; + delta = pointCoord - winSize * (1 - triggerArea[2]); + } else { + (delta = pointCoord - winSize * triggerArea[1]) >= 0 && (delta = pointCoord - winSize * (1 - triggerArea[1])) <= 0 && (delta = 0); + } + + delta *= layoutInfo.axisExpandWidth / axisCollapseWidth; + delta ? sliderMove(delta, axisExpandWindow, extent, 'all') // Avoid nonsense triger on mousemove. + : behavior = 'none'; + } // When screen is too narrow, make it visible and slidable, although it is hard to interact. + else { + var winSize2 = axisExpandWindow[1] - axisExpandWindow[0]; + var pos = extent[1] * pointCoord / winSize2; + axisExpandWindow = [mathMax$8(0, pos - winSize2 / 2)]; + axisExpandWindow[1] = mathMin$8(extent[1], axisExpandWindow[0] + winSize2); + axisExpandWindow[0] = axisExpandWindow[1] - winSize2; + } + + return { + axisExpandWindow: axisExpandWindow, + behavior: behavior + }; + }; + + return Parallel; + }(); + + function restrict$1(len, extent) { + return mathMin$8(mathMax$8(len, extent[0]), extent[1]); + } + + function layoutAxisWithoutExpand(axisIndex, layoutInfo) { + var step = layoutInfo.layoutLength / (layoutInfo.axisCount - 1); + return { + position: step * axisIndex, + axisNameAvailableWidth: step, + axisLabelShow: true + }; + } + + function layoutAxisWithExpand(axisIndex, layoutInfo) { + var layoutLength = layoutInfo.layoutLength; + var axisExpandWidth = layoutInfo.axisExpandWidth; + var axisCount = layoutInfo.axisCount; + var axisCollapseWidth = layoutInfo.axisCollapseWidth; + var winInnerIndices = layoutInfo.winInnerIndices; + var position; + var axisNameAvailableWidth = axisCollapseWidth; + var axisLabelShow = false; + var nameTruncateMaxWidth; + + if (axisIndex < winInnerIndices[0]) { + position = axisIndex * axisCollapseWidth; + nameTruncateMaxWidth = axisCollapseWidth; + } else if (axisIndex <= winInnerIndices[1]) { + position = layoutInfo.axisExpandWindow0Pos + axisIndex * axisExpandWidth - layoutInfo.axisExpandWindow[0]; + axisNameAvailableWidth = axisExpandWidth; + axisLabelShow = true; + } else { + position = layoutLength - (axisCount - 1 - axisIndex) * axisCollapseWidth; + nameTruncateMaxWidth = axisCollapseWidth; + } + + return { + position: position, + axisNameAvailableWidth: axisNameAvailableWidth, + axisLabelShow: axisLabelShow, + nameTruncateMaxWidth: nameTruncateMaxWidth + }; + } + + function createParallelCoordSys(ecModel, api) { + var coordSysList = []; + ecModel.eachComponent('parallel', function (parallelModel, idx) { + var coordSys = new Parallel(parallelModel, ecModel, api); + coordSys.name = 'parallel_' + idx; + coordSys.resize(parallelModel, api); + parallelModel.coordinateSystem = coordSys; + coordSys.model = parallelModel; + coordSysList.push(coordSys); + }); // Inject the coordinateSystems into seriesModel + + ecModel.eachSeries(function (seriesModel) { + if (seriesModel.get('coordinateSystem') === 'parallel') { + var parallelModel = seriesModel.getReferringComponents('parallel', SINGLE_REFERRING).models[0]; + seriesModel.coordinateSystem = parallelModel.coordinateSystem; + } + }); + return coordSysList; + } + + var parallelCoordSysCreator = { + create: createParallelCoordSys + }; + + var ParallelAxisModel = + /** @class */ + function (_super) { + __extends(ParallelAxisModel, _super); + + function ParallelAxisModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ParallelAxisModel.type; + /** + * @readOnly + */ + + _this.activeIntervals = []; + return _this; + } + + ParallelAxisModel.prototype.getAreaSelectStyle = function () { + return makeStyleMapper([['fill', 'color'], ['lineWidth', 'borderWidth'], ['stroke', 'borderColor'], ['width', 'width'], ['opacity', 'opacity'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`. + // So do not transfer decal directly. + ])(this.getModel('areaSelectStyle')); + }; + /** + * The code of this feature is put on AxisModel but not ParallelAxis, + * because axisModel can be alive after echarts updating but instance of + * ParallelAxis having been disposed. this._activeInterval should be kept + * when action dispatched (i.e. legend click). + * + * @param intervals `interval.length === 0` means set all active. + */ + + + ParallelAxisModel.prototype.setActiveIntervals = function (intervals) { + var activeIntervals = this.activeIntervals = clone(intervals); // Normalize + + if (activeIntervals) { + for (var i = activeIntervals.length - 1; i >= 0; i--) { + asc(activeIntervals[i]); + } + } + }; + /** + * @param value When only attempting detect whether 'no activeIntervals set', + * `value` is not needed to be input. + */ + + + ParallelAxisModel.prototype.getActiveState = function (value) { + var activeIntervals = this.activeIntervals; + + if (!activeIntervals.length) { + return 'normal'; + } + + if (value == null || isNaN(+value)) { + return 'inactive'; + } // Simple optimization + + + if (activeIntervals.length === 1) { + var interval = activeIntervals[0]; + + if (interval[0] <= value && value <= interval[1]) { + return 'active'; + } + } else { + for (var i = 0, len = activeIntervals.length; i < len; i++) { + if (activeIntervals[i][0] <= value && value <= activeIntervals[i][1]) { + return 'active'; + } + } + } + + return 'inactive'; + }; + + return ParallelAxisModel; + }(ComponentModel); + + mixin(ParallelAxisModel, AxisModelCommonMixin); + + var BRUSH_PANEL_GLOBAL = true; + var mathMin$9 = Math.min; + var mathMax$9 = Math.max; + var mathPow$2 = Math.pow; + var COVER_Z = 10000; + var UNSELECT_THRESHOLD = 6; + var MIN_RESIZE_LINE_WIDTH = 6; + var MUTEX_RESOURCE_KEY = 'globalPan'; + var DIRECTION_MAP = { + w: [0, 0], + e: [0, 1], + n: [1, 0], + s: [1, 1] + }; + var CURSOR_MAP = { + w: 'ew', + e: 'ew', + n: 'ns', + s: 'ns', + ne: 'nesw', + sw: 'nesw', + nw: 'nwse', + se: 'nwse' + }; + var DEFAULT_BRUSH_OPT = { + brushStyle: { + lineWidth: 2, + stroke: 'rgba(210,219,238,0.3)', + fill: '#D2DBEE' + }, + transformable: true, + brushMode: 'single', + removeOnClick: false + }; + var baseUID = 0; + /** + * params: + * areas: Array., coord relates to container group, + * If no container specified, to global. + * opt { + * isEnd: boolean, + * removeOnClick: boolean + * } + */ + + var BrushController = + /** @class */ + function (_super) { + __extends(BrushController, _super); + + function BrushController(zr) { + var _this = _super.call(this) || this; + /** + * @internal + */ + + + _this._track = []; + /** + * @internal + */ + + _this._covers = []; + _this._handlers = {}; + + if ("development" !== 'production') { + assert(zr); + } + + _this._zr = zr; + _this.group = new Group(); + _this._uid = 'brushController_' + baseUID++; + each(pointerHandlers, function (handler, eventName) { + this._handlers[eventName] = bind(handler, this); + }, _this); + return _this; + } + /** + * If set to `false`, select disabled. + */ + + + BrushController.prototype.enableBrush = function (brushOption) { + if ("development" !== 'production') { + assert(this._mounted); + } + + this._brushType && this._doDisableBrush(); + brushOption.brushType && this._doEnableBrush(brushOption); + return this; + }; + + BrushController.prototype._doEnableBrush = function (brushOption) { + var zr = this._zr; // Consider roam, which takes globalPan too. + + if (!this._enableGlobalPan) { + take(zr, MUTEX_RESOURCE_KEY, this._uid); + } + + each(this._handlers, function (handler, eventName) { + zr.on(eventName, handler); + }); + this._brushType = brushOption.brushType; + this._brushOption = merge(clone(DEFAULT_BRUSH_OPT), brushOption, true); + }; + + BrushController.prototype._doDisableBrush = function () { + var zr = this._zr; + release(zr, MUTEX_RESOURCE_KEY, this._uid); + each(this._handlers, function (handler, eventName) { + zr.off(eventName, handler); + }); + this._brushType = this._brushOption = null; + }; + /** + * @param panelOpts If not pass, it is global brush. + */ + + + BrushController.prototype.setPanels = function (panelOpts) { + if (panelOpts && panelOpts.length) { + var panels_1 = this._panels = {}; + each(panelOpts, function (panelOpts) { + panels_1[panelOpts.panelId] = clone(panelOpts); + }); + } else { + this._panels = null; + } + + return this; + }; + + BrushController.prototype.mount = function (opt) { + opt = opt || {}; + + if ("development" !== 'production') { + this._mounted = true; // should be at first. + } + + this._enableGlobalPan = opt.enableGlobalPan; + var thisGroup = this.group; + + this._zr.add(thisGroup); + + thisGroup.attr({ + x: opt.x || 0, + y: opt.y || 0, + rotation: opt.rotation || 0, + scaleX: opt.scaleX || 1, + scaleY: opt.scaleY || 1 + }); + this._transform = thisGroup.getLocalTransform(); + return this; + }; // eachCover(cb, context): void { + // each(this._covers, cb, context); + // } + + /** + * Update covers. + * @param coverConfigList + * If coverConfigList is null/undefined, all covers removed. + */ + + + BrushController.prototype.updateCovers = function (coverConfigList) { + if ("development" !== 'production') { + assert(this._mounted); + } + + coverConfigList = map(coverConfigList, function (coverConfig) { + return merge(clone(DEFAULT_BRUSH_OPT), coverConfig, true); + }); + var tmpIdPrefix = '\0-brush-index-'; + var oldCovers = this._covers; + var newCovers = this._covers = []; + var controller = this; + var creatingCover = this._creatingCover; + new DataDiffer(oldCovers, coverConfigList, oldGetKey, getKey).add(addOrUpdate).update(addOrUpdate).remove(remove).execute(); + return this; + + function getKey(brushOption, index) { + return (brushOption.id != null ? brushOption.id : tmpIdPrefix + index) + '-' + brushOption.brushType; + } + + function oldGetKey(cover, index) { + return getKey(cover.__brushOption, index); + } + + function addOrUpdate(newIndex, oldIndex) { + var newBrushInternal = coverConfigList[newIndex]; // Consider setOption in event listener of brushSelect, + // where updating cover when creating should be forbiden. + + if (oldIndex != null && oldCovers[oldIndex] === creatingCover) { + newCovers[newIndex] = oldCovers[oldIndex]; + } else { + var cover = newCovers[newIndex] = oldIndex != null ? (oldCovers[oldIndex].__brushOption = newBrushInternal, oldCovers[oldIndex]) : endCreating(controller, createCover(controller, newBrushInternal)); + updateCoverAfterCreation(controller, cover); + } + } + + function remove(oldIndex) { + if (oldCovers[oldIndex] !== creatingCover) { + controller.group.remove(oldCovers[oldIndex]); + } + } + }; + + BrushController.prototype.unmount = function () { + if ("development" !== 'production') { + if (!this._mounted) { + return; + } + } + + this.enableBrush(false); // container may 'removeAll' outside. + + clearCovers(this); + + this._zr.remove(this.group); + + if ("development" !== 'production') { + this._mounted = false; // should be at last. + } + + return this; + }; + + BrushController.prototype.dispose = function () { + this.unmount(); + this.off(); + }; + + return BrushController; + }(Eventful); + + function createCover(controller, brushOption) { + var cover = coverRenderers[brushOption.brushType].createCover(controller, brushOption); + cover.__brushOption = brushOption; + updateZ(cover, brushOption); + controller.group.add(cover); + return cover; + } + + function endCreating(controller, creatingCover) { + var coverRenderer = getCoverRenderer(creatingCover); + + if (coverRenderer.endCreating) { + coverRenderer.endCreating(controller, creatingCover); + updateZ(creatingCover, creatingCover.__brushOption); + } + + return creatingCover; + } + + function updateCoverShape(controller, cover) { + var brushOption = cover.__brushOption; + getCoverRenderer(cover).updateCoverShape(controller, cover, brushOption.range, brushOption); + } + + function updateZ(cover, brushOption) { + var z = brushOption.z; + z == null && (z = COVER_Z); + cover.traverse(function (el) { + el.z = z; + el.z2 = z; // Consider in given container. + }); + } + + function updateCoverAfterCreation(controller, cover) { + getCoverRenderer(cover).updateCommon(controller, cover); + updateCoverShape(controller, cover); + } + + function getCoverRenderer(cover) { + return coverRenderers[cover.__brushOption.brushType]; + } // return target panel or `true` (means global panel) + + + function getPanelByPoint(controller, e, localCursorPoint) { + var panels = controller._panels; + + if (!panels) { + return BRUSH_PANEL_GLOBAL; // Global panel + } + + var panel; + var transform = controller._transform; + each(panels, function (pn) { + pn.isTargetByCursor(e, localCursorPoint, transform) && (panel = pn); + }); + return panel; + } // Return a panel or true + + + function getPanelByCover(controller, cover) { + var panels = controller._panels; + + if (!panels) { + return BRUSH_PANEL_GLOBAL; // Global panel + } + + var panelId = cover.__brushOption.panelId; // User may give cover without coord sys info, + // which is then treated as global panel. + + return panelId != null ? panels[panelId] : BRUSH_PANEL_GLOBAL; + } + + function clearCovers(controller) { + var covers = controller._covers; + var originalLength = covers.length; + each(covers, function (cover) { + controller.group.remove(cover); + }, controller); + covers.length = 0; + return !!originalLength; + } + + function trigger$1(controller, opt) { + var areas = map(controller._covers, function (cover) { + var brushOption = cover.__brushOption; + var range = clone(brushOption.range); + return { + brushType: brushOption.brushType, + panelId: brushOption.panelId, + range: range + }; + }); + controller.trigger('brush', { + areas: areas, + isEnd: !!opt.isEnd, + removeOnClick: !!opt.removeOnClick + }); + } + + function shouldShowCover(controller) { + var track = controller._track; + + if (!track.length) { + return false; + } + + var p2 = track[track.length - 1]; + var p1 = track[0]; + var dx = p2[0] - p1[0]; + var dy = p2[1] - p1[1]; + var dist = mathPow$2(dx * dx + dy * dy, 0.5); + return dist > UNSELECT_THRESHOLD; + } + + function getTrackEnds(track) { + var tail = track.length - 1; + tail < 0 && (tail = 0); + return [track[0], track[tail]]; + } + + function createBaseRectCover(rectRangeConverter, controller, brushOption, edgeNameSequences) { + var cover = new Group(); + cover.add(new Rect({ + name: 'main', + style: makeStyle(brushOption), + silent: true, + draggable: true, + cursor: 'move', + drift: curry(driftRect, rectRangeConverter, controller, cover, ['n', 's', 'w', 'e']), + ondragend: curry(trigger$1, controller, { + isEnd: true + }) + })); + each(edgeNameSequences, function (nameSequence) { + cover.add(new Rect({ + name: nameSequence.join(''), + style: { + opacity: 0 + }, + draggable: true, + silent: true, + invisible: true, + drift: curry(driftRect, rectRangeConverter, controller, cover, nameSequence), + ondragend: curry(trigger$1, controller, { + isEnd: true + }) + })); + }); + return cover; + } + + function updateBaseRect(controller, cover, localRange, brushOption) { + var lineWidth = brushOption.brushStyle.lineWidth || 0; + var handleSize = mathMax$9(lineWidth, MIN_RESIZE_LINE_WIDTH); + var x = localRange[0][0]; + var y = localRange[1][0]; + var xa = x - lineWidth / 2; + var ya = y - lineWidth / 2; + var x2 = localRange[0][1]; + var y2 = localRange[1][1]; + var x2a = x2 - handleSize + lineWidth / 2; + var y2a = y2 - handleSize + lineWidth / 2; + var width = x2 - x; + var height = y2 - y; + var widtha = width + lineWidth; + var heighta = height + lineWidth; + updateRectShape(controller, cover, 'main', x, y, width, height); + + if (brushOption.transformable) { + updateRectShape(controller, cover, 'w', xa, ya, handleSize, heighta); + updateRectShape(controller, cover, 'e', x2a, ya, handleSize, heighta); + updateRectShape(controller, cover, 'n', xa, ya, widtha, handleSize); + updateRectShape(controller, cover, 's', xa, y2a, widtha, handleSize); + updateRectShape(controller, cover, 'nw', xa, ya, handleSize, handleSize); + updateRectShape(controller, cover, 'ne', x2a, ya, handleSize, handleSize); + updateRectShape(controller, cover, 'sw', xa, y2a, handleSize, handleSize); + updateRectShape(controller, cover, 'se', x2a, y2a, handleSize, handleSize); + } + } + + function updateCommon(controller, cover) { + var brushOption = cover.__brushOption; + var transformable = brushOption.transformable; + var mainEl = cover.childAt(0); + mainEl.useStyle(makeStyle(brushOption)); + mainEl.attr({ + silent: !transformable, + cursor: transformable ? 'move' : 'default' + }); + each([['w'], ['e'], ['n'], ['s'], ['s', 'e'], ['s', 'w'], ['n', 'e'], ['n', 'w']], function (nameSequence) { + var el = cover.childOfName(nameSequence.join('')); + var globalDir = nameSequence.length === 1 ? getGlobalDirection1(controller, nameSequence[0]) : getGlobalDirection2(controller, nameSequence); + el && el.attr({ + silent: !transformable, + invisible: !transformable, + cursor: transformable ? CURSOR_MAP[globalDir] + '-resize' : null + }); + }); + } + + function updateRectShape(controller, cover, name, x, y, w, h) { + var el = cover.childOfName(name); + el && el.setShape(pointsToRect(clipByPanel(controller, cover, [[x, y], [x + w, y + h]]))); + } + + function makeStyle(brushOption) { + return defaults({ + strokeNoScale: true + }, brushOption.brushStyle); + } + + function formatRectRange(x, y, x2, y2) { + var min = [mathMin$9(x, x2), mathMin$9(y, y2)]; + var max = [mathMax$9(x, x2), mathMax$9(y, y2)]; + return [[min[0], max[0]], [min[1], max[1]] // y range + ]; + } + + function getTransform$1(controller) { + return getTransform(controller.group); + } + + function getGlobalDirection1(controller, localDirName) { + var map = { + w: 'left', + e: 'right', + n: 'top', + s: 'bottom' + }; + var inverseMap = { + left: 'w', + right: 'e', + top: 'n', + bottom: 's' + }; + var dir = transformDirection(map[localDirName], getTransform$1(controller)); + return inverseMap[dir]; + } + + function getGlobalDirection2(controller, localDirNameSeq) { + var globalDir = [getGlobalDirection1(controller, localDirNameSeq[0]), getGlobalDirection1(controller, localDirNameSeq[1])]; + (globalDir[0] === 'e' || globalDir[0] === 'w') && globalDir.reverse(); + return globalDir.join(''); + } + + function driftRect(rectRangeConverter, controller, cover, dirNameSequence, dx, dy) { + var brushOption = cover.__brushOption; + var rectRange = rectRangeConverter.toRectRange(brushOption.range); + var localDelta = toLocalDelta(controller, dx, dy); + each(dirNameSequence, function (dirName) { + var ind = DIRECTION_MAP[dirName]; + rectRange[ind[0]][ind[1]] += localDelta[ind[0]]; + }); + brushOption.range = rectRangeConverter.fromRectRange(formatRectRange(rectRange[0][0], rectRange[1][0], rectRange[0][1], rectRange[1][1])); + updateCoverAfterCreation(controller, cover); + trigger$1(controller, { + isEnd: false + }); + } + + function driftPolygon(controller, cover, dx, dy) { + var range = cover.__brushOption.range; + var localDelta = toLocalDelta(controller, dx, dy); + each(range, function (point) { + point[0] += localDelta[0]; + point[1] += localDelta[1]; + }); + updateCoverAfterCreation(controller, cover); + trigger$1(controller, { + isEnd: false + }); + } + + function toLocalDelta(controller, dx, dy) { + var thisGroup = controller.group; + var localD = thisGroup.transformCoordToLocal(dx, dy); + var localZero = thisGroup.transformCoordToLocal(0, 0); + return [localD[0] - localZero[0], localD[1] - localZero[1]]; + } + + function clipByPanel(controller, cover, data) { + var panel = getPanelByCover(controller, cover); + return panel && panel !== BRUSH_PANEL_GLOBAL ? panel.clipPath(data, controller._transform) : clone(data); + } + + function pointsToRect(points) { + var xmin = mathMin$9(points[0][0], points[1][0]); + var ymin = mathMin$9(points[0][1], points[1][1]); + var xmax = mathMax$9(points[0][0], points[1][0]); + var ymax = mathMax$9(points[0][1], points[1][1]); + return { + x: xmin, + y: ymin, + width: xmax - xmin, + height: ymax - ymin + }; + } + + function resetCursor(controller, e, localCursorPoint) { + if ( // Check active + !controller._brushType // resetCursor should be always called when mouse is in zr area, + // but not called when mouse is out of zr area to avoid bad influence + // if `mousemove`, `mouseup` are triggered from `document` event. + || isOutsideZrArea(controller, e.offsetX, e.offsetY)) { + return; + } + + var zr = controller._zr; + var covers = controller._covers; + var currPanel = getPanelByPoint(controller, e, localCursorPoint); // Check whether in covers. + + if (!controller._dragging) { + for (var i = 0; i < covers.length; i++) { + var brushOption = covers[i].__brushOption; + + if (currPanel && (currPanel === BRUSH_PANEL_GLOBAL || brushOption.panelId === currPanel.panelId) && coverRenderers[brushOption.brushType].contain(covers[i], localCursorPoint[0], localCursorPoint[1])) { + // Use cursor style set on cover. + return; + } + } + } + + currPanel && zr.setCursorStyle('crosshair'); + } + + function preventDefault(e) { + var rawE = e.event; + rawE.preventDefault && rawE.preventDefault(); + } + + function mainShapeContain(cover, x, y) { + return cover.childOfName('main').contain(x, y); + } + + function updateCoverByMouse(controller, e, localCursorPoint, isEnd) { + var creatingCover = controller._creatingCover; + var panel = controller._creatingPanel; + var thisBrushOption = controller._brushOption; + var eventParams; + + controller._track.push(localCursorPoint.slice()); + + if (shouldShowCover(controller) || creatingCover) { + if (panel && !creatingCover) { + thisBrushOption.brushMode === 'single' && clearCovers(controller); + var brushOption = clone(thisBrushOption); + brushOption.brushType = determineBrushType(brushOption.brushType, panel); + brushOption.panelId = panel === BRUSH_PANEL_GLOBAL ? null : panel.panelId; + creatingCover = controller._creatingCover = createCover(controller, brushOption); + + controller._covers.push(creatingCover); + } + + if (creatingCover) { + var coverRenderer = coverRenderers[determineBrushType(controller._brushType, panel)]; + var coverBrushOption = creatingCover.__brushOption; + coverBrushOption.range = coverRenderer.getCreatingRange(clipByPanel(controller, creatingCover, controller._track)); + + if (isEnd) { + endCreating(controller, creatingCover); + coverRenderer.updateCommon(controller, creatingCover); + } + + updateCoverShape(controller, creatingCover); + eventParams = { + isEnd: isEnd + }; + } + } else if (isEnd && thisBrushOption.brushMode === 'single' && thisBrushOption.removeOnClick) { + // Help user to remove covers easily, only by a tiny drag, in 'single' mode. + // But a single click do not clear covers, because user may have casual + // clicks (for example, click on other component and do not expect covers + // disappear). + // Only some cover removed, trigger action, but not every click trigger action. + if (getPanelByPoint(controller, e, localCursorPoint) && clearCovers(controller)) { + eventParams = { + isEnd: isEnd, + removeOnClick: true + }; + } + } + + return eventParams; + } + + function determineBrushType(brushType, panel) { + if (brushType === 'auto') { + if ("development" !== 'production') { + assert(panel && panel.defaultBrushType, 'MUST have defaultBrushType when brushType is "atuo"'); + } + + return panel.defaultBrushType; + } + + return brushType; + } + + var pointerHandlers = { + mousedown: function (e) { + if (this._dragging) { + // In case some browser do not support globalOut, + // and release mouse out side the browser. + handleDragEnd(this, e); + } else if (!e.target || !e.target.draggable) { + preventDefault(e); + var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY); + this._creatingCover = null; + var panel = this._creatingPanel = getPanelByPoint(this, e, localCursorPoint); + + if (panel) { + this._dragging = true; + this._track = [localCursorPoint.slice()]; + } + } + }, + mousemove: function (e) { + var x = e.offsetX; + var y = e.offsetY; + var localCursorPoint = this.group.transformCoordToLocal(x, y); + resetCursor(this, e, localCursorPoint); + + if (this._dragging) { + preventDefault(e); + var eventParams = updateCoverByMouse(this, e, localCursorPoint, false); + eventParams && trigger$1(this, eventParams); + } + }, + mouseup: function (e) { + handleDragEnd(this, e); + } + }; + + function handleDragEnd(controller, e) { + if (controller._dragging) { + preventDefault(e); + var x = e.offsetX; + var y = e.offsetY; + var localCursorPoint = controller.group.transformCoordToLocal(x, y); + var eventParams = updateCoverByMouse(controller, e, localCursorPoint, true); + controller._dragging = false; + controller._track = []; + controller._creatingCover = null; // trigger event shoule be at final, after procedure will be nested. + + eventParams && trigger$1(controller, eventParams); + } + } + + function isOutsideZrArea(controller, x, y) { + var zr = controller._zr; + return x < 0 || x > zr.getWidth() || y < 0 || y > zr.getHeight(); + } + /** + * key: brushType + */ + + + var coverRenderers = { + lineX: getLineRenderer(0), + lineY: getLineRenderer(1), + rect: { + createCover: function (controller, brushOption) { + function returnInput(range) { + return range; + } + + return createBaseRectCover({ + toRectRange: returnInput, + fromRectRange: returnInput + }, controller, brushOption, [['w'], ['e'], ['n'], ['s'], ['s', 'e'], ['s', 'w'], ['n', 'e'], ['n', 'w']]); + }, + getCreatingRange: function (localTrack) { + var ends = getTrackEnds(localTrack); + return formatRectRange(ends[1][0], ends[1][1], ends[0][0], ends[0][1]); + }, + updateCoverShape: function (controller, cover, localRange, brushOption) { + updateBaseRect(controller, cover, localRange, brushOption); + }, + updateCommon: updateCommon, + contain: mainShapeContain + }, + polygon: { + createCover: function (controller, brushOption) { + var cover = new Group(); // Do not use graphic.Polygon because graphic.Polyline do not close the + // border of the shape when drawing, which is a better experience for user. + + cover.add(new Polyline({ + name: 'main', + style: makeStyle(brushOption), + silent: true + })); + return cover; + }, + getCreatingRange: function (localTrack) { + return localTrack; + }, + endCreating: function (controller, cover) { + cover.remove(cover.childAt(0)); // Use graphic.Polygon close the shape. + + cover.add(new Polygon({ + name: 'main', + draggable: true, + drift: curry(driftPolygon, controller, cover), + ondragend: curry(trigger$1, controller, { + isEnd: true + }) + })); + }, + updateCoverShape: function (controller, cover, localRange, brushOption) { + cover.childAt(0).setShape({ + points: clipByPanel(controller, cover, localRange) + }); + }, + updateCommon: updateCommon, + contain: mainShapeContain + } + }; + + function getLineRenderer(xyIndex) { + return { + createCover: function (controller, brushOption) { + return createBaseRectCover({ + toRectRange: function (range) { + var rectRange = [range, [0, 100]]; + xyIndex && rectRange.reverse(); + return rectRange; + }, + fromRectRange: function (rectRange) { + return rectRange[xyIndex]; + } + }, controller, brushOption, [[['w'], ['e']], [['n'], ['s']]][xyIndex]); + }, + getCreatingRange: function (localTrack) { + var ends = getTrackEnds(localTrack); + var min = mathMin$9(ends[0][xyIndex], ends[1][xyIndex]); + var max = mathMax$9(ends[0][xyIndex], ends[1][xyIndex]); + return [min, max]; + }, + updateCoverShape: function (controller, cover, localRange, brushOption) { + var otherExtent; // If brushWidth not specified, fit the panel. + + var panel = getPanelByCover(controller, cover); + + if (panel !== BRUSH_PANEL_GLOBAL && panel.getLinearBrushOtherExtent) { + otherExtent = panel.getLinearBrushOtherExtent(xyIndex); + } else { + var zr = controller._zr; + otherExtent = [0, [zr.getWidth(), zr.getHeight()][1 - xyIndex]]; + } + + var rectRange = [localRange, otherExtent]; + xyIndex && rectRange.reverse(); + updateBaseRect(controller, cover, rectRange, brushOption); + }, + updateCommon: updateCommon, + contain: mainShapeContain + }; + } + + function makeRectPanelClipPath(rect) { + rect = normalizeRect(rect); + return function (localPoints) { + return clipPointsByRect(localPoints, rect); + }; + } + function makeLinearBrushOtherExtent(rect, specifiedXYIndex) { + rect = normalizeRect(rect); + return function (xyIndex) { + var idx = specifiedXYIndex != null ? specifiedXYIndex : xyIndex; + var brushWidth = idx ? rect.width : rect.height; + var base = idx ? rect.x : rect.y; + return [base, base + (brushWidth || 0)]; + }; + } + function makeRectIsTargetByCursor(rect, api, targetModel) { + var boundingRect = normalizeRect(rect); + return function (e, localCursorPoint) { + return boundingRect.contain(localCursorPoint[0], localCursorPoint[1]) && !onIrrelevantElement(e, api, targetModel); + }; + } // Consider width/height is negative. + + function normalizeRect(rect) { + return BoundingRect.create(rect); + } + + var elementList = ['axisLine', 'axisTickLabel', 'axisName']; + + var ParallelAxisView = + /** @class */ + function (_super) { + __extends(ParallelAxisView, _super); + + function ParallelAxisView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ParallelAxisView.type; + return _this; + } + + ParallelAxisView.prototype.init = function (ecModel, api) { + _super.prototype.init.apply(this, arguments); + + (this._brushController = new BrushController(api.getZr())).on('brush', bind(this._onBrush, this)); + }; + + ParallelAxisView.prototype.render = function (axisModel, ecModel, api, payload) { + if (fromAxisAreaSelect(axisModel, ecModel, payload)) { + return; + } + + this.axisModel = axisModel; + this.api = api; + this.group.removeAll(); + var oldAxisGroup = this._axisGroup; + this._axisGroup = new Group(); + this.group.add(this._axisGroup); + + if (!axisModel.get('show')) { + return; + } + + var coordSysModel = getCoordSysModel(axisModel, ecModel); + var coordSys = coordSysModel.coordinateSystem; + var areaSelectStyle = axisModel.getAreaSelectStyle(); + var areaWidth = areaSelectStyle.width; + var dim = axisModel.axis.dim; + var axisLayout = coordSys.getAxisLayout(dim); + var builderOpt = extend({ + strokeContainThreshold: areaWidth + }, axisLayout); + var axisBuilder = new AxisBuilder(axisModel, builderOpt); + each(elementList, axisBuilder.add, axisBuilder); + + this._axisGroup.add(axisBuilder.getGroup()); + + this._refreshBrushController(builderOpt, areaSelectStyle, axisModel, coordSysModel, areaWidth, api); + + groupTransition(oldAxisGroup, this._axisGroup, axisModel); + }; // /** + // * @override + // */ + // updateVisual(axisModel, ecModel, api, payload) { + // this._brushController && this._brushController + // .updateCovers(getCoverInfoList(axisModel)); + // } + + + ParallelAxisView.prototype._refreshBrushController = function (builderOpt, areaSelectStyle, axisModel, coordSysModel, areaWidth, api) { + // After filtering, axis may change, select area needs to be update. + var extent = axisModel.axis.getExtent(); + var extentLen = extent[1] - extent[0]; + var extra = Math.min(30, Math.abs(extentLen) * 0.1); // Arbitrary value. + // width/height might be negative, which will be + // normalized in BoundingRect. + + var rect = BoundingRect.create({ + x: extent[0], + y: -areaWidth / 2, + width: extentLen, + height: areaWidth + }); + rect.x -= extra; + rect.width += 2 * extra; + + this._brushController.mount({ + enableGlobalPan: true, + rotation: builderOpt.rotation, + x: builderOpt.position[0], + y: builderOpt.position[1] + }).setPanels([{ + panelId: 'pl', + clipPath: makeRectPanelClipPath(rect), + isTargetByCursor: makeRectIsTargetByCursor(rect, api, coordSysModel), + getLinearBrushOtherExtent: makeLinearBrushOtherExtent(rect, 0) + }]).enableBrush({ + brushType: 'lineX', + brushStyle: areaSelectStyle, + removeOnClick: true + }).updateCovers(getCoverInfoList(axisModel)); + }; + + ParallelAxisView.prototype._onBrush = function (eventParam) { + var coverInfoList = eventParam.areas; // Do not cache these object, because the mey be changed. + + var axisModel = this.axisModel; + var axis = axisModel.axis; + var intervals = map(coverInfoList, function (coverInfo) { + return [axis.coordToData(coverInfo.range[0], true), axis.coordToData(coverInfo.range[1], true)]; + }); // If realtime is true, action is not dispatched on drag end, because + // the drag end emits the same params with the last drag move event, + // and may have some delay when using touch pad. + + if (!axisModel.option.realtime === eventParam.isEnd || eventParam.removeOnClick) { + // jshint ignore:line + this.api.dispatchAction({ + type: 'axisAreaSelect', + parallelAxisId: axisModel.id, + intervals: intervals + }); + } + }; + + ParallelAxisView.prototype.dispose = function () { + this._brushController.dispose(); + }; + + ParallelAxisView.type = 'parallelAxis'; + return ParallelAxisView; + }(ComponentView); + + function fromAxisAreaSelect(axisModel, ecModel, payload) { + return payload && payload.type === 'axisAreaSelect' && ecModel.findComponents({ + mainType: 'parallelAxis', + query: payload + })[0] === axisModel; + } + + function getCoverInfoList(axisModel) { + var axis = axisModel.axis; + return map(axisModel.activeIntervals, function (interval) { + return { + brushType: 'lineX', + panelId: 'pl', + range: [axis.dataToCoord(interval[0], true), axis.dataToCoord(interval[1], true)] + }; + }); + } + + function getCoordSysModel(axisModel, ecModel) { + return ecModel.getComponent('parallel', axisModel.get('parallelIndex')); + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + var actionInfo$1 = { + type: 'axisAreaSelect', + event: 'axisAreaSelected' // update: 'updateVisual' + + }; + function installParallelActions(registers) { + registers.registerAction(actionInfo$1, function (payload, ecModel) { + ecModel.eachComponent({ + mainType: 'parallelAxis', + query: payload + }, function (parallelAxisModel) { + parallelAxisModel.axis.model.setActiveIntervals(payload.intervals); + }); + }); + /** + * @payload + */ + + registers.registerAction('parallelAxisExpand', function (payload, ecModel) { + ecModel.eachComponent({ + mainType: 'parallel', + query: payload + }, function (parallelModel) { + parallelModel.setAxisExpand(payload); + }); + }); + } + + var defaultAxisOption = { + type: 'value', + areaSelectStyle: { + width: 20, + borderWidth: 1, + borderColor: 'rgba(160,197,232)', + color: 'rgba(160,197,232)', + opacity: 0.3 + }, + realtime: true, + z: 10 + }; + function install$g(registers) { + registers.registerComponentView(ParallelView$1); + registers.registerComponentModel(ParallelModel); + registers.registerCoordinateSystem('parallel', parallelCoordSysCreator); + registers.registerPreprocessor(parallelPreprocessor); + registers.registerComponentModel(ParallelAxisModel); + registers.registerComponentView(ParallelAxisView); + axisModelCreator(registers, 'parallel', ParallelAxisModel, defaultAxisOption); + installParallelActions(registers); + } + + function install$h(registers) { + use(install$g); + registers.registerChartView(ParallelView); + registers.registerSeriesModel(ParallelSeriesModel); + registers.registerVisual(registers.PRIORITY.VISUAL.BRUSH, parallelVisual); + } + + var SankeyPathShape = + /** @class */ + function () { + function SankeyPathShape() { + this.x1 = 0; + this.y1 = 0; + this.x2 = 0; + this.y2 = 0; + this.cpx1 = 0; + this.cpy1 = 0; + this.cpx2 = 0; + this.cpy2 = 0; + this.extent = 0; + } + + return SankeyPathShape; + }(); + + var SankeyPath = + /** @class */ + function (_super) { + __extends(SankeyPath, _super); + + function SankeyPath(opts) { + return _super.call(this, opts) || this; + } + + SankeyPath.prototype.getDefaultShape = function () { + return new SankeyPathShape(); + }; + + SankeyPath.prototype.buildPath = function (ctx, shape) { + var extent = shape.extent; + ctx.moveTo(shape.x1, shape.y1); + ctx.bezierCurveTo(shape.cpx1, shape.cpy1, shape.cpx2, shape.cpy2, shape.x2, shape.y2); + + if (shape.orient === 'vertical') { + ctx.lineTo(shape.x2 + extent, shape.y2); + ctx.bezierCurveTo(shape.cpx2 + extent, shape.cpy2, shape.cpx1 + extent, shape.cpy1, shape.x1 + extent, shape.y1); + } else { + ctx.lineTo(shape.x2, shape.y2 + extent); + ctx.bezierCurveTo(shape.cpx2, shape.cpy2 + extent, shape.cpx1, shape.cpy1 + extent, shape.x1, shape.y1 + extent); + } + + ctx.closePath(); + }; + + SankeyPath.prototype.highlight = function () { + enterEmphasis(this); + }; + + SankeyPath.prototype.downplay = function () { + leaveEmphasis(this); + }; + + return SankeyPath; + }(Path); + + var SankeyView = + /** @class */ + function (_super) { + __extends(SankeyView, _super); + + function SankeyView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = SankeyView.type; + _this._focusAdjacencyDisabled = false; + return _this; + } + + SankeyView.prototype.render = function (seriesModel, ecModel, api) { + var sankeyView = this; + var graph = seriesModel.getGraph(); + var group = this.group; + var layoutInfo = seriesModel.layoutInfo; // view width + + var width = layoutInfo.width; // view height + + var height = layoutInfo.height; + var nodeData = seriesModel.getData(); + var edgeData = seriesModel.getData('edge'); + var orient = seriesModel.get('orient'); + this._model = seriesModel; + group.removeAll(); + group.x = layoutInfo.x; + group.y = layoutInfo.y; // generate a bezire Curve for each edge + + graph.eachEdge(function (edge) { + var curve = new SankeyPath(); + var ecData = getECData(curve); + ecData.dataIndex = edge.dataIndex; + ecData.seriesIndex = seriesModel.seriesIndex; + ecData.dataType = 'edge'; + var edgeModel = edge.getModel(); + var lineStyleModel = edgeModel.getModel('lineStyle'); + var curvature = lineStyleModel.get('curveness'); + var n1Layout = edge.node1.getLayout(); + var node1Model = edge.node1.getModel(); + var dragX1 = node1Model.get('localX'); + var dragY1 = node1Model.get('localY'); + var n2Layout = edge.node2.getLayout(); + var node2Model = edge.node2.getModel(); + var dragX2 = node2Model.get('localX'); + var dragY2 = node2Model.get('localY'); + var edgeLayout = edge.getLayout(); + var x1; + var y1; + var x2; + var y2; + var cpx1; + var cpy1; + var cpx2; + var cpy2; + curve.shape.extent = Math.max(1, edgeLayout.dy); + curve.shape.orient = orient; + + if (orient === 'vertical') { + x1 = (dragX1 != null ? dragX1 * width : n1Layout.x) + edgeLayout.sy; + y1 = (dragY1 != null ? dragY1 * height : n1Layout.y) + n1Layout.dy; + x2 = (dragX2 != null ? dragX2 * width : n2Layout.x) + edgeLayout.ty; + y2 = dragY2 != null ? dragY2 * height : n2Layout.y; + cpx1 = x1; + cpy1 = y1 * (1 - curvature) + y2 * curvature; + cpx2 = x2; + cpy2 = y1 * curvature + y2 * (1 - curvature); + } else { + x1 = (dragX1 != null ? dragX1 * width : n1Layout.x) + n1Layout.dx; + y1 = (dragY1 != null ? dragY1 * height : n1Layout.y) + edgeLayout.sy; + x2 = dragX2 != null ? dragX2 * width : n2Layout.x; + y2 = (dragY2 != null ? dragY2 * height : n2Layout.y) + edgeLayout.ty; + cpx1 = x1 * (1 - curvature) + x2 * curvature; + cpy1 = y1; + cpx2 = x1 * curvature + x2 * (1 - curvature); + cpy2 = y2; + } + + curve.setShape({ + x1: x1, + y1: y1, + x2: x2, + y2: y2, + cpx1: cpx1, + cpy1: cpy1, + cpx2: cpx2, + cpy2: cpy2 + }); + curve.useStyle(lineStyleModel.getItemStyle()); // Special color, use source node color or target node color + + switch (curve.style.fill) { + case 'source': + curve.style.fill = edge.node1.getVisual('color'); + curve.style.decal = edge.node1.getVisual('style').decal; + break; + + case 'target': + curve.style.fill = edge.node2.getVisual('color'); + curve.style.decal = edge.node2.getVisual('style').decal; + break; + + case 'gradient': + var sourceColor = edge.node1.getVisual('color'); + var targetColor = edge.node2.getVisual('color'); + + if (isString(sourceColor) && isString(targetColor)) { + curve.style.fill = new LinearGradient(0, 0, +(orient === 'horizontal'), +(orient === 'vertical'), [{ + color: sourceColor, + offset: 0 + }, { + color: targetColor, + offset: 1 + }]); + } + + } + + var emphasisModel = edgeModel.getModel('emphasis'); + setStatesStylesFromModel(curve, edgeModel, 'lineStyle', function (model) { + return model.getItemStyle(); + }); + group.add(curve); + edgeData.setItemGraphicEl(edge.dataIndex, curve); + var focus = emphasisModel.get('focus'); + toggleHoverEmphasis(curve, focus === 'adjacency' ? edge.getAdjacentDataIndices() : focus, emphasisModel.get('blurScope'), emphasisModel.get('disabled')); + getECData(curve).dataType = 'edge'; + }); // Generate a rect for each node + + graph.eachNode(function (node) { + var layout = node.getLayout(); + var itemModel = node.getModel(); + var dragX = itemModel.get('localX'); + var dragY = itemModel.get('localY'); + var emphasisModel = itemModel.getModel('emphasis'); + var rect = new Rect({ + shape: { + x: dragX != null ? dragX * width : layout.x, + y: dragY != null ? dragY * height : layout.y, + width: layout.dx, + height: layout.dy + }, + style: itemModel.getModel('itemStyle').getItemStyle(), + z2: 10 + }); + setLabelStyle(rect, getLabelStatesModels(itemModel), { + labelFetcher: seriesModel, + labelDataIndex: node.dataIndex, + defaultText: node.id + }); + rect.disableLabelAnimation = true; + rect.setStyle('fill', node.getVisual('color')); + rect.setStyle('decal', node.getVisual('style').decal); + setStatesStylesFromModel(rect, itemModel); + group.add(rect); + nodeData.setItemGraphicEl(node.dataIndex, rect); + getECData(rect).dataType = 'node'; + var focus = emphasisModel.get('focus'); + toggleHoverEmphasis(rect, focus === 'adjacency' ? node.getAdjacentDataIndices() : focus, emphasisModel.get('blurScope'), emphasisModel.get('disabled')); + }); + nodeData.eachItemGraphicEl(function (el, dataIndex) { + var itemModel = nodeData.getItemModel(dataIndex); + + if (itemModel.get('draggable')) { + el.drift = function (dx, dy) { + sankeyView._focusAdjacencyDisabled = true; + this.shape.x += dx; + this.shape.y += dy; + this.dirty(); + api.dispatchAction({ + type: 'dragNode', + seriesId: seriesModel.id, + dataIndex: nodeData.getRawIndex(dataIndex), + localX: this.shape.x / width, + localY: this.shape.y / height + }); + }; + + el.ondragend = function () { + sankeyView._focusAdjacencyDisabled = false; + }; + + el.draggable = true; + el.cursor = 'move'; + } + }); + + if (!this._data && seriesModel.isAnimationEnabled()) { + group.setClipPath(createGridClipShape$1(group.getBoundingRect(), seriesModel, function () { + group.removeClipPath(); + })); + } + + this._data = seriesModel.getData(); + }; + + SankeyView.prototype.dispose = function () {}; + + SankeyView.type = 'sankey'; + return SankeyView; + }(ChartView); // Add animation to the view + + + function createGridClipShape$1(rect, seriesModel, cb) { + var rectEl = new Rect({ + shape: { + x: rect.x - 10, + y: rect.y - 10, + width: 0, + height: rect.height + 20 + } + }); + initProps(rectEl, { + shape: { + width: rect.width + 20 + } + }, seriesModel, cb); + return rectEl; + } + + var SankeySeriesModel = + /** @class */ + function (_super) { + __extends(SankeySeriesModel, _super); + + function SankeySeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = SankeySeriesModel.type; + return _this; + } + /** + * Init a graph data structure from data in option series + */ + + + SankeySeriesModel.prototype.getInitialData = function (option, ecModel) { + var links = option.edges || option.links; + var nodes = option.data || option.nodes; + var levels = option.levels; + this.levelModels = []; + var levelModels = this.levelModels; + + for (var i = 0; i < levels.length; i++) { + if (levels[i].depth != null && levels[i].depth >= 0) { + levelModels[levels[i].depth] = new Model(levels[i], this, ecModel); + } else { + if ("development" !== 'production') { + throw new Error('levels[i].depth is mandatory and should be natural number'); + } + } + } + + if (nodes && links) { + var graph = createGraphFromNodeEdge(nodes, links, this, true, beforeLink); + return graph.data; + } + + function beforeLink(nodeData, edgeData) { + nodeData.wrapMethod('getItemModel', function (model, idx) { + var seriesModel = model.parentModel; + var layout = seriesModel.getData().getItemLayout(idx); + + if (layout) { + var nodeDepth = layout.depth; + var levelModel = seriesModel.levelModels[nodeDepth]; + + if (levelModel) { + model.parentModel = levelModel; + } + } + + return model; + }); + edgeData.wrapMethod('getItemModel', function (model, idx) { + var seriesModel = model.parentModel; + var edge = seriesModel.getGraph().getEdgeByIndex(idx); + var layout = edge.node1.getLayout(); + + if (layout) { + var depth = layout.depth; + var levelModel = seriesModel.levelModels[depth]; + + if (levelModel) { + model.parentModel = levelModel; + } + } + + return model; + }); + } + }; + + SankeySeriesModel.prototype.setNodePosition = function (dataIndex, localPosition) { + var nodes = this.option.data || this.option.nodes; + var dataItem = nodes[dataIndex]; + dataItem.localX = localPosition[0]; + dataItem.localY = localPosition[1]; + }; + /** + * Return the graphic data structure + * + * @return graphic data structure + */ + + + SankeySeriesModel.prototype.getGraph = function () { + return this.getData().graph; + }; + /** + * Get edge data of graphic data structure + * + * @return data structure of list + */ + + + SankeySeriesModel.prototype.getEdgeData = function () { + return this.getGraph().edgeData; + }; + + SankeySeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + function noValue(val) { + return isNaN(val) || val == null; + } // dataType === 'node' or empty do not show tooltip by default + + + if (dataType === 'edge') { + var params = this.getDataParams(dataIndex, dataType); + var rawDataOpt = params.data; + var edgeValue = params.value; + var edgeName = rawDataOpt.source + ' -- ' + rawDataOpt.target; + return createTooltipMarkup('nameValue', { + name: edgeName, + value: edgeValue, + noValue: noValue(edgeValue) + }); + } // dataType === 'node' + else { + var node = this.getGraph().getNodeByIndex(dataIndex); + var value = node.getLayout().value; + var name_1 = this.getDataParams(dataIndex, dataType).data.name; + return createTooltipMarkup('nameValue', { + name: name_1 != null ? name_1 + '' : null, + value: value, + noValue: noValue(value) + }); + } + }; + + SankeySeriesModel.prototype.optionUpdated = function () {}; // Override Series.getDataParams() + + + SankeySeriesModel.prototype.getDataParams = function (dataIndex, dataType) { + var params = _super.prototype.getDataParams.call(this, dataIndex, dataType); + + if (params.value == null && dataType === 'node') { + var node = this.getGraph().getNodeByIndex(dataIndex); + var nodeValue = node.getLayout().value; + params.value = nodeValue; + } + + return params; + }; + + SankeySeriesModel.type = 'series.sankey'; + SankeySeriesModel.defaultOption = { + // zlevel: 0, + z: 2, + coordinateSystem: 'view', + left: '5%', + top: '5%', + right: '20%', + bottom: '5%', + orient: 'horizontal', + nodeWidth: 20, + nodeGap: 8, + draggable: true, + layoutIterations: 32, + label: { + show: true, + position: 'right', + fontSize: 12 + }, + levels: [], + nodeAlign: 'justify', + lineStyle: { + color: '#314656', + opacity: 0.2, + curveness: 0.5 + }, + emphasis: { + label: { + show: true + }, + lineStyle: { + opacity: 0.5 + } + }, + select: { + itemStyle: { + borderColor: '#212121' + } + }, + animationEasing: 'linear', + animationDuration: 1000 + }; + return SankeySeriesModel; + }(SeriesModel); + + function sankeyLayout(ecModel, api) { + ecModel.eachSeriesByType('sankey', function (seriesModel) { + var nodeWidth = seriesModel.get('nodeWidth'); + var nodeGap = seriesModel.get('nodeGap'); + var layoutInfo = getViewRect$4(seriesModel, api); + seriesModel.layoutInfo = layoutInfo; + var width = layoutInfo.width; + var height = layoutInfo.height; + var graph = seriesModel.getGraph(); + var nodes = graph.nodes; + var edges = graph.edges; + computeNodeValues(nodes); + var filteredNodes = filter(nodes, function (node) { + return node.getLayout().value === 0; + }); + var iterations = filteredNodes.length !== 0 ? 0 : seriesModel.get('layoutIterations'); + var orient = seriesModel.get('orient'); + var nodeAlign = seriesModel.get('nodeAlign'); + layoutSankey(nodes, edges, nodeWidth, nodeGap, width, height, iterations, orient, nodeAlign); + }); + } + /** + * Get the layout position of the whole view + */ + + function getViewRect$4(seriesModel, api) { + return getLayoutRect(seriesModel.getBoxLayoutParams(), { + width: api.getWidth(), + height: api.getHeight() + }); + } + + function layoutSankey(nodes, edges, nodeWidth, nodeGap, width, height, iterations, orient, nodeAlign) { + computeNodeBreadths(nodes, edges, nodeWidth, width, height, orient, nodeAlign); + computeNodeDepths(nodes, edges, height, width, nodeGap, iterations, orient); + computeEdgeDepths(nodes, orient); + } + /** + * Compute the value of each node by summing the associated edge's value + */ + + + function computeNodeValues(nodes) { + each(nodes, function (node) { + var value1 = sum(node.outEdges, getEdgeValue); + var value2 = sum(node.inEdges, getEdgeValue); + var nodeRawValue = node.getValue() || 0; + var value = Math.max(value1, value2, nodeRawValue); + node.setLayout({ + value: value + }, true); + }); + } + /** + * Compute the x-position for each node. + * + * Here we use Kahn algorithm to detect cycle when we traverse + * the node to computer the initial x position. + */ + + + function computeNodeBreadths(nodes, edges, nodeWidth, width, height, orient, nodeAlign) { + // Used to mark whether the edge is deleted. if it is deleted, + // the value is 0, otherwise it is 1. + var remainEdges = []; // Storage each node's indegree. + + var indegreeArr = []; //Used to storage the node with indegree is equal to 0. + + var zeroIndegrees = []; + var nextTargetNode = []; + var x = 0; // let kx = 0; + + for (var i = 0; i < edges.length; i++) { + remainEdges[i] = 1; + } + + for (var i = 0; i < nodes.length; i++) { + indegreeArr[i] = nodes[i].inEdges.length; + + if (indegreeArr[i] === 0) { + zeroIndegrees.push(nodes[i]); + } + } + + var maxNodeDepth = -1; // Traversing nodes using topological sorting to calculate the + // horizontal(if orient === 'horizontal') or vertical(if orient === 'vertical') + // position of the nodes. + + while (zeroIndegrees.length) { + for (var idx = 0; idx < zeroIndegrees.length; idx++) { + var node = zeroIndegrees[idx]; + var item = node.hostGraph.data.getRawDataItem(node.dataIndex); + var isItemDepth = item.depth != null && item.depth >= 0; + + if (isItemDepth && item.depth > maxNodeDepth) { + maxNodeDepth = item.depth; + } + + node.setLayout({ + depth: isItemDepth ? item.depth : x + }, true); + orient === 'vertical' ? node.setLayout({ + dy: nodeWidth + }, true) : node.setLayout({ + dx: nodeWidth + }, true); + + for (var edgeIdx = 0; edgeIdx < node.outEdges.length; edgeIdx++) { + var edge = node.outEdges[edgeIdx]; + var indexEdge = edges.indexOf(edge); + remainEdges[indexEdge] = 0; + var targetNode = edge.node2; + var nodeIndex = nodes.indexOf(targetNode); + + if (--indegreeArr[nodeIndex] === 0 && nextTargetNode.indexOf(targetNode) < 0) { + nextTargetNode.push(targetNode); + } + } + } + + ++x; + zeroIndegrees = nextTargetNode; + nextTargetNode = []; + } + + for (var i = 0; i < remainEdges.length; i++) { + if (remainEdges[i] === 1) { + throw new Error('Sankey is a DAG, the original data has cycle!'); + } + } + + var maxDepth = maxNodeDepth > x - 1 ? maxNodeDepth : x - 1; + + if (nodeAlign && nodeAlign !== 'left') { + adjustNodeWithNodeAlign(nodes, nodeAlign, orient, maxDepth); + } + + var kx = orient === 'vertical' ? (height - nodeWidth) / maxDepth : (width - nodeWidth) / maxDepth; + scaleNodeBreadths(nodes, kx, orient); + } + + function isNodeDepth(node) { + var item = node.hostGraph.data.getRawDataItem(node.dataIndex); + return item.depth != null && item.depth >= 0; + } + + function adjustNodeWithNodeAlign(nodes, nodeAlign, orient, maxDepth) { + if (nodeAlign === 'right') { + var nextSourceNode = []; + var remainNodes = nodes; + var nodeHeight = 0; + + while (remainNodes.length) { + for (var i = 0; i < remainNodes.length; i++) { + var node = remainNodes[i]; + node.setLayout({ + skNodeHeight: nodeHeight + }, true); + + for (var j = 0; j < node.inEdges.length; j++) { + var edge = node.inEdges[j]; + + if (nextSourceNode.indexOf(edge.node1) < 0) { + nextSourceNode.push(edge.node1); + } + } + } + + remainNodes = nextSourceNode; + nextSourceNode = []; + ++nodeHeight; + } + + each(nodes, function (node) { + if (!isNodeDepth(node)) { + node.setLayout({ + depth: Math.max(0, maxDepth - node.getLayout().skNodeHeight) + }, true); + } + }); + } else if (nodeAlign === 'justify') { + moveSinksRight(nodes, maxDepth); + } + } + /** + * All the node without outEgdes are assigned maximum x-position and + * be aligned in the last column. + * + * @param nodes. node of sankey view. + * @param maxDepth. use to assign to node without outEdges as x-position. + */ + + + function moveSinksRight(nodes, maxDepth) { + each(nodes, function (node) { + if (!isNodeDepth(node) && !node.outEdges.length) { + node.setLayout({ + depth: maxDepth + }, true); + } + }); + } + /** + * Scale node x-position to the width + * + * @param nodes node of sankey view + * @param kx multiple used to scale nodes + */ + + + function scaleNodeBreadths(nodes, kx, orient) { + each(nodes, function (node) { + var nodeDepth = node.getLayout().depth * kx; + orient === 'vertical' ? node.setLayout({ + y: nodeDepth + }, true) : node.setLayout({ + x: nodeDepth + }, true); + }); + } + /** + * Using Gauss-Seidel iterations method to compute the node depth(y-position) + * + * @param nodes node of sankey view + * @param edges edge of sankey view + * @param height the whole height of the area to draw the view + * @param nodeGap the vertical distance between two nodes + * in the same column. + * @param iterations the number of iterations for the algorithm + */ + + + function computeNodeDepths(nodes, edges, height, width, nodeGap, iterations, orient) { + var nodesByBreadth = prepareNodesByBreadth(nodes, orient); + initializeNodeDepth(nodesByBreadth, edges, height, width, nodeGap, orient); + resolveCollisions(nodesByBreadth, nodeGap, height, width, orient); + + for (var alpha = 1; iterations > 0; iterations--) { + // 0.99 is a experience parameter, ensure that each iterations of + // changes as small as possible. + alpha *= 0.99; + relaxRightToLeft(nodesByBreadth, alpha, orient); + resolveCollisions(nodesByBreadth, nodeGap, height, width, orient); + relaxLeftToRight(nodesByBreadth, alpha, orient); + resolveCollisions(nodesByBreadth, nodeGap, height, width, orient); + } + } + + function prepareNodesByBreadth(nodes, orient) { + var nodesByBreadth = []; + var keyAttr = orient === 'vertical' ? 'y' : 'x'; + var groupResult = groupData(nodes, function (node) { + return node.getLayout()[keyAttr]; + }); + groupResult.keys.sort(function (a, b) { + return a - b; + }); + each(groupResult.keys, function (key) { + nodesByBreadth.push(groupResult.buckets.get(key)); + }); + return nodesByBreadth; + } + /** + * Compute the original y-position for each node + */ + + + function initializeNodeDepth(nodesByBreadth, edges, height, width, nodeGap, orient) { + var minKy = Infinity; + each(nodesByBreadth, function (nodes) { + var n = nodes.length; + var sum = 0; + each(nodes, function (node) { + sum += node.getLayout().value; + }); + var ky = orient === 'vertical' ? (width - (n - 1) * nodeGap) / sum : (height - (n - 1) * nodeGap) / sum; + + if (ky < minKy) { + minKy = ky; + } + }); + each(nodesByBreadth, function (nodes) { + each(nodes, function (node, i) { + var nodeDy = node.getLayout().value * minKy; + + if (orient === 'vertical') { + node.setLayout({ + x: i + }, true); + node.setLayout({ + dx: nodeDy + }, true); + } else { + node.setLayout({ + y: i + }, true); + node.setLayout({ + dy: nodeDy + }, true); + } + }); + }); + each(edges, function (edge) { + var edgeDy = +edge.getValue() * minKy; + edge.setLayout({ + dy: edgeDy + }, true); + }); + } + /** + * Resolve the collision of initialized depth (y-position) + */ + + + function resolveCollisions(nodesByBreadth, nodeGap, height, width, orient) { + var keyAttr = orient === 'vertical' ? 'x' : 'y'; + each(nodesByBreadth, function (nodes) { + nodes.sort(function (a, b) { + return a.getLayout()[keyAttr] - b.getLayout()[keyAttr]; + }); + var nodeX; + var node; + var dy; + var y0 = 0; + var n = nodes.length; + var nodeDyAttr = orient === 'vertical' ? 'dx' : 'dy'; + + for (var i = 0; i < n; i++) { + node = nodes[i]; + dy = y0 - node.getLayout()[keyAttr]; + + if (dy > 0) { + nodeX = node.getLayout()[keyAttr] + dy; + orient === 'vertical' ? node.setLayout({ + x: nodeX + }, true) : node.setLayout({ + y: nodeX + }, true); + } + + y0 = node.getLayout()[keyAttr] + node.getLayout()[nodeDyAttr] + nodeGap; + } + + var viewWidth = orient === 'vertical' ? width : height; // If the bottommost node goes outside the bounds, push it back up + + dy = y0 - nodeGap - viewWidth; + + if (dy > 0) { + nodeX = node.getLayout()[keyAttr] - dy; + orient === 'vertical' ? node.setLayout({ + x: nodeX + }, true) : node.setLayout({ + y: nodeX + }, true); + y0 = nodeX; + + for (var i = n - 2; i >= 0; --i) { + node = nodes[i]; + dy = node.getLayout()[keyAttr] + node.getLayout()[nodeDyAttr] + nodeGap - y0; + + if (dy > 0) { + nodeX = node.getLayout()[keyAttr] - dy; + orient === 'vertical' ? node.setLayout({ + x: nodeX + }, true) : node.setLayout({ + y: nodeX + }, true); + } + + y0 = node.getLayout()[keyAttr]; + } + } + }); + } + /** + * Change the y-position of the nodes, except most the right side nodes + * @param nodesByBreadth + * @param alpha parameter used to adjust the nodes y-position + */ + + + function relaxRightToLeft(nodesByBreadth, alpha, orient) { + each(nodesByBreadth.slice().reverse(), function (nodes) { + each(nodes, function (node) { + if (node.outEdges.length) { + var y = sum(node.outEdges, weightedTarget, orient) / sum(node.outEdges, getEdgeValue); + + if (isNaN(y)) { + var len = node.outEdges.length; + y = len ? sum(node.outEdges, centerTarget, orient) / len : 0; + } + + if (orient === 'vertical') { + var nodeX = node.getLayout().x + (y - center$1(node, orient)) * alpha; + node.setLayout({ + x: nodeX + }, true); + } else { + var nodeY = node.getLayout().y + (y - center$1(node, orient)) * alpha; + node.setLayout({ + y: nodeY + }, true); + } + } + }); + }); + } + + function weightedTarget(edge, orient) { + return center$1(edge.node2, orient) * edge.getValue(); + } + + function centerTarget(edge, orient) { + return center$1(edge.node2, orient); + } + + function weightedSource(edge, orient) { + return center$1(edge.node1, orient) * edge.getValue(); + } + + function centerSource(edge, orient) { + return center$1(edge.node1, orient); + } + + function center$1(node, orient) { + return orient === 'vertical' ? node.getLayout().x + node.getLayout().dx / 2 : node.getLayout().y + node.getLayout().dy / 2; + } + + function getEdgeValue(edge) { + return edge.getValue(); + } + + function sum(array, cb, orient) { + var sum = 0; + var len = array.length; + var i = -1; + + while (++i < len) { + var value = +cb(array[i], orient); + + if (!isNaN(value)) { + sum += value; + } + } + + return sum; + } + /** + * Change the y-position of the nodes, except most the left side nodes + */ + + + function relaxLeftToRight(nodesByBreadth, alpha, orient) { + each(nodesByBreadth, function (nodes) { + each(nodes, function (node) { + if (node.inEdges.length) { + var y = sum(node.inEdges, weightedSource, orient) / sum(node.inEdges, getEdgeValue); + + if (isNaN(y)) { + var len = node.inEdges.length; + y = len ? sum(node.inEdges, centerSource, orient) / len : 0; + } + + if (orient === 'vertical') { + var nodeX = node.getLayout().x + (y - center$1(node, orient)) * alpha; + node.setLayout({ + x: nodeX + }, true); + } else { + var nodeY = node.getLayout().y + (y - center$1(node, orient)) * alpha; + node.setLayout({ + y: nodeY + }, true); + } + } + }); + }); + } + /** + * Compute the depth(y-position) of each edge + */ + + + function computeEdgeDepths(nodes, orient) { + var keyAttr = orient === 'vertical' ? 'x' : 'y'; + each(nodes, function (node) { + node.outEdges.sort(function (a, b) { + return a.node2.getLayout()[keyAttr] - b.node2.getLayout()[keyAttr]; + }); + node.inEdges.sort(function (a, b) { + return a.node1.getLayout()[keyAttr] - b.node1.getLayout()[keyAttr]; + }); + }); + each(nodes, function (node) { + var sy = 0; + var ty = 0; + each(node.outEdges, function (edge) { + edge.setLayout({ + sy: sy + }, true); + sy += edge.getLayout().dy; + }); + each(node.inEdges, function (edge) { + edge.setLayout({ + ty: ty + }, true); + ty += edge.getLayout().dy; + }); + }); + } + + function sankeyVisual(ecModel) { + ecModel.eachSeriesByType('sankey', function (seriesModel) { + var graph = seriesModel.getGraph(); + var nodes = graph.nodes; + + if (nodes.length) { + var minValue_1 = Infinity; + var maxValue_1 = -Infinity; + each(nodes, function (node) { + var nodeValue = node.getLayout().value; + + if (nodeValue < minValue_1) { + minValue_1 = nodeValue; + } + + if (nodeValue > maxValue_1) { + maxValue_1 = nodeValue; + } + }); + each(nodes, function (node) { + var mapping = new VisualMapping({ + type: 'color', + mappingMethod: 'linear', + dataExtent: [minValue_1, maxValue_1], + visual: seriesModel.get('color') + }); + var mapValueToColor = mapping.mapValueToVisual(node.getLayout().value); + var customColor = node.getModel().get(['itemStyle', 'color']); + + if (customColor != null) { + node.setVisual('color', customColor); + node.setVisual('style', { + fill: customColor + }); + } else { + node.setVisual('color', mapValueToColor); + node.setVisual('style', { + fill: mapValueToColor + }); + } + }); + } + }); + } + + function install$i(registers) { + registers.registerChartView(SankeyView); + registers.registerSeriesModel(SankeySeriesModel); + registers.registerLayout(sankeyLayout); + registers.registerVisual(sankeyVisual); + registers.registerAction({ + type: 'dragNode', + event: 'dragnode', + // here can only use 'update' now, other value is not support in echarts. + update: 'update' + }, function (payload, ecModel) { + ecModel.eachComponent({ + mainType: 'series', + subType: 'sankey', + query: payload + }, function (seriesModel) { + seriesModel.setNodePosition(payload.dataIndex, [payload.localX, payload.localY]); + }); + }); + } + + var WhiskerBoxCommonMixin = + /** @class */ + function () { + function WhiskerBoxCommonMixin() {} + /** + * @override + */ + + + WhiskerBoxCommonMixin.prototype.getInitialData = function (option, ecModel) { + // When both types of xAxis and yAxis are 'value', layout is + // needed to be specified by user. Otherwise, layout can be + // judged by which axis is category. + var ordinalMeta; + var xAxisModel = ecModel.getComponent('xAxis', this.get('xAxisIndex')); + var yAxisModel = ecModel.getComponent('yAxis', this.get('yAxisIndex')); + var xAxisType = xAxisModel.get('type'); + var yAxisType = yAxisModel.get('type'); + var addOrdinal; // FIXME + // Consider time axis. + + if (xAxisType === 'category') { + option.layout = 'horizontal'; + ordinalMeta = xAxisModel.getOrdinalMeta(); + addOrdinal = true; + } else if (yAxisType === 'category') { + option.layout = 'vertical'; + ordinalMeta = yAxisModel.getOrdinalMeta(); + addOrdinal = true; + } else { + option.layout = option.layout || 'horizontal'; + } + + var coordDims = ['x', 'y']; + var baseAxisDimIndex = option.layout === 'horizontal' ? 0 : 1; + var baseAxisDim = this._baseAxisDim = coordDims[baseAxisDimIndex]; + var otherAxisDim = coordDims[1 - baseAxisDimIndex]; + var axisModels = [xAxisModel, yAxisModel]; + var baseAxisType = axisModels[baseAxisDimIndex].get('type'); + var otherAxisType = axisModels[1 - baseAxisDimIndex].get('type'); + var data = option.data; // Clone a new data for next setOption({}) usage. + // Avoid modifying current data will affect further update. + + if (data && addOrdinal) { + var newOptionData_1 = []; + each(data, function (item, index) { + var newItem; + + if (isArray(item)) { + newItem = item.slice(); // Modify current using data. + + item.unshift(index); + } else if (isArray(item.value)) { + newItem = extend({}, item); + newItem.value = newItem.value.slice(); // Modify current using data. + + item.value.unshift(index); + } else { + newItem = item; + } + + newOptionData_1.push(newItem); + }); + option.data = newOptionData_1; + } + + var defaultValueDimensions = this.defaultValueDimensions; + var coordDimensions = [{ + name: baseAxisDim, + type: getDimensionTypeByAxis(baseAxisType), + ordinalMeta: ordinalMeta, + otherDims: { + tooltip: false, + itemName: 0 + }, + dimsDef: ['base'] + }, { + name: otherAxisDim, + type: getDimensionTypeByAxis(otherAxisType), + dimsDef: defaultValueDimensions.slice() + }]; + return createSeriesDataSimply(this, { + coordDimensions: coordDimensions, + dimensionsCount: defaultValueDimensions.length + 1, + encodeDefaulter: curry(makeSeriesEncodeForAxisCoordSys, coordDimensions, this) + }); + }; + /** + * If horizontal, base axis is x, otherwise y. + * @override + */ + + + WhiskerBoxCommonMixin.prototype.getBaseAxis = function () { + var dim = this._baseAxisDim; + return this.ecModel.getComponent(dim + 'Axis', this.get(dim + 'AxisIndex')).axis; + }; + + return WhiskerBoxCommonMixin; + }(); + + var BoxplotSeriesModel = + /** @class */ + function (_super) { + __extends(BoxplotSeriesModel, _super); + + function BoxplotSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = BoxplotSeriesModel.type; // TODO + // box width represents group size, so dimension should have 'size'. + + /** + * @see + * The meanings of 'min' and 'max' depend on user, + * and echarts do not need to know it. + * @readOnly + */ + + _this.defaultValueDimensions = [{ + name: 'min', + defaultTooltip: true + }, { + name: 'Q1', + defaultTooltip: true + }, { + name: 'median', + defaultTooltip: true + }, { + name: 'Q3', + defaultTooltip: true + }, { + name: 'max', + defaultTooltip: true + }]; + _this.visualDrawType = 'stroke'; + return _this; + } + + BoxplotSeriesModel.type = 'series.boxplot'; + BoxplotSeriesModel.dependencies = ['xAxis', 'yAxis', 'grid']; + BoxplotSeriesModel.defaultOption = { + // zlevel: 0, + z: 2, + coordinateSystem: 'cartesian2d', + legendHoverLink: true, + layout: null, + boxWidth: [7, 50], + itemStyle: { + color: '#fff', + borderWidth: 1 + }, + emphasis: { + scale: true, + itemStyle: { + borderWidth: 2, + shadowBlur: 5, + shadowOffsetX: 1, + shadowOffsetY: 1, + shadowColor: 'rgba(0,0,0,0.2)' + } + }, + animationDuration: 800 + }; + return BoxplotSeriesModel; + }(SeriesModel); + + mixin(BoxplotSeriesModel, WhiskerBoxCommonMixin, true); + + var BoxplotView = + /** @class */ + function (_super) { + __extends(BoxplotView, _super); + + function BoxplotView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = BoxplotView.type; + return _this; + } + + BoxplotView.prototype.render = function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + var group = this.group; + var oldData = this._data; // There is no old data only when first rendering or switching from + // stream mode to normal mode, where previous elements should be removed. + + if (!this._data) { + group.removeAll(); + } + + var constDim = seriesModel.get('layout') === 'horizontal' ? 1 : 0; + data.diff(oldData).add(function (newIdx) { + if (data.hasValue(newIdx)) { + var itemLayout = data.getItemLayout(newIdx); + var symbolEl = createNormalBox(itemLayout, data, newIdx, constDim, true); + data.setItemGraphicEl(newIdx, symbolEl); + group.add(symbolEl); + } + }).update(function (newIdx, oldIdx) { + var symbolEl = oldData.getItemGraphicEl(oldIdx); // Empty data + + if (!data.hasValue(newIdx)) { + group.remove(symbolEl); + return; + } + + var itemLayout = data.getItemLayout(newIdx); + + if (!symbolEl) { + symbolEl = createNormalBox(itemLayout, data, newIdx, constDim); + } else { + saveOldStyle(symbolEl); + updateNormalBoxData(itemLayout, symbolEl, data, newIdx); + } + + group.add(symbolEl); + data.setItemGraphicEl(newIdx, symbolEl); + }).remove(function (oldIdx) { + var el = oldData.getItemGraphicEl(oldIdx); + el && group.remove(el); + }).execute(); + this._data = data; + }; + + BoxplotView.prototype.remove = function (ecModel) { + var group = this.group; + var data = this._data; + this._data = null; + data && data.eachItemGraphicEl(function (el) { + el && group.remove(el); + }); + }; + + BoxplotView.type = 'boxplot'; + return BoxplotView; + }(ChartView); + + var BoxPathShape = + /** @class */ + function () { + function BoxPathShape() {} + + return BoxPathShape; + }(); + + var BoxPath = + /** @class */ + function (_super) { + __extends(BoxPath, _super); + + function BoxPath(opts) { + var _this = _super.call(this, opts) || this; + + _this.type = 'boxplotBoxPath'; + return _this; + } + + BoxPath.prototype.getDefaultShape = function () { + return new BoxPathShape(); + }; + + BoxPath.prototype.buildPath = function (ctx, shape) { + var ends = shape.points; + var i = 0; + ctx.moveTo(ends[i][0], ends[i][1]); + i++; + + for (; i < 4; i++) { + ctx.lineTo(ends[i][0], ends[i][1]); + } + + ctx.closePath(); + + for (; i < ends.length; i++) { + ctx.moveTo(ends[i][0], ends[i][1]); + i++; + ctx.lineTo(ends[i][0], ends[i][1]); + } + }; + + return BoxPath; + }(Path); + + function createNormalBox(itemLayout, data, dataIndex, constDim, isInit) { + var ends = itemLayout.ends; + var el = new BoxPath({ + shape: { + points: isInit ? transInit(ends, constDim, itemLayout) : ends + } + }); + updateNormalBoxData(itemLayout, el, data, dataIndex, isInit); + return el; + } + + function updateNormalBoxData(itemLayout, el, data, dataIndex, isInit) { + var seriesModel = data.hostModel; + var updateMethod = graphic[isInit ? 'initProps' : 'updateProps']; + updateMethod(el, { + shape: { + points: itemLayout.ends + } + }, seriesModel, dataIndex); + el.useStyle(data.getItemVisual(dataIndex, 'style')); + el.style.strokeNoScale = true; + el.z2 = 100; + var itemModel = data.getItemModel(dataIndex); + var emphasisModel = itemModel.getModel('emphasis'); + setStatesStylesFromModel(el, itemModel); + toggleHoverEmphasis(el, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled')); + } + + function transInit(points, dim, itemLayout) { + return map(points, function (point) { + point = point.slice(); + point[dim] = itemLayout.initBaseline; + return point; + }); + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + function boxplotVisual(ecModel, api) {} + + var each$6 = each; + function boxplotLayout(ecModel) { + var groupResult = groupSeriesByAxis(ecModel); + each$6(groupResult, function (groupItem) { + var seriesModels = groupItem.seriesModels; + + if (!seriesModels.length) { + return; + } + + calculateBase(groupItem); + each$6(seriesModels, function (seriesModel, idx) { + layoutSingleSeries(seriesModel, groupItem.boxOffsetList[idx], groupItem.boxWidthList[idx]); + }); + }); + } + /** + * Group series by axis. + */ + + function groupSeriesByAxis(ecModel) { + var result = []; + var axisList = []; + ecModel.eachSeriesByType('boxplot', function (seriesModel) { + var baseAxis = seriesModel.getBaseAxis(); + var idx = indexOf(axisList, baseAxis); + + if (idx < 0) { + idx = axisList.length; + axisList[idx] = baseAxis; + result[idx] = { + axis: baseAxis, + seriesModels: [] + }; + } + + result[idx].seriesModels.push(seriesModel); + }); + return result; + } + /** + * Calculate offset and box width for each series. + */ + + + function calculateBase(groupItem) { + var baseAxis = groupItem.axis; + var seriesModels = groupItem.seriesModels; + var seriesCount = seriesModels.length; + var boxWidthList = groupItem.boxWidthList = []; + var boxOffsetList = groupItem.boxOffsetList = []; + var boundList = []; + var bandWidth; + + if (baseAxis.type === 'category') { + bandWidth = baseAxis.getBandWidth(); + } else { + var maxDataCount_1 = 0; + each$6(seriesModels, function (seriesModel) { + maxDataCount_1 = Math.max(maxDataCount_1, seriesModel.getData().count()); + }); + var extent = baseAxis.getExtent(); + bandWidth = Math.abs(extent[1] - extent[0]) / maxDataCount_1; + } + + each$6(seriesModels, function (seriesModel) { + var boxWidthBound = seriesModel.get('boxWidth'); + + if (!isArray(boxWidthBound)) { + boxWidthBound = [boxWidthBound, boxWidthBound]; + } + + boundList.push([parsePercent$1(boxWidthBound[0], bandWidth) || 0, parsePercent$1(boxWidthBound[1], bandWidth) || 0]); + }); + var availableWidth = bandWidth * 0.8 - 2; + var boxGap = availableWidth / seriesCount * 0.3; + var boxWidth = (availableWidth - boxGap * (seriesCount - 1)) / seriesCount; + var base = boxWidth / 2 - availableWidth / 2; + each$6(seriesModels, function (seriesModel, idx) { + boxOffsetList.push(base); + base += boxGap + boxWidth; + boxWidthList.push(Math.min(Math.max(boxWidth, boundList[idx][0]), boundList[idx][1])); + }); + } + /** + * Calculate points location for each series. + */ + + + function layoutSingleSeries(seriesModel, offset, boxWidth) { + var coordSys = seriesModel.coordinateSystem; + var data = seriesModel.getData(); + var halfWidth = boxWidth / 2; + var cDimIdx = seriesModel.get('layout') === 'horizontal' ? 0 : 1; + var vDimIdx = 1 - cDimIdx; + var coordDims = ['x', 'y']; + var cDim = data.mapDimension(coordDims[cDimIdx]); + var vDims = data.mapDimensionsAll(coordDims[vDimIdx]); + + if (cDim == null || vDims.length < 5) { + return; + } + + for (var dataIndex = 0; dataIndex < data.count(); dataIndex++) { + var axisDimVal = data.get(cDim, dataIndex); + var median = getPoint(axisDimVal, vDims[2], dataIndex); + var end1 = getPoint(axisDimVal, vDims[0], dataIndex); + var end2 = getPoint(axisDimVal, vDims[1], dataIndex); + var end4 = getPoint(axisDimVal, vDims[3], dataIndex); + var end5 = getPoint(axisDimVal, vDims[4], dataIndex); + var ends = []; + addBodyEnd(ends, end2, false); + addBodyEnd(ends, end4, true); + ends.push(end1, end2, end5, end4); + layEndLine(ends, end1); + layEndLine(ends, end5); + layEndLine(ends, median); + data.setItemLayout(dataIndex, { + initBaseline: median[vDimIdx], + ends: ends + }); + } + + function getPoint(axisDimVal, dim, dataIndex) { + var val = data.get(dim, dataIndex); + var p = []; + p[cDimIdx] = axisDimVal; + p[vDimIdx] = val; + var point; + + if (isNaN(axisDimVal) || isNaN(val)) { + point = [NaN, NaN]; + } else { + point = coordSys.dataToPoint(p); + point[cDimIdx] += offset; + } + + return point; + } + + function addBodyEnd(ends, point, start) { + var point1 = point.slice(); + var point2 = point.slice(); + point1[cDimIdx] += halfWidth; + point2[cDimIdx] -= halfWidth; + start ? ends.push(point1, point2) : ends.push(point2, point1); + } + + function layEndLine(ends, endCenter) { + var from = endCenter.slice(); + var to = endCenter.slice(); + from[cDimIdx] -= halfWidth; + to[cDimIdx] += halfWidth; + ends.push(from, to); + } + } + + /** + * See: + * + * + * + * Helper method for preparing data. + * + * @param rawData like + * [ + * [12,232,443], (raw data set for the first box) + * [3843,5545,1232], (raw data set for the second box) + * ... + * ] + * @param opt.boundIQR=1.5 Data less than min bound is outlier. + * default 1.5, means Q1 - 1.5 * (Q3 - Q1). + * If 'none'/0 passed, min bound will not be used. + */ + + function prepareBoxplotData(rawData, opt) { + opt = opt || {}; + var boxData = []; + var outliers = []; + var boundIQR = opt.boundIQR; + var useExtreme = boundIQR === 'none' || boundIQR === 0; + + for (var i = 0; i < rawData.length; i++) { + var ascList = asc(rawData[i].slice()); + var Q1 = quantile(ascList, 0.25); + var Q2 = quantile(ascList, 0.5); + var Q3 = quantile(ascList, 0.75); + var min = ascList[0]; + var max = ascList[ascList.length - 1]; + var bound = (boundIQR == null ? 1.5 : boundIQR) * (Q3 - Q1); + var low = useExtreme ? min : Math.max(min, Q1 - bound); + var high = useExtreme ? max : Math.min(max, Q3 + bound); + var itemNameFormatter = opt.itemNameFormatter; + var itemName = isFunction(itemNameFormatter) ? itemNameFormatter({ + value: i + }) : isString(itemNameFormatter) ? itemNameFormatter.replace('{value}', i + '') : i + ''; + boxData.push([itemName, low, Q1, Q2, Q3, high]); + + for (var j = 0; j < ascList.length; j++) { + var dataItem = ascList[j]; + + if (dataItem < low || dataItem > high) { + var outlier = [itemName, dataItem]; + outliers.push(outlier); + } + } + } + + return { + boxData: boxData, + outliers: outliers + }; + } + + var boxplotTransform = { + type: 'echarts:boxplot', + transform: function transform(params) { + var upstream = params.upstream; + + if (upstream.sourceFormat !== SOURCE_FORMAT_ARRAY_ROWS) { + var errMsg = ''; + + if ("development" !== 'production') { + errMsg = makePrintable('source data is not applicable for this boxplot transform. Expect number[][].'); + } + + throwError(errMsg); + } + + var result = prepareBoxplotData(upstream.getRawData(), params.config); + return [{ + dimensions: ['ItemName', 'Low', 'Q1', 'Q2', 'Q3', 'High'], + data: result.boxData + }, { + data: result.outliers + }]; + } + }; + + function install$j(registers) { + registers.registerSeriesModel(BoxplotSeriesModel); + registers.registerChartView(BoxplotView); + registers.registerVisual(boxplotVisual); + registers.registerLayout(boxplotLayout); + registers.registerTransform(boxplotTransform); + } + + var SKIP_PROPS = ['color', 'borderColor']; + + var CandlestickView = + /** @class */ + function (_super) { + __extends(CandlestickView, _super); + + function CandlestickView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = CandlestickView.type; + return _this; + } + + CandlestickView.prototype.render = function (seriesModel, ecModel, api) { + // If there is clipPath created in large mode. Remove it. + this.group.removeClipPath(); // Clear previously rendered progressive elements. + + this._progressiveEls = null; + + this._updateDrawMode(seriesModel); + + this._isLargeDraw ? this._renderLarge(seriesModel) : this._renderNormal(seriesModel); + }; + + CandlestickView.prototype.incrementalPrepareRender = function (seriesModel, ecModel, api) { + this._clear(); + + this._updateDrawMode(seriesModel); + }; + + CandlestickView.prototype.incrementalRender = function (params, seriesModel, ecModel, api) { + this._progressiveEls = []; + this._isLargeDraw ? this._incrementalRenderLarge(params, seriesModel) : this._incrementalRenderNormal(params, seriesModel); + }; + + CandlestickView.prototype.eachRendered = function (cb) { + traverseElements(this._progressiveEls || this.group, cb); + }; + + CandlestickView.prototype._updateDrawMode = function (seriesModel) { + var isLargeDraw = seriesModel.pipelineContext.large; + + if (this._isLargeDraw == null || isLargeDraw !== this._isLargeDraw) { + this._isLargeDraw = isLargeDraw; + + this._clear(); + } + }; + + CandlestickView.prototype._renderNormal = function (seriesModel) { + var data = seriesModel.getData(); + var oldData = this._data; + var group = this.group; + var isSimpleBox = data.getLayout('isSimpleBox'); + var needsClip = seriesModel.get('clip', true); + var coord = seriesModel.coordinateSystem; + var clipArea = coord.getArea && coord.getArea(); // There is no old data only when first rendering or switching from + // stream mode to normal mode, where previous elements should be removed. + + if (!this._data) { + group.removeAll(); + } + + data.diff(oldData).add(function (newIdx) { + if (data.hasValue(newIdx)) { + var itemLayout = data.getItemLayout(newIdx); + + if (needsClip && isNormalBoxClipped(clipArea, itemLayout)) { + return; + } + + var el = createNormalBox$1(itemLayout, newIdx, true); + initProps(el, { + shape: { + points: itemLayout.ends + } + }, seriesModel, newIdx); + setBoxCommon(el, data, newIdx, isSimpleBox); + group.add(el); + data.setItemGraphicEl(newIdx, el); + } + }).update(function (newIdx, oldIdx) { + var el = oldData.getItemGraphicEl(oldIdx); // Empty data + + if (!data.hasValue(newIdx)) { + group.remove(el); + return; + } + + var itemLayout = data.getItemLayout(newIdx); + + if (needsClip && isNormalBoxClipped(clipArea, itemLayout)) { + group.remove(el); + return; + } + + if (!el) { + el = createNormalBox$1(itemLayout); + } else { + updateProps(el, { + shape: { + points: itemLayout.ends + } + }, seriesModel, newIdx); + saveOldStyle(el); + } + + setBoxCommon(el, data, newIdx, isSimpleBox); + group.add(el); + data.setItemGraphicEl(newIdx, el); + }).remove(function (oldIdx) { + var el = oldData.getItemGraphicEl(oldIdx); + el && group.remove(el); + }).execute(); + this._data = data; + }; + + CandlestickView.prototype._renderLarge = function (seriesModel) { + this._clear(); + + createLarge$1(seriesModel, this.group); + var clipPath = seriesModel.get('clip', true) ? createClipPath(seriesModel.coordinateSystem, false, seriesModel) : null; + + if (clipPath) { + this.group.setClipPath(clipPath); + } else { + this.group.removeClipPath(); + } + }; + + CandlestickView.prototype._incrementalRenderNormal = function (params, seriesModel) { + var data = seriesModel.getData(); + var isSimpleBox = data.getLayout('isSimpleBox'); + var dataIndex; + + while ((dataIndex = params.next()) != null) { + var itemLayout = data.getItemLayout(dataIndex); + var el = createNormalBox$1(itemLayout); + setBoxCommon(el, data, dataIndex, isSimpleBox); + el.incremental = true; + this.group.add(el); + + this._progressiveEls.push(el); + } + }; + + CandlestickView.prototype._incrementalRenderLarge = function (params, seriesModel) { + createLarge$1(seriesModel, this.group, this._progressiveEls, true); + }; + + CandlestickView.prototype.remove = function (ecModel) { + this._clear(); + }; + + CandlestickView.prototype._clear = function () { + this.group.removeAll(); + this._data = null; + }; + + CandlestickView.type = 'candlestick'; + return CandlestickView; + }(ChartView); + + var NormalBoxPathShape = + /** @class */ + function () { + function NormalBoxPathShape() {} + + return NormalBoxPathShape; + }(); + + var NormalBoxPath = + /** @class */ + function (_super) { + __extends(NormalBoxPath, _super); + + function NormalBoxPath(opts) { + var _this = _super.call(this, opts) || this; + + _this.type = 'normalCandlestickBox'; + return _this; + } + + NormalBoxPath.prototype.getDefaultShape = function () { + return new NormalBoxPathShape(); + }; + + NormalBoxPath.prototype.buildPath = function (ctx, shape) { + var ends = shape.points; + + if (this.__simpleBox) { + ctx.moveTo(ends[4][0], ends[4][1]); + ctx.lineTo(ends[6][0], ends[6][1]); + } else { + ctx.moveTo(ends[0][0], ends[0][1]); + ctx.lineTo(ends[1][0], ends[1][1]); + ctx.lineTo(ends[2][0], ends[2][1]); + ctx.lineTo(ends[3][0], ends[3][1]); + ctx.closePath(); + ctx.moveTo(ends[4][0], ends[4][1]); + ctx.lineTo(ends[5][0], ends[5][1]); + ctx.moveTo(ends[6][0], ends[6][1]); + ctx.lineTo(ends[7][0], ends[7][1]); + } + }; + + return NormalBoxPath; + }(Path); + + function createNormalBox$1(itemLayout, dataIndex, isInit) { + var ends = itemLayout.ends; + return new NormalBoxPath({ + shape: { + points: isInit ? transInit$1(ends, itemLayout) : ends + }, + z2: 100 + }); + } + + function isNormalBoxClipped(clipArea, itemLayout) { + var clipped = true; + + for (var i = 0; i < itemLayout.ends.length; i++) { + // If any point are in the region. + if (clipArea.contain(itemLayout.ends[i][0], itemLayout.ends[i][1])) { + clipped = false; + break; + } + } + + return clipped; + } + + function setBoxCommon(el, data, dataIndex, isSimpleBox) { + var itemModel = data.getItemModel(dataIndex); + el.useStyle(data.getItemVisual(dataIndex, 'style')); + el.style.strokeNoScale = true; + el.__simpleBox = isSimpleBox; + setStatesStylesFromModel(el, itemModel); + } + + function transInit$1(points, itemLayout) { + return map(points, function (point) { + point = point.slice(); + point[1] = itemLayout.initBaseline; + return point; + }); + } + + var LargeBoxPathShape = + /** @class */ + function () { + function LargeBoxPathShape() {} + + return LargeBoxPathShape; + }(); + + var LargeBoxPath = + /** @class */ + function (_super) { + __extends(LargeBoxPath, _super); + + function LargeBoxPath(opts) { + var _this = _super.call(this, opts) || this; + + _this.type = 'largeCandlestickBox'; + return _this; + } + + LargeBoxPath.prototype.getDefaultShape = function () { + return new LargeBoxPathShape(); + }; + + LargeBoxPath.prototype.buildPath = function (ctx, shape) { + // Drawing lines is more efficient than drawing + // a whole line or drawing rects. + var points = shape.points; + + for (var i = 0; i < points.length;) { + if (this.__sign === points[i++]) { + var x = points[i++]; + ctx.moveTo(x, points[i++]); + ctx.lineTo(x, points[i++]); + } else { + i += 3; + } + } + }; + + return LargeBoxPath; + }(Path); + + function createLarge$1(seriesModel, group, progressiveEls, incremental) { + var data = seriesModel.getData(); + var largePoints = data.getLayout('largePoints'); + var elP = new LargeBoxPath({ + shape: { + points: largePoints + }, + __sign: 1 + }); + group.add(elP); + var elN = new LargeBoxPath({ + shape: { + points: largePoints + }, + __sign: -1 + }); + group.add(elN); + setLargeStyle(1, elP, seriesModel); + setLargeStyle(-1, elN, seriesModel); + + if (incremental) { + elP.incremental = true; + elN.incremental = true; + } + + if (progressiveEls) { + progressiveEls.push(elP, elN); + } + } + + function setLargeStyle(sign, el, seriesModel, data) { + // TODO put in visual? + var borderColor = seriesModel.get(['itemStyle', sign > 0 ? 'borderColor' : 'borderColor0']) || seriesModel.get(['itemStyle', sign > 0 ? 'color' : 'color0']); // Color must be excluded. + // Because symbol provide setColor individually to set fill and stroke + + var itemStyle = seriesModel.getModel('itemStyle').getItemStyle(SKIP_PROPS); + el.useStyle(itemStyle); + el.style.fill = null; + el.style.stroke = borderColor; + } + + var CandlestickSeriesModel = + /** @class */ + function (_super) { + __extends(CandlestickSeriesModel, _super); + + function CandlestickSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = CandlestickSeriesModel.type; + _this.defaultValueDimensions = [{ + name: 'open', + defaultTooltip: true + }, { + name: 'close', + defaultTooltip: true + }, { + name: 'lowest', + defaultTooltip: true + }, { + name: 'highest', + defaultTooltip: true + }]; + return _this; + } + /** + * Get dimension for shadow in dataZoom + * @return dimension name + */ + + + CandlestickSeriesModel.prototype.getShadowDim = function () { + return 'open'; + }; + + CandlestickSeriesModel.prototype.brushSelector = function (dataIndex, data, selectors) { + var itemLayout = data.getItemLayout(dataIndex); + return itemLayout && selectors.rect(itemLayout.brushRect); + }; + + CandlestickSeriesModel.type = 'series.candlestick'; + CandlestickSeriesModel.dependencies = ['xAxis', 'yAxis', 'grid']; + CandlestickSeriesModel.defaultOption = { + // zlevel: 0, + z: 2, + coordinateSystem: 'cartesian2d', + legendHoverLink: true, + // xAxisIndex: 0, + // yAxisIndex: 0, + layout: null, + clip: true, + itemStyle: { + color: '#eb5454', + color0: '#47b262', + borderColor: '#eb5454', + borderColor0: '#47b262', + // borderColor: '#d24040', + // borderColor0: '#398f4f', + borderWidth: 1 + }, + emphasis: { + scale: true, + itemStyle: { + borderWidth: 2 + } + }, + barMaxWidth: null, + barMinWidth: null, + barWidth: null, + large: true, + largeThreshold: 600, + progressive: 3e3, + progressiveThreshold: 1e4, + progressiveChunkMode: 'mod', + animationEasing: 'linear', + animationDuration: 300 + }; + return CandlestickSeriesModel; + }(SeriesModel); + + mixin(CandlestickSeriesModel, WhiskerBoxCommonMixin, true); + + function candlestickPreprocessor(option) { + if (!option || !isArray(option.series)) { + return; + } // Translate 'k' to 'candlestick'. + + + each(option.series, function (seriesItem) { + if (isObject(seriesItem) && seriesItem.type === 'k') { + seriesItem.type = 'candlestick'; + } + }); + } + + var positiveBorderColorQuery = ['itemStyle', 'borderColor']; + var negativeBorderColorQuery = ['itemStyle', 'borderColor0']; + var positiveColorQuery = ['itemStyle', 'color']; + var negativeColorQuery = ['itemStyle', 'color0']; + var candlestickVisual = { + seriesType: 'candlestick', + plan: createRenderPlanner(), + // For legend. + performRawSeries: true, + reset: function (seriesModel, ecModel) { + function getColor(sign, model) { + return model.get(sign > 0 ? positiveColorQuery : negativeColorQuery); + } + + function getBorderColor(sign, model) { + return model.get(sign > 0 ? positiveBorderColorQuery : negativeBorderColorQuery); + } // Only visible series has each data be visual encoded + + + if (ecModel.isSeriesFiltered(seriesModel)) { + return; + } + + var isLargeRender = seriesModel.pipelineContext.large; + return !isLargeRender && { + progress: function (params, data) { + var dataIndex; + + while ((dataIndex = params.next()) != null) { + var itemModel = data.getItemModel(dataIndex); + var sign = data.getItemLayout(dataIndex).sign; + var style = itemModel.getItemStyle(); + style.fill = getColor(sign, itemModel); + style.stroke = getBorderColor(sign, itemModel) || style.fill; + var existsStyle = data.ensureUniqueItemVisual(dataIndex, 'style'); + extend(existsStyle, style); + } + } + }; + } + }; + + var candlestickLayout = { + seriesType: 'candlestick', + plan: createRenderPlanner(), + reset: function (seriesModel) { + var coordSys = seriesModel.coordinateSystem; + var data = seriesModel.getData(); + var candleWidth = calculateCandleWidth(seriesModel, data); + var cDimIdx = 0; + var vDimIdx = 1; + var coordDims = ['x', 'y']; + var cDimI = data.getDimensionIndex(data.mapDimension(coordDims[cDimIdx])); + var vDimsI = map(data.mapDimensionsAll(coordDims[vDimIdx]), data.getDimensionIndex, data); + var openDimI = vDimsI[0]; + var closeDimI = vDimsI[1]; + var lowestDimI = vDimsI[2]; + var highestDimI = vDimsI[3]; + data.setLayout({ + candleWidth: candleWidth, + // The value is experimented visually. + isSimpleBox: candleWidth <= 1.3 + }); + + if (cDimI < 0 || vDimsI.length < 4) { + return; + } + + return { + progress: seriesModel.pipelineContext.large ? largeProgress : normalProgress + }; + + function normalProgress(params, data) { + var dataIndex; + var store = data.getStore(); + + while ((dataIndex = params.next()) != null) { + var axisDimVal = store.get(cDimI, dataIndex); + var openVal = store.get(openDimI, dataIndex); + var closeVal = store.get(closeDimI, dataIndex); + var lowestVal = store.get(lowestDimI, dataIndex); + var highestVal = store.get(highestDimI, dataIndex); + var ocLow = Math.min(openVal, closeVal); + var ocHigh = Math.max(openVal, closeVal); + var ocLowPoint = getPoint(ocLow, axisDimVal); + var ocHighPoint = getPoint(ocHigh, axisDimVal); + var lowestPoint = getPoint(lowestVal, axisDimVal); + var highestPoint = getPoint(highestVal, axisDimVal); + var ends = []; + addBodyEnd(ends, ocHighPoint, 0); + addBodyEnd(ends, ocLowPoint, 1); + ends.push(subPixelOptimizePoint(highestPoint), subPixelOptimizePoint(ocHighPoint), subPixelOptimizePoint(lowestPoint), subPixelOptimizePoint(ocLowPoint)); + data.setItemLayout(dataIndex, { + sign: getSign(store, dataIndex, openVal, closeVal, closeDimI), + initBaseline: openVal > closeVal ? ocHighPoint[vDimIdx] : ocLowPoint[vDimIdx], + ends: ends, + brushRect: makeBrushRect(lowestVal, highestVal, axisDimVal) + }); + } + + function getPoint(val, axisDimVal) { + var p = []; + p[cDimIdx] = axisDimVal; + p[vDimIdx] = val; + return isNaN(axisDimVal) || isNaN(val) ? [NaN, NaN] : coordSys.dataToPoint(p); + } + + function addBodyEnd(ends, point, start) { + var point1 = point.slice(); + var point2 = point.slice(); + point1[cDimIdx] = subPixelOptimize$1(point1[cDimIdx] + candleWidth / 2, 1, false); + point2[cDimIdx] = subPixelOptimize$1(point2[cDimIdx] - candleWidth / 2, 1, true); + start ? ends.push(point1, point2) : ends.push(point2, point1); + } + + function makeBrushRect(lowestVal, highestVal, axisDimVal) { + var pmin = getPoint(lowestVal, axisDimVal); + var pmax = getPoint(highestVal, axisDimVal); + pmin[cDimIdx] -= candleWidth / 2; + pmax[cDimIdx] -= candleWidth / 2; + return { + x: pmin[0], + y: pmin[1], + width: candleWidth , + height: pmax[1] - pmin[1] + }; + } + + function subPixelOptimizePoint(point) { + point[cDimIdx] = subPixelOptimize$1(point[cDimIdx], 1); + return point; + } + } + + function largeProgress(params, data) { + // Structure: [sign, x, yhigh, ylow, sign, x, yhigh, ylow, ...] + var points = createFloat32Array(params.count * 4); + var offset = 0; + var point; + var tmpIn = []; + var tmpOut = []; + var dataIndex; + var store = data.getStore(); + + while ((dataIndex = params.next()) != null) { + var axisDimVal = store.get(cDimI, dataIndex); + var openVal = store.get(openDimI, dataIndex); + var closeVal = store.get(closeDimI, dataIndex); + var lowestVal = store.get(lowestDimI, dataIndex); + var highestVal = store.get(highestDimI, dataIndex); + + if (isNaN(axisDimVal) || isNaN(lowestVal) || isNaN(highestVal)) { + points[offset++] = NaN; + offset += 3; + continue; + } + + points[offset++] = getSign(store, dataIndex, openVal, closeVal, closeDimI); + tmpIn[cDimIdx] = axisDimVal; + tmpIn[vDimIdx] = lowestVal; + point = coordSys.dataToPoint(tmpIn, null, tmpOut); + points[offset++] = point ? point[0] : NaN; + points[offset++] = point ? point[1] : NaN; + tmpIn[vDimIdx] = highestVal; + point = coordSys.dataToPoint(tmpIn, null, tmpOut); + points[offset++] = point ? point[1] : NaN; + } + + data.setLayout('largePoints', points); + } + } + }; + + function getSign(store, dataIndex, openVal, closeVal, closeDimI) { + var sign; + + if (openVal > closeVal) { + sign = -1; + } else if (openVal < closeVal) { + sign = 1; + } else { + sign = dataIndex > 0 // If close === open, compare with close of last record + ? store.get(closeDimI, dataIndex - 1) <= closeVal ? 1 : -1 : // No record of previous, set to be positive + 1; + } + + return sign; + } + + function calculateCandleWidth(seriesModel, data) { + var baseAxis = seriesModel.getBaseAxis(); + var extent; + var bandWidth = baseAxis.type === 'category' ? baseAxis.getBandWidth() : (extent = baseAxis.getExtent(), Math.abs(extent[1] - extent[0]) / data.count()); + var barMaxWidth = parsePercent$1(retrieve2(seriesModel.get('barMaxWidth'), bandWidth), bandWidth); + var barMinWidth = parsePercent$1(retrieve2(seriesModel.get('barMinWidth'), 1), bandWidth); + var barWidth = seriesModel.get('barWidth'); + return barWidth != null ? parsePercent$1(barWidth, bandWidth) // Put max outer to ensure bar visible in spite of overlap. + : Math.max(Math.min(bandWidth / 2, barMaxWidth), barMinWidth); + } + + function install$k(registers) { + registers.registerChartView(CandlestickView); + registers.registerSeriesModel(CandlestickSeriesModel); + registers.registerPreprocessor(candlestickPreprocessor); + registers.registerVisual(candlestickVisual); + registers.registerLayout(candlestickLayout); + } + + function updateRipplePath(rippleGroup, effectCfg) { + var color = effectCfg.rippleEffectColor || effectCfg.color; + rippleGroup.eachChild(function (ripplePath) { + ripplePath.attr({ + z: effectCfg.z, + zlevel: effectCfg.zlevel, + style: { + stroke: effectCfg.brushType === 'stroke' ? color : null, + fill: effectCfg.brushType === 'fill' ? color : null + } + }); + }); + } + + var EffectSymbol = + /** @class */ + function (_super) { + __extends(EffectSymbol, _super); + + function EffectSymbol(data, idx) { + var _this = _super.call(this) || this; + + var symbol = new Symbol(data, idx); + var rippleGroup = new Group(); + + _this.add(symbol); + + _this.add(rippleGroup); + + _this.updateData(data, idx); + + return _this; + } + + EffectSymbol.prototype.stopEffectAnimation = function () { + this.childAt(1).removeAll(); + }; + + EffectSymbol.prototype.startEffectAnimation = function (effectCfg) { + var symbolType = effectCfg.symbolType; + var color = effectCfg.color; + var rippleNumber = effectCfg.rippleNumber; + var rippleGroup = this.childAt(1); + + for (var i = 0; i < rippleNumber; i++) { + // If width/height are set too small (e.g., set to 1) on ios10 + // and macOS Sierra, a circle stroke become a rect, no matter what + // the scale is set. So we set width/height as 2. See #4136. + var ripplePath = createSymbol(symbolType, -1, -1, 2, 2, color); + ripplePath.attr({ + style: { + strokeNoScale: true + }, + z2: 99, + silent: true, + scaleX: 0.5, + scaleY: 0.5 + }); + var delay = -i / rippleNumber * effectCfg.period + effectCfg.effectOffset; + ripplePath.animate('', true).when(effectCfg.period, { + scaleX: effectCfg.rippleScale / 2, + scaleY: effectCfg.rippleScale / 2 + }).delay(delay).start(); + ripplePath.animateStyle(true).when(effectCfg.period, { + opacity: 0 + }).delay(delay).start(); + rippleGroup.add(ripplePath); + } + + updateRipplePath(rippleGroup, effectCfg); + }; + /** + * Update effect symbol + */ + + + EffectSymbol.prototype.updateEffectAnimation = function (effectCfg) { + var oldEffectCfg = this._effectCfg; + var rippleGroup = this.childAt(1); // Must reinitialize effect if following configuration changed + + var DIFFICULT_PROPS = ['symbolType', 'period', 'rippleScale', 'rippleNumber']; + + for (var i = 0; i < DIFFICULT_PROPS.length; i++) { + var propName = DIFFICULT_PROPS[i]; + + if (oldEffectCfg[propName] !== effectCfg[propName]) { + this.stopEffectAnimation(); + this.startEffectAnimation(effectCfg); + return; + } + } + + updateRipplePath(rippleGroup, effectCfg); + }; + /** + * Highlight symbol + */ + + + EffectSymbol.prototype.highlight = function () { + enterEmphasis(this); + }; + /** + * Downplay symbol + */ + + + EffectSymbol.prototype.downplay = function () { + leaveEmphasis(this); + }; + + EffectSymbol.prototype.getSymbolType = function () { + var symbol = this.childAt(0); + return symbol && symbol.getSymbolType(); + }; + /** + * Update symbol properties + */ + + + EffectSymbol.prototype.updateData = function (data, idx) { + var _this = this; + + var seriesModel = data.hostModel; + this.childAt(0).updateData(data, idx); + var rippleGroup = this.childAt(1); + var itemModel = data.getItemModel(idx); + var symbolType = data.getItemVisual(idx, 'symbol'); + var symbolSize = normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize')); + var symbolStyle = data.getItemVisual(idx, 'style'); + var color = symbolStyle && symbolStyle.fill; + var emphasisModel = itemModel.getModel('emphasis'); + rippleGroup.setScale(symbolSize); + rippleGroup.traverse(function (ripplePath) { + ripplePath.setStyle('fill', color); + }); + var symbolOffset = normalizeSymbolOffset(data.getItemVisual(idx, 'symbolOffset'), symbolSize); + + if (symbolOffset) { + rippleGroup.x = symbolOffset[0]; + rippleGroup.y = symbolOffset[1]; + } + + var symbolRotate = data.getItemVisual(idx, 'symbolRotate'); + rippleGroup.rotation = (symbolRotate || 0) * Math.PI / 180 || 0; + var effectCfg = {}; + effectCfg.showEffectOn = seriesModel.get('showEffectOn'); + effectCfg.rippleScale = itemModel.get(['rippleEffect', 'scale']); + effectCfg.brushType = itemModel.get(['rippleEffect', 'brushType']); + effectCfg.period = itemModel.get(['rippleEffect', 'period']) * 1000; + effectCfg.effectOffset = idx / data.count(); + effectCfg.z = seriesModel.getShallow('z') || 0; + effectCfg.zlevel = seriesModel.getShallow('zlevel') || 0; + effectCfg.symbolType = symbolType; + effectCfg.color = color; + effectCfg.rippleEffectColor = itemModel.get(['rippleEffect', 'color']); + effectCfg.rippleNumber = itemModel.get(['rippleEffect', 'number']); + + if (effectCfg.showEffectOn === 'render') { + this._effectCfg ? this.updateEffectAnimation(effectCfg) : this.startEffectAnimation(effectCfg); + this._effectCfg = effectCfg; + } else { + // Not keep old effect config + this._effectCfg = null; + this.stopEffectAnimation(); + + this.onHoverStateChange = function (toState) { + if (toState === 'emphasis') { + if (effectCfg.showEffectOn !== 'render') { + _this.startEffectAnimation(effectCfg); + } + } else if (toState === 'normal') { + if (effectCfg.showEffectOn !== 'render') { + _this.stopEffectAnimation(); + } + } + }; + } + + this._effectCfg = effectCfg; + toggleHoverEmphasis(this, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled')); + }; + + EffectSymbol.prototype.fadeOut = function (cb) { + cb && cb(); + }; + return EffectSymbol; + }(Group); + + var EffectScatterView = + /** @class */ + function (_super) { + __extends(EffectScatterView, _super); + + function EffectScatterView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = EffectScatterView.type; + return _this; + } + + EffectScatterView.prototype.init = function () { + this._symbolDraw = new SymbolDraw(EffectSymbol); + }; + + EffectScatterView.prototype.render = function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + var effectSymbolDraw = this._symbolDraw; + effectSymbolDraw.updateData(data, { + clipShape: this._getClipShape(seriesModel) + }); + this.group.add(effectSymbolDraw.group); + }; + + EffectScatterView.prototype._getClipShape = function (seriesModel) { + var coordSys = seriesModel.coordinateSystem; + var clipArea = coordSys && coordSys.getArea && coordSys.getArea(); + return seriesModel.get('clip', true) ? clipArea : null; + }; + + EffectScatterView.prototype.updateTransform = function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + this.group.dirty(); + var res = pointsLayout('').reset(seriesModel, ecModel, api); + + if (res.progress) { + res.progress({ + start: 0, + end: data.count(), + count: data.count() + }, data); + } + + this._symbolDraw.updateLayout(); + }; + + EffectScatterView.prototype._updateGroupTransform = function (seriesModel) { + var coordSys = seriesModel.coordinateSystem; + + if (coordSys && coordSys.getRoamTransform) { + this.group.transform = clone$2(coordSys.getRoamTransform()); + this.group.decomposeTransform(); + } + }; + + EffectScatterView.prototype.remove = function (ecModel, api) { + this._symbolDraw && this._symbolDraw.remove(true); + }; + + EffectScatterView.type = 'effectScatter'; + return EffectScatterView; + }(ChartView); + + var EffectScatterSeriesModel = + /** @class */ + function (_super) { + __extends(EffectScatterSeriesModel, _super); + + function EffectScatterSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = EffectScatterSeriesModel.type; + _this.hasSymbolVisual = true; + return _this; + } + + EffectScatterSeriesModel.prototype.getInitialData = function (option, ecModel) { + return createSeriesData(null, this, { + useEncodeDefaulter: true + }); + }; + + EffectScatterSeriesModel.prototype.brushSelector = function (dataIndex, data, selectors) { + return selectors.point(data.getItemLayout(dataIndex)); + }; + + EffectScatterSeriesModel.type = 'series.effectScatter'; + EffectScatterSeriesModel.dependencies = ['grid', 'polar']; + EffectScatterSeriesModel.defaultOption = { + coordinateSystem: 'cartesian2d', + // zlevel: 0, + z: 2, + legendHoverLink: true, + effectType: 'ripple', + progressive: 0, + // When to show the effect, option: 'render'|'emphasis' + showEffectOn: 'render', + clip: true, + // Ripple effect config + rippleEffect: { + period: 4, + // Scale of ripple + scale: 2.5, + // Brush type can be fill or stroke + brushType: 'fill', + // Ripple number + number: 3 + }, + universalTransition: { + divideShape: 'clone' + }, + // Cartesian coordinate system + // xAxisIndex: 0, + // yAxisIndex: 0, + // Polar coordinate system + // polarIndex: 0, + // Geo coordinate system + // geoIndex: 0, + // symbol: null, // 图形类型 + symbolSize: 10 // 图形大小,半宽(半径)参数,当图形为方向或菱形则总宽度为symbolSize * 2 + // symbolRotate: null, // 图形旋转控制 + // itemStyle: { + // opacity: 1 + // } + + }; + return EffectScatterSeriesModel; + }(SeriesModel); + + function install$l(registers) { + registers.registerChartView(EffectScatterView); + registers.registerSeriesModel(EffectScatterSeriesModel); + registers.registerLayout(pointsLayout('effectScatter')); + } + + var EffectLine = + /** @class */ + function (_super) { + __extends(EffectLine, _super); + + function EffectLine(lineData, idx, seriesScope) { + var _this = _super.call(this) || this; + + _this.add(_this.createLine(lineData, idx, seriesScope)); + + _this._updateEffectSymbol(lineData, idx); + + return _this; + } + + EffectLine.prototype.createLine = function (lineData, idx, seriesScope) { + return new Line$1(lineData, idx, seriesScope); + }; + + EffectLine.prototype._updateEffectSymbol = function (lineData, idx) { + var itemModel = lineData.getItemModel(idx); + var effectModel = itemModel.getModel('effect'); + var size = effectModel.get('symbolSize'); + var symbolType = effectModel.get('symbol'); + + if (!isArray(size)) { + size = [size, size]; + } + + var lineStyle = lineData.getItemVisual(idx, 'style'); + var color = effectModel.get('color') || lineStyle && lineStyle.stroke; + var symbol = this.childAt(1); + + if (this._symbolType !== symbolType) { + // Remove previous + this.remove(symbol); + symbol = createSymbol(symbolType, -0.5, -0.5, 1, 1, color); + symbol.z2 = 100; + symbol.culling = true; + this.add(symbol); + } // Symbol may be removed if loop is false + + + if (!symbol) { + return; + } // Shadow color is same with color in default + + + symbol.setStyle('shadowColor', color); + symbol.setStyle(effectModel.getItemStyle(['color'])); + symbol.scaleX = size[0]; + symbol.scaleY = size[1]; + symbol.setColor(color); + this._symbolType = symbolType; + this._symbolScale = size; + + this._updateEffectAnimation(lineData, effectModel, idx); + }; + + EffectLine.prototype._updateEffectAnimation = function (lineData, effectModel, idx) { + var symbol = this.childAt(1); + + if (!symbol) { + return; + } + + var points = lineData.getItemLayout(idx); + var period = effectModel.get('period') * 1000; + var loop = effectModel.get('loop'); + var constantSpeed = effectModel.get('constantSpeed'); + var delayExpr = retrieve(effectModel.get('delay'), function (idx) { + return idx / lineData.count() * period / 3; + }); // Ignore when updating + + symbol.ignore = true; + + this._updateAnimationPoints(symbol, points); + + if (constantSpeed > 0) { + period = this._getLineLength(symbol) / constantSpeed * 1000; + } + + if (period !== this._period || loop !== this._loop) { + symbol.stopAnimation(); + var delayNum = void 0; + + if (isFunction(delayExpr)) { + delayNum = delayExpr(idx); + } else { + delayNum = delayExpr; + } + + if (symbol.__t > 0) { + delayNum = -period * symbol.__t; + } + + this._animateSymbol(symbol, period, delayNum, loop); + } + + this._period = period; + this._loop = loop; + }; + + EffectLine.prototype._animateSymbol = function (symbol, period, delayNum, loop) { + if (period > 0) { + symbol.__t = 0; + var self_1 = this; + var animator = symbol.animate('', loop).when(period, { + __t: 1 + }).delay(delayNum).during(function () { + self_1._updateSymbolPosition(symbol); + }); + + if (!loop) { + animator.done(function () { + self_1.remove(symbol); + }); + } + + animator.start(); + } + }; + + EffectLine.prototype._getLineLength = function (symbol) { + // Not so accurate + return dist(symbol.__p1, symbol.__cp1) + dist(symbol.__cp1, symbol.__p2); + }; + + EffectLine.prototype._updateAnimationPoints = function (symbol, points) { + symbol.__p1 = points[0]; + symbol.__p2 = points[1]; + symbol.__cp1 = points[2] || [(points[0][0] + points[1][0]) / 2, (points[0][1] + points[1][1]) / 2]; + }; + + EffectLine.prototype.updateData = function (lineData, idx, seriesScope) { + this.childAt(0).updateData(lineData, idx, seriesScope); + + this._updateEffectSymbol(lineData, idx); + }; + + EffectLine.prototype._updateSymbolPosition = function (symbol) { + var p1 = symbol.__p1; + var p2 = symbol.__p2; + var cp1 = symbol.__cp1; + var t = symbol.__t; + var pos = [symbol.x, symbol.y]; + var lastPos = pos.slice(); + var quadraticAt$1 = quadraticAt; + var quadraticDerivativeAt$1 = quadraticDerivativeAt; + pos[0] = quadraticAt$1(p1[0], cp1[0], p2[0], t); + pos[1] = quadraticAt$1(p1[1], cp1[1], p2[1], t); // Tangent + + var tx = quadraticDerivativeAt$1(p1[0], cp1[0], p2[0], t); + var ty = quadraticDerivativeAt$1(p1[1], cp1[1], p2[1], t); + symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2; // enable continuity trail for 'line', 'rect', 'roundRect' symbolType + + if (this._symbolType === 'line' || this._symbolType === 'rect' || this._symbolType === 'roundRect') { + if (symbol.__lastT !== undefined && symbol.__lastT < symbol.__t) { + symbol.scaleY = dist(lastPos, pos) * 1.05; // make sure the last segment render within endPoint + + if (t === 1) { + pos[0] = lastPos[0] + (pos[0] - lastPos[0]) / 2; + pos[1] = lastPos[1] + (pos[1] - lastPos[1]) / 2; + } + } else if (symbol.__lastT === 1) { + // After first loop, symbol.__t does NOT start with 0, so connect p1 to pos directly. + symbol.scaleY = 2 * dist(p1, pos); + } else { + symbol.scaleY = this._symbolScale[1]; + } + } + + symbol.__lastT = symbol.__t; + symbol.ignore = false; + symbol.x = pos[0]; + symbol.y = pos[1]; + }; + + EffectLine.prototype.updateLayout = function (lineData, idx) { + this.childAt(0).updateLayout(lineData, idx); + var effectModel = lineData.getItemModel(idx).getModel('effect'); + + this._updateEffectAnimation(lineData, effectModel, idx); + }; + + return EffectLine; + }(Group); + + var Polyline$1 = + /** @class */ + function (_super) { + __extends(Polyline$1, _super); + + function Polyline$1(lineData, idx, seriesScope) { + var _this = _super.call(this) || this; + + _this._createPolyline(lineData, idx, seriesScope); + + return _this; + } + + Polyline$1.prototype._createPolyline = function (lineData, idx, seriesScope) { + // let seriesModel = lineData.hostModel; + var points = lineData.getItemLayout(idx); + var line = new Polyline({ + shape: { + points: points + } + }); + this.add(line); + + this._updateCommonStl(lineData, idx, seriesScope); + }; + + Polyline$1.prototype.updateData = function (lineData, idx, seriesScope) { + var seriesModel = lineData.hostModel; + var line = this.childAt(0); + var target = { + shape: { + points: lineData.getItemLayout(idx) + } + }; + updateProps(line, target, seriesModel, idx); + + this._updateCommonStl(lineData, idx, seriesScope); + }; + + Polyline$1.prototype._updateCommonStl = function (lineData, idx, seriesScope) { + var line = this.childAt(0); + var itemModel = lineData.getItemModel(idx); + var emphasisLineStyle = seriesScope && seriesScope.emphasisLineStyle; + var focus = seriesScope && seriesScope.focus; + var blurScope = seriesScope && seriesScope.blurScope; + var emphasisDisabled = seriesScope && seriesScope.emphasisDisabled; + + if (!seriesScope || lineData.hasItemOption) { + var emphasisModel = itemModel.getModel('emphasis'); + emphasisLineStyle = emphasisModel.getModel('lineStyle').getLineStyle(); + emphasisDisabled = emphasisModel.get('disabled'); + focus = emphasisModel.get('focus'); + blurScope = emphasisModel.get('blurScope'); + } + + line.useStyle(lineData.getItemVisual(idx, 'style')); + line.style.fill = null; + line.style.strokeNoScale = true; + var lineEmphasisState = line.ensureState('emphasis'); + lineEmphasisState.style = emphasisLineStyle; + toggleHoverEmphasis(this, focus, blurScope, emphasisDisabled); + }; + + Polyline$1.prototype.updateLayout = function (lineData, idx) { + var polyline = this.childAt(0); + polyline.setShape('points', lineData.getItemLayout(idx)); + }; + return Polyline$1; + }(Group); + + var EffectPolyline = + /** @class */ + function (_super) { + __extends(EffectPolyline, _super); + + function EffectPolyline() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this._lastFrame = 0; + _this._lastFramePercent = 0; + return _this; + } // Override + + + EffectPolyline.prototype.createLine = function (lineData, idx, seriesScope) { + return new Polyline$1(lineData, idx, seriesScope); + }; + + EffectPolyline.prototype._updateAnimationPoints = function (symbol, points) { + this._points = points; + var accLenArr = [0]; + var len = 0; + + for (var i = 1; i < points.length; i++) { + var p1 = points[i - 1]; + var p2 = points[i]; + len += dist(p1, p2); + accLenArr.push(len); + } + + if (len === 0) { + this._length = 0; + return; + } + + for (var i = 0; i < accLenArr.length; i++) { + accLenArr[i] /= len; + } + + this._offsets = accLenArr; + this._length = len; + }; + + EffectPolyline.prototype._getLineLength = function () { + return this._length; + }; + + EffectPolyline.prototype._updateSymbolPosition = function (symbol) { + var t = symbol.__t; + var points = this._points; + var offsets = this._offsets; + var len = points.length; + + if (!offsets) { + // Has length 0 + return; + } + + var lastFrame = this._lastFrame; + var frame; + + if (t < this._lastFramePercent) { + // Start from the next frame + // PENDING start from lastFrame ? + var start = Math.min(lastFrame + 1, len - 1); + + for (frame = start; frame >= 0; frame--) { + if (offsets[frame] <= t) { + break; + } + } // PENDING really need to do this ? + + + frame = Math.min(frame, len - 2); + } else { + for (frame = lastFrame; frame < len; frame++) { + if (offsets[frame] > t) { + break; + } + } + + frame = Math.min(frame - 1, len - 2); + } + + var p = (t - offsets[frame]) / (offsets[frame + 1] - offsets[frame]); + var p0 = points[frame]; + var p1 = points[frame + 1]; + symbol.x = p0[0] * (1 - p) + p * p1[0]; + symbol.y = p0[1] * (1 - p) + p * p1[1]; + var tx = p1[0] - p0[0]; + var ty = p1[1] - p0[1]; + symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2; + this._lastFrame = frame; + this._lastFramePercent = t; + symbol.ignore = false; + }; + return EffectPolyline; + }(EffectLine); + + var LargeLinesPathShape = + /** @class */ + function () { + function LargeLinesPathShape() { + this.polyline = false; + this.curveness = 0; + this.segs = []; + } + + return LargeLinesPathShape; + }(); + + var LargeLinesPath = + /** @class */ + function (_super) { + __extends(LargeLinesPath, _super); + + function LargeLinesPath(opts) { + var _this = _super.call(this, opts) || this; + + _this._off = 0; + _this.hoverDataIdx = -1; + return _this; + } + + LargeLinesPath.prototype.reset = function () { + this.notClear = false; + this._off = 0; + }; + + LargeLinesPath.prototype.getDefaultStyle = function () { + return { + stroke: '#000', + fill: null + }; + }; + + LargeLinesPath.prototype.getDefaultShape = function () { + return new LargeLinesPathShape(); + }; + + LargeLinesPath.prototype.buildPath = function (ctx, shape) { + var segs = shape.segs; + var curveness = shape.curveness; + var i; + + if (shape.polyline) { + for (i = this._off; i < segs.length;) { + var count = segs[i++]; + + if (count > 0) { + ctx.moveTo(segs[i++], segs[i++]); + + for (var k = 1; k < count; k++) { + ctx.lineTo(segs[i++], segs[i++]); + } + } + } + } else { + for (i = this._off; i < segs.length;) { + var x0 = segs[i++]; + var y0 = segs[i++]; + var x1 = segs[i++]; + var y1 = segs[i++]; + ctx.moveTo(x0, y0); + + if (curveness > 0) { + var x2 = (x0 + x1) / 2 - (y0 - y1) * curveness; + var y2 = (y0 + y1) / 2 - (x1 - x0) * curveness; + ctx.quadraticCurveTo(x2, y2, x1, y1); + } else { + ctx.lineTo(x1, y1); + } + } + } + + if (this.incremental) { + this._off = i; + this.notClear = true; + } + }; + + LargeLinesPath.prototype.findDataIndex = function (x, y) { + var shape = this.shape; + var segs = shape.segs; + var curveness = shape.curveness; + var lineWidth = this.style.lineWidth; + + if (shape.polyline) { + var dataIndex = 0; + + for (var i = 0; i < segs.length;) { + var count = segs[i++]; + + if (count > 0) { + var x0 = segs[i++]; + var y0 = segs[i++]; + + for (var k = 1; k < count; k++) { + var x1 = segs[i++]; + var y1 = segs[i++]; + + if (containStroke(x0, y0, x1, y1, lineWidth, x, y)) { + return dataIndex; + } + } + } + + dataIndex++; + } + } else { + var dataIndex = 0; + + for (var i = 0; i < segs.length;) { + var x0 = segs[i++]; + var y0 = segs[i++]; + var x1 = segs[i++]; + var y1 = segs[i++]; + + if (curveness > 0) { + var x2 = (x0 + x1) / 2 - (y0 - y1) * curveness; + var y2 = (y0 + y1) / 2 - (x1 - x0) * curveness; + + if (containStroke$2(x0, y0, x2, y2, x1, y1, lineWidth, x, y)) { + return dataIndex; + } + } else { + if (containStroke(x0, y0, x1, y1, lineWidth, x, y)) { + return dataIndex; + } + } + + dataIndex++; + } + } + + return -1; + }; + + LargeLinesPath.prototype.contain = function (x, y) { + var localPos = this.transformCoordToLocal(x, y); + var rect = this.getBoundingRect(); + x = localPos[0]; + y = localPos[1]; + + if (rect.contain(x, y)) { + // Cache found data index. + var dataIdx = this.hoverDataIdx = this.findDataIndex(x, y); + return dataIdx >= 0; + } + + this.hoverDataIdx = -1; + return false; + }; + + LargeLinesPath.prototype.getBoundingRect = function () { + // Ignore stroke for large symbol draw. + var rect = this._rect; + + if (!rect) { + var shape = this.shape; + var points = shape.segs; + var minX = Infinity; + var minY = Infinity; + var maxX = -Infinity; + var maxY = -Infinity; + + for (var i = 0; i < points.length;) { + var x = points[i++]; + var y = points[i++]; + minX = Math.min(x, minX); + maxX = Math.max(x, maxX); + minY = Math.min(y, minY); + maxY = Math.max(y, maxY); + } + + rect = this._rect = new BoundingRect(minX, minY, maxX, maxY); + } + + return rect; + }; + + return LargeLinesPath; + }(Path); + + var LargeLineDraw = + /** @class */ + function () { + function LargeLineDraw() { + this.group = new Group(); + } + /** + * Update symbols draw by new data + */ + + + LargeLineDraw.prototype.updateData = function (data) { + this._clear(); + + var lineEl = this._create(); + + lineEl.setShape({ + segs: data.getLayout('linesPoints') + }); + + this._setCommon(lineEl, data); + }; + /** + * @override + */ + + LargeLineDraw.prototype.incrementalPrepareUpdate = function (data) { + this.group.removeAll(); + + this._clear(); + }; + /** + * @override + */ + + LargeLineDraw.prototype.incrementalUpdate = function (taskParams, data) { + var lastAdded = this._newAdded[0]; + var linePoints = data.getLayout('linesPoints'); + var oldSegs = lastAdded && lastAdded.shape.segs; // Merging the exists. Each element has 1e4 points. + // Consider the performance balance between too much elements and too much points in one shape(may affect hover optimization) + + if (oldSegs && oldSegs.length < 2e4) { + var oldLen = oldSegs.length; + var newSegs = new Float32Array(oldLen + linePoints.length); // Concat two array + + newSegs.set(oldSegs); + newSegs.set(linePoints, oldLen); + lastAdded.setShape({ + segs: newSegs + }); + } else { + // Clear + this._newAdded = []; + + var lineEl = this._create(); + + lineEl.incremental = true; + lineEl.setShape({ + segs: linePoints + }); + + this._setCommon(lineEl, data); + + lineEl.__startIndex = taskParams.start; + } + }; + /** + * @override + */ + + + LargeLineDraw.prototype.remove = function () { + this._clear(); + }; + + LargeLineDraw.prototype.eachRendered = function (cb) { + this._newAdded[0] && cb(this._newAdded[0]); + }; + + LargeLineDraw.prototype._create = function () { + var lineEl = new LargeLinesPath({ + cursor: 'default' + }); + + this._newAdded.push(lineEl); + + this.group.add(lineEl); + return lineEl; + }; + + LargeLineDraw.prototype._setCommon = function (lineEl, data, isIncremental) { + var hostModel = data.hostModel; + lineEl.setShape({ + polyline: hostModel.get('polyline'), + curveness: hostModel.get(['lineStyle', 'curveness']) + }); + lineEl.useStyle(hostModel.getModel('lineStyle').getLineStyle()); + lineEl.style.strokeNoScale = true; + var style = data.getVisual('style'); + + if (style && style.stroke) { + lineEl.setStyle('stroke', style.stroke); + } + + lineEl.setStyle('fill', null); + var ecData = getECData(lineEl); // Enable tooltip + // PENDING May have performance issue when path is extremely large + + ecData.seriesIndex = hostModel.seriesIndex; + lineEl.on('mousemove', function (e) { + ecData.dataIndex = null; + var dataIndex = lineEl.hoverDataIdx; + + if (dataIndex > 0) { + // Provide dataIndex for tooltip + ecData.dataIndex = dataIndex + lineEl.__startIndex; + } + }); + }; + + LargeLineDraw.prototype._clear = function () { + this._newAdded = []; + this.group.removeAll(); + }; + return LargeLineDraw; + }(); + + var linesLayout = { + seriesType: 'lines', + plan: createRenderPlanner(), + reset: function (seriesModel) { + var coordSys = seriesModel.coordinateSystem; + + if (!coordSys) { + if ("development" !== 'production') { + error('The lines series must have a coordinate system.'); + } + + return; + } + + var isPolyline = seriesModel.get('polyline'); + var isLarge = seriesModel.pipelineContext.large; + return { + progress: function (params, lineData) { + var lineCoords = []; + + if (isLarge) { + var points = void 0; + var segCount = params.end - params.start; + + if (isPolyline) { + var totalCoordsCount = 0; + + for (var i = params.start; i < params.end; i++) { + totalCoordsCount += seriesModel.getLineCoordsCount(i); + } + + points = new Float32Array(segCount + totalCoordsCount * 2); + } else { + points = new Float32Array(segCount * 4); + } + + var offset = 0; + var pt = []; + + for (var i = params.start; i < params.end; i++) { + var len = seriesModel.getLineCoords(i, lineCoords); + + if (isPolyline) { + points[offset++] = len; + } + + for (var k = 0; k < len; k++) { + pt = coordSys.dataToPoint(lineCoords[k], false, pt); + points[offset++] = pt[0]; + points[offset++] = pt[1]; + } + } + + lineData.setLayout('linesPoints', points); + } else { + for (var i = params.start; i < params.end; i++) { + var itemModel = lineData.getItemModel(i); + var len = seriesModel.getLineCoords(i, lineCoords); + var pts = []; + + if (isPolyline) { + for (var j = 0; j < len; j++) { + pts.push(coordSys.dataToPoint(lineCoords[j])); + } + } else { + pts[0] = coordSys.dataToPoint(lineCoords[0]); + pts[1] = coordSys.dataToPoint(lineCoords[1]); + var curveness = itemModel.get(['lineStyle', 'curveness']); + + if (+curveness) { + pts[2] = [(pts[0][0] + pts[1][0]) / 2 - (pts[0][1] - pts[1][1]) * curveness, (pts[0][1] + pts[1][1]) / 2 - (pts[1][0] - pts[0][0]) * curveness]; + } + } + + lineData.setItemLayout(i, pts); + } + } + } + }; + } + }; + + var LinesView = + /** @class */ + function (_super) { + __extends(LinesView, _super); + + function LinesView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = LinesView.type; + return _this; + } + + LinesView.prototype.render = function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + + var lineDraw = this._updateLineDraw(data, seriesModel); + + var zlevel = seriesModel.get('zlevel'); + var trailLength = seriesModel.get(['effect', 'trailLength']); + var zr = api.getZr(); // Avoid the drag cause ghost shadow + // FIXME Better way ? + // SVG doesn't support + + var isSvg = zr.painter.getType() === 'svg'; + + if (!isSvg) { + zr.painter.getLayer(zlevel).clear(true); + } // Config layer with motion blur + + + if (this._lastZlevel != null && !isSvg) { + zr.configLayer(this._lastZlevel, { + motionBlur: false + }); + } + + if (this._showEffect(seriesModel) && trailLength > 0) { + if (!isSvg) { + zr.configLayer(zlevel, { + motionBlur: true, + lastFrameAlpha: Math.max(Math.min(trailLength / 10 + 0.9, 1), 0) + }); + } else if ("development" !== 'production') { + console.warn('SVG render mode doesn\'t support lines with trail effect'); + } + } + + lineDraw.updateData(data); + var clipPath = seriesModel.get('clip', true) && createClipPath(seriesModel.coordinateSystem, false, seriesModel); + + if (clipPath) { + this.group.setClipPath(clipPath); + } else { + this.group.removeClipPath(); + } + + this._lastZlevel = zlevel; + this._finished = true; + }; + + LinesView.prototype.incrementalPrepareRender = function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + + var lineDraw = this._updateLineDraw(data, seriesModel); + + lineDraw.incrementalPrepareUpdate(data); + + this._clearLayer(api); + + this._finished = false; + }; + + LinesView.prototype.incrementalRender = function (taskParams, seriesModel, ecModel) { + this._lineDraw.incrementalUpdate(taskParams, seriesModel.getData()); + + this._finished = taskParams.end === seriesModel.getData().count(); + }; + + LinesView.prototype.eachRendered = function (cb) { + this._lineDraw && this._lineDraw.eachRendered(cb); + }; + + LinesView.prototype.updateTransform = function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + var pipelineContext = seriesModel.pipelineContext; + + if (!this._finished || pipelineContext.large || pipelineContext.progressiveRender) { + // TODO Don't have to do update in large mode. Only do it when there are millions of data. + return { + update: true + }; + } else { + // TODO Use same logic with ScatterView. + // Manually update layout + var res = linesLayout.reset(seriesModel, ecModel, api); + + if (res.progress) { + res.progress({ + start: 0, + end: data.count(), + count: data.count() + }, data); + } // Not in large mode + + + this._lineDraw.updateLayout(); + + this._clearLayer(api); + } + }; + + LinesView.prototype._updateLineDraw = function (data, seriesModel) { + var lineDraw = this._lineDraw; + + var hasEffect = this._showEffect(seriesModel); + + var isPolyline = !!seriesModel.get('polyline'); + var pipelineContext = seriesModel.pipelineContext; + var isLargeDraw = pipelineContext.large; + + if ("development" !== 'production') { + if (hasEffect && isLargeDraw) { + console.warn('Large lines not support effect'); + } + } + + if (!lineDraw || hasEffect !== this._hasEffet || isPolyline !== this._isPolyline || isLargeDraw !== this._isLargeDraw) { + if (lineDraw) { + lineDraw.remove(); + } + + lineDraw = this._lineDraw = isLargeDraw ? new LargeLineDraw() : new LineDraw(isPolyline ? hasEffect ? EffectPolyline : Polyline$1 : hasEffect ? EffectLine : Line$1); + this._hasEffet = hasEffect; + this._isPolyline = isPolyline; + this._isLargeDraw = isLargeDraw; + } + + this.group.add(lineDraw.group); + return lineDraw; + }; + + LinesView.prototype._showEffect = function (seriesModel) { + return !!seriesModel.get(['effect', 'show']); + }; + + LinesView.prototype._clearLayer = function (api) { + // Not use motion when dragging or zooming + var zr = api.getZr(); + var isSvg = zr.painter.getType() === 'svg'; + + if (!isSvg && this._lastZlevel != null) { + zr.painter.getLayer(this._lastZlevel).clear(true); + } + }; + + LinesView.prototype.remove = function (ecModel, api) { + this._lineDraw && this._lineDraw.remove(); + this._lineDraw = null; // Clear motion when lineDraw is removed + + this._clearLayer(api); + }; + + LinesView.prototype.dispose = function (ecModel, api) { + this.remove(ecModel, api); + }; + + LinesView.type = 'lines'; + return LinesView; + }(ChartView); + + var Uint32Arr = typeof Uint32Array === 'undefined' ? Array : Uint32Array; + var Float64Arr = typeof Float64Array === 'undefined' ? Array : Float64Array; + + function compatEc2(seriesOpt) { + var data = seriesOpt.data; + + if (data && data[0] && data[0][0] && data[0][0].coord) { + if ("development" !== 'production') { + console.warn('Lines data configuration has been changed to' + ' { coords:[[1,2],[2,3]] }'); + } + + seriesOpt.data = map(data, function (itemOpt) { + var coords = [itemOpt[0].coord, itemOpt[1].coord]; + var target = { + coords: coords + }; + + if (itemOpt[0].name) { + target.fromName = itemOpt[0].name; + } + + if (itemOpt[1].name) { + target.toName = itemOpt[1].name; + } + + return mergeAll([target, itemOpt[0], itemOpt[1]]); + }); + } + } + + var LinesSeriesModel = + /** @class */ + function (_super) { + __extends(LinesSeriesModel, _super); + + function LinesSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = LinesSeriesModel.type; + _this.visualStyleAccessPath = 'lineStyle'; + _this.visualDrawType = 'stroke'; + return _this; + } + + LinesSeriesModel.prototype.init = function (option) { + // The input data may be null/undefined. + option.data = option.data || []; // Not using preprocessor because mergeOption may not have series.type + + compatEc2(option); + + var result = this._processFlatCoordsArray(option.data); + + this._flatCoords = result.flatCoords; + this._flatCoordsOffset = result.flatCoordsOffset; + + if (result.flatCoords) { + option.data = new Float32Array(result.count); + } + + _super.prototype.init.apply(this, arguments); + }; + + LinesSeriesModel.prototype.mergeOption = function (option) { + compatEc2(option); + + if (option.data) { + // Only update when have option data to merge. + var result = this._processFlatCoordsArray(option.data); + + this._flatCoords = result.flatCoords; + this._flatCoordsOffset = result.flatCoordsOffset; + + if (result.flatCoords) { + option.data = new Float32Array(result.count); + } + } + + _super.prototype.mergeOption.apply(this, arguments); + }; + + LinesSeriesModel.prototype.appendData = function (params) { + var result = this._processFlatCoordsArray(params.data); + + if (result.flatCoords) { + if (!this._flatCoords) { + this._flatCoords = result.flatCoords; + this._flatCoordsOffset = result.flatCoordsOffset; + } else { + this._flatCoords = concatArray(this._flatCoords, result.flatCoords); + this._flatCoordsOffset = concatArray(this._flatCoordsOffset, result.flatCoordsOffset); + } + + params.data = new Float32Array(result.count); + } + + this.getRawData().appendData(params.data); + }; + + LinesSeriesModel.prototype._getCoordsFromItemModel = function (idx) { + var itemModel = this.getData().getItemModel(idx); + var coords = itemModel.option instanceof Array ? itemModel.option : itemModel.getShallow('coords'); + + if ("development" !== 'production') { + if (!(coords instanceof Array && coords.length > 0 && coords[0] instanceof Array)) { + throw new Error('Invalid coords ' + JSON.stringify(coords) + '. Lines must have 2d coords array in data item.'); + } + } + + return coords; + }; + + LinesSeriesModel.prototype.getLineCoordsCount = function (idx) { + if (this._flatCoordsOffset) { + return this._flatCoordsOffset[idx * 2 + 1]; + } else { + return this._getCoordsFromItemModel(idx).length; + } + }; + + LinesSeriesModel.prototype.getLineCoords = function (idx, out) { + if (this._flatCoordsOffset) { + var offset = this._flatCoordsOffset[idx * 2]; + var len = this._flatCoordsOffset[idx * 2 + 1]; + + for (var i = 0; i < len; i++) { + out[i] = out[i] || []; + out[i][0] = this._flatCoords[offset + i * 2]; + out[i][1] = this._flatCoords[offset + i * 2 + 1]; + } + + return len; + } else { + var coords = this._getCoordsFromItemModel(idx); + + for (var i = 0; i < coords.length; i++) { + out[i] = out[i] || []; + out[i][0] = coords[i][0]; + out[i][1] = coords[i][1]; + } + + return coords.length; + } + }; + + LinesSeriesModel.prototype._processFlatCoordsArray = function (data) { + var startOffset = 0; + + if (this._flatCoords) { + startOffset = this._flatCoords.length; + } // Stored as a typed array. In format + // Points Count(2) | x | y | x | y | Points Count(3) | x | y | x | y | x | y | + + + if (isNumber(data[0])) { + var len = data.length; // Store offset and len of each segment + + var coordsOffsetAndLenStorage = new Uint32Arr(len); + var coordsStorage = new Float64Arr(len); + var coordsCursor = 0; + var offsetCursor = 0; + var dataCount = 0; + + for (var i = 0; i < len;) { + dataCount++; + var count = data[i++]; // Offset + + coordsOffsetAndLenStorage[offsetCursor++] = coordsCursor + startOffset; // Len + + coordsOffsetAndLenStorage[offsetCursor++] = count; + + for (var k = 0; k < count; k++) { + var x = data[i++]; + var y = data[i++]; + coordsStorage[coordsCursor++] = x; + coordsStorage[coordsCursor++] = y; + + if (i > len) { + if ("development" !== 'production') { + throw new Error('Invalid data format.'); + } + } + } + } + + return { + flatCoordsOffset: new Uint32Array(coordsOffsetAndLenStorage.buffer, 0, offsetCursor), + flatCoords: coordsStorage, + count: dataCount + }; + } + + return { + flatCoordsOffset: null, + flatCoords: null, + count: data.length + }; + }; + + LinesSeriesModel.prototype.getInitialData = function (option, ecModel) { + if ("development" !== 'production') { + var CoordSys = CoordinateSystemManager.get(option.coordinateSystem); + + if (!CoordSys) { + throw new Error('Unkown coordinate system ' + option.coordinateSystem); + } + } + + var lineData = new SeriesData(['value'], this); + lineData.hasItemOption = false; + lineData.initData(option.data, [], function (dataItem, dimName, dataIndex, dimIndex) { + // dataItem is simply coords + if (dataItem instanceof Array) { + return NaN; + } else { + lineData.hasItemOption = true; + var value = dataItem.value; + + if (value != null) { + return value instanceof Array ? value[dimIndex] : value; + } + } + }); + return lineData; + }; + + LinesSeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + var data = this.getData(); + var itemModel = data.getItemModel(dataIndex); + var name = itemModel.get('name'); + + if (name) { + return name; + } + + var fromName = itemModel.get('fromName'); + var toName = itemModel.get('toName'); + var nameArr = []; + fromName != null && nameArr.push(fromName); + toName != null && nameArr.push(toName); + return createTooltipMarkup('nameValue', { + name: nameArr.join(' > ') + }); + }; + + LinesSeriesModel.prototype.preventIncremental = function () { + return !!this.get(['effect', 'show']); + }; + + LinesSeriesModel.prototype.getProgressive = function () { + var progressive = this.option.progressive; + + if (progressive == null) { + return this.option.large ? 1e4 : this.get('progressive'); + } + + return progressive; + }; + + LinesSeriesModel.prototype.getProgressiveThreshold = function () { + var progressiveThreshold = this.option.progressiveThreshold; + + if (progressiveThreshold == null) { + return this.option.large ? 2e4 : this.get('progressiveThreshold'); + } + + return progressiveThreshold; + }; + + LinesSeriesModel.prototype.getZLevelKey = function () { + var effectModel = this.getModel('effect'); + var trailLength = effectModel.get('trailLength'); + return this.getData().count() > this.getProgressiveThreshold() // Each progressive series has individual key. + ? this.id : effectModel.get('show') && trailLength > 0 ? trailLength + '' : ''; + }; + + LinesSeriesModel.type = 'series.lines'; + LinesSeriesModel.dependencies = ['grid', 'polar', 'geo', 'calendar']; + LinesSeriesModel.defaultOption = { + coordinateSystem: 'geo', + // zlevel: 0, + z: 2, + legendHoverLink: true, + // Cartesian coordinate system + xAxisIndex: 0, + yAxisIndex: 0, + symbol: ['none', 'none'], + symbolSize: [10, 10], + // Geo coordinate system + geoIndex: 0, + effect: { + show: false, + period: 4, + constantSpeed: 0, + symbol: 'circle', + symbolSize: 3, + loop: true, + trailLength: 0.2 + }, + large: false, + // Available when large is true + largeThreshold: 2000, + polyline: false, + clip: true, + label: { + show: false, + position: 'end' // distance: 5, + // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调 + + }, + lineStyle: { + opacity: 0.5 + } + }; + return LinesSeriesModel; + }(SeriesModel); + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + function normalize$3(a) { + if (!(a instanceof Array)) { + a = [a, a]; + } + + return a; + } + + var linesVisual = { + seriesType: 'lines', + reset: function (seriesModel) { + var symbolType = normalize$3(seriesModel.get('symbol')); + var symbolSize = normalize$3(seriesModel.get('symbolSize')); + var data = seriesModel.getData(); + data.setVisual('fromSymbol', symbolType && symbolType[0]); + data.setVisual('toSymbol', symbolType && symbolType[1]); + data.setVisual('fromSymbolSize', symbolSize && symbolSize[0]); + data.setVisual('toSymbolSize', symbolSize && symbolSize[1]); + + function dataEach(data, idx) { + var itemModel = data.getItemModel(idx); + var symbolType = normalize$3(itemModel.getShallow('symbol', true)); + var symbolSize = normalize$3(itemModel.getShallow('symbolSize', true)); + symbolType[0] && data.setItemVisual(idx, 'fromSymbol', symbolType[0]); + symbolType[1] && data.setItemVisual(idx, 'toSymbol', symbolType[1]); + symbolSize[0] && data.setItemVisual(idx, 'fromSymbolSize', symbolSize[0]); + symbolSize[1] && data.setItemVisual(idx, 'toSymbolSize', symbolSize[1]); + } + + return { + dataEach: data.hasItemOption ? dataEach : null + }; + } + }; + + function install$m(registers) { + registers.registerChartView(LinesView); + registers.registerSeriesModel(LinesSeriesModel); + registers.registerLayout(linesLayout); + registers.registerVisual(linesVisual); + } + + var GRADIENT_LEVELS = 256; + + var HeatmapLayer = + /** @class */ + function () { + function HeatmapLayer() { + this.blurSize = 30; + this.pointSize = 20; + this.maxOpacity = 1; + this.minOpacity = 0; + this._gradientPixels = { + inRange: null, + outOfRange: null + }; + var canvas = platformApi.createCanvas(); + this.canvas = canvas; + } + /** + * Renders Heatmap and returns the rendered canvas + * @param data array of data, each has x, y, value + * @param width canvas width + * @param height canvas height + */ + + + HeatmapLayer.prototype.update = function (data, width, height, normalize, colorFunc, isInRange) { + var brush = this._getBrush(); + + var gradientInRange = this._getGradient(colorFunc, 'inRange'); + + var gradientOutOfRange = this._getGradient(colorFunc, 'outOfRange'); + + var r = this.pointSize + this.blurSize; + var canvas = this.canvas; + var ctx = canvas.getContext('2d'); + var len = data.length; + canvas.width = width; + canvas.height = height; + + for (var i = 0; i < len; ++i) { + var p = data[i]; + var x = p[0]; + var y = p[1]; + var value = p[2]; // calculate alpha using value + + var alpha = normalize(value); // draw with the circle brush with alpha + + ctx.globalAlpha = alpha; + ctx.drawImage(brush, x - r, y - r); + } + + if (!canvas.width || !canvas.height) { + // Avoid "Uncaught DOMException: Failed to execute 'getImageData' on + // 'CanvasRenderingContext2D': The source height is 0." + return canvas; + } // colorize the canvas using alpha value and set with gradient + + + var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + var pixels = imageData.data; + var offset = 0; + var pixelLen = pixels.length; + var minOpacity = this.minOpacity; + var maxOpacity = this.maxOpacity; + var diffOpacity = maxOpacity - minOpacity; + + while (offset < pixelLen) { + var alpha = pixels[offset + 3] / 256; + var gradientOffset = Math.floor(alpha * (GRADIENT_LEVELS - 1)) * 4; // Simple optimize to ignore the empty data + + if (alpha > 0) { + var gradient = isInRange(alpha) ? gradientInRange : gradientOutOfRange; // Any alpha > 0 will be mapped to [minOpacity, maxOpacity] + + alpha > 0 && (alpha = alpha * diffOpacity + minOpacity); + pixels[offset++] = gradient[gradientOffset]; + pixels[offset++] = gradient[gradientOffset + 1]; + pixels[offset++] = gradient[gradientOffset + 2]; + pixels[offset++] = gradient[gradientOffset + 3] * alpha * 256; + } else { + offset += 4; + } + } + + ctx.putImageData(imageData, 0, 0); + return canvas; + }; + /** + * get canvas of a black circle brush used for canvas to draw later + */ + + + HeatmapLayer.prototype._getBrush = function () { + var brushCanvas = this._brushCanvas || (this._brushCanvas = platformApi.createCanvas()); // set brush size + + var r = this.pointSize + this.blurSize; + var d = r * 2; + brushCanvas.width = d; + brushCanvas.height = d; + var ctx = brushCanvas.getContext('2d'); + ctx.clearRect(0, 0, d, d); // in order to render shadow without the distinct circle, + // draw the distinct circle in an invisible place, + // and use shadowOffset to draw shadow in the center of the canvas + + ctx.shadowOffsetX = d; + ctx.shadowBlur = this.blurSize; // draw the shadow in black, and use alpha and shadow blur to generate + // color in color map + + ctx.shadowColor = '#000'; // draw circle in the left to the canvas + + ctx.beginPath(); + ctx.arc(-r, r, this.pointSize, 0, Math.PI * 2, true); + ctx.closePath(); + ctx.fill(); + return brushCanvas; + }; + /** + * get gradient color map + * @private + */ + + + HeatmapLayer.prototype._getGradient = function (colorFunc, state) { + var gradientPixels = this._gradientPixels; + var pixelsSingleState = gradientPixels[state] || (gradientPixels[state] = new Uint8ClampedArray(256 * 4)); + var color = [0, 0, 0, 0]; + var off = 0; + + for (var i = 0; i < 256; i++) { + colorFunc[state](i / 255, true, color); + pixelsSingleState[off++] = color[0]; + pixelsSingleState[off++] = color[1]; + pixelsSingleState[off++] = color[2]; + pixelsSingleState[off++] = color[3]; + } + + return pixelsSingleState; + }; + + return HeatmapLayer; + }(); + + function getIsInPiecewiseRange(dataExtent, pieceList, selected) { + var dataSpan = dataExtent[1] - dataExtent[0]; + pieceList = map(pieceList, function (piece) { + return { + interval: [(piece.interval[0] - dataExtent[0]) / dataSpan, (piece.interval[1] - dataExtent[0]) / dataSpan] + }; + }); + var len = pieceList.length; + var lastIndex = 0; + return function (val) { + var i; // Try to find in the location of the last found + + for (i = lastIndex; i < len; i++) { + var interval = pieceList[i].interval; + + if (interval[0] <= val && val <= interval[1]) { + lastIndex = i; + break; + } + } + + if (i === len) { + // Not found, back interation + for (i = lastIndex - 1; i >= 0; i--) { + var interval = pieceList[i].interval; + + if (interval[0] <= val && val <= interval[1]) { + lastIndex = i; + break; + } + } + } + + return i >= 0 && i < len && selected[i]; + }; + } + + function getIsInContinuousRange(dataExtent, range) { + var dataSpan = dataExtent[1] - dataExtent[0]; + range = [(range[0] - dataExtent[0]) / dataSpan, (range[1] - dataExtent[0]) / dataSpan]; + return function (val) { + return val >= range[0] && val <= range[1]; + }; + } + + function isGeoCoordSys(coordSys) { + var dimensions = coordSys.dimensions; // Not use coorSys.type === 'geo' because coordSys maybe extended + + return dimensions[0] === 'lng' && dimensions[1] === 'lat'; + } + + var HeatmapView = + /** @class */ + function (_super) { + __extends(HeatmapView, _super); + + function HeatmapView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = HeatmapView.type; + return _this; + } + + HeatmapView.prototype.render = function (seriesModel, ecModel, api) { + var visualMapOfThisSeries; + ecModel.eachComponent('visualMap', function (visualMap) { + visualMap.eachTargetSeries(function (targetSeries) { + if (targetSeries === seriesModel) { + visualMapOfThisSeries = visualMap; + } + }); + }); + + if ("development" !== 'production') { + if (!visualMapOfThisSeries) { + throw new Error('Heatmap must use with visualMap'); + } + } // Clear previously rendered progressive elements. + + + this._progressiveEls = null; + this.group.removeAll(); + var coordSys = seriesModel.coordinateSystem; + + if (coordSys.type === 'cartesian2d' || coordSys.type === 'calendar') { + this._renderOnCartesianAndCalendar(seriesModel, api, 0, seriesModel.getData().count()); + } else if (isGeoCoordSys(coordSys)) { + this._renderOnGeo(coordSys, seriesModel, visualMapOfThisSeries, api); + } + }; + + HeatmapView.prototype.incrementalPrepareRender = function (seriesModel, ecModel, api) { + this.group.removeAll(); + }; + + HeatmapView.prototype.incrementalRender = function (params, seriesModel, ecModel, api) { + var coordSys = seriesModel.coordinateSystem; + + if (coordSys) { + // geo does not support incremental rendering? + if (isGeoCoordSys(coordSys)) { + this.render(seriesModel, ecModel, api); + } else { + this._progressiveEls = []; + + this._renderOnCartesianAndCalendar(seriesModel, api, params.start, params.end, true); + } + } + }; + + HeatmapView.prototype.eachRendered = function (cb) { + traverseElements(this._progressiveEls || this.group, cb); + }; + + HeatmapView.prototype._renderOnCartesianAndCalendar = function (seriesModel, api, start, end, incremental) { + var coordSys = seriesModel.coordinateSystem; + var isCartesian2d = isCoordinateSystemType(coordSys, 'cartesian2d'); + var width; + var height; + var xAxisExtent; + var yAxisExtent; + + if (isCartesian2d) { + var xAxis = coordSys.getAxis('x'); + var yAxis = coordSys.getAxis('y'); + + if ("development" !== 'production') { + if (!(xAxis.type === 'category' && yAxis.type === 'category')) { + throw new Error('Heatmap on cartesian must have two category axes'); + } + + if (!(xAxis.onBand && yAxis.onBand)) { + throw new Error('Heatmap on cartesian must have two axes with boundaryGap true'); + } + } // add 0.5px to avoid the gaps + + + width = xAxis.getBandWidth() + .5; + height = yAxis.getBandWidth() + .5; + xAxisExtent = xAxis.scale.getExtent(); + yAxisExtent = yAxis.scale.getExtent(); + } + + var group = this.group; + var data = seriesModel.getData(); + var emphasisStyle = seriesModel.getModel(['emphasis', 'itemStyle']).getItemStyle(); + var blurStyle = seriesModel.getModel(['blur', 'itemStyle']).getItemStyle(); + var selectStyle = seriesModel.getModel(['select', 'itemStyle']).getItemStyle(); + var borderRadius = seriesModel.get(['itemStyle', 'borderRadius']); + var labelStatesModels = getLabelStatesModels(seriesModel); + var emphasisModel = seriesModel.getModel('emphasis'); + var focus = emphasisModel.get('focus'); + var blurScope = emphasisModel.get('blurScope'); + var emphasisDisabled = emphasisModel.get('disabled'); + var dataDims = isCartesian2d ? [data.mapDimension('x'), data.mapDimension('y'), data.mapDimension('value')] : [data.mapDimension('time'), data.mapDimension('value')]; + + for (var idx = start; idx < end; idx++) { + var rect = void 0; + var style = data.getItemVisual(idx, 'style'); + + if (isCartesian2d) { + var dataDimX = data.get(dataDims[0], idx); + var dataDimY = data.get(dataDims[1], idx); // Ignore empty data and out of extent data + + if (isNaN(data.get(dataDims[2], idx)) || dataDimX < xAxisExtent[0] || dataDimX > xAxisExtent[1] || dataDimY < yAxisExtent[0] || dataDimY > yAxisExtent[1]) { + continue; + } + + var point = coordSys.dataToPoint([dataDimX, dataDimY]); + rect = new Rect({ + shape: { + x: point[0] - width / 2, + y: point[1] - height / 2, + width: width, + height: height + }, + style: style + }); + } else { + // Ignore empty data + if (isNaN(data.get(dataDims[1], idx))) { + continue; + } + + rect = new Rect({ + z2: 1, + shape: coordSys.dataToRect([data.get(dataDims[0], idx)]).contentShape, + style: style + }); + } // Optimization for large datset + + + if (data.hasItemOption) { + var itemModel = data.getItemModel(idx); + var emphasisModel_1 = itemModel.getModel('emphasis'); + emphasisStyle = emphasisModel_1.getModel('itemStyle').getItemStyle(); + blurStyle = itemModel.getModel(['blur', 'itemStyle']).getItemStyle(); + selectStyle = itemModel.getModel(['select', 'itemStyle']).getItemStyle(); // Each item value struct in the data would be firstly + // { + // itemStyle: { borderRadius: [30, 30] }, + // value: [2022, 02, 22] + // } + + borderRadius = itemModel.get(['itemStyle', 'borderRadius']); + focus = emphasisModel_1.get('focus'); + blurScope = emphasisModel_1.get('blurScope'); + emphasisDisabled = emphasisModel_1.get('disabled'); + labelStatesModels = getLabelStatesModels(itemModel); + } + + rect.shape.r = borderRadius; + var rawValue = seriesModel.getRawValue(idx); + var defaultText = '-'; + + if (rawValue && rawValue[2] != null) { + defaultText = rawValue[2] + ''; + } + + setLabelStyle(rect, labelStatesModels, { + labelFetcher: seriesModel, + labelDataIndex: idx, + defaultOpacity: style.opacity, + defaultText: defaultText + }); + rect.ensureState('emphasis').style = emphasisStyle; + rect.ensureState('blur').style = blurStyle; + rect.ensureState('select').style = selectStyle; + toggleHoverEmphasis(rect, focus, blurScope, emphasisDisabled); + rect.incremental = incremental; // PENDING + + if (incremental) { + // Rect must use hover layer if it's incremental. + rect.states.emphasis.hoverLayer = true; + } + + group.add(rect); + data.setItemGraphicEl(idx, rect); + + if (this._progressiveEls) { + this._progressiveEls.push(rect); + } + } + }; + + HeatmapView.prototype._renderOnGeo = function (geo, seriesModel, visualMapModel, api) { + var inRangeVisuals = visualMapModel.targetVisuals.inRange; + var outOfRangeVisuals = visualMapModel.targetVisuals.outOfRange; // if (!visualMapping) { + // throw new Error('Data range must have color visuals'); + // } + + var data = seriesModel.getData(); + var hmLayer = this._hmLayer || this._hmLayer || new HeatmapLayer(); + hmLayer.blurSize = seriesModel.get('blurSize'); + hmLayer.pointSize = seriesModel.get('pointSize'); + hmLayer.minOpacity = seriesModel.get('minOpacity'); + hmLayer.maxOpacity = seriesModel.get('maxOpacity'); + var rect = geo.getViewRect().clone(); + var roamTransform = geo.getRoamTransform(); + rect.applyTransform(roamTransform); // Clamp on viewport + + var x = Math.max(rect.x, 0); + var y = Math.max(rect.y, 0); + var x2 = Math.min(rect.width + rect.x, api.getWidth()); + var y2 = Math.min(rect.height + rect.y, api.getHeight()); + var width = x2 - x; + var height = y2 - y; + var dims = [data.mapDimension('lng'), data.mapDimension('lat'), data.mapDimension('value')]; + var points = data.mapArray(dims, function (lng, lat, value) { + var pt = geo.dataToPoint([lng, lat]); + pt[0] -= x; + pt[1] -= y; + pt.push(value); + return pt; + }); + var dataExtent = visualMapModel.getExtent(); + var isInRange = visualMapModel.type === 'visualMap.continuous' ? getIsInContinuousRange(dataExtent, visualMapModel.option.range) : getIsInPiecewiseRange(dataExtent, visualMapModel.getPieceList(), visualMapModel.option.selected); + hmLayer.update(points, width, height, inRangeVisuals.color.getNormalizer(), { + inRange: inRangeVisuals.color.getColorMapper(), + outOfRange: outOfRangeVisuals.color.getColorMapper() + }, isInRange); + var img = new ZRImage({ + style: { + width: width, + height: height, + x: x, + y: y, + image: hmLayer.canvas + }, + silent: true + }); + this.group.add(img); + }; + + HeatmapView.type = 'heatmap'; + return HeatmapView; + }(ChartView); + + var HeatmapSeriesModel = + /** @class */ + function (_super) { + __extends(HeatmapSeriesModel, _super); + + function HeatmapSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = HeatmapSeriesModel.type; + return _this; + } + + HeatmapSeriesModel.prototype.getInitialData = function (option, ecModel) { + return createSeriesData(null, this, { + generateCoord: 'value' + }); + }; + + HeatmapSeriesModel.prototype.preventIncremental = function () { + var coordSysCreator = CoordinateSystemManager.get(this.get('coordinateSystem')); + + if (coordSysCreator && coordSysCreator.dimensions) { + return coordSysCreator.dimensions[0] === 'lng' && coordSysCreator.dimensions[1] === 'lat'; + } + }; + + HeatmapSeriesModel.type = 'series.heatmap'; + HeatmapSeriesModel.dependencies = ['grid', 'geo', 'calendar']; + HeatmapSeriesModel.defaultOption = { + coordinateSystem: 'cartesian2d', + // zlevel: 0, + z: 2, + // Cartesian coordinate system + // xAxisIndex: 0, + // yAxisIndex: 0, + // Geo coordinate system + geoIndex: 0, + blurSize: 30, + pointSize: 20, + maxOpacity: 1, + minOpacity: 0, + select: { + itemStyle: { + borderColor: '#212121' + } + } + }; + return HeatmapSeriesModel; + }(SeriesModel); + + function install$n(registers) { + registers.registerChartView(HeatmapView); + registers.registerSeriesModel(HeatmapSeriesModel); + } + + var BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'borderWidth']; // index: +isHorizontal + + var LAYOUT_ATTRS = [{ + xy: 'x', + wh: 'width', + index: 0, + posDesc: ['left', 'right'] + }, { + xy: 'y', + wh: 'height', + index: 1, + posDesc: ['top', 'bottom'] + }]; + var pathForLineWidth = new Circle(); + + var PictorialBarView = + /** @class */ + function (_super) { + __extends(PictorialBarView, _super); + + function PictorialBarView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = PictorialBarView.type; + return _this; + } + + PictorialBarView.prototype.render = function (seriesModel, ecModel, api) { + var group = this.group; + var data = seriesModel.getData(); + var oldData = this._data; + var cartesian = seriesModel.coordinateSystem; + var baseAxis = cartesian.getBaseAxis(); + var isHorizontal = baseAxis.isHorizontal(); + var coordSysRect = cartesian.master.getRect(); + var opt = { + ecSize: { + width: api.getWidth(), + height: api.getHeight() + }, + seriesModel: seriesModel, + coordSys: cartesian, + coordSysExtent: [[coordSysRect.x, coordSysRect.x + coordSysRect.width], [coordSysRect.y, coordSysRect.y + coordSysRect.height]], + isHorizontal: isHorizontal, + valueDim: LAYOUT_ATTRS[+isHorizontal], + categoryDim: LAYOUT_ATTRS[1 - +isHorizontal] + }; + data.diff(oldData).add(function (dataIndex) { + if (!data.hasValue(dataIndex)) { + return; + } + + var itemModel = getItemModel(data, dataIndex); + var symbolMeta = getSymbolMeta(data, dataIndex, itemModel, opt); + var bar = createBar(data, opt, symbolMeta); + data.setItemGraphicEl(dataIndex, bar); + group.add(bar); + updateCommon$1(bar, opt, symbolMeta); + }).update(function (newIndex, oldIndex) { + var bar = oldData.getItemGraphicEl(oldIndex); + + if (!data.hasValue(newIndex)) { + group.remove(bar); + return; + } + + var itemModel = getItemModel(data, newIndex); + var symbolMeta = getSymbolMeta(data, newIndex, itemModel, opt); + var pictorialShapeStr = getShapeStr(data, symbolMeta); + + if (bar && pictorialShapeStr !== bar.__pictorialShapeStr) { + group.remove(bar); + data.setItemGraphicEl(newIndex, null); + bar = null; + } + + if (bar) { + updateBar(bar, opt, symbolMeta); + } else { + bar = createBar(data, opt, symbolMeta, true); + } + + data.setItemGraphicEl(newIndex, bar); + bar.__pictorialSymbolMeta = symbolMeta; // Add back + + group.add(bar); + updateCommon$1(bar, opt, symbolMeta); + }).remove(function (dataIndex) { + var bar = oldData.getItemGraphicEl(dataIndex); + bar && removeBar(oldData, dataIndex, bar.__pictorialSymbolMeta.animationModel, bar); + }).execute(); + this._data = data; + return this.group; + }; + + PictorialBarView.prototype.remove = function (ecModel, api) { + var group = this.group; + var data = this._data; + + if (ecModel.get('animation')) { + if (data) { + data.eachItemGraphicEl(function (bar) { + removeBar(data, getECData(bar).dataIndex, ecModel, bar); + }); + } + } else { + group.removeAll(); + } + }; + + PictorialBarView.type = 'pictorialBar'; + return PictorialBarView; + }(ChartView); // Set or calculate default value about symbol, and calculate layout info. + + + function getSymbolMeta(data, dataIndex, itemModel, opt) { + var layout = data.getItemLayout(dataIndex); + var symbolRepeat = itemModel.get('symbolRepeat'); + var symbolClip = itemModel.get('symbolClip'); + var symbolPosition = itemModel.get('symbolPosition') || 'start'; + var symbolRotate = itemModel.get('symbolRotate'); + var rotation = (symbolRotate || 0) * Math.PI / 180 || 0; + var symbolPatternSize = itemModel.get('symbolPatternSize') || 2; + var isAnimationEnabled = itemModel.isAnimationEnabled(); + var symbolMeta = { + dataIndex: dataIndex, + layout: layout, + itemModel: itemModel, + symbolType: data.getItemVisual(dataIndex, 'symbol') || 'circle', + style: data.getItemVisual(dataIndex, 'style'), + symbolClip: symbolClip, + symbolRepeat: symbolRepeat, + symbolRepeatDirection: itemModel.get('symbolRepeatDirection'), + symbolPatternSize: symbolPatternSize, + rotation: rotation, + animationModel: isAnimationEnabled ? itemModel : null, + hoverScale: isAnimationEnabled && itemModel.get(['emphasis', 'scale']), + z2: itemModel.getShallow('z', true) || 0 + }; + prepareBarLength(itemModel, symbolRepeat, layout, opt, symbolMeta); + prepareSymbolSize(data, dataIndex, layout, symbolRepeat, symbolClip, symbolMeta.boundingLength, symbolMeta.pxSign, symbolPatternSize, opt, symbolMeta); + prepareLineWidth(itemModel, symbolMeta.symbolScale, rotation, opt, symbolMeta); + var symbolSize = symbolMeta.symbolSize; + var symbolOffset = normalizeSymbolOffset(itemModel.get('symbolOffset'), symbolSize); + prepareLayoutInfo(itemModel, symbolSize, layout, symbolRepeat, symbolClip, symbolOffset, symbolPosition, symbolMeta.valueLineWidth, symbolMeta.boundingLength, symbolMeta.repeatCutLength, opt, symbolMeta); + return symbolMeta; + } // bar length can be negative. + + + function prepareBarLength(itemModel, symbolRepeat, layout, opt, outputSymbolMeta) { + var valueDim = opt.valueDim; + var symbolBoundingData = itemModel.get('symbolBoundingData'); + var valueAxis = opt.coordSys.getOtherAxis(opt.coordSys.getBaseAxis()); + var zeroPx = valueAxis.toGlobalCoord(valueAxis.dataToCoord(0)); + var pxSignIdx = 1 - +(layout[valueDim.wh] <= 0); + var boundingLength; + + if (isArray(symbolBoundingData)) { + var symbolBoundingExtent = [convertToCoordOnAxis(valueAxis, symbolBoundingData[0]) - zeroPx, convertToCoordOnAxis(valueAxis, symbolBoundingData[1]) - zeroPx]; + symbolBoundingExtent[1] < symbolBoundingExtent[0] && symbolBoundingExtent.reverse(); + boundingLength = symbolBoundingExtent[pxSignIdx]; + } else if (symbolBoundingData != null) { + boundingLength = convertToCoordOnAxis(valueAxis, symbolBoundingData) - zeroPx; + } else if (symbolRepeat) { + boundingLength = opt.coordSysExtent[valueDim.index][pxSignIdx] - zeroPx; + } else { + boundingLength = layout[valueDim.wh]; + } + + outputSymbolMeta.boundingLength = boundingLength; + + if (symbolRepeat) { + outputSymbolMeta.repeatCutLength = layout[valueDim.wh]; + } // if 'pxSign' means sign of pixel, it can't be zero, or symbolScale will be zero + // and when borderWidth be settled, the actual linewidth will be NaN + + + outputSymbolMeta.pxSign = boundingLength > 0 ? 1 : -1; + } + + function convertToCoordOnAxis(axis, value) { + return axis.toGlobalCoord(axis.dataToCoord(axis.scale.parse(value))); + } // Support ['100%', '100%'] + + + function prepareSymbolSize(data, dataIndex, layout, symbolRepeat, symbolClip, boundingLength, pxSign, symbolPatternSize, opt, outputSymbolMeta) { + var valueDim = opt.valueDim; + var categoryDim = opt.categoryDim; + var categorySize = Math.abs(layout[categoryDim.wh]); + var symbolSize = data.getItemVisual(dataIndex, 'symbolSize'); + var parsedSymbolSize; + + if (isArray(symbolSize)) { + parsedSymbolSize = symbolSize.slice(); + } else { + if (symbolSize == null) { + // will parse to number below + parsedSymbolSize = ['100%', '100%']; + } else { + parsedSymbolSize = [symbolSize, symbolSize]; + } + } // Note: percentage symbolSize (like '100%') do not consider lineWidth, because it is + // to complicated to calculate real percent value if considering scaled lineWidth. + // So the actual size will bigger than layout size if lineWidth is bigger than zero, + // which can be tolerated in pictorial chart. + + + parsedSymbolSize[categoryDim.index] = parsePercent$1(parsedSymbolSize[categoryDim.index], categorySize); + parsedSymbolSize[valueDim.index] = parsePercent$1(parsedSymbolSize[valueDim.index], symbolRepeat ? categorySize : Math.abs(boundingLength)); + outputSymbolMeta.symbolSize = parsedSymbolSize; // If x or y is less than zero, show reversed shape. + + var symbolScale = outputSymbolMeta.symbolScale = [parsedSymbolSize[0] / symbolPatternSize, parsedSymbolSize[1] / symbolPatternSize]; // Follow convention, 'right' and 'top' is the normal scale. + + symbolScale[valueDim.index] *= (opt.isHorizontal ? -1 : 1) * pxSign; + } + + function prepareLineWidth(itemModel, symbolScale, rotation, opt, outputSymbolMeta) { + // In symbols are drawn with scale, so do not need to care about the case that width + // or height are too small. But symbol use strokeNoScale, where acture lineWidth should + // be calculated. + var valueLineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY) || 0; + + if (valueLineWidth) { + pathForLineWidth.attr({ + scaleX: symbolScale[0], + scaleY: symbolScale[1], + rotation: rotation + }); + pathForLineWidth.updateTransform(); + valueLineWidth /= pathForLineWidth.getLineScale(); + valueLineWidth *= symbolScale[opt.valueDim.index]; + } + + outputSymbolMeta.valueLineWidth = valueLineWidth || 0; + } + + function prepareLayoutInfo(itemModel, symbolSize, layout, symbolRepeat, symbolClip, symbolOffset, symbolPosition, valueLineWidth, boundingLength, repeatCutLength, opt, outputSymbolMeta) { + var categoryDim = opt.categoryDim; + var valueDim = opt.valueDim; + var pxSign = outputSymbolMeta.pxSign; + var unitLength = Math.max(symbolSize[valueDim.index] + valueLineWidth, 0); + var pathLen = unitLength; // Note: rotation will not effect the layout of symbols, because user may + // want symbols to rotate on its center, which should not be translated + // when rotating. + + if (symbolRepeat) { + var absBoundingLength = Math.abs(boundingLength); + var symbolMargin = retrieve(itemModel.get('symbolMargin'), '15%') + ''; + var hasEndGap = false; + + if (symbolMargin.lastIndexOf('!') === symbolMargin.length - 1) { + hasEndGap = true; + symbolMargin = symbolMargin.slice(0, symbolMargin.length - 1); + } + + var symbolMarginNumeric = parsePercent$1(symbolMargin, symbolSize[valueDim.index]); + var uLenWithMargin = Math.max(unitLength + symbolMarginNumeric * 2, 0); // When symbol margin is less than 0, margin at both ends will be subtracted + // to ensure that all of the symbols will not be overflow the given area. + + var endFix = hasEndGap ? 0 : symbolMarginNumeric * 2; // Both final repeatTimes and final symbolMarginNumeric area calculated based on + // boundingLength. + + var repeatSpecified = isNumeric(symbolRepeat); + var repeatTimes = repeatSpecified ? symbolRepeat : toIntTimes((absBoundingLength + endFix) / uLenWithMargin); // Adjust calculate margin, to ensure each symbol is displayed + // entirely in the given layout area. + + var mDiff = absBoundingLength - repeatTimes * unitLength; + symbolMarginNumeric = mDiff / 2 / (hasEndGap ? repeatTimes : Math.max(repeatTimes - 1, 1)); + uLenWithMargin = unitLength + symbolMarginNumeric * 2; + endFix = hasEndGap ? 0 : symbolMarginNumeric * 2; // Update repeatTimes when not all symbol will be shown. + + if (!repeatSpecified && symbolRepeat !== 'fixed') { + repeatTimes = repeatCutLength ? toIntTimes((Math.abs(repeatCutLength) + endFix) / uLenWithMargin) : 0; + } + + pathLen = repeatTimes * uLenWithMargin - endFix; + outputSymbolMeta.repeatTimes = repeatTimes; + outputSymbolMeta.symbolMargin = symbolMarginNumeric; + } + + var sizeFix = pxSign * (pathLen / 2); + var pathPosition = outputSymbolMeta.pathPosition = []; + pathPosition[categoryDim.index] = layout[categoryDim.wh] / 2; + pathPosition[valueDim.index] = symbolPosition === 'start' ? sizeFix : symbolPosition === 'end' ? boundingLength - sizeFix : boundingLength / 2; // 'center' + + if (symbolOffset) { + pathPosition[0] += symbolOffset[0]; + pathPosition[1] += symbolOffset[1]; + } + + var bundlePosition = outputSymbolMeta.bundlePosition = []; + bundlePosition[categoryDim.index] = layout[categoryDim.xy]; + bundlePosition[valueDim.index] = layout[valueDim.xy]; + var barRectShape = outputSymbolMeta.barRectShape = extend({}, layout); + barRectShape[valueDim.wh] = pxSign * Math.max(Math.abs(layout[valueDim.wh]), Math.abs(pathPosition[valueDim.index] + sizeFix)); + barRectShape[categoryDim.wh] = layout[categoryDim.wh]; + var clipShape = outputSymbolMeta.clipShape = {}; // Consider that symbol may be overflow layout rect. + + clipShape[categoryDim.xy] = -layout[categoryDim.xy]; + clipShape[categoryDim.wh] = opt.ecSize[categoryDim.wh]; + clipShape[valueDim.xy] = 0; + clipShape[valueDim.wh] = layout[valueDim.wh]; + } + + function createPath(symbolMeta) { + var symbolPatternSize = symbolMeta.symbolPatternSize; + var path = createSymbol( // Consider texture img, make a big size. + symbolMeta.symbolType, -symbolPatternSize / 2, -symbolPatternSize / 2, symbolPatternSize, symbolPatternSize); + path.attr({ + culling: true + }); + path.type !== 'image' && path.setStyle({ + strokeNoScale: true + }); + return path; + } + + function createOrUpdateRepeatSymbols(bar, opt, symbolMeta, isUpdate) { + var bundle = bar.__pictorialBundle; + var symbolSize = symbolMeta.symbolSize; + var valueLineWidth = symbolMeta.valueLineWidth; + var pathPosition = symbolMeta.pathPosition; + var valueDim = opt.valueDim; + var repeatTimes = symbolMeta.repeatTimes || 0; + var index = 0; + var unit = symbolSize[opt.valueDim.index] + valueLineWidth + symbolMeta.symbolMargin * 2; + eachPath(bar, function (path) { + path.__pictorialAnimationIndex = index; + path.__pictorialRepeatTimes = repeatTimes; + + if (index < repeatTimes) { + updateAttr(path, null, makeTarget(index), symbolMeta, isUpdate); + } else { + updateAttr(path, null, { + scaleX: 0, + scaleY: 0 + }, symbolMeta, isUpdate, function () { + bundle.remove(path); + }); + } // updateHoverAnimation(path, symbolMeta); + + + index++; + }); + + for (; index < repeatTimes; index++) { + var path = createPath(symbolMeta); + path.__pictorialAnimationIndex = index; + path.__pictorialRepeatTimes = repeatTimes; + bundle.add(path); + var target = makeTarget(index); + updateAttr(path, { + x: target.x, + y: target.y, + scaleX: 0, + scaleY: 0 + }, { + scaleX: target.scaleX, + scaleY: target.scaleY, + rotation: target.rotation + }, symbolMeta, isUpdate); + } + + function makeTarget(index) { + var position = pathPosition.slice(); // (start && pxSign > 0) || (end && pxSign < 0): i = repeatTimes - index + // Otherwise: i = index; + + var pxSign = symbolMeta.pxSign; + var i = index; + + if (symbolMeta.symbolRepeatDirection === 'start' ? pxSign > 0 : pxSign < 0) { + i = repeatTimes - 1 - index; + } + + position[valueDim.index] = unit * (i - repeatTimes / 2 + 0.5) + pathPosition[valueDim.index]; + return { + x: position[0], + y: position[1], + scaleX: symbolMeta.symbolScale[0], + scaleY: symbolMeta.symbolScale[1], + rotation: symbolMeta.rotation + }; + } + } + + function createOrUpdateSingleSymbol(bar, opt, symbolMeta, isUpdate) { + var bundle = bar.__pictorialBundle; + var mainPath = bar.__pictorialMainPath; + + if (!mainPath) { + mainPath = bar.__pictorialMainPath = createPath(symbolMeta); + bundle.add(mainPath); + updateAttr(mainPath, { + x: symbolMeta.pathPosition[0], + y: symbolMeta.pathPosition[1], + scaleX: 0, + scaleY: 0, + rotation: symbolMeta.rotation + }, { + scaleX: symbolMeta.symbolScale[0], + scaleY: symbolMeta.symbolScale[1] + }, symbolMeta, isUpdate); + } else { + updateAttr(mainPath, null, { + x: symbolMeta.pathPosition[0], + y: symbolMeta.pathPosition[1], + scaleX: symbolMeta.symbolScale[0], + scaleY: symbolMeta.symbolScale[1], + rotation: symbolMeta.rotation + }, symbolMeta, isUpdate); + } + } // bar rect is used for label. + + + function createOrUpdateBarRect(bar, symbolMeta, isUpdate) { + var rectShape = extend({}, symbolMeta.barRectShape); + var barRect = bar.__pictorialBarRect; + + if (!barRect) { + barRect = bar.__pictorialBarRect = new Rect({ + z2: 2, + shape: rectShape, + silent: true, + style: { + stroke: 'transparent', + fill: 'transparent', + lineWidth: 0 + } + }); + barRect.disableMorphing = true; + bar.add(barRect); + } else { + updateAttr(barRect, null, { + shape: rectShape + }, symbolMeta, isUpdate); + } + } + + function createOrUpdateClip(bar, opt, symbolMeta, isUpdate) { + // If not clip, symbol will be remove and rebuilt. + if (symbolMeta.symbolClip) { + var clipPath = bar.__pictorialClipPath; + var clipShape = extend({}, symbolMeta.clipShape); + var valueDim = opt.valueDim; + var animationModel = symbolMeta.animationModel; + var dataIndex = symbolMeta.dataIndex; + + if (clipPath) { + updateProps(clipPath, { + shape: clipShape + }, animationModel, dataIndex); + } else { + clipShape[valueDim.wh] = 0; + clipPath = new Rect({ + shape: clipShape + }); + + bar.__pictorialBundle.setClipPath(clipPath); + + bar.__pictorialClipPath = clipPath; + var target = {}; + target[valueDim.wh] = symbolMeta.clipShape[valueDim.wh]; + graphic[isUpdate ? 'updateProps' : 'initProps'](clipPath, { + shape: target + }, animationModel, dataIndex); + } + } + } + + function getItemModel(data, dataIndex) { + var itemModel = data.getItemModel(dataIndex); + itemModel.getAnimationDelayParams = getAnimationDelayParams; + itemModel.isAnimationEnabled = isAnimationEnabled; + return itemModel; + } + + function getAnimationDelayParams(path) { + // The order is the same as the z-order, see `symbolRepeatDiretion`. + return { + index: path.__pictorialAnimationIndex, + count: path.__pictorialRepeatTimes + }; + } + + function isAnimationEnabled() { + // `animation` prop can be set on itemModel in pictorial bar chart. + return this.parentModel.isAnimationEnabled() && !!this.getShallow('animation'); + } + + function createBar(data, opt, symbolMeta, isUpdate) { + // bar is the main element for each data. + var bar = new Group(); // bundle is used for location and clip. + + var bundle = new Group(); + bar.add(bundle); + bar.__pictorialBundle = bundle; + bundle.x = symbolMeta.bundlePosition[0]; + bundle.y = symbolMeta.bundlePosition[1]; + + if (symbolMeta.symbolRepeat) { + createOrUpdateRepeatSymbols(bar, opt, symbolMeta); + } else { + createOrUpdateSingleSymbol(bar, opt, symbolMeta); + } + + createOrUpdateBarRect(bar, symbolMeta, isUpdate); + createOrUpdateClip(bar, opt, symbolMeta, isUpdate); + bar.__pictorialShapeStr = getShapeStr(data, symbolMeta); + bar.__pictorialSymbolMeta = symbolMeta; + return bar; + } + + function updateBar(bar, opt, symbolMeta) { + var animationModel = symbolMeta.animationModel; + var dataIndex = symbolMeta.dataIndex; + var bundle = bar.__pictorialBundle; + updateProps(bundle, { + x: symbolMeta.bundlePosition[0], + y: symbolMeta.bundlePosition[1] + }, animationModel, dataIndex); + + if (symbolMeta.symbolRepeat) { + createOrUpdateRepeatSymbols(bar, opt, symbolMeta, true); + } else { + createOrUpdateSingleSymbol(bar, opt, symbolMeta, true); + } + + createOrUpdateBarRect(bar, symbolMeta, true); + createOrUpdateClip(bar, opt, symbolMeta, true); + } + + function removeBar(data, dataIndex, animationModel, bar) { + // Not show text when animating + var labelRect = bar.__pictorialBarRect; + labelRect && labelRect.removeTextContent(); + var pathes = []; + eachPath(bar, function (path) { + pathes.push(path); + }); + bar.__pictorialMainPath && pathes.push(bar.__pictorialMainPath); // I do not find proper remove animation for clip yet. + + bar.__pictorialClipPath && (animationModel = null); + each(pathes, function (path) { + removeElement(path, { + scaleX: 0, + scaleY: 0 + }, animationModel, dataIndex, function () { + bar.parent && bar.parent.remove(bar); + }); + }); + data.setItemGraphicEl(dataIndex, null); + } + + function getShapeStr(data, symbolMeta) { + return [data.getItemVisual(symbolMeta.dataIndex, 'symbol') || 'none', !!symbolMeta.symbolRepeat, !!symbolMeta.symbolClip].join(':'); + } + + function eachPath(bar, cb, context) { + // Do not use Group#eachChild, because it do not support remove. + each(bar.__pictorialBundle.children(), function (el) { + el !== bar.__pictorialBarRect && cb.call(context, el); + }); + } + + function updateAttr(el, immediateAttrs, animationAttrs, symbolMeta, isUpdate, cb) { + immediateAttrs && el.attr(immediateAttrs); // when symbolCip used, only clip path has init animation, otherwise it would be weird effect. + + if (symbolMeta.symbolClip && !isUpdate) { + animationAttrs && el.attr(animationAttrs); + } else { + animationAttrs && graphic[isUpdate ? 'updateProps' : 'initProps'](el, animationAttrs, symbolMeta.animationModel, symbolMeta.dataIndex, cb); + } + } + + function updateCommon$1(bar, opt, symbolMeta) { + var dataIndex = symbolMeta.dataIndex; + var itemModel = symbolMeta.itemModel; // Color must be excluded. + // Because symbol provide setColor individually to set fill and stroke + + var emphasisModel = itemModel.getModel('emphasis'); + var emphasisStyle = emphasisModel.getModel('itemStyle').getItemStyle(); + var blurStyle = itemModel.getModel(['blur', 'itemStyle']).getItemStyle(); + var selectStyle = itemModel.getModel(['select', 'itemStyle']).getItemStyle(); + var cursorStyle = itemModel.getShallow('cursor'); + var focus = emphasisModel.get('focus'); + var blurScope = emphasisModel.get('blurScope'); + var hoverScale = emphasisModel.get('scale'); + eachPath(bar, function (path) { + if (path instanceof ZRImage) { + var pathStyle = path.style; + path.useStyle(extend({ + // TODO other properties like dx, dy ? + image: pathStyle.image, + x: pathStyle.x, + y: pathStyle.y, + width: pathStyle.width, + height: pathStyle.height + }, symbolMeta.style)); + } else { + path.useStyle(symbolMeta.style); + } + + var emphasisState = path.ensureState('emphasis'); + emphasisState.style = emphasisStyle; + + if (hoverScale) { + // NOTE: Must after scale is set after updateAttr + emphasisState.scaleX = path.scaleX * 1.1; + emphasisState.scaleY = path.scaleY * 1.1; + } + + path.ensureState('blur').style = blurStyle; + path.ensureState('select').style = selectStyle; + cursorStyle && (path.cursor = cursorStyle); + path.z2 = symbolMeta.z2; + }); + var barPositionOutside = opt.valueDim.posDesc[+(symbolMeta.boundingLength > 0)]; + var barRect = bar.__pictorialBarRect; + setLabelStyle(barRect, getLabelStatesModels(itemModel), { + labelFetcher: opt.seriesModel, + labelDataIndex: dataIndex, + defaultText: getDefaultLabel(opt.seriesModel.getData(), dataIndex), + inheritColor: symbolMeta.style.fill, + defaultOpacity: symbolMeta.style.opacity, + defaultOutsidePosition: barPositionOutside + }); + toggleHoverEmphasis(bar, focus, blurScope, emphasisModel.get('disabled')); + } + + function toIntTimes(times) { + var roundedTimes = Math.round(times); // Escapse accurate error + + return Math.abs(times - roundedTimes) < 1e-4 ? roundedTimes : Math.ceil(times); + } + + var PictorialBarSeriesModel = + /** @class */ + function (_super) { + __extends(PictorialBarSeriesModel, _super); + + function PictorialBarSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = PictorialBarSeriesModel.type; + _this.hasSymbolVisual = true; + _this.defaultSymbol = 'roundRect'; + return _this; + } + + PictorialBarSeriesModel.prototype.getInitialData = function (option) { + // Disable stack. + option.stack = null; + return _super.prototype.getInitialData.apply(this, arguments); + }; + + PictorialBarSeriesModel.type = 'series.pictorialBar'; + PictorialBarSeriesModel.dependencies = ['grid']; + PictorialBarSeriesModel.defaultOption = inheritDefaultOption(BaseBarSeriesModel.defaultOption, { + symbol: 'circle', + symbolSize: null, + symbolRotate: null, + symbolPosition: null, + symbolOffset: null, + symbolMargin: null, + symbolRepeat: false, + symbolRepeatDirection: 'end', + symbolClip: false, + symbolBoundingData: null, + symbolPatternSize: 400, + barGap: '-100%', + // z can be set in data item, which is z2 actually. + // Disable progressive + progressive: 0, + emphasis: { + // By default pictorialBar do not hover scale. Hover scale is not suitable + // for the case that both has foreground and background. + scale: false + }, + select: { + itemStyle: { + borderColor: '#212121' + } + } + }); + return PictorialBarSeriesModel; + }(BaseBarSeriesModel); + + function install$o(registers) { + registers.registerChartView(PictorialBarView); + registers.registerSeriesModel(PictorialBarSeriesModel); + registers.registerLayout(registers.PRIORITY.VISUAL.LAYOUT, curry(layout, 'pictorialBar')); // Do layout after other overall layout, which can preapre some informations. + + registers.registerLayout(registers.PRIORITY.VISUAL.PROGRESSIVE_LAYOUT, createProgressiveLayout('pictorialBar')); + } + + var ThemeRiverView = + /** @class */ + function (_super) { + __extends(ThemeRiverView, _super); + + function ThemeRiverView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ThemeRiverView.type; + _this._layers = []; + return _this; + } + + ThemeRiverView.prototype.render = function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + var self = this; + var group = this.group; + var layersSeries = seriesModel.getLayerSeries(); + var layoutInfo = data.getLayout('layoutInfo'); + var rect = layoutInfo.rect; + var boundaryGap = layoutInfo.boundaryGap; + group.x = 0; + group.y = rect.y + boundaryGap[0]; + + function keyGetter(item) { + return item.name; + } + + var dataDiffer = new DataDiffer(this._layersSeries || [], layersSeries, keyGetter, keyGetter); + var newLayersGroups = []; + dataDiffer.add(bind(process, this, 'add')).update(bind(process, this, 'update')).remove(bind(process, this, 'remove')).execute(); + + function process(status, idx, oldIdx) { + var oldLayersGroups = self._layers; + + if (status === 'remove') { + group.remove(oldLayersGroups[idx]); + return; + } + + var points0 = []; + var points1 = []; + var style; + var indices = layersSeries[idx].indices; + var j = 0; + + for (; j < indices.length; j++) { + var layout = data.getItemLayout(indices[j]); + var x = layout.x; + var y0 = layout.y0; + var y = layout.y; + points0.push(x, y0); + points1.push(x, y0 + y); + style = data.getItemVisual(indices[j], 'style'); + } + + var polygon; + var textLayout = data.getItemLayout(indices[0]); + var labelModel = seriesModel.getModel('label'); + var margin = labelModel.get('margin'); + var emphasisModel = seriesModel.getModel('emphasis'); + + if (status === 'add') { + var layerGroup = newLayersGroups[idx] = new Group(); + polygon = new ECPolygon({ + shape: { + points: points0, + stackedOnPoints: points1, + smooth: 0.4, + stackedOnSmooth: 0.4, + smoothConstraint: false + }, + z2: 0 + }); + layerGroup.add(polygon); + group.add(layerGroup); + + if (seriesModel.isAnimationEnabled()) { + polygon.setClipPath(createGridClipShape$2(polygon.getBoundingRect(), seriesModel, function () { + polygon.removeClipPath(); + })); + } + } else { + var layerGroup = oldLayersGroups[oldIdx]; + polygon = layerGroup.childAt(0); + group.add(layerGroup); + newLayersGroups[idx] = layerGroup; + updateProps(polygon, { + shape: { + points: points0, + stackedOnPoints: points1 + } + }, seriesModel); + saveOldStyle(polygon); + } + + setLabelStyle(polygon, getLabelStatesModels(seriesModel), { + labelDataIndex: indices[j - 1], + defaultText: data.getName(indices[j - 1]), + inheritColor: style.fill + }, { + normal: { + verticalAlign: 'middle' // align: 'right' + + } + }); + polygon.setTextConfig({ + position: null, + local: true + }); + var labelEl = polygon.getTextContent(); // TODO More label position options. + + if (labelEl) { + labelEl.x = textLayout.x - margin; + labelEl.y = textLayout.y0 + textLayout.y / 2; + } + + polygon.useStyle(style); + data.setItemGraphicEl(idx, polygon); + setStatesStylesFromModel(polygon, seriesModel); + toggleHoverEmphasis(polygon, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled')); + } + + this._layersSeries = layersSeries; + this._layers = newLayersGroups; + }; + + ThemeRiverView.type = 'themeRiver'; + return ThemeRiverView; + }(ChartView); + + function createGridClipShape$2(rect, seriesModel, cb) { + var rectEl = new Rect({ + shape: { + x: rect.x - 10, + y: rect.y - 10, + width: 0, + height: rect.height + 20 + } + }); + initProps(rectEl, { + shape: { + x: rect.x - 50, + width: rect.width + 100, + height: rect.height + 20 + } + }, seriesModel, cb); + return rectEl; + } + + var DATA_NAME_INDEX = 2; + + var ThemeRiverSeriesModel = + /** @class */ + function (_super) { + __extends(ThemeRiverSeriesModel, _super); + + function ThemeRiverSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ThemeRiverSeriesModel.type; + return _this; + } + /** + * @override + */ + + + ThemeRiverSeriesModel.prototype.init = function (option) { + // eslint-disable-next-line + _super.prototype.init.apply(this, arguments); // Put this function here is for the sake of consistency of code style. + // Enable legend selection for each data item + // Use a function instead of direct access because data reference may changed + + + this.legendVisualProvider = new LegendVisualProvider(bind(this.getData, this), bind(this.getRawData, this)); + }; + /** + * If there is no value of a certain point in the time for some event,set it value to 0. + * + * @param {Array} data initial data in the option + * @return {Array} + */ + + + ThemeRiverSeriesModel.prototype.fixData = function (data) { + var rawDataLength = data.length; + /** + * Make sure every layer data get the same keys. + * The value index tells which layer has visited. + * { + * 2014/01/01: -1 + * } + */ + + var timeValueKeys = {}; // grouped data by name + + var groupResult = groupData(data, function (item) { + if (!timeValueKeys.hasOwnProperty(item[0] + '')) { + timeValueKeys[item[0] + ''] = -1; + } + + return item[2]; + }); + var layerData = []; + groupResult.buckets.each(function (items, key) { + layerData.push({ + name: key, + dataList: items + }); + }); + var layerNum = layerData.length; + + for (var k = 0; k < layerNum; ++k) { + var name_1 = layerData[k].name; + + for (var j = 0; j < layerData[k].dataList.length; ++j) { + var timeValue = layerData[k].dataList[j][0] + ''; + timeValueKeys[timeValue] = k; + } + + for (var timeValue in timeValueKeys) { + if (timeValueKeys.hasOwnProperty(timeValue) && timeValueKeys[timeValue] !== k) { + timeValueKeys[timeValue] = k; + data[rawDataLength] = [timeValue, 0, name_1]; + rawDataLength++; + } + } + } + + return data; + }; + /** + * @override + * @param option the initial option that user gived + * @param ecModel the model object for themeRiver option + */ + + + ThemeRiverSeriesModel.prototype.getInitialData = function (option, ecModel) { + var singleAxisModel = this.getReferringComponents('singleAxis', SINGLE_REFERRING).models[0]; + var axisType = singleAxisModel.get('type'); // filter the data item with the value of label is undefined + + var filterData = filter(option.data, function (dataItem) { + return dataItem[2] !== undefined; + }); // ??? TODO design a stage to transfer data for themeRiver and lines? + + var data = this.fixData(filterData || []); + var nameList = []; + var nameMap = this.nameMap = createHashMap(); + var count = 0; + + for (var i = 0; i < data.length; ++i) { + nameList.push(data[i][DATA_NAME_INDEX]); + + if (!nameMap.get(data[i][DATA_NAME_INDEX])) { + nameMap.set(data[i][DATA_NAME_INDEX], count); + count++; + } + } + + var dimensions = prepareSeriesDataSchema(data, { + coordDimensions: ['single'], + dimensionsDefine: [{ + name: 'time', + type: getDimensionTypeByAxis(axisType) + }, { + name: 'value', + type: 'float' + }, { + name: 'name', + type: 'ordinal' + }], + encodeDefine: { + single: 0, + value: 1, + itemName: 2 + } + }).dimensions; + var list = new SeriesData(dimensions, this); + list.initData(data); + return list; + }; + /** + * The raw data is divided into multiple layers and each layer + * has same name. + */ + + + ThemeRiverSeriesModel.prototype.getLayerSeries = function () { + var data = this.getData(); + var lenCount = data.count(); + var indexArr = []; + + for (var i = 0; i < lenCount; ++i) { + indexArr[i] = i; + } + + var timeDim = data.mapDimension('single'); // data group by name + + var groupResult = groupData(indexArr, function (index) { + return data.get('name', index); + }); + var layerSeries = []; + groupResult.buckets.each(function (items, key) { + items.sort(function (index1, index2) { + return data.get(timeDim, index1) - data.get(timeDim, index2); + }); + layerSeries.push({ + name: key, + indices: items + }); + }); + return layerSeries; + }; + /** + * Get data indices for show tooltip content + */ + + + ThemeRiverSeriesModel.prototype.getAxisTooltipData = function (dim, value, baseAxis) { + if (!isArray(dim)) { + dim = dim ? [dim] : []; + } + + var data = this.getData(); + var layerSeries = this.getLayerSeries(); + var indices = []; + var layerNum = layerSeries.length; + var nestestValue; + + for (var i = 0; i < layerNum; ++i) { + var minDist = Number.MAX_VALUE; + var nearestIdx = -1; + var pointNum = layerSeries[i].indices.length; + + for (var j = 0; j < pointNum; ++j) { + var theValue = data.get(dim[0], layerSeries[i].indices[j]); + var dist = Math.abs(theValue - value); + + if (dist <= minDist) { + nestestValue = theValue; + minDist = dist; + nearestIdx = layerSeries[i].indices[j]; + } + } + + indices.push(nearestIdx); + } + + return { + dataIndices: indices, + nestestValue: nestestValue + }; + }; + + ThemeRiverSeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + var data = this.getData(); + var name = data.getName(dataIndex); + var value = data.get(data.mapDimension('value'), dataIndex); + return createTooltipMarkup('nameValue', { + name: name, + value: value + }); + }; + + ThemeRiverSeriesModel.type = 'series.themeRiver'; + ThemeRiverSeriesModel.dependencies = ['singleAxis']; + ThemeRiverSeriesModel.defaultOption = { + // zlevel: 0, + z: 2, + colorBy: 'data', + coordinateSystem: 'singleAxis', + // gap in axis's orthogonal orientation + boundaryGap: ['10%', '10%'], + // legendHoverLink: true, + singleAxisIndex: 0, + animationEasing: 'linear', + label: { + margin: 4, + show: true, + position: 'left', + fontSize: 11 + }, + emphasis: { + label: { + show: true + } + } + }; + return ThemeRiverSeriesModel; + }(SeriesModel); + + function themeRiverLayout(ecModel, api) { + ecModel.eachSeriesByType('themeRiver', function (seriesModel) { + var data = seriesModel.getData(); + var single = seriesModel.coordinateSystem; + var layoutInfo = {}; // use the axis boundingRect for view + + var rect = single.getRect(); + layoutInfo.rect = rect; + var boundaryGap = seriesModel.get('boundaryGap'); + var axis = single.getAxis(); + layoutInfo.boundaryGap = boundaryGap; + + if (axis.orient === 'horizontal') { + boundaryGap[0] = parsePercent$1(boundaryGap[0], rect.height); + boundaryGap[1] = parsePercent$1(boundaryGap[1], rect.height); + var height = rect.height - boundaryGap[0] - boundaryGap[1]; + doThemeRiverLayout(data, seriesModel, height); + } else { + boundaryGap[0] = parsePercent$1(boundaryGap[0], rect.width); + boundaryGap[1] = parsePercent$1(boundaryGap[1], rect.width); + var width = rect.width - boundaryGap[0] - boundaryGap[1]; + doThemeRiverLayout(data, seriesModel, width); + } + + data.setLayout('layoutInfo', layoutInfo); + }); + } + /** + * The layout information about themeriver + * + * @param data data in the series + * @param seriesModel the model object of themeRiver series + * @param height value used to compute every series height + */ + + function doThemeRiverLayout(data, seriesModel, height) { + if (!data.count()) { + return; + } + + var coordSys = seriesModel.coordinateSystem; // the data in each layer are organized into a series. + + var layerSeries = seriesModel.getLayerSeries(); // the points in each layer. + + var timeDim = data.mapDimension('single'); + var valueDim = data.mapDimension('value'); + var layerPoints = map(layerSeries, function (singleLayer) { + return map(singleLayer.indices, function (idx) { + var pt = coordSys.dataToPoint(data.get(timeDim, idx)); + pt[1] = data.get(valueDim, idx); + return pt; + }); + }); + var base = computeBaseline(layerPoints); + var baseLine = base.y0; + var ky = height / base.max; // set layout information for each item. + + var n = layerSeries.length; + var m = layerSeries[0].indices.length; + var baseY0; + + for (var j = 0; j < m; ++j) { + baseY0 = baseLine[j] * ky; + data.setItemLayout(layerSeries[0].indices[j], { + layerIndex: 0, + x: layerPoints[0][j][0], + y0: baseY0, + y: layerPoints[0][j][1] * ky + }); + + for (var i = 1; i < n; ++i) { + baseY0 += layerPoints[i - 1][j][1] * ky; + data.setItemLayout(layerSeries[i].indices[j], { + layerIndex: i, + x: layerPoints[i][j][0], + y0: baseY0, + y: layerPoints[i][j][1] * ky + }); + } + } + } + /** + * Compute the baseLine of the rawdata + * Inspired by Lee Byron's paper Stacked Graphs - Geometry & Aesthetics + * + * @param data the points in each layer + */ + + + function computeBaseline(data) { + var layerNum = data.length; + var pointNum = data[0].length; + var sums = []; + var y0 = []; + var max = 0; + + for (var i = 0; i < pointNum; ++i) { + var temp = 0; + + for (var j = 0; j < layerNum; ++j) { + temp += data[j][i][1]; + } + + if (temp > max) { + max = temp; + } + + sums.push(temp); + } + + for (var k = 0; k < pointNum; ++k) { + y0[k] = (max - sums[k]) / 2; + } + + max = 0; + + for (var l = 0; l < pointNum; ++l) { + var sum = sums[l] + y0[l]; + + if (sum > max) { + max = sum; + } + } + + return { + y0: y0, + max: max + }; + } + + function install$p(registers) { + registers.registerChartView(ThemeRiverView); + registers.registerSeriesModel(ThemeRiverSeriesModel); + registers.registerLayout(themeRiverLayout); + registers.registerProcessor(dataFilter('themeRiver')); + } + + var DEFAULT_SECTOR_Z = 2; + var DEFAULT_TEXT_Z = 4; + /** + * Sunburstce of Sunburst including Sector, Label, LabelLine + */ + + var SunburstPiece = + /** @class */ + function (_super) { + __extends(SunburstPiece, _super); + + function SunburstPiece(node, seriesModel, ecModel, api) { + var _this = _super.call(this) || this; + + _this.z2 = DEFAULT_SECTOR_Z; + _this.textConfig = { + inside: true + }; + getECData(_this).seriesIndex = seriesModel.seriesIndex; + var text = new ZRText({ + z2: DEFAULT_TEXT_Z, + silent: node.getModel().get(['label', 'silent']) + }); + + _this.setTextContent(text); + + _this.updateData(true, node, seriesModel, ecModel, api); + + return _this; + } + + SunburstPiece.prototype.updateData = function (firstCreate, node, // state: 'emphasis' | 'normal' | 'highlight' | 'downplay', + seriesModel, ecModel, api) { + this.node = node; + node.piece = this; + seriesModel = seriesModel || this._seriesModel; + ecModel = ecModel || this._ecModel; + var sector = this; + getECData(sector).dataIndex = node.dataIndex; + var itemModel = node.getModel(); + var emphasisModel = itemModel.getModel('emphasis'); + var layout = node.getLayout(); + var sectorShape = extend({}, layout); + sectorShape.label = null; + var normalStyle = node.getVisual('style'); + normalStyle.lineJoin = 'bevel'; + var decal = node.getVisual('decal'); + + if (decal) { + normalStyle.decal = createOrUpdatePatternFromDecal(decal, api); + } + + var cornerRadius = getSectorCornerRadius(itemModel.getModel('itemStyle'), sectorShape, true); + extend(sectorShape, cornerRadius); + each(SPECIAL_STATES, function (stateName) { + var state = sector.ensureState(stateName); + var itemStyleModel = itemModel.getModel([stateName, 'itemStyle']); + state.style = itemStyleModel.getItemStyle(); // border radius + + var cornerRadius = getSectorCornerRadius(itemStyleModel, sectorShape); + + if (cornerRadius) { + state.shape = cornerRadius; + } + }); + + if (firstCreate) { + sector.setShape(sectorShape); + sector.shape.r = layout.r0; + updateProps(sector, { + shape: { + r: layout.r + } + }, seriesModel, node.dataIndex); + } else { + // Disable animation for gradient since no interpolation method + // is supported for gradient + updateProps(sector, { + shape: sectorShape + }, seriesModel); + saveOldStyle(sector); + } + + sector.useStyle(normalStyle); + + this._updateLabel(seriesModel); + + var cursorStyle = itemModel.getShallow('cursor'); + cursorStyle && sector.attr('cursor', cursorStyle); + this._seriesModel = seriesModel || this._seriesModel; + this._ecModel = ecModel || this._ecModel; + var focus = emphasisModel.get('focus'); + var focusOrIndices = focus === 'ancestor' ? node.getAncestorsIndices() : focus === 'descendant' ? node.getDescendantIndices() : focus; + toggleHoverEmphasis(this, focusOrIndices, emphasisModel.get('blurScope'), emphasisModel.get('disabled')); + }; + + SunburstPiece.prototype._updateLabel = function (seriesModel) { + var _this = this; + + var itemModel = this.node.getModel(); + var normalLabelModel = itemModel.getModel('label'); + var layout = this.node.getLayout(); + var angle = layout.endAngle - layout.startAngle; + var midAngle = (layout.startAngle + layout.endAngle) / 2; + var dx = Math.cos(midAngle); + var dy = Math.sin(midAngle); + var sector = this; + var label = sector.getTextContent(); + var dataIndex = this.node.dataIndex; + var labelMinAngle = normalLabelModel.get('minAngle') / 180 * Math.PI; + var isNormalShown = normalLabelModel.get('show') && !(labelMinAngle != null && Math.abs(angle) < labelMinAngle); + label.ignore = !isNormalShown; // TODO use setLabelStyle + + each(DISPLAY_STATES, function (stateName) { + var labelStateModel = stateName === 'normal' ? itemModel.getModel('label') : itemModel.getModel([stateName, 'label']); + var isNormal = stateName === 'normal'; + var state = isNormal ? label : label.ensureState(stateName); + var text = seriesModel.getFormattedLabel(dataIndex, stateName); + + if (isNormal) { + text = text || _this.node.name; + } + + state.style = createTextStyle(labelStateModel, {}, null, stateName !== 'normal', true); + + if (text) { + state.style.text = text; + } // Not displaying text when angle is too small + + + var isShown = labelStateModel.get('show'); + + if (isShown != null && !isNormal) { + state.ignore = !isShown; + } + + var labelPosition = getLabelAttr(labelStateModel, 'position'); + var sectorState = isNormal ? sector : sector.states[stateName]; + var labelColor = sectorState.style.fill; + sectorState.textConfig = { + outsideFill: labelStateModel.get('color') === 'inherit' ? labelColor : null, + inside: labelPosition !== 'outside' + }; + var r; + var labelPadding = getLabelAttr(labelStateModel, 'distance') || 0; + var textAlign = getLabelAttr(labelStateModel, 'align'); + + if (labelPosition === 'outside') { + r = layout.r + labelPadding; + textAlign = midAngle > Math.PI / 2 ? 'right' : 'left'; + } else { + if (!textAlign || textAlign === 'center') { + // Put label in the center if it's a circle + if (angle === 2 * Math.PI && layout.r0 === 0) { + r = 0; + } else { + r = (layout.r + layout.r0) / 2; + } + + textAlign = 'center'; + } else if (textAlign === 'left') { + r = layout.r0 + labelPadding; + + if (midAngle > Math.PI / 2) { + textAlign = 'right'; + } + } else if (textAlign === 'right') { + r = layout.r - labelPadding; + + if (midAngle > Math.PI / 2) { + textAlign = 'left'; + } + } + } + + state.style.align = textAlign; + state.style.verticalAlign = getLabelAttr(labelStateModel, 'verticalAlign') || 'middle'; + state.x = r * dx + layout.cx; + state.y = r * dy + layout.cy; + var rotateType = getLabelAttr(labelStateModel, 'rotate'); + var rotate = 0; + + if (rotateType === 'radial') { + rotate = -midAngle; + + if (rotate < -Math.PI / 2) { + rotate += Math.PI; + } + } else if (rotateType === 'tangential') { + rotate = Math.PI / 2 - midAngle; + + if (rotate > Math.PI / 2) { + rotate -= Math.PI; + } else if (rotate < -Math.PI / 2) { + rotate += Math.PI; + } + } else if (isNumber(rotateType)) { + rotate = rotateType * Math.PI / 180; + } + + state.rotation = rotate; + }); + + function getLabelAttr(model, name) { + var stateAttr = model.get(name); + + if (stateAttr == null) { + return normalLabelModel.get(name); + } + + return stateAttr; + } + + label.dirtyStyle(); + }; + + return SunburstPiece; + }(Sector); + + var ROOT_TO_NODE_ACTION = 'sunburstRootToNode'; + var HIGHLIGHT_ACTION = 'sunburstHighlight'; + var UNHIGHLIGHT_ACTION = 'sunburstUnhighlight'; + function installSunburstAction(registers) { + registers.registerAction({ + type: ROOT_TO_NODE_ACTION, + update: 'updateView' + }, function (payload, ecModel) { + ecModel.eachComponent({ + mainType: 'series', + subType: 'sunburst', + query: payload + }, handleRootToNode); + + function handleRootToNode(model, index) { + var targetInfo = retrieveTargetInfo(payload, [ROOT_TO_NODE_ACTION], model); + + if (targetInfo) { + var originViewRoot = model.getViewRoot(); + + if (originViewRoot) { + payload.direction = aboveViewRoot(originViewRoot, targetInfo.node) ? 'rollUp' : 'drillDown'; + } + + model.resetViewRoot(targetInfo.node); + } + } + }); + registers.registerAction({ + type: HIGHLIGHT_ACTION, + update: 'none' + }, function (payload, ecModel, api) { + // Clone + payload = extend({}, payload); + ecModel.eachComponent({ + mainType: 'series', + subType: 'sunburst', + query: payload + }, handleHighlight); + + function handleHighlight(model) { + var targetInfo = retrieveTargetInfo(payload, [HIGHLIGHT_ACTION], model); + + if (targetInfo) { + payload.dataIndex = targetInfo.node.dataIndex; + } + } + + if ("development" !== 'production') { + deprecateReplaceLog('highlight', 'sunburstHighlight'); + } // Fast forward action + + + api.dispatchAction(extend(payload, { + type: 'highlight' + })); + }); + registers.registerAction({ + type: UNHIGHLIGHT_ACTION, + update: 'updateView' + }, function (payload, ecModel, api) { + payload = extend({}, payload); + + if ("development" !== 'production') { + deprecateReplaceLog('downplay', 'sunburstUnhighlight'); + } + + api.dispatchAction(extend(payload, { + type: 'downplay' + })); + }); + } + + var SunburstView = + /** @class */ + function (_super) { + __extends(SunburstView, _super); + + function SunburstView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = SunburstView.type; + return _this; + } + + SunburstView.prototype.render = function (seriesModel, ecModel, api, // @ts-ignore + payload) { + var self = this; + this.seriesModel = seriesModel; + this.api = api; + this.ecModel = ecModel; + var data = seriesModel.getData(); + var virtualRoot = data.tree.root; + var newRoot = seriesModel.getViewRoot(); + var group = this.group; + var renderLabelForZeroData = seriesModel.get('renderLabelForZeroData'); + var newChildren = []; + newRoot.eachNode(function (node) { + newChildren.push(node); + }); + var oldChildren = this._oldChildren || []; + dualTravel(newChildren, oldChildren); + renderRollUp(virtualRoot, newRoot); + + this._initEvents(); + + this._oldChildren = newChildren; + + function dualTravel(newChildren, oldChildren) { + if (newChildren.length === 0 && oldChildren.length === 0) { + return; + } + + new DataDiffer(oldChildren, newChildren, getKey, getKey).add(processNode).update(processNode).remove(curry(processNode, null)).execute(); + + function getKey(node) { + return node.getId(); + } + + function processNode(newIdx, oldIdx) { + var newNode = newIdx == null ? null : newChildren[newIdx]; + var oldNode = oldIdx == null ? null : oldChildren[oldIdx]; + doRenderNode(newNode, oldNode); + } + } + + function doRenderNode(newNode, oldNode) { + if (!renderLabelForZeroData && newNode && !newNode.getValue()) { + // Not render data with value 0 + newNode = null; + } + + if (newNode !== virtualRoot && oldNode !== virtualRoot) { + if (oldNode && oldNode.piece) { + if (newNode) { + // Update + oldNode.piece.updateData(false, newNode, seriesModel, ecModel, api); // For tooltip + + data.setItemGraphicEl(newNode.dataIndex, oldNode.piece); + } else { + // Remove + removeNode(oldNode); + } + } else if (newNode) { + // Add + var piece = new SunburstPiece(newNode, seriesModel, ecModel, api); + group.add(piece); // For tooltip + + data.setItemGraphicEl(newNode.dataIndex, piece); + } + } + } + + function removeNode(node) { + if (!node) { + return; + } + + if (node.piece) { + group.remove(node.piece); + node.piece = null; + } + } + + function renderRollUp(virtualRoot, viewRoot) { + if (viewRoot.depth > 0) { + // Render + if (self.virtualPiece) { + // Update + self.virtualPiece.updateData(false, virtualRoot, seriesModel, ecModel, api); + } else { + // Add + self.virtualPiece = new SunburstPiece(virtualRoot, seriesModel, ecModel, api); + group.add(self.virtualPiece); + } // TODO event scope + + + viewRoot.piece.off('click'); + self.virtualPiece.on('click', function (e) { + self._rootToNode(viewRoot.parentNode); + }); + } else if (self.virtualPiece) { + // Remove + group.remove(self.virtualPiece); + self.virtualPiece = null; + } + } + }; + /** + * @private + */ + + + SunburstView.prototype._initEvents = function () { + var _this = this; + + this.group.off('click'); + this.group.on('click', function (e) { + var targetFound = false; + + var viewRoot = _this.seriesModel.getViewRoot(); + + viewRoot.eachNode(function (node) { + if (!targetFound && node.piece && node.piece === e.target) { + var nodeClick = node.getModel().get('nodeClick'); + + if (nodeClick === 'rootToNode') { + _this._rootToNode(node); + } else if (nodeClick === 'link') { + var itemModel = node.getModel(); + var link = itemModel.get('link'); + + if (link) { + var linkTarget = itemModel.get('target', true) || '_blank'; + windowOpen(link, linkTarget); + } + } + + targetFound = true; + } + }); + }); + }; + /** + * @private + */ + + + SunburstView.prototype._rootToNode = function (node) { + if (node !== this.seriesModel.getViewRoot()) { + this.api.dispatchAction({ + type: ROOT_TO_NODE_ACTION, + from: this.uid, + seriesId: this.seriesModel.id, + targetNode: node + }); + } + }; + /** + * @implement + */ + + + SunburstView.prototype.containPoint = function (point, seriesModel) { + var treeRoot = seriesModel.getData(); + var itemLayout = treeRoot.getItemLayout(0); + + if (itemLayout) { + var dx = point[0] - itemLayout.cx; + var dy = point[1] - itemLayout.cy; + var radius = Math.sqrt(dx * dx + dy * dy); + return radius <= itemLayout.r && radius >= itemLayout.r0; + } + }; + + SunburstView.type = 'sunburst'; + return SunburstView; + }(ChartView); + + var SunburstSeriesModel = + /** @class */ + function (_super) { + __extends(SunburstSeriesModel, _super); + + function SunburstSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = SunburstSeriesModel.type; + _this.ignoreStyleOnData = true; + return _this; + } + + SunburstSeriesModel.prototype.getInitialData = function (option, ecModel) { + // Create a virtual root. + var root = { + name: option.name, + children: option.data + }; + completeTreeValue$1(root); + var levelModels = this._levelModels = map(option.levels || [], function (levelDefine) { + return new Model(levelDefine, this, ecModel); + }, this); // Make sure always a new tree is created when setOption, + // in TreemapView, we check whether oldTree === newTree + // to choose mappings approach among old shapes and new shapes. + + var tree = Tree.createTree(root, this, beforeLink); + + function beforeLink(nodeData) { + nodeData.wrapMethod('getItemModel', function (model, idx) { + var node = tree.getNodeByDataIndex(idx); + var levelModel = levelModels[node.depth]; + levelModel && (model.parentModel = levelModel); + return model; + }); + } + + return tree.data; + }; + + SunburstSeriesModel.prototype.optionUpdated = function () { + this.resetViewRoot(); + }; + /* + * @override + */ + + + SunburstSeriesModel.prototype.getDataParams = function (dataIndex) { + var params = _super.prototype.getDataParams.apply(this, arguments); + + var node = this.getData().tree.getNodeByDataIndex(dataIndex); + params.treePathInfo = wrapTreePathInfo(node, this); + return params; + }; + + SunburstSeriesModel.prototype.getLevelModel = function (node) { + return this._levelModels && this._levelModels[node.depth]; + }; + + SunburstSeriesModel.prototype.getViewRoot = function () { + return this._viewRoot; + }; + + SunburstSeriesModel.prototype.resetViewRoot = function (viewRoot) { + viewRoot ? this._viewRoot = viewRoot : viewRoot = this._viewRoot; + var root = this.getRawData().tree.root; + + if (!viewRoot || viewRoot !== root && !root.contains(viewRoot)) { + this._viewRoot = root; + } + }; + + SunburstSeriesModel.prototype.enableAriaDecal = function () { + enableAriaDecalForTree(this); + }; + + SunburstSeriesModel.type = 'series.sunburst'; + SunburstSeriesModel.defaultOption = { + // zlevel: 0, + z: 2, + // 默认全局居中 + center: ['50%', '50%'], + radius: [0, '75%'], + // 默认顺时针 + clockwise: true, + startAngle: 90, + // 最小角度改为0 + minAngle: 0, + // If still show when all data zero. + stillShowZeroSum: true, + // 'rootToNode', 'link', or false + nodeClick: 'rootToNode', + renderLabelForZeroData: false, + label: { + // could be: 'radial', 'tangential', or 'none' + rotate: 'radial', + show: true, + opacity: 1, + // 'left' is for inner side of inside, and 'right' is for outter + // side for inside + align: 'center', + position: 'inside', + distance: 5, + silent: true + }, + itemStyle: { + borderWidth: 1, + borderColor: 'white', + borderType: 'solid', + shadowBlur: 0, + shadowColor: 'rgba(0, 0, 0, 0.2)', + shadowOffsetX: 0, + shadowOffsetY: 0, + opacity: 1 + }, + emphasis: { + focus: 'descendant' + }, + blur: { + itemStyle: { + opacity: 0.2 + }, + label: { + opacity: 0.1 + } + }, + // Animation type canbe expansion, scale + animationType: 'expansion', + animationDuration: 1000, + animationDurationUpdate: 500, + data: [], + + /** + * Sort order. + * + * Valid values: 'desc', 'asc', null, or callback function. + * 'desc' and 'asc' for descend and ascendant order; + * null for not sorting; + * example of callback function: + * function(nodeA, nodeB) { + * return nodeA.getValue() - nodeB.getValue(); + * } + */ + sort: 'desc' + }; + return SunburstSeriesModel; + }(SeriesModel); + + function completeTreeValue$1(dataNode) { + // Postorder travel tree. + // If value of none-leaf node is not set, + // calculate it by suming up the value of all children. + var sum = 0; + each(dataNode.children, function (child) { + completeTreeValue$1(child); + var childValue = child.value; // TODO First value of array must be a number + + isArray(childValue) && (childValue = childValue[0]); + sum += childValue; + }); + var thisValue = dataNode.value; + + if (isArray(thisValue)) { + thisValue = thisValue[0]; + } + + if (thisValue == null || isNaN(thisValue)) { + thisValue = sum; + } // Value should not less than 0. + + + if (thisValue < 0) { + thisValue = 0; + } + + isArray(dataNode.value) ? dataNode.value[0] = thisValue : dataNode.value = thisValue; + } + + var RADIAN$2 = Math.PI / 180; + function sunburstLayout(seriesType, ecModel, api) { + ecModel.eachSeriesByType(seriesType, function (seriesModel) { + var center = seriesModel.get('center'); + var radius = seriesModel.get('radius'); + + if (!isArray(radius)) { + radius = [0, radius]; + } + + if (!isArray(center)) { + center = [center, center]; + } + + var width = api.getWidth(); + var height = api.getHeight(); + var size = Math.min(width, height); + var cx = parsePercent$1(center[0], width); + var cy = parsePercent$1(center[1], height); + var r0 = parsePercent$1(radius[0], size / 2); + var r = parsePercent$1(radius[1], size / 2); + var startAngle = -seriesModel.get('startAngle') * RADIAN$2; + var minAngle = seriesModel.get('minAngle') * RADIAN$2; + var virtualRoot = seriesModel.getData().tree.root; + var treeRoot = seriesModel.getViewRoot(); + var rootDepth = treeRoot.depth; + var sort = seriesModel.get('sort'); + + if (sort != null) { + initChildren$1(treeRoot, sort); + } + + var validDataCount = 0; + each(treeRoot.children, function (child) { + !isNaN(child.getValue()) && validDataCount++; + }); + var sum = treeRoot.getValue(); // Sum may be 0 + + var unitRadian = Math.PI / (sum || validDataCount) * 2; + var renderRollupNode = treeRoot.depth > 0; + var levels = treeRoot.height - (renderRollupNode ? -1 : 1); + var rPerLevel = (r - r0) / (levels || 1); + var clockwise = seriesModel.get('clockwise'); + var stillShowZeroSum = seriesModel.get('stillShowZeroSum'); // In the case some sector angle is smaller than minAngle + // let restAngle = PI2; + // let valueSumLargerThanMinAngle = 0; + + var dir = clockwise ? 1 : -1; + /** + * Render a tree + * @return increased angle + */ + + var renderNode = function (node, startAngle) { + if (!node) { + return; + } + + var endAngle = startAngle; // Render self + + if (node !== virtualRoot) { + // Tree node is virtual, so it doesn't need to be drawn + var value = node.getValue(); + var angle = sum === 0 && stillShowZeroSum ? unitRadian : value * unitRadian; + + if (angle < minAngle) { + angle = minAngle; // restAngle -= minAngle; + } // else { + // valueSumLargerThanMinAngle += value; + // } + + + endAngle = startAngle + dir * angle; + var depth = node.depth - rootDepth - (renderRollupNode ? -1 : 1); + var rStart = r0 + rPerLevel * depth; + var rEnd = r0 + rPerLevel * (depth + 1); + var levelModel = seriesModel.getLevelModel(node); + + if (levelModel) { + var r0_1 = levelModel.get('r0', true); + var r_1 = levelModel.get('r', true); + var radius_1 = levelModel.get('radius', true); + + if (radius_1 != null) { + r0_1 = radius_1[0]; + r_1 = radius_1[1]; + } + + r0_1 != null && (rStart = parsePercent$1(r0_1, size / 2)); + r_1 != null && (rEnd = parsePercent$1(r_1, size / 2)); + } + + node.setLayout({ + angle: angle, + startAngle: startAngle, + endAngle: endAngle, + clockwise: clockwise, + cx: cx, + cy: cy, + r0: rStart, + r: rEnd + }); + } // Render children + + + if (node.children && node.children.length) { + // currentAngle = startAngle; + var siblingAngle_1 = 0; + each(node.children, function (node) { + siblingAngle_1 += renderNode(node, startAngle + siblingAngle_1); + }); + } + + return endAngle - startAngle; + }; // Virtual root node for roll up + + + if (renderRollupNode) { + var rStart = r0; + var rEnd = r0 + rPerLevel; + var angle = Math.PI * 2; + virtualRoot.setLayout({ + angle: angle, + startAngle: startAngle, + endAngle: startAngle + angle, + clockwise: clockwise, + cx: cx, + cy: cy, + r0: rStart, + r: rEnd + }); + } + + renderNode(treeRoot, startAngle); + }); + } + /** + * Init node children by order and update visual + */ + + function initChildren$1(node, sortOrder) { + var children = node.children || []; + node.children = sort$2(children, sortOrder); // Init children recursively + + if (children.length) { + each(node.children, function (child) { + initChildren$1(child, sortOrder); + }); + } + } + /** + * Sort children nodes + * + * @param {TreeNode[]} children children of node to be sorted + * @param {string | function | null} sort sort method + * See SunburstSeries.js for details. + */ + + + function sort$2(children, sortOrder) { + if (isFunction(sortOrder)) { + var sortTargets = map(children, function (child, idx) { + var value = child.getValue(); + return { + params: { + depth: child.depth, + height: child.height, + dataIndex: child.dataIndex, + getValue: function () { + return value; + } + }, + index: idx + }; + }); + sortTargets.sort(function (a, b) { + return sortOrder(a.params, b.params); + }); + return map(sortTargets, function (target) { + return children[target.index]; + }); + } else { + var isAsc_1 = sortOrder === 'asc'; + return children.sort(function (a, b) { + var diff = (a.getValue() - b.getValue()) * (isAsc_1 ? 1 : -1); + return diff === 0 ? (a.dataIndex - b.dataIndex) * (isAsc_1 ? -1 : 1) : diff; + }); + } + } + + function sunburstVisual(ecModel) { + var paletteScope = {}; // Default color strategy + + function pickColor(node, seriesModel, treeHeight) { + // Choose color from palette based on the first level. + var current = node; + + while (current && current.depth > 1) { + current = current.parentNode; + } + + var color = seriesModel.getColorFromPalette(current.name || current.dataIndex + '', paletteScope); + + if (node.depth > 1 && isString(color)) { + // Lighter on the deeper level. + color = lift(color, (node.depth - 1) / (treeHeight - 1) * 0.5); + } + + return color; + } + + ecModel.eachSeriesByType('sunburst', function (seriesModel) { + var data = seriesModel.getData(); + var tree = data.tree; + tree.eachNode(function (node) { + var model = node.getModel(); + var style = model.getModel('itemStyle').getItemStyle(); + + if (!style.fill) { + style.fill = pickColor(node, seriesModel, tree.root.height); + } + + var existsStyle = data.ensureUniqueItemVisual(node.dataIndex, 'style'); + extend(existsStyle, style); + }); + }); + } + + function install$q(registers) { + registers.registerChartView(SunburstView); + registers.registerSeriesModel(SunburstSeriesModel); + registers.registerLayout(curry(sunburstLayout, 'sunburst')); + registers.registerProcessor(curry(dataFilter, 'sunburst')); + registers.registerVisual(sunburstVisual); + installSunburstAction(registers); + } + + // `visual('color') visual('borderColor')` is supported. + + var STYLE_VISUAL_TYPE = { + color: 'fill', + borderColor: 'stroke' + }; + var NON_STYLE_VISUAL_PROPS = { + symbol: 1, + symbolSize: 1, + symbolKeepAspect: 1, + legendIcon: 1, + visualMeta: 1, + liftZ: 1, + decal: 1 + }; + var customInnerStore = makeInner(); + + var CustomSeriesModel = + /** @class */ + function (_super) { + __extends(CustomSeriesModel, _super); + + function CustomSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = CustomSeriesModel.type; + return _this; + } + + CustomSeriesModel.prototype.optionUpdated = function () { + this.currentZLevel = this.get('zlevel', true); + this.currentZ = this.get('z', true); + }; + + CustomSeriesModel.prototype.getInitialData = function (option, ecModel) { + return createSeriesData(null, this); + }; + + CustomSeriesModel.prototype.getDataParams = function (dataIndex, dataType, el) { + var params = _super.prototype.getDataParams.call(this, dataIndex, dataType); + + el && (params.info = customInnerStore(el).info); + return params; + }; + + CustomSeriesModel.type = 'series.custom'; + CustomSeriesModel.dependencies = ['grid', 'polar', 'geo', 'singleAxis', 'calendar']; + CustomSeriesModel.defaultOption = { + coordinateSystem: 'cartesian2d', + // zlevel: 0, + z: 2, + legendHoverLink: true, + // Custom series will not clip by default. + // Some case will use custom series to draw label + // For example https://echarts.apache.org/examples/en/editor.html?c=custom-gantt-flight + clip: false // Cartesian coordinate system + // xAxisIndex: 0, + // yAxisIndex: 0, + // Polar coordinate system + // polarIndex: 0, + // Geo coordinate system + // geoIndex: 0, + + }; + return CustomSeriesModel; + }(SeriesModel); + + function dataToCoordSize(dataSize, dataItem) { + // dataItem is necessary in log axis. + dataItem = dataItem || [0, 0]; + return map(['x', 'y'], function (dim, dimIdx) { + var axis = this.getAxis(dim); + var val = dataItem[dimIdx]; + var halfSize = dataSize[dimIdx] / 2; + return axis.type === 'category' ? axis.getBandWidth() : Math.abs(axis.dataToCoord(val - halfSize) - axis.dataToCoord(val + halfSize)); + }, this); + } + + function cartesianPrepareCustom(coordSys) { + var rect = coordSys.master.getRect(); + return { + coordSys: { + // The name exposed to user is always 'cartesian2d' but not 'grid'. + type: 'cartesian2d', + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height + }, + api: { + coord: function (data) { + // do not provide "out" param + return coordSys.dataToPoint(data); + }, + size: bind(dataToCoordSize, coordSys) + } + }; + } + + function dataToCoordSize$1(dataSize, dataItem) { + dataItem = dataItem || [0, 0]; + return map([0, 1], function (dimIdx) { + var val = dataItem[dimIdx]; + var halfSize = dataSize[dimIdx] / 2; + var p1 = []; + var p2 = []; + p1[dimIdx] = val - halfSize; + p2[dimIdx] = val + halfSize; + p1[1 - dimIdx] = p2[1 - dimIdx] = dataItem[1 - dimIdx]; + return Math.abs(this.dataToPoint(p1)[dimIdx] - this.dataToPoint(p2)[dimIdx]); + }, this); + } + + function geoPrepareCustom(coordSys) { + var rect = coordSys.getBoundingRect(); + return { + coordSys: { + type: 'geo', + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height, + zoom: coordSys.getZoom() + }, + api: { + coord: function (data) { + // do not provide "out" and noRoam param, + // Compatible with this usage: + // echarts.util.map(item.points, api.coord) + return coordSys.dataToPoint(data); + }, + size: bind(dataToCoordSize$1, coordSys) + } + }; + } + + function dataToCoordSize$2(dataSize, dataItem) { + // dataItem is necessary in log axis. + var axis = this.getAxis(); + var val = dataItem instanceof Array ? dataItem[0] : dataItem; + var halfSize = (dataSize instanceof Array ? dataSize[0] : dataSize) / 2; + return axis.type === 'category' ? axis.getBandWidth() : Math.abs(axis.dataToCoord(val - halfSize) - axis.dataToCoord(val + halfSize)); + } + + function singlePrepareCustom(coordSys) { + var rect = coordSys.getRect(); + return { + coordSys: { + type: 'singleAxis', + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height + }, + api: { + coord: function (val) { + // do not provide "out" param + return coordSys.dataToPoint(val); + }, + size: bind(dataToCoordSize$2, coordSys) + } + }; + } + + function dataToCoordSize$3(dataSize, dataItem) { + // dataItem is necessary in log axis. + dataItem = dataItem || [0, 0]; + return map(['Radius', 'Angle'], function (dim, dimIdx) { + var getterName = 'get' + dim + 'Axis'; // TODO: TYPE Check Angle Axis + + var axis = this[getterName](); + var val = dataItem[dimIdx]; + var halfSize = dataSize[dimIdx] / 2; + var result = axis.type === 'category' ? axis.getBandWidth() : Math.abs(axis.dataToCoord(val - halfSize) - axis.dataToCoord(val + halfSize)); + + if (dim === 'Angle') { + result = result * Math.PI / 180; + } + + return result; + }, this); + } + + function polarPrepareCustom(coordSys) { + var radiusAxis = coordSys.getRadiusAxis(); + var angleAxis = coordSys.getAngleAxis(); + var radius = radiusAxis.getExtent(); + radius[0] > radius[1] && radius.reverse(); + return { + coordSys: { + type: 'polar', + cx: coordSys.cx, + cy: coordSys.cy, + r: radius[1], + r0: radius[0] + }, + api: { + coord: function (data) { + var radius = radiusAxis.dataToRadius(data[0]); + var angle = angleAxis.dataToAngle(data[1]); + var coord = coordSys.coordToPoint([radius, angle]); + coord.push(radius, angle * Math.PI / 180); + return coord; + }, + size: bind(dataToCoordSize$3, coordSys) + } + }; + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + function calendarPrepareCustom(coordSys) { + var rect = coordSys.getRect(); + var rangeInfo = coordSys.getRangeInfo(); + return { + coordSys: { + type: 'calendar', + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height, + cellWidth: coordSys.getCellWidth(), + cellHeight: coordSys.getCellHeight(), + rangeInfo: { + start: rangeInfo.start, + end: rangeInfo.end, + weeks: rangeInfo.weeks, + dayCount: rangeInfo.allDay + } + }, + api: { + coord: function (data, clamp) { + return coordSys.dataToPoint(data, clamp); + } + } + }; + } + + var deprecatedLogs = {}; + /** + * Whether need to call `convertEC4CompatibleStyle`. + */ + + function isEC4CompatibleStyle(style, elType, hasOwnTextContentOption, hasOwnTextConfig) { + // Since echarts5, `RectText` is separated from its host element and style.text + // does not exist any more. The compat work brings some extra burden on performance. + // So we provide: + // `legacy: true` force make compat. + // `legacy: false`, force do not compat. + // `legacy` not set: auto detect wheter legacy. + // But in this case we do not compat (difficult to detect and rare case): + // Becuse custom series and graphic component support "merge", users may firstly + // only set `textStrokeWidth` style or secondly only set `text`. + return style && (style.legacy || style.legacy !== false && !hasOwnTextContentOption && !hasOwnTextConfig && elType !== 'tspan' // Difficult to detect whether legacy for a "text" el. + && (elType === 'text' || hasOwn(style, 'text'))); + } + /** + * `EC4CompatibleStyle` is style that might be in echarts4 format or echarts5 format. + * @param hostStyle The properties might be modified. + * @return If be text el, `textContentStyle` and `textConfig` will not be retured. + * Otherwise a `textContentStyle` and `textConfig` will be created, whose props area + * retried from the `hostStyle`. + */ + + function convertFromEC4CompatibleStyle(hostStyle, elType, isNormal) { + var srcStyle = hostStyle; + var textConfig; + var textContent; + var textContentStyle; + + if (elType === 'text') { + textContentStyle = srcStyle; + } else { + textContentStyle = {}; + hasOwn(srcStyle, 'text') && (textContentStyle.text = srcStyle.text); + hasOwn(srcStyle, 'rich') && (textContentStyle.rich = srcStyle.rich); + hasOwn(srcStyle, 'textFill') && (textContentStyle.fill = srcStyle.textFill); + hasOwn(srcStyle, 'textStroke') && (textContentStyle.stroke = srcStyle.textStroke); + hasOwn(srcStyle, 'fontFamily') && (textContentStyle.fontFamily = srcStyle.fontFamily); + hasOwn(srcStyle, 'fontSize') && (textContentStyle.fontSize = srcStyle.fontSize); + hasOwn(srcStyle, 'fontStyle') && (textContentStyle.fontStyle = srcStyle.fontStyle); + hasOwn(srcStyle, 'fontWeight') && (textContentStyle.fontWeight = srcStyle.fontWeight); + textContent = { + type: 'text', + style: textContentStyle, + // ec4 do not support rectText trigger. + // And when text postion is different in normal and emphasis + // => hover text trigger emphasis; + // => text position changed, leave mouse pointer immediately; + // That might cause state incorrect. + silent: true + }; + textConfig = {}; + var hasOwnPos = hasOwn(srcStyle, 'textPosition'); + + if (isNormal) { + textConfig.position = hasOwnPos ? srcStyle.textPosition : 'inside'; + } else { + hasOwnPos && (textConfig.position = srcStyle.textPosition); + } + + hasOwn(srcStyle, 'textPosition') && (textConfig.position = srcStyle.textPosition); + hasOwn(srcStyle, 'textOffset') && (textConfig.offset = srcStyle.textOffset); + hasOwn(srcStyle, 'textRotation') && (textConfig.rotation = srcStyle.textRotation); + hasOwn(srcStyle, 'textDistance') && (textConfig.distance = srcStyle.textDistance); + } + + convertEC4CompatibleRichItem(textContentStyle, hostStyle); + each(textContentStyle.rich, function (richItem) { + convertEC4CompatibleRichItem(richItem, richItem); + }); + return { + textConfig: textConfig, + textContent: textContent + }; + } + /** + * The result will be set to `out`. + */ + + function convertEC4CompatibleRichItem(out, richItem) { + if (!richItem) { + return; + } // (1) For simplicity, make textXXX properties (deprecated since ec5) has + // higher priority. For example, consider in ec4 `borderColor: 5, textBorderColor: 10` + // on a rect means `borderColor: 4` on the rect and `borderColor: 10` on an attached + // richText in ec5. + // (2) `out === richItem` if and only if `out` is text el or rich item. + // So we can overwite existing props in `out` since textXXX has higher priority. + + + richItem.font = richItem.textFont || richItem.font; + hasOwn(richItem, 'textStrokeWidth') && (out.lineWidth = richItem.textStrokeWidth); + hasOwn(richItem, 'textAlign') && (out.align = richItem.textAlign); + hasOwn(richItem, 'textVerticalAlign') && (out.verticalAlign = richItem.textVerticalAlign); + hasOwn(richItem, 'textLineHeight') && (out.lineHeight = richItem.textLineHeight); + hasOwn(richItem, 'textWidth') && (out.width = richItem.textWidth); + hasOwn(richItem, 'textHeight') && (out.height = richItem.textHeight); + hasOwn(richItem, 'textBackgroundColor') && (out.backgroundColor = richItem.textBackgroundColor); + hasOwn(richItem, 'textPadding') && (out.padding = richItem.textPadding); + hasOwn(richItem, 'textBorderColor') && (out.borderColor = richItem.textBorderColor); + hasOwn(richItem, 'textBorderWidth') && (out.borderWidth = richItem.textBorderWidth); + hasOwn(richItem, 'textBorderRadius') && (out.borderRadius = richItem.textBorderRadius); + hasOwn(richItem, 'textBoxShadowColor') && (out.shadowColor = richItem.textBoxShadowColor); + hasOwn(richItem, 'textBoxShadowBlur') && (out.shadowBlur = richItem.textBoxShadowBlur); + hasOwn(richItem, 'textBoxShadowOffsetX') && (out.shadowOffsetX = richItem.textBoxShadowOffsetX); + hasOwn(richItem, 'textBoxShadowOffsetY') && (out.shadowOffsetY = richItem.textBoxShadowOffsetY); + } + /** + * Convert to pure echarts4 format style. + * `itemStyle` will be modified, added with ec4 style properties from + * `textStyle` and `textConfig`. + * + * [Caveat]: For simplicity, `insideRollback` in ec4 does not compat, where + * `styleEmphasis: {textFill: 'red'}` will remove the normal auto added stroke. + */ + + + function convertToEC4StyleForCustomSerise(itemStl, txStl, txCfg) { + var out = itemStl; // See `custom.ts`, a trick to set extra `textPosition` firstly. + + out.textPosition = out.textPosition || txCfg.position || 'inside'; + txCfg.offset != null && (out.textOffset = txCfg.offset); + txCfg.rotation != null && (out.textRotation = txCfg.rotation); + txCfg.distance != null && (out.textDistance = txCfg.distance); + var isInside = out.textPosition.indexOf('inside') >= 0; + var hostFill = itemStl.fill || '#000'; + convertToEC4RichItem(out, txStl); + var textFillNotSet = out.textFill == null; + + if (isInside) { + if (textFillNotSet) { + out.textFill = txCfg.insideFill || '#fff'; + !out.textStroke && txCfg.insideStroke && (out.textStroke = txCfg.insideStroke); + !out.textStroke && (out.textStroke = hostFill); + out.textStrokeWidth == null && (out.textStrokeWidth = 2); + } + } else { + if (textFillNotSet) { + out.textFill = itemStl.fill || txCfg.outsideFill || '#000'; + } + + !out.textStroke && txCfg.outsideStroke && (out.textStroke = txCfg.outsideStroke); + } + + out.text = txStl.text; + out.rich = txStl.rich; + each(txStl.rich, function (richItem) { + convertToEC4RichItem(richItem, richItem); + }); + return out; + } + + function convertToEC4RichItem(out, richItem) { + if (!richItem) { + return; + } + + hasOwn(richItem, 'fill') && (out.textFill = richItem.fill); + hasOwn(richItem, 'stroke') && (out.textStroke = richItem.fill); + hasOwn(richItem, 'lineWidth') && (out.textStrokeWidth = richItem.lineWidth); + hasOwn(richItem, 'font') && (out.font = richItem.font); + hasOwn(richItem, 'fontStyle') && (out.fontStyle = richItem.fontStyle); + hasOwn(richItem, 'fontWeight') && (out.fontWeight = richItem.fontWeight); + hasOwn(richItem, 'fontSize') && (out.fontSize = richItem.fontSize); + hasOwn(richItem, 'fontFamily') && (out.fontFamily = richItem.fontFamily); + hasOwn(richItem, 'align') && (out.textAlign = richItem.align); + hasOwn(richItem, 'verticalAlign') && (out.textVerticalAlign = richItem.verticalAlign); + hasOwn(richItem, 'lineHeight') && (out.textLineHeight = richItem.lineHeight); + hasOwn(richItem, 'width') && (out.textWidth = richItem.width); + hasOwn(richItem, 'height') && (out.textHeight = richItem.height); + hasOwn(richItem, 'backgroundColor') && (out.textBackgroundColor = richItem.backgroundColor); + hasOwn(richItem, 'padding') && (out.textPadding = richItem.padding); + hasOwn(richItem, 'borderColor') && (out.textBorderColor = richItem.borderColor); + hasOwn(richItem, 'borderWidth') && (out.textBorderWidth = richItem.borderWidth); + hasOwn(richItem, 'borderRadius') && (out.textBorderRadius = richItem.borderRadius); + hasOwn(richItem, 'shadowColor') && (out.textBoxShadowColor = richItem.shadowColor); + hasOwn(richItem, 'shadowBlur') && (out.textBoxShadowBlur = richItem.shadowBlur); + hasOwn(richItem, 'shadowOffsetX') && (out.textBoxShadowOffsetX = richItem.shadowOffsetX); + hasOwn(richItem, 'shadowOffsetY') && (out.textBoxShadowOffsetY = richItem.shadowOffsetY); + hasOwn(richItem, 'textShadowColor') && (out.textShadowColor = richItem.textShadowColor); + hasOwn(richItem, 'textShadowBlur') && (out.textShadowBlur = richItem.textShadowBlur); + hasOwn(richItem, 'textShadowOffsetX') && (out.textShadowOffsetX = richItem.textShadowOffsetX); + hasOwn(richItem, 'textShadowOffsetY') && (out.textShadowOffsetY = richItem.textShadowOffsetY); + } + + function warnDeprecated(deprecated, insteadApproach) { + if ("development" !== 'production') { + var key = deprecated + '^_^' + insteadApproach; + + if (!deprecatedLogs[key]) { + console.warn("[ECharts] DEPRECATED: \"" + deprecated + "\" has been deprecated. " + insteadApproach); + deprecatedLogs[key] = true; + } + } + } + + var LEGACY_TRANSFORM_PROPS_MAP = { + position: ['x', 'y'], + scale: ['scaleX', 'scaleY'], + origin: ['originX', 'originY'] + }; + var LEGACY_TRANSFORM_PROPS = keys(LEGACY_TRANSFORM_PROPS_MAP); + var TRANSFORM_PROPS_MAP = reduce(TRANSFORMABLE_PROPS, function (obj, key) { + obj[key] = 1; + return obj; + }, {}); + var transformPropNamesStr = TRANSFORMABLE_PROPS.join(', '); // '' means root + + var ELEMENT_ANIMATABLE_PROPS = ['', 'style', 'shape', 'extra']; + var transitionInnerStore = makeInner(); + + function getElementAnimationConfig(animationType, el, elOption, parentModel, dataIndex) { + var animationProp = animationType + "Animation"; + var config = getAnimationConfig(animationType, parentModel, dataIndex) || {}; + var userDuring = transitionInnerStore(el).userDuring; // Only set when duration is > 0 and it's need to be animated. + + if (config.duration > 0) { + // For simplicity, if during not specified, the previous during will not work any more. + config.during = userDuring ? bind(duringCall, { + el: el, + userDuring: userDuring + }) : null; + config.setToFinal = true; + config.scope = animationType; + } + + extend(config, elOption[animationProp]); + return config; + } + + function applyUpdateTransition(el, elOption, animatableModel, opts) { + opts = opts || {}; + var dataIndex = opts.dataIndex, + isInit = opts.isInit, + clearStyle = opts.clearStyle; + var hasAnimation = animatableModel.isAnimationEnabled(); // Save the meta info for further morphing. Like apply on the sub morphing elements. + + var store = transitionInnerStore(el); + var styleOpt = elOption.style; + store.userDuring = elOption.during; + var transFromProps = {}; + var propsToSet = {}; + prepareTransformAllPropsFinal(el, elOption, propsToSet); + prepareShapeOrExtraAllPropsFinal('shape', elOption, propsToSet); + prepareShapeOrExtraAllPropsFinal('extra', elOption, propsToSet); + + if (!isInit && hasAnimation) { + prepareTransformTransitionFrom(el, elOption, transFromProps); + prepareShapeOrExtraTransitionFrom('shape', el, elOption, transFromProps); + prepareShapeOrExtraTransitionFrom('extra', el, elOption, transFromProps); + prepareStyleTransitionFrom(el, elOption, styleOpt, transFromProps); + } + + propsToSet.style = styleOpt; + applyPropsDirectly(el, propsToSet, clearStyle); + applyMiscProps(el, elOption); + + if (hasAnimation) { + if (isInit) { + var enterFromProps_1 = {}; + each(ELEMENT_ANIMATABLE_PROPS, function (propName) { + var prop = propName ? elOption[propName] : elOption; + + if (prop && prop.enterFrom) { + if (propName) { + enterFromProps_1[propName] = enterFromProps_1[propName] || {}; + } + + extend(propName ? enterFromProps_1[propName] : enterFromProps_1, prop.enterFrom); + } + }); + var config = getElementAnimationConfig('enter', el, elOption, animatableModel, dataIndex); + + if (config.duration > 0) { + el.animateFrom(enterFromProps_1, config); + } + } else { + applyPropsTransition(el, elOption, dataIndex || 0, animatableModel, transFromProps); + } + } // Store leave to be used in leave transition. + + + updateLeaveTo(el, elOption); + styleOpt ? el.dirty() : el.markRedraw(); + } + function updateLeaveTo(el, elOption) { + // Try merge to previous set leaveTo + var leaveToProps = transitionInnerStore(el).leaveToProps; + + for (var i = 0; i < ELEMENT_ANIMATABLE_PROPS.length; i++) { + var propName = ELEMENT_ANIMATABLE_PROPS[i]; + var prop = propName ? elOption[propName] : elOption; + + if (prop && prop.leaveTo) { + if (!leaveToProps) { + leaveToProps = transitionInnerStore(el).leaveToProps = {}; + } + + if (propName) { + leaveToProps[propName] = leaveToProps[propName] || {}; + } + + extend(propName ? leaveToProps[propName] : leaveToProps, prop.leaveTo); + } + } + } + function applyLeaveTransition(el, elOption, animatableModel, onRemove) { + if (el) { + var parent_1 = el.parent; + var leaveToProps = transitionInnerStore(el).leaveToProps; + + if (leaveToProps) { + // TODO TODO use leave after leaveAnimation in series is introduced + // TODO Data index? + var config = getElementAnimationConfig('update', el, elOption, animatableModel, 0); + + config.done = function () { + parent_1.remove(el); + onRemove && onRemove(); + }; + + el.animateTo(leaveToProps, config); + } else { + parent_1.remove(el); + onRemove && onRemove(); + } + } + } + function isTransitionAll(transition) { + return transition === 'all'; + } + + function applyPropsDirectly(el, // Can be null/undefined + allPropsFinal, clearStyle) { + var styleOpt = allPropsFinal.style; + + if (!el.isGroup && styleOpt) { + if (clearStyle) { + el.useStyle({}); // When style object changed, how to trade the existing animation? + // It is probably complicated and not needed to cover all the cases. + // But still need consider the case: + // (1) When using init animation on `style.opacity`, and before the animation + // ended users triggers an update by mousewhel. At that time the init + // animation should better be continued rather than terminated. + // So after `useStyle` called, we should change the animation target manually + // to continue the effect of the init animation. + // (2) PENDING: If the previous animation targeted at a `val1`, and currently we need + // to update the value to `val2` and no animation declared, should be terminate + // the previous animation or just modify the target of the animation? + // Therotically That will happen not only on `style` but also on `shape` and + // `transfrom` props. But we haven't handle this case at present yet. + // (3) PENDING: Is it proper to visit `animators` and `targetName`? + + var animators = el.animators; + + for (var i = 0; i < animators.length; i++) { + var animator = animators[i]; // targetName is the "topKey". + + if (animator.targetName === 'style') { + animator.changeTarget(el.style); + } + } + } + + el.setStyle(styleOpt); + } + + if (allPropsFinal) { + // Not set style here. + allPropsFinal.style = null; // Set el to the final state firstly. + + allPropsFinal && el.attr(allPropsFinal); + allPropsFinal.style = styleOpt; + } + } + + function applyPropsTransition(el, elOption, dataIndex, model, // Can be null/undefined + transFromProps) { + if (transFromProps) { + var config = getElementAnimationConfig('update', el, elOption, model, dataIndex); + + if (config.duration > 0) { + el.animateFrom(transFromProps, config); + } + } + } + + function applyMiscProps(el, elOption) { + // Merge by default. + hasOwn(elOption, 'silent') && (el.silent = elOption.silent); + hasOwn(elOption, 'ignore') && (el.ignore = elOption.ignore); + + if (el instanceof Displayable) { + hasOwn(elOption, 'invisible') && (el.invisible = elOption.invisible); + } + + if (el instanceof Path) { + hasOwn(elOption, 'autoBatch') && (el.autoBatch = elOption.autoBatch); + } + } // Use it to avoid it be exposed to user. + + + var tmpDuringScope = {}; + var transitionDuringAPI = { + // Usually other props do not need to be changed in animation during. + setTransform: function (key, val) { + if ("development" !== 'production') { + assert(hasOwn(TRANSFORM_PROPS_MAP, key), 'Only ' + transformPropNamesStr + ' available in `setTransform`.'); + } + + tmpDuringScope.el[key] = val; + return this; + }, + getTransform: function (key) { + if ("development" !== 'production') { + assert(hasOwn(TRANSFORM_PROPS_MAP, key), 'Only ' + transformPropNamesStr + ' available in `getTransform`.'); + } + + return tmpDuringScope.el[key]; + }, + setShape: function (key, val) { + if ("development" !== 'production') { + assertNotReserved(key); + } + + var el = tmpDuringScope.el; + var shape = el.shape || (el.shape = {}); + shape[key] = val; + el.dirtyShape && el.dirtyShape(); + return this; + }, + getShape: function (key) { + if ("development" !== 'production') { + assertNotReserved(key); + } + + var shape = tmpDuringScope.el.shape; + + if (shape) { + return shape[key]; + } + }, + setStyle: function (key, val) { + if ("development" !== 'production') { + assertNotReserved(key); + } + + var el = tmpDuringScope.el; + var style = el.style; + + if (style) { + if ("development" !== 'production') { + if (eqNaN(val)) { + warn('style.' + key + ' must not be assigned with NaN.'); + } + } + + style[key] = val; + el.dirtyStyle && el.dirtyStyle(); + } + + return this; + }, + getStyle: function (key) { + if ("development" !== 'production') { + assertNotReserved(key); + } + + var style = tmpDuringScope.el.style; + + if (style) { + return style[key]; + } + }, + setExtra: function (key, val) { + if ("development" !== 'production') { + assertNotReserved(key); + } + + var extra = tmpDuringScope.el.extra || (tmpDuringScope.el.extra = {}); + extra[key] = val; + return this; + }, + getExtra: function (key) { + if ("development" !== 'production') { + assertNotReserved(key); + } + + var extra = tmpDuringScope.el.extra; + + if (extra) { + return extra[key]; + } + } + }; + + function assertNotReserved(key) { + if ("development" !== 'production') { + if (key === 'transition' || key === 'enterFrom' || key === 'leaveTo') { + throw new Error('key must not be "' + key + '"'); + } + } + } + + function duringCall() { + // Do not provide "percent" until some requirements come. + // Because consider thies case: + // enterFrom: {x: 100, y: 30}, transition: 'x'. + // And enter duration is different from update duration. + // Thus it might be confused about the meaning of "percent" in during callback. + var scope = this; + var el = scope.el; + + if (!el) { + return; + } // If el is remove from zr by reason like legend, during still need to called, + // becuase el will be added back to zr and the prop value should not be incorrect. + + + var latestUserDuring = transitionInnerStore(el).userDuring; + var scopeUserDuring = scope.userDuring; // Ensured a during is only called once in each animation frame. + // If a during is called multiple times in one frame, maybe some users' calulation logic + // might be wrong (not sure whether this usage exists). + // The case of a during might be called twice can be: by default there is a animator for + // 'x', 'y' when init. Before the init animation finished, call `setOption` to start + // another animators for 'style'/'shape'/'extra'. + + if (latestUserDuring !== scopeUserDuring) { + // release + scope.el = scope.userDuring = null; + return; + } + + tmpDuringScope.el = el; // Give no `this` to user in "during" calling. + + scopeUserDuring(transitionDuringAPI); // FIXME: if in future meet the case that some prop will be both modified in `during` and `state`, + // consider the issue that the prop might be incorrect when return to "normal" state. + } + + function prepareShapeOrExtraTransitionFrom(mainAttr, fromEl, elOption, transFromProps) { + var attrOpt = elOption[mainAttr]; + + if (!attrOpt) { + return; + } + + var elPropsInAttr = fromEl[mainAttr]; + var transFromPropsInAttr; + + if (elPropsInAttr) { + var transition = elOption.transition; + var attrTransition = attrOpt.transition; + + if (attrTransition) { + !transFromPropsInAttr && (transFromPropsInAttr = transFromProps[mainAttr] = {}); + + if (isTransitionAll(attrTransition)) { + extend(transFromPropsInAttr, elPropsInAttr); + } else { + var transitionKeys = normalizeToArray(attrTransition); + + for (var i = 0; i < transitionKeys.length; i++) { + var key = transitionKeys[i]; + var elVal = elPropsInAttr[key]; + transFromPropsInAttr[key] = elVal; + } + } + } else if (isTransitionAll(transition) || indexOf(transition, mainAttr) >= 0) { + !transFromPropsInAttr && (transFromPropsInAttr = transFromProps[mainAttr] = {}); + var elPropsInAttrKeys = keys(elPropsInAttr); + + for (var i = 0; i < elPropsInAttrKeys.length; i++) { + var key = elPropsInAttrKeys[i]; + var elVal = elPropsInAttr[key]; + + if (isNonStyleTransitionEnabled(attrOpt[key], elVal)) { + transFromPropsInAttr[key] = elVal; + } + } + } + } + } + + function prepareShapeOrExtraAllPropsFinal(mainAttr, elOption, allProps) { + var attrOpt = elOption[mainAttr]; + + if (!attrOpt) { + return; + } + + var allPropsInAttr = allProps[mainAttr] = {}; + var keysInAttr = keys(attrOpt); + + for (var i = 0; i < keysInAttr.length; i++) { + var key = keysInAttr[i]; // To avoid share one object with different element, and + // to avoid user modify the object inexpectedly, have to clone. + + allPropsInAttr[key] = cloneValue(attrOpt[key]); + } + } + + function prepareTransformTransitionFrom(el, elOption, transFromProps) { + var transition = elOption.transition; + var transitionKeys = isTransitionAll(transition) ? TRANSFORMABLE_PROPS : normalizeToArray(transition || []); + + for (var i = 0; i < transitionKeys.length; i++) { + var key = transitionKeys[i]; + + if (key === 'style' || key === 'shape' || key === 'extra') { + continue; + } + + var elVal = el[key]; + + if ("development" !== 'production') { + checkTransformPropRefer(key, 'el.transition'); + } // Do not clone, animator will perform that clone. + + + transFromProps[key] = elVal; + } + } + + function prepareTransformAllPropsFinal(el, elOption, allProps) { + for (var i = 0; i < LEGACY_TRANSFORM_PROPS.length; i++) { + var legacyName = LEGACY_TRANSFORM_PROPS[i]; + var xyName = LEGACY_TRANSFORM_PROPS_MAP[legacyName]; + var legacyArr = elOption[legacyName]; + + if (legacyArr) { + allProps[xyName[0]] = legacyArr[0]; + allProps[xyName[1]] = legacyArr[1]; + } + } + + for (var i = 0; i < TRANSFORMABLE_PROPS.length; i++) { + var key = TRANSFORMABLE_PROPS[i]; + + if (elOption[key] != null) { + allProps[key] = elOption[key]; + } + } + } + + function prepareStyleTransitionFrom(fromEl, elOption, styleOpt, transFromProps) { + if (!styleOpt) { + return; + } + + var fromElStyle = fromEl.style; + var transFromStyleProps; + + if (fromElStyle) { + var styleTransition = styleOpt.transition; + var elTransition = elOption.transition; + + if (styleTransition && !isTransitionAll(styleTransition)) { + var transitionKeys = normalizeToArray(styleTransition); + !transFromStyleProps && (transFromStyleProps = transFromProps.style = {}); + + for (var i = 0; i < transitionKeys.length; i++) { + var key = transitionKeys[i]; + var elVal = fromElStyle[key]; // Do not clone, see `checkNonStyleTansitionRefer`. + + transFromStyleProps[key] = elVal; + } + } else if (fromEl.getAnimationStyleProps && (isTransitionAll(elTransition) || isTransitionAll(styleTransition) || indexOf(elTransition, 'style') >= 0)) { + var animationProps = fromEl.getAnimationStyleProps(); + var animationStyleProps = animationProps ? animationProps.style : null; + + if (animationStyleProps) { + !transFromStyleProps && (transFromStyleProps = transFromProps.style = {}); + var styleKeys = keys(styleOpt); + + for (var i = 0; i < styleKeys.length; i++) { + var key = styleKeys[i]; + + if (animationStyleProps[key]) { + var elVal = fromElStyle[key]; + transFromStyleProps[key] = elVal; + } + } + } + } + } + } + + function isNonStyleTransitionEnabled(optVal, elVal) { + // The same as `checkNonStyleTansitionRefer`. + return !isArrayLike(optVal) ? optVal != null && isFinite(optVal) : optVal !== elVal; + } + + var checkTransformPropRefer; + + if ("development" !== 'production') { + checkTransformPropRefer = function (key, usedIn) { + if (!hasOwn(TRANSFORM_PROPS_MAP, key)) { + warn('Prop `' + key + '` is not a permitted in `' + usedIn + '`. ' + 'Only `' + keys(TRANSFORM_PROPS_MAP).join('`, `') + '` are permitted.'); + } + }; + } + + var getStateToRestore = makeInner(); + var KEYFRAME_EXCLUDE_KEYS = ['percent', 'easing', 'shape', 'style', 'extra']; + /** + * Stop previous keyframe animation and restore the attributes. + * Avoid new keyframe animation starts with wrong internal state when the percent: 0 is not set. + */ + + function stopPreviousKeyframeAnimationAndRestore(el) { + // Stop previous keyframe animation. + el.stopAnimation('keyframe'); // Restore + + el.attr(getStateToRestore(el)); + } + function applyKeyframeAnimation(el, animationOpts, animatableModel) { + if (!animatableModel.isAnimationEnabled() || !animationOpts) { + return; + } + + if (isArray(animationOpts)) { + each(animationOpts, function (singleAnimationOpts) { + applyKeyframeAnimation(el, singleAnimationOpts, animatableModel); + }); + return; + } + + var keyframes = animationOpts.keyframes; + var duration = animationOpts.duration; + + if (animatableModel && duration == null) { + // Default to use duration of config. + // NOTE: animation config from payload will be ignored because they are mainly for transitions. + var config = getAnimationConfig('enter', animatableModel, 0); + duration = config && config.duration; + } + + if (!keyframes || !duration) { + return; + } + + var stateToRestore = getStateToRestore(el); + each(ELEMENT_ANIMATABLE_PROPS, function (targetPropName) { + if (targetPropName && !el[targetPropName]) { + return; + } + + var animator; + var endFrameIsSet = false; // Sort keyframes by percent. + + keyframes.sort(function (a, b) { + return a.percent - b.percent; + }); + each(keyframes, function (kf) { + // Stop current animation. + var animators = el.animators; + var kfValues = targetPropName ? kf[targetPropName] : kf; + + if ("development" !== 'production') { + if (kf.percent >= 1) { + endFrameIsSet = true; + } + } + + if (!kfValues) { + return; + } + + var propKeys = keys(kfValues); + + if (!targetPropName) { + // PENDING performance? + propKeys = filter(propKeys, function (key) { + return indexOf(KEYFRAME_EXCLUDE_KEYS, key) < 0; + }); + } + + if (!propKeys.length) { + return; + } + + if (!animator) { + animator = el.animate(targetPropName, animationOpts.loop, true); + animator.scope = 'keyframe'; + } + + for (var i = 0; i < animators.length; i++) { + // Stop all other animation that is not keyframe. + if (animators[i] !== animator && animators[i].targetName === animator.targetName) { + animators[i].stopTracks(propKeys); + } + } + + targetPropName && (stateToRestore[targetPropName] = stateToRestore[targetPropName] || {}); + var savedTarget = targetPropName ? stateToRestore[targetPropName] : stateToRestore; + each(propKeys, function (key) { + // Save original value. + savedTarget[key] = ((targetPropName ? el[targetPropName] : el) || {})[key]; + }); + animator.whenWithKeys(duration * kf.percent, kfValues, propKeys, kf.easing); + }); + + if (!animator) { + return; + } + + if ("development" !== 'production') { + if (!endFrameIsSet) { + warn('End frame with percent: 1 is missing in the keyframeAnimation.', true); + } + } + + animator.delay(animationOpts.delay || 0).duration(duration).start(animationOpts.easing); + }); + } + + var EMPHASIS = 'emphasis'; + var NORMAL = 'normal'; + var BLUR = 'blur'; + var SELECT = 'select'; + var STATES = [NORMAL, EMPHASIS, BLUR, SELECT]; + var PATH_ITEM_STYLE = { + normal: ['itemStyle'], + emphasis: [EMPHASIS, 'itemStyle'], + blur: [BLUR, 'itemStyle'], + select: [SELECT, 'itemStyle'] + }; + var PATH_LABEL = { + normal: ['label'], + emphasis: [EMPHASIS, 'label'], + blur: [BLUR, 'label'], + select: [SELECT, 'label'] + }; + var DEFAULT_TRANSITION = ['x', 'y']; // Use prefix to avoid index to be the same as el.name, + // which will cause weird update animation. + + var GROUP_DIFF_PREFIX = 'e\0\0'; + var attachedTxInfoTmp = { + normal: {}, + emphasis: {}, + blur: {}, + select: {} + }; + /** + * To reduce total package size of each coordinate systems, the modules `prepareCustom` + * of each coordinate systems are not required by each coordinate systems directly, but + * required by the module `custom`. + * + * prepareInfoForCustomSeries {Function}: optional + * @return {Object} {coordSys: {...}, api: { + * coord: function (data, clamp) {}, // return point in global. + * size: function (dataSize, dataItem) {} // return size of each axis in coordSys. + * }} + */ + + var prepareCustoms = { + cartesian2d: cartesianPrepareCustom, + geo: geoPrepareCustom, + singleAxis: singlePrepareCustom, + polar: polarPrepareCustom, + calendar: calendarPrepareCustom + }; + + function isPath$1(el) { + return el instanceof Path; + } + + function isDisplayable(el) { + return el instanceof Displayable; + } + + function copyElement(sourceEl, targetEl) { + targetEl.copyTransform(sourceEl); + + if (isDisplayable(targetEl) && isDisplayable(sourceEl)) { + targetEl.setStyle(sourceEl.style); + targetEl.z = sourceEl.z; + targetEl.z2 = sourceEl.z2; + targetEl.zlevel = sourceEl.zlevel; + targetEl.invisible = sourceEl.invisible; + targetEl.ignore = sourceEl.ignore; + + if (isPath$1(targetEl) && isPath$1(sourceEl)) { + targetEl.setShape(sourceEl.shape); + } + } + } + + var CustomChartView = + /** @class */ + function (_super) { + __extends(CustomChartView, _super); + + function CustomChartView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = CustomChartView.type; + return _this; + } + + CustomChartView.prototype.render = function (customSeries, ecModel, api, payload) { + // Clear previously rendered progressive elements. + this._progressiveEls = null; + var oldData = this._data; + var data = customSeries.getData(); + var group = this.group; + var renderItem = makeRenderItem(customSeries, data, ecModel, api); + + if (!oldData) { + // Previous render is incremental render or first render. + // Needs remove the incremental rendered elements. + group.removeAll(); + } + + data.diff(oldData).add(function (newIdx) { + createOrUpdateItem(api, null, newIdx, renderItem(newIdx, payload), customSeries, group, data); + }).remove(function (oldIdx) { + var el = oldData.getItemGraphicEl(oldIdx); + applyLeaveTransition(el, customInnerStore(el).option, customSeries); + }).update(function (newIdx, oldIdx) { + var oldEl = oldData.getItemGraphicEl(oldIdx); + createOrUpdateItem(api, oldEl, newIdx, renderItem(newIdx, payload), customSeries, group, data); + }).execute(); // Do clipping + + var clipPath = customSeries.get('clip', true) ? createClipPath(customSeries.coordinateSystem, false, customSeries) : null; + + if (clipPath) { + group.setClipPath(clipPath); + } else { + group.removeClipPath(); + } + + this._data = data; + }; + + CustomChartView.prototype.incrementalPrepareRender = function (customSeries, ecModel, api) { + this.group.removeAll(); + this._data = null; + }; + + CustomChartView.prototype.incrementalRender = function (params, customSeries, ecModel, api, payload) { + var data = customSeries.getData(); + var renderItem = makeRenderItem(customSeries, data, ecModel, api); + var progressiveEls = this._progressiveEls = []; + + function setIncrementalAndHoverLayer(el) { + if (!el.isGroup) { + el.incremental = true; + el.ensureState('emphasis').hoverLayer = true; + } + } + + for (var idx = params.start; idx < params.end; idx++) { + var el = createOrUpdateItem(null, null, idx, renderItem(idx, payload), customSeries, this.group, data); + + if (el) { + el.traverse(setIncrementalAndHoverLayer); + progressiveEls.push(el); + } + } + }; + + CustomChartView.prototype.eachRendered = function (cb) { + traverseElements(this._progressiveEls || this.group, cb); + }; + + CustomChartView.prototype.filterForExposedEvent = function (eventType, query, targetEl, packedEvent) { + var elementName = query.element; + + if (elementName == null || targetEl.name === elementName) { + return true; + } // Enable to give a name on a group made by `renderItem`, and listen + // events that triggerd by its descendents. + + + while ((targetEl = targetEl.__hostTarget || targetEl.parent) && targetEl !== this.group) { + if (targetEl.name === elementName) { + return true; + } + } + + return false; + }; + + CustomChartView.type = 'custom'; + return CustomChartView; + }(ChartView); + + function createEl(elOption) { + var graphicType = elOption.type; + var el; // Those graphic elements are not shapes. They should not be + // overwritten by users, so do them first. + + if (graphicType === 'path') { + var shape = elOption.shape; // Using pathRect brings convenience to users sacle svg path. + + var pathRect = shape.width != null && shape.height != null ? { + x: shape.x || 0, + y: shape.y || 0, + width: shape.width, + height: shape.height + } : null; + var pathData = getPathData(shape); // Path is also used for icon, so layout 'center' by default. + + el = makePath(pathData, null, pathRect, shape.layout || 'center'); + customInnerStore(el).customPathData = pathData; + } else if (graphicType === 'image') { + el = new ZRImage({}); + customInnerStore(el).customImagePath = elOption.style.image; + } else if (graphicType === 'text') { + el = new ZRText({}); // customInnerStore(el).customText = (elOption.style as TextStyleProps).text; + } else if (graphicType === 'group') { + el = new Group(); + } else if (graphicType === 'compoundPath') { + throw new Error('"compoundPath" is not supported yet.'); + } else { + var Clz = getShapeClass(graphicType); + + if (!Clz) { + var errMsg = ''; + + if ("development" !== 'production') { + errMsg = 'graphic type "' + graphicType + '" can not be found.'; + } + + throwError(errMsg); + } + + el = new Clz(); + } + + customInnerStore(el).customGraphicType = graphicType; + el.name = elOption.name; // Compat ec4: the default z2 lift is 1. If changing the number, + // some cases probably be broken: hierarchy layout along z, like circle packing, + // where emphasis only intending to modify color/border rather than lift z2. + + el.z2EmphasisLift = 1; + el.z2SelectLift = 1; + return el; + } + + function updateElNormal( // Can be null/undefined + api, el, dataIndex, elOption, attachedTxInfo, seriesModel, isInit) { + // Stop and restore before update any other attributes. + stopPreviousKeyframeAnimationAndRestore(el); + var txCfgOpt = attachedTxInfo && attachedTxInfo.normal.cfg; + + if (txCfgOpt) { + // PENDING: whether use user object directly rather than clone? + // TODO:5.0 textConfig transition animation? + el.setTextConfig(txCfgOpt); + } // Default transition ['x', 'y'] + + + if (elOption && elOption.transition == null) { + elOption.transition = DEFAULT_TRANSITION; + } // Do some normalization on style. + + + var styleOpt = elOption && elOption.style; + + if (styleOpt) { + if (el.type === 'text') { + var textOptionStyle = styleOpt; // Compatible with ec4: if `textFill` or `textStroke` exists use them. + + hasOwn(textOptionStyle, 'textFill') && (textOptionStyle.fill = textOptionStyle.textFill); + hasOwn(textOptionStyle, 'textStroke') && (textOptionStyle.stroke = textOptionStyle.textStroke); + } + + var decalPattern = void 0; + var decalObj = isPath$1(el) ? styleOpt.decal : null; + + if (api && decalObj) { + decalObj.dirty = true; + decalPattern = createOrUpdatePatternFromDecal(decalObj, api); + } // Always overwrite in case user specify this prop. + + + styleOpt.__decalPattern = decalPattern; + } + + if (isDisplayable(el)) { + if (styleOpt) { + var decalPattern = styleOpt.__decalPattern; + + if (decalPattern) { + styleOpt.decal = decalPattern; + } + } + } + + applyUpdateTransition(el, elOption, seriesModel, { + dataIndex: dataIndex, + isInit: isInit, + clearStyle: true + }); + applyKeyframeAnimation(el, elOption.keyframeAnimation, seriesModel); + } + + function updateElOnState(state, el, elStateOpt, styleOpt, attachedTxInfo) { + var elDisplayable = el.isGroup ? null : el; + var txCfgOpt = attachedTxInfo && attachedTxInfo[state].cfg; // PENDING:5.0 support customize scale change and transition animation? + + if (elDisplayable) { + // By default support auto lift color when hover whether `emphasis` specified. + var stateObj = elDisplayable.ensureState(state); + + if (styleOpt === false) { + var existingEmphasisState = elDisplayable.getState(state); + + if (existingEmphasisState) { + existingEmphasisState.style = null; + } + } else { + // style is needed to enable defaut emphasis. + stateObj.style = styleOpt || null; + } // If `elOption.styleEmphasis` or `elOption.emphasis.style` is `false`, + // remove hover style. + // If `elOption.textConfig` or `elOption.emphasis.textConfig` is null/undefined, it does not + // make sense. So for simplicity, we do not ditinguish `hasOwnProperty` and null/undefined. + + + if (txCfgOpt) { + stateObj.textConfig = txCfgOpt; + } + + setDefaultStateProxy(elDisplayable); + } + } + + function updateZ$1(el, elOption, seriesModel) { + // Group not support textContent and not support z yet. + if (el.isGroup) { + return; + } + + var elDisplayable = el; + var currentZ = seriesModel.currentZ; + var currentZLevel = seriesModel.currentZLevel; // Always erase. + + elDisplayable.z = currentZ; + elDisplayable.zlevel = currentZLevel; // z2 must not be null/undefined, otherwise sort error may occur. + + var optZ2 = elOption.z2; + optZ2 != null && (elDisplayable.z2 = optZ2 || 0); + + for (var i = 0; i < STATES.length; i++) { + updateZForEachState(elDisplayable, elOption, STATES[i]); + } + } + + function updateZForEachState(elDisplayable, elOption, state) { + var isNormal = state === NORMAL; + var elStateOpt = isNormal ? elOption : retrieveStateOption(elOption, state); + var optZ2 = elStateOpt ? elStateOpt.z2 : null; + var stateObj; + + if (optZ2 != null) { + // Do not `ensureState` until required. + stateObj = isNormal ? elDisplayable : elDisplayable.ensureState(state); + stateObj.z2 = optZ2 || 0; + } + } + + function makeRenderItem(customSeries, data, ecModel, api) { + var renderItem = customSeries.get('renderItem'); + var coordSys = customSeries.coordinateSystem; + var prepareResult = {}; + + if (coordSys) { + if ("development" !== 'production') { + assert(renderItem, 'series.render is required.'); + assert(coordSys.prepareCustoms || prepareCustoms[coordSys.type], 'This coordSys does not support custom series.'); + } // `coordSys.prepareCustoms` is used for external coord sys like bmap. + + + prepareResult = coordSys.prepareCustoms ? coordSys.prepareCustoms(coordSys) : prepareCustoms[coordSys.type](coordSys); + } + + var userAPI = defaults({ + getWidth: api.getWidth, + getHeight: api.getHeight, + getZr: api.getZr, + getDevicePixelRatio: api.getDevicePixelRatio, + value: value, + style: style, + ordinalRawValue: ordinalRawValue, + styleEmphasis: styleEmphasis, + visual: visual, + barLayout: barLayout, + currentSeriesIndices: currentSeriesIndices, + font: font + }, prepareResult.api || {}); + var userParams = { + // The life cycle of context: current round of rendering. + // The global life cycle is probably not necessary, because + // user can store global status by themselves. + context: {}, + seriesId: customSeries.id, + seriesName: customSeries.name, + seriesIndex: customSeries.seriesIndex, + coordSys: prepareResult.coordSys, + dataInsideLength: data.count(), + encode: wrapEncodeDef(customSeries.getData()) + }; // If someday intending to refactor them to a class, should consider do not + // break change: currently these attribute member are encapsulated in a closure + // so that do not need to force user to call these method with a scope. + // Do not support call `api` asynchronously without dataIndexInside input. + + var currDataIndexInside; + var currItemModel; + var currItemStyleModels = {}; + var currLabelModels = {}; + var seriesItemStyleModels = {}; + var seriesLabelModels = {}; + + for (var i = 0; i < STATES.length; i++) { + var stateName = STATES[i]; + seriesItemStyleModels[stateName] = customSeries.getModel(PATH_ITEM_STYLE[stateName]); + seriesLabelModels[stateName] = customSeries.getModel(PATH_LABEL[stateName]); + } + + function getItemModel(dataIndexInside) { + return dataIndexInside === currDataIndexInside ? currItemModel || (currItemModel = data.getItemModel(dataIndexInside)) : data.getItemModel(dataIndexInside); + } + + function getItemStyleModel(dataIndexInside, state) { + return !data.hasItemOption ? seriesItemStyleModels[state] : dataIndexInside === currDataIndexInside ? currItemStyleModels[state] || (currItemStyleModels[state] = getItemModel(dataIndexInside).getModel(PATH_ITEM_STYLE[state])) : getItemModel(dataIndexInside).getModel(PATH_ITEM_STYLE[state]); + } + + function getLabelModel(dataIndexInside, state) { + return !data.hasItemOption ? seriesLabelModels[state] : dataIndexInside === currDataIndexInside ? currLabelModels[state] || (currLabelModels[state] = getItemModel(dataIndexInside).getModel(PATH_LABEL[state])) : getItemModel(dataIndexInside).getModel(PATH_LABEL[state]); + } + + return function (dataIndexInside, payload) { + currDataIndexInside = dataIndexInside; + currItemModel = null; + currItemStyleModels = {}; + currLabelModels = {}; + return renderItem && renderItem(defaults({ + dataIndexInside: dataIndexInside, + dataIndex: data.getRawIndex(dataIndexInside), + // Can be used for optimization when zoom or roam. + actionType: payload ? payload.type : null + }, userParams), userAPI); + }; + /** + * @public + * @param dim by default 0. + * @param dataIndexInside by default `currDataIndexInside`. + */ + + function value(dim, dataIndexInside) { + dataIndexInside == null && (dataIndexInside = currDataIndexInside); + return data.getStore().get(data.getDimensionIndex(dim || 0), dataIndexInside); + } + /** + * @public + * @param dim by default 0. + * @param dataIndexInside by default `currDataIndexInside`. + */ + + + function ordinalRawValue(dim, dataIndexInside) { + dataIndexInside == null && (dataIndexInside = currDataIndexInside); + dim = dim || 0; + var dimInfo = data.getDimensionInfo(dim); + + if (!dimInfo) { + var dimIndex = data.getDimensionIndex(dim); + return dimIndex >= 0 ? data.getStore().get(dimIndex, dataIndexInside) : undefined; + } + + var val = data.get(dimInfo.name, dataIndexInside); + var ordinalMeta = dimInfo && dimInfo.ordinalMeta; + return ordinalMeta ? ordinalMeta.categories[val] : val; + } + /** + * @deprecated The orgininal intention of `api.style` is enable to set itemStyle + * like other series. But it not necessary and not easy to give a strict definition + * of what it return. And since echarts5 it needs to be make compat work. So + * deprecates it since echarts5. + * + * By default, `visual` is applied to style (to support visualMap). + * `visual.color` is applied at `fill`. If user want apply visual.color on `stroke`, + * it can be implemented as: + * `api.style({stroke: api.visual('color'), fill: null})`; + * + * [Compat]: since ec5, RectText has been separated from its hosts el. + * so `api.style()` will only return the style from `itemStyle` but not handle `label` + * any more. But `series.label` config is never published in doc. + * We still compat it in `api.style()`. But not encourage to use it and will still not + * to pulish it to doc. + * @public + * @param dataIndexInside by default `currDataIndexInside`. + */ + + + function style(userProps, dataIndexInside) { + if ("development" !== 'production') { + warnDeprecated('api.style', 'Please write literal style directly instead.'); + } + + dataIndexInside == null && (dataIndexInside = currDataIndexInside); + var style = data.getItemVisual(dataIndexInside, 'style'); + var visualColor = style && style.fill; + var opacity = style && style.opacity; + var itemStyle = getItemStyleModel(dataIndexInside, NORMAL).getItemStyle(); + visualColor != null && (itemStyle.fill = visualColor); + opacity != null && (itemStyle.opacity = opacity); + var opt = { + inheritColor: isString(visualColor) ? visualColor : '#000' + }; + var labelModel = getLabelModel(dataIndexInside, NORMAL); // Now that the feture of "auto adjust text fill/stroke" has been migrated to zrender + // since ec5, we should set `isAttached` as `false` here and make compat in + // `convertToEC4StyleForCustomSerise`. + + var textStyle = createTextStyle(labelModel, null, opt, false, true); + textStyle.text = labelModel.getShallow('show') ? retrieve2(customSeries.getFormattedLabel(dataIndexInside, NORMAL), getDefaultLabel(data, dataIndexInside)) : null; + var textConfig = createTextConfig(labelModel, opt, false); + preFetchFromExtra(userProps, itemStyle); + itemStyle = convertToEC4StyleForCustomSerise(itemStyle, textStyle, textConfig); + userProps && applyUserPropsAfter(itemStyle, userProps); + itemStyle.legacy = true; + return itemStyle; + } + /** + * @deprecated The reason see `api.style()` + * @public + * @param dataIndexInside by default `currDataIndexInside`. + */ + + + function styleEmphasis(userProps, dataIndexInside) { + if ("development" !== 'production') { + warnDeprecated('api.styleEmphasis', 'Please write literal style directly instead.'); + } + + dataIndexInside == null && (dataIndexInside = currDataIndexInside); + var itemStyle = getItemStyleModel(dataIndexInside, EMPHASIS).getItemStyle(); + var labelModel = getLabelModel(dataIndexInside, EMPHASIS); + var textStyle = createTextStyle(labelModel, null, null, true, true); + textStyle.text = labelModel.getShallow('show') ? retrieve3(customSeries.getFormattedLabel(dataIndexInside, EMPHASIS), customSeries.getFormattedLabel(dataIndexInside, NORMAL), getDefaultLabel(data, dataIndexInside)) : null; + var textConfig = createTextConfig(labelModel, null, true); + preFetchFromExtra(userProps, itemStyle); + itemStyle = convertToEC4StyleForCustomSerise(itemStyle, textStyle, textConfig); + userProps && applyUserPropsAfter(itemStyle, userProps); + itemStyle.legacy = true; + return itemStyle; + } + + function applyUserPropsAfter(itemStyle, extra) { + for (var key in extra) { + if (hasOwn(extra, key)) { + itemStyle[key] = extra[key]; + } + } + } + + function preFetchFromExtra(extra, itemStyle) { + // A trick to retrieve those props firstly, which are used to + // apply auto inside fill/stroke in `convertToEC4StyleForCustomSerise`. + // (It's not reasonable but only for a degree of compat) + if (extra) { + extra.textFill && (itemStyle.textFill = extra.textFill); + extra.textPosition && (itemStyle.textPosition = extra.textPosition); + } + } + /** + * @public + * @param dataIndexInside by default `currDataIndexInside`. + */ + + + function visual(visualType, dataIndexInside) { + dataIndexInside == null && (dataIndexInside = currDataIndexInside); + + if (hasOwn(STYLE_VISUAL_TYPE, visualType)) { + var style_1 = data.getItemVisual(dataIndexInside, 'style'); + return style_1 ? style_1[STYLE_VISUAL_TYPE[visualType]] : null; + } // Only support these visuals. Other visual might be inner tricky + // for performance (like `style`), do not expose to users. + + + if (hasOwn(NON_STYLE_VISUAL_PROPS, visualType)) { + return data.getItemVisual(dataIndexInside, visualType); + } + } + /** + * @public + * @return If not support, return undefined. + */ + + + function barLayout(opt) { + if (coordSys.type === 'cartesian2d') { + var baseAxis = coordSys.getBaseAxis(); + return getLayoutOnAxis(defaults({ + axis: baseAxis + }, opt)); + } + } + /** + * @public + */ + + + function currentSeriesIndices() { + return ecModel.getCurrentSeriesIndices(); + } + /** + * @public + * @return font string + */ + + + function font(opt) { + return getFont(opt, ecModel); + } + } + + function wrapEncodeDef(data) { + var encodeDef = {}; + each(data.dimensions, function (dimName) { + var dimInfo = data.getDimensionInfo(dimName); + + if (!dimInfo.isExtraCoord) { + var coordDim = dimInfo.coordDim; + var dataDims = encodeDef[coordDim] = encodeDef[coordDim] || []; + dataDims[dimInfo.coordDimIndex] = data.getDimensionIndex(dimName); + } + }); + return encodeDef; + } + + function createOrUpdateItem(api, existsEl, dataIndex, elOption, seriesModel, group, data) { + // [Rule] + // If `renderItem` returns `null`/`undefined`/`false`, remove the previous el if existing. + // (It seems that violate the "merge" principle, but most of users probably intuitively + // regard "return;" as "show nothing element whatever", so make a exception to meet the + // most cases.) + // The rule or "merge" see [STRATEGY_MERGE]. + // If `elOption` is `null`/`undefined`/`false` (when `renderItem` returns nothing). + if (!elOption) { + group.remove(existsEl); + return; + } + + var el = doCreateOrUpdateEl(api, existsEl, dataIndex, elOption, seriesModel, group); + el && data.setItemGraphicEl(dataIndex, el); + el && toggleHoverEmphasis(el, elOption.focus, elOption.blurScope, elOption.emphasisDisabled); + return el; + } + + function doCreateOrUpdateEl(api, existsEl, dataIndex, elOption, seriesModel, group) { + if ("development" !== 'production') { + assert(elOption, 'should not have an null/undefined element setting'); + } + + var toBeReplacedIdx = -1; + var oldEl = existsEl; + + if (existsEl && doesElNeedRecreate(existsEl, elOption, seriesModel) // || ( + // // PENDING: even in one-to-one mapping case, if el is marked as morph, + // // do not sure whether the el will be mapped to another el with different + // // hierarchy in Group tree. So always recreate el rather than reuse the el. + // morphHelper && morphHelper.isOneToOneFrom(el) + // ) + ) { + // Should keep at the original index, otherwise "merge by index" will be incorrect. + toBeReplacedIdx = indexOf(group.childrenRef(), existsEl); + existsEl = null; + } + + var isInit = !existsEl; + var el = existsEl; + + if (!el) { + el = createEl(elOption); + + if (oldEl) { + copyElement(oldEl, el); + } + } else { + // FIMXE:NEXT unified clearState? + // If in some case the performance issue arised, consider + // do not clearState but update cached normal state directly. + el.clearStates(); + } // Need to set morph: false explictly to disable automatically morphing. + + + if (elOption.morph === false) { + el.disableMorphing = true; + } else if (el.disableMorphing) { + el.disableMorphing = false; + } + + attachedTxInfoTmp.normal.cfg = attachedTxInfoTmp.normal.conOpt = attachedTxInfoTmp.emphasis.cfg = attachedTxInfoTmp.emphasis.conOpt = attachedTxInfoTmp.blur.cfg = attachedTxInfoTmp.blur.conOpt = attachedTxInfoTmp.select.cfg = attachedTxInfoTmp.select.conOpt = null; + attachedTxInfoTmp.isLegacy = false; + doCreateOrUpdateAttachedTx(el, dataIndex, elOption, seriesModel, isInit, attachedTxInfoTmp); + doCreateOrUpdateClipPath(el, dataIndex, elOption, seriesModel, isInit); + updateElNormal(api, el, dataIndex, elOption, attachedTxInfoTmp, seriesModel, isInit); // `elOption.info` enables user to mount some info on + // elements and use them in event handlers. + // Update them only when user specified, otherwise, remain. + + hasOwn(elOption, 'info') && (customInnerStore(el).info = elOption.info); + + for (var i = 0; i < STATES.length; i++) { + var stateName = STATES[i]; + + if (stateName !== NORMAL) { + var otherStateOpt = retrieveStateOption(elOption, stateName); + var otherStyleOpt = retrieveStyleOptionOnState(elOption, otherStateOpt, stateName); + updateElOnState(stateName, el, otherStateOpt, otherStyleOpt, attachedTxInfoTmp); + } + } + + updateZ$1(el, elOption, seriesModel); + + if (elOption.type === 'group') { + mergeChildren(api, el, dataIndex, elOption, seriesModel); + } + + if (toBeReplacedIdx >= 0) { + group.replaceAt(el, toBeReplacedIdx); + } else { + group.add(el); + } + + return el; + } // `el` must not be null/undefined. + + + function doesElNeedRecreate(el, elOption, seriesModel) { + var elInner = customInnerStore(el); + var elOptionType = elOption.type; + var elOptionShape = elOption.shape; + var elOptionStyle = elOption.style; + return (// Always create new if universal transition is enabled. + // Because we do transition after render. It needs to know what old element is. Replacement will loose it. + seriesModel.isUniversalTransitionEnabled() // If `elOptionType` is `null`, follow the merge principle. + || elOptionType != null && elOptionType !== elInner.customGraphicType || elOptionType === 'path' && hasOwnPathData(elOptionShape) && getPathData(elOptionShape) !== elInner.customPathData || elOptionType === 'image' && hasOwn(elOptionStyle, 'image') && elOptionStyle.image !== elInner.customImagePath // // FIXME test and remove this restriction? + // || (elOptionType === 'text' + // && hasOwn(elOptionStyle, 'text') + // && (elOptionStyle as TextStyleProps).text !== elInner.customText + // ) + + ); + } + + function doCreateOrUpdateClipPath(el, dataIndex, elOption, seriesModel, isInit) { + // Based on the "merge" principle, if no clipPath provided, + // do nothing. The exists clip will be totally removed only if + // `el.clipPath` is `false`. Otherwise it will be merged/replaced. + var clipPathOpt = elOption.clipPath; + + if (clipPathOpt === false) { + if (el && el.getClipPath()) { + el.removeClipPath(); + } + } else if (clipPathOpt) { + var clipPath = el.getClipPath(); + + if (clipPath && doesElNeedRecreate(clipPath, clipPathOpt, seriesModel)) { + clipPath = null; + } + + if (!clipPath) { + clipPath = createEl(clipPathOpt); + + if ("development" !== 'production') { + assert(isPath$1(clipPath), 'Only any type of `path` can be used in `clipPath`, rather than ' + clipPath.type + '.'); + } + + el.setClipPath(clipPath); + } + + updateElNormal(null, clipPath, dataIndex, clipPathOpt, null, seriesModel, isInit); + } // If not define `clipPath` in option, do nothing unnecessary. + + } + + function doCreateOrUpdateAttachedTx(el, dataIndex, elOption, seriesModel, isInit, attachedTxInfo) { + // group do not support textContent temporarily untill necessary. + if (el.isGroup) { + return; + } // Normal must be called before emphasis, for `isLegacy` detection. + + + processTxInfo(elOption, null, attachedTxInfo); + processTxInfo(elOption, EMPHASIS, attachedTxInfo); // If `elOption.textConfig` or `elOption.textContent` is null/undefined, it does not make sence. + // So for simplicity, if "elOption hasOwnProperty of them but be null/undefined", we do not + // trade them as set to null to el. + // Especially: + // `elOption.textContent: false` means remove textContent. + // `elOption.textContent.emphasis.style: false` means remove the style from emphasis state. + + var txConOptNormal = attachedTxInfo.normal.conOpt; + var txConOptEmphasis = attachedTxInfo.emphasis.conOpt; + var txConOptBlur = attachedTxInfo.blur.conOpt; + var txConOptSelect = attachedTxInfo.select.conOpt; + + if (txConOptNormal != null || txConOptEmphasis != null || txConOptSelect != null || txConOptBlur != null) { + var textContent = el.getTextContent(); + + if (txConOptNormal === false) { + textContent && el.removeTextContent(); + } else { + txConOptNormal = attachedTxInfo.normal.conOpt = txConOptNormal || { + type: 'text' + }; + + if (!textContent) { + textContent = createEl(txConOptNormal); + el.setTextContent(textContent); + } else { + // If in some case the performance issue arised, consider + // do not clearState but update cached normal state directly. + textContent.clearStates(); + } + + updateElNormal(null, textContent, dataIndex, txConOptNormal, null, seriesModel, isInit); + var txConStlOptNormal = txConOptNormal && txConOptNormal.style; + + for (var i = 0; i < STATES.length; i++) { + var stateName = STATES[i]; + + if (stateName !== NORMAL) { + var txConOptOtherState = attachedTxInfo[stateName].conOpt; + updateElOnState(stateName, textContent, txConOptOtherState, retrieveStyleOptionOnState(txConOptNormal, txConOptOtherState, stateName), null); + } + } + + txConStlOptNormal ? textContent.dirty() : textContent.markRedraw(); + } + } + } + + function processTxInfo(elOption, state, attachedTxInfo) { + var stateOpt = !state ? elOption : retrieveStateOption(elOption, state); + var styleOpt = !state ? elOption.style : retrieveStyleOptionOnState(elOption, stateOpt, EMPHASIS); + var elType = elOption.type; + var txCfg = stateOpt ? stateOpt.textConfig : null; + var txConOptNormal = elOption.textContent; + var txConOpt = !txConOptNormal ? null : !state ? txConOptNormal : retrieveStateOption(txConOptNormal, state); + + if (styleOpt && ( // Because emphasis style has little info to detect legacy, + // if normal is legacy, emphasis is trade as legacy. + attachedTxInfo.isLegacy || isEC4CompatibleStyle(styleOpt, elType, !!txCfg, !!txConOpt))) { + attachedTxInfo.isLegacy = true; + var convertResult = convertFromEC4CompatibleStyle(styleOpt, elType, !state); // Explicitly specified `textConfig` and `textContent` has higher priority than + // the ones generated by legacy style. Otherwise if users use them and `api.style` + // at the same time, they not both work and hardly to known why. + + if (!txCfg && convertResult.textConfig) { + txCfg = convertResult.textConfig; + } + + if (!txConOpt && convertResult.textContent) { + txConOpt = convertResult.textContent; + } + } + + if (!state && txConOpt) { + var txConOptNormal_1 = txConOpt; // `textContent: {type: 'text'}`, the "type" is easy to be missing. So we tolerate it. + + !txConOptNormal_1.type && (txConOptNormal_1.type = 'text'); + + if ("development" !== 'production') { + // Do not tolerate incorret type for forward compat. + assert(txConOptNormal_1.type === 'text', 'textContent.type must be "text"'); + } + } + + var info = !state ? attachedTxInfo.normal : attachedTxInfo[state]; + info.cfg = txCfg; + info.conOpt = txConOpt; + } + + function retrieveStateOption(elOption, state) { + return !state ? elOption : elOption ? elOption[state] : null; + } + + function retrieveStyleOptionOnState(stateOptionNormal, stateOption, state) { + var style = stateOption && stateOption.style; + + if (style == null && state === EMPHASIS && stateOptionNormal) { + style = stateOptionNormal.styleEmphasis; + } + + return style; + } // Usage: + // (1) By default, `elOption.$mergeChildren` is `'byIndex'`, which indicates that + // the existing children will not be removed, and enables the feature that + // update some of the props of some of the children simply by construct + // the returned children of `renderItem` like: + // `var children = group.children = []; children[3] = {opacity: 0.5};` + // (2) If `elOption.$mergeChildren` is `'byName'`, add/update/remove children + // by child.name. But that might be lower performance. + // (3) If `elOption.$mergeChildren` is `false`, the existing children will be + // replaced totally. + // (4) If `!elOption.children`, following the "merge" principle, nothing will happen. + // + // For implementation simpleness, do not provide a direct way to remove sinlge + // child (otherwise the total indicies of the children array have to be modified). + // User can remove a single child by set its `ignore` as `true`. + + + function mergeChildren(api, el, dataIndex, elOption, seriesModel) { + var newChildren = elOption.children; + var newLen = newChildren ? newChildren.length : 0; + var mergeChildren = elOption.$mergeChildren; // `diffChildrenByName` has been deprecated. + + var byName = mergeChildren === 'byName' || elOption.diffChildrenByName; + var notMerge = mergeChildren === false; // For better performance on roam update, only enter if necessary. + + if (!newLen && !byName && !notMerge) { + return; + } + + if (byName) { + diffGroupChildren({ + api: api, + oldChildren: el.children() || [], + newChildren: newChildren || [], + dataIndex: dataIndex, + seriesModel: seriesModel, + group: el + }); + return; + } + + notMerge && el.removeAll(); // Mapping children of a group simply by index, which + // might be better performance. + + var index = 0; + + for (; index < newLen; index++) { + newChildren[index] && doCreateOrUpdateEl(api, el.childAt(index), dataIndex, newChildren[index], seriesModel, el); + } + + for (var i = el.childCount() - 1; i >= index; i--) { + // Do not supprot leave elements that are not mentioned in the latest + // `renderItem` return. Otherwise users may not have a clear and simple + // concept that how to contorl all of the elements. + var child = el.childAt(i); + applyLeaveTransition(child, customInnerStore(el).option, seriesModel); + } + } + + function diffGroupChildren(context) { + new DataDiffer(context.oldChildren, context.newChildren, getKey, getKey, context).add(processAddUpdate).update(processAddUpdate).remove(processRemove).execute(); + } + + function getKey(item, idx) { + var name = item && item.name; + return name != null ? name : GROUP_DIFF_PREFIX + idx; + } + + function processAddUpdate(newIndex, oldIndex) { + var context = this.context; + var childOption = newIndex != null ? context.newChildren[newIndex] : null; + var child = oldIndex != null ? context.oldChildren[oldIndex] : null; + doCreateOrUpdateEl(context.api, child, context.dataIndex, childOption, context.seriesModel, context.group); + } + + function processRemove(oldIndex) { + var context = this.context; + var child = context.oldChildren[oldIndex]; + applyLeaveTransition(child, customInnerStore(child).option, context.seriesModel); + } + /** + * @return SVG Path data. + */ + + + function getPathData(shape) { + // "d" follows the SVG convention. + return shape && (shape.pathData || shape.d); + } + + function hasOwnPathData(shape) { + return shape && (hasOwn(shape, 'pathData') || hasOwn(shape, 'd')); + } + + function install$r(registers) { + registers.registerChartView(CustomChartView); + registers.registerSeriesModel(CustomSeriesModel); + } + + var inner$a = makeInner(); + var clone$3 = clone; + var bind$1 = bind; + /** + * Base axis pointer class in 2D. + */ + + var BaseAxisPointer = + /** @class */ + function () { + function BaseAxisPointer() { + this._dragging = false; + /** + * In px, arbitrary value. Do not set too small, + * no animation is ok for most cases. + */ + + this.animationThreshold = 15; + } + /** + * @implement + */ + + + BaseAxisPointer.prototype.render = function (axisModel, axisPointerModel, api, forceRender) { + var value = axisPointerModel.get('value'); + var status = axisPointerModel.get('status'); // Bind them to `this`, not in closure, otherwise they will not + // be replaced when user calling setOption in not merge mode. + + this._axisModel = axisModel; + this._axisPointerModel = axisPointerModel; + this._api = api; // Optimize: `render` will be called repeatly during mouse move. + // So it is power consuming if performing `render` each time, + // especially on mobile device. + + if (!forceRender && this._lastValue === value && this._lastStatus === status) { + return; + } + + this._lastValue = value; + this._lastStatus = status; + var group = this._group; + var handle = this._handle; + + if (!status || status === 'hide') { + // Do not clear here, for animation better. + group && group.hide(); + handle && handle.hide(); + return; + } + + group && group.show(); + handle && handle.show(); // Otherwise status is 'show' + + var elOption = {}; + this.makeElOption(elOption, value, axisModel, axisPointerModel, api); // Enable change axis pointer type. + + var graphicKey = elOption.graphicKey; + + if (graphicKey !== this._lastGraphicKey) { + this.clear(api); + } + + this._lastGraphicKey = graphicKey; + var moveAnimation = this._moveAnimation = this.determineAnimation(axisModel, axisPointerModel); + + if (!group) { + group = this._group = new Group(); + this.createPointerEl(group, elOption, axisModel, axisPointerModel); + this.createLabelEl(group, elOption, axisModel, axisPointerModel); + api.getZr().add(group); + } else { + var doUpdateProps = curry(updateProps$1, axisPointerModel, moveAnimation); + this.updatePointerEl(group, elOption, doUpdateProps); + this.updateLabelEl(group, elOption, doUpdateProps, axisPointerModel); + } + + updateMandatoryProps(group, axisPointerModel, true); + + this._renderHandle(value); + }; + /** + * @implement + */ + + + BaseAxisPointer.prototype.remove = function (api) { + this.clear(api); + }; + /** + * @implement + */ + + + BaseAxisPointer.prototype.dispose = function (api) { + this.clear(api); + }; + /** + * @protected + */ + + + BaseAxisPointer.prototype.determineAnimation = function (axisModel, axisPointerModel) { + var animation = axisPointerModel.get('animation'); + var axis = axisModel.axis; + var isCategoryAxis = axis.type === 'category'; + var useSnap = axisPointerModel.get('snap'); // Value axis without snap always do not snap. + + if (!useSnap && !isCategoryAxis) { + return false; + } + + if (animation === 'auto' || animation == null) { + var animationThreshold = this.animationThreshold; + + if (isCategoryAxis && axis.getBandWidth() > animationThreshold) { + return true; + } // It is important to auto animation when snap used. Consider if there is + // a dataZoom, animation will be disabled when too many points exist, while + // it will be enabled for better visual effect when little points exist. + + + if (useSnap) { + var seriesDataCount = getAxisInfo(axisModel).seriesDataCount; + var axisExtent = axis.getExtent(); // Approximate band width + + return Math.abs(axisExtent[0] - axisExtent[1]) / seriesDataCount > animationThreshold; + } + + return false; + } + + return animation === true; + }; + /** + * add {pointer, label, graphicKey} to elOption + * @protected + */ + + + BaseAxisPointer.prototype.makeElOption = function (elOption, value, axisModel, axisPointerModel, api) {// Shoule be implemenented by sub-class. + }; + /** + * @protected + */ + + + BaseAxisPointer.prototype.createPointerEl = function (group, elOption, axisModel, axisPointerModel) { + var pointerOption = elOption.pointer; + + if (pointerOption) { + var pointerEl = inner$a(group).pointerEl = new graphic[pointerOption.type](clone$3(elOption.pointer)); + group.add(pointerEl); + } + }; + /** + * @protected + */ + + + BaseAxisPointer.prototype.createLabelEl = function (group, elOption, axisModel, axisPointerModel) { + if (elOption.label) { + var labelEl = inner$a(group).labelEl = new ZRText(clone$3(elOption.label)); + group.add(labelEl); + updateLabelShowHide(labelEl, axisPointerModel); + } + }; + /** + * @protected + */ + + + BaseAxisPointer.prototype.updatePointerEl = function (group, elOption, updateProps) { + var pointerEl = inner$a(group).pointerEl; + + if (pointerEl && elOption.pointer) { + pointerEl.setStyle(elOption.pointer.style); + updateProps(pointerEl, { + shape: elOption.pointer.shape + }); + } + }; + /** + * @protected + */ + + + BaseAxisPointer.prototype.updateLabelEl = function (group, elOption, updateProps, axisPointerModel) { + var labelEl = inner$a(group).labelEl; + + if (labelEl) { + labelEl.setStyle(elOption.label.style); + updateProps(labelEl, { + // Consider text length change in vertical axis, animation should + // be used on shape, otherwise the effect will be weird. + // TODOTODO + // shape: elOption.label.shape, + x: elOption.label.x, + y: elOption.label.y + }); + updateLabelShowHide(labelEl, axisPointerModel); + } + }; + /** + * @private + */ + + + BaseAxisPointer.prototype._renderHandle = function (value) { + if (this._dragging || !this.updateHandleTransform) { + return; + } + + var axisPointerModel = this._axisPointerModel; + + var zr = this._api.getZr(); + + var handle = this._handle; + var handleModel = axisPointerModel.getModel('handle'); + var status = axisPointerModel.get('status'); + + if (!handleModel.get('show') || !status || status === 'hide') { + handle && zr.remove(handle); + this._handle = null; + return; + } + + var isInit; + + if (!this._handle) { + isInit = true; + handle = this._handle = createIcon(handleModel.get('icon'), { + cursor: 'move', + draggable: true, + onmousemove: function (e) { + // Fot mobile devicem, prevent screen slider on the button. + stop(e.event); + }, + onmousedown: bind$1(this._onHandleDragMove, this, 0, 0), + drift: bind$1(this._onHandleDragMove, this), + ondragend: bind$1(this._onHandleDragEnd, this) + }); + zr.add(handle); + } + + updateMandatoryProps(handle, axisPointerModel, false); // update style + + handle.setStyle(handleModel.getItemStyle(null, ['color', 'borderColor', 'borderWidth', 'opacity', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'])); // update position + + var handleSize = handleModel.get('size'); + + if (!isArray(handleSize)) { + handleSize = [handleSize, handleSize]; + } + + handle.scaleX = handleSize[0] / 2; + handle.scaleY = handleSize[1] / 2; + createOrUpdate(this, '_doDispatchAxisPointer', handleModel.get('throttle') || 0, 'fixRate'); + + this._moveHandleToValue(value, isInit); + }; + + BaseAxisPointer.prototype._moveHandleToValue = function (value, isInit) { + updateProps$1(this._axisPointerModel, !isInit && this._moveAnimation, this._handle, getHandleTransProps(this.getHandleTransform(value, this._axisModel, this._axisPointerModel))); + }; + + BaseAxisPointer.prototype._onHandleDragMove = function (dx, dy) { + var handle = this._handle; + + if (!handle) { + return; + } + + this._dragging = true; // Persistent for throttle. + + var trans = this.updateHandleTransform(getHandleTransProps(handle), [dx, dy], this._axisModel, this._axisPointerModel); + this._payloadInfo = trans; + handle.stopAnimation(); + handle.attr(getHandleTransProps(trans)); + inner$a(handle).lastProp = null; + + this._doDispatchAxisPointer(); + }; + /** + * Throttled method. + */ + + + BaseAxisPointer.prototype._doDispatchAxisPointer = function () { + var handle = this._handle; + + if (!handle) { + return; + } + + var payloadInfo = this._payloadInfo; + var axisModel = this._axisModel; + + this._api.dispatchAction({ + type: 'updateAxisPointer', + x: payloadInfo.cursorPoint[0], + y: payloadInfo.cursorPoint[1], + tooltipOption: payloadInfo.tooltipOption, + axesInfo: [{ + axisDim: axisModel.axis.dim, + axisIndex: axisModel.componentIndex + }] + }); + }; + + BaseAxisPointer.prototype._onHandleDragEnd = function () { + this._dragging = false; + var handle = this._handle; + + if (!handle) { + return; + } + + var value = this._axisPointerModel.get('value'); // Consider snap or categroy axis, handle may be not consistent with + // axisPointer. So move handle to align the exact value position when + // drag ended. + + + this._moveHandleToValue(value); // For the effect: tooltip will be shown when finger holding on handle + // button, and will be hidden after finger left handle button. + + + this._api.dispatchAction({ + type: 'hideTip' + }); + }; + /** + * @private + */ + + + BaseAxisPointer.prototype.clear = function (api) { + this._lastValue = null; + this._lastStatus = null; + var zr = api.getZr(); + var group = this._group; + var handle = this._handle; + + if (zr && group) { + this._lastGraphicKey = null; + group && zr.remove(group); + handle && zr.remove(handle); + this._group = null; + this._handle = null; + this._payloadInfo = null; + } + + clear(this, '_doDispatchAxisPointer'); + }; + /** + * @protected + */ + + + BaseAxisPointer.prototype.doClear = function () {// Implemented by sub-class if necessary. + }; + + BaseAxisPointer.prototype.buildLabel = function (xy, wh, xDimIndex) { + xDimIndex = xDimIndex || 0; + return { + x: xy[xDimIndex], + y: xy[1 - xDimIndex], + width: wh[xDimIndex], + height: wh[1 - xDimIndex] + }; + }; + + return BaseAxisPointer; + }(); + + function updateProps$1(animationModel, moveAnimation, el, props) { + // Animation optimize. + if (!propsEqual(inner$a(el).lastProp, props)) { + inner$a(el).lastProp = props; + moveAnimation ? updateProps(el, props, animationModel) : (el.stopAnimation(), el.attr(props)); + } + } + + function propsEqual(lastProps, newProps) { + if (isObject(lastProps) && isObject(newProps)) { + var equals_1 = true; + each(newProps, function (item, key) { + equals_1 = equals_1 && propsEqual(lastProps[key], item); + }); + return !!equals_1; + } else { + return lastProps === newProps; + } + } + + function updateLabelShowHide(labelEl, axisPointerModel) { + labelEl[axisPointerModel.get(['label', 'show']) ? 'show' : 'hide'](); + } + + function getHandleTransProps(trans) { + return { + x: trans.x || 0, + y: trans.y || 0, + rotation: trans.rotation || 0 + }; + } + + function updateMandatoryProps(group, axisPointerModel, silent) { + var z = axisPointerModel.get('z'); + var zlevel = axisPointerModel.get('zlevel'); + group && group.traverse(function (el) { + if (el.type !== 'group') { + z != null && (el.z = z); + zlevel != null && (el.zlevel = zlevel); + el.silent = silent; + } + }); + } + + function buildElStyle(axisPointerModel) { + var axisPointerType = axisPointerModel.get('type'); + var styleModel = axisPointerModel.getModel(axisPointerType + 'Style'); + var style; + + if (axisPointerType === 'line') { + style = styleModel.getLineStyle(); + style.fill = null; + } else if (axisPointerType === 'shadow') { + style = styleModel.getAreaStyle(); + style.stroke = null; + } + + return style; + } + /** + * @param {Function} labelPos {align, verticalAlign, position} + */ + + function buildLabelElOption(elOption, axisModel, axisPointerModel, api, labelPos) { + var value = axisPointerModel.get('value'); + var text = getValueLabel(value, axisModel.axis, axisModel.ecModel, axisPointerModel.get('seriesDataIndices'), { + precision: axisPointerModel.get(['label', 'precision']), + formatter: axisPointerModel.get(['label', 'formatter']) + }); + var labelModel = axisPointerModel.getModel('label'); + var paddings = normalizeCssArray$1(labelModel.get('padding') || 0); + var font = labelModel.getFont(); + var textRect = getBoundingRect(text, font); + var position = labelPos.position; + var width = textRect.width + paddings[1] + paddings[3]; + var height = textRect.height + paddings[0] + paddings[2]; // Adjust by align. + + var align = labelPos.align; + align === 'right' && (position[0] -= width); + align === 'center' && (position[0] -= width / 2); + var verticalAlign = labelPos.verticalAlign; + verticalAlign === 'bottom' && (position[1] -= height); + verticalAlign === 'middle' && (position[1] -= height / 2); // Not overflow ec container + + confineInContainer(position, width, height, api); + var bgColor = labelModel.get('backgroundColor'); + + if (!bgColor || bgColor === 'auto') { + bgColor = axisModel.get(['axisLine', 'lineStyle', 'color']); + } + + elOption.label = { + // shape: {x: 0, y: 0, width: width, height: height, r: labelModel.get('borderRadius')}, + x: position[0], + y: position[1], + style: createTextStyle(labelModel, { + text: text, + font: font, + fill: labelModel.getTextColor(), + padding: paddings, + backgroundColor: bgColor + }), + // Lable should be over axisPointer. + z2: 10 + }; + } // Do not overflow ec container + + function confineInContainer(position, width, height, api) { + var viewWidth = api.getWidth(); + var viewHeight = api.getHeight(); + position[0] = Math.min(position[0] + width, viewWidth) - width; + position[1] = Math.min(position[1] + height, viewHeight) - height; + position[0] = Math.max(position[0], 0); + position[1] = Math.max(position[1], 0); + } + + function getValueLabel(value, axis, ecModel, seriesDataIndices, opt) { + value = axis.scale.parse(value); + var text = axis.scale.getLabel({ + value: value + }, { + // If `precision` is set, width can be fixed (like '12.00500'), which + // helps to debounce when when moving label. + precision: opt.precision + }); + var formatter = opt.formatter; + + if (formatter) { + var params_1 = { + value: getAxisRawValue(axis, { + value: value + }), + axisDimension: axis.dim, + axisIndex: axis.index, + seriesData: [] + }; + each(seriesDataIndices, function (idxItem) { + var series = ecModel.getSeriesByIndex(idxItem.seriesIndex); + var dataIndex = idxItem.dataIndexInside; + var dataParams = series && series.getDataParams(dataIndex); + dataParams && params_1.seriesData.push(dataParams); + }); + + if (isString(formatter)) { + text = formatter.replace('{value}', text); + } else if (isFunction(formatter)) { + text = formatter(params_1); + } + } + + return text; + } + function getTransformedPosition(axis, value, layoutInfo) { + var transform = create$1(); + rotate(transform, transform, layoutInfo.rotation); + translate(transform, transform, layoutInfo.position); + return applyTransform$1([axis.dataToCoord(value), (layoutInfo.labelOffset || 0) + (layoutInfo.labelDirection || 1) * (layoutInfo.labelMargin || 0)], transform); + } + function buildCartesianSingleLabelElOption(value, elOption, layoutInfo, axisModel, axisPointerModel, api) { + // @ts-ignore + var textLayout = AxisBuilder.innerTextLayout(layoutInfo.rotation, 0, layoutInfo.labelDirection); + layoutInfo.labelMargin = axisPointerModel.get(['label', 'margin']); + buildLabelElOption(elOption, axisModel, axisPointerModel, api, { + position: getTransformedPosition(axisModel.axis, value, layoutInfo), + align: textLayout.textAlign, + verticalAlign: textLayout.textVerticalAlign + }); + } + function makeLineShape(p1, p2, xDimIndex) { + xDimIndex = xDimIndex || 0; + return { + x1: p1[xDimIndex], + y1: p1[1 - xDimIndex], + x2: p2[xDimIndex], + y2: p2[1 - xDimIndex] + }; + } + function makeRectShape(xy, wh, xDimIndex) { + xDimIndex = xDimIndex || 0; + return { + x: xy[xDimIndex], + y: xy[1 - xDimIndex], + width: wh[xDimIndex], + height: wh[1 - xDimIndex] + }; + } + function makeSectorShape(cx, cy, r0, r, startAngle, endAngle) { + return { + cx: cx, + cy: cy, + r0: r0, + r: r, + startAngle: startAngle, + endAngle: endAngle, + clockwise: true + }; + } + + var CartesianAxisPointer = + /** @class */ + function (_super) { + __extends(CartesianAxisPointer, _super); + + function CartesianAxisPointer() { + return _super !== null && _super.apply(this, arguments) || this; + } + /** + * @override + */ + + + CartesianAxisPointer.prototype.makeElOption = function (elOption, value, axisModel, axisPointerModel, api) { + var axis = axisModel.axis; + var grid = axis.grid; + var axisPointerType = axisPointerModel.get('type'); + var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent(); + var pixelValue = axis.toGlobalCoord(axis.dataToCoord(value, true)); + + if (axisPointerType && axisPointerType !== 'none') { + var elStyle = buildElStyle(axisPointerModel); + var pointerOption = pointerShapeBuilder[axisPointerType](axis, pixelValue, otherExtent); + pointerOption.style = elStyle; + elOption.graphicKey = pointerOption.type; + elOption.pointer = pointerOption; + } + + var layoutInfo = layout$1(grid.model, axisModel); + buildCartesianSingleLabelElOption( // @ts-ignore + value, elOption, layoutInfo, axisModel, axisPointerModel, api); + }; + /** + * @override + */ + + + CartesianAxisPointer.prototype.getHandleTransform = function (value, axisModel, axisPointerModel) { + var layoutInfo = layout$1(axisModel.axis.grid.model, axisModel, { + labelInside: false + }); // @ts-ignore + + layoutInfo.labelMargin = axisPointerModel.get(['handle', 'margin']); + var pos = getTransformedPosition(axisModel.axis, value, layoutInfo); + return { + x: pos[0], + y: pos[1], + rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0) + }; + }; + /** + * @override + */ + + + CartesianAxisPointer.prototype.updateHandleTransform = function (transform, delta, axisModel, axisPointerModel) { + var axis = axisModel.axis; + var grid = axis.grid; + var axisExtent = axis.getGlobalExtent(true); + var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent(); + var dimIndex = axis.dim === 'x' ? 0 : 1; + var currPosition = [transform.x, transform.y]; + currPosition[dimIndex] += delta[dimIndex]; + currPosition[dimIndex] = Math.min(axisExtent[1], currPosition[dimIndex]); + currPosition[dimIndex] = Math.max(axisExtent[0], currPosition[dimIndex]); + var cursorOtherValue = (otherExtent[1] + otherExtent[0]) / 2; + var cursorPoint = [cursorOtherValue, cursorOtherValue]; + cursorPoint[dimIndex] = currPosition[dimIndex]; // Make tooltip do not overlap axisPointer and in the middle of the grid. + + var tooltipOptions = [{ + verticalAlign: 'middle' + }, { + align: 'center' + }]; + return { + x: currPosition[0], + y: currPosition[1], + rotation: transform.rotation, + cursorPoint: cursorPoint, + tooltipOption: tooltipOptions[dimIndex] + }; + }; + + return CartesianAxisPointer; + }(BaseAxisPointer); + + function getCartesian(grid, axis) { + var opt = {}; + opt[axis.dim + 'AxisIndex'] = axis.index; + return grid.getCartesian(opt); + } + + var pointerShapeBuilder = { + line: function (axis, pixelValue, otherExtent) { + var targetShape = makeLineShape([pixelValue, otherExtent[0]], [pixelValue, otherExtent[1]], getAxisDimIndex(axis)); + return { + type: 'Line', + subPixelOptimize: true, + shape: targetShape + }; + }, + shadow: function (axis, pixelValue, otherExtent) { + var bandWidth = Math.max(1, axis.getBandWidth()); + var span = otherExtent[1] - otherExtent[0]; + return { + type: 'Rect', + shape: makeRectShape([pixelValue - bandWidth / 2, otherExtent[0]], [bandWidth, span], getAxisDimIndex(axis)) + }; + } + }; + + function getAxisDimIndex(axis) { + return axis.dim === 'x' ? 0 : 1; + } + + var AxisPointerModel = + /** @class */ + function (_super) { + __extends(AxisPointerModel, _super); + + function AxisPointerModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = AxisPointerModel.type; + return _this; + } + + AxisPointerModel.type = 'axisPointer'; + AxisPointerModel.defaultOption = { + // 'auto' means that show when triggered by tooltip or handle. + show: 'auto', + // zlevel: 0, + z: 50, + type: 'line', + // axispointer triggered by tootip determine snap automatically, + // see `modelHelper`. + snap: false, + triggerTooltip: true, + value: null, + status: null, + link: [], + // Do not set 'auto' here, otherwise global animation: false + // will not effect at this axispointer. + animation: null, + animationDurationUpdate: 200, + lineStyle: { + color: '#B9BEC9', + width: 1, + type: 'dashed' + }, + shadowStyle: { + color: 'rgba(210,219,238,0.2)' + }, + label: { + show: true, + formatter: null, + precision: 'auto', + margin: 3, + color: '#fff', + padding: [5, 7, 5, 7], + backgroundColor: 'auto', + borderColor: null, + borderWidth: 0, + borderRadius: 3 + }, + handle: { + show: false, + // eslint-disable-next-line + icon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z', + size: 45, + // handle margin is from symbol center to axis, which is stable when circular move. + margin: 50, + // color: '#1b8bbd' + // color: '#2f4554' + color: '#333', + shadowBlur: 3, + shadowColor: '#aaa', + shadowOffsetX: 0, + shadowOffsetY: 2, + // For mobile performance + throttle: 40 + } + }; + return AxisPointerModel; + }(ComponentModel); + + var inner$b = makeInner(); + var each$7 = each; + /** + * @param {string} key + * @param {module:echarts/ExtensionAPI} api + * @param {Function} handler + * param: {string} currTrigger + * param: {Array.} point + */ + + function register(key, api, handler) { + if (env.node) { + return; + } + + var zr = api.getZr(); + inner$b(zr).records || (inner$b(zr).records = {}); + initGlobalListeners(zr, api); + var record = inner$b(zr).records[key] || (inner$b(zr).records[key] = {}); + record.handler = handler; + } + + function initGlobalListeners(zr, api) { + if (inner$b(zr).initialized) { + return; + } + + inner$b(zr).initialized = true; + useHandler('click', curry(doEnter, 'click')); + useHandler('mousemove', curry(doEnter, 'mousemove')); // useHandler('mouseout', onLeave); + + useHandler('globalout', onLeave); + + function useHandler(eventType, cb) { + zr.on(eventType, function (e) { + var dis = makeDispatchAction(api); + each$7(inner$b(zr).records, function (record) { + record && cb(record, e, dis.dispatchAction); + }); + dispatchTooltipFinally(dis.pendings, api); + }); + } + } + + function dispatchTooltipFinally(pendings, api) { + var showLen = pendings.showTip.length; + var hideLen = pendings.hideTip.length; + var actuallyPayload; + + if (showLen) { + actuallyPayload = pendings.showTip[showLen - 1]; + } else if (hideLen) { + actuallyPayload = pendings.hideTip[hideLen - 1]; + } + + if (actuallyPayload) { + actuallyPayload.dispatchAction = null; + api.dispatchAction(actuallyPayload); + } + } + + function onLeave(record, e, dispatchAction) { + record.handler('leave', null, dispatchAction); + } + + function doEnter(currTrigger, record, e, dispatchAction) { + record.handler(currTrigger, e, dispatchAction); + } + + function makeDispatchAction(api) { + var pendings = { + showTip: [], + hideTip: [] + }; // FIXME + // better approach? + // 'showTip' and 'hideTip' can be triggered by axisPointer and tooltip, + // which may be conflict, (axisPointer call showTip but tooltip call hideTip); + // So we have to add "final stage" to merge those dispatched actions. + + var dispatchAction = function (payload) { + var pendingList = pendings[payload.type]; + + if (pendingList) { + pendingList.push(payload); + } else { + payload.dispatchAction = dispatchAction; + api.dispatchAction(payload); + } + }; + + return { + dispatchAction: dispatchAction, + pendings: pendings + }; + } + + function unregister(key, api) { + if (env.node) { + return; + } + + var zr = api.getZr(); + var record = (inner$b(zr).records || {})[key]; + + if (record) { + inner$b(zr).records[key] = null; + } + } + + var AxisPointerView = + /** @class */ + function (_super) { + __extends(AxisPointerView, _super); + + function AxisPointerView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = AxisPointerView.type; + return _this; + } + + AxisPointerView.prototype.render = function (globalAxisPointerModel, ecModel, api) { + var globalTooltipModel = ecModel.getComponent('tooltip'); + var triggerOn = globalAxisPointerModel.get('triggerOn') || globalTooltipModel && globalTooltipModel.get('triggerOn') || 'mousemove|click'; // Register global listener in AxisPointerView to enable + // AxisPointerView to be independent to Tooltip. + + register('axisPointer', api, function (currTrigger, e, dispatchAction) { + // If 'none', it is not controlled by mouse totally. + if (triggerOn !== 'none' && (currTrigger === 'leave' || triggerOn.indexOf(currTrigger) >= 0)) { + dispatchAction({ + type: 'updateAxisPointer', + currTrigger: currTrigger, + x: e && e.offsetX, + y: e && e.offsetY + }); + } + }); + }; + + AxisPointerView.prototype.remove = function (ecModel, api) { + unregister('axisPointer', api); + }; + + AxisPointerView.prototype.dispose = function (ecModel, api) { + unregister('axisPointer', api); + }; + + AxisPointerView.type = 'axisPointer'; + return AxisPointerView; + }(ComponentView); + + /** + * @param finder contains {seriesIndex, dataIndex, dataIndexInside} + * @param ecModel + * @return {point: [x, y], el: ...} point Will not be null. + */ + + function findPointFromSeries(finder, ecModel) { + var point = []; + var seriesIndex = finder.seriesIndex; + var seriesModel; + + if (seriesIndex == null || !(seriesModel = ecModel.getSeriesByIndex(seriesIndex))) { + return { + point: [] + }; + } + + var data = seriesModel.getData(); + var dataIndex = queryDataIndex(data, finder); + + if (dataIndex == null || dataIndex < 0 || isArray(dataIndex)) { + return { + point: [] + }; + } + + var el = data.getItemGraphicEl(dataIndex); + var coordSys = seriesModel.coordinateSystem; + + if (seriesModel.getTooltipPosition) { + point = seriesModel.getTooltipPosition(dataIndex) || []; + } else if (coordSys && coordSys.dataToPoint) { + if (finder.isStacked) { + var baseAxis = coordSys.getBaseAxis(); + var valueAxis = coordSys.getOtherAxis(baseAxis); + var valueAxisDim = valueAxis.dim; + var baseAxisDim = baseAxis.dim; + var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0; + var baseDim = data.mapDimension(baseAxisDim); + var stackedData = []; + stackedData[baseDataOffset] = data.get(baseDim, dataIndex); + stackedData[1 - baseDataOffset] = data.get(data.getCalculationInfo('stackResultDimension'), dataIndex); + point = coordSys.dataToPoint(stackedData) || []; + } else { + point = coordSys.dataToPoint(data.getValues(map(coordSys.dimensions, function (dim) { + return data.mapDimension(dim); + }), dataIndex)) || []; + } + } else if (el) { + // Use graphic bounding rect + var rect = el.getBoundingRect().clone(); + rect.applyTransform(el.transform); + point = [rect.x + rect.width / 2, rect.y + rect.height / 2]; + } + + return { + point: point, + el: el + }; + } + + var inner$c = makeInner(); + /** + * Basic logic: check all axis, if they do not demand show/highlight, + * then hide/downplay them. + * + * @return content of event obj for echarts.connect. + */ + + function axisTrigger(payload, ecModel, api) { + var currTrigger = payload.currTrigger; + var point = [payload.x, payload.y]; + var finder = payload; + var dispatchAction = payload.dispatchAction || bind(api.dispatchAction, api); + var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo; // Pending + // See #6121. But we are not able to reproduce it yet. + + if (!coordSysAxesInfo) { + return; + } + + if (illegalPoint(point)) { + // Used in the default behavior of `connection`: use the sample seriesIndex + // and dataIndex. And also used in the tooltipView trigger. + point = findPointFromSeries({ + seriesIndex: finder.seriesIndex, + // Do not use dataIndexInside from other ec instance. + // FIXME: auto detect it? + dataIndex: finder.dataIndex + }, ecModel).point; + } + + var isIllegalPoint = illegalPoint(point); // Axis and value can be specified when calling dispatchAction({type: 'updateAxisPointer'}). + // Notice: In this case, it is difficult to get the `point` (which is necessary to show + // tooltip, so if point is not given, we just use the point found by sample seriesIndex + // and dataIndex. + + var inputAxesInfo = finder.axesInfo; + var axesInfo = coordSysAxesInfo.axesInfo; + var shouldHide = currTrigger === 'leave' || illegalPoint(point); + var outputPayload = {}; + var showValueMap = {}; + var dataByCoordSys = { + list: [], + map: {} + }; + var updaters = { + showPointer: curry(showPointer, showValueMap), + showTooltip: curry(showTooltip, dataByCoordSys) + }; // Process for triggered axes. + + each(coordSysAxesInfo.coordSysMap, function (coordSys, coordSysKey) { + // If a point given, it must be contained by the coordinate system. + var coordSysContainsPoint = isIllegalPoint || coordSys.containPoint(point); + each(coordSysAxesInfo.coordSysAxesInfo[coordSysKey], function (axisInfo, key) { + var axis = axisInfo.axis; + var inputAxisInfo = findInputAxisInfo(inputAxesInfo, axisInfo); // If no inputAxesInfo, no axis is restricted. + + if (!shouldHide && coordSysContainsPoint && (!inputAxesInfo || inputAxisInfo)) { + var val = inputAxisInfo && inputAxisInfo.value; + + if (val == null && !isIllegalPoint) { + val = axis.pointToData(point); + } + + val != null && processOnAxis(axisInfo, val, updaters, false, outputPayload); + } + }); + }); // Process for linked axes. + + var linkTriggers = {}; + each(axesInfo, function (tarAxisInfo, tarKey) { + var linkGroup = tarAxisInfo.linkGroup; // If axis has been triggered in the previous stage, it should not be triggered by link. + + if (linkGroup && !showValueMap[tarKey]) { + each(linkGroup.axesInfo, function (srcAxisInfo, srcKey) { + var srcValItem = showValueMap[srcKey]; // If srcValItem exist, source axis is triggered, so link to target axis. + + if (srcAxisInfo !== tarAxisInfo && srcValItem) { + var val = srcValItem.value; + linkGroup.mapper && (val = tarAxisInfo.axis.scale.parse(linkGroup.mapper(val, makeMapperParam(srcAxisInfo), makeMapperParam(tarAxisInfo)))); + linkTriggers[tarAxisInfo.key] = val; + } + }); + } + }); + each(linkTriggers, function (val, tarKey) { + processOnAxis(axesInfo[tarKey], val, updaters, true, outputPayload); + }); + updateModelActually(showValueMap, axesInfo, outputPayload); + dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction); + dispatchHighDownActually(axesInfo, dispatchAction, api); + return outputPayload; + } + + function processOnAxis(axisInfo, newValue, updaters, noSnap, outputFinder) { + var axis = axisInfo.axis; + + if (axis.scale.isBlank() || !axis.containData(newValue)) { + return; + } + + if (!axisInfo.involveSeries) { + updaters.showPointer(axisInfo, newValue); + return; + } // Heavy calculation. So put it after axis.containData checking. + + + var payloadInfo = buildPayloadsBySeries(newValue, axisInfo); + var payloadBatch = payloadInfo.payloadBatch; + var snapToValue = payloadInfo.snapToValue; // Fill content of event obj for echarts.connect. + // By default use the first involved series data as a sample to connect. + + if (payloadBatch[0] && outputFinder.seriesIndex == null) { + extend(outputFinder, payloadBatch[0]); + } // If no linkSource input, this process is for collecting link + // target, where snap should not be accepted. + + + if (!noSnap && axisInfo.snap) { + if (axis.containData(snapToValue) && snapToValue != null) { + newValue = snapToValue; + } + } + + updaters.showPointer(axisInfo, newValue, payloadBatch); // Tooltip should always be snapToValue, otherwise there will be + // incorrect "axis value ~ series value" mapping displayed in tooltip. + + updaters.showTooltip(axisInfo, payloadInfo, snapToValue); + } + + function buildPayloadsBySeries(value, axisInfo) { + var axis = axisInfo.axis; + var dim = axis.dim; + var snapToValue = value; + var payloadBatch = []; + var minDist = Number.MAX_VALUE; + var minDiff = -1; + each(axisInfo.seriesModels, function (series, idx) { + var dataDim = series.getData().mapDimensionsAll(dim); + var seriesNestestValue; + var dataIndices; + + if (series.getAxisTooltipData) { + var result = series.getAxisTooltipData(dataDim, value, axis); + dataIndices = result.dataIndices; + seriesNestestValue = result.nestestValue; + } else { + dataIndices = series.getData().indicesOfNearest(dataDim[0], value, // Add a threshold to avoid find the wrong dataIndex + // when data length is not same. + // false, + axis.type === 'category' ? 0.5 : null); + + if (!dataIndices.length) { + return; + } + + seriesNestestValue = series.getData().get(dataDim[0], dataIndices[0]); + } + + if (seriesNestestValue == null || !isFinite(seriesNestestValue)) { + return; + } + + var diff = value - seriesNestestValue; + var dist = Math.abs(diff); // Consider category case + + if (dist <= minDist) { + if (dist < minDist || diff >= 0 && minDiff < 0) { + minDist = dist; + minDiff = diff; + snapToValue = seriesNestestValue; + payloadBatch.length = 0; + } + + each(dataIndices, function (dataIndex) { + payloadBatch.push({ + seriesIndex: series.seriesIndex, + dataIndexInside: dataIndex, + dataIndex: series.getData().getRawIndex(dataIndex) + }); + }); + } + }); + return { + payloadBatch: payloadBatch, + snapToValue: snapToValue + }; + } + + function showPointer(showValueMap, axisInfo, value, payloadBatch) { + showValueMap[axisInfo.key] = { + value: value, + payloadBatch: payloadBatch + }; + } + + function showTooltip(dataByCoordSys, axisInfo, payloadInfo, value) { + var payloadBatch = payloadInfo.payloadBatch; + var axis = axisInfo.axis; + var axisModel = axis.model; + var axisPointerModel = axisInfo.axisPointerModel; // If no data, do not create anything in dataByCoordSys, + // whose length will be used to judge whether dispatch action. + + if (!axisInfo.triggerTooltip || !payloadBatch.length) { + return; + } + + var coordSysModel = axisInfo.coordSys.model; + var coordSysKey = makeKey(coordSysModel); + var coordSysItem = dataByCoordSys.map[coordSysKey]; + + if (!coordSysItem) { + coordSysItem = dataByCoordSys.map[coordSysKey] = { + coordSysId: coordSysModel.id, + coordSysIndex: coordSysModel.componentIndex, + coordSysType: coordSysModel.type, + coordSysMainType: coordSysModel.mainType, + dataByAxis: [] + }; + dataByCoordSys.list.push(coordSysItem); + } + + coordSysItem.dataByAxis.push({ + axisDim: axis.dim, + axisIndex: axisModel.componentIndex, + axisType: axisModel.type, + axisId: axisModel.id, + value: value, + // Caustion: viewHelper.getValueLabel is actually on "view stage", which + // depends that all models have been updated. So it should not be performed + // here. Considering axisPointerModel used here is volatile, which is hard + // to be retrieve in TooltipView, we prepare parameters here. + valueLabelOpt: { + precision: axisPointerModel.get(['label', 'precision']), + formatter: axisPointerModel.get(['label', 'formatter']) + }, + seriesDataIndices: payloadBatch.slice() + }); + } + + function updateModelActually(showValueMap, axesInfo, outputPayload) { + var outputAxesInfo = outputPayload.axesInfo = []; // Basic logic: If no 'show' required, 'hide' this axisPointer. + + each(axesInfo, function (axisInfo, key) { + var option = axisInfo.axisPointerModel.option; + var valItem = showValueMap[key]; + + if (valItem) { + !axisInfo.useHandle && (option.status = 'show'); + option.value = valItem.value; // For label formatter param and highlight. + + option.seriesDataIndices = (valItem.payloadBatch || []).slice(); + } // When always show (e.g., handle used), remain + // original value and status. + else { + // If hide, value still need to be set, consider + // click legend to toggle axis blank. + !axisInfo.useHandle && (option.status = 'hide'); + } // If status is 'hide', should be no info in payload. + + + option.status === 'show' && outputAxesInfo.push({ + axisDim: axisInfo.axis.dim, + axisIndex: axisInfo.axis.model.componentIndex, + value: option.value + }); + }); + } + + function dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction) { + // Basic logic: If no showTip required, hideTip will be dispatched. + if (illegalPoint(point) || !dataByCoordSys.list.length) { + dispatchAction({ + type: 'hideTip' + }); + return; + } // In most case only one axis (or event one series is used). It is + // convinient to fetch payload.seriesIndex and payload.dataIndex + // dirtectly. So put the first seriesIndex and dataIndex of the first + // axis on the payload. + + + var sampleItem = ((dataByCoordSys.list[0].dataByAxis[0] || {}).seriesDataIndices || [])[0] || {}; + dispatchAction({ + type: 'showTip', + escapeConnect: true, + x: point[0], + y: point[1], + tooltipOption: payload.tooltipOption, + position: payload.position, + dataIndexInside: sampleItem.dataIndexInside, + dataIndex: sampleItem.dataIndex, + seriesIndex: sampleItem.seriesIndex, + dataByCoordSys: dataByCoordSys.list + }); + } + + function dispatchHighDownActually(axesInfo, dispatchAction, api) { + // FIXME + // highlight status modification shoule be a stage of main process? + // (Consider confilct (e.g., legend and axisPointer) and setOption) + var zr = api.getZr(); + var highDownKey = 'axisPointerLastHighlights'; + var lastHighlights = inner$c(zr)[highDownKey] || {}; + var newHighlights = inner$c(zr)[highDownKey] = {}; // Update highlight/downplay status according to axisPointer model. + // Build hash map and remove duplicate incidentally. + + each(axesInfo, function (axisInfo, key) { + var option = axisInfo.axisPointerModel.option; + option.status === 'show' && each(option.seriesDataIndices, function (batchItem) { + var key = batchItem.seriesIndex + ' | ' + batchItem.dataIndex; + newHighlights[key] = batchItem; + }); + }); // Diff. + + var toHighlight = []; + var toDownplay = []; + each(lastHighlights, function (batchItem, key) { + !newHighlights[key] && toDownplay.push(batchItem); + }); + each(newHighlights, function (batchItem, key) { + !lastHighlights[key] && toHighlight.push(batchItem); + }); + toDownplay.length && api.dispatchAction({ + type: 'downplay', + escapeConnect: true, + // Not blur others when highlight in axisPointer. + notBlur: true, + batch: toDownplay + }); + toHighlight.length && api.dispatchAction({ + type: 'highlight', + escapeConnect: true, + // Not blur others when highlight in axisPointer. + notBlur: true, + batch: toHighlight + }); + } + + function findInputAxisInfo(inputAxesInfo, axisInfo) { + for (var i = 0; i < (inputAxesInfo || []).length; i++) { + var inputAxisInfo = inputAxesInfo[i]; + + if (axisInfo.axis.dim === inputAxisInfo.axisDim && axisInfo.axis.model.componentIndex === inputAxisInfo.axisIndex) { + return inputAxisInfo; + } + } + } + + function makeMapperParam(axisInfo) { + var axisModel = axisInfo.axis.model; + var item = {}; + var dim = item.axisDim = axisInfo.axis.dim; + item.axisIndex = item[dim + 'AxisIndex'] = axisModel.componentIndex; + item.axisName = item[dim + 'AxisName'] = axisModel.name; + item.axisId = item[dim + 'AxisId'] = axisModel.id; + return item; + } + + function illegalPoint(point) { + return !point || point[0] == null || isNaN(point[0]) || point[1] == null || isNaN(point[1]); + } + + function install$s(registers) { + // CartesianAxisPointer is not supposed to be required here. But consider + // echarts.simple.js and online build tooltip, which only require gridSimple, + // CartesianAxisPointer should be able to required somewhere. + AxisView.registerAxisPointerClass('CartesianAxisPointer', CartesianAxisPointer); + registers.registerComponentModel(AxisPointerModel); + registers.registerComponentView(AxisPointerView); + registers.registerPreprocessor(function (option) { + // Always has a global axisPointerModel for default setting. + if (option) { + (!option.axisPointer || option.axisPointer.length === 0) && (option.axisPointer = {}); + var link = option.axisPointer.link; // Normalize to array to avoid object mergin. But if link + // is not set, remain null/undefined, otherwise it will + // override existent link setting. + + if (link && !isArray(link)) { + option.axisPointer.link = [link]; + } + } + }); // This process should proformed after coordinate systems created + // and series data processed. So put it on statistic processing stage. + + registers.registerProcessor(registers.PRIORITY.PROCESSOR.STATISTIC, function (ecModel, api) { + // Build axisPointerModel, mergin tooltip.axisPointer model for each axis. + // allAxesInfo should be updated when setOption performed. + ecModel.getComponent('axisPointer').coordSysAxesInfo = collect(ecModel, api); + }); // Broadcast to all views. + + registers.registerAction({ + type: 'updateAxisPointer', + event: 'updateAxisPointer', + update: ':updateAxisPointer' + }, axisTrigger); + } + + function install$t(registers) { + use(install$5); + use(install$s); + } + + var PolarAxisPointer = + /** @class */ + function (_super) { + __extends(PolarAxisPointer, _super); + + function PolarAxisPointer() { + return _super !== null && _super.apply(this, arguments) || this; + } + /** + * @override + */ + + + PolarAxisPointer.prototype.makeElOption = function (elOption, value, axisModel, axisPointerModel, api) { + var axis = axisModel.axis; + + if (axis.dim === 'angle') { + this.animationThreshold = Math.PI / 18; + } + + var polar = axis.polar; + var otherAxis = polar.getOtherAxis(axis); + var otherExtent = otherAxis.getExtent(); + var coordValue = axis.dataToCoord(value); + var axisPointerType = axisPointerModel.get('type'); + + if (axisPointerType && axisPointerType !== 'none') { + var elStyle = buildElStyle(axisPointerModel); + var pointerOption = pointerShapeBuilder$1[axisPointerType](axis, polar, coordValue, otherExtent); + pointerOption.style = elStyle; + elOption.graphicKey = pointerOption.type; + elOption.pointer = pointerOption; + } + + var labelMargin = axisPointerModel.get(['label', 'margin']); + var labelPos = getLabelPosition(value, axisModel, axisPointerModel, polar, labelMargin); + buildLabelElOption(elOption, axisModel, axisPointerModel, api, labelPos); + }; + + return PolarAxisPointer; + }(BaseAxisPointer); + + function getLabelPosition(value, axisModel, axisPointerModel, polar, labelMargin) { + var axis = axisModel.axis; + var coord = axis.dataToCoord(value); + var axisAngle = polar.getAngleAxis().getExtent()[0]; + axisAngle = axisAngle / 180 * Math.PI; + var radiusExtent = polar.getRadiusAxis().getExtent(); + var position; + var align; + var verticalAlign; + + if (axis.dim === 'radius') { + var transform = create$1(); + rotate(transform, transform, axisAngle); + translate(transform, transform, [polar.cx, polar.cy]); + position = applyTransform$1([coord, -labelMargin], transform); + var labelRotation = axisModel.getModel('axisLabel').get('rotate') || 0; // @ts-ignore + + var labelLayout = AxisBuilder.innerTextLayout(axisAngle, labelRotation * Math.PI / 180, -1); + align = labelLayout.textAlign; + verticalAlign = labelLayout.textVerticalAlign; + } else { + // angle axis + var r = radiusExtent[1]; + position = polar.coordToPoint([r + labelMargin, coord]); + var cx = polar.cx; + var cy = polar.cy; + align = Math.abs(position[0] - cx) / r < 0.3 ? 'center' : position[0] > cx ? 'left' : 'right'; + verticalAlign = Math.abs(position[1] - cy) / r < 0.3 ? 'middle' : position[1] > cy ? 'top' : 'bottom'; + } + + return { + position: position, + align: align, + verticalAlign: verticalAlign + }; + } + + var pointerShapeBuilder$1 = { + line: function (axis, polar, coordValue, otherExtent) { + return axis.dim === 'angle' ? { + type: 'Line', + shape: makeLineShape(polar.coordToPoint([otherExtent[0], coordValue]), polar.coordToPoint([otherExtent[1], coordValue])) + } : { + type: 'Circle', + shape: { + cx: polar.cx, + cy: polar.cy, + r: coordValue + } + }; + }, + shadow: function (axis, polar, coordValue, otherExtent) { + var bandWidth = Math.max(1, axis.getBandWidth()); + var radian = Math.PI / 180; + return axis.dim === 'angle' ? { + type: 'Sector', + shape: makeSectorShape(polar.cx, polar.cy, otherExtent[0], otherExtent[1], // In ECharts y is negative if angle is positive + (-coordValue - bandWidth / 2) * radian, (-coordValue + bandWidth / 2) * radian) + } : { + type: 'Sector', + shape: makeSectorShape(polar.cx, polar.cy, coordValue - bandWidth / 2, coordValue + bandWidth / 2, 0, Math.PI * 2) + }; + } + }; + + var PolarModel = + /** @class */ + function (_super) { + __extends(PolarModel, _super); + + function PolarModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = PolarModel.type; + return _this; + } + + PolarModel.prototype.findAxisModel = function (axisType) { + var foundAxisModel; + var ecModel = this.ecModel; + ecModel.eachComponent(axisType, function (axisModel) { + if (axisModel.getCoordSysModel() === this) { + foundAxisModel = axisModel; + } + }, this); + return foundAxisModel; + }; + + PolarModel.type = 'polar'; + PolarModel.dependencies = ['radiusAxis', 'angleAxis']; + PolarModel.defaultOption = { + // zlevel: 0, + z: 0, + center: ['50%', '50%'], + radius: '80%' + }; + return PolarModel; + }(ComponentModel); + + var PolarAxisModel = + /** @class */ + function (_super) { + __extends(PolarAxisModel, _super); + + function PolarAxisModel() { + return _super !== null && _super.apply(this, arguments) || this; + } + + PolarAxisModel.prototype.getCoordSysModel = function () { + return this.getReferringComponents('polar', SINGLE_REFERRING).models[0]; + }; + + PolarAxisModel.type = 'polarAxis'; + return PolarAxisModel; + }(ComponentModel); + + mixin(PolarAxisModel, AxisModelCommonMixin); + + var AngleAxisModel = + /** @class */ + function (_super) { + __extends(AngleAxisModel, _super); + + function AngleAxisModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = AngleAxisModel.type; + return _this; + } + + AngleAxisModel.type = 'angleAxis'; + return AngleAxisModel; + }(PolarAxisModel); + + var RadiusAxisModel = + /** @class */ + function (_super) { + __extends(RadiusAxisModel, _super); + + function RadiusAxisModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = RadiusAxisModel.type; + return _this; + } + + RadiusAxisModel.type = 'radiusAxis'; + return RadiusAxisModel; + }(PolarAxisModel); + + var RadiusAxis = + /** @class */ + function (_super) { + __extends(RadiusAxis, _super); + + function RadiusAxis(scale, radiusExtent) { + return _super.call(this, 'radius', scale, radiusExtent) || this; + } + + RadiusAxis.prototype.pointToData = function (point, clamp) { + return this.polar.pointToData(point, clamp)[this.dim === 'radius' ? 0 : 1]; + }; + + return RadiusAxis; + }(Axis); + + RadiusAxis.prototype.dataToRadius = Axis.prototype.dataToCoord; + RadiusAxis.prototype.radiusToData = Axis.prototype.coordToData; + + var inner$d = makeInner(); + + var AngleAxis = + /** @class */ + function (_super) { + __extends(AngleAxis, _super); + + function AngleAxis(scale, angleExtent) { + return _super.call(this, 'angle', scale, angleExtent || [0, 360]) || this; + } + + AngleAxis.prototype.pointToData = function (point, clamp) { + return this.polar.pointToData(point, clamp)[this.dim === 'radius' ? 0 : 1]; + }; + /** + * Only be called in category axis. + * Angle axis uses text height to decide interval + * + * @override + * @return {number} Auto interval for cateogry axis tick and label + */ + + + AngleAxis.prototype.calculateCategoryInterval = function () { + var axis = this; + var labelModel = axis.getLabelModel(); + var ordinalScale = axis.scale; + var ordinalExtent = ordinalScale.getExtent(); // Providing this method is for optimization: + // avoid generating a long array by `getTicks` + // in large category data case. + + var tickCount = ordinalScale.count(); + + if (ordinalExtent[1] - ordinalExtent[0] < 1) { + return 0; + } + + var tickValue = ordinalExtent[0]; + var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue); + var unitH = Math.abs(unitSpan); // Not precise, just use height as text width + // and each distance from axis line yet. + + var rect = getBoundingRect(tickValue == null ? '' : tickValue + '', labelModel.getFont(), 'center', 'top'); + var maxH = Math.max(rect.height, 7); + var dh = maxH / unitH; // 0/0 is NaN, 1/0 is Infinity. + + isNaN(dh) && (dh = Infinity); + var interval = Math.max(0, Math.floor(dh)); + var cache = inner$d(axis.model); + var lastAutoInterval = cache.lastAutoInterval; + var lastTickCount = cache.lastTickCount; // Use cache to keep interval stable while moving zoom window, + // otherwise the calculated interval might jitter when the zoom + // window size is close to the interval-changing size. + + if (lastAutoInterval != null && lastTickCount != null && Math.abs(lastAutoInterval - interval) <= 1 && Math.abs(lastTickCount - tickCount) <= 1 // Always choose the bigger one, otherwise the critical + // point is not the same when zooming in or zooming out. + && lastAutoInterval > interval) { + interval = lastAutoInterval; + } // Only update cache if cache not used, otherwise the + // changing of interval is too insensitive. + else { + cache.lastTickCount = tickCount; + cache.lastAutoInterval = interval; + } + + return interval; + }; + + return AngleAxis; + }(Axis); + + AngleAxis.prototype.dataToAngle = Axis.prototype.dataToCoord; + AngleAxis.prototype.angleToData = Axis.prototype.coordToData; + + var polarDimensions = ['radius', 'angle']; + + var Polar = + /** @class */ + function () { + function Polar(name) { + this.dimensions = polarDimensions; + this.type = 'polar'; + /** + * x of polar center + */ + + this.cx = 0; + /** + * y of polar center + */ + + this.cy = 0; + this._radiusAxis = new RadiusAxis(); + this._angleAxis = new AngleAxis(); + this.axisPointerEnabled = true; + this.name = name || ''; + this._radiusAxis.polar = this._angleAxis.polar = this; + } + /** + * If contain coord + */ + + + Polar.prototype.containPoint = function (point) { + var coord = this.pointToCoord(point); + return this._radiusAxis.contain(coord[0]) && this._angleAxis.contain(coord[1]); + }; + /** + * If contain data + */ + + + Polar.prototype.containData = function (data) { + return this._radiusAxis.containData(data[0]) && this._angleAxis.containData(data[1]); + }; + + Polar.prototype.getAxis = function (dim) { + var key = '_' + dim + 'Axis'; + return this[key]; + }; + + Polar.prototype.getAxes = function () { + return [this._radiusAxis, this._angleAxis]; + }; + /** + * Get axes by type of scale + */ + + + Polar.prototype.getAxesByScale = function (scaleType) { + var axes = []; + var angleAxis = this._angleAxis; + var radiusAxis = this._radiusAxis; + angleAxis.scale.type === scaleType && axes.push(angleAxis); + radiusAxis.scale.type === scaleType && axes.push(radiusAxis); + return axes; + }; + + Polar.prototype.getAngleAxis = function () { + return this._angleAxis; + }; + + Polar.prototype.getRadiusAxis = function () { + return this._radiusAxis; + }; + + Polar.prototype.getOtherAxis = function (axis) { + var angleAxis = this._angleAxis; + return axis === angleAxis ? this._radiusAxis : angleAxis; + }; + /** + * Base axis will be used on stacking. + * + */ + + + Polar.prototype.getBaseAxis = function () { + return this.getAxesByScale('ordinal')[0] || this.getAxesByScale('time')[0] || this.getAngleAxis(); + }; + + Polar.prototype.getTooltipAxes = function (dim) { + var baseAxis = dim != null && dim !== 'auto' ? this.getAxis(dim) : this.getBaseAxis(); + return { + baseAxes: [baseAxis], + otherAxes: [this.getOtherAxis(baseAxis)] + }; + }; + /** + * Convert a single data item to (x, y) point. + * Parameter data is an array which the first element is radius and the second is angle + */ + + + Polar.prototype.dataToPoint = function (data, clamp) { + return this.coordToPoint([this._radiusAxis.dataToRadius(data[0], clamp), this._angleAxis.dataToAngle(data[1], clamp)]); + }; + /** + * Convert a (x, y) point to data + */ + + + Polar.prototype.pointToData = function (point, clamp) { + var coord = this.pointToCoord(point); + return [this._radiusAxis.radiusToData(coord[0], clamp), this._angleAxis.angleToData(coord[1], clamp)]; + }; + /** + * Convert a (x, y) point to (radius, angle) coord + */ + + + Polar.prototype.pointToCoord = function (point) { + var dx = point[0] - this.cx; + var dy = point[1] - this.cy; + var angleAxis = this.getAngleAxis(); + var extent = angleAxis.getExtent(); + var minAngle = Math.min(extent[0], extent[1]); + var maxAngle = Math.max(extent[0], extent[1]); // Fix fixed extent in polarCreator + // FIXME + + angleAxis.inverse ? minAngle = maxAngle - 360 : maxAngle = minAngle + 360; + var radius = Math.sqrt(dx * dx + dy * dy); + dx /= radius; + dy /= radius; + var radian = Math.atan2(-dy, dx) / Math.PI * 180; // move to angleExtent + + var dir = radian < minAngle ? 1 : -1; + + while (radian < minAngle || radian > maxAngle) { + radian += dir * 360; + } + + return [radius, radian]; + }; + /** + * Convert a (radius, angle) coord to (x, y) point + */ + + + Polar.prototype.coordToPoint = function (coord) { + var radius = coord[0]; + var radian = coord[1] / 180 * Math.PI; + var x = Math.cos(radian) * radius + this.cx; // Inverse the y + + var y = -Math.sin(radian) * radius + this.cy; + return [x, y]; + }; + /** + * Get ring area of cartesian. + * Area will have a contain function to determine if a point is in the coordinate system. + */ + + + Polar.prototype.getArea = function () { + var angleAxis = this.getAngleAxis(); + var radiusAxis = this.getRadiusAxis(); + var radiusExtent = radiusAxis.getExtent().slice(); + radiusExtent[0] > radiusExtent[1] && radiusExtent.reverse(); + var angleExtent = angleAxis.getExtent(); + var RADIAN = Math.PI / 180; + return { + cx: this.cx, + cy: this.cy, + r0: radiusExtent[0], + r: radiusExtent[1], + startAngle: -angleExtent[0] * RADIAN, + endAngle: -angleExtent[1] * RADIAN, + clockwise: angleAxis.inverse, + contain: function (x, y) { + // It's a ring shape. + // Start angle and end angle don't matter + var dx = x - this.cx; + var dy = y - this.cy; // minus a tiny value 1e-4 to avoid being clipped unexpectedly + + var d2 = dx * dx + dy * dy - 1e-4; + var r = this.r; + var r0 = this.r0; + return d2 <= r * r && d2 >= r0 * r0; + } + }; + }; + + Polar.prototype.convertToPixel = function (ecModel, finder, value) { + var coordSys = getCoordSys$2(finder); + return coordSys === this ? this.dataToPoint(value) : null; + }; + + Polar.prototype.convertFromPixel = function (ecModel, finder, pixel) { + var coordSys = getCoordSys$2(finder); + return coordSys === this ? this.pointToData(pixel) : null; + }; + + return Polar; + }(); + + function getCoordSys$2(finder) { + var seriesModel = finder.seriesModel; + var polarModel = finder.polarModel; + return polarModel && polarModel.coordinateSystem || seriesModel && seriesModel.coordinateSystem; + } + + /** + * Resize method bound to the polar + */ + + function resizePolar(polar, polarModel, api) { + var center = polarModel.get('center'); + var width = api.getWidth(); + var height = api.getHeight(); + polar.cx = parsePercent$1(center[0], width); + polar.cy = parsePercent$1(center[1], height); + var radiusAxis = polar.getRadiusAxis(); + var size = Math.min(width, height) / 2; + var radius = polarModel.get('radius'); + + if (radius == null) { + radius = [0, '100%']; + } else if (!isArray(radius)) { + // r0 = 0 + radius = [0, radius]; + } + + var parsedRadius = [parsePercent$1(radius[0], size), parsePercent$1(radius[1], size)]; + radiusAxis.inverse ? radiusAxis.setExtent(parsedRadius[1], parsedRadius[0]) : radiusAxis.setExtent(parsedRadius[0], parsedRadius[1]); + } + /** + * Update polar + */ + + + function updatePolarScale(ecModel, api) { + var polar = this; + var angleAxis = polar.getAngleAxis(); + var radiusAxis = polar.getRadiusAxis(); // Reset scale + + angleAxis.scale.setExtent(Infinity, -Infinity); + radiusAxis.scale.setExtent(Infinity, -Infinity); + ecModel.eachSeries(function (seriesModel) { + if (seriesModel.coordinateSystem === polar) { + var data_1 = seriesModel.getData(); + each(getDataDimensionsOnAxis(data_1, 'radius'), function (dim) { + radiusAxis.scale.unionExtentFromData(data_1, dim); + }); + each(getDataDimensionsOnAxis(data_1, 'angle'), function (dim) { + angleAxis.scale.unionExtentFromData(data_1, dim); + }); + } + }); + niceScaleExtent(angleAxis.scale, angleAxis.model); + niceScaleExtent(radiusAxis.scale, radiusAxis.model); // Fix extent of category angle axis + + if (angleAxis.type === 'category' && !angleAxis.onBand) { + var extent = angleAxis.getExtent(); + var diff = 360 / angleAxis.scale.count(); + angleAxis.inverse ? extent[1] += diff : extent[1] -= diff; + angleAxis.setExtent(extent[0], extent[1]); + } + } + + function isAngleAxisModel(axisModel) { + return axisModel.mainType === 'angleAxis'; + } + /** + * Set common axis properties + */ + + + function setAxis(axis, axisModel) { + axis.type = axisModel.get('type'); + axis.scale = createScaleByModel(axisModel); + axis.onBand = axisModel.get('boundaryGap') && axis.type === 'category'; + axis.inverse = axisModel.get('inverse'); + + if (isAngleAxisModel(axisModel)) { + axis.inverse = axis.inverse !== axisModel.get('clockwise'); + var startAngle = axisModel.get('startAngle'); + axis.setExtent(startAngle, startAngle + (axis.inverse ? -360 : 360)); + } // Inject axis instance + + + axisModel.axis = axis; + axis.model = axisModel; + } + + var polarCreator = { + dimensions: polarDimensions, + create: function (ecModel, api) { + var polarList = []; + ecModel.eachComponent('polar', function (polarModel, idx) { + var polar = new Polar(idx + ''); // Inject resize and update method + + polar.update = updatePolarScale; + var radiusAxis = polar.getRadiusAxis(); + var angleAxis = polar.getAngleAxis(); + var radiusAxisModel = polarModel.findAxisModel('radiusAxis'); + var angleAxisModel = polarModel.findAxisModel('angleAxis'); + setAxis(radiusAxis, radiusAxisModel); + setAxis(angleAxis, angleAxisModel); + resizePolar(polar, polarModel, api); + polarList.push(polar); + polarModel.coordinateSystem = polar; + polar.model = polarModel; + }); // Inject coordinateSystem to series + + ecModel.eachSeries(function (seriesModel) { + if (seriesModel.get('coordinateSystem') === 'polar') { + var polarModel = seriesModel.getReferringComponents('polar', SINGLE_REFERRING).models[0]; + + if ("development" !== 'production') { + if (!polarModel) { + throw new Error('Polar "' + retrieve(seriesModel.get('polarIndex'), seriesModel.get('polarId'), 0) + '" not found'); + } + } + + seriesModel.coordinateSystem = polarModel.coordinateSystem; + } + }); + return polarList; + } + }; + + var elementList$1 = ['axisLine', 'axisLabel', 'axisTick', 'minorTick', 'splitLine', 'minorSplitLine', 'splitArea']; + + function getAxisLineShape(polar, rExtent, angle) { + rExtent[1] > rExtent[0] && (rExtent = rExtent.slice().reverse()); + var start = polar.coordToPoint([rExtent[0], angle]); + var end = polar.coordToPoint([rExtent[1], angle]); + return { + x1: start[0], + y1: start[1], + x2: end[0], + y2: end[1] + }; + } + + function getRadiusIdx(polar) { + var radiusAxis = polar.getRadiusAxis(); + return radiusAxis.inverse ? 0 : 1; + } // Remove the last tick which will overlap the first tick + + + function fixAngleOverlap(list) { + var firstItem = list[0]; + var lastItem = list[list.length - 1]; + + if (firstItem && lastItem && Math.abs(Math.abs(firstItem.coord - lastItem.coord) - 360) < 1e-4) { + list.pop(); + } + } + + var AngleAxisView = + /** @class */ + function (_super) { + __extends(AngleAxisView, _super); + + function AngleAxisView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = AngleAxisView.type; + _this.axisPointerClass = 'PolarAxisPointer'; + return _this; + } + + AngleAxisView.prototype.render = function (angleAxisModel, ecModel) { + this.group.removeAll(); + + if (!angleAxisModel.get('show')) { + return; + } + + var angleAxis = angleAxisModel.axis; + var polar = angleAxis.polar; + var radiusExtent = polar.getRadiusAxis().getExtent(); + var ticksAngles = angleAxis.getTicksCoords(); + var minorTickAngles = angleAxis.getMinorTicksCoords(); + var labels = map(angleAxis.getViewLabels(), function (labelItem) { + labelItem = clone(labelItem); + var scale = angleAxis.scale; + var tickValue = scale.type === 'ordinal' ? scale.getRawOrdinalNumber(labelItem.tickValue) : labelItem.tickValue; + labelItem.coord = angleAxis.dataToCoord(tickValue); + return labelItem; + }); + fixAngleOverlap(labels); + fixAngleOverlap(ticksAngles); + each(elementList$1, function (name) { + if (angleAxisModel.get([name, 'show']) && (!angleAxis.scale.isBlank() || name === 'axisLine')) { + angelAxisElementsBuilders[name](this.group, angleAxisModel, polar, ticksAngles, minorTickAngles, radiusExtent, labels); + } + }, this); + }; + + AngleAxisView.type = 'angleAxis'; + return AngleAxisView; + }(AxisView); + + var angelAxisElementsBuilders = { + axisLine: function (group, angleAxisModel, polar, ticksAngles, minorTickAngles, radiusExtent) { + var lineStyleModel = angleAxisModel.getModel(['axisLine', 'lineStyle']); // extent id of the axis radius (r0 and r) + + var rId = getRadiusIdx(polar); + var r0Id = rId ? 0 : 1; + var shape; + + if (radiusExtent[r0Id] === 0) { + shape = new Circle({ + shape: { + cx: polar.cx, + cy: polar.cy, + r: radiusExtent[rId] + }, + style: lineStyleModel.getLineStyle(), + z2: 1, + silent: true + }); + } else { + shape = new Ring({ + shape: { + cx: polar.cx, + cy: polar.cy, + r: radiusExtent[rId], + r0: radiusExtent[r0Id] + }, + style: lineStyleModel.getLineStyle(), + z2: 1, + silent: true + }); + } + + shape.style.fill = null; + group.add(shape); + }, + axisTick: function (group, angleAxisModel, polar, ticksAngles, minorTickAngles, radiusExtent) { + var tickModel = angleAxisModel.getModel('axisTick'); + var tickLen = (tickModel.get('inside') ? -1 : 1) * tickModel.get('length'); + var radius = radiusExtent[getRadiusIdx(polar)]; + var lines = map(ticksAngles, function (tickAngleItem) { + return new Line({ + shape: getAxisLineShape(polar, [radius, radius + tickLen], tickAngleItem.coord) + }); + }); + group.add(mergePath$1(lines, { + style: defaults(tickModel.getModel('lineStyle').getLineStyle(), { + stroke: angleAxisModel.get(['axisLine', 'lineStyle', 'color']) + }) + })); + }, + minorTick: function (group, angleAxisModel, polar, tickAngles, minorTickAngles, radiusExtent) { + if (!minorTickAngles.length) { + return; + } + + var tickModel = angleAxisModel.getModel('axisTick'); + var minorTickModel = angleAxisModel.getModel('minorTick'); + var tickLen = (tickModel.get('inside') ? -1 : 1) * minorTickModel.get('length'); + var radius = radiusExtent[getRadiusIdx(polar)]; + var lines = []; + + for (var i = 0; i < minorTickAngles.length; i++) { + for (var k = 0; k < minorTickAngles[i].length; k++) { + lines.push(new Line({ + shape: getAxisLineShape(polar, [radius, radius + tickLen], minorTickAngles[i][k].coord) + })); + } + } + + group.add(mergePath$1(lines, { + style: defaults(minorTickModel.getModel('lineStyle').getLineStyle(), defaults(tickModel.getLineStyle(), { + stroke: angleAxisModel.get(['axisLine', 'lineStyle', 'color']) + })) + })); + }, + axisLabel: function (group, angleAxisModel, polar, ticksAngles, minorTickAngles, radiusExtent, labels) { + var rawCategoryData = angleAxisModel.getCategories(true); + var commonLabelModel = angleAxisModel.getModel('axisLabel'); + var labelMargin = commonLabelModel.get('margin'); + var triggerEvent = angleAxisModel.get('triggerEvent'); // Use length of ticksAngles because it may remove the last tick to avoid overlapping + + each(labels, function (labelItem, idx) { + var labelModel = commonLabelModel; + var tickValue = labelItem.tickValue; + var r = radiusExtent[getRadiusIdx(polar)]; + var p = polar.coordToPoint([r + labelMargin, labelItem.coord]); + var cx = polar.cx; + var cy = polar.cy; + var labelTextAlign = Math.abs(p[0] - cx) / r < 0.3 ? 'center' : p[0] > cx ? 'left' : 'right'; + var labelTextVerticalAlign = Math.abs(p[1] - cy) / r < 0.3 ? 'middle' : p[1] > cy ? 'top' : 'bottom'; + + if (rawCategoryData && rawCategoryData[tickValue]) { + var rawCategoryItem = rawCategoryData[tickValue]; + + if (isObject(rawCategoryItem) && rawCategoryItem.textStyle) { + labelModel = new Model(rawCategoryItem.textStyle, commonLabelModel, commonLabelModel.ecModel); + } + } + + var textEl = new ZRText({ + silent: AxisBuilder.isLabelSilent(angleAxisModel), + style: createTextStyle(labelModel, { + x: p[0], + y: p[1], + fill: labelModel.getTextColor() || angleAxisModel.get(['axisLine', 'lineStyle', 'color']), + text: labelItem.formattedLabel, + align: labelTextAlign, + verticalAlign: labelTextVerticalAlign + }) + }); + group.add(textEl); // Pack data for mouse event + + if (triggerEvent) { + var eventData = AxisBuilder.makeAxisEventDataBase(angleAxisModel); + eventData.targetType = 'axisLabel'; + eventData.value = labelItem.rawLabel; + getECData(textEl).eventData = eventData; + } + }, this); + }, + splitLine: function (group, angleAxisModel, polar, ticksAngles, minorTickAngles, radiusExtent) { + var splitLineModel = angleAxisModel.getModel('splitLine'); + var lineStyleModel = splitLineModel.getModel('lineStyle'); + var lineColors = lineStyleModel.get('color'); + var lineCount = 0; + lineColors = lineColors instanceof Array ? lineColors : [lineColors]; + var splitLines = []; + + for (var i = 0; i < ticksAngles.length; i++) { + var colorIndex = lineCount++ % lineColors.length; + splitLines[colorIndex] = splitLines[colorIndex] || []; + splitLines[colorIndex].push(new Line({ + shape: getAxisLineShape(polar, radiusExtent, ticksAngles[i].coord) + })); + } // Simple optimization + // Batching the lines if color are the same + + + for (var i = 0; i < splitLines.length; i++) { + group.add(mergePath$1(splitLines[i], { + style: defaults({ + stroke: lineColors[i % lineColors.length] + }, lineStyleModel.getLineStyle()), + silent: true, + z: angleAxisModel.get('z') + })); + } + }, + minorSplitLine: function (group, angleAxisModel, polar, ticksAngles, minorTickAngles, radiusExtent) { + if (!minorTickAngles.length) { + return; + } + + var minorSplitLineModel = angleAxisModel.getModel('minorSplitLine'); + var lineStyleModel = minorSplitLineModel.getModel('lineStyle'); + var lines = []; + + for (var i = 0; i < minorTickAngles.length; i++) { + for (var k = 0; k < minorTickAngles[i].length; k++) { + lines.push(new Line({ + shape: getAxisLineShape(polar, radiusExtent, minorTickAngles[i][k].coord) + })); + } + } + + group.add(mergePath$1(lines, { + style: lineStyleModel.getLineStyle(), + silent: true, + z: angleAxisModel.get('z') + })); + }, + splitArea: function (group, angleAxisModel, polar, ticksAngles, minorTickAngles, radiusExtent) { + if (!ticksAngles.length) { + return; + } + + var splitAreaModel = angleAxisModel.getModel('splitArea'); + var areaStyleModel = splitAreaModel.getModel('areaStyle'); + var areaColors = areaStyleModel.get('color'); + var lineCount = 0; + areaColors = areaColors instanceof Array ? areaColors : [areaColors]; + var splitAreas = []; + var RADIAN = Math.PI / 180; + var prevAngle = -ticksAngles[0].coord * RADIAN; + var r0 = Math.min(radiusExtent[0], radiusExtent[1]); + var r1 = Math.max(radiusExtent[0], radiusExtent[1]); + var clockwise = angleAxisModel.get('clockwise'); + + for (var i = 1, len = ticksAngles.length; i <= len; i++) { + var coord = i === len ? ticksAngles[0].coord : ticksAngles[i].coord; + var colorIndex = lineCount++ % areaColors.length; + splitAreas[colorIndex] = splitAreas[colorIndex] || []; + splitAreas[colorIndex].push(new Sector({ + shape: { + cx: polar.cx, + cy: polar.cy, + r0: r0, + r: r1, + startAngle: prevAngle, + endAngle: -coord * RADIAN, + clockwise: clockwise + }, + silent: true + })); + prevAngle = -coord * RADIAN; + } // Simple optimization + // Batching the lines if color are the same + + + for (var i = 0; i < splitAreas.length; i++) { + group.add(mergePath$1(splitAreas[i], { + style: defaults({ + fill: areaColors[i % areaColors.length] + }, areaStyleModel.getAreaStyle()), + silent: true + })); + } + } + }; + + var axisBuilderAttrs$2 = ['axisLine', 'axisTickLabel', 'axisName']; + var selfBuilderAttrs$1 = ['splitLine', 'splitArea', 'minorSplitLine']; + + var RadiusAxisView = + /** @class */ + function (_super) { + __extends(RadiusAxisView, _super); + + function RadiusAxisView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = RadiusAxisView.type; + _this.axisPointerClass = 'PolarAxisPointer'; + return _this; + } + + RadiusAxisView.prototype.render = function (radiusAxisModel, ecModel) { + this.group.removeAll(); + + if (!radiusAxisModel.get('show')) { + return; + } + + var oldAxisGroup = this._axisGroup; + var newAxisGroup = this._axisGroup = new Group(); + this.group.add(newAxisGroup); + var radiusAxis = radiusAxisModel.axis; + var polar = radiusAxis.polar; + var angleAxis = polar.getAngleAxis(); + var ticksCoords = radiusAxis.getTicksCoords(); + var minorTicksCoords = radiusAxis.getMinorTicksCoords(); + var axisAngle = angleAxis.getExtent()[0]; + var radiusExtent = radiusAxis.getExtent(); + var layout = layoutAxis(polar, radiusAxisModel, axisAngle); + var axisBuilder = new AxisBuilder(radiusAxisModel, layout); + each(axisBuilderAttrs$2, axisBuilder.add, axisBuilder); + newAxisGroup.add(axisBuilder.getGroup()); + groupTransition(oldAxisGroup, newAxisGroup, radiusAxisModel); + each(selfBuilderAttrs$1, function (name) { + if (radiusAxisModel.get([name, 'show']) && !radiusAxis.scale.isBlank()) { + axisElementBuilders$1[name](this.group, radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords, minorTicksCoords); + } + }, this); + }; + + RadiusAxisView.type = 'radiusAxis'; + return RadiusAxisView; + }(AxisView); + + var axisElementBuilders$1 = { + splitLine: function (group, radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) { + var splitLineModel = radiusAxisModel.getModel('splitLine'); + var lineStyleModel = splitLineModel.getModel('lineStyle'); + var lineColors = lineStyleModel.get('color'); + var lineCount = 0; + lineColors = lineColors instanceof Array ? lineColors : [lineColors]; + var splitLines = []; + + for (var i = 0; i < ticksCoords.length; i++) { + var colorIndex = lineCount++ % lineColors.length; + splitLines[colorIndex] = splitLines[colorIndex] || []; + splitLines[colorIndex].push(new Circle({ + shape: { + cx: polar.cx, + cy: polar.cy, + // ensure circle radius >= 0 + r: Math.max(ticksCoords[i].coord, 0) + } + })); + } // Simple optimization + // Batching the lines if color are the same + + + for (var i = 0; i < splitLines.length; i++) { + group.add(mergePath$1(splitLines[i], { + style: defaults({ + stroke: lineColors[i % lineColors.length], + fill: null + }, lineStyleModel.getLineStyle()), + silent: true + })); + } + }, + minorSplitLine: function (group, radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords, minorTicksCoords) { + if (!minorTicksCoords.length) { + return; + } + + var minorSplitLineModel = radiusAxisModel.getModel('minorSplitLine'); + var lineStyleModel = minorSplitLineModel.getModel('lineStyle'); + var lines = []; + + for (var i = 0; i < minorTicksCoords.length; i++) { + for (var k = 0; k < minorTicksCoords[i].length; k++) { + lines.push(new Circle({ + shape: { + cx: polar.cx, + cy: polar.cy, + r: minorTicksCoords[i][k].coord + } + })); + } + } + + group.add(mergePath$1(lines, { + style: defaults({ + fill: null + }, lineStyleModel.getLineStyle()), + silent: true + })); + }, + splitArea: function (group, radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) { + if (!ticksCoords.length) { + return; + } + + var splitAreaModel = radiusAxisModel.getModel('splitArea'); + var areaStyleModel = splitAreaModel.getModel('areaStyle'); + var areaColors = areaStyleModel.get('color'); + var lineCount = 0; + areaColors = areaColors instanceof Array ? areaColors : [areaColors]; + var splitAreas = []; + var prevRadius = ticksCoords[0].coord; + + for (var i = 1; i < ticksCoords.length; i++) { + var colorIndex = lineCount++ % areaColors.length; + splitAreas[colorIndex] = splitAreas[colorIndex] || []; + splitAreas[colorIndex].push(new Sector({ + shape: { + cx: polar.cx, + cy: polar.cy, + r0: prevRadius, + r: ticksCoords[i].coord, + startAngle: 0, + endAngle: Math.PI * 2 + }, + silent: true + })); + prevRadius = ticksCoords[i].coord; + } // Simple optimization + // Batching the lines if color are the same + + + for (var i = 0; i < splitAreas.length; i++) { + group.add(mergePath$1(splitAreas[i], { + style: defaults({ + fill: areaColors[i % areaColors.length] + }, areaStyleModel.getAreaStyle()), + silent: true + })); + } + } + }; + /** + * @inner + */ + + function layoutAxis(polar, radiusAxisModel, axisAngle) { + return { + position: [polar.cx, polar.cy], + rotation: axisAngle / 180 * Math.PI, + labelDirection: -1, + tickDirection: -1, + nameDirection: 1, + labelRotate: radiusAxisModel.getModel('axisLabel').get('rotate'), + // Over splitLine and splitArea + z2: 1 + }; + } + + function getSeriesStackId$1(seriesModel) { + return seriesModel.get('stack') || '__ec_stack_' + seriesModel.seriesIndex; + } + + function getAxisKey$1(polar, axis) { + return axis.dim + polar.model.componentIndex; + } + + function barLayoutPolar(seriesType, ecModel, api) { + var lastStackCoords = {}; + var barWidthAndOffset = calRadialBar(filter(ecModel.getSeriesByType(seriesType), function (seriesModel) { + return !ecModel.isSeriesFiltered(seriesModel) && seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'polar'; + })); + ecModel.eachSeriesByType(seriesType, function (seriesModel) { + // Check series coordinate, do layout for polar only + if (seriesModel.coordinateSystem.type !== 'polar') { + return; + } + + var data = seriesModel.getData(); + var polar = seriesModel.coordinateSystem; + var baseAxis = polar.getBaseAxis(); + var axisKey = getAxisKey$1(polar, baseAxis); + var stackId = getSeriesStackId$1(seriesModel); + var columnLayoutInfo = barWidthAndOffset[axisKey][stackId]; + var columnOffset = columnLayoutInfo.offset; + var columnWidth = columnLayoutInfo.width; + var valueAxis = polar.getOtherAxis(baseAxis); + var cx = seriesModel.coordinateSystem.cx; + var cy = seriesModel.coordinateSystem.cy; + var barMinHeight = seriesModel.get('barMinHeight') || 0; + var barMinAngle = seriesModel.get('barMinAngle') || 0; + lastStackCoords[stackId] = lastStackCoords[stackId] || []; + var valueDim = data.mapDimension(valueAxis.dim); + var baseDim = data.mapDimension(baseAxis.dim); + var stacked = isDimensionStacked(data, valueDim + /*, baseDim*/ + ); + var clampLayout = baseAxis.dim !== 'radius' || !seriesModel.get('roundCap', true); + var valueAxisStart = valueAxis.dataToCoord(0); + + for (var idx = 0, len = data.count(); idx < len; idx++) { + var value = data.get(valueDim, idx); + var baseValue = data.get(baseDim, idx); + var sign = value >= 0 ? 'p' : 'n'; + var baseCoord = valueAxisStart; // Because of the barMinHeight, we can not use the value in + // stackResultDimension directly. + // Only ordinal axis can be stacked. + + if (stacked) { + if (!lastStackCoords[stackId][baseValue]) { + lastStackCoords[stackId][baseValue] = { + p: valueAxisStart, + n: valueAxisStart // Negative stack + + }; + } // Should also consider #4243 + + + baseCoord = lastStackCoords[stackId][baseValue][sign]; + } + + var r0 = void 0; + var r = void 0; + var startAngle = void 0; + var endAngle = void 0; // radial sector + + if (valueAxis.dim === 'radius') { + var radiusSpan = valueAxis.dataToCoord(value) - valueAxisStart; + var angle = baseAxis.dataToCoord(baseValue); + + if (Math.abs(radiusSpan) < barMinHeight) { + radiusSpan = (radiusSpan < 0 ? -1 : 1) * barMinHeight; + } + + r0 = baseCoord; + r = baseCoord + radiusSpan; + startAngle = angle - columnOffset; + endAngle = startAngle - columnWidth; + stacked && (lastStackCoords[stackId][baseValue][sign] = r); + } // tangential sector + else { + var angleSpan = valueAxis.dataToCoord(value, clampLayout) - valueAxisStart; + var radius = baseAxis.dataToCoord(baseValue); + + if (Math.abs(angleSpan) < barMinAngle) { + angleSpan = (angleSpan < 0 ? -1 : 1) * barMinAngle; + } + + r0 = radius + columnOffset; + r = r0 + columnWidth; + startAngle = baseCoord; + endAngle = baseCoord + angleSpan; // if the previous stack is at the end of the ring, + // add a round to differentiate it from origin + // let extent = angleAxis.getExtent(); + // let stackCoord = angle; + // if (stackCoord === extent[0] && value > 0) { + // stackCoord = extent[1]; + // } + // else if (stackCoord === extent[1] && value < 0) { + // stackCoord = extent[0]; + // } + + stacked && (lastStackCoords[stackId][baseValue][sign] = endAngle); + } + + data.setItemLayout(idx, { + cx: cx, + cy: cy, + r0: r0, + r: r, + // Consider that positive angle is anti-clockwise, + // while positive radian of sector is clockwise + startAngle: -startAngle * Math.PI / 180, + endAngle: -endAngle * Math.PI / 180, + + /** + * Keep the same logic with bar in catesion: use end value to + * control direction. Notice that if clockwise is true (by + * default), the sector will always draw clockwisely, no matter + * whether endAngle is greater or less than startAngle. + */ + clockwise: startAngle >= endAngle + }); + } + }); + } + /** + * Calculate bar width and offset for radial bar charts + */ + + + function calRadialBar(barSeries) { + // Columns info on each category axis. Key is polar name + var columnsMap = {}; + each(barSeries, function (seriesModel, idx) { + var data = seriesModel.getData(); + var polar = seriesModel.coordinateSystem; + var baseAxis = polar.getBaseAxis(); + var axisKey = getAxisKey$1(polar, baseAxis); + var axisExtent = baseAxis.getExtent(); + var bandWidth = baseAxis.type === 'category' ? baseAxis.getBandWidth() : Math.abs(axisExtent[1] - axisExtent[0]) / data.count(); + var columnsOnAxis = columnsMap[axisKey] || { + bandWidth: bandWidth, + remainedWidth: bandWidth, + autoWidthCount: 0, + categoryGap: '20%', + gap: '30%', + stacks: {} + }; + var stacks = columnsOnAxis.stacks; + columnsMap[axisKey] = columnsOnAxis; + var stackId = getSeriesStackId$1(seriesModel); + + if (!stacks[stackId]) { + columnsOnAxis.autoWidthCount++; + } + + stacks[stackId] = stacks[stackId] || { + width: 0, + maxWidth: 0 + }; + var barWidth = parsePercent$1(seriesModel.get('barWidth'), bandWidth); + var barMaxWidth = parsePercent$1(seriesModel.get('barMaxWidth'), bandWidth); + var barGap = seriesModel.get('barGap'); + var barCategoryGap = seriesModel.get('barCategoryGap'); + + if (barWidth && !stacks[stackId].width) { + barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth); + stacks[stackId].width = barWidth; + columnsOnAxis.remainedWidth -= barWidth; + } + + barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth); + barGap != null && (columnsOnAxis.gap = barGap); + barCategoryGap != null && (columnsOnAxis.categoryGap = barCategoryGap); + }); + var result = {}; + each(columnsMap, function (columnsOnAxis, coordSysName) { + result[coordSysName] = {}; + var stacks = columnsOnAxis.stacks; + var bandWidth = columnsOnAxis.bandWidth; + var categoryGap = parsePercent$1(columnsOnAxis.categoryGap, bandWidth); + var barGapPercent = parsePercent$1(columnsOnAxis.gap, 1); + var remainedWidth = columnsOnAxis.remainedWidth; + var autoWidthCount = columnsOnAxis.autoWidthCount; + var autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent); + autoWidth = Math.max(autoWidth, 0); // Find if any auto calculated bar exceeded maxBarWidth + + each(stacks, function (column, stack) { + var maxWidth = column.maxWidth; + + if (maxWidth && maxWidth < autoWidth) { + maxWidth = Math.min(maxWidth, remainedWidth); + + if (column.width) { + maxWidth = Math.min(maxWidth, column.width); + } + + remainedWidth -= maxWidth; + column.width = maxWidth; + autoWidthCount--; + } + }); // Recalculate width again + + autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent); + autoWidth = Math.max(autoWidth, 0); + var widthSum = 0; + var lastColumn; + each(stacks, function (column, idx) { + if (!column.width) { + column.width = autoWidth; + } + + lastColumn = column; + widthSum += column.width * (1 + barGapPercent); + }); + + if (lastColumn) { + widthSum -= lastColumn.width * barGapPercent; + } + + var offset = -widthSum / 2; + each(stacks, function (column, stackId) { + result[coordSysName][stackId] = result[coordSysName][stackId] || { + offset: offset, + width: column.width + }; + offset += column.width * (1 + barGapPercent); + }); + }); + return result; + } + + var angleAxisExtraOption = { + startAngle: 90, + clockwise: true, + splitNumber: 12, + axisLabel: { + rotate: 0 + } + }; + var radiusAxisExtraOption = { + splitNumber: 5 + }; + + var PolarView = + /** @class */ + function (_super) { + __extends(PolarView, _super); + + function PolarView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = PolarView.type; + return _this; + } + + PolarView.type = 'polar'; + return PolarView; + }(ComponentView); + + function install$u(registers) { + use(install$s); + AxisView.registerAxisPointerClass('PolarAxisPointer', PolarAxisPointer); + registers.registerCoordinateSystem('polar', polarCreator); + registers.registerComponentModel(PolarModel); + registers.registerComponentView(PolarView); // Model and view for angleAxis and radiusAxis + + axisModelCreator(registers, 'angle', AngleAxisModel, angleAxisExtraOption); + axisModelCreator(registers, 'radius', RadiusAxisModel, radiusAxisExtraOption); + registers.registerComponentView(AngleAxisView); + registers.registerComponentView(RadiusAxisView); + registers.registerLayout(curry(barLayoutPolar, 'bar')); + } + + function layout$2(axisModel, opt) { + opt = opt || {}; + var single = axisModel.coordinateSystem; + var axis = axisModel.axis; + var layout = {}; + var axisPosition = axis.position; + var orient = axis.orient; + var rect = single.getRect(); + var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height]; + var positionMap = { + horizontal: { + top: rectBound[2], + bottom: rectBound[3] + }, + vertical: { + left: rectBound[0], + right: rectBound[1] + } + }; + layout.position = [orient === 'vertical' ? positionMap.vertical[axisPosition] : rectBound[0], orient === 'horizontal' ? positionMap.horizontal[axisPosition] : rectBound[3]]; + var r = { + horizontal: 0, + vertical: 1 + }; + layout.rotation = Math.PI / 2 * r[orient]; + var directionMap = { + top: -1, + bottom: 1, + right: 1, + left: -1 + }; + layout.labelDirection = layout.tickDirection = layout.nameDirection = directionMap[axisPosition]; + + if (axisModel.get(['axisTick', 'inside'])) { + layout.tickDirection = -layout.tickDirection; + } + + if (retrieve(opt.labelInside, axisModel.get(['axisLabel', 'inside']))) { + layout.labelDirection = -layout.labelDirection; + } + + var labelRotation = opt.rotate; + labelRotation == null && (labelRotation = axisModel.get(['axisLabel', 'rotate'])); + layout.labelRotation = axisPosition === 'top' ? -labelRotation : labelRotation; + layout.z2 = 1; + return layout; + } + + var axisBuilderAttrs$3 = ['axisLine', 'axisTickLabel', 'axisName']; + var selfBuilderAttrs$2 = ['splitArea', 'splitLine']; + + var SingleAxisView = + /** @class */ + function (_super) { + __extends(SingleAxisView, _super); + + function SingleAxisView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = SingleAxisView.type; + _this.axisPointerClass = 'SingleAxisPointer'; + return _this; + } + + SingleAxisView.prototype.render = function (axisModel, ecModel, api, payload) { + var group = this.group; + group.removeAll(); + var oldAxisGroup = this._axisGroup; + this._axisGroup = new Group(); + var layout = layout$2(axisModel); + var axisBuilder = new AxisBuilder(axisModel, layout); + each(axisBuilderAttrs$3, axisBuilder.add, axisBuilder); + group.add(this._axisGroup); + group.add(axisBuilder.getGroup()); + each(selfBuilderAttrs$2, function (name) { + if (axisModel.get([name, 'show'])) { + axisElementBuilders$2[name](this, this.group, this._axisGroup, axisModel); + } + }, this); + groupTransition(oldAxisGroup, this._axisGroup, axisModel); + + _super.prototype.render.call(this, axisModel, ecModel, api, payload); + }; + + SingleAxisView.prototype.remove = function () { + rectCoordAxisHandleRemove(this); + }; + + SingleAxisView.type = 'singleAxis'; + return SingleAxisView; + }(AxisView); + + var axisElementBuilders$2 = { + splitLine: function (axisView, group, axisGroup, axisModel) { + var axis = axisModel.axis; + + if (axis.scale.isBlank()) { + return; + } + + var splitLineModel = axisModel.getModel('splitLine'); + var lineStyleModel = splitLineModel.getModel('lineStyle'); + var lineColors = lineStyleModel.get('color'); + lineColors = lineColors instanceof Array ? lineColors : [lineColors]; + var gridRect = axisModel.coordinateSystem.getRect(); + var isHorizontal = axis.isHorizontal(); + var splitLines = []; + var lineCount = 0; + var ticksCoords = axis.getTicksCoords({ + tickModel: splitLineModel + }); + var p1 = []; + var p2 = []; + + for (var i = 0; i < ticksCoords.length; ++i) { + var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord); + + if (isHorizontal) { + p1[0] = tickCoord; + p1[1] = gridRect.y; + p2[0] = tickCoord; + p2[1] = gridRect.y + gridRect.height; + } else { + p1[0] = gridRect.x; + p1[1] = tickCoord; + p2[0] = gridRect.x + gridRect.width; + p2[1] = tickCoord; + } + + var colorIndex = lineCount++ % lineColors.length; + splitLines[colorIndex] = splitLines[colorIndex] || []; + splitLines[colorIndex].push(new Line({ + subPixelOptimize: true, + shape: { + x1: p1[0], + y1: p1[1], + x2: p2[0], + y2: p2[1] + }, + silent: true + })); + } + + var lineStyle = lineStyleModel.getLineStyle(['color']); + + for (var i = 0; i < splitLines.length; ++i) { + group.add(mergePath$1(splitLines[i], { + style: defaults({ + stroke: lineColors[i % lineColors.length] + }, lineStyle), + silent: true + })); + } + }, + splitArea: function (axisView, group, axisGroup, axisModel) { + rectCoordAxisBuildSplitArea(axisView, axisGroup, axisModel, axisModel); + } + }; + + var SingleAxisModel = + /** @class */ + function (_super) { + __extends(SingleAxisModel, _super); + + function SingleAxisModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = SingleAxisModel.type; + return _this; + } + + SingleAxisModel.prototype.getCoordSysModel = function () { + return this; + }; + + SingleAxisModel.type = 'singleAxis'; + SingleAxisModel.layoutMode = 'box'; + SingleAxisModel.defaultOption = { + left: '5%', + top: '5%', + right: '5%', + bottom: '5%', + type: 'value', + position: 'bottom', + orient: 'horizontal', + axisLine: { + show: true, + lineStyle: { + width: 1, + type: 'solid' + } + }, + // Single coordinate system and single axis is the, + // which is used as the parent tooltip model. + // same model, so we set default tooltip show as true. + tooltip: { + show: true + }, + axisTick: { + show: true, + length: 6, + lineStyle: { + width: 1 + } + }, + axisLabel: { + show: true, + interval: 'auto' + }, + splitLine: { + show: true, + lineStyle: { + type: 'dashed', + opacity: 0.2 + } + } + }; + return SingleAxisModel; + }(ComponentModel); + + mixin(SingleAxisModel, AxisModelCommonMixin.prototype); + + var SingleAxis = + /** @class */ + function (_super) { + __extends(SingleAxis, _super); + + function SingleAxis(dim, scale, coordExtent, axisType, position) { + var _this = _super.call(this, dim, scale, coordExtent) || this; + + _this.type = axisType || 'value'; + _this.position = position || 'bottom'; + return _this; + } + /** + * Judge the orient of the axis. + */ + + + SingleAxis.prototype.isHorizontal = function () { + var position = this.position; + return position === 'top' || position === 'bottom'; + }; + + SingleAxis.prototype.pointToData = function (point, clamp) { + return this.coordinateSystem.pointToData(point)[0]; + }; + + return SingleAxis; + }(Axis); + + var singleDimensions = ['single']; + /** + * Create a single coordinates system. + */ + + var Single = + /** @class */ + function () { + function Single(axisModel, ecModel, api) { + this.type = 'single'; + this.dimension = 'single'; + /** + * Add it just for draw tooltip. + */ + + this.dimensions = singleDimensions; + this.axisPointerEnabled = true; + this.model = axisModel; + + this._init(axisModel, ecModel, api); + } + /** + * Initialize single coordinate system. + */ + + + Single.prototype._init = function (axisModel, ecModel, api) { + var dim = this.dimension; + var axis = new SingleAxis(dim, createScaleByModel(axisModel), [0, 0], axisModel.get('type'), axisModel.get('position')); + var isCategory = axis.type === 'category'; + axis.onBand = isCategory && axisModel.get('boundaryGap'); + axis.inverse = axisModel.get('inverse'); + axis.orient = axisModel.get('orient'); + axisModel.axis = axis; + axis.model = axisModel; + axis.coordinateSystem = this; + this._axis = axis; + }; + /** + * Update axis scale after data processed + */ + + + Single.prototype.update = function (ecModel, api) { + ecModel.eachSeries(function (seriesModel) { + if (seriesModel.coordinateSystem === this) { + var data_1 = seriesModel.getData(); + each(data_1.mapDimensionsAll(this.dimension), function (dim) { + this._axis.scale.unionExtentFromData(data_1, dim); + }, this); + niceScaleExtent(this._axis.scale, this._axis.model); + } + }, this); + }; + /** + * Resize the single coordinate system. + */ + + + Single.prototype.resize = function (axisModel, api) { + this._rect = getLayoutRect({ + left: axisModel.get('left'), + top: axisModel.get('top'), + right: axisModel.get('right'), + bottom: axisModel.get('bottom'), + width: axisModel.get('width'), + height: axisModel.get('height') + }, { + width: api.getWidth(), + height: api.getHeight() + }); + + this._adjustAxis(); + }; + + Single.prototype.getRect = function () { + return this._rect; + }; + + Single.prototype._adjustAxis = function () { + var rect = this._rect; + var axis = this._axis; + var isHorizontal = axis.isHorizontal(); + var extent = isHorizontal ? [0, rect.width] : [0, rect.height]; + var idx = axis.reverse ? 1 : 0; + axis.setExtent(extent[idx], extent[1 - idx]); + + this._updateAxisTransform(axis, isHorizontal ? rect.x : rect.y); + }; + + Single.prototype._updateAxisTransform = function (axis, coordBase) { + var axisExtent = axis.getExtent(); + var extentSum = axisExtent[0] + axisExtent[1]; + var isHorizontal = axis.isHorizontal(); + axis.toGlobalCoord = isHorizontal ? function (coord) { + return coord + coordBase; + } : function (coord) { + return extentSum - coord + coordBase; + }; + axis.toLocalCoord = isHorizontal ? function (coord) { + return coord - coordBase; + } : function (coord) { + return extentSum - coord + coordBase; + }; + }; + /** + * Get axis. + */ + + + Single.prototype.getAxis = function () { + return this._axis; + }; + /** + * Get axis, add it just for draw tooltip. + */ + + + Single.prototype.getBaseAxis = function () { + return this._axis; + }; + + Single.prototype.getAxes = function () { + return [this._axis]; + }; + + Single.prototype.getTooltipAxes = function () { + return { + baseAxes: [this.getAxis()], + // Empty otherAxes + otherAxes: [] + }; + }; + /** + * If contain point. + */ + + + Single.prototype.containPoint = function (point) { + var rect = this.getRect(); + var axis = this.getAxis(); + var orient = axis.orient; + + if (orient === 'horizontal') { + return axis.contain(axis.toLocalCoord(point[0])) && point[1] >= rect.y && point[1] <= rect.y + rect.height; + } else { + return axis.contain(axis.toLocalCoord(point[1])) && point[0] >= rect.y && point[0] <= rect.y + rect.height; + } + }; + + Single.prototype.pointToData = function (point) { + var axis = this.getAxis(); + return [axis.coordToData(axis.toLocalCoord(point[axis.orient === 'horizontal' ? 0 : 1]))]; + }; + /** + * Convert the series data to concrete point. + * Can be [val] | val + */ + + + Single.prototype.dataToPoint = function (val) { + var axis = this.getAxis(); + var rect = this.getRect(); + var pt = []; + var idx = axis.orient === 'horizontal' ? 0 : 1; + + if (val instanceof Array) { + val = val[0]; + } + + pt[idx] = axis.toGlobalCoord(axis.dataToCoord(+val)); + pt[1 - idx] = idx === 0 ? rect.y + rect.height / 2 : rect.x + rect.width / 2; + return pt; + }; + + Single.prototype.convertToPixel = function (ecModel, finder, value) { + var coordSys = getCoordSys$3(finder); + return coordSys === this ? this.dataToPoint(value) : null; + }; + + Single.prototype.convertFromPixel = function (ecModel, finder, pixel) { + var coordSys = getCoordSys$3(finder); + return coordSys === this ? this.pointToData(pixel) : null; + }; + + return Single; + }(); + + function getCoordSys$3(finder) { + var seriesModel = finder.seriesModel; + var singleModel = finder.singleAxisModel; + return singleModel && singleModel.coordinateSystem || seriesModel && seriesModel.coordinateSystem; + } + + /** + * Create single coordinate system and inject it into seriesModel. + */ + + function create$2(ecModel, api) { + var singles = []; + ecModel.eachComponent('singleAxis', function (axisModel, idx) { + var single = new Single(axisModel, ecModel, api); + single.name = 'single_' + idx; + single.resize(axisModel, api); + axisModel.coordinateSystem = single; + singles.push(single); + }); + ecModel.eachSeries(function (seriesModel) { + if (seriesModel.get('coordinateSystem') === 'singleAxis') { + var singleAxisModel = seriesModel.getReferringComponents('singleAxis', SINGLE_REFERRING).models[0]; + seriesModel.coordinateSystem = singleAxisModel && singleAxisModel.coordinateSystem; + } + }); + return singles; + } + + var singleCreator = { + create: create$2, + dimensions: singleDimensions + }; + + var XY = ['x', 'y']; + var WH = ['width', 'height']; + + var SingleAxisPointer = + /** @class */ + function (_super) { + __extends(SingleAxisPointer, _super); + + function SingleAxisPointer() { + return _super !== null && _super.apply(this, arguments) || this; + } + /** + * @override + */ + + + SingleAxisPointer.prototype.makeElOption = function (elOption, value, axisModel, axisPointerModel, api) { + var axis = axisModel.axis; + var coordSys = axis.coordinateSystem; + var otherExtent = getGlobalExtent(coordSys, 1 - getPointDimIndex(axis)); + var pixelValue = coordSys.dataToPoint(value)[0]; + var axisPointerType = axisPointerModel.get('type'); + + if (axisPointerType && axisPointerType !== 'none') { + var elStyle = buildElStyle(axisPointerModel); + var pointerOption = pointerShapeBuilder$2[axisPointerType](axis, pixelValue, otherExtent); + pointerOption.style = elStyle; + elOption.graphicKey = pointerOption.type; + elOption.pointer = pointerOption; + } + + var layoutInfo = layout$2(axisModel); + buildCartesianSingleLabelElOption( // @ts-ignore + value, elOption, layoutInfo, axisModel, axisPointerModel, api); + }; + /** + * @override + */ + + + SingleAxisPointer.prototype.getHandleTransform = function (value, axisModel, axisPointerModel) { + var layoutInfo = layout$2(axisModel, { + labelInside: false + }); // @ts-ignore + + layoutInfo.labelMargin = axisPointerModel.get(['handle', 'margin']); + var position = getTransformedPosition(axisModel.axis, value, layoutInfo); + return { + x: position[0], + y: position[1], + rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0) + }; + }; + /** + * @override + */ + + + SingleAxisPointer.prototype.updateHandleTransform = function (transform, delta, axisModel, axisPointerModel) { + var axis = axisModel.axis; + var coordSys = axis.coordinateSystem; + var dimIndex = getPointDimIndex(axis); + var axisExtent = getGlobalExtent(coordSys, dimIndex); + var currPosition = [transform.x, transform.y]; + currPosition[dimIndex] += delta[dimIndex]; + currPosition[dimIndex] = Math.min(axisExtent[1], currPosition[dimIndex]); + currPosition[dimIndex] = Math.max(axisExtent[0], currPosition[dimIndex]); + var otherExtent = getGlobalExtent(coordSys, 1 - dimIndex); + var cursorOtherValue = (otherExtent[1] + otherExtent[0]) / 2; + var cursorPoint = [cursorOtherValue, cursorOtherValue]; + cursorPoint[dimIndex] = currPosition[dimIndex]; + return { + x: currPosition[0], + y: currPosition[1], + rotation: transform.rotation, + cursorPoint: cursorPoint, + tooltipOption: { + verticalAlign: 'middle' + } + }; + }; + + return SingleAxisPointer; + }(BaseAxisPointer); + + var pointerShapeBuilder$2 = { + line: function (axis, pixelValue, otherExtent) { + var targetShape = makeLineShape([pixelValue, otherExtent[0]], [pixelValue, otherExtent[1]], getPointDimIndex(axis)); + return { + type: 'Line', + subPixelOptimize: true, + shape: targetShape + }; + }, + shadow: function (axis, pixelValue, otherExtent) { + var bandWidth = axis.getBandWidth(); + var span = otherExtent[1] - otherExtent[0]; + return { + type: 'Rect', + shape: makeRectShape([pixelValue - bandWidth / 2, otherExtent[0]], [bandWidth, span], getPointDimIndex(axis)) + }; + } + }; + + function getPointDimIndex(axis) { + return axis.isHorizontal() ? 0 : 1; + } + + function getGlobalExtent(coordSys, dimIndex) { + var rect = coordSys.getRect(); + return [rect[XY[dimIndex]], rect[XY[dimIndex]] + rect[WH[dimIndex]]]; + } + + var SingleView = + /** @class */ + function (_super) { + __extends(SingleView, _super); + + function SingleView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = SingleView.type; + return _this; + } + + SingleView.type = 'single'; + return SingleView; + }(ComponentView); + + function install$v(registers) { + use(install$s); + AxisView.registerAxisPointerClass('SingleAxisPointer', SingleAxisPointer); + registers.registerComponentView(SingleView); // Axis + + registers.registerComponentView(SingleAxisView); + registers.registerComponentModel(SingleAxisModel); + axisModelCreator(registers, 'single', SingleAxisModel, SingleAxisModel.defaultOption); + registers.registerCoordinateSystem('single', singleCreator); + } + + var CalendarModel = + /** @class */ + function (_super) { + __extends(CalendarModel, _super); + + function CalendarModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = CalendarModel.type; + return _this; + } + /** + * @override + */ + + + CalendarModel.prototype.init = function (option, parentModel, ecModel) { + var inputPositionParams = getLayoutParams(option); + + _super.prototype.init.apply(this, arguments); + + mergeAndNormalizeLayoutParams(option, inputPositionParams); + }; + /** + * @override + */ + + + CalendarModel.prototype.mergeOption = function (option) { + _super.prototype.mergeOption.apply(this, arguments); + + mergeAndNormalizeLayoutParams(this.option, option); + }; + + CalendarModel.prototype.getCellSize = function () { + // Has been normalized + return this.option.cellSize; + }; + + CalendarModel.type = 'calendar'; + CalendarModel.defaultOption = { + // zlevel: 0, + z: 2, + left: 80, + top: 60, + cellSize: 20, + // horizontal vertical + orient: 'horizontal', + // month separate line style + splitLine: { + show: true, + lineStyle: { + color: '#000', + width: 1, + type: 'solid' + } + }, + // rect style temporarily unused emphasis + itemStyle: { + color: '#fff', + borderWidth: 1, + borderColor: '#ccc' + }, + // week text style + dayLabel: { + show: true, + firstDay: 0, + // start end + position: 'start', + margin: '50%', + color: '#000' + }, + // month text style + monthLabel: { + show: true, + // start end + position: 'start', + margin: 5, + // center or left + align: 'center', + formatter: null, + color: '#000' + }, + // year text style + yearLabel: { + show: true, + // top bottom left right + position: null, + margin: 30, + formatter: null, + color: '#ccc', + fontFamily: 'sans-serif', + fontWeight: 'bolder', + fontSize: 20 + } + }; + return CalendarModel; + }(ComponentModel); + + function mergeAndNormalizeLayoutParams(target, raw) { + // Normalize cellSize + var cellSize = target.cellSize; + var cellSizeArr; + + if (!isArray(cellSize)) { + cellSizeArr = target.cellSize = [cellSize, cellSize]; + } else { + cellSizeArr = cellSize; + } + + if (cellSizeArr.length === 1) { + cellSizeArr[1] = cellSizeArr[0]; + } + + var ignoreSize = map([0, 1], function (hvIdx) { + // If user have set `width` or both `left` and `right`, cellSizeArr + // will be automatically set to 'auto', otherwise the default + // setting of cellSizeArr will make `width` setting not work. + if (sizeCalculable(raw, hvIdx)) { + cellSizeArr[hvIdx] = 'auto'; + } + + return cellSizeArr[hvIdx] != null && cellSizeArr[hvIdx] !== 'auto'; + }); + mergeLayoutParam(target, raw, { + type: 'box', + ignoreSize: ignoreSize + }); + } + + var CalendarView = + /** @class */ + function (_super) { + __extends(CalendarView, _super); + + function CalendarView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = CalendarView.type; + return _this; + } + + CalendarView.prototype.render = function (calendarModel, ecModel, api) { + var group = this.group; + group.removeAll(); + var coordSys = calendarModel.coordinateSystem; // range info + + var rangeData = coordSys.getRangeInfo(); + var orient = coordSys.getOrient(); // locale + + var localeModel = ecModel.getLocaleModel(); + + this._renderDayRect(calendarModel, rangeData, group); // _renderLines must be called prior to following function + + + this._renderLines(calendarModel, rangeData, orient, group); + + this._renderYearText(calendarModel, rangeData, orient, group); + + this._renderMonthText(calendarModel, localeModel, orient, group); + + this._renderWeekText(calendarModel, localeModel, rangeData, orient, group); + }; // render day rect + + + CalendarView.prototype._renderDayRect = function (calendarModel, rangeData, group) { + var coordSys = calendarModel.coordinateSystem; + var itemRectStyleModel = calendarModel.getModel('itemStyle').getItemStyle(); + var sw = coordSys.getCellWidth(); + var sh = coordSys.getCellHeight(); + + for (var i = rangeData.start.time; i <= rangeData.end.time; i = coordSys.getNextNDay(i, 1).time) { + var point = coordSys.dataToRect([i], false).tl; // every rect + + var rect = new Rect({ + shape: { + x: point[0], + y: point[1], + width: sw, + height: sh + }, + cursor: 'default', + style: itemRectStyleModel + }); + group.add(rect); + } + }; // render separate line + + + CalendarView.prototype._renderLines = function (calendarModel, rangeData, orient, group) { + var self = this; + var coordSys = calendarModel.coordinateSystem; + var lineStyleModel = calendarModel.getModel(['splitLine', 'lineStyle']).getLineStyle(); + var show = calendarModel.get(['splitLine', 'show']); + var lineWidth = lineStyleModel.lineWidth; + this._tlpoints = []; + this._blpoints = []; + this._firstDayOfMonth = []; + this._firstDayPoints = []; + var firstDay = rangeData.start; + + for (var i = 0; firstDay.time <= rangeData.end.time; i++) { + addPoints(firstDay.formatedDate); + + if (i === 0) { + firstDay = coordSys.getDateInfo(rangeData.start.y + '-' + rangeData.start.m); + } + + var date = firstDay.date; + date.setMonth(date.getMonth() + 1); + firstDay = coordSys.getDateInfo(date); + } + + addPoints(coordSys.getNextNDay(rangeData.end.time, 1).formatedDate); + + function addPoints(date) { + self._firstDayOfMonth.push(coordSys.getDateInfo(date)); + + self._firstDayPoints.push(coordSys.dataToRect([date], false).tl); + + var points = self._getLinePointsOfOneWeek(calendarModel, date, orient); + + self._tlpoints.push(points[0]); + + self._blpoints.push(points[points.length - 1]); + + show && self._drawSplitline(points, lineStyleModel, group); + } // render top/left line + + + show && this._drawSplitline(self._getEdgesPoints(self._tlpoints, lineWidth, orient), lineStyleModel, group); // render bottom/right line + + show && this._drawSplitline(self._getEdgesPoints(self._blpoints, lineWidth, orient), lineStyleModel, group); + }; // get points at both ends + + + CalendarView.prototype._getEdgesPoints = function (points, lineWidth, orient) { + var rs = [points[0].slice(), points[points.length - 1].slice()]; + var idx = orient === 'horizontal' ? 0 : 1; // both ends of the line are extend half lineWidth + + rs[0][idx] = rs[0][idx] - lineWidth / 2; + rs[1][idx] = rs[1][idx] + lineWidth / 2; + return rs; + }; // render split line + + + CalendarView.prototype._drawSplitline = function (points, lineStyle, group) { + var poyline = new Polyline({ + z2: 20, + shape: { + points: points + }, + style: lineStyle + }); + group.add(poyline); + }; // render month line of one week points + + + CalendarView.prototype._getLinePointsOfOneWeek = function (calendarModel, date, orient) { + var coordSys = calendarModel.coordinateSystem; + var parsedDate = coordSys.getDateInfo(date); + var points = []; + + for (var i = 0; i < 7; i++) { + var tmpD = coordSys.getNextNDay(parsedDate.time, i); + var point = coordSys.dataToRect([tmpD.time], false); + points[2 * tmpD.day] = point.tl; + points[2 * tmpD.day + 1] = point[orient === 'horizontal' ? 'bl' : 'tr']; + } + + return points; + }; + + CalendarView.prototype._formatterLabel = function (formatter, params) { + if (isString(formatter) && formatter) { + return formatTplSimple(formatter, params); + } + + if (isFunction(formatter)) { + return formatter(params); + } + + return params.nameMap; + }; + + CalendarView.prototype._yearTextPositionControl = function (textEl, point, orient, position, margin) { + var x = point[0]; + var y = point[1]; + var aligns = ['center', 'bottom']; + + if (position === 'bottom') { + y += margin; + aligns = ['center', 'top']; + } else if (position === 'left') { + x -= margin; + } else if (position === 'right') { + x += margin; + aligns = ['center', 'top']; + } else { + // top + y -= margin; + } + + var rotate = 0; + + if (position === 'left' || position === 'right') { + rotate = Math.PI / 2; + } + + return { + rotation: rotate, + x: x, + y: y, + style: { + align: aligns[0], + verticalAlign: aligns[1] + } + }; + }; // render year + + + CalendarView.prototype._renderYearText = function (calendarModel, rangeData, orient, group) { + var yearLabel = calendarModel.getModel('yearLabel'); + + if (!yearLabel.get('show')) { + return; + } + + var margin = yearLabel.get('margin'); + var pos = yearLabel.get('position'); + + if (!pos) { + pos = orient !== 'horizontal' ? 'top' : 'left'; + } + + var points = [this._tlpoints[this._tlpoints.length - 1], this._blpoints[0]]; + var xc = (points[0][0] + points[1][0]) / 2; + var yc = (points[0][1] + points[1][1]) / 2; + var idx = orient === 'horizontal' ? 0 : 1; + var posPoints = { + top: [xc, points[idx][1]], + bottom: [xc, points[1 - idx][1]], + left: [points[1 - idx][0], yc], + right: [points[idx][0], yc] + }; + var name = rangeData.start.y; + + if (+rangeData.end.y > +rangeData.start.y) { + name = name + '-' + rangeData.end.y; + } + + var formatter = yearLabel.get('formatter'); + var params = { + start: rangeData.start.y, + end: rangeData.end.y, + nameMap: name + }; + + var content = this._formatterLabel(formatter, params); + + var yearText = new ZRText({ + z2: 30, + style: createTextStyle(yearLabel, { + text: content + }) + }); + yearText.attr(this._yearTextPositionControl(yearText, posPoints[pos], orient, pos, margin)); + group.add(yearText); + }; + + CalendarView.prototype._monthTextPositionControl = function (point, isCenter, orient, position, margin) { + var align = 'left'; + var vAlign = 'top'; + var x = point[0]; + var y = point[1]; + + if (orient === 'horizontal') { + y = y + margin; + + if (isCenter) { + align = 'center'; + } + + if (position === 'start') { + vAlign = 'bottom'; + } + } else { + x = x + margin; + + if (isCenter) { + vAlign = 'middle'; + } + + if (position === 'start') { + align = 'right'; + } + } + + return { + x: x, + y: y, + align: align, + verticalAlign: vAlign + }; + }; // render month and year text + + + CalendarView.prototype._renderMonthText = function (calendarModel, localeModel, orient, group) { + var monthLabel = calendarModel.getModel('monthLabel'); + + if (!monthLabel.get('show')) { + return; + } + + var nameMap = monthLabel.get('nameMap'); + var margin = monthLabel.get('margin'); + var pos = monthLabel.get('position'); + var align = monthLabel.get('align'); + var termPoints = [this._tlpoints, this._blpoints]; + + if (!nameMap || isString(nameMap)) { + if (nameMap) { + // case-sensitive + localeModel = getLocaleModel(nameMap) || localeModel; + } // PENDING + // for ZH locale, original form is `一月` but current form is `1月` + + + nameMap = localeModel.get(['time', 'monthAbbr']) || []; + } + + var idx = pos === 'start' ? 0 : 1; + var axis = orient === 'horizontal' ? 0 : 1; + margin = pos === 'start' ? -margin : margin; + var isCenter = align === 'center'; + + for (var i = 0; i < termPoints[idx].length - 1; i++) { + var tmp = termPoints[idx][i].slice(); + var firstDay = this._firstDayOfMonth[i]; + + if (isCenter) { + var firstDayPoints = this._firstDayPoints[i]; + tmp[axis] = (firstDayPoints[axis] + termPoints[0][i + 1][axis]) / 2; + } + + var formatter = monthLabel.get('formatter'); + var name_1 = nameMap[+firstDay.m - 1]; + var params = { + yyyy: firstDay.y, + yy: (firstDay.y + '').slice(2), + MM: firstDay.m, + M: +firstDay.m, + nameMap: name_1 + }; + + var content = this._formatterLabel(formatter, params); + + var monthText = new ZRText({ + z2: 30, + style: extend(createTextStyle(monthLabel, { + text: content + }), this._monthTextPositionControl(tmp, isCenter, orient, pos, margin)) + }); + group.add(monthText); + } + }; + + CalendarView.prototype._weekTextPositionControl = function (point, orient, position, margin, cellSize) { + var align = 'center'; + var vAlign = 'middle'; + var x = point[0]; + var y = point[1]; + var isStart = position === 'start'; + + if (orient === 'horizontal') { + x = x + margin + (isStart ? 1 : -1) * cellSize[0] / 2; + align = isStart ? 'right' : 'left'; + } else { + y = y + margin + (isStart ? 1 : -1) * cellSize[1] / 2; + vAlign = isStart ? 'bottom' : 'top'; + } + + return { + x: x, + y: y, + align: align, + verticalAlign: vAlign + }; + }; // render weeks + + + CalendarView.prototype._renderWeekText = function (calendarModel, localeModel, rangeData, orient, group) { + var dayLabel = calendarModel.getModel('dayLabel'); + + if (!dayLabel.get('show')) { + return; + } + + var coordSys = calendarModel.coordinateSystem; + var pos = dayLabel.get('position'); + var nameMap = dayLabel.get('nameMap'); + var margin = dayLabel.get('margin'); + var firstDayOfWeek = coordSys.getFirstDayOfWeek(); + + if (!nameMap || isString(nameMap)) { + if (nameMap) { + // case-sensitive + localeModel = getLocaleModel(nameMap) || localeModel; + } // Use the first letter of `dayOfWeekAbbr` if `dayOfWeekShort` doesn't exist in the locale file + + + var dayOfWeekShort = localeModel.get(['time', 'dayOfWeekShort']); + nameMap = dayOfWeekShort || map(localeModel.get(['time', 'dayOfWeekAbbr']), function (val) { + return val[0]; + }); + } + + var start = coordSys.getNextNDay(rangeData.end.time, 7 - rangeData.lweek).time; + var cellSize = [coordSys.getCellWidth(), coordSys.getCellHeight()]; + margin = parsePercent$1(margin, Math.min(cellSize[1], cellSize[0])); + + if (pos === 'start') { + start = coordSys.getNextNDay(rangeData.start.time, -(7 + rangeData.fweek)).time; + margin = -margin; + } + + for (var i = 0; i < 7; i++) { + var tmpD = coordSys.getNextNDay(start, i); + var point = coordSys.dataToRect([tmpD.time], false).center; + var day = i; + day = Math.abs((i + firstDayOfWeek) % 7); + var weekText = new ZRText({ + z2: 30, + style: extend(createTextStyle(dayLabel, { + text: nameMap[day] + }), this._weekTextPositionControl(point, orient, pos, margin, cellSize)) + }); + group.add(weekText); + } + }; + + CalendarView.type = 'calendar'; + return CalendarView; + }(ComponentView); + + var PROXIMATE_ONE_DAY = 86400000; + + var Calendar = + /** @class */ + function () { + function Calendar(calendarModel, ecModel, api) { + this.type = 'calendar'; + this.dimensions = Calendar.dimensions; // Required in createListFromData + + this.getDimensionsInfo = Calendar.getDimensionsInfo; + this._model = calendarModel; + } + + Calendar.getDimensionsInfo = function () { + return [{ + name: 'time', + type: 'time' + }, 'value']; + }; + + Calendar.prototype.getRangeInfo = function () { + return this._rangeInfo; + }; + + Calendar.prototype.getModel = function () { + return this._model; + }; + + Calendar.prototype.getRect = function () { + return this._rect; + }; + + Calendar.prototype.getCellWidth = function () { + return this._sw; + }; + + Calendar.prototype.getCellHeight = function () { + return this._sh; + }; + + Calendar.prototype.getOrient = function () { + return this._orient; + }; + /** + * getFirstDayOfWeek + * + * @example + * 0 : start at Sunday + * 1 : start at Monday + * + * @return {number} + */ + + + Calendar.prototype.getFirstDayOfWeek = function () { + return this._firstDayOfWeek; + }; + /** + * get date info + * } + */ + + + Calendar.prototype.getDateInfo = function (date) { + date = parseDate(date); + var y = date.getFullYear(); + var m = date.getMonth() + 1; + var mStr = m < 10 ? '0' + m : '' + m; + var d = date.getDate(); + var dStr = d < 10 ? '0' + d : '' + d; + var day = date.getDay(); + day = Math.abs((day + 7 - this.getFirstDayOfWeek()) % 7); + return { + y: y + '', + m: mStr, + d: dStr, + day: day, + time: date.getTime(), + formatedDate: y + '-' + mStr + '-' + dStr, + date: date + }; + }; + + Calendar.prototype.getNextNDay = function (date, n) { + n = n || 0; + + if (n === 0) { + return this.getDateInfo(date); + } + + date = new Date(this.getDateInfo(date).time); + date.setDate(date.getDate() + n); + return this.getDateInfo(date); + }; + + Calendar.prototype.update = function (ecModel, api) { + this._firstDayOfWeek = +this._model.getModel('dayLabel').get('firstDay'); + this._orient = this._model.get('orient'); + this._lineWidth = this._model.getModel('itemStyle').getItemStyle().lineWidth || 0; + this._rangeInfo = this._getRangeInfo(this._initRangeOption()); + var weeks = this._rangeInfo.weeks || 1; + var whNames = ['width', 'height']; + + var cellSize = this._model.getCellSize().slice(); + + var layoutParams = this._model.getBoxLayoutParams(); + + var cellNumbers = this._orient === 'horizontal' ? [weeks, 7] : [7, weeks]; + each([0, 1], function (idx) { + if (cellSizeSpecified(cellSize, idx)) { + layoutParams[whNames[idx]] = cellSize[idx] * cellNumbers[idx]; + } + }); + var whGlobal = { + width: api.getWidth(), + height: api.getHeight() + }; + var calendarRect = this._rect = getLayoutRect(layoutParams, whGlobal); + each([0, 1], function (idx) { + if (!cellSizeSpecified(cellSize, idx)) { + cellSize[idx] = calendarRect[whNames[idx]] / cellNumbers[idx]; + } + }); + + function cellSizeSpecified(cellSize, idx) { + return cellSize[idx] != null && cellSize[idx] !== 'auto'; + } // Has been calculated out number. + + + this._sw = cellSize[0]; + this._sh = cellSize[1]; + }; + /** + * Convert a time data(time, value) item to (x, y) point. + */ + // TODO Clamp of calendar is not same with cartesian coordinate systems. + // It will return NaN if data exceeds. + + + Calendar.prototype.dataToPoint = function (data, clamp) { + isArray(data) && (data = data[0]); + clamp == null && (clamp = true); + var dayInfo = this.getDateInfo(data); + var range = this._rangeInfo; + var date = dayInfo.formatedDate; // if not in range return [NaN, NaN] + + if (clamp && !(dayInfo.time >= range.start.time && dayInfo.time < range.end.time + PROXIMATE_ONE_DAY)) { + return [NaN, NaN]; + } + + var week = dayInfo.day; + + var nthWeek = this._getRangeInfo([range.start.time, date]).nthWeek; + + if (this._orient === 'vertical') { + return [this._rect.x + week * this._sw + this._sw / 2, this._rect.y + nthWeek * this._sh + this._sh / 2]; + } + + return [this._rect.x + nthWeek * this._sw + this._sw / 2, this._rect.y + week * this._sh + this._sh / 2]; + }; + /** + * Convert a (x, y) point to time data + */ + + + Calendar.prototype.pointToData = function (point) { + var date = this.pointToDate(point); + return date && date.time; + }; + /** + * Convert a time date item to (x, y) four point. + */ + + + Calendar.prototype.dataToRect = function (data, clamp) { + var point = this.dataToPoint(data, clamp); + return { + contentShape: { + x: point[0] - (this._sw - this._lineWidth) / 2, + y: point[1] - (this._sh - this._lineWidth) / 2, + width: this._sw - this._lineWidth, + height: this._sh - this._lineWidth + }, + center: point, + tl: [point[0] - this._sw / 2, point[1] - this._sh / 2], + tr: [point[0] + this._sw / 2, point[1] - this._sh / 2], + br: [point[0] + this._sw / 2, point[1] + this._sh / 2], + bl: [point[0] - this._sw / 2, point[1] + this._sh / 2] + }; + }; + /** + * Convert a (x, y) point to time date + * + * @param {Array} point point + * @return {Object} date + */ + + + Calendar.prototype.pointToDate = function (point) { + var nthX = Math.floor((point[0] - this._rect.x) / this._sw) + 1; + var nthY = Math.floor((point[1] - this._rect.y) / this._sh) + 1; + var range = this._rangeInfo.range; + + if (this._orient === 'vertical') { + return this._getDateByWeeksAndDay(nthY, nthX - 1, range); + } + + return this._getDateByWeeksAndDay(nthX, nthY - 1, range); + }; + + Calendar.prototype.convertToPixel = function (ecModel, finder, value) { + var coordSys = getCoordSys$4(finder); + return coordSys === this ? coordSys.dataToPoint(value) : null; + }; + + Calendar.prototype.convertFromPixel = function (ecModel, finder, pixel) { + var coordSys = getCoordSys$4(finder); + return coordSys === this ? coordSys.pointToData(pixel) : null; + }; + + Calendar.prototype.containPoint = function (point) { + console.warn('Not implemented.'); + return false; + }; + /** + * initRange + * Normalize to an [start, end] array + */ + + + Calendar.prototype._initRangeOption = function () { + var range = this._model.get('range'); + + var normalizedRange; // Convert [1990] to 1990 + + if (isArray(range) && range.length === 1) { + range = range[0]; + } + + if (!isArray(range)) { + var rangeStr = range.toString(); // One year. + + if (/^\d{4}$/.test(rangeStr)) { + normalizedRange = [rangeStr + '-01-01', rangeStr + '-12-31']; + } // One month + + + if (/^\d{4}[\/|-]\d{1,2}$/.test(rangeStr)) { + var start = this.getDateInfo(rangeStr); + var firstDay = start.date; + firstDay.setMonth(firstDay.getMonth() + 1); + var end = this.getNextNDay(firstDay, -1); + normalizedRange = [start.formatedDate, end.formatedDate]; + } // One day + + + if (/^\d{4}[\/|-]\d{1,2}[\/|-]\d{1,2}$/.test(rangeStr)) { + normalizedRange = [rangeStr, rangeStr]; + } + } else { + normalizedRange = range; + } + + if (!normalizedRange) { + if ("development" !== 'production') { + logError('Invalid date range.'); + } // Not handling it. + + + return range; + } + + var tmp = this._getRangeInfo(normalizedRange); + + if (tmp.start.time > tmp.end.time) { + normalizedRange.reverse(); + } + + return normalizedRange; + }; + /** + * range info + * + * @private + * @param {Array} range range ['2017-01-01', '2017-07-08'] + * If range[0] > range[1], they will not be reversed. + * @return {Object} obj + */ + + + Calendar.prototype._getRangeInfo = function (range) { + var parsedRange = [this.getDateInfo(range[0]), this.getDateInfo(range[1])]; + var reversed; + + if (parsedRange[0].time > parsedRange[1].time) { + reversed = true; + parsedRange.reverse(); + } + + var allDay = Math.floor(parsedRange[1].time / PROXIMATE_ONE_DAY) - Math.floor(parsedRange[0].time / PROXIMATE_ONE_DAY) + 1; // Consider case1 (#11677 #10430): + // Set the system timezone as "UK", set the range to `['2016-07-01', '2016-12-31']` + // Consider case2: + // Firstly set system timezone as "Time Zone: America/Toronto", + // ``` + // let first = new Date(1478412000000 - 3600 * 1000 * 2.5); + // let second = new Date(1478412000000); + // let allDays = Math.floor(second / ONE_DAY) - Math.floor(first / ONE_DAY) + 1; + // ``` + // will get wrong result because of DST. So we should fix it. + + var date = new Date(parsedRange[0].time); + var startDateNum = date.getDate(); + var endDateNum = parsedRange[1].date.getDate(); + date.setDate(startDateNum + allDay - 1); // The bias can not over a month, so just compare date. + + var dateNum = date.getDate(); + + if (dateNum !== endDateNum) { + var sign = date.getTime() - parsedRange[1].time > 0 ? 1 : -1; + + while ((dateNum = date.getDate()) !== endDateNum && (date.getTime() - parsedRange[1].time) * sign > 0) { + allDay -= sign; + date.setDate(dateNum - sign); + } + } + + var weeks = Math.floor((allDay + parsedRange[0].day + 6) / 7); + var nthWeek = reversed ? -weeks + 1 : weeks - 1; + reversed && parsedRange.reverse(); + return { + range: [parsedRange[0].formatedDate, parsedRange[1].formatedDate], + start: parsedRange[0], + end: parsedRange[1], + allDay: allDay, + weeks: weeks, + // From 0. + nthWeek: nthWeek, + fweek: parsedRange[0].day, + lweek: parsedRange[1].day + }; + }; + /** + * get date by nthWeeks and week day in range + * + * @private + * @param {number} nthWeek the week + * @param {number} day the week day + * @param {Array} range [d1, d2] + * @return {Object} + */ + + + Calendar.prototype._getDateByWeeksAndDay = function (nthWeek, day, range) { + var rangeInfo = this._getRangeInfo(range); + + if (nthWeek > rangeInfo.weeks || nthWeek === 0 && day < rangeInfo.fweek || nthWeek === rangeInfo.weeks && day > rangeInfo.lweek) { + return null; + } + + var nthDay = (nthWeek - 1) * 7 - rangeInfo.fweek + day; + var date = new Date(rangeInfo.start.time); + date.setDate(+rangeInfo.start.d + nthDay); + return this.getDateInfo(date); + }; + + Calendar.create = function (ecModel, api) { + var calendarList = []; + ecModel.eachComponent('calendar', function (calendarModel) { + var calendar = new Calendar(calendarModel, ecModel, api); + calendarList.push(calendar); + calendarModel.coordinateSystem = calendar; + }); + ecModel.eachSeries(function (calendarSeries) { + if (calendarSeries.get('coordinateSystem') === 'calendar') { + // Inject coordinate system + calendarSeries.coordinateSystem = calendarList[calendarSeries.get('calendarIndex') || 0]; + } + }); + return calendarList; + }; + + Calendar.dimensions = ['time', 'value']; + return Calendar; + }(); + + function getCoordSys$4(finder) { + var calendarModel = finder.calendarModel; + var seriesModel = finder.seriesModel; + var coordSys = calendarModel ? calendarModel.coordinateSystem : seriesModel ? seriesModel.coordinateSystem : null; + return coordSys; + } + + function install$w(registers) { + registers.registerComponentModel(CalendarModel); + registers.registerComponentView(CalendarView); + registers.registerCoordinateSystem('calendar', Calendar); + } + + function setKeyInfoToNewElOption(resultItem, newElOption) { + var existElOption = resultItem.existing; // Set id and type after id assigned. + + newElOption.id = resultItem.keyInfo.id; + !newElOption.type && existElOption && (newElOption.type = existElOption.type); // Set parent id if not specified + + if (newElOption.parentId == null) { + var newElParentOption = newElOption.parentOption; + + if (newElParentOption) { + newElOption.parentId = newElParentOption.id; + } else if (existElOption) { + newElOption.parentId = existElOption.parentId; + } + } // Clear + + + newElOption.parentOption = null; + } + + function isSetLoc(obj, props) { + var isSet; + each(props, function (prop) { + obj[prop] != null && obj[prop] !== 'auto' && (isSet = true); + }); + return isSet; + } + + function mergeNewElOptionToExist(existList, index, newElOption) { + // Update existing options, for `getOption` feature. + var newElOptCopy = extend({}, newElOption); + var existElOption = existList[index]; + var $action = newElOption.$action || 'merge'; + + if ($action === 'merge') { + if (existElOption) { + if ("development" !== 'production') { + var newType = newElOption.type; + assert(!newType || existElOption.type === newType, 'Please set $action: "replace" to change `type`'); + } // We can ensure that newElOptCopy and existElOption are not + // the same object, so `merge` will not change newElOptCopy. + + + merge(existElOption, newElOptCopy, true); // Rigid body, use ignoreSize. + + mergeLayoutParam(existElOption, newElOptCopy, { + ignoreSize: true + }); // Will be used in render. + + copyLayoutParams(newElOption, existElOption); // Copy transition info to new option so it can be used in the transition. + // DO IT AFTER merge + + copyTransitionInfo(newElOption, existElOption); + copyTransitionInfo(newElOption, existElOption, 'shape'); + copyTransitionInfo(newElOption, existElOption, 'style'); + copyTransitionInfo(newElOption, existElOption, 'extra'); // Copy clipPath + + newElOption.clipPath = existElOption.clipPath; + } else { + existList[index] = newElOptCopy; + } + } else if ($action === 'replace') { + existList[index] = newElOptCopy; + } else if ($action === 'remove') { + // null will be cleaned later. + existElOption && (existList[index] = null); + } + } + + var TRANSITION_PROPS_TO_COPY = ['transition', 'enterFrom', 'leaveTo']; + var ROOT_TRANSITION_PROPS_TO_COPY = TRANSITION_PROPS_TO_COPY.concat(['enterAnimation', 'updateAnimation', 'leaveAnimation']); + + function copyTransitionInfo(target, source, targetProp) { + if (targetProp) { + if (!target[targetProp] && source[targetProp]) { + // TODO avoid creating this empty object when there is no transition configuration. + target[targetProp] = {}; + } + + target = target[targetProp]; + source = source[targetProp]; + } + + if (!target || !source) { + return; + } + + var props = targetProp ? TRANSITION_PROPS_TO_COPY : ROOT_TRANSITION_PROPS_TO_COPY; + + for (var i = 0; i < props.length; i++) { + var prop = props[i]; + + if (target[prop] == null && source[prop] != null) { + target[prop] = source[prop]; + } + } + } + + function setLayoutInfoToExist(existItem, newElOption) { + if (!existItem) { + return; + } + + existItem.hv = newElOption.hv = [// Rigid body, dont care `width`. + isSetLoc(newElOption, ['left', 'right']), // Rigid body, dont care `height`. + isSetLoc(newElOption, ['top', 'bottom'])]; // Give default group size. Otherwise layout error may occur. + + if (existItem.type === 'group') { + var existingGroupOpt = existItem; + var newGroupOpt = newElOption; + existingGroupOpt.width == null && (existingGroupOpt.width = newGroupOpt.width = 0); + existingGroupOpt.height == null && (existingGroupOpt.height = newGroupOpt.height = 0); + } + } + + var GraphicComponentModel = + /** @class */ + function (_super) { + __extends(GraphicComponentModel, _super); + + function GraphicComponentModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = GraphicComponentModel.type; + _this.preventAutoZ = true; + return _this; + } + + GraphicComponentModel.prototype.mergeOption = function (option, ecModel) { + // Prevent default merge to elements + var elements = this.option.elements; + this.option.elements = null; + + _super.prototype.mergeOption.call(this, option, ecModel); + + this.option.elements = elements; + }; + + GraphicComponentModel.prototype.optionUpdated = function (newOption, isInit) { + var thisOption = this.option; + var newList = (isInit ? thisOption : newOption).elements; + var existList = thisOption.elements = isInit ? [] : thisOption.elements; + var flattenedList = []; + + this._flatten(newList, flattenedList, null); + + var mappingResult = mappingToExists(existList, flattenedList, 'normalMerge'); // Clear elOptionsToUpdate + + var elOptionsToUpdate = this._elOptionsToUpdate = []; + each(mappingResult, function (resultItem, index) { + var newElOption = resultItem.newOption; + + if ("development" !== 'production') { + assert(isObject(newElOption) || resultItem.existing, 'Empty graphic option definition'); + } + + if (!newElOption) { + return; + } + + elOptionsToUpdate.push(newElOption); + setKeyInfoToNewElOption(resultItem, newElOption); + mergeNewElOptionToExist(existList, index, newElOption); + setLayoutInfoToExist(existList[index], newElOption); + }, this); // Clean + + thisOption.elements = filter(existList, function (item) { + // $action should be volatile, otherwise option gotten from + // `getOption` will contain unexpected $action. + item && delete item.$action; + return item != null; + }); + }; + /** + * Convert + * [{ + * type: 'group', + * id: 'xx', + * children: [{type: 'circle'}, {type: 'polygon'}] + * }] + * to + * [ + * {type: 'group', id: 'xx'}, + * {type: 'circle', parentId: 'xx'}, + * {type: 'polygon', parentId: 'xx'} + * ] + */ + + + GraphicComponentModel.prototype._flatten = function (optionList, result, parentOption) { + each(optionList, function (option) { + if (!option) { + return; + } + + if (parentOption) { + option.parentOption = parentOption; + } + + result.push(option); + var children = option.children; + + if (option.type === 'group' && children) { + this._flatten(children, result, option); + } // Deleting for JSON output, and for not affecting group creation. + + + delete option.children; + }, this); + }; // FIXME + // Pass to view using payload? setOption has a payload? + + + GraphicComponentModel.prototype.useElOptionsToUpdate = function () { + var els = this._elOptionsToUpdate; // Clear to avoid render duplicately when zooming. + + this._elOptionsToUpdate = null; + return els; + }; + + GraphicComponentModel.type = 'graphic'; + GraphicComponentModel.defaultOption = { + elements: [] // parentId: null + + }; + return GraphicComponentModel; + }(ComponentModel); + + var nonShapeGraphicElements = { + // Reserved but not supported in graphic component. + path: null, + compoundPath: null, + // Supported in graphic component. + group: Group, + image: ZRImage, + text: ZRText + }; + var inner$e = makeInner(); // ------------------------ + // View + // ------------------------ + + var GraphicComponentView = + /** @class */ + function (_super) { + __extends(GraphicComponentView, _super); + + function GraphicComponentView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = GraphicComponentView.type; + return _this; + } + + GraphicComponentView.prototype.init = function () { + this._elMap = createHashMap(); + }; + + GraphicComponentView.prototype.render = function (graphicModel, ecModel, api) { + // Having leveraged between use cases and algorithm complexity, a very + // simple layout mechanism is used: + // The size(width/height) can be determined by itself or its parent (not + // implemented yet), but can not by its children. (Top-down travel) + // The location(x/y) can be determined by the bounding rect of itself + // (can including its descendants or not) and the size of its parent. + // (Bottom-up travel) + // When `chart.clear()` or `chart.setOption({...}, true)` with the same id, + // view will be reused. + if (graphicModel !== this._lastGraphicModel) { + this._clear(); + } + + this._lastGraphicModel = graphicModel; + + this._updateElements(graphicModel); + + this._relocate(graphicModel, api); + }; + /** + * Update graphic elements. + */ + + + GraphicComponentView.prototype._updateElements = function (graphicModel) { + var elOptionsToUpdate = graphicModel.useElOptionsToUpdate(); + + if (!elOptionsToUpdate) { + return; + } + + var elMap = this._elMap; + var rootGroup = this.group; + var globalZ = graphicModel.get('z'); + var globalZLevel = graphicModel.get('zlevel'); // Top-down tranverse to assign graphic settings to each elements. + + each(elOptionsToUpdate, function (elOption) { + var id = convertOptionIdName(elOption.id, null); + var elExisting = id != null ? elMap.get(id) : null; + var parentId = convertOptionIdName(elOption.parentId, null); + var targetElParent = parentId != null ? elMap.get(parentId) : rootGroup; + var elType = elOption.type; + var elOptionStyle = elOption.style; + + if (elType === 'text' && elOptionStyle) { + // In top/bottom mode, textVerticalAlign should not be used, which cause + // inaccurately locating. + if (elOption.hv && elOption.hv[1]) { + elOptionStyle.textVerticalAlign = elOptionStyle.textBaseline = elOptionStyle.verticalAlign = elOptionStyle.align = null; + } + } + + var textContentOption = elOption.textContent; + var textConfig = elOption.textConfig; + + if (elOptionStyle && isEC4CompatibleStyle(elOptionStyle, elType, !!textConfig, !!textContentOption)) { + var convertResult = convertFromEC4CompatibleStyle(elOptionStyle, elType, true); + + if (!textConfig && convertResult.textConfig) { + textConfig = elOption.textConfig = convertResult.textConfig; + } + + if (!textContentOption && convertResult.textContent) { + textContentOption = convertResult.textContent; + } + } // Remove unnecessary props to avoid potential problems. + + + var elOptionCleaned = getCleanedElOption(elOption); // For simple, do not support parent change, otherwise reorder is needed. + + if ("development" !== 'production') { + elExisting && assert(targetElParent === elExisting.parent, 'Changing parent is not supported.'); + } + + var $action = elOption.$action || 'merge'; + var isMerge = $action === 'merge'; + var isReplace = $action === 'replace'; + + if (isMerge) { + var isInit = !elExisting; + var el_1 = elExisting; + + if (isInit) { + el_1 = createEl$1(id, targetElParent, elOption.type, elMap); + } else { + el_1 && (inner$e(el_1).isNew = false); // Stop and restore before update any other attributes. + + stopPreviousKeyframeAnimationAndRestore(el_1); + } + + if (el_1) { + applyUpdateTransition(el_1, elOptionCleaned, graphicModel, { + isInit: isInit + }); + updateCommonAttrs(el_1, elOption, globalZ, globalZLevel); + } + } else if (isReplace) { + removeEl(elExisting, elOption, elMap, graphicModel); + var el_2 = createEl$1(id, targetElParent, elOption.type, elMap); + + if (el_2) { + applyUpdateTransition(el_2, elOptionCleaned, graphicModel, { + isInit: true + }); + updateCommonAttrs(el_2, elOption, globalZ, globalZLevel); + } + } else if ($action === 'remove') { + updateLeaveTo(elExisting, elOption); + removeEl(elExisting, elOption, elMap, graphicModel); + } + + var el = elMap.get(id); + + if (el && textContentOption) { + if (isMerge) { + var textContentExisting = el.getTextContent(); + textContentExisting ? textContentExisting.attr(textContentOption) : el.setTextContent(new ZRText(textContentOption)); + } else if (isReplace) { + el.setTextContent(new ZRText(textContentOption)); + } + } + + if (el) { + var clipPathOption = elOption.clipPath; + + if (clipPathOption) { + var clipPathType = clipPathOption.type; + var clipPath = void 0; + var isInit = false; + + if (isMerge) { + var oldClipPath = el.getClipPath(); + isInit = !oldClipPath || inner$e(oldClipPath).type !== clipPathType; + clipPath = isInit ? newEl(clipPathType) : oldClipPath; + } else if (isReplace) { + isInit = true; + clipPath = newEl(clipPathType); + } + + el.setClipPath(clipPath); + applyUpdateTransition(clipPath, clipPathOption, graphicModel, { + isInit: isInit + }); + applyKeyframeAnimation(clipPath, clipPathOption.keyframeAnimation, graphicModel); + } + + var elInner = inner$e(el); + el.setTextConfig(textConfig); + elInner.option = elOption; + setEventData(el, graphicModel, elOption); + setTooltipConfig({ + el: el, + componentModel: graphicModel, + itemName: el.name, + itemTooltipOption: elOption.tooltip + }); + applyKeyframeAnimation(el, elOption.keyframeAnimation, graphicModel); + } + }); + }; + /** + * Locate graphic elements. + */ + + + GraphicComponentView.prototype._relocate = function (graphicModel, api) { + var elOptions = graphicModel.option.elements; + var rootGroup = this.group; + var elMap = this._elMap; + var apiWidth = api.getWidth(); + var apiHeight = api.getHeight(); + var xy = ['x', 'y']; // Top-down to calculate percentage width/height of group + + for (var i = 0; i < elOptions.length; i++) { + var elOption = elOptions[i]; + var id = convertOptionIdName(elOption.id, null); + var el = id != null ? elMap.get(id) : null; + + if (!el || !el.isGroup) { + continue; + } + + var parentEl = el.parent; + var isParentRoot = parentEl === rootGroup; // Like 'position:absolut' in css, default 0. + + var elInner = inner$e(el); + var parentElInner = inner$e(parentEl); + elInner.width = parsePercent$1(elInner.option.width, isParentRoot ? apiWidth : parentElInner.width) || 0; + elInner.height = parsePercent$1(elInner.option.height, isParentRoot ? apiHeight : parentElInner.height) || 0; + } // Bottom-up tranvese all elements (consider ec resize) to locate elements. + + + for (var i = elOptions.length - 1; i >= 0; i--) { + var elOption = elOptions[i]; + var id = convertOptionIdName(elOption.id, null); + var el = id != null ? elMap.get(id) : null; + + if (!el) { + continue; + } + + var parentEl = el.parent; + var parentElInner = inner$e(parentEl); + var containerInfo = parentEl === rootGroup ? { + width: apiWidth, + height: apiHeight + } : { + width: parentElInner.width, + height: parentElInner.height + }; // PENDING + // Currently, when `bounding: 'all'`, the union bounding rect of the group + // does not include the rect of [0, 0, group.width, group.height], which + // is probably weird for users. Should we make a break change for it? + + var layoutPos = {}; + var layouted = positionElement(el, elOption, containerInfo, null, { + hv: elOption.hv, + boundingMode: elOption.bounding + }, layoutPos); + + if (!inner$e(el).isNew && layouted) { + var transition = elOption.transition; + var animatePos = {}; + + for (var k = 0; k < xy.length; k++) { + var key = xy[k]; + var val = layoutPos[key]; + + if (transition && (isTransitionAll(transition) || indexOf(transition, key) >= 0)) { + animatePos[key] = val; + } else { + el[key] = val; + } + } + + updateProps(el, animatePos, graphicModel, 0); + } else { + el.attr(layoutPos); + } + } + }; + /** + * Clear all elements. + */ + + + GraphicComponentView.prototype._clear = function () { + var _this = this; + + var elMap = this._elMap; + elMap.each(function (el) { + removeEl(el, inner$e(el).option, elMap, _this._lastGraphicModel); + }); + this._elMap = createHashMap(); + }; + + GraphicComponentView.prototype.dispose = function () { + this._clear(); + }; + + GraphicComponentView.type = 'graphic'; + return GraphicComponentView; + }(ComponentView); + + function newEl(graphicType) { + if ("development" !== 'production') { + assert(graphicType, 'graphic type MUST be set'); + } + + var Clz = hasOwn(nonShapeGraphicElements, graphicType) // Those graphic elements are not shapes. They should not be + // overwritten by users, so do them first. + ? nonShapeGraphicElements[graphicType] : getShapeClass(graphicType); + + if ("development" !== 'production') { + assert(Clz, "graphic type " + graphicType + " can not be found"); + } + + var el = new Clz({}); + inner$e(el).type = graphicType; + return el; + } + + function createEl$1(id, targetElParent, graphicType, elMap) { + var el = newEl(graphicType); + targetElParent.add(el); + elMap.set(id, el); + inner$e(el).id = id; + inner$e(el).isNew = true; + return el; + } + + function removeEl(elExisting, elOption, elMap, graphicModel) { + var existElParent = elExisting && elExisting.parent; + + if (existElParent) { + elExisting.type === 'group' && elExisting.traverse(function (el) { + removeEl(el, elOption, elMap, graphicModel); + }); + applyLeaveTransition(elExisting, elOption, graphicModel); + elMap.removeKey(inner$e(elExisting).id); + } + } + + function updateCommonAttrs(el, elOption, defaultZ, defaultZlevel) { + if (!el.isGroup) { + var elDisplayable = el; + elDisplayable.cursor = retrieve2(elOption.cursor, Displayable.prototype.cursor); // We should not support configure z and zlevel in the element level. + // But seems we didn't limit it previously. So here still use it to avoid breaking. + + elDisplayable.z = retrieve2(elOption.z, defaultZ || 0); + elDisplayable.zlevel = retrieve2(elOption.zlevel, defaultZlevel || 0); // z2 must not be null/undefined, otherwise sort error may occur. + + var optZ2 = elOption.z2; + optZ2 != null && (elDisplayable.z2 = optZ2 || 0); + } + + each(keys(elOption), function (key) { + var val = elOption[key]; // Assign event handlers. + // PENDING: should enumerate all event names or use pattern matching? + + if (key.indexOf('on') === 0 && isFunction(val)) { + el[key] = val; + } + }); + el.draggable = elOption.draggable; // Other attributes + + elOption.name != null && (el.name = elOption.name); + elOption.id != null && (el.id = elOption.id); + } // Remove unnecessary props to avoid potential problems. + + + function getCleanedElOption(elOption) { + elOption = extend({}, elOption); + each(['id', 'parentId', '$action', 'hv', 'bounding', 'textContent', 'clipPath'].concat(LOCATION_PARAMS), function (name) { + delete elOption[name]; + }); + return elOption; + } + + function setEventData(el, graphicModel, elOption) { + var eventData = getECData(el).eventData; // Simple optimize for large amount of elements that no need event. + + if (!el.silent && !el.ignore && !eventData) { + eventData = getECData(el).eventData = { + componentType: 'graphic', + componentIndex: graphicModel.componentIndex, + name: el.name + }; + } // `elOption.info` enables user to mount some info on + // elements and use them in event handlers. + + + if (eventData) { + eventData.info = elOption.info; + } + } + + function install$x(registers) { + registers.registerComponentModel(GraphicComponentModel); + registers.registerComponentView(GraphicComponentView); + registers.registerPreprocessor(function (option) { + var graphicOption = option.graphic; // Convert + // {graphic: [{left: 10, type: 'circle'}, ...]} + // or + // {graphic: {left: 10, type: 'circle'}} + // to + // {graphic: [{elements: [{left: 10, type: 'circle'}, ...]}]} + + if (isArray(graphicOption)) { + if (!graphicOption[0] || !graphicOption[0].elements) { + option.graphic = [{ + elements: graphicOption + }]; + } else { + // Only one graphic instance can be instantiated. (We dont + // want that too many views are created in echarts._viewMap) + option.graphic = [option.graphic[0]]; + } + } else if (graphicOption && !graphicOption.elements) { + option.graphic = [{ + elements: [graphicOption] + }]; + } + }); + } + + var DATA_ZOOM_AXIS_DIMENSIONS = ['x', 'y', 'radius', 'angle', 'single']; // Supported coords. + // FIXME: polar has been broken (but rarely used). + + var SERIES_COORDS = ['cartesian2d', 'polar', 'singleAxis']; + function isCoordSupported(seriesModel) { + var coordType = seriesModel.get('coordinateSystem'); + return indexOf(SERIES_COORDS, coordType) >= 0; + } + function getAxisMainType(axisDim) { + if ("development" !== 'production') { + assert(axisDim); + } + + return axisDim + 'Axis'; + } + /** + * If two dataZoomModels has the same axis controlled, we say that they are 'linked'. + * This function finds all linked dataZoomModels start from the given payload. + */ + + function findEffectedDataZooms(ecModel, payload) { + // Key: `DataZoomAxisDimension` + var axisRecords = createHashMap(); + var effectedModels = []; // Key: uid of dataZoomModel + + var effectedModelMap = createHashMap(); // Find the dataZooms specified by payload. + + ecModel.eachComponent({ + mainType: 'dataZoom', + query: payload + }, function (dataZoomModel) { + if (!effectedModelMap.get(dataZoomModel.uid)) { + addToEffected(dataZoomModel); + } + }); // Start from the given dataZoomModels, travel the graph to find + // all of the linked dataZoom models. + + var foundNewLink; + + do { + foundNewLink = false; + ecModel.eachComponent('dataZoom', processSingle); + } while (foundNewLink); + + function processSingle(dataZoomModel) { + if (!effectedModelMap.get(dataZoomModel.uid) && isLinked(dataZoomModel)) { + addToEffected(dataZoomModel); + foundNewLink = true; + } + } + + function addToEffected(dataZoom) { + effectedModelMap.set(dataZoom.uid, true); + effectedModels.push(dataZoom); + markAxisControlled(dataZoom); + } + + function isLinked(dataZoomModel) { + var isLink = false; + dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) { + var axisIdxArr = axisRecords.get(axisDim); + + if (axisIdxArr && axisIdxArr[axisIndex]) { + isLink = true; + } + }); + return isLink; + } + + function markAxisControlled(dataZoomModel) { + dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) { + (axisRecords.get(axisDim) || axisRecords.set(axisDim, []))[axisIndex] = true; + }); + } + + return effectedModels; + } + /** + * Find the first target coordinate system. + * Available after model built. + * + * @return Like { + * grid: [ + * {model: coord0, axisModels: [axis1, axis3], coordIndex: 1}, + * {model: coord1, axisModels: [axis0, axis2], coordIndex: 0}, + * ... + * ], // cartesians must not be null/undefined. + * polar: [ + * {model: coord0, axisModels: [axis4], coordIndex: 0}, + * ... + * ], // polars must not be null/undefined. + * singleAxis: [ + * {model: coord0, axisModels: [], coordIndex: 0} + * ] + * } + */ + + function collectReferCoordSysModelInfo(dataZoomModel) { + var ecModel = dataZoomModel.ecModel; + var coordSysInfoWrap = { + infoList: [], + infoMap: createHashMap() + }; + dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) { + var axisModel = ecModel.getComponent(getAxisMainType(axisDim), axisIndex); + + if (!axisModel) { + return; + } + + var coordSysModel = axisModel.getCoordSysModel(); + + if (!coordSysModel) { + return; + } + + var coordSysUid = coordSysModel.uid; + var coordSysInfo = coordSysInfoWrap.infoMap.get(coordSysUid); + + if (!coordSysInfo) { + coordSysInfo = { + model: coordSysModel, + axisModels: [] + }; + coordSysInfoWrap.infoList.push(coordSysInfo); + coordSysInfoWrap.infoMap.set(coordSysUid, coordSysInfo); + } + + coordSysInfo.axisModels.push(axisModel); + }); + return coordSysInfoWrap; + } + + var DataZoomAxisInfo = + /** @class */ + function () { + function DataZoomAxisInfo() { + this.indexList = []; + this.indexMap = []; + } + + DataZoomAxisInfo.prototype.add = function (axisCmptIdx) { + // Remove duplication. + if (!this.indexMap[axisCmptIdx]) { + this.indexList.push(axisCmptIdx); + this.indexMap[axisCmptIdx] = true; + } + }; + + return DataZoomAxisInfo; + }(); + + var DataZoomModel = + /** @class */ + function (_super) { + __extends(DataZoomModel, _super); + + function DataZoomModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = DataZoomModel.type; + _this._autoThrottle = true; + _this._noTarget = true; + /** + * It is `[rangeModeForMin, rangeModeForMax]`. + * The optional values for `rangeMode`: + * + `'value'` mode: the axis extent will always be determined by + * `dataZoom.startValue` and `dataZoom.endValue`, despite + * how data like and how `axis.min` and `axis.max` are. + * + `'percent'` mode: `100` represents 100% of the `[dMin, dMax]`, + * where `dMin` is `axis.min` if `axis.min` specified, otherwise `data.extent[0]`, + * and `dMax` is `axis.max` if `axis.max` specified, otherwise `data.extent[1]`. + * Axis extent will be determined by the result of the percent of `[dMin, dMax]`. + * + * For example, when users are using dynamic data (update data periodically via `setOption`), + * if in `'value`' mode, the window will be kept in a fixed value range despite how + * data are appended, while if in `'percent'` mode, whe window range will be changed alone with + * the appended data (suppose `axis.min` and `axis.max` are not specified). + */ + + _this._rangePropMode = ['percent', 'percent']; + return _this; + } + + DataZoomModel.prototype.init = function (option, parentModel, ecModel) { + var inputRawOption = retrieveRawOption(option); + /** + * Suppose a "main process" start at the point that model prepared (that is, + * model initialized or merged or method called in `action`). + * We should keep the `main process` idempotent, that is, given a set of values + * on `option`, we get the same result. + * + * But sometimes, values on `option` will be updated for providing users + * a "final calculated value" (`dataZoomProcessor` will do that). Those value + * should not be the base/input of the `main process`. + * + * So in that case we should save and keep the input of the `main process` + * separately, called `settledOption`. + * + * For example, consider the case: + * (Step_1) brush zoom the grid by `toolbox.dataZoom`, + * where the original input `option.startValue`, `option.endValue` are earsed by + * calculated value. + * (Step)2) click the legend to hide and show a series, + * where the new range is calculated by the earsed `startValue` and `endValue`, + * which brings incorrect result. + */ + + this.settledOption = inputRawOption; + this.mergeDefaultAndTheme(option, ecModel); + + this._doInit(inputRawOption); + }; + + DataZoomModel.prototype.mergeOption = function (newOption) { + var inputRawOption = retrieveRawOption(newOption); //FIX #2591 + + merge(this.option, newOption, true); + merge(this.settledOption, inputRawOption, true); + + this._doInit(inputRawOption); + }; + + DataZoomModel.prototype._doInit = function (inputRawOption) { + var thisOption = this.option; + + this._setDefaultThrottle(inputRawOption); + + this._updateRangeUse(inputRawOption); + + var settledOption = this.settledOption; + each([['start', 'startValue'], ['end', 'endValue']], function (names, index) { + // start/end has higher priority over startValue/endValue if they + // both set, but we should make chart.setOption({endValue: 1000}) + // effective, rather than chart.setOption({endValue: 1000, end: null}). + if (this._rangePropMode[index] === 'value') { + thisOption[names[0]] = settledOption[names[0]] = null; + } // Otherwise do nothing and use the merge result. + + }, this); + + this._resetTarget(); + }; + + DataZoomModel.prototype._resetTarget = function () { + var optionOrient = this.get('orient', true); + var targetAxisIndexMap = this._targetAxisInfoMap = createHashMap(); + + var hasAxisSpecified = this._fillSpecifiedTargetAxis(targetAxisIndexMap); + + if (hasAxisSpecified) { + this._orient = optionOrient || this._makeAutoOrientByTargetAxis(); + } else { + this._orient = optionOrient || 'horizontal'; + + this._fillAutoTargetAxisByOrient(targetAxisIndexMap, this._orient); + } + + this._noTarget = true; + targetAxisIndexMap.each(function (axisInfo) { + if (axisInfo.indexList.length) { + this._noTarget = false; + } + }, this); + }; + + DataZoomModel.prototype._fillSpecifiedTargetAxis = function (targetAxisIndexMap) { + var hasAxisSpecified = false; + each(DATA_ZOOM_AXIS_DIMENSIONS, function (axisDim) { + var refering = this.getReferringComponents(getAxisMainType(axisDim), MULTIPLE_REFERRING); // When user set axisIndex as a empty array, we think that user specify axisIndex + // but do not want use auto mode. Because empty array may be encountered when + // some error occured. + + if (!refering.specified) { + return; + } + + hasAxisSpecified = true; + var axisInfo = new DataZoomAxisInfo(); + each(refering.models, function (axisModel) { + axisInfo.add(axisModel.componentIndex); + }); + targetAxisIndexMap.set(axisDim, axisInfo); + }, this); + return hasAxisSpecified; + }; + + DataZoomModel.prototype._fillAutoTargetAxisByOrient = function (targetAxisIndexMap, orient) { + var ecModel = this.ecModel; + var needAuto = true; // Find axis that parallel to dataZoom as default. + + if (needAuto) { + var axisDim = orient === 'vertical' ? 'y' : 'x'; + var axisModels = ecModel.findComponents({ + mainType: axisDim + 'Axis' + }); + setParallelAxis(axisModels, axisDim); + } // Find axis that parallel to dataZoom as default. + + + if (needAuto) { + var axisModels = ecModel.findComponents({ + mainType: 'singleAxis', + filter: function (axisModel) { + return axisModel.get('orient', true) === orient; + } + }); + setParallelAxis(axisModels, 'single'); + } + + function setParallelAxis(axisModels, axisDim) { + // At least use the first parallel axis as the target axis. + var axisModel = axisModels[0]; + + if (!axisModel) { + return; + } + + var axisInfo = new DataZoomAxisInfo(); + axisInfo.add(axisModel.componentIndex); + targetAxisIndexMap.set(axisDim, axisInfo); + needAuto = false; // Find parallel axes in the same grid. + + if (axisDim === 'x' || axisDim === 'y') { + var gridModel_1 = axisModel.getReferringComponents('grid', SINGLE_REFERRING).models[0]; + gridModel_1 && each(axisModels, function (axModel) { + if (axisModel.componentIndex !== axModel.componentIndex && gridModel_1 === axModel.getReferringComponents('grid', SINGLE_REFERRING).models[0]) { + axisInfo.add(axModel.componentIndex); + } + }); + } + } + + if (needAuto) { + // If no parallel axis, find the first category axis as default. (Also consider polar). + each(DATA_ZOOM_AXIS_DIMENSIONS, function (axisDim) { + if (!needAuto) { + return; + } + + var axisModels = ecModel.findComponents({ + mainType: getAxisMainType(axisDim), + filter: function (axisModel) { + return axisModel.get('type', true) === 'category'; + } + }); + + if (axisModels[0]) { + var axisInfo = new DataZoomAxisInfo(); + axisInfo.add(axisModels[0].componentIndex); + targetAxisIndexMap.set(axisDim, axisInfo); + needAuto = false; + } + }, this); + } + }; + + DataZoomModel.prototype._makeAutoOrientByTargetAxis = function () { + var dim; // Find the first axis + + this.eachTargetAxis(function (axisDim) { + !dim && (dim = axisDim); + }, this); + return dim === 'y' ? 'vertical' : 'horizontal'; + }; + + DataZoomModel.prototype._setDefaultThrottle = function (inputRawOption) { + // When first time user set throttle, auto throttle ends. + if (inputRawOption.hasOwnProperty('throttle')) { + this._autoThrottle = false; + } + + if (this._autoThrottle) { + var globalOption = this.ecModel.option; + this.option.throttle = globalOption.animation && globalOption.animationDurationUpdate > 0 ? 100 : 20; + } + }; + + DataZoomModel.prototype._updateRangeUse = function (inputRawOption) { + var rangePropMode = this._rangePropMode; + var rangeModeInOption = this.get('rangeMode'); + each([['start', 'startValue'], ['end', 'endValue']], function (names, index) { + var percentSpecified = inputRawOption[names[0]] != null; + var valueSpecified = inputRawOption[names[1]] != null; + + if (percentSpecified && !valueSpecified) { + rangePropMode[index] = 'percent'; + } else if (!percentSpecified && valueSpecified) { + rangePropMode[index] = 'value'; + } else if (rangeModeInOption) { + rangePropMode[index] = rangeModeInOption[index]; + } else if (percentSpecified) { + // percentSpecified && valueSpecified + rangePropMode[index] = 'percent'; + } // else remain its original setting. + + }); + }; + + DataZoomModel.prototype.noTarget = function () { + return this._noTarget; + }; + + DataZoomModel.prototype.getFirstTargetAxisModel = function () { + var firstAxisModel; + this.eachTargetAxis(function (axisDim, axisIndex) { + if (firstAxisModel == null) { + firstAxisModel = this.ecModel.getComponent(getAxisMainType(axisDim), axisIndex); + } + }, this); + return firstAxisModel; + }; + /** + * @param {Function} callback param: axisModel, dimNames, axisIndex, dataZoomModel, ecModel + */ + + + DataZoomModel.prototype.eachTargetAxis = function (callback, context) { + this._targetAxisInfoMap.each(function (axisInfo, axisDim) { + each(axisInfo.indexList, function (axisIndex) { + callback.call(context, axisDim, axisIndex); + }); + }); + }; + /** + * @return If not found, return null/undefined. + */ + + + DataZoomModel.prototype.getAxisProxy = function (axisDim, axisIndex) { + var axisModel = this.getAxisModel(axisDim, axisIndex); + + if (axisModel) { + return axisModel.__dzAxisProxy; + } + }; + /** + * @return If not found, return null/undefined. + */ + + + DataZoomModel.prototype.getAxisModel = function (axisDim, axisIndex) { + if ("development" !== 'production') { + assert(axisDim && axisIndex != null); + } + + var axisInfo = this._targetAxisInfoMap.get(axisDim); + + if (axisInfo && axisInfo.indexMap[axisIndex]) { + return this.ecModel.getComponent(getAxisMainType(axisDim), axisIndex); + } + }; + /** + * If not specified, set to undefined. + */ + + + DataZoomModel.prototype.setRawRange = function (opt) { + var thisOption = this.option; + var settledOption = this.settledOption; + each([['start', 'startValue'], ['end', 'endValue']], function (names) { + // Consider the pair : + // If one has value and the other one is `null/undefined`, we both set them + // to `settledOption`. This strategy enables the feature to clear the original + // value in `settledOption` to `null/undefined`. + // But if both of them are `null/undefined`, we do not set them to `settledOption` + // and keep `settledOption` with the original value. This strategy enables users to + // only set but not set when calling + // `dispatchAction`. + // The pair is treated in the same way. + if (opt[names[0]] != null || opt[names[1]] != null) { + thisOption[names[0]] = settledOption[names[0]] = opt[names[0]]; + thisOption[names[1]] = settledOption[names[1]] = opt[names[1]]; + } + }, this); + + this._updateRangeUse(opt); + }; + + DataZoomModel.prototype.setCalculatedRange = function (opt) { + var option = this.option; + each(['start', 'startValue', 'end', 'endValue'], function (name) { + option[name] = opt[name]; + }); + }; + + DataZoomModel.prototype.getPercentRange = function () { + var axisProxy = this.findRepresentativeAxisProxy(); + + if (axisProxy) { + return axisProxy.getDataPercentWindow(); + } + }; + /** + * For example, chart.getModel().getComponent('dataZoom').getValueRange('y', 0); + * + * @return [startValue, endValue] value can only be '-' or finite number. + */ + + + DataZoomModel.prototype.getValueRange = function (axisDim, axisIndex) { + if (axisDim == null && axisIndex == null) { + var axisProxy = this.findRepresentativeAxisProxy(); + + if (axisProxy) { + return axisProxy.getDataValueWindow(); + } + } else { + return this.getAxisProxy(axisDim, axisIndex).getDataValueWindow(); + } + }; + /** + * @param axisModel If axisModel given, find axisProxy + * corresponding to the axisModel + */ + + + DataZoomModel.prototype.findRepresentativeAxisProxy = function (axisModel) { + if (axisModel) { + return axisModel.__dzAxisProxy; + } // Find the first hosted axisProxy + + + var firstProxy; + + var axisDimList = this._targetAxisInfoMap.keys(); + + for (var i = 0; i < axisDimList.length; i++) { + var axisDim = axisDimList[i]; + + var axisInfo = this._targetAxisInfoMap.get(axisDim); + + for (var j = 0; j < axisInfo.indexList.length; j++) { + var proxy = this.getAxisProxy(axisDim, axisInfo.indexList[j]); + + if (proxy.hostedBy(this)) { + return proxy; + } + + if (!firstProxy) { + firstProxy = proxy; + } + } + } // If no hosted proxy found, still need to return a proxy. + // This case always happens in toolbox dataZoom, where axes are all hosted by + // other dataZooms. + + + return firstProxy; + }; + + DataZoomModel.prototype.getRangePropMode = function () { + return this._rangePropMode.slice(); + }; + + DataZoomModel.prototype.getOrient = function () { + if ("development" !== 'production') { + // Should not be called before initialized. + assert(this._orient); + } + + return this._orient; + }; + + DataZoomModel.type = 'dataZoom'; + DataZoomModel.dependencies = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'series', 'toolbox']; + DataZoomModel.defaultOption = { + // zlevel: 0, + z: 4, + filterMode: 'filter', + start: 0, + end: 100 + }; + return DataZoomModel; + }(ComponentModel); + /** + * Retrieve the those raw params from option, which will be cached separately. + * becasue they will be overwritten by normalized/calculated values in the main + * process. + */ + + + function retrieveRawOption(option) { + var ret = {}; + each(['start', 'end', 'startValue', 'endValue', 'throttle'], function (name) { + option.hasOwnProperty(name) && (ret[name] = option[name]); + }); + return ret; + } + + var SelectDataZoomModel = + /** @class */ + function (_super) { + __extends(SelectDataZoomModel, _super); + + function SelectDataZoomModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = SelectDataZoomModel.type; + return _this; + } + + SelectDataZoomModel.type = 'dataZoom.select'; + return SelectDataZoomModel; + }(DataZoomModel); + + var DataZoomView = + /** @class */ + function (_super) { + __extends(DataZoomView, _super); + + function DataZoomView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = DataZoomView.type; + return _this; + } + + DataZoomView.prototype.render = function (dataZoomModel, ecModel, api, payload) { + this.dataZoomModel = dataZoomModel; + this.ecModel = ecModel; + this.api = api; + }; + + DataZoomView.type = 'dataZoom'; + return DataZoomView; + }(ComponentView); + + var SelectDataZoomView = + /** @class */ + function (_super) { + __extends(SelectDataZoomView, _super); + + function SelectDataZoomView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = SelectDataZoomView.type; + return _this; + } + + SelectDataZoomView.type = 'dataZoom.select'; + return SelectDataZoomView; + }(DataZoomView); + + var each$8 = each; + var asc$1 = asc; + /** + * Operate single axis. + * One axis can only operated by one axis operator. + * Different dataZoomModels may be defined to operate the same axis. + * (i.e. 'inside' data zoom and 'slider' data zoom components) + * So dataZoomModels share one axisProxy in that case. + */ + + var AxisProxy = + /** @class */ + function () { + function AxisProxy(dimName, axisIndex, dataZoomModel, ecModel) { + this._dimName = dimName; + this._axisIndex = axisIndex; + this.ecModel = ecModel; + this._dataZoomModel = dataZoomModel; // /** + // * @readOnly + // * @private + // */ + // this.hasSeriesStacked; + } + /** + * Whether the axisProxy is hosted by dataZoomModel. + */ + + + AxisProxy.prototype.hostedBy = function (dataZoomModel) { + return this._dataZoomModel === dataZoomModel; + }; + /** + * @return Value can only be NaN or finite value. + */ + + + AxisProxy.prototype.getDataValueWindow = function () { + return this._valueWindow.slice(); + }; + /** + * @return {Array.} + */ + + + AxisProxy.prototype.getDataPercentWindow = function () { + return this._percentWindow.slice(); + }; + + AxisProxy.prototype.getTargetSeriesModels = function () { + var seriesModels = []; + this.ecModel.eachSeries(function (seriesModel) { + if (isCoordSupported(seriesModel)) { + var axisMainType = getAxisMainType(this._dimName); + var axisModel = seriesModel.getReferringComponents(axisMainType, SINGLE_REFERRING).models[0]; + + if (axisModel && this._axisIndex === axisModel.componentIndex) { + seriesModels.push(seriesModel); + } + } + }, this); + return seriesModels; + }; + + AxisProxy.prototype.getAxisModel = function () { + return this.ecModel.getComponent(this._dimName + 'Axis', this._axisIndex); + }; + + AxisProxy.prototype.getMinMaxSpan = function () { + return clone(this._minMaxSpan); + }; + /** + * Only calculate by given range and this._dataExtent, do not change anything. + */ + + + AxisProxy.prototype.calculateDataWindow = function (opt) { + var dataExtent = this._dataExtent; + var axisModel = this.getAxisModel(); + var scale = axisModel.axis.scale; + + var rangePropMode = this._dataZoomModel.getRangePropMode(); + + var percentExtent = [0, 100]; + var percentWindow = []; + var valueWindow = []; + var hasPropModeValue; + each$8(['start', 'end'], function (prop, idx) { + var boundPercent = opt[prop]; + var boundValue = opt[prop + 'Value']; // Notice: dataZoom is based either on `percentProp` ('start', 'end') or + // on `valueProp` ('startValue', 'endValue'). (They are based on the data extent + // but not min/max of axis, which will be calculated by data window then). + // The former one is suitable for cases that a dataZoom component controls multiple + // axes with different unit or extent, and the latter one is suitable for accurate + // zoom by pixel (e.g., in dataZoomSelect). + // we use `getRangePropMode()` to mark which prop is used. `rangePropMode` is updated + // only when setOption or dispatchAction, otherwise it remains its original value. + // (Why not only record `percentProp` and always map to `valueProp`? Because + // the map `valueProp` -> `percentProp` -> `valueProp` probably not the original + // `valueProp`. consider two axes constrolled by one dataZoom. They have different + // data extent. All of values that are overflow the `dataExtent` will be calculated + // to percent '100%'). + + if (rangePropMode[idx] === 'percent') { + boundPercent == null && (boundPercent = percentExtent[idx]); // Use scale.parse to math round for category or time axis. + + boundValue = scale.parse(linearMap(boundPercent, percentExtent, dataExtent)); + } else { + hasPropModeValue = true; + boundValue = boundValue == null ? dataExtent[idx] : scale.parse(boundValue); // Calculating `percent` from `value` may be not accurate, because + // This calculation can not be inversed, because all of values that + // are overflow the `dataExtent` will be calculated to percent '100%' + + boundPercent = linearMap(boundValue, dataExtent, percentExtent); + } // valueWindow[idx] = round(boundValue); + // percentWindow[idx] = round(boundPercent); + + + valueWindow[idx] = boundValue; + percentWindow[idx] = boundPercent; + }); + asc$1(valueWindow); + asc$1(percentWindow); // The windows from user calling of `dispatchAction` might be out of the extent, + // or do not obey the `min/maxSpan`, `min/maxValueSpan`. But we dont restrict window + // by `zoomLock` here, because we see `zoomLock` just as a interaction constraint, + // where API is able to initialize/modify the window size even though `zoomLock` + // specified. + + var spans = this._minMaxSpan; + hasPropModeValue ? restrictSet(valueWindow, percentWindow, dataExtent, percentExtent, false) : restrictSet(percentWindow, valueWindow, percentExtent, dataExtent, true); + + function restrictSet(fromWindow, toWindow, fromExtent, toExtent, toValue) { + var suffix = toValue ? 'Span' : 'ValueSpan'; + sliderMove(0, fromWindow, fromExtent, 'all', spans['min' + suffix], spans['max' + suffix]); + + for (var i = 0; i < 2; i++) { + toWindow[i] = linearMap(fromWindow[i], fromExtent, toExtent, true); + toValue && (toWindow[i] = scale.parse(toWindow[i])); + } + } + + return { + valueWindow: valueWindow, + percentWindow: percentWindow + }; + }; + /** + * Notice: reset should not be called before series.restoreData() called, + * so it is recommanded to be called in "process stage" but not "model init + * stage". + */ + + + AxisProxy.prototype.reset = function (dataZoomModel) { + if (dataZoomModel !== this._dataZoomModel) { + return; + } + + var targetSeries = this.getTargetSeriesModels(); // Culculate data window and data extent, and record them. + + this._dataExtent = calculateDataExtent(this, this._dimName, targetSeries); // `calculateDataWindow` uses min/maxSpan. + + this._updateMinMaxSpan(); + + var dataWindow = this.calculateDataWindow(dataZoomModel.settledOption); + this._valueWindow = dataWindow.valueWindow; + this._percentWindow = dataWindow.percentWindow; // Update axis setting then. + + this._setAxisModel(); + }; + + AxisProxy.prototype.filterData = function (dataZoomModel, api) { + if (dataZoomModel !== this._dataZoomModel) { + return; + } + + var axisDim = this._dimName; + var seriesModels = this.getTargetSeriesModels(); + var filterMode = dataZoomModel.get('filterMode'); + var valueWindow = this._valueWindow; + + if (filterMode === 'none') { + return; + } // FIXME + // Toolbox may has dataZoom injected. And if there are stacked bar chart + // with NaN data, NaN will be filtered and stack will be wrong. + // So we need to force the mode to be set empty. + // In fect, it is not a big deal that do not support filterMode-'filter' + // when using toolbox#dataZoom, utill tooltip#dataZoom support "single axis + // selection" some day, which might need "adapt to data extent on the + // otherAxis", which is disabled by filterMode-'empty'. + // But currently, stack has been fixed to based on value but not index, + // so this is not an issue any more. + // let otherAxisModel = this.getOtherAxisModel(); + // if (dataZoomModel.get('$fromToolbox') + // && otherAxisModel + // && otherAxisModel.hasSeriesStacked + // ) { + // filterMode = 'empty'; + // } + // TODO + // filterMode 'weakFilter' and 'empty' is not optimized for huge data yet. + + + each$8(seriesModels, function (seriesModel) { + var seriesData = seriesModel.getData(); + var dataDims = seriesData.mapDimensionsAll(axisDim); + + if (!dataDims.length) { + return; + } + + if (filterMode === 'weakFilter') { + var store_1 = seriesData.getStore(); + var dataDimIndices_1 = map(dataDims, function (dim) { + return seriesData.getDimensionIndex(dim); + }, seriesData); + seriesData.filterSelf(function (dataIndex) { + var leftOut; + var rightOut; + var hasValue; + + for (var i = 0; i < dataDims.length; i++) { + var value = store_1.get(dataDimIndices_1[i], dataIndex); + var thisHasValue = !isNaN(value); + var thisLeftOut = value < valueWindow[0]; + var thisRightOut = value > valueWindow[1]; + + if (thisHasValue && !thisLeftOut && !thisRightOut) { + return true; + } + + thisHasValue && (hasValue = true); + thisLeftOut && (leftOut = true); + thisRightOut && (rightOut = true); + } // If both left out and right out, do not filter. + + + return hasValue && leftOut && rightOut; + }); + } else { + each$8(dataDims, function (dim) { + if (filterMode === 'empty') { + seriesModel.setData(seriesData = seriesData.map(dim, function (value) { + return !isInWindow(value) ? NaN : value; + })); + } else { + var range = {}; + range[dim] = valueWindow; // console.time('select'); + + seriesData.selectRange(range); // console.timeEnd('select'); + } + }); + } + + each$8(dataDims, function (dim) { + seriesData.setApproximateExtent(valueWindow, dim); + }); + }); + + function isInWindow(value) { + return value >= valueWindow[0] && value <= valueWindow[1]; + } + }; + + AxisProxy.prototype._updateMinMaxSpan = function () { + var minMaxSpan = this._minMaxSpan = {}; + var dataZoomModel = this._dataZoomModel; + var dataExtent = this._dataExtent; + each$8(['min', 'max'], function (minMax) { + var percentSpan = dataZoomModel.get(minMax + 'Span'); + var valueSpan = dataZoomModel.get(minMax + 'ValueSpan'); + valueSpan != null && (valueSpan = this.getAxisModel().axis.scale.parse(valueSpan)); // minValueSpan and maxValueSpan has higher priority than minSpan and maxSpan + + if (valueSpan != null) { + percentSpan = linearMap(dataExtent[0] + valueSpan, dataExtent, [0, 100], true); + } else if (percentSpan != null) { + valueSpan = linearMap(percentSpan, [0, 100], dataExtent, true) - dataExtent[0]; + } + + minMaxSpan[minMax + 'Span'] = percentSpan; + minMaxSpan[minMax + 'ValueSpan'] = valueSpan; + }, this); + }; + + AxisProxy.prototype._setAxisModel = function () { + var axisModel = this.getAxisModel(); + var percentWindow = this._percentWindow; + var valueWindow = this._valueWindow; + + if (!percentWindow) { + return; + } // [0, 500]: arbitrary value, guess axis extent. + + + var precision = getPixelPrecision(valueWindow, [0, 500]); + precision = Math.min(precision, 20); // For value axis, if min/max/scale are not set, we just use the extent obtained + // by series data, which may be a little different from the extent calculated by + // `axisHelper.getScaleExtent`. But the different just affects the experience a + // little when zooming. So it will not be fixed until some users require it strongly. + + var rawExtentInfo = axisModel.axis.scale.rawExtentInfo; + + if (percentWindow[0] !== 0) { + rawExtentInfo.setDeterminedMinMax('min', +valueWindow[0].toFixed(precision)); + } + + if (percentWindow[1] !== 100) { + rawExtentInfo.setDeterminedMinMax('max', +valueWindow[1].toFixed(precision)); + } + + rawExtentInfo.freeze(); + }; + + return AxisProxy; + }(); + + function calculateDataExtent(axisProxy, axisDim, seriesModels) { + var dataExtent = [Infinity, -Infinity]; + each$8(seriesModels, function (seriesModel) { + unionAxisExtentFromData(dataExtent, seriesModel.getData(), axisDim); + }); // It is important to get "consistent" extent when more then one axes is + // controlled by a `dataZoom`, otherwise those axes will not be synchronized + // when zooming. But it is difficult to know what is "consistent", considering + // axes have different type or even different meanings (For example, two + // time axes are used to compare data of the same date in different years). + // So basically dataZoom just obtains extent by series.data (in category axis + // extent can be obtained from axis.data). + // Nevertheless, user can set min/max/scale on axes to make extent of axes + // consistent. + + var axisModel = axisProxy.getAxisModel(); + var rawExtentResult = ensureScaleRawExtentInfo(axisModel.axis.scale, axisModel, dataExtent).calculate(); + return [rawExtentResult.min, rawExtentResult.max]; + } + + var dataZoomProcessor = { + // `dataZoomProcessor` will only be performed in needed series. Consider if + // there is a line series and a pie series, it is better not to update the + // line series if only pie series is needed to be updated. + getTargetSeries: function (ecModel) { + function eachAxisModel(cb) { + ecModel.eachComponent('dataZoom', function (dataZoomModel) { + dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) { + var axisModel = ecModel.getComponent(getAxisMainType(axisDim), axisIndex); + cb(axisDim, axisIndex, axisModel, dataZoomModel); + }); + }); + } // FIXME: it brings side-effect to `getTargetSeries`. + // Prepare axis proxies. + + + eachAxisModel(function (axisDim, axisIndex, axisModel, dataZoomModel) { + // dispose all last axis proxy, in case that some axis are deleted. + axisModel.__dzAxisProxy = null; + }); + var proxyList = []; + eachAxisModel(function (axisDim, axisIndex, axisModel, dataZoomModel) { + // Different dataZooms may constrol the same axis. In that case, + // an axisProxy serves both of them. + if (!axisModel.__dzAxisProxy) { + // Use the first dataZoomModel as the main model of axisProxy. + axisModel.__dzAxisProxy = new AxisProxy(axisDim, axisIndex, dataZoomModel, ecModel); + proxyList.push(axisModel.__dzAxisProxy); + } + }); + var seriesModelMap = createHashMap(); + each(proxyList, function (axisProxy) { + each(axisProxy.getTargetSeriesModels(), function (seriesModel) { + seriesModelMap.set(seriesModel.uid, seriesModel); + }); + }); + return seriesModelMap; + }, + // Consider appendData, where filter should be performed. Because data process is + // in block mode currently, it is not need to worry about that the overallProgress + // execute every frame. + overallReset: function (ecModel, api) { + ecModel.eachComponent('dataZoom', function (dataZoomModel) { + // We calculate window and reset axis here but not in model + // init stage and not after action dispatch handler, because + // reset should be called after seriesData.restoreData. + dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) { + dataZoomModel.getAxisProxy(axisDim, axisIndex).reset(dataZoomModel); + }); // Caution: data zoom filtering is order sensitive when using + // percent range and no min/max/scale set on axis. + // For example, we have dataZoom definition: + // [ + // {xAxisIndex: 0, start: 30, end: 70}, + // {yAxisIndex: 0, start: 20, end: 80} + // ] + // In this case, [20, 80] of y-dataZoom should be based on data + // that have filtered by x-dataZoom using range of [30, 70], + // but should not be based on full raw data. Thus sliding + // x-dataZoom will change both ranges of xAxis and yAxis, + // while sliding y-dataZoom will only change the range of yAxis. + // So we should filter x-axis after reset x-axis immediately, + // and then reset y-axis and filter y-axis. + + dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) { + dataZoomModel.getAxisProxy(axisDim, axisIndex).filterData(dataZoomModel, api); + }); + }); + ecModel.eachComponent('dataZoom', function (dataZoomModel) { + // Fullfill all of the range props so that user + // is able to get them from chart.getOption(). + var axisProxy = dataZoomModel.findRepresentativeAxisProxy(); + + if (axisProxy) { + var percentRange = axisProxy.getDataPercentWindow(); + var valueRange = axisProxy.getDataValueWindow(); + dataZoomModel.setCalculatedRange({ + start: percentRange[0], + end: percentRange[1], + startValue: valueRange[0], + endValue: valueRange[1] + }); + } + }); + } + }; + + function installDataZoomAction(registers) { + registers.registerAction('dataZoom', function (payload, ecModel) { + var effectedModels = findEffectedDataZooms(ecModel, payload); + each(effectedModels, function (dataZoomModel) { + dataZoomModel.setRawRange({ + start: payload.start, + end: payload.end, + startValue: payload.startValue, + endValue: payload.endValue + }); + }); + }); + } + + var installed = false; + function installCommon(registers) { + if (installed) { + return; + } + + installed = true; + registers.registerProcessor(registers.PRIORITY.PROCESSOR.FILTER, dataZoomProcessor); + installDataZoomAction(registers); + registers.registerSubTypeDefaulter('dataZoom', function () { + // Default 'slider' when no type specified. + return 'slider'; + }); + } + + function install$y(registers) { + registers.registerComponentModel(SelectDataZoomModel); + registers.registerComponentView(SelectDataZoomView); + installCommon(registers); + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + var ToolboxFeature = + /** @class */ + function () { + function ToolboxFeature() {} + + return ToolboxFeature; + }(); + var features = {}; + function registerFeature(name, ctor) { + features[name] = ctor; + } + function getFeature(name) { + return features[name]; + } + + var ToolboxModel = + /** @class */ + function (_super) { + __extends(ToolboxModel, _super); + + function ToolboxModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ToolboxModel.type; + return _this; + } + + ToolboxModel.prototype.optionUpdated = function () { + _super.prototype.optionUpdated.apply(this, arguments); + + var ecModel = this.ecModel; + each(this.option.feature, function (featureOpt, featureName) { + var Feature = getFeature(featureName); + + if (Feature) { + if (Feature.getDefaultOption) { + Feature.defaultOption = Feature.getDefaultOption(ecModel); + } + + merge(featureOpt, Feature.defaultOption); + } + }); + }; + + ToolboxModel.type = 'toolbox'; + ToolboxModel.layoutMode = { + type: 'box', + ignoreSize: true + }; + ToolboxModel.defaultOption = { + show: true, + z: 6, + // zlevel: 0, + orient: 'horizontal', + left: 'right', + top: 'top', + // right + // bottom + backgroundColor: 'transparent', + borderColor: '#ccc', + borderRadius: 0, + borderWidth: 0, + padding: 5, + itemSize: 15, + itemGap: 8, + showTitle: true, + iconStyle: { + borderColor: '#666', + color: 'none' + }, + emphasis: { + iconStyle: { + borderColor: '#3E98C5' + } + }, + // textStyle: {}, + // feature + tooltip: { + show: false, + position: 'bottom' + } + }; + return ToolboxModel; + }(ComponentModel); + + /** + * Layout list like component. + * It will box layout each items in group of component and then position the whole group in the viewport + * @param {module:zrender/group/Group} group + * @param {module:echarts/model/Component} componentModel + * @param {module:echarts/ExtensionAPI} + */ + + function layout$3(group, componentModel, api) { + var boxLayoutParams = componentModel.getBoxLayoutParams(); + var padding = componentModel.get('padding'); + var viewportSize = { + width: api.getWidth(), + height: api.getHeight() + }; + var rect = getLayoutRect(boxLayoutParams, viewportSize, padding); + box(componentModel.get('orient'), group, componentModel.get('itemGap'), rect.width, rect.height); + positionElement(group, boxLayoutParams, viewportSize, padding); + } + function makeBackground(rect, componentModel) { + var padding = normalizeCssArray$1(componentModel.get('padding')); + var style = componentModel.getItemStyle(['color', 'opacity']); + style.fill = componentModel.get('backgroundColor'); + rect = new Rect({ + shape: { + x: rect.x - padding[3], + y: rect.y - padding[0], + width: rect.width + padding[1] + padding[3], + height: rect.height + padding[0] + padding[2], + r: componentModel.get('borderRadius') + }, + style: style, + silent: true, + z2: -1 + }); // FIXME + // `subPixelOptimizeRect` may bring some gap between edge of viewpart + // and background rect when setting like `left: 0`, `top: 0`. + // graphic.subPixelOptimizeRect(rect); + + return rect; + } + + var ToolboxView = + /** @class */ + function (_super) { + __extends(ToolboxView, _super); + + function ToolboxView() { + return _super !== null && _super.apply(this, arguments) || this; + } + + ToolboxView.prototype.render = function (toolboxModel, ecModel, api, payload) { + var group = this.group; + group.removeAll(); + + if (!toolboxModel.get('show')) { + return; + } + + var itemSize = +toolboxModel.get('itemSize'); + var isVertical = toolboxModel.get('orient') === 'vertical'; + var featureOpts = toolboxModel.get('feature') || {}; + var features = this._features || (this._features = {}); + var featureNames = []; + each(featureOpts, function (opt, name) { + featureNames.push(name); + }); + new DataDiffer(this._featureNames || [], featureNames).add(processFeature).update(processFeature).remove(curry(processFeature, null)).execute(); // Keep for diff. + + this._featureNames = featureNames; + + function processFeature(newIndex, oldIndex) { + var featureName = featureNames[newIndex]; + var oldName = featureNames[oldIndex]; + var featureOpt = featureOpts[featureName]; + var featureModel = new Model(featureOpt, toolboxModel, toolboxModel.ecModel); + var feature; // FIX#11236, merge feature title from MagicType newOption. TODO: consider seriesIndex ? + + if (payload && payload.newTitle != null && payload.featureName === featureName) { + featureOpt.title = payload.newTitle; + } + + if (featureName && !oldName) { + // Create + if (isUserFeatureName(featureName)) { + feature = { + onclick: featureModel.option.onclick, + featureName: featureName + }; + } else { + var Feature = getFeature(featureName); + + if (!Feature) { + return; + } + + feature = new Feature(); + } + + features[featureName] = feature; + } else { + feature = features[oldName]; // If feature does not exsit. + + if (!feature) { + return; + } + } + + feature.uid = getUID('toolbox-feature'); + feature.model = featureModel; + feature.ecModel = ecModel; + feature.api = api; + var isToolboxFeature = feature instanceof ToolboxFeature; + + if (!featureName && oldName) { + isToolboxFeature && feature.dispose && feature.dispose(ecModel, api); + return; + } + + if (!featureModel.get('show') || isToolboxFeature && feature.unusable) { + isToolboxFeature && feature.remove && feature.remove(ecModel, api); + return; + } + + createIconPaths(featureModel, feature, featureName); + + featureModel.setIconStatus = function (iconName, status) { + var option = this.option; + var iconPaths = this.iconPaths; + option.iconStatus = option.iconStatus || {}; + option.iconStatus[iconName] = status; + + if (iconPaths[iconName]) { + (status === 'emphasis' ? enterEmphasis : leaveEmphasis)(iconPaths[iconName]); + } + }; + + if (feature instanceof ToolboxFeature) { + if (feature.render) { + feature.render(featureModel, ecModel, api, payload); + } + } + } + + function createIconPaths(featureModel, feature, featureName) { + var iconStyleModel = featureModel.getModel('iconStyle'); + var iconStyleEmphasisModel = featureModel.getModel(['emphasis', 'iconStyle']); // If one feature has mutiple icon. they are orginaized as + // { + // icon: { + // foo: '', + // bar: '' + // }, + // title: { + // foo: '', + // bar: '' + // } + // } + + var icons = feature instanceof ToolboxFeature && feature.getIcons ? feature.getIcons() : featureModel.get('icon'); + var titles = featureModel.get('title') || {}; + var iconsMap; + var titlesMap; + + if (isString(icons)) { + iconsMap = {}; + iconsMap[featureName] = icons; + } else { + iconsMap = icons; + } + + if (isString(titles)) { + titlesMap = {}; + titlesMap[featureName] = titles; + } else { + titlesMap = titles; + } + + var iconPaths = featureModel.iconPaths = {}; + each(iconsMap, function (iconStr, iconName) { + var path = createIcon(iconStr, {}, { + x: -itemSize / 2, + y: -itemSize / 2, + width: itemSize, + height: itemSize + }); // TODO handling image + + path.setStyle(iconStyleModel.getItemStyle()); + var pathEmphasisState = path.ensureState('emphasis'); + pathEmphasisState.style = iconStyleEmphasisModel.getItemStyle(); // Text position calculation + + var textContent = new ZRText({ + style: { + text: titlesMap[iconName], + align: iconStyleEmphasisModel.get('textAlign'), + borderRadius: iconStyleEmphasisModel.get('textBorderRadius'), + padding: iconStyleEmphasisModel.get('textPadding'), + fill: null + }, + ignore: true + }); + path.setTextContent(textContent); + setTooltipConfig({ + el: path, + componentModel: toolboxModel, + itemName: iconName, + formatterParamsExtra: { + title: titlesMap[iconName] + } + }); + path.__title = titlesMap[iconName]; + path.on('mouseover', function () { + // Should not reuse above hoverStyle, which might be modified. + var hoverStyle = iconStyleEmphasisModel.getItemStyle(); + var defaultTextPosition = isVertical ? toolboxModel.get('right') == null && toolboxModel.get('left') !== 'right' ? 'right' : 'left' : toolboxModel.get('bottom') == null && toolboxModel.get('top') !== 'bottom' ? 'bottom' : 'top'; + textContent.setStyle({ + fill: iconStyleEmphasisModel.get('textFill') || hoverStyle.fill || hoverStyle.stroke || '#000', + backgroundColor: iconStyleEmphasisModel.get('textBackgroundColor') + }); + path.setTextConfig({ + position: iconStyleEmphasisModel.get('textPosition') || defaultTextPosition + }); + textContent.ignore = !toolboxModel.get('showTitle'); // Use enterEmphasis and leaveEmphasis provide by ec. + // There are flags managed by the echarts. + + api.enterEmphasis(this); + }).on('mouseout', function () { + if (featureModel.get(['iconStatus', iconName]) !== 'emphasis') { + api.leaveEmphasis(this); + } + + textContent.hide(); + }); + (featureModel.get(['iconStatus', iconName]) === 'emphasis' ? enterEmphasis : leaveEmphasis)(path); + group.add(path); + path.on('click', bind(feature.onclick, feature, ecModel, api, iconName)); + iconPaths[iconName] = path; + }); + } + + layout$3(group, toolboxModel, api); // Render background after group is layout + // FIXME + + group.add(makeBackground(group.getBoundingRect(), toolboxModel)); // Adjust icon title positions to avoid them out of screen + + isVertical || group.eachChild(function (icon) { + var titleText = icon.__title; // const hoverStyle = icon.hoverStyle; + // TODO simplify code? + + var emphasisState = icon.ensureState('emphasis'); + var emphasisTextConfig = emphasisState.textConfig || (emphasisState.textConfig = {}); + var textContent = icon.getTextContent(); + var emphasisTextState = textContent && textContent.ensureState('emphasis'); // May be background element + + if (emphasisTextState && !isFunction(emphasisTextState) && titleText) { + var emphasisTextStyle = emphasisTextState.style || (emphasisTextState.style = {}); + var rect = getBoundingRect(titleText, ZRText.makeFont(emphasisTextStyle)); + var offsetX = icon.x + group.x; + var offsetY = icon.y + group.y + itemSize; + var needPutOnTop = false; + + if (offsetY + rect.height > api.getHeight()) { + emphasisTextConfig.position = 'top'; + needPutOnTop = true; + } + + var topOffset = needPutOnTop ? -5 - rect.height : itemSize + 10; + + if (offsetX + rect.width / 2 > api.getWidth()) { + emphasisTextConfig.position = ['100%', topOffset]; + emphasisTextStyle.align = 'right'; + } else if (offsetX - rect.width / 2 < 0) { + emphasisTextConfig.position = [0, topOffset]; + emphasisTextStyle.align = 'left'; + } + } + }); + }; + + ToolboxView.prototype.updateView = function (toolboxModel, ecModel, api, payload) { + each(this._features, function (feature) { + feature instanceof ToolboxFeature && feature.updateView && feature.updateView(feature.model, ecModel, api, payload); + }); + }; // updateLayout(toolboxModel, ecModel, api, payload) { + // zrUtil.each(this._features, function (feature) { + // feature.updateLayout && feature.updateLayout(feature.model, ecModel, api, payload); + // }); + // }, + + + ToolboxView.prototype.remove = function (ecModel, api) { + each(this._features, function (feature) { + feature instanceof ToolboxFeature && feature.remove && feature.remove(ecModel, api); + }); + this.group.removeAll(); + }; + + ToolboxView.prototype.dispose = function (ecModel, api) { + each(this._features, function (feature) { + feature instanceof ToolboxFeature && feature.dispose && feature.dispose(ecModel, api); + }); + }; + + ToolboxView.type = 'toolbox'; + return ToolboxView; + }(ComponentView); + + function isUserFeatureName(featureName) { + return featureName.indexOf('my') === 0; + } + + /* global window, document */ + + var SaveAsImage = + /** @class */ + function (_super) { + __extends(SaveAsImage, _super); + + function SaveAsImage() { + return _super !== null && _super.apply(this, arguments) || this; + } + + SaveAsImage.prototype.onclick = function (ecModel, api) { + var model = this.model; + var title = model.get('name') || ecModel.get('title.0.text') || 'echarts'; + var isSvg = api.getZr().painter.getType() === 'svg'; + var type = isSvg ? 'svg' : model.get('type', true) || 'png'; + var url = api.getConnectedDataURL({ + type: type, + backgroundColor: model.get('backgroundColor', true) || ecModel.get('backgroundColor') || '#fff', + connectedBackgroundColor: model.get('connectedBackgroundColor'), + excludeComponents: model.get('excludeComponents'), + pixelRatio: model.get('pixelRatio') + }); + var browser = env.browser; // Chrome, Firefox, New Edge + + if (isFunction(MouseEvent) && (browser.newEdge || !browser.ie && !browser.edge)) { + var $a = document.createElement('a'); + $a.download = title + '.' + type; + $a.target = '_blank'; + $a.href = url; + var evt = new MouseEvent('click', { + // some micro front-end framework, window maybe is a Proxy + view: document.defaultView, + bubbles: true, + cancelable: false + }); + $a.dispatchEvent(evt); + } // IE or old Edge + else { + // @ts-ignore + if (window.navigator.msSaveOrOpenBlob || isSvg) { + var parts = url.split(','); // data:[][;charset=][;base64], + + var base64Encoded = parts[0].indexOf('base64') > -1; + var bstr = isSvg // should decode the svg data uri first + ? decodeURIComponent(parts[1]) : parts[1]; // only `atob` when the data uri is encoded with base64 + // otherwise, like `svg` data uri exported by zrender, + // there will be an error, for it's not encoded with base64. + // (just a url-encoded string through `encodeURIComponent`) + + base64Encoded && (bstr = window.atob(bstr)); + var filename = title + '.' + type; // @ts-ignore + + if (window.navigator.msSaveOrOpenBlob) { + var n = bstr.length; + var u8arr = new Uint8Array(n); + + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + + var blob = new Blob([u8arr]); // @ts-ignore + + window.navigator.msSaveOrOpenBlob(blob, filename); + } else { + var frame = document.createElement('iframe'); + document.body.appendChild(frame); + var cw = frame.contentWindow; + var doc = cw.document; + doc.open('image/svg+xml', 'replace'); + doc.write(bstr); + doc.close(); + cw.focus(); + doc.execCommand('SaveAs', true, filename); + document.body.removeChild(frame); + } + } else { + var lang = model.get('lang'); + var html = '' + '' + '' + ''; + var tab = window.open(); + tab.document.write(html); + tab.document.title = title; + } + } + }; + + SaveAsImage.getDefaultOption = function (ecModel) { + var defaultOption = { + show: true, + icon: 'M4.7,22.9L29.3,45.5L54.7,23.4M4.6,43.6L4.6,58L53.8,58L53.8,43.6M29.2,45.1L29.2,0', + title: ecModel.getLocaleModel().get(['toolbox', 'saveAsImage', 'title']), + type: 'png', + // Default use option.backgroundColor + // backgroundColor: '#fff', + connectedBackgroundColor: '#fff', + name: '', + excludeComponents: ['toolbox'], + // use current pixel ratio of device by default + // pixelRatio: 1, + lang: ecModel.getLocaleModel().get(['toolbox', 'saveAsImage', 'lang']) + }; + return defaultOption; + }; + + return SaveAsImage; + }(ToolboxFeature); + + var INNER_STACK_KEYWORD = '__ec_magicType_stack__'; + var radioTypes = [['line', 'bar'], ['stack']]; + + var MagicType = + /** @class */ + function (_super) { + __extends(MagicType, _super); + + function MagicType() { + return _super !== null && _super.apply(this, arguments) || this; + } + + MagicType.prototype.getIcons = function () { + var model = this.model; + var availableIcons = model.get('icon'); + var icons = {}; + each(model.get('type'), function (type) { + if (availableIcons[type]) { + icons[type] = availableIcons[type]; + } + }); + return icons; + }; + + MagicType.getDefaultOption = function (ecModel) { + var defaultOption = { + show: true, + type: [], + // Icon group + icon: { + line: 'M4.1,28.9h7.1l9.3-22l7.4,38l9.7-19.7l3,12.8h14.9M4.1,58h51.4', + bar: 'M6.7,22.9h10V48h-10V22.9zM24.9,13h10v35h-10V13zM43.2,2h10v46h-10V2zM3.1,58h53.7', + // eslint-disable-next-line + stack: 'M8.2,38.4l-8.4,4.1l30.6,15.3L60,42.5l-8.1-4.1l-21.5,11L8.2,38.4z M51.9,30l-8.1,4.2l-13.4,6.9l-13.9-6.9L8.2,30l-8.4,4.2l8.4,4.2l22.2,11l21.5-11l8.1-4.2L51.9,30z M51.9,21.7l-8.1,4.2L35.7,30l-5.3,2.8L24.9,30l-8.4-4.1l-8.3-4.2l-8.4,4.2L8.2,30l8.3,4.2l13.9,6.9l13.4-6.9l8.1-4.2l8.1-4.1L51.9,21.7zM30.4,2.2L-0.2,17.5l8.4,4.1l8.3,4.2l8.4,4.2l5.5,2.7l5.3-2.7l8.1-4.2l8.1-4.2l8.1-4.1L30.4,2.2z' // jshint ignore:line + + }, + // `line`, `bar`, `stack`, `tiled` + title: ecModel.getLocaleModel().get(['toolbox', 'magicType', 'title']), + option: {}, + seriesIndex: {} + }; + return defaultOption; + }; + + MagicType.prototype.onclick = function (ecModel, api, type) { + var model = this.model; + var seriesIndex = model.get(['seriesIndex', type]); // Not supported magicType + + if (!seriesOptGenreator[type]) { + return; + } + + var newOption = { + series: [] + }; + + var generateNewSeriesTypes = function (seriesModel) { + var seriesType = seriesModel.subType; + var seriesId = seriesModel.id; + var newSeriesOpt = seriesOptGenreator[type](seriesType, seriesId, seriesModel, model); + + if (newSeriesOpt) { + // PENDING If merge original option? + defaults(newSeriesOpt, seriesModel.option); + newOption.series.push(newSeriesOpt); + } // Modify boundaryGap + + + var coordSys = seriesModel.coordinateSystem; + + if (coordSys && coordSys.type === 'cartesian2d' && (type === 'line' || type === 'bar')) { + var categoryAxis = coordSys.getAxesByScale('ordinal')[0]; + + if (categoryAxis) { + var axisDim = categoryAxis.dim; + var axisType = axisDim + 'Axis'; + var axisModel = seriesModel.getReferringComponents(axisType, SINGLE_REFERRING).models[0]; + var axisIndex = axisModel.componentIndex; + newOption[axisType] = newOption[axisType] || []; + + for (var i = 0; i <= axisIndex; i++) { + newOption[axisType][axisIndex] = newOption[axisType][axisIndex] || {}; + } + + newOption[axisType][axisIndex].boundaryGap = type === 'bar'; + } + } + }; + + each(radioTypes, function (radio) { + if (indexOf(radio, type) >= 0) { + each(radio, function (item) { + model.setIconStatus(item, 'normal'); + }); + } + }); + model.setIconStatus(type, 'emphasis'); + ecModel.eachComponent({ + mainType: 'series', + query: seriesIndex == null ? null : { + seriesIndex: seriesIndex + } + }, generateNewSeriesTypes); + var newTitle; + var currentType = type; // Change title of stack + + if (type === 'stack') { + // use titles in model instead of ecModel + // as stack and tiled appears in pair, just flip them + // no need of checking stack state + newTitle = merge({ + stack: model.option.title.tiled, + tiled: model.option.title.stack + }, model.option.title); + + if (model.get(['iconStatus', type]) !== 'emphasis') { + currentType = 'tiled'; + } + } + + api.dispatchAction({ + type: 'changeMagicType', + currentType: currentType, + newOption: newOption, + newTitle: newTitle, + featureName: 'magicType' + }); + }; + + return MagicType; + }(ToolboxFeature); + + var seriesOptGenreator = { + 'line': function (seriesType, seriesId, seriesModel, model) { + if (seriesType === 'bar') { + return merge({ + id: seriesId, + type: 'line', + // Preserve data related option + data: seriesModel.get('data'), + stack: seriesModel.get('stack'), + markPoint: seriesModel.get('markPoint'), + markLine: seriesModel.get('markLine') + }, model.get(['option', 'line']) || {}, true); + } + }, + 'bar': function (seriesType, seriesId, seriesModel, model) { + if (seriesType === 'line') { + return merge({ + id: seriesId, + type: 'bar', + // Preserve data related option + data: seriesModel.get('data'), + stack: seriesModel.get('stack'), + markPoint: seriesModel.get('markPoint'), + markLine: seriesModel.get('markLine') + }, model.get(['option', 'bar']) || {}, true); + } + }, + 'stack': function (seriesType, seriesId, seriesModel, model) { + var isStack = seriesModel.get('stack') === INNER_STACK_KEYWORD; + + if (seriesType === 'line' || seriesType === 'bar') { + model.setIconStatus('stack', isStack ? 'normal' : 'emphasis'); + return merge({ + id: seriesId, + stack: isStack ? '' : INNER_STACK_KEYWORD + }, model.get(['option', 'stack']) || {}, true); + } + } + }; // TODO: SELF REGISTERED. + + registerAction({ + type: 'changeMagicType', + event: 'magicTypeChanged', + update: 'prepareAndUpdate' + }, function (payload, ecModel) { + ecModel.mergeOption(payload.newOption); + }); + + /* global document */ + + var BLOCK_SPLITER = new Array(60).join('-'); + var ITEM_SPLITER = '\t'; + /** + * Group series into two types + * 1. on category axis, like line, bar + * 2. others, like scatter, pie + */ + + function groupSeries(ecModel) { + var seriesGroupByCategoryAxis = {}; + var otherSeries = []; + var meta = []; + ecModel.eachRawSeries(function (seriesModel) { + var coordSys = seriesModel.coordinateSystem; + + if (coordSys && (coordSys.type === 'cartesian2d' || coordSys.type === 'polar')) { + // TODO: TYPE Consider polar? Include polar may increase unecessary bundle size. + var baseAxis = coordSys.getBaseAxis(); + + if (baseAxis.type === 'category') { + var key = baseAxis.dim + '_' + baseAxis.index; + + if (!seriesGroupByCategoryAxis[key]) { + seriesGroupByCategoryAxis[key] = { + categoryAxis: baseAxis, + valueAxis: coordSys.getOtherAxis(baseAxis), + series: [] + }; + meta.push({ + axisDim: baseAxis.dim, + axisIndex: baseAxis.index + }); + } + + seriesGroupByCategoryAxis[key].series.push(seriesModel); + } else { + otherSeries.push(seriesModel); + } + } else { + otherSeries.push(seriesModel); + } + }); + return { + seriesGroupByCategoryAxis: seriesGroupByCategoryAxis, + other: otherSeries, + meta: meta + }; + } + /** + * Assemble content of series on cateogory axis + * @inner + */ + + + function assembleSeriesWithCategoryAxis(groups) { + var tables = []; + each(groups, function (group, key) { + var categoryAxis = group.categoryAxis; + var valueAxis = group.valueAxis; + var valueAxisDim = valueAxis.dim; + var headers = [' '].concat(map(group.series, function (series) { + return series.name; + })); // @ts-ignore TODO Polar + + var columns = [categoryAxis.model.getCategories()]; + each(group.series, function (series) { + var rawData = series.getRawData(); + columns.push(series.getRawData().mapArray(rawData.mapDimension(valueAxisDim), function (val) { + return val; + })); + }); // Assemble table content + + var lines = [headers.join(ITEM_SPLITER)]; + + for (var i = 0; i < columns[0].length; i++) { + var items = []; + + for (var j = 0; j < columns.length; j++) { + items.push(columns[j][i]); + } + + lines.push(items.join(ITEM_SPLITER)); + } + + tables.push(lines.join('\n')); + }); + return tables.join('\n\n' + BLOCK_SPLITER + '\n\n'); + } + /** + * Assemble content of other series + */ + + + function assembleOtherSeries(series) { + return map(series, function (series) { + var data = series.getRawData(); + var lines = [series.name]; + var vals = []; + data.each(data.dimensions, function () { + var argLen = arguments.length; + var dataIndex = arguments[argLen - 1]; + var name = data.getName(dataIndex); + + for (var i = 0; i < argLen - 1; i++) { + vals[i] = arguments[i]; + } + + lines.push((name ? name + ITEM_SPLITER : '') + vals.join(ITEM_SPLITER)); + }); + return lines.join('\n'); + }).join('\n\n' + BLOCK_SPLITER + '\n\n'); + } + + function getContentFromModel(ecModel) { + var result = groupSeries(ecModel); + return { + value: filter([assembleSeriesWithCategoryAxis(result.seriesGroupByCategoryAxis), assembleOtherSeries(result.other)], function (str) { + return !!str.replace(/[\n\t\s]/g, ''); + }).join('\n\n' + BLOCK_SPLITER + '\n\n'), + meta: result.meta + }; + } + + function trim$1(str) { + return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); + } + /** + * If a block is tsv format + */ + + + function isTSVFormat(block) { + // Simple method to find out if a block is tsv format + var firstLine = block.slice(0, block.indexOf('\n')); + + if (firstLine.indexOf(ITEM_SPLITER) >= 0) { + return true; + } + } + + var itemSplitRegex = new RegExp('[' + ITEM_SPLITER + ']+', 'g'); + /** + * @param {string} tsv + * @return {Object} + */ + + function parseTSVContents(tsv) { + var tsvLines = tsv.split(/\n+/g); + var headers = trim$1(tsvLines.shift()).split(itemSplitRegex); + var categories = []; + var series = map(headers, function (header) { + return { + name: header, + data: [] + }; + }); + + for (var i = 0; i < tsvLines.length; i++) { + var items = trim$1(tsvLines[i]).split(itemSplitRegex); + categories.push(items.shift()); + + for (var j = 0; j < items.length; j++) { + series[j] && (series[j].data[i] = items[j]); + } + } + + return { + series: series, + categories: categories + }; + } + + function parseListContents(str) { + var lines = str.split(/\n+/g); + var seriesName = trim$1(lines.shift()); + var data = []; + + for (var i = 0; i < lines.length; i++) { + // if line is empty, ignore it. + // there is a case that a user forgot to delete `\n`. + var line = trim$1(lines[i]); + + if (!line) { + continue; + } + + var items = line.split(itemSplitRegex); + var name_1 = ''; + var value = void 0; + var hasName = false; + + if (isNaN(items[0])) { + // First item is name + hasName = true; + name_1 = items[0]; + items = items.slice(1); + data[i] = { + name: name_1, + value: [] + }; + value = data[i].value; + } else { + value = data[i] = []; + } + + for (var j = 0; j < items.length; j++) { + value.push(+items[j]); + } + + if (value.length === 1) { + hasName ? data[i].value = value[0] : data[i] = value[0]; + } + } + + return { + name: seriesName, + data: data + }; + } + + function parseContents(str, blockMetaList) { + var blocks = str.split(new RegExp('\n*' + BLOCK_SPLITER + '\n*', 'g')); + var newOption = { + series: [] + }; + each(blocks, function (block, idx) { + if (isTSVFormat(block)) { + var result = parseTSVContents(block); + var blockMeta = blockMetaList[idx]; + var axisKey = blockMeta.axisDim + 'Axis'; + + if (blockMeta) { + newOption[axisKey] = newOption[axisKey] || []; + newOption[axisKey][blockMeta.axisIndex] = { + data: result.categories + }; + newOption.series = newOption.series.concat(result.series); + } + } else { + var result = parseListContents(block); + newOption.series.push(result); + } + }); + return newOption; + } + + var DataView = + /** @class */ + function (_super) { + __extends(DataView, _super); + + function DataView() { + return _super !== null && _super.apply(this, arguments) || this; + } + + DataView.prototype.onclick = function (ecModel, api) { + // FIXME: better way? + setTimeout(function () { + api.dispatchAction({ + type: 'hideTip' + }); + }); + var container = api.getDom(); + var model = this.model; + + if (this._dom) { + container.removeChild(this._dom); + } + + var root = document.createElement('div'); // use padding to avoid 5px whitespace + + root.style.cssText = 'position:absolute;top:0;bottom:0;left:0;right:0;padding:5px'; + root.style.backgroundColor = model.get('backgroundColor') || '#fff'; // Create elements + + var header = document.createElement('h4'); + var lang = model.get('lang') || []; + header.innerHTML = lang[0] || model.get('title'); + header.style.cssText = 'margin:10px 20px'; + header.style.color = model.get('textColor'); + var viewMain = document.createElement('div'); + var textarea = document.createElement('textarea'); + viewMain.style.cssText = 'overflow:auto'; + var optionToContent = model.get('optionToContent'); + var contentToOption = model.get('contentToOption'); + var result = getContentFromModel(ecModel); + + if (isFunction(optionToContent)) { + var htmlOrDom = optionToContent(api.getOption()); + + if (isString(htmlOrDom)) { + viewMain.innerHTML = htmlOrDom; + } else if (isDom(htmlOrDom)) { + viewMain.appendChild(htmlOrDom); + } + } else { + // Use default textarea + textarea.readOnly = model.get('readOnly'); + var style = textarea.style; // eslint-disable-next-line max-len + + style.cssText = 'display:block;width:100%;height:100%;font-family:monospace;font-size:14px;line-height:1.6rem;resize:none;box-sizing:border-box;outline:none'; + style.color = model.get('textColor'); + style.borderColor = model.get('textareaBorderColor'); + style.backgroundColor = model.get('textareaColor'); + textarea.value = result.value; + viewMain.appendChild(textarea); + } + + var blockMetaList = result.meta; + var buttonContainer = document.createElement('div'); + buttonContainer.style.cssText = 'position:absolute;bottom:5px;left:0;right:0'; // eslint-disable-next-line max-len + + var buttonStyle = 'float:right;margin-right:20px;border:none;cursor:pointer;padding:2px 5px;font-size:12px;border-radius:3px'; + var closeButton = document.createElement('div'); + var refreshButton = document.createElement('div'); + buttonStyle += ';background-color:' + model.get('buttonColor'); + buttonStyle += ';color:' + model.get('buttonTextColor'); + var self = this; + + function close() { + container.removeChild(root); + self._dom = null; + } + + addEventListener(closeButton, 'click', close); + addEventListener(refreshButton, 'click', function () { + if (contentToOption == null && optionToContent != null || contentToOption != null && optionToContent == null) { + if ("development" !== 'production') { + // eslint-disable-next-line + warn('It seems you have just provided one of `contentToOption` and `optionToContent` functions but missed the other one. Data change is ignored.'); + } + + close(); + return; + } + + var newOption; + + try { + if (isFunction(contentToOption)) { + newOption = contentToOption(viewMain, api.getOption()); + } else { + newOption = parseContents(textarea.value, blockMetaList); + } + } catch (e) { + close(); + throw new Error('Data view format error ' + e); + } + + if (newOption) { + api.dispatchAction({ + type: 'changeDataView', + newOption: newOption + }); + } + + close(); + }); + closeButton.innerHTML = lang[1]; + refreshButton.innerHTML = lang[2]; + refreshButton.style.cssText = closeButton.style.cssText = buttonStyle; + !model.get('readOnly') && buttonContainer.appendChild(refreshButton); + buttonContainer.appendChild(closeButton); + root.appendChild(header); + root.appendChild(viewMain); + root.appendChild(buttonContainer); + viewMain.style.height = container.clientHeight - 80 + 'px'; + container.appendChild(root); + this._dom = root; + }; + + DataView.prototype.remove = function (ecModel, api) { + this._dom && api.getDom().removeChild(this._dom); + }; + + DataView.prototype.dispose = function (ecModel, api) { + this.remove(ecModel, api); + }; + + DataView.getDefaultOption = function (ecModel) { + var defaultOption = { + show: true, + readOnly: false, + optionToContent: null, + contentToOption: null, + // eslint-disable-next-line + icon: 'M17.5,17.3H33 M17.5,17.3H33 M45.4,29.5h-28 M11.5,2v56H51V14.8L38.4,2H11.5z M38.4,2.2v12.7H51 M45.4,41.7h-28', + title: ecModel.getLocaleModel().get(['toolbox', 'dataView', 'title']), + lang: ecModel.getLocaleModel().get(['toolbox', 'dataView', 'lang']), + backgroundColor: '#fff', + textColor: '#000', + textareaColor: '#fff', + textareaBorderColor: '#333', + buttonColor: '#c23531', + buttonTextColor: '#fff' + }; + return defaultOption; + }; + + return DataView; + }(ToolboxFeature); + /** + * @inner + */ + + + function tryMergeDataOption(newData, originalData) { + return map(newData, function (newVal, idx) { + var original = originalData && originalData[idx]; + + if (isObject(original) && !isArray(original)) { + var newValIsObject = isObject(newVal) && !isArray(newVal); + + if (!newValIsObject) { + newVal = { + value: newVal + }; + } // original data has name but new data has no name + + + var shouldDeleteName = original.name != null && newVal.name == null; // Original data has option + + newVal = defaults(newVal, original); + shouldDeleteName && delete newVal.name; + return newVal; + } else { + return newVal; + } + }); + } // TODO: SELF REGISTERED. + + + registerAction({ + type: 'changeDataView', + event: 'dataViewChanged', + update: 'prepareAndUpdate' + }, function (payload, ecModel) { + var newSeriesOptList = []; + each(payload.newOption.series, function (seriesOpt) { + var seriesModel = ecModel.getSeriesByName(seriesOpt.name)[0]; + + if (!seriesModel) { + // New created series + // Geuss the series type + newSeriesOptList.push(extend({ + // Default is scatter + type: 'scatter' + }, seriesOpt)); + } else { + var originalData = seriesModel.get('data'); + newSeriesOptList.push({ + name: seriesOpt.name, + data: tryMergeDataOption(seriesOpt.data, originalData) + }); + } + }); + ecModel.mergeOption(defaults({ + series: newSeriesOptList + }, payload.newOption)); + }); + + var each$9 = each; + var inner$f = makeInner(); + /** + * @param ecModel + * @param newSnapshot key is dataZoomId + */ + + function push(ecModel, newSnapshot) { + var storedSnapshots = getStoreSnapshots(ecModel); // If previous dataZoom can not be found, + // complete an range with current range. + + each$9(newSnapshot, function (batchItem, dataZoomId) { + var i = storedSnapshots.length - 1; + + for (; i >= 0; i--) { + var snapshot = storedSnapshots[i]; + + if (snapshot[dataZoomId]) { + break; + } + } + + if (i < 0) { + // No origin range set, create one by current range. + var dataZoomModel = ecModel.queryComponents({ + mainType: 'dataZoom', + subType: 'select', + id: dataZoomId + })[0]; + + if (dataZoomModel) { + var percentRange = dataZoomModel.getPercentRange(); + storedSnapshots[0][dataZoomId] = { + dataZoomId: dataZoomId, + start: percentRange[0], + end: percentRange[1] + }; + } + } + }); + storedSnapshots.push(newSnapshot); + } + function pop(ecModel) { + var storedSnapshots = getStoreSnapshots(ecModel); + var head = storedSnapshots[storedSnapshots.length - 1]; + storedSnapshots.length > 1 && storedSnapshots.pop(); // Find top for all dataZoom. + + var snapshot = {}; + each$9(head, function (batchItem, dataZoomId) { + for (var i = storedSnapshots.length - 1; i >= 0; i--) { + batchItem = storedSnapshots[i][dataZoomId]; + + if (batchItem) { + snapshot[dataZoomId] = batchItem; + break; + } + } + }); + return snapshot; + } + function clear$1(ecModel) { + inner$f(ecModel).snapshots = null; + } + function count(ecModel) { + return getStoreSnapshots(ecModel).length; + } + /** + * History length of each dataZoom may be different. + * this._history[0] is used to store origin range. + */ + + function getStoreSnapshots(ecModel) { + var store = inner$f(ecModel); + + if (!store.snapshots) { + store.snapshots = [{}]; + } + + return store.snapshots; + } + + var RestoreOption = + /** @class */ + function (_super) { + __extends(RestoreOption, _super); + + function RestoreOption() { + return _super !== null && _super.apply(this, arguments) || this; + } + + RestoreOption.prototype.onclick = function (ecModel, api) { + clear$1(ecModel); + api.dispatchAction({ + type: 'restore', + from: this.uid + }); + }; + + RestoreOption.getDefaultOption = function (ecModel) { + var defaultOption = { + show: true, + // eslint-disable-next-line + icon: 'M3.8,33.4 M47,18.9h9.8V8.7 M56.3,20.1 C52.1,9,40.5,0.6,26.8,2.1C12.6,3.7,1.6,16.2,2.1,30.6 M13,41.1H3.1v10.2 M3.7,39.9c4.2,11.1,15.8,19.5,29.5,18 c14.2-1.6,25.2-14.1,24.7-28.5', + title: ecModel.getLocaleModel().get(['toolbox', 'restore', 'title']) + }; + return defaultOption; + }; + + return RestoreOption; + }(ToolboxFeature); // TODO: SELF REGISTERED. + + + registerAction({ + type: 'restore', + event: 'restore', + update: 'prepareAndUpdate' + }, function (payload, ecModel) { + ecModel.resetOption('recreate'); + }); + + // how to genarialize to more coordinate systems. + + var INCLUDE_FINDER_MAIN_TYPES = ['grid', 'xAxis', 'yAxis', 'geo', 'graph', 'polar', 'radiusAxis', 'angleAxis', 'bmap']; + + var BrushTargetManager = + /** @class */ + function () { + /** + * @param finder contains Index/Id/Name of xAxis/yAxis/geo/grid + * Each can be {number|Array.}. like: {xAxisIndex: [3, 4]} + * @param opt.include include coordinate system types. + */ + function BrushTargetManager(finder, ecModel, opt) { + var _this = this; + + this._targetInfoList = []; + var foundCpts = parseFinder$1(ecModel, finder); + each(targetInfoBuilders, function (builder, type) { + if (!opt || !opt.include || indexOf(opt.include, type) >= 0) { + builder(foundCpts, _this._targetInfoList); + } + }); + } + + BrushTargetManager.prototype.setOutputRanges = function (areas, ecModel) { + this.matchOutputRanges(areas, ecModel, function (area, coordRange, coordSys) { + (area.coordRanges || (area.coordRanges = [])).push(coordRange); // area.coordRange is the first of area.coordRanges + + if (!area.coordRange) { + area.coordRange = coordRange; // In 'category' axis, coord to pixel is not reversible, so we can not + // rebuild range by coordRange accrately, which may bring trouble when + // brushing only one item. So we use __rangeOffset to rebuilding range + // by coordRange. And this it only used in brush component so it is no + // need to be adapted to coordRanges. + + var result = coordConvert[area.brushType](0, coordSys, coordRange); + area.__rangeOffset = { + offset: diffProcessor[area.brushType](result.values, area.range, [1, 1]), + xyMinMax: result.xyMinMax + }; + } + }); + return areas; + }; + + BrushTargetManager.prototype.matchOutputRanges = function (areas, ecModel, cb) { + each(areas, function (area) { + var targetInfo = this.findTargetInfo(area, ecModel); + + if (targetInfo && targetInfo !== true) { + each(targetInfo.coordSyses, function (coordSys) { + var result = coordConvert[area.brushType](1, coordSys, area.range, true); + cb(area, result.values, coordSys, ecModel); + }); + } + }, this); + }; + /** + * the `areas` is `BrushModel.areas`. + * Called in layout stage. + * convert `area.coordRange` to global range and set panelId to `area.range`. + */ + + + BrushTargetManager.prototype.setInputRanges = function (areas, ecModel) { + each(areas, function (area) { + var targetInfo = this.findTargetInfo(area, ecModel); + + if ("development" !== 'production') { + assert(!targetInfo || targetInfo === true || area.coordRange, 'coordRange must be specified when coord index specified.'); + assert(!targetInfo || targetInfo !== true || area.range, 'range must be specified in global brush.'); + } + + area.range = area.range || []; // convert coordRange to global range and set panelId. + + if (targetInfo && targetInfo !== true) { + area.panelId = targetInfo.panelId; // (1) area.range shoule always be calculate from coordRange but does + // not keep its original value, for the sake of the dataZoom scenario, + // where area.coordRange remains unchanged but area.range may be changed. + // (2) Only support converting one coordRange to pixel range in brush + // component. So do not consider `coordRanges`. + // (3) About __rangeOffset, see comment above. + + var result = coordConvert[area.brushType](0, targetInfo.coordSys, area.coordRange); + var rangeOffset = area.__rangeOffset; + area.range = rangeOffset ? diffProcessor[area.brushType](result.values, rangeOffset.offset, getScales(result.xyMinMax, rangeOffset.xyMinMax)) : result.values; + } + }, this); + }; + + BrushTargetManager.prototype.makePanelOpts = function (api, getDefaultBrushType) { + return map(this._targetInfoList, function (targetInfo) { + var rect = targetInfo.getPanelRect(); + return { + panelId: targetInfo.panelId, + defaultBrushType: getDefaultBrushType ? getDefaultBrushType(targetInfo) : null, + clipPath: makeRectPanelClipPath(rect), + isTargetByCursor: makeRectIsTargetByCursor(rect, api, targetInfo.coordSysModel), + getLinearBrushOtherExtent: makeLinearBrushOtherExtent(rect) + }; + }); + }; + + BrushTargetManager.prototype.controlSeries = function (area, seriesModel, ecModel) { + // Check whether area is bound in coord, and series do not belong to that coord. + // If do not do this check, some brush (like lineX) will controll all axes. + var targetInfo = this.findTargetInfo(area, ecModel); + return targetInfo === true || targetInfo && indexOf(targetInfo.coordSyses, seriesModel.coordinateSystem) >= 0; + }; + /** + * If return Object, a coord found. + * If reutrn true, global found. + * Otherwise nothing found. + */ + + + BrushTargetManager.prototype.findTargetInfo = function (area, ecModel) { + var targetInfoList = this._targetInfoList; + var foundCpts = parseFinder$1(ecModel, area); + + for (var i = 0; i < targetInfoList.length; i++) { + var targetInfo = targetInfoList[i]; + var areaPanelId = area.panelId; + + if (areaPanelId) { + if (targetInfo.panelId === areaPanelId) { + return targetInfo; + } + } else { + for (var j = 0; j < targetInfoMatchers.length; j++) { + if (targetInfoMatchers[j](foundCpts, targetInfo)) { + return targetInfo; + } + } + } + } + + return true; + }; + + return BrushTargetManager; + }(); + + function formatMinMax(minMax) { + minMax[0] > minMax[1] && minMax.reverse(); + return minMax; + } + + function parseFinder$1(ecModel, finder) { + return parseFinder(ecModel, finder, { + includeMainTypes: INCLUDE_FINDER_MAIN_TYPES + }); + } + + var targetInfoBuilders = { + grid: function (foundCpts, targetInfoList) { + var xAxisModels = foundCpts.xAxisModels; + var yAxisModels = foundCpts.yAxisModels; + var gridModels = foundCpts.gridModels; // Remove duplicated. + + var gridModelMap = createHashMap(); + var xAxesHas = {}; + var yAxesHas = {}; + + if (!xAxisModels && !yAxisModels && !gridModels) { + return; + } + + each(xAxisModels, function (axisModel) { + var gridModel = axisModel.axis.grid.model; + gridModelMap.set(gridModel.id, gridModel); + xAxesHas[gridModel.id] = true; + }); + each(yAxisModels, function (axisModel) { + var gridModel = axisModel.axis.grid.model; + gridModelMap.set(gridModel.id, gridModel); + yAxesHas[gridModel.id] = true; + }); + each(gridModels, function (gridModel) { + gridModelMap.set(gridModel.id, gridModel); + xAxesHas[gridModel.id] = true; + yAxesHas[gridModel.id] = true; + }); + gridModelMap.each(function (gridModel) { + var grid = gridModel.coordinateSystem; + var cartesians = []; + each(grid.getCartesians(), function (cartesian, index) { + if (indexOf(xAxisModels, cartesian.getAxis('x').model) >= 0 || indexOf(yAxisModels, cartesian.getAxis('y').model) >= 0) { + cartesians.push(cartesian); + } + }); + targetInfoList.push({ + panelId: 'grid--' + gridModel.id, + gridModel: gridModel, + coordSysModel: gridModel, + // Use the first one as the representitive coordSys. + coordSys: cartesians[0], + coordSyses: cartesians, + getPanelRect: panelRectBuilders.grid, + xAxisDeclared: xAxesHas[gridModel.id], + yAxisDeclared: yAxesHas[gridModel.id] + }); + }); + }, + geo: function (foundCpts, targetInfoList) { + each(foundCpts.geoModels, function (geoModel) { + var coordSys = geoModel.coordinateSystem; + targetInfoList.push({ + panelId: 'geo--' + geoModel.id, + geoModel: geoModel, + coordSysModel: geoModel, + coordSys: coordSys, + coordSyses: [coordSys], + getPanelRect: panelRectBuilders.geo + }); + }); + } + }; + var targetInfoMatchers = [// grid + function (foundCpts, targetInfo) { + var xAxisModel = foundCpts.xAxisModel; + var yAxisModel = foundCpts.yAxisModel; + var gridModel = foundCpts.gridModel; + !gridModel && xAxisModel && (gridModel = xAxisModel.axis.grid.model); + !gridModel && yAxisModel && (gridModel = yAxisModel.axis.grid.model); + return gridModel && gridModel === targetInfo.gridModel; + }, // geo + function (foundCpts, targetInfo) { + var geoModel = foundCpts.geoModel; + return geoModel && geoModel === targetInfo.geoModel; + }]; + var panelRectBuilders = { + grid: function () { + // grid is not Transformable. + return this.coordSys.master.getRect().clone(); + }, + geo: function () { + var coordSys = this.coordSys; + var rect = coordSys.getBoundingRect().clone(); // geo roam and zoom transform + + rect.applyTransform(getTransform(coordSys)); + return rect; + } + }; + var coordConvert = { + lineX: curry(axisConvert, 0), + lineY: curry(axisConvert, 1), + rect: function (to, coordSys, rangeOrCoordRange, clamp) { + var xminymin = to ? coordSys.pointToData([rangeOrCoordRange[0][0], rangeOrCoordRange[1][0]], clamp) : coordSys.dataToPoint([rangeOrCoordRange[0][0], rangeOrCoordRange[1][0]], clamp); + var xmaxymax = to ? coordSys.pointToData([rangeOrCoordRange[0][1], rangeOrCoordRange[1][1]], clamp) : coordSys.dataToPoint([rangeOrCoordRange[0][1], rangeOrCoordRange[1][1]], clamp); + var values = [formatMinMax([xminymin[0], xmaxymax[0]]), formatMinMax([xminymin[1], xmaxymax[1]])]; + return { + values: values, + xyMinMax: values + }; + }, + polygon: function (to, coordSys, rangeOrCoordRange, clamp) { + var xyMinMax = [[Infinity, -Infinity], [Infinity, -Infinity]]; + var values = map(rangeOrCoordRange, function (item) { + var p = to ? coordSys.pointToData(item, clamp) : coordSys.dataToPoint(item, clamp); + xyMinMax[0][0] = Math.min(xyMinMax[0][0], p[0]); + xyMinMax[1][0] = Math.min(xyMinMax[1][0], p[1]); + xyMinMax[0][1] = Math.max(xyMinMax[0][1], p[0]); + xyMinMax[1][1] = Math.max(xyMinMax[1][1], p[1]); + return p; + }); + return { + values: values, + xyMinMax: xyMinMax + }; + } + }; + + function axisConvert(axisNameIndex, to, coordSys, rangeOrCoordRange) { + if ("development" !== 'production') { + assert(coordSys.type === 'cartesian2d', 'lineX/lineY brush is available only in cartesian2d.'); + } + + var axis = coordSys.getAxis(['x', 'y'][axisNameIndex]); + var values = formatMinMax(map([0, 1], function (i) { + return to ? axis.coordToData(axis.toLocalCoord(rangeOrCoordRange[i]), true) : axis.toGlobalCoord(axis.dataToCoord(rangeOrCoordRange[i])); + })); + var xyMinMax = []; + xyMinMax[axisNameIndex] = values; + xyMinMax[1 - axisNameIndex] = [NaN, NaN]; + return { + values: values, + xyMinMax: xyMinMax + }; + } + + var diffProcessor = { + lineX: curry(axisDiffProcessor, 0), + lineY: curry(axisDiffProcessor, 1), + rect: function (values, refer, scales) { + return [[values[0][0] - scales[0] * refer[0][0], values[0][1] - scales[0] * refer[0][1]], [values[1][0] - scales[1] * refer[1][0], values[1][1] - scales[1] * refer[1][1]]]; + }, + polygon: function (values, refer, scales) { + return map(values, function (item, idx) { + return [item[0] - scales[0] * refer[idx][0], item[1] - scales[1] * refer[idx][1]]; + }); + } + }; + + function axisDiffProcessor(axisNameIndex, values, refer, scales) { + return [values[0] - scales[axisNameIndex] * refer[0], values[1] - scales[axisNameIndex] * refer[1]]; + } // We have to process scale caused by dataZoom manually, + // although it might be not accurate. + // Return [0~1, 0~1] + + + function getScales(xyMinMaxCurr, xyMinMaxOrigin) { + var sizeCurr = getSize$1(xyMinMaxCurr); + var sizeOrigin = getSize$1(xyMinMaxOrigin); + var scales = [sizeCurr[0] / sizeOrigin[0], sizeCurr[1] / sizeOrigin[1]]; + isNaN(scales[0]) && (scales[0] = 1); + isNaN(scales[1]) && (scales[1] = 1); + return scales; + } + + function getSize$1(xyMinMax) { + return xyMinMax ? [xyMinMax[0][1] - xyMinMax[0][0], xyMinMax[1][1] - xyMinMax[1][0]] : [NaN, NaN]; + } + + var each$a = each; + var DATA_ZOOM_ID_BASE = makeInternalComponentId('toolbox-dataZoom_'); + + var DataZoomFeature = + /** @class */ + function (_super) { + __extends(DataZoomFeature, _super); + + function DataZoomFeature() { + return _super !== null && _super.apply(this, arguments) || this; + } + + DataZoomFeature.prototype.render = function (featureModel, ecModel, api, payload) { + if (!this._brushController) { + this._brushController = new BrushController(api.getZr()); + + this._brushController.on('brush', bind(this._onBrush, this)).mount(); + } + + updateZoomBtnStatus(featureModel, ecModel, this, payload, api); + updateBackBtnStatus(featureModel, ecModel); + }; + + DataZoomFeature.prototype.onclick = function (ecModel, api, type) { + handlers$1[type].call(this); + }; + + DataZoomFeature.prototype.remove = function (ecModel, api) { + this._brushController && this._brushController.unmount(); + }; + + DataZoomFeature.prototype.dispose = function (ecModel, api) { + this._brushController && this._brushController.dispose(); + }; + + DataZoomFeature.prototype._onBrush = function (eventParam) { + var areas = eventParam.areas; + + if (!eventParam.isEnd || !areas.length) { + return; + } + + var snapshot = {}; + var ecModel = this.ecModel; + + this._brushController.updateCovers([]); // remove cover + + + var brushTargetManager = new BrushTargetManager(makeAxisFinder(this.model), ecModel, { + include: ['grid'] + }); + brushTargetManager.matchOutputRanges(areas, ecModel, function (area, coordRange, coordSys) { + if (coordSys.type !== 'cartesian2d') { + return; + } + + var brushType = area.brushType; + + if (brushType === 'rect') { + setBatch('x', coordSys, coordRange[0]); + setBatch('y', coordSys, coordRange[1]); + } else { + setBatch({ + lineX: 'x', + lineY: 'y' + }[brushType], coordSys, coordRange); + } + }); + push(ecModel, snapshot); + + this._dispatchZoomAction(snapshot); + + function setBatch(dimName, coordSys, minMax) { + var axis = coordSys.getAxis(dimName); + var axisModel = axis.model; + var dataZoomModel = findDataZoom(dimName, axisModel, ecModel); // Restrict range. + + var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy(axisModel).getMinMaxSpan(); + + if (minMaxSpan.minValueSpan != null || minMaxSpan.maxValueSpan != null) { + minMax = sliderMove(0, minMax.slice(), axis.scale.getExtent(), 0, minMaxSpan.minValueSpan, minMaxSpan.maxValueSpan); + } + + dataZoomModel && (snapshot[dataZoomModel.id] = { + dataZoomId: dataZoomModel.id, + startValue: minMax[0], + endValue: minMax[1] + }); + } + + function findDataZoom(dimName, axisModel, ecModel) { + var found; + ecModel.eachComponent({ + mainType: 'dataZoom', + subType: 'select' + }, function (dzModel) { + var has = dzModel.getAxisModel(dimName, axisModel.componentIndex); + has && (found = dzModel); + }); + return found; + } + }; + + DataZoomFeature.prototype._dispatchZoomAction = function (snapshot) { + var batch = []; // Convert from hash map to array. + + each$a(snapshot, function (batchItem, dataZoomId) { + batch.push(clone(batchItem)); + }); + batch.length && this.api.dispatchAction({ + type: 'dataZoom', + from: this.uid, + batch: batch + }); + }; + + DataZoomFeature.getDefaultOption = function (ecModel) { + var defaultOption = { + show: true, + filterMode: 'filter', + // Icon group + icon: { + zoom: 'M0,13.5h26.9 M13.5,26.9V0 M32.1,13.5H58V58H13.5 V32.1', + back: 'M22,1.4L9.9,13.5l12.3,12.3 M10.3,13.5H54.9v44.6 H10.3v-26' + }, + // `zoom`, `back` + title: ecModel.getLocaleModel().get(['toolbox', 'dataZoom', 'title']), + brushStyle: { + borderWidth: 0, + color: 'rgba(210,219,238,0.2)' + } + }; + return defaultOption; + }; + + return DataZoomFeature; + }(ToolboxFeature); + + var handlers$1 = { + zoom: function () { + var nextActive = !this._isZoomActive; + this.api.dispatchAction({ + type: 'takeGlobalCursor', + key: 'dataZoomSelect', + dataZoomSelectActive: nextActive + }); + }, + back: function () { + this._dispatchZoomAction(pop(this.ecModel)); + } + }; + + function makeAxisFinder(dzFeatureModel) { + var setting = { + xAxisIndex: dzFeatureModel.get('xAxisIndex', true), + yAxisIndex: dzFeatureModel.get('yAxisIndex', true), + xAxisId: dzFeatureModel.get('xAxisId', true), + yAxisId: dzFeatureModel.get('yAxisId', true) + }; // If both `xAxisIndex` `xAxisId` not set, it means 'all'. + // If both `yAxisIndex` `yAxisId` not set, it means 'all'. + // Some old cases set like this below to close yAxis control but leave xAxis control: + // `{ feature: { dataZoom: { yAxisIndex: false } }`. + + if (setting.xAxisIndex == null && setting.xAxisId == null) { + setting.xAxisIndex = 'all'; + } + + if (setting.yAxisIndex == null && setting.yAxisId == null) { + setting.yAxisIndex = 'all'; + } + + return setting; + } + + function updateBackBtnStatus(featureModel, ecModel) { + featureModel.setIconStatus('back', count(ecModel) > 1 ? 'emphasis' : 'normal'); + } + + function updateZoomBtnStatus(featureModel, ecModel, view, payload, api) { + var zoomActive = view._isZoomActive; + + if (payload && payload.type === 'takeGlobalCursor') { + zoomActive = payload.key === 'dataZoomSelect' ? payload.dataZoomSelectActive : false; + } + + view._isZoomActive = zoomActive; + featureModel.setIconStatus('zoom', zoomActive ? 'emphasis' : 'normal'); + var brushTargetManager = new BrushTargetManager(makeAxisFinder(featureModel), ecModel, { + include: ['grid'] + }); + var panels = brushTargetManager.makePanelOpts(api, function (targetInfo) { + return targetInfo.xAxisDeclared && !targetInfo.yAxisDeclared ? 'lineX' : !targetInfo.xAxisDeclared && targetInfo.yAxisDeclared ? 'lineY' : 'rect'; + }); + + view._brushController.setPanels(panels).enableBrush(zoomActive && panels.length ? { + brushType: 'auto', + brushStyle: featureModel.getModel('brushStyle').getItemStyle() + } : false); + } + + registerInternalOptionCreator('dataZoom', function (ecModel) { + var toolboxModel = ecModel.getComponent('toolbox', 0); + var featureDataZoomPath = ['feature', 'dataZoom']; + + if (!toolboxModel || toolboxModel.get(featureDataZoomPath) == null) { + return; + } + + var dzFeatureModel = toolboxModel.getModel(featureDataZoomPath); + var dzOptions = []; + var finder = makeAxisFinder(dzFeatureModel); + var finderResult = parseFinder(ecModel, finder); + each$a(finderResult.xAxisModels, function (axisModel) { + return buildInternalOptions(axisModel, 'xAxis', 'xAxisIndex'); + }); + each$a(finderResult.yAxisModels, function (axisModel) { + return buildInternalOptions(axisModel, 'yAxis', 'yAxisIndex'); + }); + + function buildInternalOptions(axisModel, axisMainType, axisIndexPropName) { + var axisIndex = axisModel.componentIndex; + var newOpt = { + type: 'select', + $fromToolbox: true, + // Default to be filter + filterMode: dzFeatureModel.get('filterMode', true) || 'filter', + // Id for merge mapping. + id: DATA_ZOOM_ID_BASE + axisMainType + axisIndex + }; + newOpt[axisIndexPropName] = axisIndex; + dzOptions.push(newOpt); + } + + return dzOptions; + }); + + function install$z(registers) { + registers.registerComponentModel(ToolboxModel); + registers.registerComponentView(ToolboxView); + registerFeature('saveAsImage', SaveAsImage); + registerFeature('magicType', MagicType); + registerFeature('dataView', DataView); + registerFeature('dataZoom', DataZoomFeature); + registerFeature('restore', RestoreOption); + use(install$y); + } + + var TooltipModel = + /** @class */ + function (_super) { + __extends(TooltipModel, _super); + + function TooltipModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = TooltipModel.type; + return _this; + } + + TooltipModel.type = 'tooltip'; + TooltipModel.dependencies = ['axisPointer']; + TooltipModel.defaultOption = { + // zlevel: 0, + z: 60, + show: true, + // tooltip main content + showContent: true, + // 'trigger' only works on coordinate system. + // 'item' | 'axis' | 'none' + trigger: 'item', + // 'click' | 'mousemove' | 'none' + triggerOn: 'mousemove|click', + alwaysShowContent: false, + displayMode: 'single', + renderMode: 'auto', + // whether restraint content inside viewRect. + // If renderMode: 'richText', default true. + // If renderMode: 'html', defaut false (for backward compat). + confine: null, + showDelay: 0, + hideDelay: 100, + // Animation transition time, unit is second + transitionDuration: 0.4, + enterable: false, + backgroundColor: '#fff', + // box shadow + shadowBlur: 10, + shadowColor: 'rgba(0, 0, 0, .2)', + shadowOffsetX: 1, + shadowOffsetY: 2, + // tooltip border radius, unit is px, default is 4 + borderRadius: 4, + // tooltip border width, unit is px, default is 0 (no border) + borderWidth: 1, + // Tooltip inside padding, default is 5 for all direction + // Array is allowed to set up, right, bottom, left, same with css + // The default value: See `tooltip/tooltipMarkup.ts#getPaddingFromTooltipModel`. + padding: null, + // Extra css text + extraCssText: '', + // axis indicator, trigger by axis + axisPointer: { + // default is line + // legal values: 'line' | 'shadow' | 'cross' + type: 'line', + // Valid when type is line, appoint tooltip line locate on which line. Optional + // legal values: 'x' | 'y' | 'angle' | 'radius' | 'auto' + // default is 'auto', chose the axis which type is category. + // for multiply y axis, cartesian coord chose x axis, polar chose angle axis + axis: 'auto', + animation: 'auto', + animationDurationUpdate: 200, + animationEasingUpdate: 'exponentialOut', + crossStyle: { + color: '#999', + width: 1, + type: 'dashed', + // TODO formatter + textStyle: {} + } // lineStyle and shadowStyle should not be specified here, + // otherwise it will always override those styles on option.axisPointer. + + }, + textStyle: { + color: '#666', + fontSize: 14 + } + }; + return TooltipModel; + }(ComponentModel); + + /* global document */ + + function shouldTooltipConfine(tooltipModel) { + var confineOption = tooltipModel.get('confine'); + return confineOption != null ? !!confineOption // In richText mode, the outside part can not be visible. + : tooltipModel.get('renderMode') === 'richText'; + } + + function testStyle(styleProps) { + if (!env.domSupported) { + return; + } + + var style = document.documentElement.style; + + for (var i = 0, len = styleProps.length; i < len; i++) { + if (styleProps[i] in style) { + return styleProps[i]; + } + } + } + + var TRANSFORM_VENDOR = testStyle(['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']); + var TRANSITION_VENDOR = testStyle(['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']); + function toCSSVendorPrefix(styleVendor, styleProp) { + if (!styleVendor) { + return styleProp; + } + + styleProp = toCamelCase(styleProp, true); + var idx = styleVendor.indexOf(styleProp); + styleVendor = idx === -1 ? styleProp : "-" + styleVendor.slice(0, idx) + "-" + styleProp; + return styleVendor.toLowerCase(); + } + function getComputedStyle(el, style) { + var stl = el.currentStyle || document.defaultView && document.defaultView.getComputedStyle(el); + return stl ? style ? stl[style] : stl : null; + } + + /* global document, window */ + + var CSS_TRANSITION_VENDOR = toCSSVendorPrefix(TRANSITION_VENDOR, 'transition'); + var CSS_TRANSFORM_VENDOR = toCSSVendorPrefix(TRANSFORM_VENDOR, 'transform'); // eslint-disable-next-line + + var gCssText = "position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;" + (env.transform3dSupported ? 'will-change:transform;' : ''); + + function mirrorPos(pos) { + pos = pos === 'left' ? 'right' : pos === 'right' ? 'left' : pos === 'top' ? 'bottom' : 'top'; + return pos; + } + + function assembleArrow(tooltipModel, borderColor, arrowPosition) { + if (!isString(arrowPosition) || arrowPosition === 'inside') { + return ''; + } + + var backgroundColor = tooltipModel.get('backgroundColor'); + var borderWidth = tooltipModel.get('borderWidth'); + borderColor = convertToColorString(borderColor); + var arrowPos = mirrorPos(arrowPosition); + var arrowSize = Math.max(Math.round(borderWidth) * 1.5, 6); + var positionStyle = ''; + var transformStyle = CSS_TRANSFORM_VENDOR + ':'; + var rotateDeg; + + if (indexOf(['left', 'right'], arrowPos) > -1) { + positionStyle += 'top:50%'; + transformStyle += "translateY(-50%) rotate(" + (rotateDeg = arrowPos === 'left' ? -225 : -45) + "deg)"; + } else { + positionStyle += 'left:50%'; + transformStyle += "translateX(-50%) rotate(" + (rotateDeg = arrowPos === 'top' ? 225 : 45) + "deg)"; + } + + var rotateRadian = rotateDeg * Math.PI / 180; + var arrowWH = arrowSize + borderWidth; + var rotatedWH = arrowWH * Math.abs(Math.cos(rotateRadian)) + arrowWH * Math.abs(Math.sin(rotateRadian)); + var arrowOffset = Math.round(((rotatedWH - Math.SQRT2 * borderWidth) / 2 + Math.SQRT2 * borderWidth - (rotatedWH - arrowWH) / 2) * 100) / 100; + positionStyle += ";" + arrowPos + ":-" + arrowOffset + "px"; + var borderStyle = borderColor + " solid " + borderWidth + "px;"; + var styleCss = ["position:absolute;width:" + arrowSize + "px;height:" + arrowSize + "px;", positionStyle + ";" + transformStyle + ";", "border-bottom:" + borderStyle, "border-right:" + borderStyle, "background-color:" + backgroundColor + ";"]; + return "
            "; + } + + function assembleTransition(duration, onlyFade) { + var transitionCurve = 'cubic-bezier(0.23,1,0.32,1)'; + var transitionOption = " " + duration / 2 + "s " + transitionCurve; + var transitionText = "opacity" + transitionOption + ",visibility" + transitionOption; + + if (!onlyFade) { + transitionOption = " " + duration + "s " + transitionCurve; + transitionText += env.transformSupported ? "," + CSS_TRANSFORM_VENDOR + transitionOption : ",left" + transitionOption + ",top" + transitionOption; + } + + return CSS_TRANSITION_VENDOR + ':' + transitionText; + } + + function assembleTransform(x, y, toString) { + // If using float on style, the final width of the dom might + // keep changing slightly while mouse move. So `toFixed(0)` them. + var x0 = x.toFixed(0) + 'px'; + var y0 = y.toFixed(0) + 'px'; // not support transform, use `left` and `top` instead. + + if (!env.transformSupported) { + return toString ? "top:" + y0 + ";left:" + x0 + ";" : [['top', y0], ['left', x0]]; + } // support transform + + + var is3d = env.transform3dSupported; + var translate = "translate" + (is3d ? '3d' : '') + "(" + x0 + "," + y0 + (is3d ? ',0' : '') + ")"; + return toString ? 'top:0;left:0;' + CSS_TRANSFORM_VENDOR + ':' + translate + ';' : [['top', 0], ['left', 0], [TRANSFORM_VENDOR, translate]]; + } + /** + * @param {Object} textStyle + * @return {string} + * @inner + */ + + + function assembleFont(textStyleModel) { + var cssText = []; + var fontSize = textStyleModel.get('fontSize'); + var color = textStyleModel.getTextColor(); + color && cssText.push('color:' + color); + cssText.push('font:' + textStyleModel.getFont()); + fontSize // @ts-ignore, leave it to the tooltip refactor. + && cssText.push('line-height:' + Math.round(fontSize * 3 / 2) + 'px'); + var shadowColor = textStyleModel.get('textShadowColor'); + var shadowBlur = textStyleModel.get('textShadowBlur') || 0; + var shadowOffsetX = textStyleModel.get('textShadowOffsetX') || 0; + var shadowOffsetY = textStyleModel.get('textShadowOffsetY') || 0; + shadowColor && shadowBlur && cssText.push('text-shadow:' + shadowOffsetX + 'px ' + shadowOffsetY + 'px ' + shadowBlur + 'px ' + shadowColor); + each(['decoration', 'align'], function (name) { + var val = textStyleModel.get(name); + val && cssText.push('text-' + name + ':' + val); + }); + return cssText.join(';'); + } + + function assembleCssText(tooltipModel, enableTransition, onlyFade) { + var cssText = []; + var transitionDuration = tooltipModel.get('transitionDuration'); + var backgroundColor = tooltipModel.get('backgroundColor'); + var shadowBlur = tooltipModel.get('shadowBlur'); + var shadowColor = tooltipModel.get('shadowColor'); + var shadowOffsetX = tooltipModel.get('shadowOffsetX'); + var shadowOffsetY = tooltipModel.get('shadowOffsetY'); + var textStyleModel = tooltipModel.getModel('textStyle'); + var padding = getPaddingFromTooltipModel(tooltipModel, 'html'); + var boxShadow = shadowOffsetX + "px " + shadowOffsetY + "px " + shadowBlur + "px " + shadowColor; + cssText.push('box-shadow:' + boxShadow); // Animation transition. Do not animate when transitionDuration is 0. + + enableTransition && transitionDuration && cssText.push(assembleTransition(transitionDuration, onlyFade)); + + if (backgroundColor) { + cssText.push('background-color:' + backgroundColor); + } // Border style + + + each(['width', 'color', 'radius'], function (name) { + var borderName = 'border-' + name; + var camelCase = toCamelCase(borderName); + var val = tooltipModel.get(camelCase); + val != null && cssText.push(borderName + ':' + val + (name === 'color' ? '' : 'px')); + }); // Text style + + cssText.push(assembleFont(textStyleModel)); // Padding + + if (padding != null) { + cssText.push('padding:' + normalizeCssArray$1(padding).join('px ') + 'px'); + } + + return cssText.join(';') + ';'; + } // If not able to make, do not modify the input `out`. + + + function makeStyleCoord(out, zr, appendToBody, zrX, zrY) { + var zrPainter = zr && zr.painter; + + if (appendToBody) { + var zrViewportRoot = zrPainter && zrPainter.getViewportRoot(); + + if (zrViewportRoot) { + // Some APPs might use scale on body, so we support CSS transform here. + transformLocalCoord(out, zrViewportRoot, document.body, zrX, zrY); + } + } else { + out[0] = zrX; + out[1] = zrY; // xy should be based on canvas root. But tooltipContent is + // the sibling of canvas root. So padding of ec container + // should be considered here. + + var viewportRootOffset = zrPainter && zrPainter.getViewportRootOffset(); + + if (viewportRootOffset) { + out[0] += viewportRootOffset.offsetLeft; + out[1] += viewportRootOffset.offsetTop; + } + } + + out[2] = out[0] / zr.getWidth(); + out[3] = out[1] / zr.getHeight(); + } + + var TooltipHTMLContent = + /** @class */ + function () { + function TooltipHTMLContent(container, api, opt) { + this._show = false; + this._styleCoord = [0, 0, 0, 0]; + this._enterable = true; + this._firstShow = true; + this._longHide = true; + + if (env.wxa) { + return null; + } + + var el = document.createElement('div'); // TODO: TYPE + + el.domBelongToZr = true; + this.el = el; + var zr = this._zr = api.getZr(); + var appendToBody = this._appendToBody = opt && opt.appendToBody; + makeStyleCoord(this._styleCoord, zr, appendToBody, api.getWidth() / 2, api.getHeight() / 2); + + if (appendToBody) { + document.body.appendChild(el); + } else { + container.appendChild(el); + } + + this._container = container; // FIXME + // Is it needed to trigger zr event manually if + // the browser do not support `pointer-events: none`. + + var self = this; + + el.onmouseenter = function () { + // clear the timeout in hideLater and keep showing tooltip + if (self._enterable) { + clearTimeout(self._hideTimeout); + self._show = true; + } + + self._inContent = true; + }; + + el.onmousemove = function (e) { + e = e || window.event; + + if (!self._enterable) { + // `pointer-events: none` is set to tooltip content div + // if `enterable` is set as `false`, and `el.onmousemove` + // can not be triggered. But in browser that do not + // support `pointer-events`, we need to do this: + // Try trigger zrender event to avoid mouse + // in and out shape too frequently + var handler = zr.handler; + var zrViewportRoot = zr.painter.getViewportRoot(); + normalizeEvent(zrViewportRoot, e, true); + handler.dispatch('mousemove', e); + } + }; + + el.onmouseleave = function () { + // set `_inContent` to `false` before `hideLater` + self._inContent = false; + + if (self._enterable) { + if (self._show) { + self.hideLater(self._hideDelay); + } + } + }; + } + /** + * Update when tooltip is rendered + */ + + + TooltipHTMLContent.prototype.update = function (tooltipModel) { + // FIXME + // Move this logic to ec main? + var container = this._container; + var position = getComputedStyle(container, 'position'); + var domStyle = container.style; + + if (domStyle.position !== 'absolute' && position !== 'absolute') { + domStyle.position = 'relative'; + } // move tooltip if chart resized + + + var alwaysShowContent = tooltipModel.get('alwaysShowContent'); + alwaysShowContent && this._moveIfResized(); // update className + + this.el.className = tooltipModel.get('className') || ''; // Hide the tooltip + // PENDING + // this.hide(); + }; + + TooltipHTMLContent.prototype.show = function (tooltipModel, nearPointColor) { + clearTimeout(this._hideTimeout); + clearTimeout(this._longHideTimeout); + var el = this.el; + var style = el.style; + var styleCoord = this._styleCoord; + + if (!el.innerHTML) { + style.display = 'none'; + } else { + style.cssText = gCssText + assembleCssText(tooltipModel, !this._firstShow, this._longHide) // initial transform + + assembleTransform(styleCoord[0], styleCoord[1], true) + ("border-color:" + convertToColorString(nearPointColor) + ";") + (tooltipModel.get('extraCssText') || '') // If mouse occasionally move over the tooltip, a mouseout event will be + // triggered by canvas, and cause some unexpectable result like dragging + // stop, "unfocusAdjacency". Here `pointer-events: none` is used to solve + // it. Although it is not supported by IE8~IE10, fortunately it is a rare + // scenario. + + (";pointer-events:" + (this._enterable ? 'auto' : 'none')); + } + + this._show = true; + this._firstShow = false; + this._longHide = false; + }; + + TooltipHTMLContent.prototype.setContent = function (content, markers, tooltipModel, borderColor, arrowPosition) { + var el = this.el; + + if (content == null) { + el.innerHTML = ''; + return; + } + + var arrow = ''; + + if (isString(arrowPosition) && tooltipModel.get('trigger') === 'item' && !shouldTooltipConfine(tooltipModel)) { + arrow = assembleArrow(tooltipModel, borderColor, arrowPosition); + } + + if (isString(content)) { + el.innerHTML = content + arrow; + } else if (content) { + // Clear previous + el.innerHTML = ''; + + if (!isArray(content)) { + content = [content]; + } + + for (var i = 0; i < content.length; i++) { + if (isDom(content[i]) && content[i].parentNode !== el) { + el.appendChild(content[i]); + } + } // no arrow if empty + + + if (arrow && el.childNodes.length) { + // no need to create a new parent element, but it's not supported by IE 10 and older. + // const arrowEl = document.createRange().createContextualFragment(arrow); + var arrowEl = document.createElement('div'); + arrowEl.innerHTML = arrow; + el.appendChild(arrowEl); + } + } + }; + + TooltipHTMLContent.prototype.setEnterable = function (enterable) { + this._enterable = enterable; + }; + + TooltipHTMLContent.prototype.getSize = function () { + var el = this.el; + return [el.offsetWidth, el.offsetHeight]; + }; + + TooltipHTMLContent.prototype.moveTo = function (zrX, zrY) { + var styleCoord = this._styleCoord; + makeStyleCoord(styleCoord, this._zr, this._appendToBody, zrX, zrY); + + if (styleCoord[0] != null && styleCoord[1] != null) { + var style_1 = this.el.style; + var transforms = assembleTransform(styleCoord[0], styleCoord[1]); + each(transforms, function (transform) { + style_1[transform[0]] = transform[1]; + }); + } + }; + /** + * when `alwaysShowContent` is true, + * move the tooltip after chart resized + */ + + + TooltipHTMLContent.prototype._moveIfResized = function () { + // The ratio of left to width + var ratioX = this._styleCoord[2]; // The ratio of top to height + + var ratioY = this._styleCoord[3]; + this.moveTo(ratioX * this._zr.getWidth(), ratioY * this._zr.getHeight()); + }; + + TooltipHTMLContent.prototype.hide = function () { + var _this = this; + + var style = this.el.style; + style.visibility = 'hidden'; + style.opacity = '0'; + env.transform3dSupported && (style.willChange = ''); + this._show = false; + this._longHideTimeout = setTimeout(function () { + return _this._longHide = true; + }, 500); + }; + + TooltipHTMLContent.prototype.hideLater = function (time) { + if (this._show && !(this._inContent && this._enterable)) { + if (time) { + this._hideDelay = time; // Set show false to avoid invoke hideLater multiple times + + this._show = false; + this._hideTimeout = setTimeout(bind(this.hide, this), time); + } else { + this.hide(); + } + } + }; + + TooltipHTMLContent.prototype.isShow = function () { + return this._show; + }; + + TooltipHTMLContent.prototype.dispose = function () { + this.el.parentNode.removeChild(this.el); + }; + + return TooltipHTMLContent; + }(); + + var TooltipRichContent = + /** @class */ + function () { + function TooltipRichContent(api) { + this._show = false; + this._styleCoord = [0, 0, 0, 0]; + this._enterable = true; + this._zr = api.getZr(); + makeStyleCoord$1(this._styleCoord, this._zr, api.getWidth() / 2, api.getHeight() / 2); + } + /** + * Update when tooltip is rendered + */ + + + TooltipRichContent.prototype.update = function (tooltipModel) { + var alwaysShowContent = tooltipModel.get('alwaysShowContent'); + alwaysShowContent && this._moveIfResized(); + }; + + TooltipRichContent.prototype.show = function () { + if (this._hideTimeout) { + clearTimeout(this._hideTimeout); + } + + this.el.show(); + this._show = true; + }; + /** + * Set tooltip content + */ + + + TooltipRichContent.prototype.setContent = function (content, markupStyleCreator, tooltipModel, borderColor, arrowPosition) { + var _this = this; + + if (isObject(content)) { + throwError("development" !== 'production' ? 'Passing DOM nodes as content is not supported in richText tooltip!' : ''); + } + + if (this.el) { + this._zr.remove(this.el); + } + + var textStyleModel = tooltipModel.getModel('textStyle'); + this.el = new ZRText({ + style: { + rich: markupStyleCreator.richTextStyles, + text: content, + lineHeight: 22, + borderWidth: 1, + borderColor: borderColor, + textShadowColor: textStyleModel.get('textShadowColor'), + fill: tooltipModel.get(['textStyle', 'color']), + padding: getPaddingFromTooltipModel(tooltipModel, 'richText'), + verticalAlign: 'top', + align: 'left' + }, + z: tooltipModel.get('z') + }); + each(['backgroundColor', 'borderRadius', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'], function (propName) { + _this.el.style[propName] = tooltipModel.get(propName); + }); + each(['textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY'], function (propName) { + _this.el.style[propName] = textStyleModel.get(propName) || 0; + }); + + this._zr.add(this.el); + + var self = this; + this.el.on('mouseover', function () { + // clear the timeout in hideLater and keep showing tooltip + if (self._enterable) { + clearTimeout(self._hideTimeout); + self._show = true; + } + + self._inContent = true; + }); + this.el.on('mouseout', function () { + if (self._enterable) { + if (self._show) { + self.hideLater(self._hideDelay); + } + } + + self._inContent = false; + }); + }; + + TooltipRichContent.prototype.setEnterable = function (enterable) { + this._enterable = enterable; + }; + + TooltipRichContent.prototype.getSize = function () { + var el = this.el; + var bounding = this.el.getBoundingRect(); // bounding rect does not include shadow. For renderMode richText, + // if overflow, it will be cut. So calculate them accurately. + + var shadowOuterSize = calcShadowOuterSize(el.style); + return [bounding.width + shadowOuterSize.left + shadowOuterSize.right, bounding.height + shadowOuterSize.top + shadowOuterSize.bottom]; + }; + + TooltipRichContent.prototype.moveTo = function (x, y) { + var el = this.el; + + if (el) { + var styleCoord = this._styleCoord; + makeStyleCoord$1(styleCoord, this._zr, x, y); + x = styleCoord[0]; + y = styleCoord[1]; + var style = el.style; + var borderWidth = mathMaxWith0(style.borderWidth || 0); + var shadowOuterSize = calcShadowOuterSize(style); // rich text x, y do not include border. + + el.x = x + borderWidth + shadowOuterSize.left; + el.y = y + borderWidth + shadowOuterSize.top; + el.markRedraw(); + } + }; + /** + * when `alwaysShowContent` is true, + * move the tooltip after chart resized + */ + + + TooltipRichContent.prototype._moveIfResized = function () { + // The ratio of left to width + var ratioX = this._styleCoord[2]; // The ratio of top to height + + var ratioY = this._styleCoord[3]; + this.moveTo(ratioX * this._zr.getWidth(), ratioY * this._zr.getHeight()); + }; + + TooltipRichContent.prototype.hide = function () { + if (this.el) { + this.el.hide(); + } + + this._show = false; + }; + + TooltipRichContent.prototype.hideLater = function (time) { + if (this._show && !(this._inContent && this._enterable)) { + if (time) { + this._hideDelay = time; // Set show false to avoid invoke hideLater multiple times + + this._show = false; + this._hideTimeout = setTimeout(bind(this.hide, this), time); + } else { + this.hide(); + } + } + }; + + TooltipRichContent.prototype.isShow = function () { + return this._show; + }; + + TooltipRichContent.prototype.dispose = function () { + this._zr.remove(this.el); + }; + + return TooltipRichContent; + }(); + + function mathMaxWith0(val) { + return Math.max(0, val); + } + + function calcShadowOuterSize(style) { + var shadowBlur = mathMaxWith0(style.shadowBlur || 0); + var shadowOffsetX = mathMaxWith0(style.shadowOffsetX || 0); + var shadowOffsetY = mathMaxWith0(style.shadowOffsetY || 0); + return { + left: mathMaxWith0(shadowBlur - shadowOffsetX), + right: mathMaxWith0(shadowBlur + shadowOffsetX), + top: mathMaxWith0(shadowBlur - shadowOffsetY), + bottom: mathMaxWith0(shadowBlur + shadowOffsetY) + }; + } + + function makeStyleCoord$1(out, zr, zrX, zrY) { + out[0] = zrX; + out[1] = zrY; + out[2] = out[0] / zr.getWidth(); + out[3] = out[1] / zr.getHeight(); + } + + var proxyRect = new Rect({ + shape: { + x: -1, + y: -1, + width: 2, + height: 2 + } + }); + + var TooltipView = + /** @class */ + function (_super) { + __extends(TooltipView, _super); + + function TooltipView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = TooltipView.type; + return _this; + } + + TooltipView.prototype.init = function (ecModel, api) { + if (env.node || !api.getDom()) { + return; + } + + var tooltipModel = ecModel.getComponent('tooltip'); + var renderMode = this._renderMode = getTooltipRenderMode(tooltipModel.get('renderMode')); + this._tooltipContent = renderMode === 'richText' ? new TooltipRichContent(api) : new TooltipHTMLContent(api.getDom(), api, { + appendToBody: tooltipModel.get('appendToBody', true) + }); + }; + + TooltipView.prototype.render = function (tooltipModel, ecModel, api) { + if (env.node || !api.getDom()) { + return; + } // Reset + + + this.group.removeAll(); + this._tooltipModel = tooltipModel; + this._ecModel = ecModel; + this._api = api; + /** + * @private + * @type {boolean} + */ + + this._alwaysShowContent = tooltipModel.get('alwaysShowContent'); + var tooltipContent = this._tooltipContent; + tooltipContent.update(tooltipModel); + tooltipContent.setEnterable(tooltipModel.get('enterable')); + + this._initGlobalListener(); + + this._keepShow(); // PENDING + // `mousemove` event will be triggered very frequently when the mouse moves fast, + // which causes that the `updatePosition` function was also called frequently. + // In Chrome with devtools open and Firefox, tooltip looks laggy and shakes. See #14695 #16101 + // To avoid frequent triggering, + // consider throttling it in 50ms when transition is enabled + + + if (this._renderMode !== 'richText' && tooltipModel.get('transitionDuration')) { + createOrUpdate(this, '_updatePosition', 50, 'fixRate'); + } else { + clear(this, '_updatePosition'); + } + }; + + TooltipView.prototype._initGlobalListener = function () { + var tooltipModel = this._tooltipModel; + var triggerOn = tooltipModel.get('triggerOn'); + register('itemTooltip', this._api, bind(function (currTrigger, e, dispatchAction) { + // If 'none', it is not controlled by mouse totally. + if (triggerOn !== 'none') { + if (triggerOn.indexOf(currTrigger) >= 0) { + this._tryShow(e, dispatchAction); + } else if (currTrigger === 'leave') { + this._hide(dispatchAction); + } + } + }, this)); + }; + + TooltipView.prototype._keepShow = function () { + var tooltipModel = this._tooltipModel; + var ecModel = this._ecModel; + var api = this._api; // Try to keep the tooltip show when refreshing + + if (this._lastX != null && this._lastY != null // When user is willing to control tooltip totally using API, + // self.manuallyShowTip({x, y}) might cause tooltip hide, + // which is not expected. + && tooltipModel.get('triggerOn') !== 'none') { + var self_1 = this; + clearTimeout(this._refreshUpdateTimeout); + this._refreshUpdateTimeout = setTimeout(function () { + // Show tip next tick after other charts are rendered + // In case highlight action has wrong result + // FIXME + !api.isDisposed() && self_1.manuallyShowTip(tooltipModel, ecModel, api, { + x: self_1._lastX, + y: self_1._lastY, + dataByCoordSys: self_1._lastDataByCoordSys + }); + }); + } + }; + /** + * Show tip manually by + * dispatchAction({ + * type: 'showTip', + * x: 10, + * y: 10 + * }); + * Or + * dispatchAction({ + * type: 'showTip', + * seriesIndex: 0, + * dataIndex or dataIndexInside or name + * }); + * + * TODO Batch + */ + + + TooltipView.prototype.manuallyShowTip = function (tooltipModel, ecModel, api, payload) { + if (payload.from === this.uid || env.node || !api.getDom()) { + return; + } + + var dispatchAction = makeDispatchAction$1(payload, api); // Reset ticket + + this._ticket = ''; // When triggered from axisPointer. + + var dataByCoordSys = payload.dataByCoordSys; + var cmptRef = findComponentReference(payload, ecModel, api); + + if (cmptRef) { + var rect = cmptRef.el.getBoundingRect().clone(); + rect.applyTransform(cmptRef.el.transform); + + this._tryShow({ + offsetX: rect.x + rect.width / 2, + offsetY: rect.y + rect.height / 2, + target: cmptRef.el, + position: payload.position, + // When manully trigger, the mouse is not on the el, so we'd better to + // position tooltip on the bottom of the el and display arrow is possible. + positionDefault: 'bottom' + }, dispatchAction); + } else if (payload.tooltip && payload.x != null && payload.y != null) { + var el = proxyRect; + el.x = payload.x; + el.y = payload.y; + el.update(); + getECData(el).tooltipConfig = { + name: null, + option: payload.tooltip + }; // Manually show tooltip while view is not using zrender elements. + + this._tryShow({ + offsetX: payload.x, + offsetY: payload.y, + target: el + }, dispatchAction); + } else if (dataByCoordSys) { + this._tryShow({ + offsetX: payload.x, + offsetY: payload.y, + position: payload.position, + dataByCoordSys: dataByCoordSys, + tooltipOption: payload.tooltipOption + }, dispatchAction); + } else if (payload.seriesIndex != null) { + if (this._manuallyAxisShowTip(tooltipModel, ecModel, api, payload)) { + return; + } + + var pointInfo = findPointFromSeries(payload, ecModel); + var cx = pointInfo.point[0]; + var cy = pointInfo.point[1]; + + if (cx != null && cy != null) { + this._tryShow({ + offsetX: cx, + offsetY: cy, + target: pointInfo.el, + position: payload.position, + // When manully trigger, the mouse is not on the el, so we'd better to + // position tooltip on the bottom of the el and display arrow is possible. + positionDefault: 'bottom' + }, dispatchAction); + } + } else if (payload.x != null && payload.y != null) { + // FIXME + // should wrap dispatchAction like `axisPointer/globalListener` ? + api.dispatchAction({ + type: 'updateAxisPointer', + x: payload.x, + y: payload.y + }); + + this._tryShow({ + offsetX: payload.x, + offsetY: payload.y, + position: payload.position, + target: api.getZr().findHover(payload.x, payload.y).target + }, dispatchAction); + } + }; + + TooltipView.prototype.manuallyHideTip = function (tooltipModel, ecModel, api, payload) { + var tooltipContent = this._tooltipContent; + + if (!this._alwaysShowContent && this._tooltipModel) { + tooltipContent.hideLater(this._tooltipModel.get('hideDelay')); + } + + this._lastX = this._lastY = this._lastDataByCoordSys = null; + + if (payload.from !== this.uid) { + this._hide(makeDispatchAction$1(payload, api)); + } + }; // Be compatible with previous design, that is, when tooltip.type is 'axis' and + // dispatchAction 'showTip' with seriesIndex and dataIndex will trigger axis pointer + // and tooltip. + + + TooltipView.prototype._manuallyAxisShowTip = function (tooltipModel, ecModel, api, payload) { + var seriesIndex = payload.seriesIndex; + var dataIndex = payload.dataIndex; // @ts-ignore + + var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo; + + if (seriesIndex == null || dataIndex == null || coordSysAxesInfo == null) { + return; + } + + var seriesModel = ecModel.getSeriesByIndex(seriesIndex); + + if (!seriesModel) { + return; + } + + var data = seriesModel.getData(); + var tooltipCascadedModel = buildTooltipModel([data.getItemModel(dataIndex), seriesModel, (seriesModel.coordinateSystem || {}).model], this._tooltipModel); + + if (tooltipCascadedModel.get('trigger') !== 'axis') { + return; + } + + api.dispatchAction({ + type: 'updateAxisPointer', + seriesIndex: seriesIndex, + dataIndex: dataIndex, + position: payload.position + }); + return true; + }; + + TooltipView.prototype._tryShow = function (e, dispatchAction) { + var el = e.target; + var tooltipModel = this._tooltipModel; + + if (!tooltipModel) { + return; + } // Save mouse x, mouse y. So we can try to keep showing the tip if chart is refreshed + + + this._lastX = e.offsetX; + this._lastY = e.offsetY; + var dataByCoordSys = e.dataByCoordSys; + + if (dataByCoordSys && dataByCoordSys.length) { + this._showAxisTooltip(dataByCoordSys, e); + } else if (el) { + this._lastDataByCoordSys = null; + var seriesDispatcher_1; + var cmptDispatcher_1; + findEventDispatcher(el, function (target) { + // Always show item tooltip if mouse is on the element with dataIndex + if (getECData(target).dataIndex != null) { + seriesDispatcher_1 = target; + return true; + } // Tooltip provided directly. Like legend. + + + if (getECData(target).tooltipConfig != null) { + cmptDispatcher_1 = target; + return true; + } + }, true); + + if (seriesDispatcher_1) { + this._showSeriesItemTooltip(e, seriesDispatcher_1, dispatchAction); + } else if (cmptDispatcher_1) { + this._showComponentItemTooltip(e, cmptDispatcher_1, dispatchAction); + } else { + this._hide(dispatchAction); + } + } else { + this._lastDataByCoordSys = null; + + this._hide(dispatchAction); + } + }; + + TooltipView.prototype._showOrMove = function (tooltipModel, cb) { + // showDelay is used in this case: tooltip.enterable is set + // as true. User intent to move mouse into tooltip and click + // something. `showDelay` makes it easier to enter the content + // but tooltip do not move immediately. + var delay = tooltipModel.get('showDelay'); + cb = bind(cb, this); + clearTimeout(this._showTimout); + delay > 0 ? this._showTimout = setTimeout(cb, delay) : cb(); + }; + + TooltipView.prototype._showAxisTooltip = function (dataByCoordSys, e) { + var ecModel = this._ecModel; + var globalTooltipModel = this._tooltipModel; + var point = [e.offsetX, e.offsetY]; + var singleTooltipModel = buildTooltipModel([e.tooltipOption], globalTooltipModel); + var renderMode = this._renderMode; + var cbParamsList = []; + var articleMarkup = createTooltipMarkup('section', { + blocks: [], + noHeader: true + }); // Only for legacy: `Serise['formatTooltip']` returns a string. + + var markupTextArrLegacy = []; + var markupStyleCreator = new TooltipMarkupStyleCreator(); + each(dataByCoordSys, function (itemCoordSys) { + each(itemCoordSys.dataByAxis, function (axisItem) { + var axisModel = ecModel.getComponent(axisItem.axisDim + 'Axis', axisItem.axisIndex); + var axisValue = axisItem.value; + + if (!axisModel || axisValue == null) { + return; + } + + var axisValueLabel = getValueLabel(axisValue, axisModel.axis, ecModel, axisItem.seriesDataIndices, axisItem.valueLabelOpt); + var axisSectionMarkup = createTooltipMarkup('section', { + header: axisValueLabel, + noHeader: !trim(axisValueLabel), + sortBlocks: true, + blocks: [] + }); + articleMarkup.blocks.push(axisSectionMarkup); + each(axisItem.seriesDataIndices, function (idxItem) { + var series = ecModel.getSeriesByIndex(idxItem.seriesIndex); + var dataIndex = idxItem.dataIndexInside; + var cbParams = series.getDataParams(dataIndex); // Can't find data. + + if (cbParams.dataIndex < 0) { + return; + } + + cbParams.axisDim = axisItem.axisDim; + cbParams.axisIndex = axisItem.axisIndex; + cbParams.axisType = axisItem.axisType; + cbParams.axisId = axisItem.axisId; + cbParams.axisValue = getAxisRawValue(axisModel.axis, { + value: axisValue + }); + cbParams.axisValueLabel = axisValueLabel; // Pre-create marker style for makers. Users can assemble richText + // text in `formatter` callback and use those markers style. + + cbParams.marker = markupStyleCreator.makeTooltipMarker('item', convertToColorString(cbParams.color), renderMode); + var seriesTooltipResult = normalizeTooltipFormatResult(series.formatTooltip(dataIndex, true, null)); + var frag = seriesTooltipResult.frag; + + if (frag) { + var valueFormatter = buildTooltipModel([series], globalTooltipModel).get('valueFormatter'); + axisSectionMarkup.blocks.push(valueFormatter ? extend({ + valueFormatter: valueFormatter + }, frag) : frag); + } + + if (seriesTooltipResult.text) { + markupTextArrLegacy.push(seriesTooltipResult.text); + } + + cbParamsList.push(cbParams); + }); + }); + }); // In most cases, the second axis is displays upper on the first one. + // So we reverse it to look better. + + articleMarkup.blocks.reverse(); + markupTextArrLegacy.reverse(); + var positionExpr = e.position; + var orderMode = singleTooltipModel.get('order'); + var builtMarkupText = buildTooltipMarkup(articleMarkup, markupStyleCreator, renderMode, orderMode, ecModel.get('useUTC'), singleTooltipModel.get('textStyle')); + builtMarkupText && markupTextArrLegacy.unshift(builtMarkupText); + var blockBreak = renderMode === 'richText' ? '\n\n' : '
            '; + var allMarkupText = markupTextArrLegacy.join(blockBreak); + + this._showOrMove(singleTooltipModel, function () { + if (this._updateContentNotChangedOnAxis(dataByCoordSys, cbParamsList)) { + this._updatePosition(singleTooltipModel, positionExpr, point[0], point[1], this._tooltipContent, cbParamsList); + } else { + this._showTooltipContent(singleTooltipModel, allMarkupText, cbParamsList, Math.random() + '', point[0], point[1], positionExpr, null, markupStyleCreator); + } + }); // Do not trigger events here, because this branch only be entered + // from dispatchAction. + + }; + + TooltipView.prototype._showSeriesItemTooltip = function (e, dispatcher, dispatchAction) { + var ecModel = this._ecModel; + var ecData = getECData(dispatcher); // Use dataModel in element if possible + // Used when mouseover on a element like markPoint or edge + // In which case, the data is not main data in series. + + var seriesIndex = ecData.seriesIndex; + var seriesModel = ecModel.getSeriesByIndex(seriesIndex); // For example, graph link. + + var dataModel = ecData.dataModel || seriesModel; + var dataIndex = ecData.dataIndex; + var dataType = ecData.dataType; + var data = dataModel.getData(dataType); + var renderMode = this._renderMode; + var positionDefault = e.positionDefault; + var tooltipModel = buildTooltipModel([data.getItemModel(dataIndex), dataModel, seriesModel && (seriesModel.coordinateSystem || {}).model], this._tooltipModel, positionDefault ? { + position: positionDefault + } : null); + var tooltipTrigger = tooltipModel.get('trigger'); + + if (tooltipTrigger != null && tooltipTrigger !== 'item') { + return; + } + + var params = dataModel.getDataParams(dataIndex, dataType); + var markupStyleCreator = new TooltipMarkupStyleCreator(); // Pre-create marker style for makers. Users can assemble richText + // text in `formatter` callback and use those markers style. + + params.marker = markupStyleCreator.makeTooltipMarker('item', convertToColorString(params.color), renderMode); + var seriesTooltipResult = normalizeTooltipFormatResult(dataModel.formatTooltip(dataIndex, false, dataType)); + var orderMode = tooltipModel.get('order'); + var valueFormatter = tooltipModel.get('valueFormatter'); + var frag = seriesTooltipResult.frag; + var markupText = frag ? buildTooltipMarkup(valueFormatter ? extend({ + valueFormatter: valueFormatter + }, frag) : frag, markupStyleCreator, renderMode, orderMode, ecModel.get('useUTC'), tooltipModel.get('textStyle')) : seriesTooltipResult.text; + var asyncTicket = 'item_' + dataModel.name + '_' + dataIndex; + + this._showOrMove(tooltipModel, function () { + this._showTooltipContent(tooltipModel, markupText, params, asyncTicket, e.offsetX, e.offsetY, e.position, e.target, markupStyleCreator); + }); // FIXME + // duplicated showtip if manuallyShowTip is called from dispatchAction. + + + dispatchAction({ + type: 'showTip', + dataIndexInside: dataIndex, + dataIndex: data.getRawIndex(dataIndex), + seriesIndex: seriesIndex, + from: this.uid + }); + }; + + TooltipView.prototype._showComponentItemTooltip = function (e, el, dispatchAction) { + var ecData = getECData(el); + var tooltipConfig = ecData.tooltipConfig; + var tooltipOpt = tooltipConfig.option || {}; + + if (isString(tooltipOpt)) { + var content = tooltipOpt; + tooltipOpt = { + content: content, + // Fixed formatter + formatter: content + }; + } + + var tooltipModelCascade = [tooltipOpt]; + + var cmpt = this._ecModel.getComponent(ecData.componentMainType, ecData.componentIndex); + + if (cmpt) { + tooltipModelCascade.push(cmpt); + } // In most cases, component tooltip formatter has different params with series tooltip formatter, + // so that they can not share the same formatter. Since the global tooltip formatter is used for series + // by convension, we do not use it as the default formatter for component. + + + tooltipModelCascade.push({ + formatter: tooltipOpt.content + }); + var positionDefault = e.positionDefault; + var subTooltipModel = buildTooltipModel(tooltipModelCascade, this._tooltipModel, positionDefault ? { + position: positionDefault + } : null); + var defaultHtml = subTooltipModel.get('content'); + var asyncTicket = Math.random() + ''; // PENDING: this case do not support richText style yet. + + var markupStyleCreator = new TooltipMarkupStyleCreator(); // Do not check whether `trigger` is 'none' here, because `trigger` + // only works on coordinate system. In fact, we have not found case + // that requires setting `trigger` nothing on component yet. + + this._showOrMove(subTooltipModel, function () { + // Use formatterParams from element defined in component + // Avoid users modify it. + var formatterParams = clone(subTooltipModel.get('formatterParams') || {}); + + this._showTooltipContent(subTooltipModel, defaultHtml, formatterParams, asyncTicket, e.offsetX, e.offsetY, e.position, el, markupStyleCreator); + }); // If not dispatch showTip, tip may be hide triggered by axis. + + + dispatchAction({ + type: 'showTip', + from: this.uid + }); + }; + + TooltipView.prototype._showTooltipContent = function ( // Use Model insteadof TooltipModel because this model may be from series or other options. + // Instead of top level tooltip. + tooltipModel, defaultHtml, params, asyncTicket, x, y, positionExpr, el, markupStyleCreator) { + // Reset ticket + this._ticket = ''; + + if (!tooltipModel.get('showContent') || !tooltipModel.get('show')) { + return; + } + + var tooltipContent = this._tooltipContent; + tooltipContent.setEnterable(tooltipModel.get('enterable')); + var formatter = tooltipModel.get('formatter'); + positionExpr = positionExpr || tooltipModel.get('position'); + var html = defaultHtml; + + var nearPoint = this._getNearestPoint([x, y], params, tooltipModel.get('trigger'), tooltipModel.get('borderColor')); + + var nearPointColor = nearPoint.color; + + if (formatter) { + if (isString(formatter)) { + var useUTC = tooltipModel.ecModel.get('useUTC'); + var params0 = isArray(params) ? params[0] : params; + var isTimeAxis = params0 && params0.axisType && params0.axisType.indexOf('time') >= 0; + html = formatter; + + if (isTimeAxis) { + html = format(params0.axisValue, html, useUTC); + } + + html = formatTpl(html, params, true); + } else if (isFunction(formatter)) { + var callback = bind(function (cbTicket, html) { + if (cbTicket === this._ticket) { + tooltipContent.setContent(html, markupStyleCreator, tooltipModel, nearPointColor, positionExpr); + + this._updatePosition(tooltipModel, positionExpr, x, y, tooltipContent, params, el); + } + }, this); + this._ticket = asyncTicket; + html = formatter(params, asyncTicket, callback); + } else { + html = formatter; + } + } + + tooltipContent.setContent(html, markupStyleCreator, tooltipModel, nearPointColor, positionExpr); + tooltipContent.show(tooltipModel, nearPointColor); + + this._updatePosition(tooltipModel, positionExpr, x, y, tooltipContent, params, el); + }; + + TooltipView.prototype._getNearestPoint = function (point, tooltipDataParams, trigger, borderColor) { + if (trigger === 'axis' || isArray(tooltipDataParams)) { + return { + color: borderColor || (this._renderMode === 'html' ? '#fff' : 'none') + }; + } + + if (!isArray(tooltipDataParams)) { + return { + color: borderColor || tooltipDataParams.color || tooltipDataParams.borderColor + }; + } + }; + + TooltipView.prototype._updatePosition = function (tooltipModel, positionExpr, x, // Mouse x + y, // Mouse y + content, params, el) { + var viewWidth = this._api.getWidth(); + + var viewHeight = this._api.getHeight(); + + positionExpr = positionExpr || tooltipModel.get('position'); + var contentSize = content.getSize(); + var align = tooltipModel.get('align'); + var vAlign = tooltipModel.get('verticalAlign'); + var rect = el && el.getBoundingRect().clone(); + el && rect.applyTransform(el.transform); + + if (isFunction(positionExpr)) { + // Callback of position can be an array or a string specify the position + positionExpr = positionExpr([x, y], params, content.el, rect, { + viewSize: [viewWidth, viewHeight], + contentSize: contentSize.slice() + }); + } + + if (isArray(positionExpr)) { + x = parsePercent$1(positionExpr[0], viewWidth); + y = parsePercent$1(positionExpr[1], viewHeight); + } else if (isObject(positionExpr)) { + var boxLayoutPosition = positionExpr; + boxLayoutPosition.width = contentSize[0]; + boxLayoutPosition.height = contentSize[1]; + var layoutRect = getLayoutRect(boxLayoutPosition, { + width: viewWidth, + height: viewHeight + }); + x = layoutRect.x; + y = layoutRect.y; + align = null; // When positionExpr is left/top/right/bottom, + // align and verticalAlign will not work. + + vAlign = null; + } // Specify tooltip position by string 'top' 'bottom' 'left' 'right' around graphic element + else if (isString(positionExpr) && el) { + var pos = calcTooltipPosition(positionExpr, rect, contentSize, tooltipModel.get('borderWidth')); + x = pos[0]; + y = pos[1]; + } else { + var pos = refixTooltipPosition(x, y, content, viewWidth, viewHeight, align ? null : 20, vAlign ? null : 20); + x = pos[0]; + y = pos[1]; + } + + align && (x -= isCenterAlign(align) ? contentSize[0] / 2 : align === 'right' ? contentSize[0] : 0); + vAlign && (y -= isCenterAlign(vAlign) ? contentSize[1] / 2 : vAlign === 'bottom' ? contentSize[1] : 0); + + if (shouldTooltipConfine(tooltipModel)) { + var pos = confineTooltipPosition(x, y, content, viewWidth, viewHeight); + x = pos[0]; + y = pos[1]; + } + + content.moveTo(x, y); + }; // FIXME + // Should we remove this but leave this to user? + + + TooltipView.prototype._updateContentNotChangedOnAxis = function (dataByCoordSys, cbParamsList) { + var lastCoordSys = this._lastDataByCoordSys; + var lastCbParamsList = this._cbParamsList; + var contentNotChanged = !!lastCoordSys && lastCoordSys.length === dataByCoordSys.length; + contentNotChanged && each(lastCoordSys, function (lastItemCoordSys, indexCoordSys) { + var lastDataByAxis = lastItemCoordSys.dataByAxis || []; + var thisItemCoordSys = dataByCoordSys[indexCoordSys] || {}; + var thisDataByAxis = thisItemCoordSys.dataByAxis || []; + contentNotChanged = contentNotChanged && lastDataByAxis.length === thisDataByAxis.length; + contentNotChanged && each(lastDataByAxis, function (lastItem, indexAxis) { + var thisItem = thisDataByAxis[indexAxis] || {}; + var lastIndices = lastItem.seriesDataIndices || []; + var newIndices = thisItem.seriesDataIndices || []; + contentNotChanged = contentNotChanged && lastItem.value === thisItem.value && lastItem.axisType === thisItem.axisType && lastItem.axisId === thisItem.axisId && lastIndices.length === newIndices.length; + contentNotChanged && each(lastIndices, function (lastIdxItem, j) { + var newIdxItem = newIndices[j]; + contentNotChanged = contentNotChanged && lastIdxItem.seriesIndex === newIdxItem.seriesIndex && lastIdxItem.dataIndex === newIdxItem.dataIndex; + }); // check is cbParams data value changed + + lastCbParamsList && each(lastItem.seriesDataIndices, function (idxItem) { + var seriesIdx = idxItem.seriesIndex; + var cbParams = cbParamsList[seriesIdx]; + var lastCbParams = lastCbParamsList[seriesIdx]; + + if (cbParams && lastCbParams && lastCbParams.data !== cbParams.data) { + contentNotChanged = false; + } + }); + }); + }); + this._lastDataByCoordSys = dataByCoordSys; + this._cbParamsList = cbParamsList; + return !!contentNotChanged; + }; + + TooltipView.prototype._hide = function (dispatchAction) { + // Do not directly hideLater here, because this behavior may be prevented + // in dispatchAction when showTip is dispatched. + // FIXME + // duplicated hideTip if manuallyHideTip is called from dispatchAction. + this._lastDataByCoordSys = null; + dispatchAction({ + type: 'hideTip', + from: this.uid + }); + }; + + TooltipView.prototype.dispose = function (ecModel, api) { + if (env.node || !api.getDom()) { + return; + } + + clear(this, '_updatePosition'); + + this._tooltipContent.dispose(); + + unregister('itemTooltip', api); + }; + + TooltipView.type = 'tooltip'; + return TooltipView; + }(ComponentView); + /** + * From top to bottom. (the last one should be globalTooltipModel); + */ + + + function buildTooltipModel(modelCascade, globalTooltipModel, defaultTooltipOption) { + // Last is always tooltip model. + var ecModel = globalTooltipModel.ecModel; + var resultModel; + + if (defaultTooltipOption) { + resultModel = new Model(defaultTooltipOption, ecModel, ecModel); + resultModel = new Model(globalTooltipModel.option, resultModel, ecModel); + } else { + resultModel = globalTooltipModel; + } + + for (var i = modelCascade.length - 1; i >= 0; i--) { + var tooltipOpt = modelCascade[i]; + + if (tooltipOpt) { + if (tooltipOpt instanceof Model) { + tooltipOpt = tooltipOpt.get('tooltip', true); + } // In each data item tooltip can be simply write: + // { + // value: 10, + // tooltip: 'Something you need to know' + // } + + + if (isString(tooltipOpt)) { + tooltipOpt = { + formatter: tooltipOpt + }; + } + + if (tooltipOpt) { + resultModel = new Model(tooltipOpt, resultModel, ecModel); + } + } + } + + return resultModel; + } + + function makeDispatchAction$1(payload, api) { + return payload.dispatchAction || bind(api.dispatchAction, api); + } + + function refixTooltipPosition(x, y, content, viewWidth, viewHeight, gapH, gapV) { + var size = content.getSize(); + var width = size[0]; + var height = size[1]; + + if (gapH != null) { + // Add extra 2 pixels for this case: + // At present the "values" in defaut tooltip are using CSS `float: right`. + // When the right edge of the tooltip box is on the right side of the + // viewport, the `float` layout might push the "values" to the second line. + if (x + width + gapH + 2 > viewWidth) { + x -= width + gapH; + } else { + x += gapH; + } + } + + if (gapV != null) { + if (y + height + gapV > viewHeight) { + y -= height + gapV; + } else { + y += gapV; + } + } + + return [x, y]; + } + + function confineTooltipPosition(x, y, content, viewWidth, viewHeight) { + var size = content.getSize(); + var width = size[0]; + var height = size[1]; + x = Math.min(x + width, viewWidth) - width; + y = Math.min(y + height, viewHeight) - height; + x = Math.max(x, 0); + y = Math.max(y, 0); + return [x, y]; + } + + function calcTooltipPosition(position, rect, contentSize, borderWidth) { + var domWidth = contentSize[0]; + var domHeight = contentSize[1]; + var offset = Math.ceil(Math.SQRT2 * borderWidth) + 8; + var x = 0; + var y = 0; + var rectWidth = rect.width; + var rectHeight = rect.height; + + switch (position) { + case 'inside': + x = rect.x + rectWidth / 2 - domWidth / 2; + y = rect.y + rectHeight / 2 - domHeight / 2; + break; + + case 'top': + x = rect.x + rectWidth / 2 - domWidth / 2; + y = rect.y - domHeight - offset; + break; + + case 'bottom': + x = rect.x + rectWidth / 2 - domWidth / 2; + y = rect.y + rectHeight + offset; + break; + + case 'left': + x = rect.x - domWidth - offset; + y = rect.y + rectHeight / 2 - domHeight / 2; + break; + + case 'right': + x = rect.x + rectWidth + offset; + y = rect.y + rectHeight / 2 - domHeight / 2; + } + + return [x, y]; + } + + function isCenterAlign(align) { + return align === 'center' || align === 'middle'; + } + /** + * Find target component by payload like: + * ```js + * { legendId: 'some_id', name: 'xxx' } + * { toolboxIndex: 1, name: 'xxx' } + * { geoName: 'some_name', name: 'xxx' } + * ``` + * PENDING: at present only + * + * If not found, return null/undefined. + */ + + + function findComponentReference(payload, ecModel, api) { + var queryOptionMap = preParseFinder(payload).queryOptionMap; + var componentMainType = queryOptionMap.keys()[0]; + + if (!componentMainType || componentMainType === 'series') { + return; + } + + var queryResult = queryReferringComponents(ecModel, componentMainType, queryOptionMap.get(componentMainType), { + useDefault: false, + enableAll: false, + enableNone: false + }); + var model = queryResult.models[0]; + + if (!model) { + return; + } + + var view = api.getViewOfComponentModel(model); + var el; + view.group.traverse(function (subEl) { + var tooltipConfig = getECData(subEl).tooltipConfig; + + if (tooltipConfig && tooltipConfig.name === payload.name) { + el = subEl; + return true; // stop + } + }); + + if (el) { + return { + componentMainType: componentMainType, + componentIndex: model.componentIndex, + el: el + }; + } + } + + function install$A(registers) { + use(install$s); + registers.registerComponentModel(TooltipModel); + registers.registerComponentView(TooltipView); + /** + * @action + * @property {string} type + * @property {number} seriesIndex + * @property {number} dataIndex + * @property {number} [x] + * @property {number} [y] + */ + + registers.registerAction({ + type: 'showTip', + event: 'showTip', + update: 'tooltip:manuallyShowTip' + }, noop); + registers.registerAction({ + type: 'hideTip', + event: 'hideTip', + update: 'tooltip:manuallyHideTip' + }, noop); + } + + var DEFAULT_TOOLBOX_BTNS = ['rect', 'polygon', 'keep', 'clear']; + function brushPreprocessor(option, isNew) { + var brushComponents = normalizeToArray(option ? option.brush : []); + + if (!brushComponents.length) { + return; + } + + var brushComponentSpecifiedBtns = []; + each(brushComponents, function (brushOpt) { + var tbs = brushOpt.hasOwnProperty('toolbox') ? brushOpt.toolbox : []; + + if (tbs instanceof Array) { + brushComponentSpecifiedBtns = brushComponentSpecifiedBtns.concat(tbs); + } + }); + var toolbox = option && option.toolbox; + + if (isArray(toolbox)) { + toolbox = toolbox[0]; + } + + if (!toolbox) { + toolbox = { + feature: {} + }; + option.toolbox = [toolbox]; + } + + var toolboxFeature = toolbox.feature || (toolbox.feature = {}); + var toolboxBrush = toolboxFeature.brush || (toolboxFeature.brush = {}); + var brushTypes = toolboxBrush.type || (toolboxBrush.type = []); + brushTypes.push.apply(brushTypes, brushComponentSpecifiedBtns); + removeDuplicate(brushTypes); + + if (isNew && !brushTypes.length) { + brushTypes.push.apply(brushTypes, DEFAULT_TOOLBOX_BTNS); + } + } + + function removeDuplicate(arr) { + var map = {}; + each(arr, function (val) { + map[val] = 1; + }); + arr.length = 0; + each(map, function (flag, val) { + arr.push(val); + }); + } + + var each$b = each; + + function hasKeys(obj) { + if (obj) { + for (var name_1 in obj) { + if (obj.hasOwnProperty(name_1)) { + return true; + } + } + } + } + + function createVisualMappings(option, stateList, supplementVisualOption) { + var visualMappings = {}; + each$b(stateList, function (state) { + var mappings = visualMappings[state] = createMappings(); + each$b(option[state], function (visualData, visualType) { + if (!VisualMapping.isValidType(visualType)) { + return; + } + + var mappingOption = { + type: visualType, + visual: visualData + }; + supplementVisualOption && supplementVisualOption(mappingOption, state); + mappings[visualType] = new VisualMapping(mappingOption); // Prepare a alpha for opacity, for some case that opacity + // is not supported, such as rendering using gradient color. + + if (visualType === 'opacity') { + mappingOption = clone(mappingOption); + mappingOption.type = 'colorAlpha'; + mappings.__hidden.__alphaForOpacity = new VisualMapping(mappingOption); + } + }); + }); + return visualMappings; + + function createMappings() { + var Creater = function () {}; // Make sure hidden fields will not be visited by + // object iteration (with hasOwnProperty checking). + + + Creater.prototype.__hidden = Creater.prototype; + var obj = new Creater(); + return obj; + } + } + function replaceVisualOption(thisOption, newOption, keys) { + // Visual attributes merge is not supported, otherwise it + // brings overcomplicated merge logic. See #2853. So if + // newOption has anyone of these keys, all of these keys + // will be reset. Otherwise, all keys remain. + var has; + each(keys, function (key) { + if (newOption.hasOwnProperty(key) && hasKeys(newOption[key])) { + has = true; + } + }); + has && each(keys, function (key) { + if (newOption.hasOwnProperty(key) && hasKeys(newOption[key])) { + thisOption[key] = clone(newOption[key]); + } else { + delete thisOption[key]; + } + }); + } + /** + * @param stateList + * @param visualMappings + * @param list + * @param getValueState param: valueOrIndex, return: state. + * @param scope Scope for getValueState + * @param dimension Concrete dimension, if used. + */ + // ???! handle brush? + + function applyVisual(stateList, visualMappings, data, getValueState, scope, dimension) { + var visualTypesMap = {}; + each(stateList, function (state) { + var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]); + visualTypesMap[state] = visualTypes; + }); + var dataIndex; + + function getVisual(key) { + return getItemVisualFromData(data, dataIndex, key); + } + + function setVisual(key, value) { + setItemVisualFromData(data, dataIndex, key, value); + } + + if (dimension == null) { + data.each(eachItem); + } else { + data.each([dimension], eachItem); + } + + function eachItem(valueOrIndex, index) { + dataIndex = dimension == null ? valueOrIndex // First argument is index + : index; + var rawDataItem = data.getRawDataItem(dataIndex); // Consider performance + // @ts-ignore + + if (rawDataItem && rawDataItem.visualMap === false) { + return; + } + + var valueState = getValueState.call(scope, valueOrIndex); + var mappings = visualMappings[valueState]; + var visualTypes = visualTypesMap[valueState]; + + for (var i = 0, len = visualTypes.length; i < len; i++) { + var type = visualTypes[i]; + mappings[type] && mappings[type].applyVisual(valueOrIndex, getVisual, setVisual); + } + } + } + /** + * @param data + * @param stateList + * @param visualMappings > + * @param getValueState param: valueOrIndex, return: state. + * @param dim dimension or dimension index. + */ + + function incrementalApplyVisual(stateList, visualMappings, getValueState, dim) { + var visualTypesMap = {}; + each(stateList, function (state) { + var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]); + visualTypesMap[state] = visualTypes; + }); + return { + progress: function progress(params, data) { + var dimIndex; + + if (dim != null) { + dimIndex = data.getDimensionIndex(dim); + } + + function getVisual(key) { + return getItemVisualFromData(data, dataIndex, key); + } + + function setVisual(key, value) { + setItemVisualFromData(data, dataIndex, key, value); + } + + var dataIndex; + var store = data.getStore(); + + while ((dataIndex = params.next()) != null) { + var rawDataItem = data.getRawDataItem(dataIndex); // Consider performance + // @ts-ignore + + if (rawDataItem && rawDataItem.visualMap === false) { + continue; + } + + var value = dim != null ? store.get(dimIndex, dataIndex) : dataIndex; + var valueState = getValueState(value); + var mappings = visualMappings[valueState]; + var visualTypes = visualTypesMap[valueState]; + + for (var i = 0, len = visualTypes.length; i < len; i++) { + var type = visualTypes[i]; + mappings[type] && mappings[type].applyVisual(value, getVisual, setVisual); + } + } + } + }; + } + + function makeBrushCommonSelectorForSeries(area) { + var brushType = area.brushType; // Do not use function binding or curry for performance. + + var selectors = { + point: function (itemLayout) { + return selector[brushType].point(itemLayout, selectors, area); + }, + rect: function (itemLayout) { + return selector[brushType].rect(itemLayout, selectors, area); + } + }; + return selectors; + } + var selector = { + lineX: getLineSelectors(0), + lineY: getLineSelectors(1), + rect: { + point: function (itemLayout, selectors, area) { + return itemLayout && area.boundingRect.contain(itemLayout[0], itemLayout[1]); + }, + rect: function (itemLayout, selectors, area) { + return itemLayout && area.boundingRect.intersect(itemLayout); + } + }, + polygon: { + point: function (itemLayout, selectors, area) { + return itemLayout && area.boundingRect.contain(itemLayout[0], itemLayout[1]) && contain$2(area.range, itemLayout[0], itemLayout[1]); + }, + rect: function (itemLayout, selectors, area) { + var points = area.range; + + if (!itemLayout || points.length <= 1) { + return false; + } + + var x = itemLayout.x; + var y = itemLayout.y; + var width = itemLayout.width; + var height = itemLayout.height; + var p = points[0]; + + if (contain$2(points, x, y) || contain$2(points, x + width, y) || contain$2(points, x, y + height) || contain$2(points, x + width, y + height) || BoundingRect.create(itemLayout).contain(p[0], p[1]) || linePolygonIntersect(x, y, x + width, y, points) || linePolygonIntersect(x, y, x, y + height, points) || linePolygonIntersect(x + width, y, x + width, y + height, points) || linePolygonIntersect(x, y + height, x + width, y + height, points)) { + return true; + } + } + } + }; + + function getLineSelectors(xyIndex) { + var xy = ['x', 'y']; + var wh = ['width', 'height']; + return { + point: function (itemLayout, selectors, area) { + if (itemLayout) { + var range = area.range; + var p = itemLayout[xyIndex]; + return inLineRange(p, range); + } + }, + rect: function (itemLayout, selectors, area) { + if (itemLayout) { + var range = area.range; + var layoutRange = [itemLayout[xy[xyIndex]], itemLayout[xy[xyIndex]] + itemLayout[wh[xyIndex]]]; + layoutRange[1] < layoutRange[0] && layoutRange.reverse(); + return inLineRange(layoutRange[0], range) || inLineRange(layoutRange[1], range) || inLineRange(range[0], layoutRange) || inLineRange(range[1], layoutRange); + } + } + }; + } + + function inLineRange(p, range) { + return range[0] <= p && p <= range[1]; + } + + var STATE_LIST = ['inBrush', 'outOfBrush']; + var DISPATCH_METHOD = '__ecBrushSelect'; + var DISPATCH_FLAG = '__ecInBrushSelectEvent'; + function layoutCovers(ecModel) { + ecModel.eachComponent({ + mainType: 'brush' + }, function (brushModel) { + var brushTargetManager = brushModel.brushTargetManager = new BrushTargetManager(brushModel.option, ecModel); + brushTargetManager.setInputRanges(brushModel.areas, ecModel); + }); + } + /** + * Register the visual encoding if this modules required. + */ + + function brushVisual(ecModel, api, payload) { + var brushSelected = []; + var throttleType; + var throttleDelay; + ecModel.eachComponent({ + mainType: 'brush' + }, function (brushModel) { + payload && payload.type === 'takeGlobalCursor' && brushModel.setBrushOption(payload.key === 'brush' ? payload.brushOption : { + brushType: false + }); + }); + layoutCovers(ecModel); + ecModel.eachComponent({ + mainType: 'brush' + }, function (brushModel, brushIndex) { + var thisBrushSelected = { + brushId: brushModel.id, + brushIndex: brushIndex, + brushName: brushModel.name, + areas: clone(brushModel.areas), + selected: [] + }; // Every brush component exists in event params, convenient + // for user to find by index. + + brushSelected.push(thisBrushSelected); + var brushOption = brushModel.option; + var brushLink = brushOption.brushLink; + var linkedSeriesMap = []; + var selectedDataIndexForLink = []; + var rangeInfoBySeries = []; + var hasBrushExists = false; + + if (!brushIndex) { + // Only the first throttle setting works. + throttleType = brushOption.throttleType; + throttleDelay = brushOption.throttleDelay; + } // Add boundingRect and selectors to range. + + + var areas = map(brushModel.areas, function (area) { + var builder = boundingRectBuilders[area.brushType]; + var selectableArea = defaults({ + boundingRect: builder ? builder(area) : void 0 + }, area); + selectableArea.selectors = makeBrushCommonSelectorForSeries(selectableArea); + return selectableArea; + }); + var visualMappings = createVisualMappings(brushModel.option, STATE_LIST, function (mappingOption) { + mappingOption.mappingMethod = 'fixed'; + }); + isArray(brushLink) && each(brushLink, function (seriesIndex) { + linkedSeriesMap[seriesIndex] = 1; + }); + + function linkOthers(seriesIndex) { + return brushLink === 'all' || !!linkedSeriesMap[seriesIndex]; + } // If no supported brush or no brush on the series, + // all visuals should be in original state. + + + function brushed(rangeInfoList) { + return !!rangeInfoList.length; + } + /** + * Logic for each series: (If the logic has to be modified one day, do it carefully!) + * + * ( brushed ┬ && ┬hasBrushExist ┬ && linkOthers ) => StepA: ┬record, ┬ StepB: ┬visualByRecord. + * !brushed┘ ├hasBrushExist ┤ └nothing,┘ ├visualByRecord. + * └!hasBrushExist┘ └nothing. + * ( !brushed && ┬hasBrushExist ┬ && linkOthers ) => StepA: nothing, StepB: ┬visualByRecord. + * └!hasBrushExist┘ └nothing. + * ( brushed ┬ && !linkOthers ) => StepA: nothing, StepB: ┬visualByCheck. + * !brushed┘ └nothing. + * ( !brushed && !linkOthers ) => StepA: nothing, StepB: nothing. + */ + // Step A + + + ecModel.eachSeries(function (seriesModel, seriesIndex) { + var rangeInfoList = rangeInfoBySeries[seriesIndex] = []; + seriesModel.subType === 'parallel' ? stepAParallel(seriesModel, seriesIndex) : stepAOthers(seriesModel, seriesIndex, rangeInfoList); + }); + + function stepAParallel(seriesModel, seriesIndex) { + var coordSys = seriesModel.coordinateSystem; + hasBrushExists = hasBrushExists || coordSys.hasAxisBrushed(); + linkOthers(seriesIndex) && coordSys.eachActiveState(seriesModel.getData(), function (activeState, dataIndex) { + activeState === 'active' && (selectedDataIndexForLink[dataIndex] = 1); + }); + } + + function stepAOthers(seriesModel, seriesIndex, rangeInfoList) { + if (!seriesModel.brushSelector || brushModelNotControll(brushModel, seriesIndex)) { + return; + } + + each(areas, function (area) { + if (brushModel.brushTargetManager.controlSeries(area, seriesModel, ecModel)) { + rangeInfoList.push(area); + } + + hasBrushExists = hasBrushExists || brushed(rangeInfoList); + }); + + if (linkOthers(seriesIndex) && brushed(rangeInfoList)) { + var data_1 = seriesModel.getData(); + data_1.each(function (dataIndex) { + if (checkInRange(seriesModel, rangeInfoList, data_1, dataIndex)) { + selectedDataIndexForLink[dataIndex] = 1; + } + }); + } + } // Step B + + + ecModel.eachSeries(function (seriesModel, seriesIndex) { + var seriesBrushSelected = { + seriesId: seriesModel.id, + seriesIndex: seriesIndex, + seriesName: seriesModel.name, + dataIndex: [] + }; // Every series exists in event params, convenient + // for user to find series by seriesIndex. + + thisBrushSelected.selected.push(seriesBrushSelected); + var rangeInfoList = rangeInfoBySeries[seriesIndex]; + var data = seriesModel.getData(); + var getValueState = linkOthers(seriesIndex) ? function (dataIndex) { + return selectedDataIndexForLink[dataIndex] ? (seriesBrushSelected.dataIndex.push(data.getRawIndex(dataIndex)), 'inBrush') : 'outOfBrush'; + } : function (dataIndex) { + return checkInRange(seriesModel, rangeInfoList, data, dataIndex) ? (seriesBrushSelected.dataIndex.push(data.getRawIndex(dataIndex)), 'inBrush') : 'outOfBrush'; + }; // If no supported brush or no brush, all visuals are in original state. + + (linkOthers(seriesIndex) ? hasBrushExists : brushed(rangeInfoList)) && applyVisual(STATE_LIST, visualMappings, data, getValueState); + }); + }); + dispatchAction(api, throttleType, throttleDelay, brushSelected, payload); + } + + function dispatchAction(api, throttleType, throttleDelay, brushSelected, payload) { + // This event will not be triggered when `setOpion`, otherwise dead lock may + // triggered when do `setOption` in event listener, which we do not find + // satisfactory way to solve yet. Some considered resolutions: + // (a) Diff with prevoius selected data ant only trigger event when changed. + // But store previous data and diff precisely (i.e., not only by dataIndex, but + // also detect value changes in selected data) might bring complexity or fragility. + // (b) Use spectial param like `silent` to suppress event triggering. + // But such kind of volatile param may be weird in `setOption`. + if (!payload) { + return; + } + + var zr = api.getZr(); + + if (zr[DISPATCH_FLAG]) { + return; + } + + if (!zr[DISPATCH_METHOD]) { + zr[DISPATCH_METHOD] = doDispatch; + } + + var fn = createOrUpdate(zr, DISPATCH_METHOD, throttleDelay, throttleType); + fn(api, brushSelected); + } + + function doDispatch(api, brushSelected) { + if (!api.isDisposed()) { + var zr = api.getZr(); + zr[DISPATCH_FLAG] = true; + api.dispatchAction({ + type: 'brushSelect', + batch: brushSelected + }); + zr[DISPATCH_FLAG] = false; + } + } + + function checkInRange(seriesModel, rangeInfoList, data, dataIndex) { + for (var i = 0, len = rangeInfoList.length; i < len; i++) { + var area = rangeInfoList[i]; + + if (seriesModel.brushSelector(dataIndex, data, area.selectors, area)) { + return true; + } + } + } + + function brushModelNotControll(brushModel, seriesIndex) { + var seriesIndices = brushModel.option.seriesIndex; + return seriesIndices != null && seriesIndices !== 'all' && (isArray(seriesIndices) ? indexOf(seriesIndices, seriesIndex) < 0 : seriesIndex !== seriesIndices); + } + + var boundingRectBuilders = { + rect: function (area) { + return getBoundingRectFromMinMax(area.range); + }, + polygon: function (area) { + var minMax; + var range = area.range; + + for (var i = 0, len = range.length; i < len; i++) { + minMax = minMax || [[Infinity, -Infinity], [Infinity, -Infinity]]; + var rg = range[i]; + rg[0] < minMax[0][0] && (minMax[0][0] = rg[0]); + rg[0] > minMax[0][1] && (minMax[0][1] = rg[0]); + rg[1] < minMax[1][0] && (minMax[1][0] = rg[1]); + rg[1] > minMax[1][1] && (minMax[1][1] = rg[1]); + } + + return minMax && getBoundingRectFromMinMax(minMax); + } + }; + + function getBoundingRectFromMinMax(minMax) { + return new BoundingRect(minMax[0][0], minMax[1][0], minMax[0][1] - minMax[0][0], minMax[1][1] - minMax[1][0]); + } + + var BrushView = + /** @class */ + function (_super) { + __extends(BrushView, _super); + + function BrushView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = BrushView.type; + return _this; + } + + BrushView.prototype.init = function (ecModel, api) { + this.ecModel = ecModel; + this.api = api; + this.model; + (this._brushController = new BrushController(api.getZr())).on('brush', bind(this._onBrush, this)).mount(); + }; + + BrushView.prototype.render = function (brushModel, ecModel, api, payload) { + this.model = brushModel; + + this._updateController(brushModel, ecModel, api, payload); + }; + + BrushView.prototype.updateTransform = function (brushModel, ecModel, api, payload) { + // PENDING: `updateTransform` is a little tricky, whose layout need + // to be calculate mandatorily and other stages will not be performed. + // Take care the correctness of the logic. See #11754 . + layoutCovers(ecModel); + + this._updateController(brushModel, ecModel, api, payload); + }; + + BrushView.prototype.updateVisual = function (brushModel, ecModel, api, payload) { + this.updateTransform(brushModel, ecModel, api, payload); + }; + + BrushView.prototype.updateView = function (brushModel, ecModel, api, payload) { + this._updateController(brushModel, ecModel, api, payload); + }; + + BrushView.prototype._updateController = function (brushModel, ecModel, api, payload) { + // Do not update controller when drawing. + (!payload || payload.$from !== brushModel.id) && this._brushController.setPanels(brushModel.brushTargetManager.makePanelOpts(api)).enableBrush(brushModel.brushOption).updateCovers(brushModel.areas.slice()); + }; // updateLayout: updateController, + // updateVisual: updateController, + + + BrushView.prototype.dispose = function () { + this._brushController.dispose(); + }; + + BrushView.prototype._onBrush = function (eventParam) { + var modelId = this.model.id; + var areas = this.model.brushTargetManager.setOutputRanges(eventParam.areas, this.ecModel); // Action is not dispatched on drag end, because the drag end + // emits the same params with the last drag move event, and + // may have some delay when using touch pad, which makes + // animation not smooth (when using debounce). + + (!eventParam.isEnd || eventParam.removeOnClick) && this.api.dispatchAction({ + type: 'brush', + brushId: modelId, + areas: clone(areas), + $from: modelId + }); + eventParam.isEnd && this.api.dispatchAction({ + type: 'brushEnd', + brushId: modelId, + areas: clone(areas), + $from: modelId + }); + }; + + BrushView.type = 'brush'; + return BrushView; + }(ComponentView); + + var DEFAULT_OUT_OF_BRUSH_COLOR = '#ddd'; + + var BrushModel = + /** @class */ + function (_super) { + __extends(BrushModel, _super); + + function BrushModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = BrushModel.type; + /** + * @readOnly + */ + + _this.areas = []; + /** + * Current brush painting area settings. + * @readOnly + */ + + _this.brushOption = {}; + return _this; + } + + BrushModel.prototype.optionUpdated = function (newOption, isInit) { + var thisOption = this.option; + !isInit && replaceVisualOption(thisOption, newOption, ['inBrush', 'outOfBrush']); + var inBrush = thisOption.inBrush = thisOption.inBrush || {}; // Always give default visual, consider setOption at the second time. + + thisOption.outOfBrush = thisOption.outOfBrush || { + color: DEFAULT_OUT_OF_BRUSH_COLOR + }; + + if (!inBrush.hasOwnProperty('liftZ')) { + // Bigger than the highlight z lift, otherwise it will + // be effected by the highlight z when brush. + inBrush.liftZ = 5; + } + }; + /** + * If `areas` is null/undefined, range state remain. + */ + + + BrushModel.prototype.setAreas = function (areas) { + if ("development" !== 'production') { + assert(isArray(areas)); + each(areas, function (area) { + assert(area.brushType, 'Illegal areas'); + }); + } // If areas is null/undefined, range state remain. + // This helps user to dispatchAction({type: 'brush'}) with no areas + // set but just want to get the current brush select info from a `brush` event. + + + if (!areas) { + return; + } + + this.areas = map(areas, function (area) { + return generateBrushOption(this.option, area); + }, this); + }; + /** + * Set the current painting brush option. + */ + + + BrushModel.prototype.setBrushOption = function (brushOption) { + this.brushOption = generateBrushOption(this.option, brushOption); + this.brushType = this.brushOption.brushType; + }; + + BrushModel.type = 'brush'; + BrushModel.dependencies = ['geo', 'grid', 'xAxis', 'yAxis', 'parallel', 'series']; + BrushModel.defaultOption = { + seriesIndex: 'all', + brushType: 'rect', + brushMode: 'single', + transformable: true, + brushStyle: { + borderWidth: 1, + color: 'rgba(210,219,238,0.3)', + borderColor: '#D2DBEE' + }, + throttleType: 'fixRate', + throttleDelay: 0, + removeOnClick: true, + z: 10000 + }; + return BrushModel; + }(ComponentModel); + + function generateBrushOption(option, brushOption) { + return merge({ + brushType: option.brushType, + brushMode: option.brushMode, + transformable: option.transformable, + brushStyle: new Model(option.brushStyle).getItemStyle(), + removeOnClick: option.removeOnClick, + z: option.z + }, brushOption, true); + } + + var ICON_TYPES = ['rect', 'polygon', 'lineX', 'lineY', 'keep', 'clear']; + + var BrushFeature = + /** @class */ + function (_super) { + __extends(BrushFeature, _super); + + function BrushFeature() { + return _super !== null && _super.apply(this, arguments) || this; + } + + BrushFeature.prototype.render = function (featureModel, ecModel, api) { + var brushType; + var brushMode; + var isBrushed; + ecModel.eachComponent({ + mainType: 'brush' + }, function (brushModel) { + brushType = brushModel.brushType; + brushMode = brushModel.brushOption.brushMode || 'single'; + isBrushed = isBrushed || !!brushModel.areas.length; + }); + this._brushType = brushType; + this._brushMode = brushMode; + each(featureModel.get('type', true), function (type) { + featureModel.setIconStatus(type, (type === 'keep' ? brushMode === 'multiple' : type === 'clear' ? isBrushed : type === brushType) ? 'emphasis' : 'normal'); + }); + }; + + BrushFeature.prototype.updateView = function (featureModel, ecModel, api) { + this.render(featureModel, ecModel, api); + }; + + BrushFeature.prototype.getIcons = function () { + var model = this.model; + var availableIcons = model.get('icon', true); + var icons = {}; + each(model.get('type', true), function (type) { + if (availableIcons[type]) { + icons[type] = availableIcons[type]; + } + }); + return icons; + }; + + BrushFeature.prototype.onclick = function (ecModel, api, type) { + var brushType = this._brushType; + var brushMode = this._brushMode; + + if (type === 'clear') { + // Trigger parallel action firstly + api.dispatchAction({ + type: 'axisAreaSelect', + intervals: [] + }); + api.dispatchAction({ + type: 'brush', + command: 'clear', + // Clear all areas of all brush components. + areas: [] + }); + } else { + api.dispatchAction({ + type: 'takeGlobalCursor', + key: 'brush', + brushOption: { + brushType: type === 'keep' ? brushType : brushType === type ? false : type, + brushMode: type === 'keep' ? brushMode === 'multiple' ? 'single' : 'multiple' : brushMode + } + }); + } + }; + + BrushFeature.getDefaultOption = function (ecModel) { + var defaultOption = { + show: true, + type: ICON_TYPES.slice(), + icon: { + /* eslint-disable */ + rect: 'M7.3,34.7 M0.4,10V-0.2h9.8 M89.6,10V-0.2h-9.8 M0.4,60v10.2h9.8 M89.6,60v10.2h-9.8 M12.3,22.4V10.5h13.1 M33.6,10.5h7.8 M49.1,10.5h7.8 M77.5,22.4V10.5h-13 M12.3,31.1v8.2 M77.7,31.1v8.2 M12.3,47.6v11.9h13.1 M33.6,59.5h7.6 M49.1,59.5 h7.7 M77.5,47.6v11.9h-13', + polygon: 'M55.2,34.9c1.7,0,3.1,1.4,3.1,3.1s-1.4,3.1-3.1,3.1 s-3.1-1.4-3.1-3.1S53.5,34.9,55.2,34.9z M50.4,51c1.7,0,3.1,1.4,3.1,3.1c0,1.7-1.4,3.1-3.1,3.1c-1.7,0-3.1-1.4-3.1-3.1 C47.3,52.4,48.7,51,50.4,51z M55.6,37.1l1.5-7.8 M60.1,13.5l1.6-8.7l-7.8,4 M59,19l-1,5.3 M24,16.1l6.4,4.9l6.4-3.3 M48.5,11.6 l-5.9,3.1 M19.1,12.8L9.7,5.1l1.1,7.7 M13.4,29.8l1,7.3l6.6,1.6 M11.6,18.4l1,6.1 M32.8,41.9 M26.6,40.4 M27.3,40.2l6.1,1.6 M49.9,52.1l-5.6-7.6l-4.9-1.2', + lineX: 'M15.2,30 M19.7,15.6V1.9H29 M34.8,1.9H40.4 M55.3,15.6V1.9H45.9 M19.7,44.4V58.1H29 M34.8,58.1H40.4 M55.3,44.4 V58.1H45.9 M12.5,20.3l-9.4,9.6l9.6,9.8 M3.1,29.9h16.5 M62.5,20.3l9.4,9.6L62.3,39.7 M71.9,29.9H55.4', + lineY: 'M38.8,7.7 M52.7,12h13.2v9 M65.9,26.6V32 M52.7,46.3h13.2v-9 M24.9,12H11.8v9 M11.8,26.6V32 M24.9,46.3H11.8v-9 M48.2,5.1l-9.3-9l-9.4,9.2 M38.9-3.9V12 M48.2,53.3l-9.3,9l-9.4-9.2 M38.9,62.3V46.4', + keep: 'M4,10.5V1h10.3 M20.7,1h6.1 M33,1h6.1 M55.4,10.5V1H45.2 M4,17.3v6.6 M55.6,17.3v6.6 M4,30.5V40h10.3 M20.7,40 h6.1 M33,40h6.1 M55.4,30.5V40H45.2 M21,18.9h62.9v48.6H21V18.9z', + clear: 'M22,14.7l30.9,31 M52.9,14.7L22,45.7 M4.7,16.8V4.2h13.1 M26,4.2h7.8 M41.6,4.2h7.8 M70.3,16.8V4.2H57.2 M4.7,25.9v8.6 M70.3,25.9v8.6 M4.7,43.2v12.6h13.1 M26,55.8h7.8 M41.6,55.8h7.8 M70.3,43.2v12.6H57.2' // jshint ignore:line + + /* eslint-enable */ + + }, + // `rect`, `polygon`, `lineX`, `lineY`, `keep`, `clear` + title: ecModel.getLocaleModel().get(['toolbox', 'brush', 'title']) + }; + return defaultOption; + }; + + return BrushFeature; + }(ToolboxFeature); + + function install$B(registers) { + registers.registerComponentView(BrushView); + registers.registerComponentModel(BrushModel); + registers.registerPreprocessor(brushPreprocessor); + registers.registerVisual(registers.PRIORITY.VISUAL.BRUSH, brushVisual); + registers.registerAction({ + type: 'brush', + event: 'brush', + update: 'updateVisual' + }, function (payload, ecModel) { + ecModel.eachComponent({ + mainType: 'brush', + query: payload + }, function (brushModel) { + brushModel.setAreas(payload.areas); + }); + }); + /** + * payload: { + * brushComponents: [ + * { + * brushId, + * brushIndex, + * brushName, + * series: [ + * { + * seriesId, + * seriesIndex, + * seriesName, + * rawIndices: [21, 34, ...] + * }, + * ... + * ] + * }, + * ... + * ] + * } + */ + + registers.registerAction({ + type: 'brushSelect', + event: 'brushSelected', + update: 'none' + }, noop); + registers.registerAction({ + type: 'brushEnd', + event: 'brushEnd', + update: 'none' + }, noop); + registerFeature('brush', BrushFeature); + } + + var TitleModel = + /** @class */ + function (_super) { + __extends(TitleModel, _super); + + function TitleModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = TitleModel.type; + _this.layoutMode = { + type: 'box', + ignoreSize: true + }; + return _this; + } + + TitleModel.type = 'title'; + TitleModel.defaultOption = { + // zlevel: 0, + z: 6, + show: true, + text: '', + target: 'blank', + subtext: '', + subtarget: 'blank', + left: 0, + top: 0, + backgroundColor: 'rgba(0,0,0,0)', + borderColor: '#ccc', + borderWidth: 0, + padding: 5, + itemGap: 10, + textStyle: { + fontSize: 18, + fontWeight: 'bold', + color: '#464646' + }, + subtextStyle: { + fontSize: 12, + color: '#6E7079' + } + }; + return TitleModel; + }(ComponentModel); // View + + + var TitleView = + /** @class */ + function (_super) { + __extends(TitleView, _super); + + function TitleView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = TitleView.type; + return _this; + } + + TitleView.prototype.render = function (titleModel, ecModel, api) { + this.group.removeAll(); + + if (!titleModel.get('show')) { + return; + } + + var group = this.group; + var textStyleModel = titleModel.getModel('textStyle'); + var subtextStyleModel = titleModel.getModel('subtextStyle'); + var textAlign = titleModel.get('textAlign'); + var textVerticalAlign = retrieve2(titleModel.get('textBaseline'), titleModel.get('textVerticalAlign')); + var textEl = new ZRText({ + style: createTextStyle(textStyleModel, { + text: titleModel.get('text'), + fill: textStyleModel.getTextColor() + }, { + disableBox: true + }), + z2: 10 + }); + var textRect = textEl.getBoundingRect(); + var subText = titleModel.get('subtext'); + var subTextEl = new ZRText({ + style: createTextStyle(subtextStyleModel, { + text: subText, + fill: subtextStyleModel.getTextColor(), + y: textRect.height + titleModel.get('itemGap'), + verticalAlign: 'top' + }, { + disableBox: true + }), + z2: 10 + }); + var link = titleModel.get('link'); + var sublink = titleModel.get('sublink'); + var triggerEvent = titleModel.get('triggerEvent', true); + textEl.silent = !link && !triggerEvent; + subTextEl.silent = !sublink && !triggerEvent; + + if (link) { + textEl.on('click', function () { + windowOpen(link, '_' + titleModel.get('target')); + }); + } + + if (sublink) { + subTextEl.on('click', function () { + windowOpen(sublink, '_' + titleModel.get('subtarget')); + }); + } + + getECData(textEl).eventData = getECData(subTextEl).eventData = triggerEvent ? { + componentType: 'title', + componentIndex: titleModel.componentIndex + } : null; + group.add(textEl); + subText && group.add(subTextEl); // If no subText, but add subTextEl, there will be an empty line. + + var groupRect = group.getBoundingRect(); + var layoutOption = titleModel.getBoxLayoutParams(); + layoutOption.width = groupRect.width; + layoutOption.height = groupRect.height; + var layoutRect = getLayoutRect(layoutOption, { + width: api.getWidth(), + height: api.getHeight() + }, titleModel.get('padding')); // Adjust text align based on position + + if (!textAlign) { + // Align left if title is on the left. center and right is same + textAlign = titleModel.get('left') || titleModel.get('right'); // @ts-ignore + + if (textAlign === 'middle') { + textAlign = 'center'; + } // Adjust layout by text align + + + if (textAlign === 'right') { + layoutRect.x += layoutRect.width; + } else if (textAlign === 'center') { + layoutRect.x += layoutRect.width / 2; + } + } + + if (!textVerticalAlign) { + textVerticalAlign = titleModel.get('top') || titleModel.get('bottom'); // @ts-ignore + + if (textVerticalAlign === 'center') { + textVerticalAlign = 'middle'; + } + + if (textVerticalAlign === 'bottom') { + layoutRect.y += layoutRect.height; + } else if (textVerticalAlign === 'middle') { + layoutRect.y += layoutRect.height / 2; + } + + textVerticalAlign = textVerticalAlign || 'top'; + } + + group.x = layoutRect.x; + group.y = layoutRect.y; + group.markRedraw(); + var alignStyle = { + align: textAlign, + verticalAlign: textVerticalAlign + }; + textEl.setStyle(alignStyle); + subTextEl.setStyle(alignStyle); // Render background + // Get groupRect again because textAlign has been changed + + groupRect = group.getBoundingRect(); + var padding = layoutRect.margin; + var style = titleModel.getItemStyle(['color', 'opacity']); + style.fill = titleModel.get('backgroundColor'); + var rect = new Rect({ + shape: { + x: groupRect.x - padding[3], + y: groupRect.y - padding[0], + width: groupRect.width + padding[1] + padding[3], + height: groupRect.height + padding[0] + padding[2], + r: titleModel.get('borderRadius') + }, + style: style, + subPixelOptimize: true, + silent: true + }); + group.add(rect); + }; + + TitleView.type = 'title'; + return TitleView; + }(ComponentView); + + function install$C(registers) { + registers.registerComponentModel(TitleModel); + registers.registerComponentView(TitleView); + } + + var TimelineModel = + /** @class */ + function (_super) { + __extends(TimelineModel, _super); + + function TimelineModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = TimelineModel.type; + _this.layoutMode = 'box'; + return _this; + } + /** + * @override + */ + + + TimelineModel.prototype.init = function (option, parentModel, ecModel) { + this.mergeDefaultAndTheme(option, ecModel); + + this._initData(); + }; + /** + * @override + */ + + + TimelineModel.prototype.mergeOption = function (option) { + _super.prototype.mergeOption.apply(this, arguments); + + this._initData(); + }; + + TimelineModel.prototype.setCurrentIndex = function (currentIndex) { + if (currentIndex == null) { + currentIndex = this.option.currentIndex; + } + + var count = this._data.count(); + + if (this.option.loop) { + currentIndex = (currentIndex % count + count) % count; + } else { + currentIndex >= count && (currentIndex = count - 1); + currentIndex < 0 && (currentIndex = 0); + } + + this.option.currentIndex = currentIndex; + }; + /** + * @return {number} currentIndex + */ + + + TimelineModel.prototype.getCurrentIndex = function () { + return this.option.currentIndex; + }; + /** + * @return {boolean} + */ + + + TimelineModel.prototype.isIndexMax = function () { + return this.getCurrentIndex() >= this._data.count() - 1; + }; + /** + * @param {boolean} state true: play, false: stop + */ + + + TimelineModel.prototype.setPlayState = function (state) { + this.option.autoPlay = !!state; + }; + /** + * @return {boolean} true: play, false: stop + */ + + + TimelineModel.prototype.getPlayState = function () { + return !!this.option.autoPlay; + }; + /** + * @private + */ + + + TimelineModel.prototype._initData = function () { + var thisOption = this.option; + var dataArr = thisOption.data || []; + var axisType = thisOption.axisType; + var names = this._names = []; + var processedDataArr; + + if (axisType === 'category') { + processedDataArr = []; + each(dataArr, function (item, index) { + var value = convertOptionIdName(getDataItemValue(item), ''); + var newItem; + + if (isObject(item)) { + newItem = clone(item); + newItem.value = index; + } else { + newItem = index; + } + + processedDataArr.push(newItem); + names.push(value); + }); + } else { + processedDataArr = dataArr; + } + + var dimType = { + category: 'ordinal', + time: 'time', + value: 'number' + }[axisType] || 'number'; + var data = this._data = new SeriesData([{ + name: 'value', + type: dimType + }], this); + data.initData(processedDataArr, names); + }; + + TimelineModel.prototype.getData = function () { + return this._data; + }; + /** + * @public + * @return {Array.} categoreis + */ + + + TimelineModel.prototype.getCategories = function () { + if (this.get('axisType') === 'category') { + return this._names.slice(); + } + }; + + TimelineModel.type = 'timeline'; + /** + * @protected + */ + + TimelineModel.defaultOption = { + // zlevel: 0, // 一级层叠 + z: 4, + show: true, + axisType: 'time', + realtime: true, + left: '20%', + top: null, + right: '20%', + bottom: 0, + width: null, + height: 40, + padding: 5, + controlPosition: 'left', + autoPlay: false, + rewind: false, + loop: true, + playInterval: 2000, + currentIndex: 0, + itemStyle: {}, + label: { + color: '#000' + }, + data: [] + }; + return TimelineModel; + }(ComponentModel); + + var SliderTimelineModel = + /** @class */ + function (_super) { + __extends(SliderTimelineModel, _super); + + function SliderTimelineModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = SliderTimelineModel.type; + return _this; + } + + SliderTimelineModel.type = 'timeline.slider'; + /** + * @protected + */ + + SliderTimelineModel.defaultOption = inheritDefaultOption(TimelineModel.defaultOption, { + backgroundColor: 'rgba(0,0,0,0)', + borderColor: '#ccc', + borderWidth: 0, + orient: 'horizontal', + inverse: false, + tooltip: { + trigger: 'item' // data item may also have tootip attr. + + }, + symbol: 'circle', + symbolSize: 12, + lineStyle: { + show: true, + width: 2, + color: '#DAE1F5' + }, + label: { + position: 'auto', + // When using number, label position is not + // restricted by viewRect. + // positive: right/bottom, negative: left/top + show: true, + interval: 'auto', + rotate: 0, + // formatter: null, + // 其余属性默认使用全局文本样式,详见TEXTSTYLE + color: '#A4B1D7' + }, + itemStyle: { + color: '#A4B1D7', + borderWidth: 1 + }, + checkpointStyle: { + symbol: 'circle', + symbolSize: 15, + color: '#316bf3', + borderColor: '#fff', + borderWidth: 2, + shadowBlur: 2, + shadowOffsetX: 1, + shadowOffsetY: 1, + shadowColor: 'rgba(0, 0, 0, 0.3)', + // borderColor: 'rgba(194,53,49, 0.5)', + animation: true, + animationDuration: 300, + animationEasing: 'quinticInOut' + }, + controlStyle: { + show: true, + showPlayBtn: true, + showPrevBtn: true, + showNextBtn: true, + itemSize: 24, + itemGap: 12, + position: 'left', + playIcon: 'path://M31.6,53C17.5,53,6,41.5,6,27.4S17.5,1.8,31.6,1.8C45.7,1.8,57.2,13.3,57.2,27.4S45.7,53,31.6,53z M31.6,3.3 C18.4,3.3,7.5,14.1,7.5,27.4c0,13.3,10.8,24.1,24.1,24.1C44.9,51.5,55.7,40.7,55.7,27.4C55.7,14.1,44.9,3.3,31.6,3.3z M24.9,21.3 c0-2.2,1.6-3.1,3.5-2l10.5,6.1c1.899,1.1,1.899,2.9,0,4l-10.5,6.1c-1.9,1.1-3.5,0.2-3.5-2V21.3z', + stopIcon: 'path://M30.9,53.2C16.8,53.2,5.3,41.7,5.3,27.6S16.8,2,30.9,2C45,2,56.4,13.5,56.4,27.6S45,53.2,30.9,53.2z M30.9,3.5C17.6,3.5,6.8,14.4,6.8,27.6c0,13.3,10.8,24.1,24.101,24.1C44.2,51.7,55,40.9,55,27.6C54.9,14.4,44.1,3.5,30.9,3.5z M36.9,35.8c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H36c0.5,0,0.9,0.4,0.9,1V35.8z M27.8,35.8 c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H27c0.5,0,0.9,0.4,0.9,1L27.8,35.8L27.8,35.8z', + // eslint-disable-next-line max-len + nextIcon: 'M2,18.5A1.52,1.52,0,0,1,.92,18a1.49,1.49,0,0,1,0-2.12L7.81,9.36,1,3.11A1.5,1.5,0,1,1,3,.89l8,7.34a1.48,1.48,0,0,1,.49,1.09,1.51,1.51,0,0,1-.46,1.1L3,18.08A1.5,1.5,0,0,1,2,18.5Z', + // eslint-disable-next-line max-len + prevIcon: 'M10,.5A1.52,1.52,0,0,1,11.08,1a1.49,1.49,0,0,1,0,2.12L4.19,9.64,11,15.89a1.5,1.5,0,1,1-2,2.22L1,10.77A1.48,1.48,0,0,1,.5,9.68,1.51,1.51,0,0,1,1,8.58L9,.92A1.5,1.5,0,0,1,10,.5Z', + prevBtnSize: 18, + nextBtnSize: 18, + color: '#A4B1D7', + borderColor: '#A4B1D7', + borderWidth: 1 + }, + emphasis: { + label: { + show: true, + // 其余属性默认使用全局文本样式,详见TEXTSTYLE + color: '#6f778d' + }, + itemStyle: { + color: '#316BF3' + }, + controlStyle: { + color: '#316BF3', + borderColor: '#316BF3', + borderWidth: 2 + } + }, + progress: { + lineStyle: { + color: '#316BF3' + }, + itemStyle: { + color: '#316BF3' + }, + label: { + color: '#6f778d' + } + }, + data: [] + }); + return SliderTimelineModel; + }(TimelineModel); + + mixin(SliderTimelineModel, DataFormatMixin.prototype); + + var TimelineView = + /** @class */ + function (_super) { + __extends(TimelineView, _super); + + function TimelineView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = TimelineView.type; + return _this; + } + + TimelineView.type = 'timeline'; + return TimelineView; + }(ComponentView); + + /** + * Extend axis 2d + */ + + var TimelineAxis = + /** @class */ + function (_super) { + __extends(TimelineAxis, _super); + + function TimelineAxis(dim, scale, coordExtent, axisType) { + var _this = _super.call(this, dim, scale, coordExtent) || this; + + _this.type = axisType || 'value'; + return _this; + } + /** + * @override + */ + + + TimelineAxis.prototype.getLabelModel = function () { + // Force override + return this.model.getModel('label'); + }; + /** + * @override + */ + + + TimelineAxis.prototype.isHorizontal = function () { + return this.model.get('orient') === 'horizontal'; + }; + + return TimelineAxis; + }(Axis); + + var PI$8 = Math.PI; + var labelDataIndexStore = makeInner(); + + var SliderTimelineView = + /** @class */ + function (_super) { + __extends(SliderTimelineView, _super); + + function SliderTimelineView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = SliderTimelineView.type; + return _this; + } + + SliderTimelineView.prototype.init = function (ecModel, api) { + this.api = api; + }; + /** + * @override + */ + + + SliderTimelineView.prototype.render = function (timelineModel, ecModel, api) { + this.model = timelineModel; + this.api = api; + this.ecModel = ecModel; + this.group.removeAll(); + + if (timelineModel.get('show', true)) { + var layoutInfo_1 = this._layout(timelineModel, api); + + var mainGroup_1 = this._createGroup('_mainGroup'); + + var labelGroup = this._createGroup('_labelGroup'); + + var axis_1 = this._axis = this._createAxis(layoutInfo_1, timelineModel); + + timelineModel.formatTooltip = function (dataIndex) { + var name = axis_1.scale.getLabel({ + value: dataIndex + }); + return createTooltipMarkup('nameValue', { + noName: true, + value: name + }); + }; + + each(['AxisLine', 'AxisTick', 'Control', 'CurrentPointer'], function (name) { + this['_render' + name](layoutInfo_1, mainGroup_1, axis_1, timelineModel); + }, this); + + this._renderAxisLabel(layoutInfo_1, labelGroup, axis_1, timelineModel); + + this._position(layoutInfo_1, timelineModel); + } + + this._doPlayStop(); + + this._updateTicksStatus(); + }; + /** + * @override + */ + + + SliderTimelineView.prototype.remove = function () { + this._clearTimer(); + + this.group.removeAll(); + }; + /** + * @override + */ + + + SliderTimelineView.prototype.dispose = function () { + this._clearTimer(); + }; + + SliderTimelineView.prototype._layout = function (timelineModel, api) { + var labelPosOpt = timelineModel.get(['label', 'position']); + var orient = timelineModel.get('orient'); + var viewRect = getViewRect$5(timelineModel, api); + var parsedLabelPos; // Auto label offset. + + if (labelPosOpt == null || labelPosOpt === 'auto') { + parsedLabelPos = orient === 'horizontal' ? viewRect.y + viewRect.height / 2 < api.getHeight() / 2 ? '-' : '+' : viewRect.x + viewRect.width / 2 < api.getWidth() / 2 ? '+' : '-'; + } else if (isString(labelPosOpt)) { + parsedLabelPos = { + horizontal: { + top: '-', + bottom: '+' + }, + vertical: { + left: '-', + right: '+' + } + }[orient][labelPosOpt]; + } else { + // is number + parsedLabelPos = labelPosOpt; + } + + var labelAlignMap = { + horizontal: 'center', + vertical: parsedLabelPos >= 0 || parsedLabelPos === '+' ? 'left' : 'right' + }; + var labelBaselineMap = { + horizontal: parsedLabelPos >= 0 || parsedLabelPos === '+' ? 'top' : 'bottom', + vertical: 'middle' + }; + var rotationMap = { + horizontal: 0, + vertical: PI$8 / 2 + }; // Position + + var mainLength = orient === 'vertical' ? viewRect.height : viewRect.width; + var controlModel = timelineModel.getModel('controlStyle'); + var showControl = controlModel.get('show', true); + var controlSize = showControl ? controlModel.get('itemSize') : 0; + var controlGap = showControl ? controlModel.get('itemGap') : 0; + var sizePlusGap = controlSize + controlGap; // Special label rotate. + + var labelRotation = timelineModel.get(['label', 'rotate']) || 0; + labelRotation = labelRotation * PI$8 / 180; // To radian. + + var playPosition; + var prevBtnPosition; + var nextBtnPosition; + var controlPosition = controlModel.get('position', true); + var showPlayBtn = showControl && controlModel.get('showPlayBtn', true); + var showPrevBtn = showControl && controlModel.get('showPrevBtn', true); + var showNextBtn = showControl && controlModel.get('showNextBtn', true); + var xLeft = 0; + var xRight = mainLength; // position[0] means left, position[1] means middle. + + if (controlPosition === 'left' || controlPosition === 'bottom') { + showPlayBtn && (playPosition = [0, 0], xLeft += sizePlusGap); + showPrevBtn && (prevBtnPosition = [xLeft, 0], xLeft += sizePlusGap); + showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap); + } else { + // 'top' 'right' + showPlayBtn && (playPosition = [xRight - controlSize, 0], xRight -= sizePlusGap); + showPrevBtn && (prevBtnPosition = [0, 0], xLeft += sizePlusGap); + showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap); + } + + var axisExtent = [xLeft, xRight]; + + if (timelineModel.get('inverse')) { + axisExtent.reverse(); + } + + return { + viewRect: viewRect, + mainLength: mainLength, + orient: orient, + rotation: rotationMap[orient], + labelRotation: labelRotation, + labelPosOpt: parsedLabelPos, + labelAlign: timelineModel.get(['label', 'align']) || labelAlignMap[orient], + labelBaseline: timelineModel.get(['label', 'verticalAlign']) || timelineModel.get(['label', 'baseline']) || labelBaselineMap[orient], + // Based on mainGroup. + playPosition: playPosition, + prevBtnPosition: prevBtnPosition, + nextBtnPosition: nextBtnPosition, + axisExtent: axisExtent, + controlSize: controlSize, + controlGap: controlGap + }; + }; + + SliderTimelineView.prototype._position = function (layoutInfo, timelineModel) { + // Position is be called finally, because bounding rect is needed for + // adapt content to fill viewRect (auto adapt offset). + // Timeline may be not all in the viewRect when 'offset' is specified + // as a number, because it is more appropriate that label aligns at + // 'offset' but not the other edge defined by viewRect. + var mainGroup = this._mainGroup; + var labelGroup = this._labelGroup; + var viewRect = layoutInfo.viewRect; + + if (layoutInfo.orient === 'vertical') { + // transform to horizontal, inverse rotate by left-top point. + var m = create$1(); + var rotateOriginX = viewRect.x; + var rotateOriginY = viewRect.y + viewRect.height; + translate(m, m, [-rotateOriginX, -rotateOriginY]); + rotate(m, m, -PI$8 / 2); + translate(m, m, [rotateOriginX, rotateOriginY]); + viewRect = viewRect.clone(); + viewRect.applyTransform(m); + } + + var viewBound = getBound(viewRect); + var mainBound = getBound(mainGroup.getBoundingRect()); + var labelBound = getBound(labelGroup.getBoundingRect()); + var mainPosition = [mainGroup.x, mainGroup.y]; + var labelsPosition = [labelGroup.x, labelGroup.y]; + labelsPosition[0] = mainPosition[0] = viewBound[0][0]; + var labelPosOpt = layoutInfo.labelPosOpt; + + if (labelPosOpt == null || isString(labelPosOpt)) { + // '+' or '-' + var mainBoundIdx = labelPosOpt === '+' ? 0 : 1; + toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx); + toBound(labelsPosition, labelBound, viewBound, 1, 1 - mainBoundIdx); + } else { + var mainBoundIdx = labelPosOpt >= 0 ? 0 : 1; + toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx); + labelsPosition[1] = mainPosition[1] + labelPosOpt; + } + + mainGroup.setPosition(mainPosition); + labelGroup.setPosition(labelsPosition); + mainGroup.rotation = labelGroup.rotation = layoutInfo.rotation; + setOrigin(mainGroup); + setOrigin(labelGroup); + + function setOrigin(targetGroup) { + targetGroup.originX = viewBound[0][0] - targetGroup.x; + targetGroup.originY = viewBound[1][0] - targetGroup.y; + } + + function getBound(rect) { + // [[xmin, xmax], [ymin, ymax]] + return [[rect.x, rect.x + rect.width], [rect.y, rect.y + rect.height]]; + } + + function toBound(fromPos, from, to, dimIdx, boundIdx) { + fromPos[dimIdx] += to[dimIdx][boundIdx] - from[dimIdx][boundIdx]; + } + }; + + SliderTimelineView.prototype._createAxis = function (layoutInfo, timelineModel) { + var data = timelineModel.getData(); + var axisType = timelineModel.get('axisType'); + var scale = createScaleByModel$1(timelineModel, axisType); // Customize scale. The `tickValue` is `dataIndex`. + + scale.getTicks = function () { + return data.mapArray(['value'], function (value) { + return { + value: value + }; + }); + }; + + var dataExtent = data.getDataExtent('value'); + scale.setExtent(dataExtent[0], dataExtent[1]); + scale.calcNiceTicks(); + var axis = new TimelineAxis('value', scale, layoutInfo.axisExtent, axisType); + axis.model = timelineModel; + return axis; + }; + + SliderTimelineView.prototype._createGroup = function (key) { + var newGroup = this[key] = new Group(); + this.group.add(newGroup); + return newGroup; + }; + + SliderTimelineView.prototype._renderAxisLine = function (layoutInfo, group, axis, timelineModel) { + var axisExtent = axis.getExtent(); + + if (!timelineModel.get(['lineStyle', 'show'])) { + return; + } + + var line = new Line({ + shape: { + x1: axisExtent[0], + y1: 0, + x2: axisExtent[1], + y2: 0 + }, + style: extend({ + lineCap: 'round' + }, timelineModel.getModel('lineStyle').getLineStyle()), + silent: true, + z2: 1 + }); + group.add(line); + var progressLine = this._progressLine = new Line({ + shape: { + x1: axisExtent[0], + x2: this._currentPointer ? this._currentPointer.x : axisExtent[0], + y1: 0, + y2: 0 + }, + style: defaults({ + lineCap: 'round', + lineWidth: line.style.lineWidth + }, timelineModel.getModel(['progress', 'lineStyle']).getLineStyle()), + silent: true, + z2: 1 + }); + group.add(progressLine); + }; + + SliderTimelineView.prototype._renderAxisTick = function (layoutInfo, group, axis, timelineModel) { + var _this = this; + + var data = timelineModel.getData(); // Show all ticks, despite ignoring strategy. + + var ticks = axis.scale.getTicks(); + this._tickSymbols = []; // The value is dataIndex, see the costomized scale. + + each(ticks, function (tick) { + var tickCoord = axis.dataToCoord(tick.value); + var itemModel = data.getItemModel(tick.value); + var itemStyleModel = itemModel.getModel('itemStyle'); + var hoverStyleModel = itemModel.getModel(['emphasis', 'itemStyle']); + var progressStyleModel = itemModel.getModel(['progress', 'itemStyle']); + var symbolOpt = { + x: tickCoord, + y: 0, + onclick: bind(_this._changeTimeline, _this, tick.value) + }; + var el = giveSymbol(itemModel, itemStyleModel, group, symbolOpt); + el.ensureState('emphasis').style = hoverStyleModel.getItemStyle(); + el.ensureState('progress').style = progressStyleModel.getItemStyle(); + enableHoverEmphasis(el); + var ecData = getECData(el); + + if (itemModel.get('tooltip')) { + ecData.dataIndex = tick.value; + ecData.dataModel = timelineModel; + } else { + ecData.dataIndex = ecData.dataModel = null; + } + + _this._tickSymbols.push(el); + }); + }; + + SliderTimelineView.prototype._renderAxisLabel = function (layoutInfo, group, axis, timelineModel) { + var _this = this; + + var labelModel = axis.getLabelModel(); + + if (!labelModel.get('show')) { + return; + } + + var data = timelineModel.getData(); + var labels = axis.getViewLabels(); + this._tickLabels = []; + each(labels, function (labelItem) { + // The tickValue is dataIndex, see the costomized scale. + var dataIndex = labelItem.tickValue; + var itemModel = data.getItemModel(dataIndex); + var normalLabelModel = itemModel.getModel('label'); + var hoverLabelModel = itemModel.getModel(['emphasis', 'label']); + var progressLabelModel = itemModel.getModel(['progress', 'label']); + var tickCoord = axis.dataToCoord(labelItem.tickValue); + var textEl = new ZRText({ + x: tickCoord, + y: 0, + rotation: layoutInfo.labelRotation - layoutInfo.rotation, + onclick: bind(_this._changeTimeline, _this, dataIndex), + silent: false, + style: createTextStyle(normalLabelModel, { + text: labelItem.formattedLabel, + align: layoutInfo.labelAlign, + verticalAlign: layoutInfo.labelBaseline + }) + }); + textEl.ensureState('emphasis').style = createTextStyle(hoverLabelModel); + textEl.ensureState('progress').style = createTextStyle(progressLabelModel); + group.add(textEl); + enableHoverEmphasis(textEl); + labelDataIndexStore(textEl).dataIndex = dataIndex; + + _this._tickLabels.push(textEl); + }); + }; + + SliderTimelineView.prototype._renderControl = function (layoutInfo, group, axis, timelineModel) { + var controlSize = layoutInfo.controlSize; + var rotation = layoutInfo.rotation; + var itemStyle = timelineModel.getModel('controlStyle').getItemStyle(); + var hoverStyle = timelineModel.getModel(['emphasis', 'controlStyle']).getItemStyle(); + var playState = timelineModel.getPlayState(); + var inverse = timelineModel.get('inverse', true); + makeBtn(layoutInfo.nextBtnPosition, 'next', bind(this._changeTimeline, this, inverse ? '-' : '+')); + makeBtn(layoutInfo.prevBtnPosition, 'prev', bind(this._changeTimeline, this, inverse ? '+' : '-')); + makeBtn(layoutInfo.playPosition, playState ? 'stop' : 'play', bind(this._handlePlayClick, this, !playState), true); + + function makeBtn(position, iconName, onclick, willRotate) { + if (!position) { + return; + } + + var iconSize = parsePercent(retrieve2(timelineModel.get(['controlStyle', iconName + 'BtnSize']), controlSize), controlSize); + var rect = [0, -iconSize / 2, iconSize, iconSize]; + var btn = makeControlIcon(timelineModel, iconName + 'Icon', rect, { + x: position[0], + y: position[1], + originX: controlSize / 2, + originY: 0, + rotation: willRotate ? -rotation : 0, + rectHover: true, + style: itemStyle, + onclick: onclick + }); + btn.ensureState('emphasis').style = hoverStyle; + group.add(btn); + enableHoverEmphasis(btn); + } + }; + + SliderTimelineView.prototype._renderCurrentPointer = function (layoutInfo, group, axis, timelineModel) { + var data = timelineModel.getData(); + var currentIndex = timelineModel.getCurrentIndex(); + var pointerModel = data.getItemModel(currentIndex).getModel('checkpointStyle'); + var me = this; + var callback = { + onCreate: function (pointer) { + pointer.draggable = true; + pointer.drift = bind(me._handlePointerDrag, me); + pointer.ondragend = bind(me._handlePointerDragend, me); + pointerMoveTo(pointer, me._progressLine, currentIndex, axis, timelineModel, true); + }, + onUpdate: function (pointer) { + pointerMoveTo(pointer, me._progressLine, currentIndex, axis, timelineModel); + } + }; // Reuse when exists, for animation and drag. + + this._currentPointer = giveSymbol(pointerModel, pointerModel, this._mainGroup, {}, this._currentPointer, callback); + }; + + SliderTimelineView.prototype._handlePlayClick = function (nextState) { + this._clearTimer(); + + this.api.dispatchAction({ + type: 'timelinePlayChange', + playState: nextState, + from: this.uid + }); + }; + + SliderTimelineView.prototype._handlePointerDrag = function (dx, dy, e) { + this._clearTimer(); + + this._pointerChangeTimeline([e.offsetX, e.offsetY]); + }; + + SliderTimelineView.prototype._handlePointerDragend = function (e) { + this._pointerChangeTimeline([e.offsetX, e.offsetY], true); + }; + + SliderTimelineView.prototype._pointerChangeTimeline = function (mousePos, trigger) { + var toCoord = this._toAxisCoord(mousePos)[0]; + + var axis = this._axis; + var axisExtent = asc(axis.getExtent().slice()); + toCoord > axisExtent[1] && (toCoord = axisExtent[1]); + toCoord < axisExtent[0] && (toCoord = axisExtent[0]); + this._currentPointer.x = toCoord; + + this._currentPointer.markRedraw(); + + this._progressLine.shape.x2 = toCoord; + + this._progressLine.dirty(); + + var targetDataIndex = this._findNearestTick(toCoord); + + var timelineModel = this.model; + + if (trigger || targetDataIndex !== timelineModel.getCurrentIndex() && timelineModel.get('realtime')) { + this._changeTimeline(targetDataIndex); + } + }; + + SliderTimelineView.prototype._doPlayStop = function () { + var _this = this; + + this._clearTimer(); + + if (this.model.getPlayState()) { + this._timer = setTimeout(function () { + // Do not cache + var timelineModel = _this.model; + + _this._changeTimeline(timelineModel.getCurrentIndex() + (timelineModel.get('rewind', true) ? -1 : 1)); + }, this.model.get('playInterval')); + } + }; + + SliderTimelineView.prototype._toAxisCoord = function (vertex) { + var trans = this._mainGroup.getLocalTransform(); + + return applyTransform$1(vertex, trans, true); + }; + + SliderTimelineView.prototype._findNearestTick = function (axisCoord) { + var data = this.model.getData(); + var dist = Infinity; + var targetDataIndex; + var axis = this._axis; + data.each(['value'], function (value, dataIndex) { + var coord = axis.dataToCoord(value); + var d = Math.abs(coord - axisCoord); + + if (d < dist) { + dist = d; + targetDataIndex = dataIndex; + } + }); + return targetDataIndex; + }; + + SliderTimelineView.prototype._clearTimer = function () { + if (this._timer) { + clearTimeout(this._timer); + this._timer = null; + } + }; + + SliderTimelineView.prototype._changeTimeline = function (nextIndex) { + var currentIndex = this.model.getCurrentIndex(); + + if (nextIndex === '+') { + nextIndex = currentIndex + 1; + } else if (nextIndex === '-') { + nextIndex = currentIndex - 1; + } + + this.api.dispatchAction({ + type: 'timelineChange', + currentIndex: nextIndex, + from: this.uid + }); + }; + + SliderTimelineView.prototype._updateTicksStatus = function () { + var currentIndex = this.model.getCurrentIndex(); + var tickSymbols = this._tickSymbols; + var tickLabels = this._tickLabels; + + if (tickSymbols) { + for (var i = 0; i < tickSymbols.length; i++) { + tickSymbols && tickSymbols[i] && tickSymbols[i].toggleState('progress', i < currentIndex); + } + } + + if (tickLabels) { + for (var i = 0; i < tickLabels.length; i++) { + tickLabels && tickLabels[i] && tickLabels[i].toggleState('progress', labelDataIndexStore(tickLabels[i]).dataIndex <= currentIndex); + } + } + }; + + SliderTimelineView.type = 'timeline.slider'; + return SliderTimelineView; + }(TimelineView); + + function createScaleByModel$1(model, axisType) { + axisType = axisType || model.get('type'); + + if (axisType) { + switch (axisType) { + // Buildin scale + case 'category': + return new OrdinalScale({ + ordinalMeta: model.getCategories(), + extent: [Infinity, -Infinity] + }); + + case 'time': + return new TimeScale({ + locale: model.ecModel.getLocaleModel(), + useUTC: model.ecModel.get('useUTC') + }); + + default: + // default to be value + return new IntervalScale(); + } + } + } + + function getViewRect$5(model, api) { + return getLayoutRect(model.getBoxLayoutParams(), { + width: api.getWidth(), + height: api.getHeight() + }, model.get('padding')); + } + + function makeControlIcon(timelineModel, objPath, rect, opts) { + var style = opts.style; + var icon = createIcon(timelineModel.get(['controlStyle', objPath]), opts || {}, new BoundingRect(rect[0], rect[1], rect[2], rect[3])); // TODO createIcon won't use style in opt. + + if (style) { + icon.setStyle(style); + } + + return icon; + } + /** + * Create symbol or update symbol + * opt: basic position and event handlers + */ + + + function giveSymbol(hostModel, itemStyleModel, group, opt, symbol, callback) { + var color = itemStyleModel.get('color'); + + if (!symbol) { + var symbolType = hostModel.get('symbol'); + symbol = createSymbol(symbolType, -1, -1, 2, 2, color); + symbol.setStyle('strokeNoScale', true); + group.add(symbol); + callback && callback.onCreate(symbol); + } else { + symbol.setColor(color); + group.add(symbol); // Group may be new, also need to add. + + callback && callback.onUpdate(symbol); + } // Style + + + var itemStyle = itemStyleModel.getItemStyle(['color']); + symbol.setStyle(itemStyle); // Transform and events. + + opt = merge({ + rectHover: true, + z2: 100 + }, opt, true); + var symbolSize = normalizeSymbolSize(hostModel.get('symbolSize')); + opt.scaleX = symbolSize[0] / 2; + opt.scaleY = symbolSize[1] / 2; + var symbolOffset = normalizeSymbolOffset(hostModel.get('symbolOffset'), symbolSize); + + if (symbolOffset) { + opt.x = (opt.x || 0) + symbolOffset[0]; + opt.y = (opt.y || 0) + symbolOffset[1]; + } + + var symbolRotate = hostModel.get('symbolRotate'); + opt.rotation = (symbolRotate || 0) * Math.PI / 180 || 0; + symbol.attr(opt); // FIXME + // (1) When symbol.style.strokeNoScale is true and updateTransform is not performed, + // getBoundingRect will return wrong result. + // (This is supposed to be resolved in zrender, but it is a little difficult to + // leverage performance and auto updateTransform) + // (2) All of ancesters of symbol do not scale, so we can just updateTransform symbol. + + symbol.updateTransform(); + return symbol; + } + + function pointerMoveTo(pointer, progressLine, dataIndex, axis, timelineModel, noAnimation) { + if (pointer.dragging) { + return; + } + + var pointerModel = timelineModel.getModel('checkpointStyle'); + var toCoord = axis.dataToCoord(timelineModel.getData().get('value', dataIndex)); + + if (noAnimation || !pointerModel.get('animation', true)) { + pointer.attr({ + x: toCoord, + y: 0 + }); + progressLine && progressLine.attr({ + shape: { + x2: toCoord + } + }); + } else { + var animationCfg = { + duration: pointerModel.get('animationDuration', true), + easing: pointerModel.get('animationEasing', true) + }; + pointer.stopAnimation(null, true); + pointer.animateTo({ + x: toCoord, + y: 0 + }, animationCfg); + progressLine && progressLine.animateTo({ + shape: { + x2: toCoord + } + }, animationCfg); + } + } + + function installTimelineAction(registers) { + registers.registerAction({ + type: 'timelineChange', + event: 'timelineChanged', + update: 'prepareAndUpdate' + }, function (payload, ecModel, api) { + var timelineModel = ecModel.getComponent('timeline'); + + if (timelineModel && payload.currentIndex != null) { + timelineModel.setCurrentIndex(payload.currentIndex); + + if (!timelineModel.get('loop', true) && timelineModel.isIndexMax() && timelineModel.getPlayState()) { + timelineModel.setPlayState(false); // The timeline has played to the end, trigger event + + api.dispatchAction({ + type: 'timelinePlayChange', + playState: false, + from: payload.from + }); + } + } // Set normalized currentIndex to payload. + + + ecModel.resetOption('timeline', { + replaceMerge: timelineModel.get('replaceMerge', true) + }); + return defaults({ + currentIndex: timelineModel.option.currentIndex + }, payload); + }); + registers.registerAction({ + type: 'timelinePlayChange', + event: 'timelinePlayChanged', + update: 'update' + }, function (payload, ecModel) { + var timelineModel = ecModel.getComponent('timeline'); + + if (timelineModel && payload.playState != null) { + timelineModel.setPlayState(payload.playState); + } + }); + } + + function timelinePreprocessor(option) { + var timelineOpt = option && option.timeline; + + if (!isArray(timelineOpt)) { + timelineOpt = timelineOpt ? [timelineOpt] : []; + } + + each(timelineOpt, function (opt) { + if (!opt) { + return; + } + + compatibleEC2(opt); + }); + } + + function compatibleEC2(opt) { + var type = opt.type; + var ec2Types = { + 'number': 'value', + 'time': 'time' + }; // Compatible with ec2 + + if (ec2Types[type]) { + opt.axisType = ec2Types[type]; + delete opt.type; + } + + transferItem(opt); + + if (has(opt, 'controlPosition')) { + var controlStyle = opt.controlStyle || (opt.controlStyle = {}); + + if (!has(controlStyle, 'position')) { + controlStyle.position = opt.controlPosition; + } + + if (controlStyle.position === 'none' && !has(controlStyle, 'show')) { + controlStyle.show = false; + delete controlStyle.position; + } + + delete opt.controlPosition; + } + + each(opt.data || [], function (dataItem) { + if (isObject(dataItem) && !isArray(dataItem)) { + if (!has(dataItem, 'value') && has(dataItem, 'name')) { + // In ec2, using name as value. + dataItem.value = dataItem.name; + } + + transferItem(dataItem); + } + }); + } + + function transferItem(opt) { + var itemStyle = opt.itemStyle || (opt.itemStyle = {}); + var itemStyleEmphasis = itemStyle.emphasis || (itemStyle.emphasis = {}); // Transfer label out + + var label = opt.label || opt.label || {}; + var labelNormal = label.normal || (label.normal = {}); + var excludeLabelAttr = { + normal: 1, + emphasis: 1 + }; + each(label, function (value, name) { + if (!excludeLabelAttr[name] && !has(labelNormal, name)) { + labelNormal[name] = value; + } + }); + + if (itemStyleEmphasis.label && !has(label, 'emphasis')) { + label.emphasis = itemStyleEmphasis.label; + delete itemStyleEmphasis.label; + } + } + + function has(obj, attr) { + return obj.hasOwnProperty(attr); + } + + function install$D(registers) { + registers.registerComponentModel(SliderTimelineModel); + registers.registerComponentView(SliderTimelineView); + registers.registerSubTypeDefaulter('timeline', function () { + // Only slider now. + return 'slider'; + }); + installTimelineAction(registers); + registers.registerPreprocessor(timelinePreprocessor); + } + + function checkMarkerInSeries(seriesOpts, markerType) { + if (!seriesOpts) { + return false; + } + + var seriesOptArr = isArray(seriesOpts) ? seriesOpts : [seriesOpts]; + + for (var idx = 0; idx < seriesOptArr.length; idx++) { + if (seriesOptArr[idx] && seriesOptArr[idx][markerType]) { + return true; + } + } + + return false; + } + + function fillLabel(opt) { + defaultEmphasis(opt, 'label', ['show']); + } // { [componentType]: MarkerModel } + + + var inner$g = makeInner(); + + var MarkerModel = + /** @class */ + function (_super) { + __extends(MarkerModel, _super); + + function MarkerModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MarkerModel.type; + /** + * If marker model is created by self from series + */ + + _this.createdBySelf = false; + return _this; + } + /** + * @overrite + */ + + + MarkerModel.prototype.init = function (option, parentModel, ecModel) { + if ("development" !== 'production') { + if (this.type === 'marker') { + throw new Error('Marker component is abstract component. Use markLine, markPoint, markArea instead.'); + } + } + + this.mergeDefaultAndTheme(option, ecModel); + + this._mergeOption(option, ecModel, false, true); + }; + + MarkerModel.prototype.isAnimationEnabled = function () { + if (env.node) { + return false; + } + + var hostSeries = this.__hostSeries; + return this.getShallow('animation') && hostSeries && hostSeries.isAnimationEnabled(); + }; + /** + * @overrite + */ + + + MarkerModel.prototype.mergeOption = function (newOpt, ecModel) { + this._mergeOption(newOpt, ecModel, false, false); + }; + + MarkerModel.prototype._mergeOption = function (newOpt, ecModel, createdBySelf, isInit) { + var componentType = this.mainType; + + if (!createdBySelf) { + ecModel.eachSeries(function (seriesModel) { + // mainType can be markPoint, markLine, markArea + var markerOpt = seriesModel.get(this.mainType, true); + var markerModel = inner$g(seriesModel)[componentType]; + + if (!markerOpt || !markerOpt.data) { + inner$g(seriesModel)[componentType] = null; + return; + } + + if (!markerModel) { + if (isInit) { + // Default label emphasis `position` and `show` + fillLabel(markerOpt); + } + + each(markerOpt.data, function (item) { + // FIXME Overwrite fillLabel method ? + if (item instanceof Array) { + fillLabel(item[0]); + fillLabel(item[1]); + } else { + fillLabel(item); + } + }); + markerModel = this.createMarkerModelFromSeries(markerOpt, this, ecModel); // markerModel = new ImplementedMarkerModel( + // markerOpt, this, ecModel + // ); + + extend(markerModel, { + mainType: this.mainType, + // Use the same series index and name + seriesIndex: seriesModel.seriesIndex, + name: seriesModel.name, + createdBySelf: true + }); + markerModel.__hostSeries = seriesModel; + } else { + markerModel._mergeOption(markerOpt, ecModel, true); + } + + inner$g(seriesModel)[componentType] = markerModel; + }, this); + } + }; + + MarkerModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + var data = this.getData(); + var value = this.getRawValue(dataIndex); + var itemName = data.getName(dataIndex); + return createTooltipMarkup('section', { + header: this.name, + blocks: [createTooltipMarkup('nameValue', { + name: itemName, + value: value, + noName: !itemName, + noValue: value == null + })] + }); + }; + + MarkerModel.prototype.getData = function () { + return this._data; + }; + + MarkerModel.prototype.setData = function (data) { + this._data = data; + }; + + MarkerModel.getMarkerModelFromSeries = function (seriesModel, // Support three types of markers. Strict check. + componentType) { + return inner$g(seriesModel)[componentType]; + }; + + MarkerModel.type = 'marker'; + MarkerModel.dependencies = ['series', 'grid', 'polar', 'geo']; + return MarkerModel; + }(ComponentModel); + + mixin(MarkerModel, DataFormatMixin.prototype); + + var MarkPointModel = + /** @class */ + function (_super) { + __extends(MarkPointModel, _super); + + function MarkPointModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MarkPointModel.type; + return _this; + } + + MarkPointModel.prototype.createMarkerModelFromSeries = function (markerOpt, masterMarkerModel, ecModel) { + return new MarkPointModel(markerOpt, masterMarkerModel, ecModel); + }; + + MarkPointModel.type = 'markPoint'; + MarkPointModel.defaultOption = { + // zlevel: 0, + z: 5, + symbol: 'pin', + symbolSize: 50, + //symbolRotate: 0, + //symbolOffset: [0, 0] + tooltip: { + trigger: 'item' + }, + label: { + show: true, + position: 'inside' + }, + itemStyle: { + borderWidth: 2 + }, + emphasis: { + label: { + show: true + } + } + }; + return MarkPointModel; + }(MarkerModel); + + function hasXOrY(item) { + return !(isNaN(parseFloat(item.x)) && isNaN(parseFloat(item.y))); + } + + function hasXAndY(item) { + return !isNaN(parseFloat(item.x)) && !isNaN(parseFloat(item.y)); + } + + function markerTypeCalculatorWithExtent(markerType, data, otherDataDim, targetDataDim, otherCoordIndex, targetCoordIndex) { + var coordArr = []; + var stacked = isDimensionStacked(data, targetDataDim + /*, otherDataDim*/ + ); + var calcDataDim = stacked ? data.getCalculationInfo('stackResultDimension') : targetDataDim; + var value = numCalculate(data, calcDataDim, markerType); + var dataIndex = data.indicesOfNearest(calcDataDim, value)[0]; + coordArr[otherCoordIndex] = data.get(otherDataDim, dataIndex); + coordArr[targetCoordIndex] = data.get(calcDataDim, dataIndex); + var coordArrValue = data.get(targetDataDim, dataIndex); // Make it simple, do not visit all stacked value to count precision. + + var precision = getPrecision(data.get(targetDataDim, dataIndex)); + precision = Math.min(precision, 20); + + if (precision >= 0) { + coordArr[targetCoordIndex] = +coordArr[targetCoordIndex].toFixed(precision); + } + + return [coordArr, coordArrValue]; + } // TODO Specified percent + + + var markerTypeCalculator = { + min: curry(markerTypeCalculatorWithExtent, 'min'), + max: curry(markerTypeCalculatorWithExtent, 'max'), + average: curry(markerTypeCalculatorWithExtent, 'average'), + median: curry(markerTypeCalculatorWithExtent, 'median') + }; + /** + * Transform markPoint data item to format used in List by do the following + * 1. Calculate statistic like `max`, `min`, `average` + * 2. Convert `item.xAxis`, `item.yAxis` to `item.coord` array + */ + + function dataTransform(seriesModel, item) { + var data = seriesModel.getData(); + var coordSys = seriesModel.coordinateSystem; // 1. If not specify the position with pixel directly + // 2. If `coord` is not a data array. Which uses `xAxis`, + // `yAxis` to specify the coord on each dimension + // parseFloat first because item.x and item.y can be percent string like '20%' + + if (item && !hasXAndY(item) && !isArray(item.coord) && coordSys) { + var dims = coordSys.dimensions; + var axisInfo = getAxisInfo$1(item, data, coordSys, seriesModel); // Clone the option + // Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value + + item = clone(item); + + if (item.type && markerTypeCalculator[item.type] && axisInfo.baseAxis && axisInfo.valueAxis) { + var otherCoordIndex = indexOf(dims, axisInfo.baseAxis.dim); + var targetCoordIndex = indexOf(dims, axisInfo.valueAxis.dim); + var coordInfo = markerTypeCalculator[item.type](data, axisInfo.baseDataDim, axisInfo.valueDataDim, otherCoordIndex, targetCoordIndex); + item.coord = coordInfo[0]; // Force to use the value of calculated value. + // let item use the value without stack. + + item.value = coordInfo[1]; + } else { + // FIXME Only has one of xAxis and yAxis. + var coord = [item.xAxis != null ? item.xAxis : item.radiusAxis, item.yAxis != null ? item.yAxis : item.angleAxis]; // Each coord support max, min, average + + for (var i = 0; i < 2; i++) { + if (markerTypeCalculator[coord[i]]) { + coord[i] = numCalculate(data, data.mapDimension(dims[i]), coord[i]); + } + } + + item.coord = coord; + } + } + + return item; + } + function getAxisInfo$1(item, data, coordSys, seriesModel) { + var ret = {}; + + if (item.valueIndex != null || item.valueDim != null) { + ret.valueDataDim = item.valueIndex != null ? data.getDimension(item.valueIndex) : item.valueDim; + ret.valueAxis = coordSys.getAxis(dataDimToCoordDim(seriesModel, ret.valueDataDim)); + ret.baseAxis = coordSys.getOtherAxis(ret.valueAxis); + ret.baseDataDim = data.mapDimension(ret.baseAxis.dim); + } else { + ret.baseAxis = seriesModel.getBaseAxis(); + ret.valueAxis = coordSys.getOtherAxis(ret.baseAxis); + ret.baseDataDim = data.mapDimension(ret.baseAxis.dim); + ret.valueDataDim = data.mapDimension(ret.valueAxis.dim); + } + + return ret; + } + + function dataDimToCoordDim(seriesModel, dataDim) { + var dimItem = seriesModel.getData().getDimensionInfo(dataDim); + return dimItem && dimItem.coordDim; + } + /** + * Filter data which is out of coordinateSystem range + * [dataFilter description] + */ + + + function dataFilter$1( // Currently only polar and cartesian has containData. + coordSys, item) { + // Alwalys return true if there is no coordSys + return coordSys && coordSys.containData && item.coord && !hasXOrY(item) ? coordSys.containData(item.coord) : true; + } + function createMarkerDimValueGetter(inCoordSys, dims) { + return inCoordSys ? function (item, dimName, dataIndex, dimIndex) { + var rawVal = dimIndex < 2 // x, y, radius, angle + ? item.coord && item.coord[dimIndex] : item.value; + return parseDataValue(rawVal, dims[dimIndex]); + } : function (item, dimName, dataIndex, dimIndex) { + return parseDataValue(item.value, dims[dimIndex]); + }; + } + function numCalculate(data, valueDataDim, type) { + if (type === 'average') { + var sum_1 = 0; + var count_1 = 0; + data.each(valueDataDim, function (val, idx) { + if (!isNaN(val)) { + sum_1 += val; + count_1++; + } + }); + return sum_1 / count_1; + } else if (type === 'median') { + return data.getMedian(valueDataDim); + } else { + // max & min + return data.getDataExtent(valueDataDim)[type === 'max' ? 1 : 0]; + } + } + + var inner$h = makeInner(); + + var MarkerView = + /** @class */ + function (_super) { + __extends(MarkerView, _super); + + function MarkerView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MarkerView.type; + return _this; + } + + MarkerView.prototype.init = function () { + this.markerGroupMap = createHashMap(); + }; + + MarkerView.prototype.render = function (markerModel, ecModel, api) { + var _this = this; + + var markerGroupMap = this.markerGroupMap; + markerGroupMap.each(function (item) { + inner$h(item).keep = false; + }); + ecModel.eachSeries(function (seriesModel) { + var markerModel = MarkerModel.getMarkerModelFromSeries(seriesModel, _this.type); + markerModel && _this.renderSeries(seriesModel, markerModel, ecModel, api); + }); + markerGroupMap.each(function (item) { + !inner$h(item).keep && _this.group.remove(item.group); + }); + }; + + MarkerView.prototype.markKeep = function (drawGroup) { + inner$h(drawGroup).keep = true; + }; + + MarkerView.prototype.toggleBlurSeries = function (seriesModelList, isBlur) { + var _this = this; + + each(seriesModelList, function (seriesModel) { + var markerModel = MarkerModel.getMarkerModelFromSeries(seriesModel, _this.type); + + if (markerModel) { + var data = markerModel.getData(); + data.eachItemGraphicEl(function (el) { + if (el) { + isBlur ? enterBlur(el) : leaveBlur(el); + } + }); + } + }); + }; + + MarkerView.type = 'marker'; + return MarkerView; + }(ComponentView); + + function updateMarkerLayout(mpData, seriesModel, api) { + var coordSys = seriesModel.coordinateSystem; + mpData.each(function (idx) { + var itemModel = mpData.getItemModel(idx); + var point; + var xPx = parsePercent$1(itemModel.get('x'), api.getWidth()); + var yPx = parsePercent$1(itemModel.get('y'), api.getHeight()); + + if (!isNaN(xPx) && !isNaN(yPx)) { + point = [xPx, yPx]; + } // Chart like bar may have there own marker positioning logic + else if (seriesModel.getMarkerPosition) { + // Use the getMarkerPoisition + point = seriesModel.getMarkerPosition(mpData.getValues(mpData.dimensions, idx)); + } else if (coordSys) { + var x = mpData.get(coordSys.dimensions[0], idx); + var y = mpData.get(coordSys.dimensions[1], idx); + point = coordSys.dataToPoint([x, y]); + } // Use x, y if has any + + + if (!isNaN(xPx)) { + point[0] = xPx; + } + + if (!isNaN(yPx)) { + point[1] = yPx; + } + + mpData.setItemLayout(idx, point); + }); + } + + var MarkPointView = + /** @class */ + function (_super) { + __extends(MarkPointView, _super); + + function MarkPointView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MarkPointView.type; + return _this; + } + + MarkPointView.prototype.updateTransform = function (markPointModel, ecModel, api) { + ecModel.eachSeries(function (seriesModel) { + var mpModel = MarkerModel.getMarkerModelFromSeries(seriesModel, 'markPoint'); + + if (mpModel) { + updateMarkerLayout(mpModel.getData(), seriesModel, api); + this.markerGroupMap.get(seriesModel.id).updateLayout(); + } + }, this); + }; + + MarkPointView.prototype.renderSeries = function (seriesModel, mpModel, ecModel, api) { + var coordSys = seriesModel.coordinateSystem; + var seriesId = seriesModel.id; + var seriesData = seriesModel.getData(); + var symbolDrawMap = this.markerGroupMap; + var symbolDraw = symbolDrawMap.get(seriesId) || symbolDrawMap.set(seriesId, new SymbolDraw()); + var mpData = createData(coordSys, seriesModel, mpModel); // FIXME + + mpModel.setData(mpData); + updateMarkerLayout(mpModel.getData(), seriesModel, api); + mpData.each(function (idx) { + var itemModel = mpData.getItemModel(idx); + var symbol = itemModel.getShallow('symbol'); + var symbolSize = itemModel.getShallow('symbolSize'); + var symbolRotate = itemModel.getShallow('symbolRotate'); + var symbolOffset = itemModel.getShallow('symbolOffset'); + var symbolKeepAspect = itemModel.getShallow('symbolKeepAspect'); // TODO: refactor needed: single data item should not support callback function + + if (isFunction(symbol) || isFunction(symbolSize) || isFunction(symbolRotate) || isFunction(symbolOffset)) { + var rawIdx = mpModel.getRawValue(idx); + var dataParams = mpModel.getDataParams(idx); + + if (isFunction(symbol)) { + symbol = symbol(rawIdx, dataParams); + } + + if (isFunction(symbolSize)) { + // FIXME 这里不兼容 ECharts 2.x,2.x 貌似参数是整个数据? + symbolSize = symbolSize(rawIdx, dataParams); + } + + if (isFunction(symbolRotate)) { + symbolRotate = symbolRotate(rawIdx, dataParams); + } + + if (isFunction(symbolOffset)) { + symbolOffset = symbolOffset(rawIdx, dataParams); + } + } + + var style = itemModel.getModel('itemStyle').getItemStyle(); + var color = getVisualFromData(seriesData, 'color'); + + if (!style.fill) { + style.fill = color; + } + + mpData.setItemVisual(idx, { + symbol: symbol, + symbolSize: symbolSize, + symbolRotate: symbolRotate, + symbolOffset: symbolOffset, + symbolKeepAspect: symbolKeepAspect, + style: style + }); + }); // TODO Text are wrong + + symbolDraw.updateData(mpData); + this.group.add(symbolDraw.group); // Set host model for tooltip + // FIXME + + mpData.eachItemGraphicEl(function (el) { + el.traverse(function (child) { + getECData(child).dataModel = mpModel; + }); + }); + this.markKeep(symbolDraw); + symbolDraw.group.silent = mpModel.get('silent') || seriesModel.get('silent'); + }; + + MarkPointView.type = 'markPoint'; + return MarkPointView; + }(MarkerView); + + function createData(coordSys, seriesModel, mpModel) { + var coordDimsInfos; + + if (coordSys) { + coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) { + var info = seriesModel.getData().getDimensionInfo(seriesModel.getData().mapDimension(coordDim)) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys + + return extend(extend({}, info), { + name: coordDim, + // DON'T use ordinalMeta to parse and collect ordinal. + ordinalMeta: null + }); + }); + } else { + coordDimsInfos = [{ + name: 'value', + type: 'float' + }]; + } + + var mpData = new SeriesData(coordDimsInfos, mpModel); + var dataOpt = map(mpModel.get('data'), curry(dataTransform, seriesModel)); + + if (coordSys) { + dataOpt = filter(dataOpt, curry(dataFilter$1, coordSys)); + } + + var dimValueGetter = createMarkerDimValueGetter(!!coordSys, coordDimsInfos); + mpData.initData(dataOpt, null, dimValueGetter); + return mpData; + } + + function install$E(registers) { + registers.registerComponentModel(MarkPointModel); + registers.registerComponentView(MarkPointView); + registers.registerPreprocessor(function (opt) { + if (checkMarkerInSeries(opt.series, 'markPoint')) { + // Make sure markPoint component is enabled + opt.markPoint = opt.markPoint || {}; + } + }); + } + + var MarkLineModel = + /** @class */ + function (_super) { + __extends(MarkLineModel, _super); + + function MarkLineModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MarkLineModel.type; + return _this; + } + + MarkLineModel.prototype.createMarkerModelFromSeries = function (markerOpt, masterMarkerModel, ecModel) { + return new MarkLineModel(markerOpt, masterMarkerModel, ecModel); + }; + + MarkLineModel.type = 'markLine'; + MarkLineModel.defaultOption = { + // zlevel: 0, + z: 5, + symbol: ['circle', 'arrow'], + symbolSize: [8, 16], + //symbolRotate: 0, + symbolOffset: 0, + precision: 2, + tooltip: { + trigger: 'item' + }, + label: { + show: true, + position: 'end', + distance: 5 + }, + lineStyle: { + type: 'dashed' + }, + emphasis: { + label: { + show: true + }, + lineStyle: { + width: 3 + } + }, + animationEasing: 'linear' + }; + return MarkLineModel; + }(MarkerModel); + + var inner$i = makeInner(); + + var markLineTransform = function (seriesModel, coordSys, mlModel, item) { + var data = seriesModel.getData(); + var itemArray; + + if (!isArray(item)) { + // Special type markLine like 'min', 'max', 'average', 'median' + var mlType = item.type; + + if (mlType === 'min' || mlType === 'max' || mlType === 'average' || mlType === 'median' // In case + // data: [{ + // yAxis: 10 + // }] + || item.xAxis != null || item.yAxis != null) { + var valueAxis = void 0; + var value = void 0; + + if (item.yAxis != null || item.xAxis != null) { + valueAxis = coordSys.getAxis(item.yAxis != null ? 'y' : 'x'); + value = retrieve(item.yAxis, item.xAxis); + } else { + var axisInfo = getAxisInfo$1(item, data, coordSys, seriesModel); + valueAxis = axisInfo.valueAxis; + var valueDataDim = getStackedDimension(data, axisInfo.valueDataDim); + value = numCalculate(data, valueDataDim, mlType); + } + + var valueIndex = valueAxis.dim === 'x' ? 0 : 1; + var baseIndex = 1 - valueIndex; // Normized to 2d data with start and end point + + var mlFrom = clone(item); + var mlTo = { + coord: [] + }; + mlFrom.type = null; + mlFrom.coord = []; + mlFrom.coord[baseIndex] = -Infinity; + mlTo.coord[baseIndex] = Infinity; + var precision = mlModel.get('precision'); + + if (precision >= 0 && isNumber(value)) { + value = +value.toFixed(Math.min(precision, 20)); + } + + mlFrom.coord[valueIndex] = mlTo.coord[valueIndex] = value; + itemArray = [mlFrom, mlTo, { + type: mlType, + valueIndex: item.valueIndex, + // Force to use the value of calculated value. + value: value + }]; + } else { + // Invalid data + if ("development" !== 'production') { + logError('Invalid markLine data.'); + } + + itemArray = []; + } + } else { + itemArray = item; + } + + var normalizedItem = [dataTransform(seriesModel, itemArray[0]), dataTransform(seriesModel, itemArray[1]), extend({}, itemArray[2])]; // Avoid line data type is extended by from(to) data type + + normalizedItem[2].type = normalizedItem[2].type || null; // Merge from option and to option into line option + + merge(normalizedItem[2], normalizedItem[0]); + merge(normalizedItem[2], normalizedItem[1]); + return normalizedItem; + }; + + function isInifinity(val) { + return !isNaN(val) && !isFinite(val); + } // If a markLine has one dim + + + function ifMarkLineHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) { + var otherDimIndex = 1 - dimIndex; + var dimName = coordSys.dimensions[dimIndex]; + return isInifinity(fromCoord[otherDimIndex]) && isInifinity(toCoord[otherDimIndex]) && fromCoord[dimIndex] === toCoord[dimIndex] && coordSys.getAxis(dimName).containData(fromCoord[dimIndex]); + } + + function markLineFilter(coordSys, item) { + if (coordSys.type === 'cartesian2d') { + var fromCoord = item[0].coord; + var toCoord = item[1].coord; // In case + // { + // markLine: { + // data: [{ yAxis: 2 }] + // } + // } + + if (fromCoord && toCoord && (ifMarkLineHasOnlyDim(1, fromCoord, toCoord, coordSys) || ifMarkLineHasOnlyDim(0, fromCoord, toCoord, coordSys))) { + return true; + } + } + + return dataFilter$1(coordSys, item[0]) && dataFilter$1(coordSys, item[1]); + } + + function updateSingleMarkerEndLayout(data, idx, isFrom, seriesModel, api) { + var coordSys = seriesModel.coordinateSystem; + var itemModel = data.getItemModel(idx); + var point; + var xPx = parsePercent$1(itemModel.get('x'), api.getWidth()); + var yPx = parsePercent$1(itemModel.get('y'), api.getHeight()); + + if (!isNaN(xPx) && !isNaN(yPx)) { + point = [xPx, yPx]; + } else { + // Chart like bar may have there own marker positioning logic + if (seriesModel.getMarkerPosition) { + // Use the getMarkerPoisition + point = seriesModel.getMarkerPosition(data.getValues(data.dimensions, idx)); + } else { + var dims = coordSys.dimensions; + var x = data.get(dims[0], idx); + var y = data.get(dims[1], idx); + point = coordSys.dataToPoint([x, y]); + } // Expand line to the edge of grid if value on one axis is Inifnity + // In case + // markLine: { + // data: [{ + // yAxis: 2 + // // or + // type: 'average' + // }] + // } + + + if (isCoordinateSystemType(coordSys, 'cartesian2d')) { + // TODO: TYPE ts@4.1 may still infer it as Axis instead of Axis2D. Not sure if it's a bug + var xAxis = coordSys.getAxis('x'); + var yAxis = coordSys.getAxis('y'); + var dims = coordSys.dimensions; + + if (isInifinity(data.get(dims[0], idx))) { + point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[isFrom ? 0 : 1]); + } else if (isInifinity(data.get(dims[1], idx))) { + point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[isFrom ? 0 : 1]); + } + } // Use x, y if has any + + + if (!isNaN(xPx)) { + point[0] = xPx; + } + + if (!isNaN(yPx)) { + point[1] = yPx; + } + } + + data.setItemLayout(idx, point); + } + + var MarkLineView = + /** @class */ + function (_super) { + __extends(MarkLineView, _super); + + function MarkLineView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MarkLineView.type; + return _this; + } + + MarkLineView.prototype.updateTransform = function (markLineModel, ecModel, api) { + ecModel.eachSeries(function (seriesModel) { + var mlModel = MarkerModel.getMarkerModelFromSeries(seriesModel, 'markLine'); + + if (mlModel) { + var mlData_1 = mlModel.getData(); + var fromData_1 = inner$i(mlModel).from; + var toData_1 = inner$i(mlModel).to; // Update visual and layout of from symbol and to symbol + + fromData_1.each(function (idx) { + updateSingleMarkerEndLayout(fromData_1, idx, true, seriesModel, api); + updateSingleMarkerEndLayout(toData_1, idx, false, seriesModel, api); + }); // Update layout of line + + mlData_1.each(function (idx) { + mlData_1.setItemLayout(idx, [fromData_1.getItemLayout(idx), toData_1.getItemLayout(idx)]); + }); + this.markerGroupMap.get(seriesModel.id).updateLayout(); + } + }, this); + }; + + MarkLineView.prototype.renderSeries = function (seriesModel, mlModel, ecModel, api) { + var coordSys = seriesModel.coordinateSystem; + var seriesId = seriesModel.id; + var seriesData = seriesModel.getData(); + var lineDrawMap = this.markerGroupMap; + var lineDraw = lineDrawMap.get(seriesId) || lineDrawMap.set(seriesId, new LineDraw()); + this.group.add(lineDraw.group); + var mlData = createList$1(coordSys, seriesModel, mlModel); + var fromData = mlData.from; + var toData = mlData.to; + var lineData = mlData.line; + inner$i(mlModel).from = fromData; + inner$i(mlModel).to = toData; // Line data for tooltip and formatter + + mlModel.setData(lineData); // TODO + // Functionally, `symbolSize` & `symbolOffset` can also be 2D array now. + // But the related logic and type definition are not finished yet. + // Finish it if required + + var symbolType = mlModel.get('symbol'); + var symbolSize = mlModel.get('symbolSize'); + var symbolRotate = mlModel.get('symbolRotate'); + var symbolOffset = mlModel.get('symbolOffset'); // TODO: support callback function like markPoint + + if (!isArray(symbolType)) { + symbolType = [symbolType, symbolType]; + } + + if (!isArray(symbolSize)) { + symbolSize = [symbolSize, symbolSize]; + } + + if (!isArray(symbolRotate)) { + symbolRotate = [symbolRotate, symbolRotate]; + } + + if (!isArray(symbolOffset)) { + symbolOffset = [symbolOffset, symbolOffset]; + } // Update visual and layout of from symbol and to symbol + + + mlData.from.each(function (idx) { + updateDataVisualAndLayout(fromData, idx, true); + updateDataVisualAndLayout(toData, idx, false); + }); // Update visual and layout of line + + lineData.each(function (idx) { + var lineStyle = lineData.getItemModel(idx).getModel('lineStyle').getLineStyle(); // lineData.setItemVisual(idx, { + // color: lineColor || fromData.getItemVisual(idx, 'color') + // }); + + lineData.setItemLayout(idx, [fromData.getItemLayout(idx), toData.getItemLayout(idx)]); + + if (lineStyle.stroke == null) { + lineStyle.stroke = fromData.getItemVisual(idx, 'style').fill; + } + + lineData.setItemVisual(idx, { + fromSymbolKeepAspect: fromData.getItemVisual(idx, 'symbolKeepAspect'), + fromSymbolOffset: fromData.getItemVisual(idx, 'symbolOffset'), + fromSymbolRotate: fromData.getItemVisual(idx, 'symbolRotate'), + fromSymbolSize: fromData.getItemVisual(idx, 'symbolSize'), + fromSymbol: fromData.getItemVisual(idx, 'symbol'), + toSymbolKeepAspect: toData.getItemVisual(idx, 'symbolKeepAspect'), + toSymbolOffset: toData.getItemVisual(idx, 'symbolOffset'), + toSymbolRotate: toData.getItemVisual(idx, 'symbolRotate'), + toSymbolSize: toData.getItemVisual(idx, 'symbolSize'), + toSymbol: toData.getItemVisual(idx, 'symbol'), + style: lineStyle + }); + }); + lineDraw.updateData(lineData); // Set host model for tooltip + // FIXME + + mlData.line.eachItemGraphicEl(function (el, idx) { + el.traverse(function (child) { + getECData(child).dataModel = mlModel; + }); + }); + + function updateDataVisualAndLayout(data, idx, isFrom) { + var itemModel = data.getItemModel(idx); + updateSingleMarkerEndLayout(data, idx, isFrom, seriesModel, api); + var style = itemModel.getModel('itemStyle').getItemStyle(); + + if (style.fill == null) { + style.fill = getVisualFromData(seriesData, 'color'); + } + + data.setItemVisual(idx, { + symbolKeepAspect: itemModel.get('symbolKeepAspect'), + // `0` should be considered as a valid value, so use `retrieve2` instead of `||` + symbolOffset: retrieve2(itemModel.get('symbolOffset', true), symbolOffset[isFrom ? 0 : 1]), + symbolRotate: retrieve2(itemModel.get('symbolRotate', true), symbolRotate[isFrom ? 0 : 1]), + // TODO: when 2d array is supported, it should ignore parent + symbolSize: retrieve2(itemModel.get('symbolSize'), symbolSize[isFrom ? 0 : 1]), + symbol: retrieve2(itemModel.get('symbol', true), symbolType[isFrom ? 0 : 1]), + style: style + }); + } + + this.markKeep(lineDraw); + lineDraw.group.silent = mlModel.get('silent') || seriesModel.get('silent'); + }; + + MarkLineView.type = 'markLine'; + return MarkLineView; + }(MarkerView); + + function createList$1(coordSys, seriesModel, mlModel) { + var coordDimsInfos; + + if (coordSys) { + coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) { + var info = seriesModel.getData().getDimensionInfo(seriesModel.getData().mapDimension(coordDim)) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys + + return extend(extend({}, info), { + name: coordDim, + // DON'T use ordinalMeta to parse and collect ordinal. + ordinalMeta: null + }); + }); + } else { + coordDimsInfos = [{ + name: 'value', + type: 'float' + }]; + } + + var fromData = new SeriesData(coordDimsInfos, mlModel); + var toData = new SeriesData(coordDimsInfos, mlModel); // No dimensions + + var lineData = new SeriesData([], mlModel); + var optData = map(mlModel.get('data'), curry(markLineTransform, seriesModel, coordSys, mlModel)); + + if (coordSys) { + optData = filter(optData, curry(markLineFilter, coordSys)); + } + + var dimValueGetter = createMarkerDimValueGetter(!!coordSys, coordDimsInfos); + fromData.initData(map(optData, function (item) { + return item[0]; + }), null, dimValueGetter); + toData.initData(map(optData, function (item) { + return item[1]; + }), null, dimValueGetter); + lineData.initData(map(optData, function (item) { + return item[2]; + })); + lineData.hasItemOption = true; + return { + from: fromData, + to: toData, + line: lineData + }; + } + + function install$F(registers) { + registers.registerComponentModel(MarkLineModel); + registers.registerComponentView(MarkLineView); + registers.registerPreprocessor(function (opt) { + if (checkMarkerInSeries(opt.series, 'markLine')) { + // Make sure markLine component is enabled + opt.markLine = opt.markLine || {}; + } + }); + } + + var MarkAreaModel = + /** @class */ + function (_super) { + __extends(MarkAreaModel, _super); + + function MarkAreaModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MarkAreaModel.type; + return _this; + } + + MarkAreaModel.prototype.createMarkerModelFromSeries = function (markerOpt, masterMarkerModel, ecModel) { + return new MarkAreaModel(markerOpt, masterMarkerModel, ecModel); + }; + + MarkAreaModel.type = 'markArea'; + MarkAreaModel.defaultOption = { + // zlevel: 0, + // PENDING + z: 1, + tooltip: { + trigger: 'item' + }, + // markArea should fixed on the coordinate system + animation: false, + label: { + show: true, + position: 'top' + }, + itemStyle: { + // color and borderColor default to use color from series + // color: 'auto' + // borderColor: 'auto' + borderWidth: 0 + }, + emphasis: { + label: { + show: true, + position: 'top' + } + } + }; + return MarkAreaModel; + }(MarkerModel); + + var inner$j = makeInner(); + + var markAreaTransform = function (seriesModel, coordSys, maModel, item) { + var lt = dataTransform(seriesModel, item[0]); + var rb = dataTransform(seriesModel, item[1]); // FIXME make sure lt is less than rb + + var ltCoord = lt.coord; + var rbCoord = rb.coord; + ltCoord[0] = retrieve(ltCoord[0], -Infinity); + ltCoord[1] = retrieve(ltCoord[1], -Infinity); + rbCoord[0] = retrieve(rbCoord[0], Infinity); + rbCoord[1] = retrieve(rbCoord[1], Infinity); // Merge option into one + + var result = mergeAll([{}, lt, rb]); + result.coord = [lt.coord, rb.coord]; + result.x0 = lt.x; + result.y0 = lt.y; + result.x1 = rb.x; + result.y1 = rb.y; + return result; + }; + + function isInifinity$1(val) { + return !isNaN(val) && !isFinite(val); + } // If a markArea has one dim + + + function ifMarkAreaHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) { + var otherDimIndex = 1 - dimIndex; + return isInifinity$1(fromCoord[otherDimIndex]) && isInifinity$1(toCoord[otherDimIndex]); + } + + function markAreaFilter(coordSys, item) { + var fromCoord = item.coord[0]; + var toCoord = item.coord[1]; + + if (isCoordinateSystemType(coordSys, 'cartesian2d')) { + // In case + // { + // markArea: { + // data: [{ yAxis: 2 }] + // } + // } + if (fromCoord && toCoord && (ifMarkAreaHasOnlyDim(1, fromCoord, toCoord) || ifMarkAreaHasOnlyDim(0, fromCoord, toCoord))) { + return true; + } + } + + return dataFilter$1(coordSys, { + coord: fromCoord, + x: item.x0, + y: item.y0 + }) || dataFilter$1(coordSys, { + coord: toCoord, + x: item.x1, + y: item.y1 + }); + } // dims can be ['x0', 'y0'], ['x1', 'y1'], ['x0', 'y1'], ['x1', 'y0'] + + + function getSingleMarkerEndPoint(data, idx, dims, seriesModel, api) { + var coordSys = seriesModel.coordinateSystem; + var itemModel = data.getItemModel(idx); + var point; + var xPx = parsePercent$1(itemModel.get(dims[0]), api.getWidth()); + var yPx = parsePercent$1(itemModel.get(dims[1]), api.getHeight()); + + if (!isNaN(xPx) && !isNaN(yPx)) { + point = [xPx, yPx]; + } else { + // Chart like bar may have there own marker positioning logic + if (seriesModel.getMarkerPosition) { + // Use the getMarkerPoisition + point = seriesModel.getMarkerPosition(data.getValues(dims, idx)); + } else { + var x = data.get(dims[0], idx); + var y = data.get(dims[1], idx); + var pt = [x, y]; + coordSys.clampData && coordSys.clampData(pt, pt); + point = coordSys.dataToPoint(pt, true); + } + + if (isCoordinateSystemType(coordSys, 'cartesian2d')) { + // TODO: TYPE ts@4.1 may still infer it as Axis instead of Axis2D. Not sure if it's a bug + var xAxis = coordSys.getAxis('x'); + var yAxis = coordSys.getAxis('y'); + var x = data.get(dims[0], idx); + var y = data.get(dims[1], idx); + + if (isInifinity$1(x)) { + point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[dims[0] === 'x0' ? 0 : 1]); + } else if (isInifinity$1(y)) { + point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[dims[1] === 'y0' ? 0 : 1]); + } + } // Use x, y if has any + + + if (!isNaN(xPx)) { + point[0] = xPx; + } + + if (!isNaN(yPx)) { + point[1] = yPx; + } + } + + return point; + } + + var dimPermutations = [['x0', 'y0'], ['x1', 'y0'], ['x1', 'y1'], ['x0', 'y1']]; + + var MarkAreaView = + /** @class */ + function (_super) { + __extends(MarkAreaView, _super); + + function MarkAreaView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MarkAreaView.type; + return _this; + } + + MarkAreaView.prototype.updateTransform = function (markAreaModel, ecModel, api) { + ecModel.eachSeries(function (seriesModel) { + var maModel = MarkerModel.getMarkerModelFromSeries(seriesModel, 'markArea'); + + if (maModel) { + var areaData_1 = maModel.getData(); + areaData_1.each(function (idx) { + var points = map(dimPermutations, function (dim) { + return getSingleMarkerEndPoint(areaData_1, idx, dim, seriesModel, api); + }); // Layout + + areaData_1.setItemLayout(idx, points); + var el = areaData_1.getItemGraphicEl(idx); + el.setShape('points', points); + }); + } + }, this); + }; + + MarkAreaView.prototype.renderSeries = function (seriesModel, maModel, ecModel, api) { + var coordSys = seriesModel.coordinateSystem; + var seriesId = seriesModel.id; + var seriesData = seriesModel.getData(); + var areaGroupMap = this.markerGroupMap; + var polygonGroup = areaGroupMap.get(seriesId) || areaGroupMap.set(seriesId, { + group: new Group() + }); + this.group.add(polygonGroup.group); + this.markKeep(polygonGroup); + var areaData = createList$2(coordSys, seriesModel, maModel); // Line data for tooltip and formatter + + maModel.setData(areaData); // Update visual and layout of line + + areaData.each(function (idx) { + // Layout + var points = map(dimPermutations, function (dim) { + return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api); + }); + var xAxisScale = coordSys.getAxis('x').scale; + var yAxisScale = coordSys.getAxis('y').scale; + var xAxisExtent = xAxisScale.getExtent(); + var yAxisExtent = yAxisScale.getExtent(); + var xPointExtent = [xAxisScale.parse(areaData.get('x0', idx)), xAxisScale.parse(areaData.get('x1', idx))]; + var yPointExtent = [yAxisScale.parse(areaData.get('y0', idx)), yAxisScale.parse(areaData.get('y1', idx))]; + asc(xPointExtent); + asc(yPointExtent); + var overlapped = !(xAxisExtent[0] > xPointExtent[1] || xAxisExtent[1] < xPointExtent[0] || yAxisExtent[0] > yPointExtent[1] || yAxisExtent[1] < yPointExtent[0]); // If none of the area is inside coordSys, allClipped is set to be true + // in layout so that label will not be displayed. See #12591 + + var allClipped = !overlapped; + areaData.setItemLayout(idx, { + points: points, + allClipped: allClipped + }); + var style = areaData.getItemModel(idx).getModel('itemStyle').getItemStyle(); + var color$1 = getVisualFromData(seriesData, 'color'); + + if (!style.fill) { + style.fill = color$1; + + if (isString(style.fill)) { + style.fill = modifyAlpha(style.fill, 0.4); + } + } + + if (!style.stroke) { + style.stroke = color$1; + } // Visual + + + areaData.setItemVisual(idx, 'style', style); + }); + areaData.diff(inner$j(polygonGroup).data).add(function (idx) { + var layout = areaData.getItemLayout(idx); + + if (!layout.allClipped) { + var polygon = new Polygon({ + shape: { + points: layout.points + } + }); + areaData.setItemGraphicEl(idx, polygon); + polygonGroup.group.add(polygon); + } + }).update(function (newIdx, oldIdx) { + var polygon = inner$j(polygonGroup).data.getItemGraphicEl(oldIdx); + var layout = areaData.getItemLayout(newIdx); + + if (!layout.allClipped) { + if (polygon) { + updateProps(polygon, { + shape: { + points: layout.points + } + }, maModel, newIdx); + } else { + polygon = new Polygon({ + shape: { + points: layout.points + } + }); + } + + areaData.setItemGraphicEl(newIdx, polygon); + polygonGroup.group.add(polygon); + } else if (polygon) { + polygonGroup.group.remove(polygon); + } + }).remove(function (idx) { + var polygon = inner$j(polygonGroup).data.getItemGraphicEl(idx); + polygonGroup.group.remove(polygon); + }).execute(); + areaData.eachItemGraphicEl(function (polygon, idx) { + var itemModel = areaData.getItemModel(idx); + var style = areaData.getItemVisual(idx, 'style'); + polygon.useStyle(areaData.getItemVisual(idx, 'style')); + setLabelStyle(polygon, getLabelStatesModels(itemModel), { + labelFetcher: maModel, + labelDataIndex: idx, + defaultText: areaData.getName(idx) || '', + inheritColor: isString(style.fill) ? modifyAlpha(style.fill, 1) : '#000' + }); + setStatesStylesFromModel(polygon, itemModel); + toggleHoverEmphasis(polygon, null, null, itemModel.get(['emphasis', 'disabled'])); + getECData(polygon).dataModel = maModel; + }); + inner$j(polygonGroup).data = areaData; + polygonGroup.group.silent = maModel.get('silent') || seriesModel.get('silent'); + }; + + MarkAreaView.type = 'markArea'; + return MarkAreaView; + }(MarkerView); + + function createList$2(coordSys, seriesModel, maModel) { + var areaData; + var dataDims; + var dims = ['x0', 'y0', 'x1', 'y1']; + + if (coordSys) { + var coordDimsInfos_1 = map(coordSys && coordSys.dimensions, function (coordDim) { + var data = seriesModel.getData(); + var info = data.getDimensionInfo(data.mapDimension(coordDim)) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys + + return extend(extend({}, info), { + name: coordDim, + // DON'T use ordinalMeta to parse and collect ordinal. + ordinalMeta: null + }); + }); + dataDims = map(dims, function (dim, idx) { + return { + name: dim, + type: coordDimsInfos_1[idx % 2].type + }; + }); + areaData = new SeriesData(dataDims, maModel); + } else { + dataDims = [{ + name: 'value', + type: 'float' + }]; + areaData = new SeriesData(dataDims, maModel); + } + + var optData = map(maModel.get('data'), curry(markAreaTransform, seriesModel, coordSys, maModel)); + + if (coordSys) { + optData = filter(optData, curry(markAreaFilter, coordSys)); + } + + var dimValueGetter = coordSys ? function (item, dimName, dataIndex, dimIndex) { + // TODO should convert to ParsedValue? + var rawVal = item.coord[Math.floor(dimIndex / 2)][dimIndex % 2]; + return parseDataValue(rawVal, dataDims[dimIndex]); + } : function (item, dimName, dataIndex, dimIndex) { + return parseDataValue(item.value, dataDims[dimIndex]); + }; + areaData.initData(optData, null, dimValueGetter); + areaData.hasItemOption = true; + return areaData; + } + + function install$G(registers) { + registers.registerComponentModel(MarkAreaModel); + registers.registerComponentView(MarkAreaView); + registers.registerPreprocessor(function (opt) { + if (checkMarkerInSeries(opt.series, 'markArea')) { + // Make sure markArea component is enabled + opt.markArea = opt.markArea || {}; + } + }); + } + + var getDefaultSelectorOptions = function (ecModel, type) { + if (type === 'all') { + return { + type: 'all', + title: ecModel.getLocaleModel().get(['legend', 'selector', 'all']) + }; + } else if (type === 'inverse') { + return { + type: 'inverse', + title: ecModel.getLocaleModel().get(['legend', 'selector', 'inverse']) + }; + } + }; + + var LegendModel = + /** @class */ + function (_super) { + __extends(LegendModel, _super); + + function LegendModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = LegendModel.type; + _this.layoutMode = { + type: 'box', + // legend.width/height are maxWidth/maxHeight actually, + // whereas realy width/height is calculated by its content. + // (Setting {left: 10, right: 10} does not make sense). + // So consider the case: + // `setOption({legend: {left: 10});` + // then `setOption({legend: {right: 10});` + // The previous `left` should be cleared by setting `ignoreSize`. + ignoreSize: true + }; + return _this; + } + + LegendModel.prototype.init = function (option, parentModel, ecModel) { + this.mergeDefaultAndTheme(option, ecModel); + option.selected = option.selected || {}; + + this._updateSelector(option); + }; + + LegendModel.prototype.mergeOption = function (option, ecModel) { + _super.prototype.mergeOption.call(this, option, ecModel); + + this._updateSelector(option); + }; + + LegendModel.prototype._updateSelector = function (option) { + var selector = option.selector; + var ecModel = this.ecModel; + + if (selector === true) { + selector = option.selector = ['all', 'inverse']; + } + + if (isArray(selector)) { + each(selector, function (item, index) { + isString(item) && (item = { + type: item + }); + selector[index] = merge(item, getDefaultSelectorOptions(ecModel, item.type)); + }); + } + }; + + LegendModel.prototype.optionUpdated = function () { + this._updateData(this.ecModel); + + var legendData = this._data; // If selectedMode is single, try to select one + + if (legendData[0] && this.get('selectedMode') === 'single') { + var hasSelected = false; // If has any selected in option.selected + + for (var i = 0; i < legendData.length; i++) { + var name_1 = legendData[i].get('name'); + + if (this.isSelected(name_1)) { + // Force to unselect others + this.select(name_1); + hasSelected = true; + break; + } + } // Try select the first if selectedMode is single + + + !hasSelected && this.select(legendData[0].get('name')); + } + }; + + LegendModel.prototype._updateData = function (ecModel) { + var potentialData = []; + var availableNames = []; + ecModel.eachRawSeries(function (seriesModel) { + var seriesName = seriesModel.name; + availableNames.push(seriesName); + var isPotential; + + if (seriesModel.legendVisualProvider) { + var provider = seriesModel.legendVisualProvider; + var names = provider.getAllNames(); + + if (!ecModel.isSeriesFiltered(seriesModel)) { + availableNames = availableNames.concat(names); + } + + if (names.length) { + potentialData = potentialData.concat(names); + } else { + isPotential = true; + } + } else { + isPotential = true; + } + + if (isPotential && isNameSpecified(seriesModel)) { + potentialData.push(seriesModel.name); + } + }); + /** + * @type {Array.} + * @private + */ + + this._availableNames = availableNames; // If legend.data not specified in option, use availableNames as data, + // which is convinient for user preparing option. + + var rawData = this.get('data') || potentialData; + var legendData = map(rawData, function (dataItem) { + // Can be string or number + if (isString(dataItem) || isNumber(dataItem)) { + dataItem = { + name: dataItem + }; + } + + return new Model(dataItem, this, this.ecModel); + }, this); + /** + * @type {Array.} + * @private + */ + + this._data = legendData; + }; + + LegendModel.prototype.getData = function () { + return this._data; + }; + + LegendModel.prototype.select = function (name) { + var selected = this.option.selected; + var selectedMode = this.get('selectedMode'); + + if (selectedMode === 'single') { + var data = this._data; + each(data, function (dataItem) { + selected[dataItem.get('name')] = false; + }); + } + + selected[name] = true; + }; + + LegendModel.prototype.unSelect = function (name) { + if (this.get('selectedMode') !== 'single') { + this.option.selected[name] = false; + } + }; + + LegendModel.prototype.toggleSelected = function (name) { + var selected = this.option.selected; // Default is true + + if (!selected.hasOwnProperty(name)) { + selected[name] = true; + } + + this[selected[name] ? 'unSelect' : 'select'](name); + }; + + LegendModel.prototype.allSelect = function () { + var data = this._data; + var selected = this.option.selected; + each(data, function (dataItem) { + selected[dataItem.get('name', true)] = true; + }); + }; + + LegendModel.prototype.inverseSelect = function () { + var data = this._data; + var selected = this.option.selected; + each(data, function (dataItem) { + var name = dataItem.get('name', true); // Initially, default value is true + + if (!selected.hasOwnProperty(name)) { + selected[name] = true; + } + + selected[name] = !selected[name]; + }); + }; + + LegendModel.prototype.isSelected = function (name) { + var selected = this.option.selected; + return !(selected.hasOwnProperty(name) && !selected[name]) && indexOf(this._availableNames, name) >= 0; + }; + + LegendModel.prototype.getOrient = function () { + return this.get('orient') === 'vertical' ? { + index: 1, + name: 'vertical' + } : { + index: 0, + name: 'horizontal' + }; + }; + + LegendModel.type = 'legend.plain'; + LegendModel.dependencies = ['series']; + LegendModel.defaultOption = { + // zlevel: 0, + z: 4, + show: true, + orient: 'horizontal', + left: 'center', + // right: 'center', + top: 0, + // bottom: null, + align: 'auto', + backgroundColor: 'rgba(0,0,0,0)', + borderColor: '#ccc', + borderRadius: 0, + borderWidth: 0, + padding: 5, + itemGap: 10, + itemWidth: 25, + itemHeight: 14, + symbolRotate: 'inherit', + symbolKeepAspect: true, + inactiveColor: '#ccc', + inactiveBorderColor: '#ccc', + inactiveBorderWidth: 'auto', + itemStyle: { + color: 'inherit', + opacity: 'inherit', + borderColor: 'inherit', + borderWidth: 'auto', + borderCap: 'inherit', + borderJoin: 'inherit', + borderDashOffset: 'inherit', + borderMiterLimit: 'inherit' + }, + lineStyle: { + width: 'auto', + color: 'inherit', + inactiveColor: '#ccc', + inactiveWidth: 2, + opacity: 'inherit', + type: 'inherit', + cap: 'inherit', + join: 'inherit', + dashOffset: 'inherit', + miterLimit: 'inherit' + }, + textStyle: { + color: '#333' + }, + selectedMode: true, + selector: false, + selectorLabel: { + show: true, + borderRadius: 10, + padding: [3, 5, 3, 5], + fontSize: 12, + fontFamily: 'sans-serif', + color: '#666', + borderWidth: 1, + borderColor: '#666' + }, + emphasis: { + selectorLabel: { + show: true, + color: '#eee', + backgroundColor: '#666' + } + }, + selectorPosition: 'auto', + selectorItemGap: 7, + selectorButtonGap: 10, + tooltip: { + show: false + } + }; + return LegendModel; + }(ComponentModel); + + var curry$1 = curry; + var each$c = each; + var Group$2 = Group; + + var LegendView = + /** @class */ + function (_super) { + __extends(LegendView, _super); + + function LegendView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = LegendView.type; + _this.newlineDisabled = false; + return _this; + } + + LegendView.prototype.init = function () { + this.group.add(this._contentGroup = new Group$2()); + this.group.add(this._selectorGroup = new Group$2()); + this._isFirstRender = true; + }; + /** + * @protected + */ + + + LegendView.prototype.getContentGroup = function () { + return this._contentGroup; + }; + /** + * @protected + */ + + + LegendView.prototype.getSelectorGroup = function () { + return this._selectorGroup; + }; + /** + * @override + */ + + + LegendView.prototype.render = function (legendModel, ecModel, api) { + var isFirstRender = this._isFirstRender; + this._isFirstRender = false; + this.resetInner(); + + if (!legendModel.get('show', true)) { + return; + } + + var itemAlign = legendModel.get('align'); + var orient = legendModel.get('orient'); + + if (!itemAlign || itemAlign === 'auto') { + itemAlign = legendModel.get('left') === 'right' && orient === 'vertical' ? 'right' : 'left'; + } // selector has been normalized to an array in model + + + var selector = legendModel.get('selector', true); + var selectorPosition = legendModel.get('selectorPosition', true); + + if (selector && (!selectorPosition || selectorPosition === 'auto')) { + selectorPosition = orient === 'horizontal' ? 'end' : 'start'; + } + + this.renderInner(itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition); // Perform layout. + + var positionInfo = legendModel.getBoxLayoutParams(); + var viewportSize = { + width: api.getWidth(), + height: api.getHeight() + }; + var padding = legendModel.get('padding'); + var maxSize = getLayoutRect(positionInfo, viewportSize, padding); + var mainRect = this.layoutInner(legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition); // Place mainGroup, based on the calculated `mainRect`. + + var layoutRect = getLayoutRect(defaults({ + width: mainRect.width, + height: mainRect.height + }, positionInfo), viewportSize, padding); + this.group.x = layoutRect.x - mainRect.x; + this.group.y = layoutRect.y - mainRect.y; + this.group.markRedraw(); // Render background after group is layout. + + this.group.add(this._backgroundEl = makeBackground(mainRect, legendModel)); + }; + + LegendView.prototype.resetInner = function () { + this.getContentGroup().removeAll(); + this._backgroundEl && this.group.remove(this._backgroundEl); + this.getSelectorGroup().removeAll(); + }; + + LegendView.prototype.renderInner = function (itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition) { + var contentGroup = this.getContentGroup(); + var legendDrawnMap = createHashMap(); + var selectMode = legendModel.get('selectedMode'); + var excludeSeriesId = []; + ecModel.eachRawSeries(function (seriesModel) { + !seriesModel.get('legendHoverLink') && excludeSeriesId.push(seriesModel.id); + }); + each$c(legendModel.getData(), function (legendItemModel, dataIndex) { + var name = legendItemModel.get('name'); // Use empty string or \n as a newline string + + if (!this.newlineDisabled && (name === '' || name === '\n')) { + var g = new Group$2(); // @ts-ignore + + g.newline = true; + contentGroup.add(g); + return; + } // Representitive series. + + + var seriesModel = ecModel.getSeriesByName(name)[0]; + + if (legendDrawnMap.get(name)) { + // Have been drawed + return; + } // Legend to control series. + + + if (seriesModel) { + var data = seriesModel.getData(); + var lineVisualStyle = data.getVisual('legendLineStyle') || {}; + var legendIcon = data.getVisual('legendIcon'); + /** + * `data.getVisual('style')` may be the color from the register + * in series. For example, for line series, + */ + + var style = data.getVisual('style'); + + var itemGroup = this._createItem(seriesModel, name, dataIndex, legendItemModel, legendModel, itemAlign, lineVisualStyle, style, legendIcon, selectMode); + + itemGroup.on('click', curry$1(dispatchSelectAction, name, null, api, excludeSeriesId)).on('mouseover', curry$1(dispatchHighlightAction, seriesModel.name, null, api, excludeSeriesId)).on('mouseout', curry$1(dispatchDownplayAction, seriesModel.name, null, api, excludeSeriesId)); + legendDrawnMap.set(name, true); + } else { + // Legend to control data. In pie and funnel. + ecModel.eachRawSeries(function (seriesModel) { + // In case multiple series has same data name + if (legendDrawnMap.get(name)) { + return; + } + + if (seriesModel.legendVisualProvider) { + var provider = seriesModel.legendVisualProvider; + + if (!provider.containName(name)) { + return; + } + + var idx = provider.indexOfName(name); + var style = provider.getItemVisual(idx, 'style'); + var legendIcon = provider.getItemVisual(idx, 'legendIcon'); + var colorArr = parse(style.fill); // Color may be set to transparent in visualMap when data is out of range. + // Do not show nothing. + + if (colorArr && colorArr[3] === 0) { + colorArr[3] = 0.2; // TODO color is set to 0, 0, 0, 0. Should show correct RGBA + + style = extend(extend({}, style), { + fill: stringify(colorArr, 'rgba') + }); + } + + var itemGroup = this._createItem(seriesModel, name, dataIndex, legendItemModel, legendModel, itemAlign, {}, style, legendIcon, selectMode); // FIXME: consider different series has items with the same name. + + + itemGroup.on('click', curry$1(dispatchSelectAction, null, name, api, excludeSeriesId)) // Should not specify the series name, consider legend controls + // more than one pie series. + .on('mouseover', curry$1(dispatchHighlightAction, null, name, api, excludeSeriesId)).on('mouseout', curry$1(dispatchDownplayAction, null, name, api, excludeSeriesId)); + legendDrawnMap.set(name, true); + } + }, this); + } + + if ("development" !== 'production') { + if (!legendDrawnMap.get(name)) { + console.warn(name + ' series not exists. Legend data should be same with series name or data name.'); + } + } + }, this); + + if (selector) { + this._createSelector(selector, legendModel, api, orient, selectorPosition); + } + }; + + LegendView.prototype._createSelector = function (selector, legendModel, api, orient, selectorPosition) { + var selectorGroup = this.getSelectorGroup(); + each$c(selector, function createSelectorButton(selectorItem) { + var type = selectorItem.type; + var labelText = new ZRText({ + style: { + x: 0, + y: 0, + align: 'center', + verticalAlign: 'middle' + }, + onclick: function () { + api.dispatchAction({ + type: type === 'all' ? 'legendAllSelect' : 'legendInverseSelect' + }); + } + }); + selectorGroup.add(labelText); + var labelModel = legendModel.getModel('selectorLabel'); + var emphasisLabelModel = legendModel.getModel(['emphasis', 'selectorLabel']); + setLabelStyle(labelText, { + normal: labelModel, + emphasis: emphasisLabelModel + }, { + defaultText: selectorItem.title + }); + enableHoverEmphasis(labelText); + }); + }; + + LegendView.prototype._createItem = function (seriesModel, name, dataIndex, legendItemModel, legendModel, itemAlign, lineVisualStyle, itemVisualStyle, legendIcon, selectMode) { + var drawType = seriesModel.visualDrawType; + var itemWidth = legendModel.get('itemWidth'); + var itemHeight = legendModel.get('itemHeight'); + var isSelected = legendModel.isSelected(name); + var iconRotate = legendItemModel.get('symbolRotate'); + var symbolKeepAspect = legendItemModel.get('symbolKeepAspect'); + var legendIconType = legendItemModel.get('icon'); + legendIcon = legendIconType || legendIcon || 'roundRect'; + var style = getLegendStyle(legendIcon, legendItemModel, lineVisualStyle, itemVisualStyle, drawType, isSelected); + var itemGroup = new Group$2(); + var textStyleModel = legendItemModel.getModel('textStyle'); + + if (isFunction(seriesModel.getLegendIcon) && (!legendIconType || legendIconType === 'inherit')) { + // Series has specific way to define legend icon + itemGroup.add(seriesModel.getLegendIcon({ + itemWidth: itemWidth, + itemHeight: itemHeight, + icon: legendIcon, + iconRotate: iconRotate, + itemStyle: style.itemStyle, + lineStyle: style.lineStyle, + symbolKeepAspect: symbolKeepAspect + })); + } else { + // Use default legend icon policy for most series + var rotate = legendIconType === 'inherit' && seriesModel.getData().getVisual('symbol') ? iconRotate === 'inherit' ? seriesModel.getData().getVisual('symbolRotate') : iconRotate : 0; // No rotation for no icon + + itemGroup.add(getDefaultLegendIcon({ + itemWidth: itemWidth, + itemHeight: itemHeight, + icon: legendIcon, + iconRotate: rotate, + itemStyle: style.itemStyle, + lineStyle: style.lineStyle, + symbolKeepAspect: symbolKeepAspect + })); + } + + var textX = itemAlign === 'left' ? itemWidth + 5 : -5; + var textAlign = itemAlign; + var formatter = legendModel.get('formatter'); + var content = name; + + if (isString(formatter) && formatter) { + content = formatter.replace('{name}', name != null ? name : ''); + } else if (isFunction(formatter)) { + content = formatter(name); + } + + var inactiveColor = legendItemModel.get('inactiveColor'); + itemGroup.add(new ZRText({ + style: createTextStyle(textStyleModel, { + text: content, + x: textX, + y: itemHeight / 2, + fill: isSelected ? textStyleModel.getTextColor() : inactiveColor, + align: textAlign, + verticalAlign: 'middle' + }) + })); // Add a invisible rect to increase the area of mouse hover + + var hitRect = new Rect({ + shape: itemGroup.getBoundingRect(), + invisible: true + }); + var tooltipModel = legendItemModel.getModel('tooltip'); + + if (tooltipModel.get('show')) { + setTooltipConfig({ + el: hitRect, + componentModel: legendModel, + itemName: name, + itemTooltipOption: tooltipModel.option + }); + } + + itemGroup.add(hitRect); + itemGroup.eachChild(function (child) { + child.silent = true; + }); + hitRect.silent = !selectMode; + this.getContentGroup().add(itemGroup); + enableHoverEmphasis(itemGroup); // @ts-ignore + + itemGroup.__legendDataIndex = dataIndex; + return itemGroup; + }; + + LegendView.prototype.layoutInner = function (legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition) { + var contentGroup = this.getContentGroup(); + var selectorGroup = this.getSelectorGroup(); // Place items in contentGroup. + + box(legendModel.get('orient'), contentGroup, legendModel.get('itemGap'), maxSize.width, maxSize.height); + var contentRect = contentGroup.getBoundingRect(); + var contentPos = [-contentRect.x, -contentRect.y]; + selectorGroup.markRedraw(); + contentGroup.markRedraw(); + + if (selector) { + // Place buttons in selectorGroup + box( // Buttons in selectorGroup always layout horizontally + 'horizontal', selectorGroup, legendModel.get('selectorItemGap', true)); + var selectorRect = selectorGroup.getBoundingRect(); + var selectorPos = [-selectorRect.x, -selectorRect.y]; + var selectorButtonGap = legendModel.get('selectorButtonGap', true); + var orientIdx = legendModel.getOrient().index; + var wh = orientIdx === 0 ? 'width' : 'height'; + var hw = orientIdx === 0 ? 'height' : 'width'; + var yx = orientIdx === 0 ? 'y' : 'x'; + + if (selectorPosition === 'end') { + selectorPos[orientIdx] += contentRect[wh] + selectorButtonGap; + } else { + contentPos[orientIdx] += selectorRect[wh] + selectorButtonGap; + } //Always align selector to content as 'middle' + + + selectorPos[1 - orientIdx] += contentRect[hw] / 2 - selectorRect[hw] / 2; + selectorGroup.x = selectorPos[0]; + selectorGroup.y = selectorPos[1]; + contentGroup.x = contentPos[0]; + contentGroup.y = contentPos[1]; + var mainRect = { + x: 0, + y: 0 + }; + mainRect[wh] = contentRect[wh] + selectorButtonGap + selectorRect[wh]; + mainRect[hw] = Math.max(contentRect[hw], selectorRect[hw]); + mainRect[yx] = Math.min(0, selectorRect[yx] + selectorPos[1 - orientIdx]); + return mainRect; + } else { + contentGroup.x = contentPos[0]; + contentGroup.y = contentPos[1]; + return this.group.getBoundingRect(); + } + }; + /** + * @protected + */ + + + LegendView.prototype.remove = function () { + this.getContentGroup().removeAll(); + this._isFirstRender = true; + }; + + LegendView.type = 'legend.plain'; + return LegendView; + }(ComponentView); + + function getLegendStyle(iconType, legendModel, lineVisualStyle, itemVisualStyle, drawType, isSelected) { + /** + * Use series style if is inherit; + * elsewise, use legend style + */ + function handleCommonProps(style, visualStyle) { + // If lineStyle.width is 'auto', it is set to be 2 if series has border + if (style.lineWidth === 'auto') { + style.lineWidth = visualStyle.lineWidth > 0 ? 2 : 0; + } + + each$c(style, function (propVal, propName) { + style[propName] === 'inherit' && (style[propName] = visualStyle[propName]); + }); + } // itemStyle + + + var legendItemModel = legendModel.getModel('itemStyle'); + var itemStyle = legendItemModel.getItemStyle(); + var iconBrushType = iconType.lastIndexOf('empty', 0) === 0 ? 'fill' : 'stroke'; + itemStyle.decal = itemVisualStyle.decal; + + if (itemStyle.fill === 'inherit') { + /** + * Series with visualDrawType as 'stroke' should have + * series stroke as legend fill + */ + itemStyle.fill = itemVisualStyle[drawType]; + } + + if (itemStyle.stroke === 'inherit') { + /** + * icon type with "emptyXXX" should use fill color + * in visual style + */ + itemStyle.stroke = itemVisualStyle[iconBrushType]; + } + + if (itemStyle.opacity === 'inherit') { + /** + * Use lineStyle.opacity if drawType is stroke + */ + itemStyle.opacity = (drawType === 'fill' ? itemVisualStyle : lineVisualStyle).opacity; + } + + handleCommonProps(itemStyle, itemVisualStyle); // lineStyle + + var legendLineModel = legendModel.getModel('lineStyle'); + var lineStyle = legendLineModel.getLineStyle(); + handleCommonProps(lineStyle, lineVisualStyle); // Fix auto color to real color + + itemStyle.fill === 'auto' && (itemStyle.fill = itemVisualStyle.fill); + itemStyle.stroke === 'auto' && (itemStyle.stroke = itemVisualStyle.fill); + lineStyle.stroke === 'auto' && (lineStyle.stroke = itemVisualStyle.fill); + + if (!isSelected) { + var borderWidth = legendModel.get('inactiveBorderWidth'); + /** + * Since stroke is set to be inactiveBorderColor, it may occur that + * there is no border in series but border in legend, so we need to + * use border only when series has border if is set to be auto + */ + + var visualHasBorder = itemStyle[iconBrushType]; + itemStyle.lineWidth = borderWidth === 'auto' ? itemVisualStyle.lineWidth > 0 && visualHasBorder ? 2 : 0 : itemStyle.lineWidth; + itemStyle.fill = legendModel.get('inactiveColor'); + itemStyle.stroke = legendModel.get('inactiveBorderColor'); + lineStyle.stroke = legendLineModel.get('inactiveColor'); + lineStyle.lineWidth = legendLineModel.get('inactiveWidth'); + } + + return { + itemStyle: itemStyle, + lineStyle: lineStyle + }; + } + + function getDefaultLegendIcon(opt) { + var symboType = opt.icon || 'roundRect'; + var icon = createSymbol(symboType, 0, 0, opt.itemWidth, opt.itemHeight, opt.itemStyle.fill, opt.symbolKeepAspect); + icon.setStyle(opt.itemStyle); + icon.rotation = (opt.iconRotate || 0) * Math.PI / 180; + icon.setOrigin([opt.itemWidth / 2, opt.itemHeight / 2]); + + if (symboType.indexOf('empty') > -1) { + icon.style.stroke = icon.style.fill; + icon.style.fill = '#fff'; + icon.style.lineWidth = 2; + } + + return icon; + } + + function dispatchSelectAction(seriesName, dataName, api, excludeSeriesId) { + // downplay before unselect + dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId); + api.dispatchAction({ + type: 'legendToggleSelect', + name: seriesName != null ? seriesName : dataName + }); // highlight after select + // TODO higlight immediately may cause animation loss. + + dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId); + } + + function isUseHoverLayer(api) { + var list = api.getZr().storage.getDisplayList(); + var emphasisState; + var i = 0; + var len = list.length; + + while (i < len && !(emphasisState = list[i].states.emphasis)) { + i++; + } + + return emphasisState && emphasisState.hoverLayer; + } + + function dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId) { + // If element hover will move to a hoverLayer. + if (!isUseHoverLayer(api)) { + api.dispatchAction({ + type: 'highlight', + seriesName: seriesName, + name: dataName, + excludeSeriesId: excludeSeriesId + }); + } + } + + function dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId) { + // If element hover will move to a hoverLayer. + if (!isUseHoverLayer(api)) { + api.dispatchAction({ + type: 'downplay', + seriesName: seriesName, + name: dataName, + excludeSeriesId: excludeSeriesId + }); + } + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + function legendFilter(ecModel) { + var legendModels = ecModel.findComponents({ + mainType: 'legend' + }); + + if (legendModels && legendModels.length) { + ecModel.filterSeries(function (series) { + // If in any legend component the status is not selected. + // Because in legend series is assumed selected when it is not in the legend data. + for (var i = 0; i < legendModels.length; i++) { + if (!legendModels[i].isSelected(series.name)) { + return false; + } + } + + return true; + }); + } + } + + function legendSelectActionHandler(methodName, payload, ecModel) { + var selectedMap = {}; + var isToggleSelect = methodName === 'toggleSelected'; + var isSelected; // Update all legend components + + ecModel.eachComponent('legend', function (legendModel) { + if (isToggleSelect && isSelected != null) { + // Force other legend has same selected status + // Or the first is toggled to true and other are toggled to false + // In the case one legend has some item unSelected in option. And if other legend + // doesn't has the item, they will assume it is selected. + legendModel[isSelected ? 'select' : 'unSelect'](payload.name); + } else if (methodName === 'allSelect' || methodName === 'inverseSelect') { + legendModel[methodName](); + } else { + legendModel[methodName](payload.name); + isSelected = legendModel.isSelected(payload.name); + } + + var legendData = legendModel.getData(); + each(legendData, function (model) { + var name = model.get('name'); // Wrap element + + if (name === '\n' || name === '') { + return; + } + + var isItemSelected = legendModel.isSelected(name); + + if (selectedMap.hasOwnProperty(name)) { + // Unselected if any legend is unselected + selectedMap[name] = selectedMap[name] && isItemSelected; + } else { + selectedMap[name] = isItemSelected; + } + }); + }); // Return the event explicitly + + return methodName === 'allSelect' || methodName === 'inverseSelect' ? { + selected: selectedMap + } : { + name: payload.name, + selected: selectedMap + }; + } + + function installLegendAction(registers) { + /** + * @event legendToggleSelect + * @type {Object} + * @property {string} type 'legendToggleSelect' + * @property {string} [from] + * @property {string} name Series name or data item name + */ + registers.registerAction('legendToggleSelect', 'legendselectchanged', curry(legendSelectActionHandler, 'toggleSelected')); + registers.registerAction('legendAllSelect', 'legendselectall', curry(legendSelectActionHandler, 'allSelect')); + registers.registerAction('legendInverseSelect', 'legendinverseselect', curry(legendSelectActionHandler, 'inverseSelect')); + /** + * @event legendSelect + * @type {Object} + * @property {string} type 'legendSelect' + * @property {string} name Series name or data item name + */ + + registers.registerAction('legendSelect', 'legendselected', curry(legendSelectActionHandler, 'select')); + /** + * @event legendUnSelect + * @type {Object} + * @property {string} type 'legendUnSelect' + * @property {string} name Series name or data item name + */ + + registers.registerAction('legendUnSelect', 'legendunselected', curry(legendSelectActionHandler, 'unSelect')); + } + + function install$H(registers) { + registers.registerComponentModel(LegendModel); + registers.registerComponentView(LegendView); + registers.registerProcessor(registers.PRIORITY.PROCESSOR.SERIES_FILTER, legendFilter); + registers.registerSubTypeDefaulter('legend', function () { + return 'plain'; + }); + installLegendAction(registers); + } + + var ScrollableLegendModel = + /** @class */ + function (_super) { + __extends(ScrollableLegendModel, _super); + + function ScrollableLegendModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ScrollableLegendModel.type; + return _this; + } + /** + * @param {number} scrollDataIndex + */ + + + ScrollableLegendModel.prototype.setScrollDataIndex = function (scrollDataIndex) { + this.option.scrollDataIndex = scrollDataIndex; + }; + + ScrollableLegendModel.prototype.init = function (option, parentModel, ecModel) { + var inputPositionParams = getLayoutParams(option); + + _super.prototype.init.call(this, option, parentModel, ecModel); + + mergeAndNormalizeLayoutParams$1(this, option, inputPositionParams); + }; + /** + * @override + */ + + + ScrollableLegendModel.prototype.mergeOption = function (option, ecModel) { + _super.prototype.mergeOption.call(this, option, ecModel); + + mergeAndNormalizeLayoutParams$1(this, this.option, option); + }; + + ScrollableLegendModel.type = 'legend.scroll'; + ScrollableLegendModel.defaultOption = inheritDefaultOption(LegendModel.defaultOption, { + scrollDataIndex: 0, + pageButtonItemGap: 5, + pageButtonGap: null, + pageButtonPosition: 'end', + pageFormatter: '{current}/{total}', + pageIcons: { + horizontal: ['M0,0L12,-10L12,10z', 'M0,0L-12,-10L-12,10z'], + vertical: ['M0,0L20,0L10,-20z', 'M0,0L20,0L10,20z'] + }, + pageIconColor: '#2f4554', + pageIconInactiveColor: '#aaa', + pageIconSize: 15, + pageTextStyle: { + color: '#333' + }, + animationDurationUpdate: 800 + }); + return ScrollableLegendModel; + }(LegendModel); + + function mergeAndNormalizeLayoutParams$1(legendModel, target, raw) { + var orient = legendModel.getOrient(); + var ignoreSize = [1, 1]; + ignoreSize[orient.index] = 0; + mergeLayoutParam(target, raw, { + type: 'box', + ignoreSize: !!ignoreSize + }); + } + + var Group$3 = Group; + var WH$1 = ['width', 'height']; + var XY$1 = ['x', 'y']; + + var ScrollableLegendView = + /** @class */ + function (_super) { + __extends(ScrollableLegendView, _super); + + function ScrollableLegendView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ScrollableLegendView.type; + _this.newlineDisabled = true; + _this._currentIndex = 0; + return _this; + } + + ScrollableLegendView.prototype.init = function () { + _super.prototype.init.call(this); + + this.group.add(this._containerGroup = new Group$3()); + + this._containerGroup.add(this.getContentGroup()); + + this.group.add(this._controllerGroup = new Group$3()); + }; + /** + * @override + */ + + + ScrollableLegendView.prototype.resetInner = function () { + _super.prototype.resetInner.call(this); + + this._controllerGroup.removeAll(); + + this._containerGroup.removeClipPath(); + + this._containerGroup.__rectSize = null; + }; + /** + * @override + */ + + + ScrollableLegendView.prototype.renderInner = function (itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition) { + var self = this; // Render content items. + + _super.prototype.renderInner.call(this, itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition); + + var controllerGroup = this._controllerGroup; // FIXME: support be 'auto' adapt to size number text length, + // e.g., '3/12345' should not overlap with the control arrow button. + + var pageIconSize = legendModel.get('pageIconSize', true); + var pageIconSizeArr = isArray(pageIconSize) ? pageIconSize : [pageIconSize, pageIconSize]; + createPageButton('pagePrev', 0); + var pageTextStyleModel = legendModel.getModel('pageTextStyle'); + controllerGroup.add(new ZRText({ + name: 'pageText', + style: { + // Placeholder to calculate a proper layout. + text: 'xx/xx', + fill: pageTextStyleModel.getTextColor(), + font: pageTextStyleModel.getFont(), + verticalAlign: 'middle', + align: 'center' + }, + silent: true + })); + createPageButton('pageNext', 1); + + function createPageButton(name, iconIdx) { + var pageDataIndexName = name + 'DataIndex'; + var icon = createIcon(legendModel.get('pageIcons', true)[legendModel.getOrient().name][iconIdx], { + // Buttons will be created in each render, so we do not need + // to worry about avoiding using legendModel kept in scope. + onclick: bind(self._pageGo, self, pageDataIndexName, legendModel, api) + }, { + x: -pageIconSizeArr[0] / 2, + y: -pageIconSizeArr[1] / 2, + width: pageIconSizeArr[0], + height: pageIconSizeArr[1] + }); + icon.name = name; + controllerGroup.add(icon); + } + }; + /** + * @override + */ + + + ScrollableLegendView.prototype.layoutInner = function (legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition) { + var selectorGroup = this.getSelectorGroup(); + var orientIdx = legendModel.getOrient().index; + var wh = WH$1[orientIdx]; + var xy = XY$1[orientIdx]; + var hw = WH$1[1 - orientIdx]; + var yx = XY$1[1 - orientIdx]; + selector && box( // Buttons in selectorGroup always layout horizontally + 'horizontal', selectorGroup, legendModel.get('selectorItemGap', true)); + var selectorButtonGap = legendModel.get('selectorButtonGap', true); + var selectorRect = selectorGroup.getBoundingRect(); + var selectorPos = [-selectorRect.x, -selectorRect.y]; + var processMaxSize = clone(maxSize); + selector && (processMaxSize[wh] = maxSize[wh] - selectorRect[wh] - selectorButtonGap); + + var mainRect = this._layoutContentAndController(legendModel, isFirstRender, processMaxSize, orientIdx, wh, hw, yx, xy); + + if (selector) { + if (selectorPosition === 'end') { + selectorPos[orientIdx] += mainRect[wh] + selectorButtonGap; + } else { + var offset = selectorRect[wh] + selectorButtonGap; + selectorPos[orientIdx] -= offset; + mainRect[xy] -= offset; + } + + mainRect[wh] += selectorRect[wh] + selectorButtonGap; + selectorPos[1 - orientIdx] += mainRect[yx] + mainRect[hw] / 2 - selectorRect[hw] / 2; + mainRect[hw] = Math.max(mainRect[hw], selectorRect[hw]); + mainRect[yx] = Math.min(mainRect[yx], selectorRect[yx] + selectorPos[1 - orientIdx]); + selectorGroup.x = selectorPos[0]; + selectorGroup.y = selectorPos[1]; + selectorGroup.markRedraw(); + } + + return mainRect; + }; + + ScrollableLegendView.prototype._layoutContentAndController = function (legendModel, isFirstRender, maxSize, orientIdx, wh, hw, yx, xy) { + var contentGroup = this.getContentGroup(); + var containerGroup = this._containerGroup; + var controllerGroup = this._controllerGroup; // Place items in contentGroup. + + box(legendModel.get('orient'), contentGroup, legendModel.get('itemGap'), !orientIdx ? null : maxSize.width, orientIdx ? null : maxSize.height); + box( // Buttons in controller are layout always horizontally. + 'horizontal', controllerGroup, legendModel.get('pageButtonItemGap', true)); + var contentRect = contentGroup.getBoundingRect(); + var controllerRect = controllerGroup.getBoundingRect(); + var showController = this._showController = contentRect[wh] > maxSize[wh]; // In case that the inner elements of contentGroup layout do not based on [0, 0] + + var contentPos = [-contentRect.x, -contentRect.y]; // Remain contentPos when scroll animation perfroming. + // If first rendering, `contentGroup.position` is [0, 0], which + // does not make sense and may cause unexepcted animation if adopted. + + if (!isFirstRender) { + contentPos[orientIdx] = contentGroup[xy]; + } // Layout container group based on 0. + + + var containerPos = [0, 0]; + var controllerPos = [-controllerRect.x, -controllerRect.y]; + var pageButtonGap = retrieve2(legendModel.get('pageButtonGap', true), legendModel.get('itemGap', true)); // Place containerGroup and controllerGroup and contentGroup. + + if (showController) { + var pageButtonPosition = legendModel.get('pageButtonPosition', true); // controller is on the right / bottom. + + if (pageButtonPosition === 'end') { + controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh]; + } // controller is on the left / top. + else { + containerPos[orientIdx] += controllerRect[wh] + pageButtonGap; + } + } // Always align controller to content as 'middle'. + + + controllerPos[1 - orientIdx] += contentRect[hw] / 2 - controllerRect[hw] / 2; + contentGroup.setPosition(contentPos); + containerGroup.setPosition(containerPos); + controllerGroup.setPosition(controllerPos); // Calculate `mainRect` and set `clipPath`. + // mainRect should not be calculated by `this.group.getBoundingRect()` + // for sake of the overflow. + + var mainRect = { + x: 0, + y: 0 + }; // Consider content may be overflow (should be clipped). + + mainRect[wh] = showController ? maxSize[wh] : contentRect[wh]; + mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw]); // `containerRect[yx] + containerPos[1 - orientIdx]` is 0. + + mainRect[yx] = Math.min(0, controllerRect[yx] + controllerPos[1 - orientIdx]); + containerGroup.__rectSize = maxSize[wh]; + + if (showController) { + var clipShape = { + x: 0, + y: 0 + }; + clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap, 0); + clipShape[hw] = mainRect[hw]; + containerGroup.setClipPath(new Rect({ + shape: clipShape + })); // Consider content may be larger than container, container rect + // can not be obtained from `containerGroup.getBoundingRect()`. + + containerGroup.__rectSize = clipShape[wh]; + } else { + // Do not remove or ignore controller. Keep them set as placeholders. + controllerGroup.eachChild(function (child) { + child.attr({ + invisible: true, + silent: true + }); + }); + } // Content translate animation. + + + var pageInfo = this._getPageInfo(legendModel); + + pageInfo.pageIndex != null && updateProps(contentGroup, { + x: pageInfo.contentPosition[0], + y: pageInfo.contentPosition[1] + }, // When switch from "show controller" to "not show controller", view should be + // updated immediately without animation, otherwise causes weird effect. + showController ? legendModel : null); + + this._updatePageInfoView(legendModel, pageInfo); + + return mainRect; + }; + + ScrollableLegendView.prototype._pageGo = function (to, legendModel, api) { + var scrollDataIndex = this._getPageInfo(legendModel)[to]; + + scrollDataIndex != null && api.dispatchAction({ + type: 'legendScroll', + scrollDataIndex: scrollDataIndex, + legendId: legendModel.id + }); + }; + + ScrollableLegendView.prototype._updatePageInfoView = function (legendModel, pageInfo) { + var controllerGroup = this._controllerGroup; + each(['pagePrev', 'pageNext'], function (name) { + var key = name + 'DataIndex'; + var canJump = pageInfo[key] != null; + var icon = controllerGroup.childOfName(name); + + if (icon) { + icon.setStyle('fill', canJump ? legendModel.get('pageIconColor', true) : legendModel.get('pageIconInactiveColor', true)); + icon.cursor = canJump ? 'pointer' : 'default'; + } + }); + var pageText = controllerGroup.childOfName('pageText'); + var pageFormatter = legendModel.get('pageFormatter'); + var pageIndex = pageInfo.pageIndex; + var current = pageIndex != null ? pageIndex + 1 : 0; + var total = pageInfo.pageCount; + pageText && pageFormatter && pageText.setStyle('text', isString(pageFormatter) ? pageFormatter.replace('{current}', current == null ? '' : current + '').replace('{total}', total == null ? '' : total + '') : pageFormatter({ + current: current, + total: total + })); + }; + /** + * contentPosition: Array., null when data item not found. + * pageIndex: number, null when data item not found. + * pageCount: number, always be a number, can be 0. + * pagePrevDataIndex: number, null when no previous page. + * pageNextDataIndex: number, null when no next page. + * } + */ + + + ScrollableLegendView.prototype._getPageInfo = function (legendModel) { + var scrollDataIndex = legendModel.get('scrollDataIndex', true); + var contentGroup = this.getContentGroup(); + var containerRectSize = this._containerGroup.__rectSize; + var orientIdx = legendModel.getOrient().index; + var wh = WH$1[orientIdx]; + var xy = XY$1[orientIdx]; + + var targetItemIndex = this._findTargetItemIndex(scrollDataIndex); + + var children = contentGroup.children(); + var targetItem = children[targetItemIndex]; + var itemCount = children.length; + var pCount = !itemCount ? 0 : 1; + var result = { + contentPosition: [contentGroup.x, contentGroup.y], + pageCount: pCount, + pageIndex: pCount - 1, + pagePrevDataIndex: null, + pageNextDataIndex: null + }; + + if (!targetItem) { + return result; + } + + var targetItemInfo = getItemInfo(targetItem); + result.contentPosition[orientIdx] = -targetItemInfo.s; // Strategy: + // (1) Always align based on the left/top most item. + // (2) It is user-friendly that the last item shown in the + // current window is shown at the begining of next window. + // Otherwise if half of the last item is cut by the window, + // it will have no chance to display entirely. + // (3) Consider that item size probably be different, we + // have calculate pageIndex by size rather than item index, + // and we can not get page index directly by division. + // (4) The window is to narrow to contain more than + // one item, we should make sure that the page can be fliped. + + for (var i = targetItemIndex + 1, winStartItemInfo = targetItemInfo, winEndItemInfo = targetItemInfo, currItemInfo = null; i <= itemCount; ++i) { + currItemInfo = getItemInfo(children[i]); + + if ( // Half of the last item is out of the window. + !currItemInfo && winEndItemInfo.e > winStartItemInfo.s + containerRectSize || // If the current item does not intersect with the window, the new page + // can be started at the current item or the last item. + currItemInfo && !intersect(currItemInfo, winStartItemInfo.s)) { + if (winEndItemInfo.i > winStartItemInfo.i) { + winStartItemInfo = winEndItemInfo; + } else { + // e.g., when page size is smaller than item size. + winStartItemInfo = currItemInfo; + } + + if (winStartItemInfo) { + if (result.pageNextDataIndex == null) { + result.pageNextDataIndex = winStartItemInfo.i; + } + + ++result.pageCount; + } + } + + winEndItemInfo = currItemInfo; + } + + for (var i = targetItemIndex - 1, winStartItemInfo = targetItemInfo, winEndItemInfo = targetItemInfo, currItemInfo = null; i >= -1; --i) { + currItemInfo = getItemInfo(children[i]); + + if ( // If the the end item does not intersect with the window started + // from the current item, a page can be settled. + (!currItemInfo || !intersect(winEndItemInfo, currItemInfo.s)) && // e.g., when page size is smaller than item size. + winStartItemInfo.i < winEndItemInfo.i) { + winEndItemInfo = winStartItemInfo; + + if (result.pagePrevDataIndex == null) { + result.pagePrevDataIndex = winStartItemInfo.i; + } + + ++result.pageCount; + ++result.pageIndex; + } + + winStartItemInfo = currItemInfo; + } + + return result; + + function getItemInfo(el) { + if (el) { + var itemRect = el.getBoundingRect(); + var start = itemRect[xy] + el[xy]; + return { + s: start, + e: start + itemRect[wh], + i: el.__legendDataIndex + }; + } + } + + function intersect(itemInfo, winStart) { + return itemInfo.e >= winStart && itemInfo.s <= winStart + containerRectSize; + } + }; + + ScrollableLegendView.prototype._findTargetItemIndex = function (targetDataIndex) { + if (!this._showController) { + return 0; + } + + var index; + var contentGroup = this.getContentGroup(); + var defaultIndex; + contentGroup.eachChild(function (child, idx) { + var legendDataIdx = child.__legendDataIndex; // FIXME + // If the given targetDataIndex (from model) is illegal, + // we use defaultIndex. But the index on the legend model and + // action payload is still illegal. That case will not be + // changed until some scenario requires. + + if (defaultIndex == null && legendDataIdx != null) { + defaultIndex = idx; + } + + if (legendDataIdx === targetDataIndex) { + index = idx; + } + }); + return index != null ? index : defaultIndex; + }; + + ScrollableLegendView.type = 'legend.scroll'; + return ScrollableLegendView; + }(LegendView); + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + function installScrollableLegendAction(registers) { + /** + * @event legendScroll + * @type {Object} + * @property {string} type 'legendScroll' + * @property {string} scrollDataIndex + */ + registers.registerAction('legendScroll', 'legendscroll', function (payload, ecModel) { + var scrollDataIndex = payload.scrollDataIndex; + scrollDataIndex != null && ecModel.eachComponent({ + mainType: 'legend', + subType: 'scroll', + query: payload + }, function (legendModel) { + legendModel.setScrollDataIndex(scrollDataIndex); + }); + }); + } + + function install$I(registers) { + use(install$H); + registers.registerComponentModel(ScrollableLegendModel); + registers.registerComponentView(ScrollableLegendView); + installScrollableLegendAction(registers); + } + + function install$J(registers) { + use(install$H); + use(install$I); + } + + var InsideZoomModel = + /** @class */ + function (_super) { + __extends(InsideZoomModel, _super); + + function InsideZoomModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = InsideZoomModel.type; + return _this; + } + + InsideZoomModel.type = 'dataZoom.inside'; + InsideZoomModel.defaultOption = inheritDefaultOption(DataZoomModel.defaultOption, { + disabled: false, + zoomLock: false, + zoomOnMouseWheel: true, + moveOnMouseMove: true, + moveOnMouseWheel: false, + preventDefaultMouseMove: true + }); + return InsideZoomModel; + }(DataZoomModel); + + var inner$k = makeInner(); + function setViewInfoToCoordSysRecord(api, dataZoomModel, getRange) { + inner$k(api).coordSysRecordMap.each(function (coordSysRecord) { + var dzInfo = coordSysRecord.dataZoomInfoMap.get(dataZoomModel.uid); + + if (dzInfo) { + dzInfo.getRange = getRange; + } + }); + } + function disposeCoordSysRecordIfNeeded(api, dataZoomModel) { + var coordSysRecordMap = inner$k(api).coordSysRecordMap; + var coordSysKeyArr = coordSysRecordMap.keys(); + + for (var i = 0; i < coordSysKeyArr.length; i++) { + var coordSysKey = coordSysKeyArr[i]; + var coordSysRecord = coordSysRecordMap.get(coordSysKey); + var dataZoomInfoMap = coordSysRecord.dataZoomInfoMap; + + if (dataZoomInfoMap) { + var dzUid = dataZoomModel.uid; + var dzInfo = dataZoomInfoMap.get(dzUid); + + if (dzInfo) { + dataZoomInfoMap.removeKey(dzUid); + + if (!dataZoomInfoMap.keys().length) { + disposeCoordSysRecord(coordSysRecordMap, coordSysRecord); + } + } + } + } + } + + function disposeCoordSysRecord(coordSysRecordMap, coordSysRecord) { + if (coordSysRecord) { + coordSysRecordMap.removeKey(coordSysRecord.model.uid); + var controller = coordSysRecord.controller; + controller && controller.dispose(); + } + } + + function createCoordSysRecord(api, coordSysModel) { + // These init props will never change after record created. + var coordSysRecord = { + model: coordSysModel, + containsPoint: curry(containsPoint, coordSysModel), + dispatchAction: curry(dispatchAction$1, api), + dataZoomInfoMap: null, + controller: null + }; // Must not do anything depends on coordSysRecord outside the event handler here, + // because coordSysRecord not completed yet. + + var controller = coordSysRecord.controller = new RoamController(api.getZr()); + each(['pan', 'zoom', 'scrollMove'], function (eventName) { + controller.on(eventName, function (event) { + var batch = []; + coordSysRecord.dataZoomInfoMap.each(function (dzInfo) { + // Check whether the behaviors (zoomOnMouseWheel, moveOnMouseMove, + // moveOnMouseWheel, ...) enabled. + if (!event.isAvailableBehavior(dzInfo.model.option)) { + return; + } + + var method = (dzInfo.getRange || {})[eventName]; + var range = method && method(dzInfo.dzReferCoordSysInfo, coordSysRecord.model.mainType, coordSysRecord.controller, event); + !dzInfo.model.get('disabled', true) && range && batch.push({ + dataZoomId: dzInfo.model.id, + start: range[0], + end: range[1] + }); + }); + batch.length && coordSysRecord.dispatchAction(batch); + }); + }); + return coordSysRecord; + } + /** + * This action will be throttled. + */ + + + function dispatchAction$1(api, batch) { + if (!api.isDisposed()) { + api.dispatchAction({ + type: 'dataZoom', + animation: { + easing: 'cubicOut', + duration: 100 + }, + batch: batch + }); + } + } + + function containsPoint(coordSysModel, e, x, y) { + return coordSysModel.coordinateSystem.containPoint([x, y]); + } + /** + * Merge roamController settings when multiple dataZooms share one roamController. + */ + + + function mergeControllerParams(dataZoomInfoMap) { + var controlType; // DO NOT use reserved word (true, false, undefined) as key literally. Even if encapsulated + // as string, it is probably revert to reserved word by compress tool. See #7411. + + var prefix = 'type_'; + var typePriority = { + 'type_true': 2, + 'type_move': 1, + 'type_false': 0, + 'type_undefined': -1 + }; + var preventDefaultMouseMove = true; + dataZoomInfoMap.each(function (dataZoomInfo) { + var dataZoomModel = dataZoomInfo.model; + var oneType = dataZoomModel.get('disabled', true) ? false : dataZoomModel.get('zoomLock', true) ? 'move' : true; + + if (typePriority[prefix + oneType] > typePriority[prefix + controlType]) { + controlType = oneType; + } // Prevent default move event by default. If one false, do not prevent. Otherwise + // users may be confused why it does not work when multiple insideZooms exist. + + + preventDefaultMouseMove = preventDefaultMouseMove && dataZoomModel.get('preventDefaultMouseMove', true); + }); + return { + controlType: controlType, + opt: { + // RoamController will enable all of these functionalities, + // and the final behavior is determined by its event listener + // provided by each inside zoom. + zoomOnMouseWheel: true, + moveOnMouseMove: true, + moveOnMouseWheel: true, + preventDefaultMouseMove: !!preventDefaultMouseMove + } + }; + } + + function installDataZoomRoamProcessor(registers) { + registers.registerProcessor(registers.PRIORITY.PROCESSOR.FILTER, function (ecModel, api) { + var apiInner = inner$k(api); + var coordSysRecordMap = apiInner.coordSysRecordMap || (apiInner.coordSysRecordMap = createHashMap()); + coordSysRecordMap.each(function (coordSysRecord) { + // `coordSysRecordMap` always exists (becuase it hold the `roam controller`, which should + // better not re-create each time), but clear `dataZoomInfoMap` each round of the workflow. + coordSysRecord.dataZoomInfoMap = null; + }); + ecModel.eachComponent({ + mainType: 'dataZoom', + subType: 'inside' + }, function (dataZoomModel) { + var dzReferCoordSysWrap = collectReferCoordSysModelInfo(dataZoomModel); + each(dzReferCoordSysWrap.infoList, function (dzCoordSysInfo) { + var coordSysUid = dzCoordSysInfo.model.uid; + var coordSysRecord = coordSysRecordMap.get(coordSysUid) || coordSysRecordMap.set(coordSysUid, createCoordSysRecord(api, dzCoordSysInfo.model)); + var dataZoomInfoMap = coordSysRecord.dataZoomInfoMap || (coordSysRecord.dataZoomInfoMap = createHashMap()); // Notice these props might be changed each time for a single dataZoomModel. + + dataZoomInfoMap.set(dataZoomModel.uid, { + dzReferCoordSysInfo: dzCoordSysInfo, + model: dataZoomModel, + getRange: null + }); + }); + }); // (1) Merge dataZoom settings for each coord sys and set to the roam controller. + // (2) Clear coord sys if not refered by any dataZoom. + + coordSysRecordMap.each(function (coordSysRecord) { + var controller = coordSysRecord.controller; + var firstDzInfo; + var dataZoomInfoMap = coordSysRecord.dataZoomInfoMap; + + if (dataZoomInfoMap) { + var firstDzKey = dataZoomInfoMap.keys()[0]; + + if (firstDzKey != null) { + firstDzInfo = dataZoomInfoMap.get(firstDzKey); + } + } + + if (!firstDzInfo) { + disposeCoordSysRecord(coordSysRecordMap, coordSysRecord); + return; + } + + var controllerParams = mergeControllerParams(dataZoomInfoMap); + controller.enable(controllerParams.controlType, controllerParams.opt); + controller.setPointerChecker(coordSysRecord.containsPoint); + createOrUpdate(coordSysRecord, 'dispatchAction', firstDzInfo.model.get('throttle', true), 'fixRate'); + }); + }); + } + + var InsideZoomView = + /** @class */ + function (_super) { + __extends(InsideZoomView, _super); + + function InsideZoomView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'dataZoom.inside'; + return _this; + } + + InsideZoomView.prototype.render = function (dataZoomModel, ecModel, api) { + _super.prototype.render.apply(this, arguments); + + if (dataZoomModel.noTarget()) { + this._clear(); + + return; + } // Hence the `throttle` util ensures to preserve command order, + // here simply updating range all the time will not cause missing + // any of the the roam change. + + + this.range = dataZoomModel.getPercentRange(); // Reset controllers. + + setViewInfoToCoordSysRecord(api, dataZoomModel, { + pan: bind(getRangeHandlers.pan, this), + zoom: bind(getRangeHandlers.zoom, this), + scrollMove: bind(getRangeHandlers.scrollMove, this) + }); + }; + + InsideZoomView.prototype.dispose = function () { + this._clear(); + + _super.prototype.dispose.apply(this, arguments); + }; + + InsideZoomView.prototype._clear = function () { + disposeCoordSysRecordIfNeeded(this.api, this.dataZoomModel); + this.range = null; + }; + + InsideZoomView.type = 'dataZoom.inside'; + return InsideZoomView; + }(DataZoomView); + + var getRangeHandlers = { + zoom: function (coordSysInfo, coordSysMainType, controller, e) { + var lastRange = this.range; + var range = lastRange.slice(); // Calculate transform by the first axis. + + var axisModel = coordSysInfo.axisModels[0]; + + if (!axisModel) { + return; + } + + var directionInfo = getDirectionInfo[coordSysMainType](null, [e.originX, e.originY], axisModel, controller, coordSysInfo); + var percentPoint = (directionInfo.signal > 0 ? directionInfo.pixelStart + directionInfo.pixelLength - directionInfo.pixel : directionInfo.pixel - directionInfo.pixelStart) / directionInfo.pixelLength * (range[1] - range[0]) + range[0]; + var scale = Math.max(1 / e.scale, 0); + range[0] = (range[0] - percentPoint) * scale + percentPoint; + range[1] = (range[1] - percentPoint) * scale + percentPoint; // Restrict range. + + var minMaxSpan = this.dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan(); + sliderMove(0, range, [0, 100], 0, minMaxSpan.minSpan, minMaxSpan.maxSpan); + this.range = range; + + if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) { + return range; + } + }, + pan: makeMover(function (range, axisModel, coordSysInfo, coordSysMainType, controller, e) { + var directionInfo = getDirectionInfo[coordSysMainType]([e.oldX, e.oldY], [e.newX, e.newY], axisModel, controller, coordSysInfo); + return directionInfo.signal * (range[1] - range[0]) * directionInfo.pixel / directionInfo.pixelLength; + }), + scrollMove: makeMover(function (range, axisModel, coordSysInfo, coordSysMainType, controller, e) { + var directionInfo = getDirectionInfo[coordSysMainType]([0, 0], [e.scrollDelta, e.scrollDelta], axisModel, controller, coordSysInfo); + return directionInfo.signal * (range[1] - range[0]) * e.scrollDelta; + }) + }; + + function makeMover(getPercentDelta) { + return function (coordSysInfo, coordSysMainType, controller, e) { + var lastRange = this.range; + var range = lastRange.slice(); // Calculate transform by the first axis. + + var axisModel = coordSysInfo.axisModels[0]; + + if (!axisModel) { + return; + } + + var percentDelta = getPercentDelta(range, axisModel, coordSysInfo, coordSysMainType, controller, e); + sliderMove(percentDelta, range, [0, 100], 'all'); + this.range = range; + + if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) { + return range; + } + }; + } + + var getDirectionInfo = { + grid: function (oldPoint, newPoint, axisModel, controller, coordSysInfo) { + var axis = axisModel.axis; + var ret = {}; + var rect = coordSysInfo.model.coordinateSystem.getRect(); + oldPoint = oldPoint || [0, 0]; + + if (axis.dim === 'x') { + ret.pixel = newPoint[0] - oldPoint[0]; + ret.pixelLength = rect.width; + ret.pixelStart = rect.x; + ret.signal = axis.inverse ? 1 : -1; + } else { + // axis.dim === 'y' + ret.pixel = newPoint[1] - oldPoint[1]; + ret.pixelLength = rect.height; + ret.pixelStart = rect.y; + ret.signal = axis.inverse ? -1 : 1; + } + + return ret; + }, + polar: function (oldPoint, newPoint, axisModel, controller, coordSysInfo) { + var axis = axisModel.axis; + var ret = {}; + var polar = coordSysInfo.model.coordinateSystem; + var radiusExtent = polar.getRadiusAxis().getExtent(); + var angleExtent = polar.getAngleAxis().getExtent(); + oldPoint = oldPoint ? polar.pointToCoord(oldPoint) : [0, 0]; + newPoint = polar.pointToCoord(newPoint); + + if (axisModel.mainType === 'radiusAxis') { + ret.pixel = newPoint[0] - oldPoint[0]; // ret.pixelLength = Math.abs(radiusExtent[1] - radiusExtent[0]); + // ret.pixelStart = Math.min(radiusExtent[0], radiusExtent[1]); + + ret.pixelLength = radiusExtent[1] - radiusExtent[0]; + ret.pixelStart = radiusExtent[0]; + ret.signal = axis.inverse ? 1 : -1; + } else { + // 'angleAxis' + ret.pixel = newPoint[1] - oldPoint[1]; // ret.pixelLength = Math.abs(angleExtent[1] - angleExtent[0]); + // ret.pixelStart = Math.min(angleExtent[0], angleExtent[1]); + + ret.pixelLength = angleExtent[1] - angleExtent[0]; + ret.pixelStart = angleExtent[0]; + ret.signal = axis.inverse ? -1 : 1; + } + + return ret; + }, + singleAxis: function (oldPoint, newPoint, axisModel, controller, coordSysInfo) { + var axis = axisModel.axis; + var rect = coordSysInfo.model.coordinateSystem.getRect(); + var ret = {}; + oldPoint = oldPoint || [0, 0]; + + if (axis.orient === 'horizontal') { + ret.pixel = newPoint[0] - oldPoint[0]; + ret.pixelLength = rect.width; + ret.pixelStart = rect.x; + ret.signal = axis.inverse ? 1 : -1; + } else { + // 'vertical' + ret.pixel = newPoint[1] - oldPoint[1]; + ret.pixelLength = rect.height; + ret.pixelStart = rect.y; + ret.signal = axis.inverse ? -1 : 1; + } + + return ret; + } + }; + + function install$K(registers) { + installCommon(registers); + registers.registerComponentModel(InsideZoomModel); + registers.registerComponentView(InsideZoomView); + installDataZoomRoamProcessor(registers); + } + + var SliderZoomModel = + /** @class */ + function (_super) { + __extends(SliderZoomModel, _super); + + function SliderZoomModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = SliderZoomModel.type; + return _this; + } + + SliderZoomModel.type = 'dataZoom.slider'; + SliderZoomModel.layoutMode = 'box'; + SliderZoomModel.defaultOption = inheritDefaultOption(DataZoomModel.defaultOption, { + show: true, + // deault value can only be drived in view stage. + right: 'ph', + top: 'ph', + width: 'ph', + height: 'ph', + left: null, + bottom: null, + borderColor: '#d2dbee', + borderRadius: 3, + backgroundColor: 'rgba(47,69,84,0)', + // dataBackgroundColor: '#ddd', + dataBackground: { + lineStyle: { + color: '#d2dbee', + width: 0.5 + }, + areaStyle: { + color: '#d2dbee', + opacity: 0.2 + } + }, + selectedDataBackground: { + lineStyle: { + color: '#8fb0f7', + width: 0.5 + }, + areaStyle: { + color: '#8fb0f7', + opacity: 0.2 + } + }, + // Color of selected window. + fillerColor: 'rgba(135,175,274,0.2)', + handleIcon: 'path://M-9.35,34.56V42m0-40V9.5m-2,0h4a2,2,0,0,1,2,2v21a2,2,0,0,1-2,2h-4a2,2,0,0,1-2-2v-21A2,2,0,0,1-11.35,9.5Z', + // Percent of the slider height + handleSize: '100%', + handleStyle: { + color: '#fff', + borderColor: '#ACB8D1' + }, + moveHandleSize: 7, + moveHandleIcon: 'path://M-320.9-50L-320.9-50c18.1,0,27.1,9,27.1,27.1V85.7c0,18.1-9,27.1-27.1,27.1l0,0c-18.1,0-27.1-9-27.1-27.1V-22.9C-348-41-339-50-320.9-50z M-212.3-50L-212.3-50c18.1,0,27.1,9,27.1,27.1V85.7c0,18.1-9,27.1-27.1,27.1l0,0c-18.1,0-27.1-9-27.1-27.1V-22.9C-239.4-41-230.4-50-212.3-50z M-103.7-50L-103.7-50c18.1,0,27.1,9,27.1,27.1V85.7c0,18.1-9,27.1-27.1,27.1l0,0c-18.1,0-27.1-9-27.1-27.1V-22.9C-130.9-41-121.8-50-103.7-50z', + moveHandleStyle: { + color: '#D2DBEE', + opacity: 0.7 + }, + showDetail: true, + showDataShadow: 'auto', + realtime: true, + zoomLock: false, + textStyle: { + color: '#6E7079' + }, + brushSelect: true, + brushStyle: { + color: 'rgba(135,175,274,0.15)' + }, + emphasis: { + handleStyle: { + borderColor: '#8FB0F7' + }, + moveHandleStyle: { + color: '#8FB0F7' + } + } + }); + return SliderZoomModel; + }(DataZoomModel); + + var Rect$2 = Rect; // Constants + + var DEFAULT_LOCATION_EDGE_GAP = 7; + var DEFAULT_FRAME_BORDER_WIDTH = 1; + var DEFAULT_FILLER_SIZE = 30; + var DEFAULT_MOVE_HANDLE_SIZE = 7; + var HORIZONTAL = 'horizontal'; + var VERTICAL = 'vertical'; + var LABEL_GAP = 5; + var SHOW_DATA_SHADOW_SERIES_TYPE = ['line', 'bar', 'candlestick', 'scatter']; + var REALTIME_ANIMATION_CONFIG = { + easing: 'cubicOut', + duration: 100, + delay: 0 + }; + + var SliderZoomView = + /** @class */ + function (_super) { + __extends(SliderZoomView, _super); + + function SliderZoomView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = SliderZoomView.type; + _this._displayables = {}; + return _this; + } + + SliderZoomView.prototype.init = function (ecModel, api) { + this.api = api; // A unique handler for each dataZoom component + + this._onBrush = bind(this._onBrush, this); + this._onBrushEnd = bind(this._onBrushEnd, this); + }; + + SliderZoomView.prototype.render = function (dataZoomModel, ecModel, api, payload) { + _super.prototype.render.apply(this, arguments); + + createOrUpdate(this, '_dispatchZoomAction', dataZoomModel.get('throttle'), 'fixRate'); + this._orient = dataZoomModel.getOrient(); + + if (dataZoomModel.get('show') === false) { + this.group.removeAll(); + return; + } + + if (dataZoomModel.noTarget()) { + this._clear(); + + this.group.removeAll(); + return; + } // Notice: this._resetInterval() should not be executed when payload.type + // is 'dataZoom', origin this._range should be maintained, otherwise 'pan' + // or 'zoom' info will be missed because of 'throttle' of this.dispatchAction, + + + if (!payload || payload.type !== 'dataZoom' || payload.from !== this.uid) { + this._buildView(); + } + + this._updateView(); + }; + + SliderZoomView.prototype.dispose = function () { + this._clear(); + + _super.prototype.dispose.apply(this, arguments); + }; + + SliderZoomView.prototype._clear = function () { + clear(this, '_dispatchZoomAction'); + var zr = this.api.getZr(); + zr.off('mousemove', this._onBrush); + zr.off('mouseup', this._onBrushEnd); + }; + + SliderZoomView.prototype._buildView = function () { + var thisGroup = this.group; + thisGroup.removeAll(); + this._brushing = false; + this._displayables.brushRect = null; + + this._resetLocation(); + + this._resetInterval(); + + var barGroup = this._displayables.sliderGroup = new Group(); + + this._renderBackground(); + + this._renderHandle(); + + this._renderDataShadow(); + + thisGroup.add(barGroup); + + this._positionGroup(); + }; + + SliderZoomView.prototype._resetLocation = function () { + var dataZoomModel = this.dataZoomModel; + var api = this.api; + var showMoveHandle = dataZoomModel.get('brushSelect'); + var moveHandleSize = showMoveHandle ? DEFAULT_MOVE_HANDLE_SIZE : 0; // If some of x/y/width/height are not specified, + // auto-adapt according to target grid. + + var coordRect = this._findCoordRect(); + + var ecSize = { + width: api.getWidth(), + height: api.getHeight() + }; // Default align by coordinate system rect. + + var positionInfo = this._orient === HORIZONTAL ? { + // Why using 'right', because right should be used in vertical, + // and it is better to be consistent for dealing with position param merge. + right: ecSize.width - coordRect.x - coordRect.width, + top: ecSize.height - DEFAULT_FILLER_SIZE - DEFAULT_LOCATION_EDGE_GAP - moveHandleSize, + width: coordRect.width, + height: DEFAULT_FILLER_SIZE + } : { + right: DEFAULT_LOCATION_EDGE_GAP, + top: coordRect.y, + width: DEFAULT_FILLER_SIZE, + height: coordRect.height + }; // Do not write back to option and replace value 'ph', because + // the 'ph' value should be recalculated when resize. + + var layoutParams = getLayoutParams(dataZoomModel.option); // Replace the placeholder value. + + each(['right', 'top', 'width', 'height'], function (name) { + if (layoutParams[name] === 'ph') { + layoutParams[name] = positionInfo[name]; + } + }); + var layoutRect = getLayoutRect(layoutParams, ecSize); + this._location = { + x: layoutRect.x, + y: layoutRect.y + }; + this._size = [layoutRect.width, layoutRect.height]; + this._orient === VERTICAL && this._size.reverse(); + }; + + SliderZoomView.prototype._positionGroup = function () { + var thisGroup = this.group; + var location = this._location; + var orient = this._orient; // Just use the first axis to determine mapping. + + var targetAxisModel = this.dataZoomModel.getFirstTargetAxisModel(); + var inverse = targetAxisModel && targetAxisModel.get('inverse'); + var sliderGroup = this._displayables.sliderGroup; + var otherAxisInverse = (this._dataShadowInfo || {}).otherAxisInverse; // Transform barGroup. + + sliderGroup.attr(orient === HORIZONTAL && !inverse ? { + scaleY: otherAxisInverse ? 1 : -1, + scaleX: 1 + } : orient === HORIZONTAL && inverse ? { + scaleY: otherAxisInverse ? 1 : -1, + scaleX: -1 + } : orient === VERTICAL && !inverse ? { + scaleY: otherAxisInverse ? -1 : 1, + scaleX: 1, + rotation: Math.PI / 2 + } // Dont use Math.PI, considering shadow direction. + : { + scaleY: otherAxisInverse ? -1 : 1, + scaleX: -1, + rotation: Math.PI / 2 + }); // Position barGroup + + var rect = thisGroup.getBoundingRect([sliderGroup]); + thisGroup.x = location.x - rect.x; + thisGroup.y = location.y - rect.y; + thisGroup.markRedraw(); + }; + + SliderZoomView.prototype._getViewExtent = function () { + return [0, this._size[0]]; + }; + + SliderZoomView.prototype._renderBackground = function () { + var dataZoomModel = this.dataZoomModel; + var size = this._size; + var barGroup = this._displayables.sliderGroup; + var brushSelect = dataZoomModel.get('brushSelect'); + barGroup.add(new Rect$2({ + silent: true, + shape: { + x: 0, + y: 0, + width: size[0], + height: size[1] + }, + style: { + fill: dataZoomModel.get('backgroundColor') + }, + z2: -40 + })); // Click panel, over shadow, below handles. + + var clickPanel = new Rect$2({ + shape: { + x: 0, + y: 0, + width: size[0], + height: size[1] + }, + style: { + fill: 'transparent' + }, + z2: 0, + onclick: bind(this._onClickPanel, this) + }); + var zr = this.api.getZr(); + + if (brushSelect) { + clickPanel.on('mousedown', this._onBrushStart, this); + clickPanel.cursor = 'crosshair'; + zr.on('mousemove', this._onBrush); + zr.on('mouseup', this._onBrushEnd); + } else { + zr.off('mousemove', this._onBrush); + zr.off('mouseup', this._onBrushEnd); + } + + barGroup.add(clickPanel); + }; + + SliderZoomView.prototype._renderDataShadow = function () { + var info = this._dataShadowInfo = this._prepareDataShadowInfo(); + + this._displayables.dataShadowSegs = []; + + if (!info) { + return; + } + + var size = this._size; + var oldSize = this._shadowSize || []; + var seriesModel = info.series; + var data = seriesModel.getRawData(); + var otherDim = seriesModel.getShadowDim ? seriesModel.getShadowDim() // @see candlestick + : info.otherDim; + + if (otherDim == null) { + return; + } + + var polygonPts = this._shadowPolygonPts; + var polylinePts = this._shadowPolylinePts; // Not re-render if data doesn't change. + + if (data !== this._shadowData || otherDim !== this._shadowDim || size[0] !== oldSize[0] || size[1] !== oldSize[1]) { + var otherDataExtent_1 = data.getDataExtent(otherDim); // Nice extent. + + var otherOffset = (otherDataExtent_1[1] - otherDataExtent_1[0]) * 0.3; + otherDataExtent_1 = [otherDataExtent_1[0] - otherOffset, otherDataExtent_1[1] + otherOffset]; + var otherShadowExtent_1 = [0, size[1]]; + var thisShadowExtent = [0, size[0]]; + var areaPoints_1 = [[size[0], 0], [0, 0]]; + var linePoints_1 = []; + var step_1 = thisShadowExtent[1] / (data.count() - 1); + var thisCoord_1 = 0; // Optimize for large data shadow + + var stride_1 = Math.round(data.count() / size[0]); + var lastIsEmpty_1; + data.each([otherDim], function (value, index) { + if (stride_1 > 0 && index % stride_1) { + thisCoord_1 += step_1; + return; + } // FIXME + // Should consider axis.min/axis.max when drawing dataShadow. + // FIXME + // 应该使用统一的空判断?还是在list里进行空判断? + + + var isEmpty = value == null || isNaN(value) || value === ''; // See #4235. + + var otherCoord = isEmpty ? 0 : linearMap(value, otherDataExtent_1, otherShadowExtent_1, true); // Attempt to draw data shadow precisely when there are empty value. + + if (isEmpty && !lastIsEmpty_1 && index) { + areaPoints_1.push([areaPoints_1[areaPoints_1.length - 1][0], 0]); + linePoints_1.push([linePoints_1[linePoints_1.length - 1][0], 0]); + } else if (!isEmpty && lastIsEmpty_1) { + areaPoints_1.push([thisCoord_1, 0]); + linePoints_1.push([thisCoord_1, 0]); + } + + areaPoints_1.push([thisCoord_1, otherCoord]); + linePoints_1.push([thisCoord_1, otherCoord]); + thisCoord_1 += step_1; + lastIsEmpty_1 = isEmpty; + }); + polygonPts = this._shadowPolygonPts = areaPoints_1; + polylinePts = this._shadowPolylinePts = linePoints_1; + } + + this._shadowData = data; + this._shadowDim = otherDim; + this._shadowSize = [size[0], size[1]]; + var dataZoomModel = this.dataZoomModel; + + function createDataShadowGroup(isSelectedArea) { + var model = dataZoomModel.getModel(isSelectedArea ? 'selectedDataBackground' : 'dataBackground'); + var group = new Group(); + var polygon = new Polygon({ + shape: { + points: polygonPts + }, + segmentIgnoreThreshold: 1, + style: model.getModel('areaStyle').getAreaStyle(), + silent: true, + z2: -20 + }); + var polyline = new Polyline({ + shape: { + points: polylinePts + }, + segmentIgnoreThreshold: 1, + style: model.getModel('lineStyle').getLineStyle(), + silent: true, + z2: -19 + }); + group.add(polygon); + group.add(polyline); + return group; + } // let dataBackgroundModel = dataZoomModel.getModel('dataBackground'); + + + for (var i = 0; i < 3; i++) { + var group = createDataShadowGroup(i === 1); + + this._displayables.sliderGroup.add(group); + + this._displayables.dataShadowSegs.push(group); + } + }; + + SliderZoomView.prototype._prepareDataShadowInfo = function () { + var dataZoomModel = this.dataZoomModel; + var showDataShadow = dataZoomModel.get('showDataShadow'); + + if (showDataShadow === false) { + return; + } // Find a representative series. + + + var result; + var ecModel = this.ecModel; + dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) { + var seriesModels = dataZoomModel.getAxisProxy(axisDim, axisIndex).getTargetSeriesModels(); + each(seriesModels, function (seriesModel) { + if (result) { + return; + } + + if (showDataShadow !== true && indexOf(SHOW_DATA_SHADOW_SERIES_TYPE, seriesModel.get('type')) < 0) { + return; + } + + var thisAxis = ecModel.getComponent(getAxisMainType(axisDim), axisIndex).axis; + var otherDim = getOtherDim(axisDim); + var otherAxisInverse; + var coordSys = seriesModel.coordinateSystem; + + if (otherDim != null && coordSys.getOtherAxis) { + otherAxisInverse = coordSys.getOtherAxis(thisAxis).inverse; + } + + otherDim = seriesModel.getData().mapDimension(otherDim); + result = { + thisAxis: thisAxis, + series: seriesModel, + thisDim: axisDim, + otherDim: otherDim, + otherAxisInverse: otherAxisInverse + }; + }, this); + }, this); + return result; + }; + + SliderZoomView.prototype._renderHandle = function () { + var thisGroup = this.group; + var displayables = this._displayables; + var handles = displayables.handles = [null, null]; + var handleLabels = displayables.handleLabels = [null, null]; + var sliderGroup = this._displayables.sliderGroup; + var size = this._size; + var dataZoomModel = this.dataZoomModel; + var api = this.api; + var borderRadius = dataZoomModel.get('borderRadius') || 0; + var brushSelect = dataZoomModel.get('brushSelect'); + var filler = displayables.filler = new Rect$2({ + silent: brushSelect, + style: { + fill: dataZoomModel.get('fillerColor') + }, + textConfig: { + position: 'inside' + } + }); + sliderGroup.add(filler); // Frame border. + + sliderGroup.add(new Rect$2({ + silent: true, + subPixelOptimize: true, + shape: { + x: 0, + y: 0, + width: size[0], + height: size[1], + r: borderRadius + }, + style: { + stroke: dataZoomModel.get('dataBackgroundColor') // deprecated option + || dataZoomModel.get('borderColor'), + lineWidth: DEFAULT_FRAME_BORDER_WIDTH, + fill: 'rgba(0,0,0,0)' + } + })); // Left and right handle to resize + + each([0, 1], function (handleIndex) { + var iconStr = dataZoomModel.get('handleIcon'); + + if (!symbolBuildProxies[iconStr] && iconStr.indexOf('path://') < 0 && iconStr.indexOf('image://') < 0) { + // Compatitable with the old icon parsers. Which can use a path string without path:// + iconStr = 'path://' + iconStr; + + if ("development" !== 'production') { + deprecateLog('handleIcon now needs \'path://\' prefix when using a path string'); + } + } + + var path = createSymbol(iconStr, -1, 0, 2, 2, null, true); + path.attr({ + cursor: getCursor(this._orient), + draggable: true, + drift: bind(this._onDragMove, this, handleIndex), + ondragend: bind(this._onDragEnd, this), + onmouseover: bind(this._showDataInfo, this, true), + onmouseout: bind(this._showDataInfo, this, false), + z2: 5 + }); + var bRect = path.getBoundingRect(); + var handleSize = dataZoomModel.get('handleSize'); + this._handleHeight = parsePercent$1(handleSize, this._size[1]); + this._handleWidth = bRect.width / bRect.height * this._handleHeight; + path.setStyle(dataZoomModel.getModel('handleStyle').getItemStyle()); + path.style.strokeNoScale = true; + path.rectHover = true; + path.ensureState('emphasis').style = dataZoomModel.getModel(['emphasis', 'handleStyle']).getItemStyle(); + enableHoverEmphasis(path); + var handleColor = dataZoomModel.get('handleColor'); // deprecated option + // Compatitable with previous version + + if (handleColor != null) { + path.style.fill = handleColor; + } + + sliderGroup.add(handles[handleIndex] = path); + var textStyleModel = dataZoomModel.getModel('textStyle'); + thisGroup.add(handleLabels[handleIndex] = new ZRText({ + silent: true, + invisible: true, + style: createTextStyle(textStyleModel, { + x: 0, + y: 0, + text: '', + verticalAlign: 'middle', + align: 'center', + fill: textStyleModel.getTextColor(), + font: textStyleModel.getFont() + }), + z2: 10 + })); + }, this); // Handle to move. Only visible when brushSelect is set true. + + var actualMoveZone = filler; + + if (brushSelect) { + var moveHandleHeight = parsePercent$1(dataZoomModel.get('moveHandleSize'), size[1]); + var moveHandle_1 = displayables.moveHandle = new Rect({ + style: dataZoomModel.getModel('moveHandleStyle').getItemStyle(), + silent: true, + shape: { + r: [0, 0, 2, 2], + y: size[1] - 0.5, + height: moveHandleHeight + } + }); + var iconSize = moveHandleHeight * 0.8; + var moveHandleIcon = displayables.moveHandleIcon = createSymbol(dataZoomModel.get('moveHandleIcon'), -iconSize / 2, -iconSize / 2, iconSize, iconSize, '#fff', true); + moveHandleIcon.silent = true; + moveHandleIcon.y = size[1] + moveHandleHeight / 2 - 0.5; + moveHandle_1.ensureState('emphasis').style = dataZoomModel.getModel(['emphasis', 'moveHandleStyle']).getItemStyle(); + var moveZoneExpandSize = Math.min(size[1] / 2, Math.max(moveHandleHeight, 10)); + actualMoveZone = displayables.moveZone = new Rect({ + invisible: true, + shape: { + y: size[1] - moveZoneExpandSize, + height: moveHandleHeight + moveZoneExpandSize + } + }); + actualMoveZone.on('mouseover', function () { + api.enterEmphasis(moveHandle_1); + }).on('mouseout', function () { + api.leaveEmphasis(moveHandle_1); + }); + sliderGroup.add(moveHandle_1); + sliderGroup.add(moveHandleIcon); + sliderGroup.add(actualMoveZone); + } + + actualMoveZone.attr({ + draggable: true, + cursor: getCursor(this._orient), + drift: bind(this._onDragMove, this, 'all'), + ondragstart: bind(this._showDataInfo, this, true), + ondragend: bind(this._onDragEnd, this), + onmouseover: bind(this._showDataInfo, this, true), + onmouseout: bind(this._showDataInfo, this, false) + }); + }; + + SliderZoomView.prototype._resetInterval = function () { + var range = this._range = this.dataZoomModel.getPercentRange(); + + var viewExtent = this._getViewExtent(); + + this._handleEnds = [linearMap(range[0], [0, 100], viewExtent, true), linearMap(range[1], [0, 100], viewExtent, true)]; + }; + + SliderZoomView.prototype._updateInterval = function (handleIndex, delta) { + var dataZoomModel = this.dataZoomModel; + var handleEnds = this._handleEnds; + + var viewExtend = this._getViewExtent(); + + var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan(); + var percentExtent = [0, 100]; + sliderMove(delta, handleEnds, viewExtend, dataZoomModel.get('zoomLock') ? 'all' : handleIndex, minMaxSpan.minSpan != null ? linearMap(minMaxSpan.minSpan, percentExtent, viewExtend, true) : null, minMaxSpan.maxSpan != null ? linearMap(minMaxSpan.maxSpan, percentExtent, viewExtend, true) : null); + var lastRange = this._range; + var range = this._range = asc([linearMap(handleEnds[0], viewExtend, percentExtent, true), linearMap(handleEnds[1], viewExtend, percentExtent, true)]); + return !lastRange || lastRange[0] !== range[0] || lastRange[1] !== range[1]; + }; + + SliderZoomView.prototype._updateView = function (nonRealtime) { + var displaybles = this._displayables; + var handleEnds = this._handleEnds; + var handleInterval = asc(handleEnds.slice()); + var size = this._size; + each([0, 1], function (handleIndex) { + // Handles + var handle = displaybles.handles[handleIndex]; + var handleHeight = this._handleHeight; + handle.attr({ + scaleX: handleHeight / 2, + scaleY: handleHeight / 2, + // This is a trick, by adding an extra tiny offset to let the default handle's end point align to the drag window. + // NOTE: It may affect some custom shapes a bit. But we prefer to have better result by default. + x: handleEnds[handleIndex] + (handleIndex ? -1 : 1), + y: size[1] / 2 - handleHeight / 2 + }); + }, this); // Filler + + displaybles.filler.setShape({ + x: handleInterval[0], + y: 0, + width: handleInterval[1] - handleInterval[0], + height: size[1] + }); + var viewExtent = { + x: handleInterval[0], + width: handleInterval[1] - handleInterval[0] + }; // Move handle + + if (displaybles.moveHandle) { + displaybles.moveHandle.setShape(viewExtent); + displaybles.moveZone.setShape(viewExtent); // Force update path on the invisible object + + displaybles.moveZone.getBoundingRect(); + displaybles.moveHandleIcon && displaybles.moveHandleIcon.attr('x', viewExtent.x + viewExtent.width / 2); + } // update clip path of shadow. + + + var dataShadowSegs = displaybles.dataShadowSegs; + var segIntervals = [0, handleInterval[0], handleInterval[1], size[0]]; + + for (var i = 0; i < dataShadowSegs.length; i++) { + var segGroup = dataShadowSegs[i]; + var clipPath = segGroup.getClipPath(); + + if (!clipPath) { + clipPath = new Rect(); + segGroup.setClipPath(clipPath); + } + + clipPath.setShape({ + x: segIntervals[i], + y: 0, + width: segIntervals[i + 1] - segIntervals[i], + height: size[1] + }); + } + + this._updateDataInfo(nonRealtime); + }; + + SliderZoomView.prototype._updateDataInfo = function (nonRealtime) { + var dataZoomModel = this.dataZoomModel; + var displaybles = this._displayables; + var handleLabels = displaybles.handleLabels; + var orient = this._orient; + var labelTexts = ['', '']; // FIXME + // date型,支持formatter,autoformatter(ec2 date.getAutoFormatter) + + if (dataZoomModel.get('showDetail')) { + var axisProxy = dataZoomModel.findRepresentativeAxisProxy(); + + if (axisProxy) { + var axis = axisProxy.getAxisModel().axis; + var range = this._range; + var dataInterval = nonRealtime // See #4434, data and axis are not processed and reset yet in non-realtime mode. + ? axisProxy.calculateDataWindow({ + start: range[0], + end: range[1] + }).valueWindow : axisProxy.getDataValueWindow(); + labelTexts = [this._formatLabel(dataInterval[0], axis), this._formatLabel(dataInterval[1], axis)]; + } + } + + var orderedHandleEnds = asc(this._handleEnds.slice()); + setLabel.call(this, 0); + setLabel.call(this, 1); + + function setLabel(handleIndex) { + // Label + // Text should not transform by barGroup. + // Ignore handlers transform + var barTransform = getTransform(displaybles.handles[handleIndex].parent, this.group); + var direction = transformDirection(handleIndex === 0 ? 'right' : 'left', barTransform); + var offset = this._handleWidth / 2 + LABEL_GAP; + var textPoint = applyTransform$1([orderedHandleEnds[handleIndex] + (handleIndex === 0 ? -offset : offset), this._size[1] / 2], barTransform); + handleLabels[handleIndex].setStyle({ + x: textPoint[0], + y: textPoint[1], + verticalAlign: orient === HORIZONTAL ? 'middle' : direction, + align: orient === HORIZONTAL ? direction : 'center', + text: labelTexts[handleIndex] + }); + } + }; + + SliderZoomView.prototype._formatLabel = function (value, axis) { + var dataZoomModel = this.dataZoomModel; + var labelFormatter = dataZoomModel.get('labelFormatter'); + var labelPrecision = dataZoomModel.get('labelPrecision'); + + if (labelPrecision == null || labelPrecision === 'auto') { + labelPrecision = axis.getPixelPrecision(); + } + + var valueStr = value == null || isNaN(value) ? '' // FIXME Glue code + : axis.type === 'category' || axis.type === 'time' ? axis.scale.getLabel({ + value: Math.round(value) + }) // param of toFixed should less then 20. + : value.toFixed(Math.min(labelPrecision, 20)); + return isFunction(labelFormatter) ? labelFormatter(value, valueStr) : isString(labelFormatter) ? labelFormatter.replace('{value}', valueStr) : valueStr; + }; + /** + * @param showOrHide true: show, false: hide + */ + + + SliderZoomView.prototype._showDataInfo = function (showOrHide) { + // Always show when drgging. + showOrHide = this._dragging || showOrHide; + var displayables = this._displayables; + var handleLabels = displayables.handleLabels; + handleLabels[0].attr('invisible', !showOrHide); + handleLabels[1].attr('invisible', !showOrHide); // Highlight move handle + + displayables.moveHandle && this.api[showOrHide ? 'enterEmphasis' : 'leaveEmphasis'](displayables.moveHandle, 1); + }; + + SliderZoomView.prototype._onDragMove = function (handleIndex, dx, dy, event) { + this._dragging = true; // For mobile device, prevent screen slider on the button. + + stop(event.event); // Transform dx, dy to bar coordination. + + var barTransform = this._displayables.sliderGroup.getLocalTransform(); + + var vertex = applyTransform$1([dx, dy], barTransform, true); + + var changed = this._updateInterval(handleIndex, vertex[0]); + + var realtime = this.dataZoomModel.get('realtime'); + + this._updateView(!realtime); // Avoid dispatch dataZoom repeatly but range not changed, + // which cause bad visual effect when progressive enabled. + + + changed && realtime && this._dispatchZoomAction(true); + }; + + SliderZoomView.prototype._onDragEnd = function () { + this._dragging = false; + + this._showDataInfo(false); // While in realtime mode and stream mode, dispatch action when + // drag end will cause the whole view rerender, which is unnecessary. + + + var realtime = this.dataZoomModel.get('realtime'); + !realtime && this._dispatchZoomAction(false); + }; + + SliderZoomView.prototype._onClickPanel = function (e) { + var size = this._size; + + var localPoint = this._displayables.sliderGroup.transformCoordToLocal(e.offsetX, e.offsetY); + + if (localPoint[0] < 0 || localPoint[0] > size[0] || localPoint[1] < 0 || localPoint[1] > size[1]) { + return; + } + + var handleEnds = this._handleEnds; + var center = (handleEnds[0] + handleEnds[1]) / 2; + + var changed = this._updateInterval('all', localPoint[0] - center); + + this._updateView(); + + changed && this._dispatchZoomAction(false); + }; + + SliderZoomView.prototype._onBrushStart = function (e) { + var x = e.offsetX; + var y = e.offsetY; + this._brushStart = new Point(x, y); + this._brushing = true; + this._brushStartTime = +new Date(); // this._updateBrushRect(x, y); + }; + + SliderZoomView.prototype._onBrushEnd = function (e) { + if (!this._brushing) { + return; + } + + var brushRect = this._displayables.brushRect; + this._brushing = false; + + if (!brushRect) { + return; + } + + brushRect.attr('ignore', true); + var brushShape = brushRect.shape; + var brushEndTime = +new Date(); // console.log(brushEndTime - this._brushStartTime); + + if (brushEndTime - this._brushStartTime < 200 && Math.abs(brushShape.width) < 5) { + // Will treat it as a click + return; + } + + var viewExtend = this._getViewExtent(); + + var percentExtent = [0, 100]; + this._range = asc([linearMap(brushShape.x, viewExtend, percentExtent, true), linearMap(brushShape.x + brushShape.width, viewExtend, percentExtent, true)]); + this._handleEnds = [brushShape.x, brushShape.x + brushShape.width]; + + this._updateView(); + + this._dispatchZoomAction(false); + }; + + SliderZoomView.prototype._onBrush = function (e) { + if (this._brushing) { + // For mobile device, prevent screen slider on the button. + stop(e.event); + + this._updateBrushRect(e.offsetX, e.offsetY); + } + }; + + SliderZoomView.prototype._updateBrushRect = function (mouseX, mouseY) { + var displayables = this._displayables; + var dataZoomModel = this.dataZoomModel; + var brushRect = displayables.brushRect; + + if (!brushRect) { + brushRect = displayables.brushRect = new Rect$2({ + silent: true, + style: dataZoomModel.getModel('brushStyle').getItemStyle() + }); + displayables.sliderGroup.add(brushRect); + } + + brushRect.attr('ignore', false); + var brushStart = this._brushStart; + var sliderGroup = this._displayables.sliderGroup; + var endPoint = sliderGroup.transformCoordToLocal(mouseX, mouseY); + var startPoint = sliderGroup.transformCoordToLocal(brushStart.x, brushStart.y); + var size = this._size; + endPoint[0] = Math.max(Math.min(size[0], endPoint[0]), 0); + brushRect.setShape({ + x: startPoint[0], + y: 0, + width: endPoint[0] - startPoint[0], + height: size[1] + }); + }; + /** + * This action will be throttled. + */ + + + SliderZoomView.prototype._dispatchZoomAction = function (realtime) { + var range = this._range; + this.api.dispatchAction({ + type: 'dataZoom', + from: this.uid, + dataZoomId: this.dataZoomModel.id, + animation: realtime ? REALTIME_ANIMATION_CONFIG : null, + start: range[0], + end: range[1] + }); + }; + + SliderZoomView.prototype._findCoordRect = function () { + // Find the grid coresponding to the first axis referred by dataZoom. + var rect; + var coordSysInfoList = collectReferCoordSysModelInfo(this.dataZoomModel).infoList; + + if (!rect && coordSysInfoList.length) { + var coordSys = coordSysInfoList[0].model.coordinateSystem; + rect = coordSys.getRect && coordSys.getRect(); + } + + if (!rect) { + var width = this.api.getWidth(); + var height = this.api.getHeight(); + rect = { + x: width * 0.2, + y: height * 0.2, + width: width * 0.6, + height: height * 0.6 + }; + } + + return rect; + }; + + SliderZoomView.type = 'dataZoom.slider'; + return SliderZoomView; + }(DataZoomView); + + function getOtherDim(thisDim) { + // FIXME + // 这个逻辑和getOtherAxis里一致,但是写在这里是否不好 + var map = { + x: 'y', + y: 'x', + radius: 'angle', + angle: 'radius' + }; + return map[thisDim]; + } + + function getCursor(orient) { + return orient === 'vertical' ? 'ns-resize' : 'ew-resize'; + } + + function install$L(registers) { + registers.registerComponentModel(SliderZoomModel); + registers.registerComponentView(SliderZoomView); + installCommon(registers); + } + + function install$M(registers) { + use(install$K); + use(install$L); // Do not install './dataZoomSelect', + // since it only work for toolbox dataZoom. + } + + var visualDefault = { + /** + * @public + */ + get: function (visualType, key, isCategory) { + var value = clone((defaultOption$1[visualType] || {})[key]); + return isCategory ? isArray(value) ? value[value.length - 1] : value : value; + } + }; + var defaultOption$1 = { + color: { + active: ['#006edd', '#e0ffff'], + inactive: ['rgba(0,0,0,0)'] + }, + colorHue: { + active: [0, 360], + inactive: [0, 0] + }, + colorSaturation: { + active: [0.3, 1], + inactive: [0, 0] + }, + colorLightness: { + active: [0.9, 0.5], + inactive: [0, 0] + }, + colorAlpha: { + active: [0.3, 1], + inactive: [0, 0] + }, + opacity: { + active: [0.3, 1], + inactive: [0, 0] + }, + symbol: { + active: ['circle', 'roundRect', 'diamond'], + inactive: ['none'] + }, + symbolSize: { + active: [10, 50], + inactive: [0, 0] + } + }; + + var mapVisual$1 = VisualMapping.mapVisual; + var eachVisual = VisualMapping.eachVisual; + var isArray$1 = isArray; + var each$d = each; + var asc$2 = asc; + var linearMap$1 = linearMap; + + var VisualMapModel = + /** @class */ + function (_super) { + __extends(VisualMapModel, _super); + + function VisualMapModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = VisualMapModel.type; + _this.stateList = ['inRange', 'outOfRange']; + _this.replacableOptionKeys = ['inRange', 'outOfRange', 'target', 'controller', 'color']; + _this.layoutMode = { + type: 'box', + ignoreSize: true + }; + /** + * [lowerBound, upperBound] + */ + + _this.dataBound = [-Infinity, Infinity]; + _this.targetVisuals = {}; + _this.controllerVisuals = {}; + return _this; + } + + VisualMapModel.prototype.init = function (option, parentModel, ecModel) { + this.mergeDefaultAndTheme(option, ecModel); + }; + /** + * @protected + */ + + + VisualMapModel.prototype.optionUpdated = function (newOption, isInit) { + var thisOption = this.option; + !isInit && replaceVisualOption(thisOption, newOption, this.replacableOptionKeys); + this.textStyleModel = this.getModel('textStyle'); + this.resetItemSize(); + this.completeVisualOption(); + }; + /** + * @protected + */ + + + VisualMapModel.prototype.resetVisual = function (supplementVisualOption) { + var stateList = this.stateList; + supplementVisualOption = bind(supplementVisualOption, this); + this.controllerVisuals = createVisualMappings(this.option.controller, stateList, supplementVisualOption); + this.targetVisuals = createVisualMappings(this.option.target, stateList, supplementVisualOption); + }; + /** + * @public + */ + + + VisualMapModel.prototype.getItemSymbol = function () { + return null; + }; + /** + * @protected + * @return {Array.} An array of series indices. + */ + + + VisualMapModel.prototype.getTargetSeriesIndices = function () { + var optionSeriesIndex = this.option.seriesIndex; + var seriesIndices = []; + + if (optionSeriesIndex == null || optionSeriesIndex === 'all') { + this.ecModel.eachSeries(function (seriesModel, index) { + seriesIndices.push(index); + }); + } else { + seriesIndices = normalizeToArray(optionSeriesIndex); + } + + return seriesIndices; + }; + /** + * @public + */ + + + VisualMapModel.prototype.eachTargetSeries = function (callback, context) { + each(this.getTargetSeriesIndices(), function (seriesIndex) { + var seriesModel = this.ecModel.getSeriesByIndex(seriesIndex); + + if (seriesModel) { + callback.call(context, seriesModel); + } + }, this); + }; + /** + * @pubilc + */ + + + VisualMapModel.prototype.isTargetSeries = function (seriesModel) { + var is = false; + this.eachTargetSeries(function (model) { + model === seriesModel && (is = true); + }); + return is; + }; + /** + * @example + * this.formatValueText(someVal); // format single numeric value to text. + * this.formatValueText(someVal, true); // format single category value to text. + * this.formatValueText([min, max]); // format numeric min-max to text. + * this.formatValueText([this.dataBound[0], max]); // using data lower bound. + * this.formatValueText([min, this.dataBound[1]]); // using data upper bound. + * + * @param value Real value, or this.dataBound[0 or 1]. + * @param isCategory Only available when value is number. + * @param edgeSymbols Open-close symbol when value is interval. + * @protected + */ + + + VisualMapModel.prototype.formatValueText = function (value, isCategory, edgeSymbols) { + var option = this.option; + var precision = option.precision; + var dataBound = this.dataBound; + var formatter = option.formatter; + var isMinMax; + edgeSymbols = edgeSymbols || ['<', '>']; + + if (isArray(value)) { + value = value.slice(); + isMinMax = true; + } + + var textValue = isCategory ? value // Value is string when isCategory + : isMinMax ? [toFixed(value[0]), toFixed(value[1])] : toFixed(value); + + if (isString(formatter)) { + return formatter.replace('{value}', isMinMax ? textValue[0] : textValue).replace('{value2}', isMinMax ? textValue[1] : textValue); + } else if (isFunction(formatter)) { + return isMinMax ? formatter(value[0], value[1]) : formatter(value); + } + + if (isMinMax) { + if (value[0] === dataBound[0]) { + return edgeSymbols[0] + ' ' + textValue[1]; + } else if (value[1] === dataBound[1]) { + return edgeSymbols[1] + ' ' + textValue[0]; + } else { + return textValue[0] + ' - ' + textValue[1]; + } + } else { + // Format single value (includes category case). + return textValue; + } + + function toFixed(val) { + return val === dataBound[0] ? 'min' : val === dataBound[1] ? 'max' : (+val).toFixed(Math.min(precision, 20)); + } + }; + /** + * @protected + */ + + + VisualMapModel.prototype.resetExtent = function () { + var thisOption = this.option; // Can not calculate data extent by data here. + // Because series and data may be modified in processing stage. + // So we do not support the feature "auto min/max". + + var extent = asc$2([thisOption.min, thisOption.max]); + this._dataExtent = extent; + }; + /** + * PENDING: + * delete this method if no outer usage. + * + * Return Concrete dimention. If return null/undefined, no dimension used. + */ + // getDataDimension(data: SeriesData) { + // const optDim = this.option.dimension; + // if (optDim != null) { + // return data.getDimension(optDim); + // } + // const dimNames = data.dimensions; + // for (let i = dimNames.length - 1; i >= 0; i--) { + // const dimName = dimNames[i]; + // const dimInfo = data.getDimensionInfo(dimName); + // if (!dimInfo.isCalculationCoord) { + // return dimName; + // } + // } + // } + + + VisualMapModel.prototype.getDataDimensionIndex = function (data) { + var optDim = this.option.dimension; + + if (optDim != null) { + return data.getDimensionIndex(optDim); + } + + var dimNames = data.dimensions; + + for (var i = dimNames.length - 1; i >= 0; i--) { + var dimName = dimNames[i]; + var dimInfo = data.getDimensionInfo(dimName); + + if (!dimInfo.isCalculationCoord) { + return dimInfo.storeDimIndex; + } + } + }; + + VisualMapModel.prototype.getExtent = function () { + return this._dataExtent.slice(); + }; + + VisualMapModel.prototype.completeVisualOption = function () { + var ecModel = this.ecModel; + var thisOption = this.option; + var base = { + inRange: thisOption.inRange, + outOfRange: thisOption.outOfRange + }; + var target = thisOption.target || (thisOption.target = {}); + var controller = thisOption.controller || (thisOption.controller = {}); + merge(target, base); // Do not override + + merge(controller, base); // Do not override + + var isCategory = this.isCategory(); + completeSingle.call(this, target); + completeSingle.call(this, controller); + completeInactive.call(this, target, 'inRange', 'outOfRange'); // completeInactive.call(this, target, 'outOfRange', 'inRange'); + + completeController.call(this, controller); + + function completeSingle(base) { + // Compatible with ec2 dataRange.color. + // The mapping order of dataRange.color is: [high value, ..., low value] + // whereas inRange.color and outOfRange.color is [low value, ..., high value] + // Notice: ec2 has no inverse. + if (isArray$1(thisOption.color) // If there has been inRange: {symbol: ...}, adding color is a mistake. + // So adding color only when no inRange defined. + && !base.inRange) { + base.inRange = { + color: thisOption.color.slice().reverse() + }; + } // Compatible with previous logic, always give a defautl color, otherwise + // simple config with no inRange and outOfRange will not work. + // Originally we use visualMap.color as the default color, but setOption at + // the second time the default color will be erased. So we change to use + // constant DEFAULT_COLOR. + // If user do not want the default color, set inRange: {color: null}. + + + base.inRange = base.inRange || { + color: ecModel.get('gradientColor') + }; + } + + function completeInactive(base, stateExist, stateAbsent) { + var optExist = base[stateExist]; + var optAbsent = base[stateAbsent]; + + if (optExist && !optAbsent) { + optAbsent = base[stateAbsent] = {}; + each$d(optExist, function (visualData, visualType) { + if (!VisualMapping.isValidType(visualType)) { + return; + } + + var defa = visualDefault.get(visualType, 'inactive', isCategory); + + if (defa != null) { + optAbsent[visualType] = defa; // Compatibable with ec2: + // Only inactive color to rgba(0,0,0,0) can not + // make label transparent, so use opacity also. + + if (visualType === 'color' && !optAbsent.hasOwnProperty('opacity') && !optAbsent.hasOwnProperty('colorAlpha')) { + optAbsent.opacity = [0, 0]; + } + } + }); + } + } + + function completeController(controller) { + var symbolExists = (controller.inRange || {}).symbol || (controller.outOfRange || {}).symbol; + var symbolSizeExists = (controller.inRange || {}).symbolSize || (controller.outOfRange || {}).symbolSize; + var inactiveColor = this.get('inactiveColor'); + var itemSymbol = this.getItemSymbol(); + var defaultSymbol = itemSymbol || 'roundRect'; + each$d(this.stateList, function (state) { + var itemSize = this.itemSize; + var visuals = controller[state]; // Set inactive color for controller if no other color + // attr (like colorAlpha) specified. + + if (!visuals) { + visuals = controller[state] = { + color: isCategory ? inactiveColor : [inactiveColor] + }; + } // Consistent symbol and symbolSize if not specified. + + + if (visuals.symbol == null) { + visuals.symbol = symbolExists && clone(symbolExists) || (isCategory ? defaultSymbol : [defaultSymbol]); + } + + if (visuals.symbolSize == null) { + visuals.symbolSize = symbolSizeExists && clone(symbolSizeExists) || (isCategory ? itemSize[0] : [itemSize[0], itemSize[0]]); + } // Filter none + + + visuals.symbol = mapVisual$1(visuals.symbol, function (symbol) { + return symbol === 'none' ? defaultSymbol : symbol; + }); // Normalize symbolSize + + var symbolSize = visuals.symbolSize; + + if (symbolSize != null) { + var max_1 = -Infinity; // symbolSize can be object when categories defined. + + eachVisual(symbolSize, function (value) { + value > max_1 && (max_1 = value); + }); + visuals.symbolSize = mapVisual$1(symbolSize, function (value) { + return linearMap$1(value, [0, max_1], [0, itemSize[0]], true); + }); + } + }, this); + } + }; + + VisualMapModel.prototype.resetItemSize = function () { + this.itemSize = [parseFloat(this.get('itemWidth')), parseFloat(this.get('itemHeight'))]; + }; + + VisualMapModel.prototype.isCategory = function () { + return !!this.option.categories; + }; + /** + * @public + * @abstract + */ + + + VisualMapModel.prototype.setSelected = function (selected) {}; + + VisualMapModel.prototype.getSelected = function () { + return null; + }; + /** + * @public + * @abstract + */ + + + VisualMapModel.prototype.getValueState = function (value) { + return null; + }; + /** + * FIXME + * Do not publish to thirt-part-dev temporarily + * util the interface is stable. (Should it return + * a function but not visual meta?) + * + * @pubilc + * @abstract + * @param getColorVisual + * params: value, valueState + * return: color + * @return {Object} visualMeta + * should includes {stops, outerColors} + * outerColor means [colorBeyondMinValue, colorBeyondMaxValue] + */ + + + VisualMapModel.prototype.getVisualMeta = function (getColorVisual) { + return null; + }; + + VisualMapModel.type = 'visualMap'; + VisualMapModel.dependencies = ['series']; + VisualMapModel.defaultOption = { + show: true, + // zlevel: 0, + z: 4, + seriesIndex: 'all', + min: 0, + max: 200, + left: 0, + right: null, + top: null, + bottom: 0, + itemWidth: null, + itemHeight: null, + inverse: false, + orient: 'vertical', + backgroundColor: 'rgba(0,0,0,0)', + borderColor: '#ccc', + contentColor: '#5793f3', + inactiveColor: '#aaa', + borderWidth: 0, + padding: 5, + // 接受数组分别设定上右下左边距,同css + textGap: 10, + precision: 0, + textStyle: { + color: '#333' // 值域文字颜色 + + } + }; + return VisualMapModel; + }(ComponentModel); + + var DEFAULT_BAR_BOUND = [20, 140]; + + var ContinuousModel = + /** @class */ + function (_super) { + __extends(ContinuousModel, _super); + + function ContinuousModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ContinuousModel.type; + return _this; + } + /** + * @override + */ + + + ContinuousModel.prototype.optionUpdated = function (newOption, isInit) { + _super.prototype.optionUpdated.apply(this, arguments); + + this.resetExtent(); + this.resetVisual(function (mappingOption) { + mappingOption.mappingMethod = 'linear'; + mappingOption.dataExtent = this.getExtent(); + }); + + this._resetRange(); + }; + /** + * @protected + * @override + */ + + + ContinuousModel.prototype.resetItemSize = function () { + _super.prototype.resetItemSize.apply(this, arguments); + + var itemSize = this.itemSize; + (itemSize[0] == null || isNaN(itemSize[0])) && (itemSize[0] = DEFAULT_BAR_BOUND[0]); + (itemSize[1] == null || isNaN(itemSize[1])) && (itemSize[1] = DEFAULT_BAR_BOUND[1]); + }; + /** + * @private + */ + + + ContinuousModel.prototype._resetRange = function () { + var dataExtent = this.getExtent(); + var range = this.option.range; + + if (!range || range.auto) { + // `range` should always be array (so we dont use other + // value like 'auto') for user-friend. (consider getOption). + dataExtent.auto = 1; + this.option.range = dataExtent; + } else if (isArray(range)) { + if (range[0] > range[1]) { + range.reverse(); + } + + range[0] = Math.max(range[0], dataExtent[0]); + range[1] = Math.min(range[1], dataExtent[1]); + } + }; + /** + * @protected + * @override + */ + + + ContinuousModel.prototype.completeVisualOption = function () { + _super.prototype.completeVisualOption.apply(this, arguments); + + each(this.stateList, function (state) { + var symbolSize = this.option.controller[state].symbolSize; + + if (symbolSize && symbolSize[0] !== symbolSize[1]) { + symbolSize[0] = symbolSize[1] / 3; // For good looking. + } + }, this); + }; + /** + * @override + */ + + + ContinuousModel.prototype.setSelected = function (selected) { + this.option.range = selected.slice(); + + this._resetRange(); + }; + /** + * @public + */ + + + ContinuousModel.prototype.getSelected = function () { + var dataExtent = this.getExtent(); + var dataInterval = asc((this.get('range') || []).slice()); // Clamp + + dataInterval[0] > dataExtent[1] && (dataInterval[0] = dataExtent[1]); + dataInterval[1] > dataExtent[1] && (dataInterval[1] = dataExtent[1]); + dataInterval[0] < dataExtent[0] && (dataInterval[0] = dataExtent[0]); + dataInterval[1] < dataExtent[0] && (dataInterval[1] = dataExtent[0]); + return dataInterval; + }; + /** + * @override + */ + + + ContinuousModel.prototype.getValueState = function (value) { + var range = this.option.range; + var dataExtent = this.getExtent(); // When range[0] === dataExtent[0], any value larger than dataExtent[0] maps to 'inRange'. + // range[1] is processed likewise. + + return (range[0] <= dataExtent[0] || range[0] <= value) && (range[1] >= dataExtent[1] || value <= range[1]) ? 'inRange' : 'outOfRange'; + }; + + ContinuousModel.prototype.findTargetDataIndices = function (range) { + var result = []; + this.eachTargetSeries(function (seriesModel) { + var dataIndices = []; + var data = seriesModel.getData(); + data.each(this.getDataDimensionIndex(data), function (value, dataIndex) { + range[0] <= value && value <= range[1] && dataIndices.push(dataIndex); + }, this); + result.push({ + seriesId: seriesModel.id, + dataIndex: dataIndices + }); + }, this); + return result; + }; + /** + * @implement + */ + + + ContinuousModel.prototype.getVisualMeta = function (getColorVisual) { + var oVals = getColorStopValues(this, 'outOfRange', this.getExtent()); + var iVals = getColorStopValues(this, 'inRange', this.option.range.slice()); + var stops = []; + + function setStop(value, valueState) { + stops.push({ + value: value, + color: getColorVisual(value, valueState) + }); + } // Format to: outOfRange -- inRange -- outOfRange. + + + var iIdx = 0; + var oIdx = 0; + var iLen = iVals.length; + var oLen = oVals.length; + + for (; oIdx < oLen && (!iVals.length || oVals[oIdx] <= iVals[0]); oIdx++) { + // If oVal[oIdx] === iVals[iIdx], oVal[oIdx] should be ignored. + if (oVals[oIdx] < iVals[iIdx]) { + setStop(oVals[oIdx], 'outOfRange'); + } + } + + for (var first = 1; iIdx < iLen; iIdx++, first = 0) { + // If range is full, value beyond min, max will be clamped. + // make a singularity + first && stops.length && setStop(iVals[iIdx], 'outOfRange'); + setStop(iVals[iIdx], 'inRange'); + } + + for (var first = 1; oIdx < oLen; oIdx++) { + if (!iVals.length || iVals[iVals.length - 1] < oVals[oIdx]) { + // make a singularity + if (first) { + stops.length && setStop(stops[stops.length - 1].value, 'outOfRange'); + first = 0; + } + + setStop(oVals[oIdx], 'outOfRange'); + } + } + + var stopsLen = stops.length; + return { + stops: stops, + outerColors: [stopsLen ? stops[0].color : 'transparent', stopsLen ? stops[stopsLen - 1].color : 'transparent'] + }; + }; + + ContinuousModel.type = 'visualMap.continuous'; + ContinuousModel.defaultOption = inheritDefaultOption(VisualMapModel.defaultOption, { + align: 'auto', + calculable: false, + hoverLink: true, + realtime: true, + handleIcon: 'path://M-11.39,9.77h0a3.5,3.5,0,0,1-3.5,3.5h-22a3.5,3.5,0,0,1-3.5-3.5h0a3.5,3.5,0,0,1,3.5-3.5h22A3.5,3.5,0,0,1-11.39,9.77Z', + handleSize: '120%', + handleStyle: { + borderColor: '#fff', + borderWidth: 1 + }, + indicatorIcon: 'circle', + indicatorSize: '50%', + indicatorStyle: { + borderColor: '#fff', + borderWidth: 2, + shadowBlur: 2, + shadowOffsetX: 1, + shadowOffsetY: 1, + shadowColor: 'rgba(0,0,0,0.2)' + } // emphasis: { + // handleStyle: { + // shadowBlur: 3, + // shadowOffsetX: 1, + // shadowOffsetY: 1, + // shadowColor: 'rgba(0,0,0,0.2)' + // } + // } + + }); + return ContinuousModel; + }(VisualMapModel); + + function getColorStopValues(visualMapModel, valueState, dataExtent) { + if (dataExtent[0] === dataExtent[1]) { + return dataExtent.slice(); + } // When using colorHue mapping, it is not linear color any more. + // Moreover, canvas gradient seems not to be accurate linear. + // FIXME + // Should be arbitrary value 100? or based on pixel size? + + + var count = 200; + var step = (dataExtent[1] - dataExtent[0]) / count; + var value = dataExtent[0]; + var stopValues = []; + + for (var i = 0; i <= count && value < dataExtent[1]; i++) { + stopValues.push(value); + value += step; + } + + stopValues.push(dataExtent[1]); + return stopValues; + } + + var VisualMapView = + /** @class */ + function (_super) { + __extends(VisualMapView, _super); + + function VisualMapView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = VisualMapView.type; + _this.autoPositionValues = { + left: 1, + right: 1, + top: 1, + bottom: 1 + }; + return _this; + } + + VisualMapView.prototype.init = function (ecModel, api) { + this.ecModel = ecModel; + this.api = api; + }; + /** + * @protected + */ + + + VisualMapView.prototype.render = function (visualMapModel, ecModel, api, payload // TODO: TYPE + ) { + this.visualMapModel = visualMapModel; + + if (visualMapModel.get('show') === false) { + this.group.removeAll(); + return; + } + + this.doRender(visualMapModel, ecModel, api, payload); + }; + /** + * @protected + */ + + + VisualMapView.prototype.renderBackground = function (group) { + var visualMapModel = this.visualMapModel; + var padding = normalizeCssArray$1(visualMapModel.get('padding') || 0); + var rect = group.getBoundingRect(); + group.add(new Rect({ + z2: -1, + silent: true, + shape: { + x: rect.x - padding[3], + y: rect.y - padding[0], + width: rect.width + padding[3] + padding[1], + height: rect.height + padding[0] + padding[2] + }, + style: { + fill: visualMapModel.get('backgroundColor'), + stroke: visualMapModel.get('borderColor'), + lineWidth: visualMapModel.get('borderWidth') + } + })); + }; + /** + * @protected + * @param targetValue can be Infinity or -Infinity + * @param visualCluster Only can be 'color' 'opacity' 'symbol' 'symbolSize' + * @param opts + * @param opts.forceState Specify state, instead of using getValueState method. + * @param opts.convertOpacityToAlpha For color gradient in controller widget. + * @return {*} Visual value. + */ + + + VisualMapView.prototype.getControllerVisual = function (targetValue, visualCluster, opts) { + opts = opts || {}; + var forceState = opts.forceState; + var visualMapModel = this.visualMapModel; + var visualObj = {}; // Default values. + + if (visualCluster === 'color') { + var defaultColor = visualMapModel.get('contentColor'); + visualObj.color = defaultColor; + } + + function getter(key) { + return visualObj[key]; + } + + function setter(key, value) { + visualObj[key] = value; + } + + var mappings = visualMapModel.controllerVisuals[forceState || visualMapModel.getValueState(targetValue)]; + var visualTypes = VisualMapping.prepareVisualTypes(mappings); + each(visualTypes, function (type) { + var visualMapping = mappings[type]; + + if (opts.convertOpacityToAlpha && type === 'opacity') { + type = 'colorAlpha'; + visualMapping = mappings.__alphaForOpacity; + } + + if (VisualMapping.dependsOn(type, visualCluster)) { + visualMapping && visualMapping.applyVisual(targetValue, getter, setter); + } + }); + return visualObj[visualCluster]; + }; + + VisualMapView.prototype.positionGroup = function (group) { + var model = this.visualMapModel; + var api = this.api; + positionElement(group, model.getBoxLayoutParams(), { + width: api.getWidth(), + height: api.getHeight() + }); + }; + + VisualMapView.prototype.doRender = function (visualMapModel, ecModel, api, payload) {}; + + VisualMapView.type = 'visualMap'; + return VisualMapView; + }(ComponentView); + + var paramsSet = [['left', 'right', 'width'], ['top', 'bottom', 'height']]; + /** + * @param visualMapModel + * @param api + * @param itemSize always [short, long] + * @return {string} 'left' or 'right' or 'top' or 'bottom' + */ + + function getItemAlign(visualMapModel, api, itemSize) { + var modelOption = visualMapModel.option; + var itemAlign = modelOption.align; + + if (itemAlign != null && itemAlign !== 'auto') { + return itemAlign; + } // Auto decision align. + + + var ecSize = { + width: api.getWidth(), + height: api.getHeight() + }; + var realIndex = modelOption.orient === 'horizontal' ? 1 : 0; + var reals = paramsSet[realIndex]; + var fakeValue = [0, null, 10]; + var layoutInput = {}; + + for (var i = 0; i < 3; i++) { + layoutInput[paramsSet[1 - realIndex][i]] = fakeValue[i]; + layoutInput[reals[i]] = i === 2 ? itemSize[0] : modelOption[reals[i]]; + } + + var rParam = [['x', 'width', 3], ['y', 'height', 0]][realIndex]; + var rect = getLayoutRect(layoutInput, ecSize, modelOption.padding); + return reals[(rect.margin[rParam[2]] || 0) + rect[rParam[0]] + rect[rParam[1]] * 0.5 < ecSize[rParam[1]] * 0.5 ? 0 : 1]; + } + /** + * Prepare dataIndex for outside usage, where dataIndex means rawIndex, and + * dataIndexInside means filtered index. + */ + // TODO: TYPE more specified payload types. + + function makeHighDownBatch(batch, visualMapModel) { + each(batch || [], function (batchItem) { + if (batchItem.dataIndex != null) { + batchItem.dataIndexInside = batchItem.dataIndex; + batchItem.dataIndex = null; + } + + batchItem.highlightKey = 'visualMap' + (visualMapModel ? visualMapModel.componentIndex : ''); + }); + return batch; + } + + var linearMap$2 = linearMap; + var each$e = each; + var mathMin$a = Math.min; + var mathMax$a = Math.max; // Arbitrary value + + var HOVER_LINK_SIZE = 12; + var HOVER_LINK_OUT = 6; // Notice: + // Any "interval" should be by the order of [low, high]. + // "handle0" (handleIndex === 0) maps to + // low data value: this._dataInterval[0] and has low coord. + // "handle1" (handleIndex === 1) maps to + // high data value: this._dataInterval[1] and has high coord. + // The logic of transform is implemented in this._createBarGroup. + + var ContinuousView = + /** @class */ + function (_super) { + __extends(ContinuousView, _super); + + function ContinuousView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ContinuousView.type; + _this._shapes = {}; + _this._dataInterval = []; + _this._handleEnds = []; + _this._hoverLinkDataIndices = []; + return _this; + } + + ContinuousView.prototype.doRender = function (visualMapModel, ecModel, api, payload) { + this._api = api; + + if (!payload || payload.type !== 'selectDataRange' || payload.from !== this.uid) { + this._buildView(); + } + }; + + ContinuousView.prototype._buildView = function () { + this.group.removeAll(); + var visualMapModel = this.visualMapModel; + var thisGroup = this.group; + this._orient = visualMapModel.get('orient'); + this._useHandle = visualMapModel.get('calculable'); + + this._resetInterval(); + + this._renderBar(thisGroup); + + var dataRangeText = visualMapModel.get('text'); + + this._renderEndsText(thisGroup, dataRangeText, 0); + + this._renderEndsText(thisGroup, dataRangeText, 1); // Do this for background size calculation. + + + this._updateView(true); // After updating view, inner shapes is built completely, + // and then background can be rendered. + + + this.renderBackground(thisGroup); // Real update view + + this._updateView(); + + this._enableHoverLinkToSeries(); + + this._enableHoverLinkFromSeries(); + + this.positionGroup(thisGroup); + }; + + ContinuousView.prototype._renderEndsText = function (group, dataRangeText, endsIndex) { + if (!dataRangeText) { + return; + } // Compatible with ec2, text[0] map to high value, text[1] map low value. + + + var text = dataRangeText[1 - endsIndex]; + text = text != null ? text + '' : ''; + var visualMapModel = this.visualMapModel; + var textGap = visualMapModel.get('textGap'); + var itemSize = visualMapModel.itemSize; + var barGroup = this._shapes.mainGroup; + + var position = this._applyTransform([itemSize[0] / 2, endsIndex === 0 ? -textGap : itemSize[1] + textGap], barGroup); + + var align = this._applyTransform(endsIndex === 0 ? 'bottom' : 'top', barGroup); + + var orient = this._orient; + var textStyleModel = this.visualMapModel.textStyleModel; + this.group.add(new ZRText({ + style: createTextStyle(textStyleModel, { + x: position[0], + y: position[1], + verticalAlign: orient === 'horizontal' ? 'middle' : align, + align: orient === 'horizontal' ? align : 'center', + text: text + }) + })); + }; + + ContinuousView.prototype._renderBar = function (targetGroup) { + var visualMapModel = this.visualMapModel; + var shapes = this._shapes; + var itemSize = visualMapModel.itemSize; + var orient = this._orient; + var useHandle = this._useHandle; + var itemAlign = getItemAlign(visualMapModel, this.api, itemSize); + + var mainGroup = shapes.mainGroup = this._createBarGroup(itemAlign); + + var gradientBarGroup = new Group(); + mainGroup.add(gradientBarGroup); // Bar + + gradientBarGroup.add(shapes.outOfRange = createPolygon()); + gradientBarGroup.add(shapes.inRange = createPolygon(null, useHandle ? getCursor$1(this._orient) : null, bind(this._dragHandle, this, 'all', false), bind(this._dragHandle, this, 'all', true))); // A border radius clip. + + gradientBarGroup.setClipPath(new Rect({ + shape: { + x: 0, + y: 0, + width: itemSize[0], + height: itemSize[1], + r: 3 + } + })); + var textRect = visualMapModel.textStyleModel.getTextRect('国'); + var textSize = mathMax$a(textRect.width, textRect.height); // Handle + + if (useHandle) { + shapes.handleThumbs = []; + shapes.handleLabels = []; + shapes.handleLabelPoints = []; + + this._createHandle(visualMapModel, mainGroup, 0, itemSize, textSize, orient); + + this._createHandle(visualMapModel, mainGroup, 1, itemSize, textSize, orient); + } + + this._createIndicator(visualMapModel, mainGroup, itemSize, textSize, orient); + + targetGroup.add(mainGroup); + }; + + ContinuousView.prototype._createHandle = function (visualMapModel, mainGroup, handleIndex, itemSize, textSize, orient) { + var onDrift = bind(this._dragHandle, this, handleIndex, false); + var onDragEnd = bind(this._dragHandle, this, handleIndex, true); + var handleSize = parsePercent(visualMapModel.get('handleSize'), itemSize[0]); + var handleThumb = createSymbol(visualMapModel.get('handleIcon'), -handleSize / 2, -handleSize / 2, handleSize, handleSize, null, true); + var cursor = getCursor$1(this._orient); + handleThumb.attr({ + cursor: cursor, + draggable: true, + drift: onDrift, + ondragend: onDragEnd, + onmousemove: function (e) { + stop(e.event); + } + }); + handleThumb.x = itemSize[0] / 2; + handleThumb.useStyle(visualMapModel.getModel('handleStyle').getItemStyle()); + handleThumb.setStyle({ + strokeNoScale: true, + strokeFirst: true + }); + handleThumb.style.lineWidth *= 2; + handleThumb.ensureState('emphasis').style = visualMapModel.getModel(['emphasis', 'handleStyle']).getItemStyle(); + setAsHighDownDispatcher(handleThumb, true); + mainGroup.add(handleThumb); // Text is always horizontal layout but should not be effected by + // transform (orient/inverse). So label is built separately but not + // use zrender/graphic/helper/RectText, and is located based on view + // group (according to handleLabelPoint) but not barGroup. + + var textStyleModel = this.visualMapModel.textStyleModel; + var handleLabel = new ZRText({ + cursor: cursor, + draggable: true, + drift: onDrift, + onmousemove: function (e) { + // Fot mobile devicem, prevent screen slider on the button. + stop(e.event); + }, + ondragend: onDragEnd, + style: createTextStyle(textStyleModel, { + x: 0, + y: 0, + text: '' + }) + }); + handleLabel.ensureState('blur').style = { + opacity: 0.1 + }; + handleLabel.stateTransition = { + duration: 200 + }; + this.group.add(handleLabel); + var handleLabelPoint = [handleSize, 0]; + var shapes = this._shapes; + shapes.handleThumbs[handleIndex] = handleThumb; + shapes.handleLabelPoints[handleIndex] = handleLabelPoint; + shapes.handleLabels[handleIndex] = handleLabel; + }; + + ContinuousView.prototype._createIndicator = function (visualMapModel, mainGroup, itemSize, textSize, orient) { + var scale = parsePercent(visualMapModel.get('indicatorSize'), itemSize[0]); + var indicator = createSymbol(visualMapModel.get('indicatorIcon'), -scale / 2, -scale / 2, scale, scale, null, true); + indicator.attr({ + cursor: 'move', + invisible: true, + silent: true, + x: itemSize[0] / 2 + }); + var indicatorStyle = visualMapModel.getModel('indicatorStyle').getItemStyle(); + + if (indicator instanceof ZRImage) { + var pathStyle = indicator.style; + indicator.useStyle(extend({ + // TODO other properties like x, y ? + image: pathStyle.image, + x: pathStyle.x, + y: pathStyle.y, + width: pathStyle.width, + height: pathStyle.height + }, indicatorStyle)); + } else { + indicator.useStyle(indicatorStyle); + } + + mainGroup.add(indicator); + var textStyleModel = this.visualMapModel.textStyleModel; + var indicatorLabel = new ZRText({ + silent: true, + invisible: true, + style: createTextStyle(textStyleModel, { + x: 0, + y: 0, + text: '' + }) + }); + this.group.add(indicatorLabel); + var indicatorLabelPoint = [(orient === 'horizontal' ? textSize / 2 : HOVER_LINK_OUT) + itemSize[0] / 2, 0]; + var shapes = this._shapes; + shapes.indicator = indicator; + shapes.indicatorLabel = indicatorLabel; + shapes.indicatorLabelPoint = indicatorLabelPoint; + this._firstShowIndicator = true; + }; + + ContinuousView.prototype._dragHandle = function (handleIndex, isEnd, // dx is event from ondragend if isEnd is true. It's not used + dx, dy) { + if (!this._useHandle) { + return; + } + + this._dragging = !isEnd; + + if (!isEnd) { + // Transform dx, dy to bar coordination. + var vertex = this._applyTransform([dx, dy], this._shapes.mainGroup, true); + + this._updateInterval(handleIndex, vertex[1]); + + this._hideIndicator(); // Considering realtime, update view should be executed + // before dispatch action. + + + this._updateView(); + } // dragEnd do not dispatch action when realtime. + + + if (isEnd === !this.visualMapModel.get('realtime')) { + // jshint ignore:line + this.api.dispatchAction({ + type: 'selectDataRange', + from: this.uid, + visualMapId: this.visualMapModel.id, + selected: this._dataInterval.slice() + }); + } + + if (isEnd) { + !this._hovering && this._clearHoverLinkToSeries(); + } else if (useHoverLinkOnHandle(this.visualMapModel)) { + this._doHoverLinkToSeries(this._handleEnds[handleIndex], false); + } + }; + + ContinuousView.prototype._resetInterval = function () { + var visualMapModel = this.visualMapModel; + var dataInterval = this._dataInterval = visualMapModel.getSelected(); + var dataExtent = visualMapModel.getExtent(); + var sizeExtent = [0, visualMapModel.itemSize[1]]; + this._handleEnds = [linearMap$2(dataInterval[0], dataExtent, sizeExtent, true), linearMap$2(dataInterval[1], dataExtent, sizeExtent, true)]; + }; + /** + * @private + * @param {(number|string)} handleIndex 0 or 1 or 'all' + * @param {number} dx + * @param {number} dy + */ + + + ContinuousView.prototype._updateInterval = function (handleIndex, delta) { + delta = delta || 0; + var visualMapModel = this.visualMapModel; + var handleEnds = this._handleEnds; + var sizeExtent = [0, visualMapModel.itemSize[1]]; + sliderMove(delta, handleEnds, sizeExtent, handleIndex, // cross is forbiden + 0); + var dataExtent = visualMapModel.getExtent(); // Update data interval. + + this._dataInterval = [linearMap$2(handleEnds[0], sizeExtent, dataExtent, true), linearMap$2(handleEnds[1], sizeExtent, dataExtent, true)]; + }; + + ContinuousView.prototype._updateView = function (forSketch) { + var visualMapModel = this.visualMapModel; + var dataExtent = visualMapModel.getExtent(); + var shapes = this._shapes; + var outOfRangeHandleEnds = [0, visualMapModel.itemSize[1]]; + var inRangeHandleEnds = forSketch ? outOfRangeHandleEnds : this._handleEnds; + + var visualInRange = this._createBarVisual(this._dataInterval, dataExtent, inRangeHandleEnds, 'inRange'); + + var visualOutOfRange = this._createBarVisual(dataExtent, dataExtent, outOfRangeHandleEnds, 'outOfRange'); + + shapes.inRange.setStyle({ + fill: visualInRange.barColor // opacity: visualInRange.opacity + + }).setShape('points', visualInRange.barPoints); + shapes.outOfRange.setStyle({ + fill: visualOutOfRange.barColor // opacity: visualOutOfRange.opacity + + }).setShape('points', visualOutOfRange.barPoints); + + this._updateHandle(inRangeHandleEnds, visualInRange); + }; + + ContinuousView.prototype._createBarVisual = function (dataInterval, dataExtent, handleEnds, forceState) { + var opts = { + forceState: forceState, + convertOpacityToAlpha: true + }; + + var colorStops = this._makeColorGradient(dataInterval, opts); + + var symbolSizes = [this.getControllerVisual(dataInterval[0], 'symbolSize', opts), this.getControllerVisual(dataInterval[1], 'symbolSize', opts)]; + + var barPoints = this._createBarPoints(handleEnds, symbolSizes); + + return { + barColor: new LinearGradient(0, 0, 0, 1, colorStops), + barPoints: barPoints, + handlesColor: [colorStops[0].color, colorStops[colorStops.length - 1].color] + }; + }; + + ContinuousView.prototype._makeColorGradient = function (dataInterval, opts) { + // Considering colorHue, which is not linear, so we have to sample + // to calculate gradient color stops, but not only caculate head + // and tail. + var sampleNumber = 100; // Arbitrary value. + + var colorStops = []; + var step = (dataInterval[1] - dataInterval[0]) / sampleNumber; + colorStops.push({ + color: this.getControllerVisual(dataInterval[0], 'color', opts), + offset: 0 + }); + + for (var i = 1; i < sampleNumber; i++) { + var currValue = dataInterval[0] + step * i; + + if (currValue > dataInterval[1]) { + break; + } + + colorStops.push({ + color: this.getControllerVisual(currValue, 'color', opts), + offset: i / sampleNumber + }); + } + + colorStops.push({ + color: this.getControllerVisual(dataInterval[1], 'color', opts), + offset: 1 + }); + return colorStops; + }; + + ContinuousView.prototype._createBarPoints = function (handleEnds, symbolSizes) { + var itemSize = this.visualMapModel.itemSize; + return [[itemSize[0] - symbolSizes[0], handleEnds[0]], [itemSize[0], handleEnds[0]], [itemSize[0], handleEnds[1]], [itemSize[0] - symbolSizes[1], handleEnds[1]]]; + }; + + ContinuousView.prototype._createBarGroup = function (itemAlign) { + var orient = this._orient; + var inverse = this.visualMapModel.get('inverse'); + return new Group(orient === 'horizontal' && !inverse ? { + scaleX: itemAlign === 'bottom' ? 1 : -1, + rotation: Math.PI / 2 + } : orient === 'horizontal' && inverse ? { + scaleX: itemAlign === 'bottom' ? -1 : 1, + rotation: -Math.PI / 2 + } : orient === 'vertical' && !inverse ? { + scaleX: itemAlign === 'left' ? 1 : -1, + scaleY: -1 + } : { + scaleX: itemAlign === 'left' ? 1 : -1 + }); + }; + + ContinuousView.prototype._updateHandle = function (handleEnds, visualInRange) { + if (!this._useHandle) { + return; + } + + var shapes = this._shapes; + var visualMapModel = this.visualMapModel; + var handleThumbs = shapes.handleThumbs; + var handleLabels = shapes.handleLabels; + var itemSize = visualMapModel.itemSize; + var dataExtent = visualMapModel.getExtent(); + each$e([0, 1], function (handleIndex) { + var handleThumb = handleThumbs[handleIndex]; + handleThumb.setStyle('fill', visualInRange.handlesColor[handleIndex]); + handleThumb.y = handleEnds[handleIndex]; + var val = linearMap$2(handleEnds[handleIndex], [0, itemSize[1]], dataExtent, true); + var symbolSize = this.getControllerVisual(val, 'symbolSize'); + handleThumb.scaleX = handleThumb.scaleY = symbolSize / itemSize[0]; + handleThumb.x = itemSize[0] - symbolSize / 2; // Update handle label position. + + var textPoint = applyTransform$1(shapes.handleLabelPoints[handleIndex], getTransform(handleThumb, this.group)); + handleLabels[handleIndex].setStyle({ + x: textPoint[0], + y: textPoint[1], + text: visualMapModel.formatValueText(this._dataInterval[handleIndex]), + verticalAlign: 'middle', + align: this._orient === 'vertical' ? this._applyTransform('left', shapes.mainGroup) : 'center' + }); + }, this); + }; + + ContinuousView.prototype._showIndicator = function (cursorValue, textValue, rangeSymbol, halfHoverLinkSize) { + var visualMapModel = this.visualMapModel; + var dataExtent = visualMapModel.getExtent(); + var itemSize = visualMapModel.itemSize; + var sizeExtent = [0, itemSize[1]]; + var shapes = this._shapes; + var indicator = shapes.indicator; + + if (!indicator) { + return; + } + + indicator.attr('invisible', false); + var opts = { + convertOpacityToAlpha: true + }; + var color = this.getControllerVisual(cursorValue, 'color', opts); + var symbolSize = this.getControllerVisual(cursorValue, 'symbolSize'); + var y = linearMap$2(cursorValue, dataExtent, sizeExtent, true); + var x = itemSize[0] - symbolSize / 2; + var oldIndicatorPos = { + x: indicator.x, + y: indicator.y + }; // Update handle label position. + + indicator.y = y; + indicator.x = x; + var textPoint = applyTransform$1(shapes.indicatorLabelPoint, getTransform(indicator, this.group)); + var indicatorLabel = shapes.indicatorLabel; + indicatorLabel.attr('invisible', false); + + var align = this._applyTransform('left', shapes.mainGroup); + + var orient = this._orient; + var isHorizontal = orient === 'horizontal'; + indicatorLabel.setStyle({ + text: (rangeSymbol ? rangeSymbol : '') + visualMapModel.formatValueText(textValue), + verticalAlign: isHorizontal ? align : 'middle', + align: isHorizontal ? 'center' : align + }); + var indicatorNewProps = { + x: x, + y: y, + style: { + fill: color + } + }; + var labelNewProps = { + style: { + x: textPoint[0], + y: textPoint[1] + } + }; + + if (visualMapModel.ecModel.isAnimationEnabled() && !this._firstShowIndicator) { + var animationCfg = { + duration: 100, + easing: 'cubicInOut', + additive: true + }; + indicator.x = oldIndicatorPos.x; + indicator.y = oldIndicatorPos.y; + indicator.animateTo(indicatorNewProps, animationCfg); + indicatorLabel.animateTo(labelNewProps, animationCfg); + } else { + indicator.attr(indicatorNewProps); + indicatorLabel.attr(labelNewProps); + } + + this._firstShowIndicator = false; + var handleLabels = this._shapes.handleLabels; + + if (handleLabels) { + for (var i = 0; i < handleLabels.length; i++) { + // Fade out handle labels. + // NOTE: Must use api enter/leave on emphasis/blur/select state. Or the global states manager will change it. + this._api.enterBlur(handleLabels[i]); + } + } + }; + + ContinuousView.prototype._enableHoverLinkToSeries = function () { + var self = this; + + this._shapes.mainGroup.on('mousemove', function (e) { + self._hovering = true; + + if (!self._dragging) { + var itemSize = self.visualMapModel.itemSize; + + var pos = self._applyTransform([e.offsetX, e.offsetY], self._shapes.mainGroup, true, true); // For hover link show when hover handle, which might be + // below or upper than sizeExtent. + + + pos[1] = mathMin$a(mathMax$a(0, pos[1]), itemSize[1]); + + self._doHoverLinkToSeries(pos[1], 0 <= pos[0] && pos[0] <= itemSize[0]); + } + }).on('mouseout', function () { + // When mouse is out of handle, hoverLink still need + // to be displayed when realtime is set as false. + self._hovering = false; + !self._dragging && self._clearHoverLinkToSeries(); + }); + }; + + ContinuousView.prototype._enableHoverLinkFromSeries = function () { + var zr = this.api.getZr(); + + if (this.visualMapModel.option.hoverLink) { + zr.on('mouseover', this._hoverLinkFromSeriesMouseOver, this); + zr.on('mouseout', this._hideIndicator, this); + } else { + this._clearHoverLinkFromSeries(); + } + }; + + ContinuousView.prototype._doHoverLinkToSeries = function (cursorPos, hoverOnBar) { + var visualMapModel = this.visualMapModel; + var itemSize = visualMapModel.itemSize; + + if (!visualMapModel.option.hoverLink) { + return; + } + + var sizeExtent = [0, itemSize[1]]; + var dataExtent = visualMapModel.getExtent(); // For hover link show when hover handle, which might be below or upper than sizeExtent. + + cursorPos = mathMin$a(mathMax$a(sizeExtent[0], cursorPos), sizeExtent[1]); + var halfHoverLinkSize = getHalfHoverLinkSize(visualMapModel, dataExtent, sizeExtent); + var hoverRange = [cursorPos - halfHoverLinkSize, cursorPos + halfHoverLinkSize]; + var cursorValue = linearMap$2(cursorPos, sizeExtent, dataExtent, true); + var valueRange = [linearMap$2(hoverRange[0], sizeExtent, dataExtent, true), linearMap$2(hoverRange[1], sizeExtent, dataExtent, true)]; // Consider data range is out of visualMap range, see test/visualMap-continuous.html, + // where china and india has very large population. + + hoverRange[0] < sizeExtent[0] && (valueRange[0] = -Infinity); + hoverRange[1] > sizeExtent[1] && (valueRange[1] = Infinity); // Do not show indicator when mouse is over handle, + // otherwise labels overlap, especially when dragging. + + if (hoverOnBar) { + if (valueRange[0] === -Infinity) { + this._showIndicator(cursorValue, valueRange[1], '< ', halfHoverLinkSize); + } else if (valueRange[1] === Infinity) { + this._showIndicator(cursorValue, valueRange[0], '> ', halfHoverLinkSize); + } else { + this._showIndicator(cursorValue, cursorValue, '≈ ', halfHoverLinkSize); + } + } // When realtime is set as false, handles, which are in barGroup, + // also trigger hoverLink, which help user to realize where they + // focus on when dragging. (see test/heatmap-large.html) + // When realtime is set as true, highlight will not show when hover + // handle, because the label on handle, which displays a exact value + // but not range, might mislead users. + + + var oldBatch = this._hoverLinkDataIndices; + var newBatch = []; + + if (hoverOnBar || useHoverLinkOnHandle(visualMapModel)) { + newBatch = this._hoverLinkDataIndices = visualMapModel.findTargetDataIndices(valueRange); + } + + var resultBatches = compressBatches(oldBatch, newBatch); + + this._dispatchHighDown('downplay', makeHighDownBatch(resultBatches[0], visualMapModel)); + + this._dispatchHighDown('highlight', makeHighDownBatch(resultBatches[1], visualMapModel)); + }; + + ContinuousView.prototype._hoverLinkFromSeriesMouseOver = function (e) { + var el = e.target; + var visualMapModel = this.visualMapModel; + + if (!el || getECData(el).dataIndex == null) { + return; + } + + var ecData = getECData(el); + var dataModel = this.ecModel.getSeriesByIndex(ecData.seriesIndex); + + if (!visualMapModel.isTargetSeries(dataModel)) { + return; + } + + var data = dataModel.getData(ecData.dataType); + var value = data.getStore().get(visualMapModel.getDataDimensionIndex(data), ecData.dataIndex); + + if (!isNaN(value)) { + this._showIndicator(value, value); + } + }; + + ContinuousView.prototype._hideIndicator = function () { + var shapes = this._shapes; + shapes.indicator && shapes.indicator.attr('invisible', true); + shapes.indicatorLabel && shapes.indicatorLabel.attr('invisible', true); + var handleLabels = this._shapes.handleLabels; + + if (handleLabels) { + for (var i = 0; i < handleLabels.length; i++) { + // Fade out handle labels. + // NOTE: Must use api enter/leave on emphasis/blur/select state. Or the global states manager will change it. + this._api.leaveBlur(handleLabels[i]); + } + } + }; + + ContinuousView.prototype._clearHoverLinkToSeries = function () { + this._hideIndicator(); + + var indices = this._hoverLinkDataIndices; + + this._dispatchHighDown('downplay', makeHighDownBatch(indices, this.visualMapModel)); + + indices.length = 0; + }; + + ContinuousView.prototype._clearHoverLinkFromSeries = function () { + this._hideIndicator(); + + var zr = this.api.getZr(); + zr.off('mouseover', this._hoverLinkFromSeriesMouseOver); + zr.off('mouseout', this._hideIndicator); + }; + + ContinuousView.prototype._applyTransform = function (vertex, element, inverse, global) { + var transform = getTransform(element, global ? null : this.group); + return isArray(vertex) ? applyTransform$1(vertex, transform, inverse) : transformDirection(vertex, transform, inverse); + }; // TODO: TYPE more specified payload types. + + + ContinuousView.prototype._dispatchHighDown = function (type, batch) { + batch && batch.length && this.api.dispatchAction({ + type: type, + batch: batch + }); + }; + /** + * @override + */ + + + ContinuousView.prototype.dispose = function () { + this._clearHoverLinkFromSeries(); + + this._clearHoverLinkToSeries(); + }; + /** + * @override + */ + + + ContinuousView.prototype.remove = function () { + this._clearHoverLinkFromSeries(); + + this._clearHoverLinkToSeries(); + }; + + ContinuousView.type = 'visualMap.continuous'; + return ContinuousView; + }(VisualMapView); + + function createPolygon(points, cursor, onDrift, onDragEnd) { + return new Polygon({ + shape: { + points: points + }, + draggable: !!onDrift, + cursor: cursor, + drift: onDrift, + onmousemove: function (e) { + // Fot mobile devicem, prevent screen slider on the button. + stop(e.event); + }, + ondragend: onDragEnd + }); + } + + function getHalfHoverLinkSize(visualMapModel, dataExtent, sizeExtent) { + var halfHoverLinkSize = HOVER_LINK_SIZE / 2; + var hoverLinkDataSize = visualMapModel.get('hoverLinkDataSize'); + + if (hoverLinkDataSize) { + halfHoverLinkSize = linearMap$2(hoverLinkDataSize, dataExtent, sizeExtent, true) / 2; + } + + return halfHoverLinkSize; + } + + function useHoverLinkOnHandle(visualMapModel) { + var hoverLinkOnHandle = visualMapModel.get('hoverLinkOnHandle'); + return !!(hoverLinkOnHandle == null ? visualMapModel.get('realtime') : hoverLinkOnHandle); + } + + function getCursor$1(orient) { + return orient === 'vertical' ? 'ns-resize' : 'ew-resize'; + } + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + var visualMapActionInfo = { + type: 'selectDataRange', + event: 'dataRangeSelected', + // FIXME use updateView appears wrong + update: 'update' + }; + var visualMapActionHander = function (payload, ecModel) { + ecModel.eachComponent({ + mainType: 'visualMap', + query: payload + }, function (model) { + model.setSelected(payload.selected); + }); + }; + + var visualMapEncodingHandlers = [{ + createOnAllSeries: true, + reset: function (seriesModel, ecModel) { + var resetDefines = []; + ecModel.eachComponent('visualMap', function (visualMapModel) { + var pipelineContext = seriesModel.pipelineContext; + + if (!visualMapModel.isTargetSeries(seriesModel) || pipelineContext && pipelineContext.large) { + return; + } + + resetDefines.push(incrementalApplyVisual(visualMapModel.stateList, visualMapModel.targetVisuals, bind(visualMapModel.getValueState, visualMapModel), visualMapModel.getDataDimensionIndex(seriesModel.getData()))); + }); + return resetDefines; + } + }, // Only support color. + { + createOnAllSeries: true, + reset: function (seriesModel, ecModel) { + var data = seriesModel.getData(); + var visualMetaList = []; + ecModel.eachComponent('visualMap', function (visualMapModel) { + if (visualMapModel.isTargetSeries(seriesModel)) { + var visualMeta = visualMapModel.getVisualMeta(bind(getColorVisual, null, seriesModel, visualMapModel)) || { + stops: [], + outerColors: [] + }; + var dimIdx = visualMapModel.getDataDimensionIndex(data); + + if (dimIdx >= 0) { + // visualMeta.dimension should be dimension index, but not concrete dimension. + visualMeta.dimension = dimIdx; + visualMetaList.push(visualMeta); + } + } + }); // console.log(JSON.stringify(visualMetaList.map(a => a.stops))); + + seriesModel.getData().setVisual('visualMeta', visualMetaList); + } + }]; // FIXME + // performance and export for heatmap? + // value can be Infinity or -Infinity + + function getColorVisual(seriesModel, visualMapModel, value, valueState) { + var mappings = visualMapModel.targetVisuals[valueState]; + var visualTypes = VisualMapping.prepareVisualTypes(mappings); + var resultVisual = { + color: getVisualFromData(seriesModel.getData(), 'color') // default color. + + }; + + for (var i = 0, len = visualTypes.length; i < len; i++) { + var type = visualTypes[i]; + var mapping = mappings[type === 'opacity' ? '__alphaForOpacity' : type]; + mapping && mapping.applyVisual(value, getVisual, setVisual); + } + + return resultVisual.color; + + function getVisual(key) { + return resultVisual[key]; + } + + function setVisual(key, value) { + resultVisual[key] = value; + } + } + + var each$f = each; + function visualMapPreprocessor(option) { + var visualMap = option && option.visualMap; + + if (!isArray(visualMap)) { + visualMap = visualMap ? [visualMap] : []; + } + + each$f(visualMap, function (opt) { + if (!opt) { + return; + } // rename splitList to pieces + + + if (has$1(opt, 'splitList') && !has$1(opt, 'pieces')) { + opt.pieces = opt.splitList; + delete opt.splitList; + } + + var pieces = opt.pieces; + + if (pieces && isArray(pieces)) { + each$f(pieces, function (piece) { + if (isObject(piece)) { + if (has$1(piece, 'start') && !has$1(piece, 'min')) { + piece.min = piece.start; + } + + if (has$1(piece, 'end') && !has$1(piece, 'max')) { + piece.max = piece.end; + } + } + }); + } + }); + } + + function has$1(obj, name) { + return obj && obj.hasOwnProperty && obj.hasOwnProperty(name); + } + + var installed$1 = false; + function installCommon$1(registers) { + if (installed$1) { + return; + } + + installed$1 = true; + registers.registerSubTypeDefaulter('visualMap', function (option) { + // Compatible with ec2, when splitNumber === 0, continuous visualMap will be used. + return !option.categories && (!(option.pieces ? option.pieces.length > 0 : option.splitNumber > 0) || option.calculable) ? 'continuous' : 'piecewise'; + }); + registers.registerAction(visualMapActionInfo, visualMapActionHander); + each(visualMapEncodingHandlers, function (handler) { + registers.registerVisual(registers.PRIORITY.VISUAL.COMPONENT, handler); + }); + registers.registerPreprocessor(visualMapPreprocessor); + } + + function install$N(registers) { + registers.registerComponentModel(ContinuousModel); + registers.registerComponentView(ContinuousView); + installCommon$1(registers); + } + + var PiecewiseModel = + /** @class */ + function (_super) { + __extends(PiecewiseModel, _super); + + function PiecewiseModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = PiecewiseModel.type; + /** + * The order is always [low, ..., high]. + * [{text: string, interval: Array.}, ...] + */ + + _this._pieceList = []; + return _this; + } + + PiecewiseModel.prototype.optionUpdated = function (newOption, isInit) { + _super.prototype.optionUpdated.apply(this, arguments); + + this.resetExtent(); + + var mode = this._mode = this._determineMode(); + + this._pieceList = []; + + resetMethods[this._mode].call(this, this._pieceList); + + this._resetSelected(newOption, isInit); + + var categories = this.option.categories; + this.resetVisual(function (mappingOption, state) { + if (mode === 'categories') { + mappingOption.mappingMethod = 'category'; + mappingOption.categories = clone(categories); + } else { + mappingOption.dataExtent = this.getExtent(); + mappingOption.mappingMethod = 'piecewise'; + mappingOption.pieceList = map(this._pieceList, function (piece) { + piece = clone(piece); + + if (state !== 'inRange') { + // FIXME + // outOfRange do not support special visual in pieces. + piece.visual = null; + } + + return piece; + }); + } + }); + }; + /** + * @protected + * @override + */ + + + PiecewiseModel.prototype.completeVisualOption = function () { + // Consider this case: + // visualMap: { + // pieces: [{symbol: 'circle', lt: 0}, {symbol: 'rect', gte: 0}] + // } + // where no inRange/outOfRange set but only pieces. So we should make + // default inRange/outOfRange for this case, otherwise visuals that only + // appear in `pieces` will not be taken into account in visual encoding. + var option = this.option; + var visualTypesInPieces = {}; + var visualTypes = VisualMapping.listVisualTypes(); + var isCategory = this.isCategory(); + each(option.pieces, function (piece) { + each(visualTypes, function (visualType) { + if (piece.hasOwnProperty(visualType)) { + visualTypesInPieces[visualType] = 1; + } + }); + }); + each(visualTypesInPieces, function (v, visualType) { + var exists = false; + each(this.stateList, function (state) { + exists = exists || has(option, state, visualType) || has(option.target, state, visualType); + }, this); + !exists && each(this.stateList, function (state) { + (option[state] || (option[state] = {}))[visualType] = visualDefault.get(visualType, state === 'inRange' ? 'active' : 'inactive', isCategory); + }); + }, this); + + function has(obj, state, visualType) { + return obj && obj[state] && obj[state].hasOwnProperty(visualType); + } + + _super.prototype.completeVisualOption.apply(this, arguments); + }; + + PiecewiseModel.prototype._resetSelected = function (newOption, isInit) { + var thisOption = this.option; + var pieceList = this._pieceList; // Selected do not merge but all override. + + var selected = (isInit ? thisOption : newOption).selected || {}; + thisOption.selected = selected; // Consider 'not specified' means true. + + each(pieceList, function (piece, index) { + var key = this.getSelectedMapKey(piece); + + if (!selected.hasOwnProperty(key)) { + selected[key] = true; + } + }, this); + + if (thisOption.selectedMode === 'single') { + // Ensure there is only one selected. + var hasSel_1 = false; + each(pieceList, function (piece, index) { + var key = this.getSelectedMapKey(piece); + + if (selected[key]) { + hasSel_1 ? selected[key] = false : hasSel_1 = true; + } + }, this); + } // thisOption.selectedMode === 'multiple', default: all selected. + + }; + /** + * @public + */ + + + PiecewiseModel.prototype.getItemSymbol = function () { + return this.get('itemSymbol'); + }; + /** + * @public + */ + + + PiecewiseModel.prototype.getSelectedMapKey = function (piece) { + return this._mode === 'categories' ? piece.value + '' : piece.index + ''; + }; + /** + * @public + */ + + + PiecewiseModel.prototype.getPieceList = function () { + return this._pieceList; + }; + /** + * @return {string} + */ + + + PiecewiseModel.prototype._determineMode = function () { + var option = this.option; + return option.pieces && option.pieces.length > 0 ? 'pieces' : this.option.categories ? 'categories' : 'splitNumber'; + }; + /** + * @override + */ + + + PiecewiseModel.prototype.setSelected = function (selected) { + this.option.selected = clone(selected); + }; + /** + * @override + */ + + + PiecewiseModel.prototype.getValueState = function (value) { + var index = VisualMapping.findPieceIndex(value, this._pieceList); + return index != null ? this.option.selected[this.getSelectedMapKey(this._pieceList[index])] ? 'inRange' : 'outOfRange' : 'outOfRange'; + }; + /** + * @public + * @param pieceIndex piece index in visualMapModel.getPieceList() + */ + + + PiecewiseModel.prototype.findTargetDataIndices = function (pieceIndex) { + var result = []; + var pieceList = this._pieceList; + this.eachTargetSeries(function (seriesModel) { + var dataIndices = []; + var data = seriesModel.getData(); + data.each(this.getDataDimensionIndex(data), function (value, dataIndex) { + // Should always base on model pieceList, because it is order sensitive. + var pIdx = VisualMapping.findPieceIndex(value, pieceList); + pIdx === pieceIndex && dataIndices.push(dataIndex); + }, this); + result.push({ + seriesId: seriesModel.id, + dataIndex: dataIndices + }); + }, this); + return result; + }; + /** + * @private + * @param piece piece.value or piece.interval is required. + * @return Can be Infinity or -Infinity + */ + + + PiecewiseModel.prototype.getRepresentValue = function (piece) { + var representValue; + + if (this.isCategory()) { + representValue = piece.value; + } else { + if (piece.value != null) { + representValue = piece.value; + } else { + var pieceInterval = piece.interval || []; + representValue = pieceInterval[0] === -Infinity && pieceInterval[1] === Infinity ? 0 : (pieceInterval[0] + pieceInterval[1]) / 2; + } + } + + return representValue; + }; + + PiecewiseModel.prototype.getVisualMeta = function (getColorVisual) { + // Do not support category. (category axis is ordinal, numerical) + if (this.isCategory()) { + return; + } + + var stops = []; + var outerColors = ['', '']; + var visualMapModel = this; + + function setStop(interval, valueState) { + var representValue = visualMapModel.getRepresentValue({ + interval: interval + }); // Not category + + if (!valueState) { + valueState = visualMapModel.getValueState(representValue); + } + + var color = getColorVisual(representValue, valueState); + + if (interval[0] === -Infinity) { + outerColors[0] = color; + } else if (interval[1] === Infinity) { + outerColors[1] = color; + } else { + stops.push({ + value: interval[0], + color: color + }, { + value: interval[1], + color: color + }); + } + } // Suplement + + + var pieceList = this._pieceList.slice(); + + if (!pieceList.length) { + pieceList.push({ + interval: [-Infinity, Infinity] + }); + } else { + var edge = pieceList[0].interval[0]; + edge !== -Infinity && pieceList.unshift({ + interval: [-Infinity, edge] + }); + edge = pieceList[pieceList.length - 1].interval[1]; + edge !== Infinity && pieceList.push({ + interval: [edge, Infinity] + }); + } + + var curr = -Infinity; + each(pieceList, function (piece) { + var interval = piece.interval; + + if (interval) { + // Fulfill gap. + interval[0] > curr && setStop([curr, interval[0]], 'outOfRange'); + setStop(interval.slice()); + curr = interval[1]; + } + }, this); + return { + stops: stops, + outerColors: outerColors + }; + }; + + PiecewiseModel.type = 'visualMap.piecewise'; + PiecewiseModel.defaultOption = inheritDefaultOption(VisualMapModel.defaultOption, { + selected: null, + minOpen: false, + maxOpen: false, + align: 'auto', + itemWidth: 20, + itemHeight: 14, + itemSymbol: 'roundRect', + pieces: null, + categories: null, + splitNumber: 5, + selectedMode: 'multiple', + itemGap: 10, + hoverLink: true // Enable hover highlight. + + }); + return PiecewiseModel; + }(VisualMapModel); + /** + * Key is this._mode + * @type {Object} + * @this {module:echarts/component/viusalMap/PiecewiseMode} + */ + + var resetMethods = { + splitNumber: function (outPieceList) { + var thisOption = this.option; + var precision = Math.min(thisOption.precision, 20); + var dataExtent = this.getExtent(); + var splitNumber = thisOption.splitNumber; + splitNumber = Math.max(parseInt(splitNumber, 10), 1); + thisOption.splitNumber = splitNumber; + var splitStep = (dataExtent[1] - dataExtent[0]) / splitNumber; // Precision auto-adaption + + while (+splitStep.toFixed(precision) !== splitStep && precision < 5) { + precision++; + } + + thisOption.precision = precision; + splitStep = +splitStep.toFixed(precision); + + if (thisOption.minOpen) { + outPieceList.push({ + interval: [-Infinity, dataExtent[0]], + close: [0, 0] + }); + } + + for (var index = 0, curr = dataExtent[0]; index < splitNumber; curr += splitStep, index++) { + var max = index === splitNumber - 1 ? dataExtent[1] : curr + splitStep; + outPieceList.push({ + interval: [curr, max], + close: [1, 1] + }); + } + + if (thisOption.maxOpen) { + outPieceList.push({ + interval: [dataExtent[1], Infinity], + close: [0, 0] + }); + } + + reformIntervals(outPieceList); + each(outPieceList, function (piece, index) { + piece.index = index; + piece.text = this.formatValueText(piece.interval); + }, this); + }, + categories: function (outPieceList) { + var thisOption = this.option; + each(thisOption.categories, function (cate) { + // FIXME category模式也使用pieceList,但在visualMapping中不是使用pieceList。 + // 是否改一致。 + outPieceList.push({ + text: this.formatValueText(cate, true), + value: cate + }); + }, this); // See "Order Rule". + + normalizeReverse(thisOption, outPieceList); + }, + pieces: function (outPieceList) { + var thisOption = this.option; + each(thisOption.pieces, function (pieceListItem, index) { + if (!isObject(pieceListItem)) { + pieceListItem = { + value: pieceListItem + }; + } + + var item = { + text: '', + index: index + }; + + if (pieceListItem.label != null) { + item.text = pieceListItem.label; + } + + if (pieceListItem.hasOwnProperty('value')) { + var value = item.value = pieceListItem.value; + item.interval = [value, value]; + item.close = [1, 1]; + } else { + // `min` `max` is legacy option. + // `lt` `gt` `lte` `gte` is recommanded. + var interval = item.interval = []; + var close_1 = item.close = [0, 0]; + var closeList = [1, 0, 1]; + var infinityList = [-Infinity, Infinity]; + var useMinMax = []; + + for (var lg = 0; lg < 2; lg++) { + var names = [['gte', 'gt', 'min'], ['lte', 'lt', 'max']][lg]; + + for (var i = 0; i < 3 && interval[lg] == null; i++) { + interval[lg] = pieceListItem[names[i]]; + close_1[lg] = closeList[i]; + useMinMax[lg] = i === 2; + } + + interval[lg] == null && (interval[lg] = infinityList[lg]); + } + + useMinMax[0] && interval[1] === Infinity && (close_1[0] = 0); + useMinMax[1] && interval[0] === -Infinity && (close_1[1] = 0); + + if ("development" !== 'production') { + if (interval[0] > interval[1]) { + console.warn('Piece ' + index + 'is illegal: ' + interval + ' lower bound should not greater then uppper bound.'); + } + } + + if (interval[0] === interval[1] && close_1[0] && close_1[1]) { + // Consider: [{min: 5, max: 5, visual: {...}}, {min: 0, max: 5}], + // we use value to lift the priority when min === max + item.value = interval[0]; + } + } + + item.visual = VisualMapping.retrieveVisuals(pieceListItem); + outPieceList.push(item); + }, this); // See "Order Rule". + + normalizeReverse(thisOption, outPieceList); // Only pieces + + reformIntervals(outPieceList); + each(outPieceList, function (piece) { + var close = piece.close; + var edgeSymbols = [['<', '≤'][close[1]], ['>', '≥'][close[0]]]; + piece.text = piece.text || this.formatValueText(piece.value != null ? piece.value : piece.interval, false, edgeSymbols); + }, this); + } + }; + + function normalizeReverse(thisOption, pieceList) { + var inverse = thisOption.inverse; + + if (thisOption.orient === 'vertical' ? !inverse : inverse) { + pieceList.reverse(); + } + } + + var PiecewiseVisualMapView = + /** @class */ + function (_super) { + __extends(PiecewiseVisualMapView, _super); + + function PiecewiseVisualMapView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = PiecewiseVisualMapView.type; + return _this; + } + + PiecewiseVisualMapView.prototype.doRender = function () { + var thisGroup = this.group; + thisGroup.removeAll(); + var visualMapModel = this.visualMapModel; + var textGap = visualMapModel.get('textGap'); + var textStyleModel = visualMapModel.textStyleModel; + var textFont = textStyleModel.getFont(); + var textFill = textStyleModel.getTextColor(); + + var itemAlign = this._getItemAlign(); + + var itemSize = visualMapModel.itemSize; + + var viewData = this._getViewData(); + + var endsText = viewData.endsText; + var showLabel = retrieve(visualMapModel.get('showLabel', true), !endsText); + endsText && this._renderEndsText(thisGroup, endsText[0], itemSize, showLabel, itemAlign); + each(viewData.viewPieceList, function (item) { + var piece = item.piece; + var itemGroup = new Group(); + itemGroup.onclick = bind(this._onItemClick, this, piece); + + this._enableHoverLink(itemGroup, item.indexInModelPieceList); // TODO Category + + + var representValue = visualMapModel.getRepresentValue(piece); + + this._createItemSymbol(itemGroup, representValue, [0, 0, itemSize[0], itemSize[1]]); + + if (showLabel) { + var visualState = this.visualMapModel.getValueState(representValue); + itemGroup.add(new ZRText({ + style: { + x: itemAlign === 'right' ? -textGap : itemSize[0] + textGap, + y: itemSize[1] / 2, + text: piece.text, + verticalAlign: 'middle', + align: itemAlign, + font: textFont, + fill: textFill, + opacity: visualState === 'outOfRange' ? 0.5 : 1 + } + })); + } + + thisGroup.add(itemGroup); + }, this); + endsText && this._renderEndsText(thisGroup, endsText[1], itemSize, showLabel, itemAlign); + box(visualMapModel.get('orient'), thisGroup, visualMapModel.get('itemGap')); + this.renderBackground(thisGroup); + this.positionGroup(thisGroup); + }; + + PiecewiseVisualMapView.prototype._enableHoverLink = function (itemGroup, pieceIndex) { + var _this = this; + + itemGroup.on('mouseover', function () { + return onHoverLink('highlight'); + }).on('mouseout', function () { + return onHoverLink('downplay'); + }); + + var onHoverLink = function (method) { + var visualMapModel = _this.visualMapModel; // TODO: TYPE More detailed action types + + visualMapModel.option.hoverLink && _this.api.dispatchAction({ + type: method, + batch: makeHighDownBatch(visualMapModel.findTargetDataIndices(pieceIndex), visualMapModel) + }); + }; + }; + + PiecewiseVisualMapView.prototype._getItemAlign = function () { + var visualMapModel = this.visualMapModel; + var modelOption = visualMapModel.option; + + if (modelOption.orient === 'vertical') { + return getItemAlign(visualMapModel, this.api, visualMapModel.itemSize); + } else { + // horizontal, most case left unless specifying right. + var align = modelOption.align; + + if (!align || align === 'auto') { + align = 'left'; + } + + return align; + } + }; + + PiecewiseVisualMapView.prototype._renderEndsText = function (group, text, itemSize, showLabel, itemAlign) { + if (!text) { + return; + } + + var itemGroup = new Group(); + var textStyleModel = this.visualMapModel.textStyleModel; + itemGroup.add(new ZRText({ + style: createTextStyle(textStyleModel, { + x: showLabel ? itemAlign === 'right' ? itemSize[0] : 0 : itemSize[0] / 2, + y: itemSize[1] / 2, + verticalAlign: 'middle', + align: showLabel ? itemAlign : 'center', + text: text + }) + })); + group.add(itemGroup); + }; + /** + * @private + * @return {Object} {peiceList, endsText} The order is the same as screen pixel order. + */ + + + PiecewiseVisualMapView.prototype._getViewData = function () { + var visualMapModel = this.visualMapModel; + var viewPieceList = map(visualMapModel.getPieceList(), function (piece, index) { + return { + piece: piece, + indexInModelPieceList: index + }; + }); + var endsText = visualMapModel.get('text'); // Consider orient and inverse. + + var orient = visualMapModel.get('orient'); + var inverse = visualMapModel.get('inverse'); // Order of model pieceList is always [low, ..., high] + + if (orient === 'horizontal' ? inverse : !inverse) { + viewPieceList.reverse(); + } // Origin order of endsText is [high, low] + else if (endsText) { + endsText = endsText.slice().reverse(); + } + + return { + viewPieceList: viewPieceList, + endsText: endsText + }; + }; + + PiecewiseVisualMapView.prototype._createItemSymbol = function (group, representValue, shapeParam) { + group.add(createSymbol( // symbol will be string + this.getControllerVisual(representValue, 'symbol'), shapeParam[0], shapeParam[1], shapeParam[2], shapeParam[3], // color will be string + this.getControllerVisual(representValue, 'color'))); + }; + + PiecewiseVisualMapView.prototype._onItemClick = function (piece) { + var visualMapModel = this.visualMapModel; + var option = visualMapModel.option; + var selected = clone(option.selected); + var newKey = visualMapModel.getSelectedMapKey(piece); + + if (option.selectedMode === 'single') { + selected[newKey] = true; + each(selected, function (o, key) { + selected[key] = key === newKey; + }); + } else { + selected[newKey] = !selected[newKey]; + } + + this.api.dispatchAction({ + type: 'selectDataRange', + from: this.uid, + visualMapId: this.visualMapModel.id, + selected: selected + }); + }; + + PiecewiseVisualMapView.type = 'visualMap.piecewise'; + return PiecewiseVisualMapView; + }(VisualMapView); + + function install$O(registers) { + registers.registerComponentModel(PiecewiseModel); + registers.registerComponentView(PiecewiseVisualMapView); + installCommon$1(registers); + } + + function install$P(registers) { + use(install$N); + use(install$O); // Do not install './dataZoomSelect', + // since it only work for toolbox dataZoom. + } + + var DEFAULT_OPTION = { + label: { + enabled: true + }, + decal: { + show: false + } + }; + var inner$l = makeInner(); + var decalPaletteScope = {}; + function ariaVisual(ecModel, api) { + var ariaModel = ecModel.getModel('aria'); // See "area enabled" detection code in `GlobalModel.ts`. + + if (!ariaModel.get('enabled')) { + return; + } + + var defaultOption = clone(DEFAULT_OPTION); + merge(defaultOption.label, ecModel.getLocaleModel().get('aria'), false); + merge(ariaModel.option, defaultOption, false); + setDecal(); + setLabel(); + + function setDecal() { + var decalModel = ariaModel.getModel('decal'); + var useDecal = decalModel.get('show'); + + if (useDecal) { + // Each type of series use one scope. + // Pie and funnel are using diferrent scopes + var paletteScopeGroupByType_1 = createHashMap(); + ecModel.eachSeries(function (seriesModel) { + if (seriesModel.isColorBySeries()) { + return; + } + + var decalScope = paletteScopeGroupByType_1.get(seriesModel.type); + + if (!decalScope) { + decalScope = {}; + paletteScopeGroupByType_1.set(seriesModel.type, decalScope); + } + + inner$l(seriesModel).scope = decalScope; + }); + ecModel.eachRawSeries(function (seriesModel) { + if (ecModel.isSeriesFiltered(seriesModel)) { + return; + } + + if (isFunction(seriesModel.enableAriaDecal)) { + // Let series define how to use decal palette on data + seriesModel.enableAriaDecal(); + return; + } + + var data = seriesModel.getData(); + + if (!seriesModel.isColorBySeries()) { + var dataAll_1 = seriesModel.getRawData(); + var idxMap_1 = {}; + var decalScope_1 = inner$l(seriesModel).scope; + data.each(function (idx) { + var rawIdx = data.getRawIndex(idx); + idxMap_1[rawIdx] = idx; + }); + var dataCount_1 = dataAll_1.count(); + dataAll_1.each(function (rawIdx) { + var idx = idxMap_1[rawIdx]; + var name = dataAll_1.getName(rawIdx) || rawIdx + ''; + var paletteDecal = getDecalFromPalette(seriesModel.ecModel, name, decalScope_1, dataCount_1); + var specifiedDecal = data.getItemVisual(idx, 'decal'); + data.setItemVisual(idx, 'decal', mergeDecal(specifiedDecal, paletteDecal)); + }); + } else { + var paletteDecal = getDecalFromPalette(seriesModel.ecModel, seriesModel.name, decalPaletteScope, ecModel.getSeriesCount()); + var specifiedDecal = data.getVisual('decal'); + data.setVisual('decal', mergeDecal(specifiedDecal, paletteDecal)); + } + + function mergeDecal(specifiedDecal, paletteDecal) { + // Merge decal from palette to decal from itemStyle. + // User do not need to specify all of the decal props. + var resultDecal = specifiedDecal ? extend(extend({}, paletteDecal), specifiedDecal) : paletteDecal; + resultDecal.dirty = true; + return resultDecal; + } + }); + } + } + + function setLabel() { + var labelLocale = ecModel.getLocaleModel().get('aria'); + var labelModel = ariaModel.getModel('label'); + labelModel.option = defaults(labelModel.option, labelLocale); + + if (!labelModel.get('enabled')) { + return; + } + + var dom = api.getZr().dom; + + if (labelModel.get('description')) { + dom.setAttribute('aria-label', labelModel.get('description')); + return; + } + + var seriesCnt = ecModel.getSeriesCount(); + var maxDataCnt = labelModel.get(['data', 'maxCount']) || 10; + var maxSeriesCnt = labelModel.get(['series', 'maxCount']) || 10; + var displaySeriesCnt = Math.min(seriesCnt, maxSeriesCnt); + var ariaLabel; + + if (seriesCnt < 1) { + // No series, no aria label + return; + } else { + var title = getTitle(); + + if (title) { + var withTitle = labelModel.get(['general', 'withTitle']); + ariaLabel = replace(withTitle, { + title: title + }); + } else { + ariaLabel = labelModel.get(['general', 'withoutTitle']); + } + + var seriesLabels_1 = []; + var prefix = seriesCnt > 1 ? labelModel.get(['series', 'multiple', 'prefix']) : labelModel.get(['series', 'single', 'prefix']); + ariaLabel += replace(prefix, { + seriesCount: seriesCnt + }); + ecModel.eachSeries(function (seriesModel, idx) { + if (idx < displaySeriesCnt) { + var seriesLabel = void 0; + var seriesName = seriesModel.get('name'); + var withName = seriesName ? 'withName' : 'withoutName'; + seriesLabel = seriesCnt > 1 ? labelModel.get(['series', 'multiple', withName]) : labelModel.get(['series', 'single', withName]); + seriesLabel = replace(seriesLabel, { + seriesId: seriesModel.seriesIndex, + seriesName: seriesModel.get('name'), + seriesType: getSeriesTypeName(seriesModel.subType) + }); + var data = seriesModel.getData(); + + if (data.count() > maxDataCnt) { + // Show part of data + var partialLabel = labelModel.get(['data', 'partialData']); + seriesLabel += replace(partialLabel, { + displayCnt: maxDataCnt + }); + } else { + seriesLabel += labelModel.get(['data', 'allData']); + } + + var middleSeparator_1 = labelModel.get(['data', 'separator', 'middle']); + var endSeparator_1 = labelModel.get(['data', 'separator', 'end']); + var dataLabels = []; + + for (var i = 0; i < data.count(); i++) { + if (i < maxDataCnt) { + var name_1 = data.getName(i); + var value = data.getValues(i); + var dataLabel = labelModel.get(['data', name_1 ? 'withName' : 'withoutName']); + dataLabels.push(replace(dataLabel, { + name: name_1, + value: value.join(middleSeparator_1) + })); + } + } + + seriesLabel += dataLabels.join(middleSeparator_1) + endSeparator_1; + seriesLabels_1.push(seriesLabel); + } + }); + var separatorModel = labelModel.getModel(['series', 'multiple', 'separator']); + var middleSeparator = separatorModel.get('middle'); + var endSeparator = separatorModel.get('end'); + ariaLabel += seriesLabels_1.join(middleSeparator) + endSeparator; + dom.setAttribute('aria-label', ariaLabel); + } + } + + function replace(str, keyValues) { + if (!isString(str)) { + return str; + } + + var result = str; + each(keyValues, function (value, key) { + result = result.replace(new RegExp('\\{\\s*' + key + '\\s*\\}', 'g'), value); + }); + return result; + } + + function getTitle() { + var title = ecModel.get('title'); + + if (title && title.length) { + title = title[0]; + } + + return title && title.text; + } + + function getSeriesTypeName(type) { + return ecModel.getLocaleModel().get(['series', 'typeNames'])[type] || '自定义图'; + } + } + + function ariaPreprocessor(option) { + if (!option || !option.aria) { + return; + } + + var aria = option.aria; // aria.show is deprecated and should use aria.enabled instead + + if (aria.show != null) { + aria.enabled = aria.show; + } + + aria.label = aria.label || {}; // move description, general, series, data to be under aria.label + + each(['description', 'general', 'series', 'data'], function (name) { + if (aria[name] != null) { + aria.label[name] = aria[name]; + } + }); + } + + function install$Q(registers) { + registers.registerPreprocessor(ariaPreprocessor); + registers.registerVisual(registers.PRIORITY.VISUAL.ARIA, ariaVisual); + } + + var RELATIONAL_EXPRESSION_OP_ALIAS_MAP = { + value: 'eq', + // PENDING: not good for literal semantic? + '<': 'lt', + '<=': 'lte', + '>': 'gt', + '>=': 'gte', + '=': 'eq', + '!=': 'ne', + '<>': 'ne' // Might mileading for sake of the different between '==' and '===', + // So dont support them. + // '==': 'eq', + // '===': 'seq', + // '!==': 'sne' + // PENDING: Whether support some common alias "ge", "le", "neq"? + // ge: 'gte', + // le: 'lte', + // neq: 'ne', + + }; // type RelationalExpressionOpEvaluate = (tarVal: unknown, condVal: unknown) => boolean; + + var RegExpEvaluator = + /** @class */ + function () { + function RegExpEvaluator(rVal) { + // Support condVal: RegExp | string + var condValue = this._condVal = isString(rVal) ? new RegExp(rVal) : isRegExp(rVal) ? rVal : null; + + if (condValue == null) { + var errMsg = ''; + + if ("development" !== 'production') { + errMsg = makePrintable('Illegal regexp', rVal, 'in'); + } + + throwError(errMsg); + } + } + + RegExpEvaluator.prototype.evaluate = function (lVal) { + var type = typeof lVal; + return isString(type) ? this._condVal.test(lVal) : isNumber(type) ? this._condVal.test(lVal + '') : false; + }; + + return RegExpEvaluator; + }(); + + var ConstConditionInternal = + /** @class */ + function () { + function ConstConditionInternal() {} + + ConstConditionInternal.prototype.evaluate = function () { + return this.value; + }; + + return ConstConditionInternal; + }(); + + var AndConditionInternal = + /** @class */ + function () { + function AndConditionInternal() {} + + AndConditionInternal.prototype.evaluate = function () { + var children = this.children; + + for (var i = 0; i < children.length; i++) { + if (!children[i].evaluate()) { + return false; + } + } + + return true; + }; + + return AndConditionInternal; + }(); + + var OrConditionInternal = + /** @class */ + function () { + function OrConditionInternal() {} + + OrConditionInternal.prototype.evaluate = function () { + var children = this.children; + + for (var i = 0; i < children.length; i++) { + if (children[i].evaluate()) { + return true; + } + } + + return false; + }; + + return OrConditionInternal; + }(); + + var NotConditionInternal = + /** @class */ + function () { + function NotConditionInternal() {} + + NotConditionInternal.prototype.evaluate = function () { + return !this.child.evaluate(); + }; + + return NotConditionInternal; + }(); + + var RelationalConditionInternal = + /** @class */ + function () { + function RelationalConditionInternal() {} + + RelationalConditionInternal.prototype.evaluate = function () { + var needParse = !!this.valueParser; // Call getValue with no `this`. + + var getValue = this.getValue; + var tarValRaw = getValue(this.valueGetterParam); + var tarValParsed = needParse ? this.valueParser(tarValRaw) : null; // Relational cond follow "and" logic internally. + + for (var i = 0; i < this.subCondList.length; i++) { + if (!this.subCondList[i].evaluate(needParse ? tarValParsed : tarValRaw)) { + return false; + } + } + + return true; + }; + + return RelationalConditionInternal; + }(); + + function parseOption(exprOption, getters) { + if (exprOption === true || exprOption === false) { + var cond = new ConstConditionInternal(); + cond.value = exprOption; + return cond; + } + + var errMsg = ''; + + if (!isObjectNotArray(exprOption)) { + if ("development" !== 'production') { + errMsg = makePrintable('Illegal config. Expect a plain object but actually', exprOption); + } + + throwError(errMsg); + } + + if (exprOption.and) { + return parseAndOrOption('and', exprOption, getters); + } else if (exprOption.or) { + return parseAndOrOption('or', exprOption, getters); + } else if (exprOption.not) { + return parseNotOption(exprOption, getters); + } + + return parseRelationalOption(exprOption, getters); + } + + function parseAndOrOption(op, exprOption, getters) { + var subOptionArr = exprOption[op]; + var errMsg = ''; + + if ("development" !== 'production') { + errMsg = makePrintable('"and"/"or" condition should only be `' + op + ': [...]` and must not be empty array.', 'Illegal condition:', exprOption); + } + + if (!isArray(subOptionArr)) { + throwError(errMsg); + } + + if (!subOptionArr.length) { + throwError(errMsg); + } + + var cond = op === 'and' ? new AndConditionInternal() : new OrConditionInternal(); + cond.children = map(subOptionArr, function (subOption) { + return parseOption(subOption, getters); + }); + + if (!cond.children.length) { + throwError(errMsg); + } + + return cond; + } + + function parseNotOption(exprOption, getters) { + var subOption = exprOption.not; + var errMsg = ''; + + if ("development" !== 'production') { + errMsg = makePrintable('"not" condition should only be `not: {}`.', 'Illegal condition:', exprOption); + } + + if (!isObjectNotArray(subOption)) { + throwError(errMsg); + } + + var cond = new NotConditionInternal(); + cond.child = parseOption(subOption, getters); + + if (!cond.child) { + throwError(errMsg); + } + + return cond; + } + + function parseRelationalOption(exprOption, getters) { + var errMsg = ''; + var valueGetterParam = getters.prepareGetValue(exprOption); + var subCondList = []; + var exprKeys = keys(exprOption); + var parserName = exprOption.parser; + var valueParser = parserName ? getRawValueParser(parserName) : null; + + for (var i = 0; i < exprKeys.length; i++) { + var keyRaw = exprKeys[i]; + + if (keyRaw === 'parser' || getters.valueGetterAttrMap.get(keyRaw)) { + continue; + } + + var op = hasOwn(RELATIONAL_EXPRESSION_OP_ALIAS_MAP, keyRaw) ? RELATIONAL_EXPRESSION_OP_ALIAS_MAP[keyRaw] : keyRaw; + var condValueRaw = exprOption[keyRaw]; + var condValueParsed = valueParser ? valueParser(condValueRaw) : condValueRaw; + var evaluator = createFilterComparator(op, condValueParsed) || op === 'reg' && new RegExpEvaluator(condValueParsed); + + if (!evaluator) { + if ("development" !== 'production') { + errMsg = makePrintable('Illegal relational operation: "' + keyRaw + '" in condition:', exprOption); + } + + throwError(errMsg); + } + + subCondList.push(evaluator); + } + + if (!subCondList.length) { + if ("development" !== 'production') { + errMsg = makePrintable('Relational condition must have at least one operator.', 'Illegal condition:', exprOption); + } // No relational operator always disabled in case of dangers result. + + + throwError(errMsg); + } + + var cond = new RelationalConditionInternal(); + cond.valueGetterParam = valueGetterParam; + cond.valueParser = valueParser; + cond.getValue = getters.getValue; + cond.subCondList = subCondList; + return cond; + } + + function isObjectNotArray(val) { + return isObject(val) && !isArrayLike(val); + } + + var ConditionalExpressionParsed = + /** @class */ + function () { + function ConditionalExpressionParsed(exprOption, getters) { + this._cond = parseOption(exprOption, getters); + } + + ConditionalExpressionParsed.prototype.evaluate = function () { + return this._cond.evaluate(); + }; + + return ConditionalExpressionParsed; + }(); + function parseConditionalExpression(exprOption, getters) { + return new ConditionalExpressionParsed(exprOption, getters); + } + + var filterTransform = { + type: 'echarts:filter', + // PEDING: enhance to filter by index rather than create new data + transform: function (params) { + // [Caveat] Fail-Fast: + // Do not return the whole dataset unless user config indicate it explicitly. + // For example, if no condition specified by mistake, return an empty result + // is better than return the entire raw soruce for user to find the mistake. + var upstream = params.upstream; + var rawItem; + var condition = parseConditionalExpression(params.config, { + valueGetterAttrMap: createHashMap({ + dimension: true + }), + prepareGetValue: function (exprOption) { + var errMsg = ''; + var dimLoose = exprOption.dimension; + + if (!hasOwn(exprOption, 'dimension')) { + if ("development" !== 'production') { + errMsg = makePrintable('Relation condition must has prop "dimension" specified.', 'Illegal condition:', exprOption); + } + + throwError(errMsg); + } + + var dimInfo = upstream.getDimensionInfo(dimLoose); + + if (!dimInfo) { + if ("development" !== 'production') { + errMsg = makePrintable('Can not find dimension info via: ' + dimLoose + '.\n', 'Existing dimensions: ', upstream.cloneAllDimensionInfo(), '.\n', 'Illegal condition:', exprOption, '.\n'); + } + + throwError(errMsg); + } + + return { + dimIdx: dimInfo.index + }; + }, + getValue: function (param) { + return upstream.retrieveValueFromItem(rawItem, param.dimIdx); + } + }); + var resultData = []; + + for (var i = 0, len = upstream.count(); i < len; i++) { + rawItem = upstream.getRawDataItem(i); + + if (condition.evaluate()) { + resultData.push(rawItem); + } + } + + return { + data: resultData + }; + } + }; + + var sampleLog = ''; + + if ("development" !== 'production') { + sampleLog = ['Valid config is like:', '{ dimension: "age", order: "asc" }', 'or [{ dimension: "age", order: "asc"], { dimension: "date", order: "desc" }]'].join(' '); + } + + var sortTransform = { + type: 'echarts:sort', + transform: function (params) { + var upstream = params.upstream; + var config = params.config; + var errMsg = ''; // Normalize + // const orderExprList: OrderExpression[] = isArray(config[0]) + // ? config as OrderExpression[] + // : [config as OrderExpression]; + + var orderExprList = normalizeToArray(config); + + if (!orderExprList.length) { + if ("development" !== 'production') { + errMsg = 'Empty `config` in sort transform.'; + } + + throwError(errMsg); + } + + var orderDefList = []; + each(orderExprList, function (orderExpr) { + var dimLoose = orderExpr.dimension; + var order = orderExpr.order; + var parserName = orderExpr.parser; + var incomparable = orderExpr.incomparable; + + if (dimLoose == null) { + if ("development" !== 'production') { + errMsg = 'Sort transform config must has "dimension" specified.' + sampleLog; + } + + throwError(errMsg); + } + + if (order !== 'asc' && order !== 'desc') { + if ("development" !== 'production') { + errMsg = 'Sort transform config must has "order" specified.' + sampleLog; + } + + throwError(errMsg); + } + + if (incomparable && incomparable !== 'min' && incomparable !== 'max') { + var errMsg_1 = ''; + + if ("development" !== 'production') { + errMsg_1 = 'incomparable must be "min" or "max" rather than "' + incomparable + '".'; + } + + throwError(errMsg_1); + } + + if (order !== 'asc' && order !== 'desc') { + var errMsg_2 = ''; + + if ("development" !== 'production') { + errMsg_2 = 'order must be "asc" or "desc" rather than "' + order + '".'; + } + + throwError(errMsg_2); + } + + var dimInfo = upstream.getDimensionInfo(dimLoose); + + if (!dimInfo) { + if ("development" !== 'production') { + errMsg = makePrintable('Can not find dimension info via: ' + dimLoose + '.\n', 'Existing dimensions: ', upstream.cloneAllDimensionInfo(), '.\n', 'Illegal config:', orderExpr, '.\n'); + } + + throwError(errMsg); + } + + var parser = parserName ? getRawValueParser(parserName) : null; + + if (parserName && !parser) { + if ("development" !== 'production') { + errMsg = makePrintable('Invalid parser name ' + parserName + '.\n', 'Illegal config:', orderExpr, '.\n'); + } + + throwError(errMsg); + } + + orderDefList.push({ + dimIdx: dimInfo.index, + parser: parser, + comparator: new SortOrderComparator(order, incomparable) + }); + }); // TODO: support it? + + var sourceFormat = upstream.sourceFormat; + + if (sourceFormat !== SOURCE_FORMAT_ARRAY_ROWS && sourceFormat !== SOURCE_FORMAT_OBJECT_ROWS) { + if ("development" !== 'production') { + errMsg = 'sourceFormat "' + sourceFormat + '" is not supported yet'; + } + + throwError(errMsg); + } // Other upstream format are all array. + + + var resultData = []; + + for (var i = 0, len = upstream.count(); i < len; i++) { + resultData.push(upstream.getRawDataItem(i)); + } + + resultData.sort(function (item0, item1) { + for (var i = 0; i < orderDefList.length; i++) { + var orderDef = orderDefList[i]; + var val0 = upstream.retrieveValueFromItem(item0, orderDef.dimIdx); + var val1 = upstream.retrieveValueFromItem(item1, orderDef.dimIdx); + + if (orderDef.parser) { + val0 = orderDef.parser(val0); + val1 = orderDef.parser(val1); + } + + var result = orderDef.comparator.evaluate(val0, val1); + + if (result !== 0) { + return result; + } + } + + return 0; + }); + return { + data: resultData + }; + } + }; + + function install$R(registers) { + registers.registerTransform(filterTransform); + registers.registerTransform(sortTransform); + } + + var DatasetModel = + /** @class */ + function (_super) { + __extends(DatasetModel, _super); + + function DatasetModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'dataset'; + return _this; + } + + DatasetModel.prototype.init = function (option, parentModel, ecModel) { + _super.prototype.init.call(this, option, parentModel, ecModel); + + this._sourceManager = new SourceManager(this); + disableTransformOptionMerge(this); + }; + + DatasetModel.prototype.mergeOption = function (newOption, ecModel) { + _super.prototype.mergeOption.call(this, newOption, ecModel); + + disableTransformOptionMerge(this); + }; + + DatasetModel.prototype.optionUpdated = function () { + this._sourceManager.dirty(); + }; + + DatasetModel.prototype.getSourceManager = function () { + return this._sourceManager; + }; + + DatasetModel.type = 'dataset'; + DatasetModel.defaultOption = { + seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN + }; + return DatasetModel; + }(ComponentModel); + + var DatasetView = + /** @class */ + function (_super) { + __extends(DatasetView, _super); + + function DatasetView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'dataset'; + return _this; + } + + DatasetView.type = 'dataset'; + return DatasetView; + }(ComponentView); + + function install$S(registers) { + registers.registerComponentModel(DatasetModel); + registers.registerComponentView(DatasetView); + } + + var CMD$4 = PathProxy.CMD; + function aroundEqual(a, b) { + return Math.abs(a - b) < 1e-5; + } + function pathToBezierCurves(path) { + var data = path.data; + var len = path.len(); + var bezierArrayGroups = []; + var currentSubpath; + var xi = 0; + var yi = 0; + var x0 = 0; + var y0 = 0; + function createNewSubpath(x, y) { + if (currentSubpath && currentSubpath.length > 2) { + bezierArrayGroups.push(currentSubpath); + } + currentSubpath = [x, y]; + } + function addLine(x0, y0, x1, y1) { + if (!(aroundEqual(x0, x1) && aroundEqual(y0, y1))) { + currentSubpath.push(x0, y0, x1, y1, x1, y1); + } + } + function addArc(startAngle, endAngle, cx, cy, rx, ry) { + var delta = Math.abs(endAngle - startAngle); + var len = Math.tan(delta / 4) * 4 / 3; + var dir = endAngle < startAngle ? -1 : 1; + var c1 = Math.cos(startAngle); + var s1 = Math.sin(startAngle); + var c2 = Math.cos(endAngle); + var s2 = Math.sin(endAngle); + var x1 = c1 * rx + cx; + var y1 = s1 * ry + cy; + var x4 = c2 * rx + cx; + var y4 = s2 * ry + cy; + var hx = rx * len * dir; + var hy = ry * len * dir; + currentSubpath.push(x1 - hx * s1, y1 + hy * c1, x4 + hx * s2, y4 - hy * c2, x4, y4); + } + var x1; + var y1; + var x2; + var y2; + for (var i = 0; i < len;) { + var cmd = data[i++]; + var isFirst = i === 1; + if (isFirst) { + xi = data[i]; + yi = data[i + 1]; + x0 = xi; + y0 = yi; + if (cmd === CMD$4.L || cmd === CMD$4.C || cmd === CMD$4.Q) { + currentSubpath = [x0, y0]; + } + } + switch (cmd) { + case CMD$4.M: + xi = x0 = data[i++]; + yi = y0 = data[i++]; + createNewSubpath(x0, y0); + break; + case CMD$4.L: + x1 = data[i++]; + y1 = data[i++]; + addLine(xi, yi, x1, y1); + xi = x1; + yi = y1; + break; + case CMD$4.C: + currentSubpath.push(data[i++], data[i++], data[i++], data[i++], xi = data[i++], yi = data[i++]); + break; + case CMD$4.Q: + x1 = data[i++]; + y1 = data[i++]; + x2 = data[i++]; + y2 = data[i++]; + currentSubpath.push(xi + 2 / 3 * (x1 - xi), yi + 2 / 3 * (y1 - yi), x2 + 2 / 3 * (x1 - x2), y2 + 2 / 3 * (y1 - y2), x2, y2); + xi = x2; + yi = y2; + break; + case CMD$4.A: + var cx = data[i++]; + var cy = data[i++]; + var rx = data[i++]; + var ry = data[i++]; + var startAngle = data[i++]; + var endAngle = data[i++] + startAngle; + i += 1; + var anticlockwise = !data[i++]; + x1 = Math.cos(startAngle) * rx + cx; + y1 = Math.sin(startAngle) * ry + cy; + if (isFirst) { + x0 = x1; + y0 = y1; + createNewSubpath(x0, y0); + } + else { + addLine(xi, yi, x1, y1); + } + xi = Math.cos(endAngle) * rx + cx; + yi = Math.sin(endAngle) * ry + cy; + var step = (anticlockwise ? -1 : 1) * Math.PI / 2; + for (var angle = startAngle; anticlockwise ? angle > endAngle : angle < endAngle; angle += step) { + var nextAngle = anticlockwise ? Math.max(angle + step, endAngle) + : Math.min(angle + step, endAngle); + addArc(angle, nextAngle, cx, cy, rx, ry); + } + break; + case CMD$4.R: + x0 = xi = data[i++]; + y0 = yi = data[i++]; + x1 = x0 + data[i++]; + y1 = y0 + data[i++]; + createNewSubpath(x1, y0); + addLine(x1, y0, x1, y1); + addLine(x1, y1, x0, y1); + addLine(x0, y1, x0, y0); + addLine(x0, y0, x1, y0); + break; + case CMD$4.Z: + currentSubpath && addLine(xi, yi, x0, y0); + xi = x0; + yi = y0; + break; + } + } + if (currentSubpath && currentSubpath.length > 2) { + bezierArrayGroups.push(currentSubpath); + } + return bezierArrayGroups; + } + function adpativeBezier(x0, y0, x1, y1, x2, y2, x3, y3, out, scale) { + if (aroundEqual(x0, x1) && aroundEqual(y0, y1) && aroundEqual(x2, x3) && aroundEqual(y2, y3)) { + out.push(x3, y3); + return; + } + var PIXEL_DISTANCE = 2 / scale; + var PIXEL_DISTANCE_SQR = PIXEL_DISTANCE * PIXEL_DISTANCE; + var dx = x3 - x0; + var dy = y3 - y0; + var d = Math.sqrt(dx * dx + dy * dy); + dx /= d; + dy /= d; + var dx1 = x1 - x0; + var dy1 = y1 - y0; + var dx2 = x2 - x3; + var dy2 = y2 - y3; + var cp1LenSqr = dx1 * dx1 + dy1 * dy1; + var cp2LenSqr = dx2 * dx2 + dy2 * dy2; + if (cp1LenSqr < PIXEL_DISTANCE_SQR && cp2LenSqr < PIXEL_DISTANCE_SQR) { + out.push(x3, y3); + return; + } + var projLen1 = dx * dx1 + dy * dy1; + var projLen2 = -dx * dx2 - dy * dy2; + var d1Sqr = cp1LenSqr - projLen1 * projLen1; + var d2Sqr = cp2LenSqr - projLen2 * projLen2; + if (d1Sqr < PIXEL_DISTANCE_SQR && projLen1 >= 0 + && d2Sqr < PIXEL_DISTANCE_SQR && projLen2 >= 0) { + out.push(x3, y3); + return; + } + var tmpSegX = []; + var tmpSegY = []; + cubicSubdivide(x0, x1, x2, x3, 0.5, tmpSegX); + cubicSubdivide(y0, y1, y2, y3, 0.5, tmpSegY); + adpativeBezier(tmpSegX[0], tmpSegY[0], tmpSegX[1], tmpSegY[1], tmpSegX[2], tmpSegY[2], tmpSegX[3], tmpSegY[3], out, scale); + adpativeBezier(tmpSegX[4], tmpSegY[4], tmpSegX[5], tmpSegY[5], tmpSegX[6], tmpSegY[6], tmpSegX[7], tmpSegY[7], out, scale); + } + function pathToPolygons(path, scale) { + var bezierArrayGroups = pathToBezierCurves(path); + var polygons = []; + scale = scale || 1; + for (var i = 0; i < bezierArrayGroups.length; i++) { + var beziers = bezierArrayGroups[i]; + var polygon = []; + var x0 = beziers[0]; + var y0 = beziers[1]; + polygon.push(x0, y0); + for (var k = 2; k < beziers.length;) { + var x1 = beziers[k++]; + var y1 = beziers[k++]; + var x2 = beziers[k++]; + var y2 = beziers[k++]; + var x3 = beziers[k++]; + var y3 = beziers[k++]; + adpativeBezier(x0, y0, x1, y1, x2, y2, x3, y3, polygon, scale); + x0 = x3; + y0 = y3; + } + polygons.push(polygon); + } + return polygons; + } + + function getDividingGrids(dimSize, rowDim, count) { + var rowSize = dimSize[rowDim]; + var columnSize = dimSize[1 - rowDim]; + var ratio = Math.abs(rowSize / columnSize); + var rowCount = Math.ceil(Math.sqrt(ratio * count)); + var columnCount = Math.floor(count / rowCount); + if (columnCount === 0) { + columnCount = 1; + rowCount = count; + } + var grids = []; + for (var i = 0; i < rowCount; i++) { + grids.push(columnCount); + } + var currentCount = rowCount * columnCount; + var remained = count - currentCount; + if (remained > 0) { + for (var i = 0; i < remained; i++) { + grids[i % rowCount] += 1; + } + } + return grids; + } + function divideSector(sectorShape, count, outShapes) { + var r0 = sectorShape.r0; + var r = sectorShape.r; + var startAngle = sectorShape.startAngle; + var endAngle = sectorShape.endAngle; + var angle = Math.abs(endAngle - startAngle); + var arcLen = angle * r; + var deltaR = r - r0; + var isAngleRow = arcLen > Math.abs(deltaR); + var grids = getDividingGrids([arcLen, deltaR], isAngleRow ? 0 : 1, count); + var rowSize = (isAngleRow ? angle : deltaR) / grids.length; + for (var row = 0; row < grids.length; row++) { + var columnSize = (isAngleRow ? deltaR : angle) / grids[row]; + for (var column = 0; column < grids[row]; column++) { + var newShape = {}; + if (isAngleRow) { + newShape.startAngle = startAngle + rowSize * row; + newShape.endAngle = startAngle + rowSize * (row + 1); + newShape.r0 = r0 + columnSize * column; + newShape.r = r0 + columnSize * (column + 1); + } + else { + newShape.startAngle = startAngle + columnSize * column; + newShape.endAngle = startAngle + columnSize * (column + 1); + newShape.r0 = r0 + rowSize * row; + newShape.r = r0 + rowSize * (row + 1); + } + newShape.clockwise = sectorShape.clockwise; + newShape.cx = sectorShape.cx; + newShape.cy = sectorShape.cy; + outShapes.push(newShape); + } + } + } + function divideRect(rectShape, count, outShapes) { + var width = rectShape.width; + var height = rectShape.height; + var isHorizontalRow = width > height; + var grids = getDividingGrids([width, height], isHorizontalRow ? 0 : 1, count); + var rowSizeDim = isHorizontalRow ? 'width' : 'height'; + var columnSizeDim = isHorizontalRow ? 'height' : 'width'; + var rowDim = isHorizontalRow ? 'x' : 'y'; + var columnDim = isHorizontalRow ? 'y' : 'x'; + var rowSize = rectShape[rowSizeDim] / grids.length; + for (var row = 0; row < grids.length; row++) { + var columnSize = rectShape[columnSizeDim] / grids[row]; + for (var column = 0; column < grids[row]; column++) { + var newShape = {}; + newShape[rowDim] = row * rowSize; + newShape[columnDim] = column * columnSize; + newShape[rowSizeDim] = rowSize; + newShape[columnSizeDim] = columnSize; + newShape.x += rectShape.x; + newShape.y += rectShape.y; + outShapes.push(newShape); + } + } + } + function crossProduct2d$1(x1, y1, x2, y2) { + return x1 * y2 - x2 * y1; + } + function lineLineIntersect$1(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) { + var mx = a2x - a1x; + var my = a2y - a1y; + var nx = b2x - b1x; + var ny = b2y - b1y; + var nmCrossProduct = crossProduct2d$1(nx, ny, mx, my); + if (Math.abs(nmCrossProduct) < 1e-6) { + return null; + } + var b1a1x = a1x - b1x; + var b1a1y = a1y - b1y; + var p = crossProduct2d$1(b1a1x, b1a1y, nx, ny) / nmCrossProduct; + if (p < 0 || p > 1) { + return null; + } + return new Point(p * mx + a1x, p * my + a1y); + } + function projPtOnLine(pt, lineA, lineB) { + var dir = new Point(); + Point.sub(dir, lineB, lineA); + dir.normalize(); + var dir2 = new Point(); + Point.sub(dir2, pt, lineA); + var len = dir2.dot(dir); + return len; + } + function addToPoly(poly, pt) { + var last = poly[poly.length - 1]; + if (last && last[0] === pt[0] && last[1] === pt[1]) { + return; + } + poly.push(pt); + } + function splitPolygonByLine(points, lineA, lineB) { + var len = points.length; + var intersections = []; + for (var i = 0; i < len; i++) { + var p0 = points[i]; + var p1 = points[(i + 1) % len]; + var intersectionPt = lineLineIntersect$1(p0[0], p0[1], p1[0], p1[1], lineA.x, lineA.y, lineB.x, lineB.y); + if (intersectionPt) { + intersections.push({ + projPt: projPtOnLine(intersectionPt, lineA, lineB), + pt: intersectionPt, + idx: i + }); + } + } + if (intersections.length < 2) { + return [{ points: points }, { points: points }]; + } + intersections.sort(function (a, b) { + return a.projPt - b.projPt; + }); + var splitPt0 = intersections[0]; + var splitPt1 = intersections[intersections.length - 1]; + if (splitPt1.idx < splitPt0.idx) { + var tmp = splitPt0; + splitPt0 = splitPt1; + splitPt1 = tmp; + } + var splitPt0Arr = [splitPt0.pt.x, splitPt0.pt.y]; + var splitPt1Arr = [splitPt1.pt.x, splitPt1.pt.y]; + var newPolyA = [splitPt0Arr]; + var newPolyB = [splitPt1Arr]; + for (var i = splitPt0.idx + 1; i <= splitPt1.idx; i++) { + addToPoly(newPolyA, points[i].slice()); + } + addToPoly(newPolyA, splitPt1Arr); + addToPoly(newPolyA, splitPt0Arr); + for (var i = splitPt1.idx + 1; i <= splitPt0.idx + len; i++) { + addToPoly(newPolyB, points[i % len].slice()); + } + addToPoly(newPolyB, splitPt0Arr); + addToPoly(newPolyB, splitPt1Arr); + return [{ + points: newPolyA + }, { + points: newPolyB + }]; + } + function binaryDividePolygon(polygonShape) { + var points = polygonShape.points; + var min = []; + var max = []; + fromPoints(points, min, max); + var boundingRect = new BoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]); + var width = boundingRect.width; + var height = boundingRect.height; + var x = boundingRect.x; + var y = boundingRect.y; + var pt0 = new Point(); + var pt1 = new Point(); + if (width > height) { + pt0.x = pt1.x = x + width / 2; + pt0.y = y; + pt1.y = y + height; + } + else { + pt0.y = pt1.y = y + height / 2; + pt0.x = x; + pt1.x = x + width; + } + return splitPolygonByLine(points, pt0, pt1); + } + function binaryDivideRecursive(divider, shape, count, out) { + if (count === 1) { + out.push(shape); + } + else { + var mid = Math.floor(count / 2); + var sub = divider(shape); + binaryDivideRecursive(divider, sub[0], mid, out); + binaryDivideRecursive(divider, sub[1], count - mid, out); + } + return out; + } + function clone$4(path, count) { + var paths = []; + for (var i = 0; i < count; i++) { + paths.push(clonePath(path)); + } + return paths; + } + function copyPathProps(source, target) { + target.setStyle(source.style); + target.z = source.z; + target.z2 = source.z2; + target.zlevel = source.zlevel; + } + function polygonConvert(points) { + var out = []; + for (var i = 0; i < points.length;) { + out.push([points[i++], points[i++]]); + } + return out; + } + function split(path, count) { + var outShapes = []; + var shape = path.shape; + var OutShapeCtor; + switch (path.type) { + case 'rect': + divideRect(shape, count, outShapes); + OutShapeCtor = Rect; + break; + case 'sector': + divideSector(shape, count, outShapes); + OutShapeCtor = Sector; + break; + case 'circle': + divideSector({ + r0: 0, r: shape.r, startAngle: 0, endAngle: Math.PI * 2, + cx: shape.cx, cy: shape.cy + }, count, outShapes); + OutShapeCtor = Sector; + break; + default: + var m = path.getComputedTransform(); + var scale = m ? Math.sqrt(Math.max(m[0] * m[0] + m[1] * m[1], m[2] * m[2] + m[3] * m[3])) : 1; + var polygons = map(pathToPolygons(path.getUpdatedPathProxy(), scale), function (poly) { return polygonConvert(poly); }); + var polygonCount = polygons.length; + if (polygonCount === 0) { + binaryDivideRecursive(binaryDividePolygon, { + points: polygons[0] + }, count, outShapes); + } + else if (polygonCount === count) { + for (var i = 0; i < polygonCount; i++) { + outShapes.push({ + points: polygons[i] + }); + } + } + else { + var totalArea_1 = 0; + var items = map(polygons, function (poly) { + var min = []; + var max = []; + fromPoints(poly, min, max); + var area = (max[1] - min[1]) * (max[0] - min[0]); + totalArea_1 += area; + return { poly: poly, area: area }; + }); + items.sort(function (a, b) { return b.area - a.area; }); + var left = count; + for (var i = 0; i < polygonCount; i++) { + var item = items[i]; + if (left <= 0) { + break; + } + var selfCount = i === polygonCount - 1 + ? left + : Math.ceil(item.area / totalArea_1 * count); + if (selfCount < 0) { + continue; + } + binaryDivideRecursive(binaryDividePolygon, { + points: item.poly + }, selfCount, outShapes); + left -= selfCount; + } + } + OutShapeCtor = Polygon; + break; + } + if (!OutShapeCtor) { + return clone$4(path, count); + } + var out = []; + for (var i = 0; i < outShapes.length; i++) { + var subPath = new OutShapeCtor(); + subPath.setShape(outShapes[i]); + copyPathProps(path, subPath); + out.push(subPath); + } + return out; + } + + function alignSubpath(subpath1, subpath2) { + var len1 = subpath1.length; + var len2 = subpath2.length; + if (len1 === len2) { + return [subpath1, subpath2]; + } + var tmpSegX = []; + var tmpSegY = []; + var shorterPath = len1 < len2 ? subpath1 : subpath2; + var shorterLen = Math.min(len1, len2); + var diff = Math.abs(len2 - len1) / 6; + var shorterBezierCount = (shorterLen - 2) / 6; + var eachCurveSubDivCount = Math.ceil(diff / shorterBezierCount) + 1; + var newSubpath = [shorterPath[0], shorterPath[1]]; + var remained = diff; + for (var i = 2; i < shorterLen;) { + var x0 = shorterPath[i - 2]; + var y0 = shorterPath[i - 1]; + var x1 = shorterPath[i++]; + var y1 = shorterPath[i++]; + var x2 = shorterPath[i++]; + var y2 = shorterPath[i++]; + var x3 = shorterPath[i++]; + var y3 = shorterPath[i++]; + if (remained <= 0) { + newSubpath.push(x1, y1, x2, y2, x3, y3); + continue; + } + var actualSubDivCount = Math.min(remained, eachCurveSubDivCount - 1) + 1; + for (var k = 1; k <= actualSubDivCount; k++) { + var p = k / actualSubDivCount; + cubicSubdivide(x0, x1, x2, x3, p, tmpSegX); + cubicSubdivide(y0, y1, y2, y3, p, tmpSegY); + x0 = tmpSegX[3]; + y0 = tmpSegY[3]; + newSubpath.push(tmpSegX[1], tmpSegY[1], tmpSegX[2], tmpSegY[2], x0, y0); + x1 = tmpSegX[5]; + y1 = tmpSegY[5]; + x2 = tmpSegX[6]; + y2 = tmpSegY[6]; + } + remained -= actualSubDivCount - 1; + } + return shorterPath === subpath1 ? [newSubpath, subpath2] : [subpath1, newSubpath]; + } + function createSubpath(lastSubpathSubpath, otherSubpath) { + var len = lastSubpathSubpath.length; + var lastX = lastSubpathSubpath[len - 2]; + var lastY = lastSubpathSubpath[len - 1]; + var newSubpath = []; + for (var i = 0; i < otherSubpath.length;) { + newSubpath[i++] = lastX; + newSubpath[i++] = lastY; + } + return newSubpath; + } + function alignBezierCurves(array1, array2) { + var _a; + var lastSubpath1; + var lastSubpath2; + var newArray1 = []; + var newArray2 = []; + for (var i = 0; i < Math.max(array1.length, array2.length); i++) { + var subpath1 = array1[i]; + var subpath2 = array2[i]; + var newSubpath1 = void 0; + var newSubpath2 = void 0; + if (!subpath1) { + newSubpath1 = createSubpath(lastSubpath1 || subpath2, subpath2); + newSubpath2 = subpath2; + } + else if (!subpath2) { + newSubpath2 = createSubpath(lastSubpath2 || subpath1, subpath1); + newSubpath1 = subpath1; + } + else { + _a = alignSubpath(subpath1, subpath2), newSubpath1 = _a[0], newSubpath2 = _a[1]; + lastSubpath1 = newSubpath1; + lastSubpath2 = newSubpath2; + } + newArray1.push(newSubpath1); + newArray2.push(newSubpath2); + } + return [newArray1, newArray2]; + } + function centroid$1(array) { + var signedArea = 0; + var cx = 0; + var cy = 0; + var len = array.length; + for (var i = 0, j = len - 2; i < len; j = i, i += 2) { + var x0 = array[j]; + var y0 = array[j + 1]; + var x1 = array[i]; + var y1 = array[i + 1]; + var a = x0 * y1 - x1 * y0; + signedArea += a; + cx += (x0 + x1) * a; + cy += (y0 + y1) * a; + } + if (signedArea === 0) { + return [array[0] || 0, array[1] || 0]; + } + return [cx / signedArea / 3, cy / signedArea / 3, signedArea]; + } + function findBestRingOffset(fromSubBeziers, toSubBeziers, fromCp, toCp) { + var bezierCount = (fromSubBeziers.length - 2) / 6; + var bestScore = Infinity; + var bestOffset = 0; + var len = fromSubBeziers.length; + var len2 = len - 2; + for (var offset = 0; offset < bezierCount; offset++) { + var cursorOffset = offset * 6; + var score = 0; + for (var k = 0; k < len; k += 2) { + var idx = k === 0 ? cursorOffset : ((cursorOffset + k - 2) % len2 + 2); + var x0 = fromSubBeziers[idx] - fromCp[0]; + var y0 = fromSubBeziers[idx + 1] - fromCp[1]; + var x1 = toSubBeziers[k] - toCp[0]; + var y1 = toSubBeziers[k + 1] - toCp[1]; + var dx = x1 - x0; + var dy = y1 - y0; + score += dx * dx + dy * dy; + } + if (score < bestScore) { + bestScore = score; + bestOffset = offset; + } + } + return bestOffset; + } + function reverse(array) { + var newArr = []; + var len = array.length; + for (var i = 0; i < len; i += 2) { + newArr[i] = array[len - i - 2]; + newArr[i + 1] = array[len - i - 1]; + } + return newArr; + } + function findBestMorphingRotation(fromArr, toArr, searchAngleIteration, searchAngleRange) { + var result = []; + var fromNeedsReverse; + for (var i = 0; i < fromArr.length; i++) { + var fromSubpathBezier = fromArr[i]; + var toSubpathBezier = toArr[i]; + var fromCp = centroid$1(fromSubpathBezier); + var toCp = centroid$1(toSubpathBezier); + if (fromNeedsReverse == null) { + fromNeedsReverse = fromCp[2] < 0 !== toCp[2] < 0; + } + var newFromSubpathBezier = []; + var newToSubpathBezier = []; + var bestAngle = 0; + var bestScore = Infinity; + var tmpArr = []; + var len = fromSubpathBezier.length; + if (fromNeedsReverse) { + fromSubpathBezier = reverse(fromSubpathBezier); + } + var offset = findBestRingOffset(fromSubpathBezier, toSubpathBezier, fromCp, toCp) * 6; + var len2 = len - 2; + for (var k = 0; k < len2; k += 2) { + var idx = (offset + k) % len2 + 2; + newFromSubpathBezier[k + 2] = fromSubpathBezier[idx] - fromCp[0]; + newFromSubpathBezier[k + 3] = fromSubpathBezier[idx + 1] - fromCp[1]; + } + newFromSubpathBezier[0] = fromSubpathBezier[offset] - fromCp[0]; + newFromSubpathBezier[1] = fromSubpathBezier[offset + 1] - fromCp[1]; + if (searchAngleIteration > 0) { + var step = searchAngleRange / searchAngleIteration; + for (var angle = -searchAngleRange / 2; angle <= searchAngleRange / 2; angle += step) { + var sa = Math.sin(angle); + var ca = Math.cos(angle); + var score = 0; + for (var k = 0; k < fromSubpathBezier.length; k += 2) { + var x0 = newFromSubpathBezier[k]; + var y0 = newFromSubpathBezier[k + 1]; + var x1 = toSubpathBezier[k] - toCp[0]; + var y1 = toSubpathBezier[k + 1] - toCp[1]; + var newX1 = x1 * ca - y1 * sa; + var newY1 = x1 * sa + y1 * ca; + tmpArr[k] = newX1; + tmpArr[k + 1] = newY1; + var dx = newX1 - x0; + var dy = newY1 - y0; + score += dx * dx + dy * dy; + } + if (score < bestScore) { + bestScore = score; + bestAngle = angle; + for (var m = 0; m < tmpArr.length; m++) { + newToSubpathBezier[m] = tmpArr[m]; + } + } + } + } + else { + for (var i_1 = 0; i_1 < len; i_1 += 2) { + newToSubpathBezier[i_1] = toSubpathBezier[i_1] - toCp[0]; + newToSubpathBezier[i_1 + 1] = toSubpathBezier[i_1 + 1] - toCp[1]; + } + } + result.push({ + from: newFromSubpathBezier, + to: newToSubpathBezier, + fromCp: fromCp, + toCp: toCp, + rotation: -bestAngle + }); + } + return result; + } + function isCombineMorphing(path) { + return path.__isCombineMorphing; + } + var SAVED_METHOD_PREFIX = '__mOriginal_'; + function saveAndModifyMethod(obj, methodName, modifiers) { + var savedMethodName = SAVED_METHOD_PREFIX + methodName; + var originalMethod = obj[savedMethodName] || obj[methodName]; + if (!obj[savedMethodName]) { + obj[savedMethodName] = obj[methodName]; + } + var replace = modifiers.replace; + var after = modifiers.after; + var before = modifiers.before; + obj[methodName] = function () { + var args = arguments; + var res; + before && before.apply(this, args); + if (replace) { + res = replace.apply(this, args); + } + else { + res = originalMethod.apply(this, args); + } + after && after.apply(this, args); + return res; + }; + } + function restoreMethod(obj, methodName) { + var savedMethodName = SAVED_METHOD_PREFIX + methodName; + if (obj[savedMethodName]) { + obj[methodName] = obj[savedMethodName]; + obj[savedMethodName] = null; + } + } + function applyTransformOnBeziers(bezierCurves, mm) { + for (var i = 0; i < bezierCurves.length; i++) { + var subBeziers = bezierCurves[i]; + for (var k = 0; k < subBeziers.length;) { + var x = subBeziers[k]; + var y = subBeziers[k + 1]; + subBeziers[k++] = mm[0] * x + mm[2] * y + mm[4]; + subBeziers[k++] = mm[1] * x + mm[3] * y + mm[5]; + } + } + } + function prepareMorphPath(fromPath, toPath) { + var fromPathProxy = fromPath.getUpdatedPathProxy(); + var toPathProxy = toPath.getUpdatedPathProxy(); + var _a = alignBezierCurves(pathToBezierCurves(fromPathProxy), pathToBezierCurves(toPathProxy)), fromBezierCurves = _a[0], toBezierCurves = _a[1]; + var fromPathTransform = fromPath.getComputedTransform(); + var toPathTransform = toPath.getComputedTransform(); + function updateIdentityTransform() { + this.transform = null; + } + fromPathTransform && applyTransformOnBeziers(fromBezierCurves, fromPathTransform); + toPathTransform && applyTransformOnBeziers(toBezierCurves, toPathTransform); + saveAndModifyMethod(toPath, 'updateTransform', { replace: updateIdentityTransform }); + toPath.transform = null; + var morphingData = findBestMorphingRotation(fromBezierCurves, toBezierCurves, 10, Math.PI); + var tmpArr = []; + saveAndModifyMethod(toPath, 'buildPath', { replace: function (path) { + var t = toPath.__morphT; + var onet = 1 - t; + var newCp = []; + for (var i = 0; i < morphingData.length; i++) { + var item = morphingData[i]; + var from = item.from; + var to = item.to; + var angle = item.rotation * t; + var fromCp = item.fromCp; + var toCp = item.toCp; + var sa = Math.sin(angle); + var ca = Math.cos(angle); + lerp(newCp, fromCp, toCp, t); + for (var m = 0; m < from.length; m += 2) { + var x0_1 = from[m]; + var y0_1 = from[m + 1]; + var x1 = to[m]; + var y1 = to[m + 1]; + var x = x0_1 * onet + x1 * t; + var y = y0_1 * onet + y1 * t; + tmpArr[m] = (x * ca - y * sa) + newCp[0]; + tmpArr[m + 1] = (x * sa + y * ca) + newCp[1]; + } + var x0 = tmpArr[0]; + var y0 = tmpArr[1]; + path.moveTo(x0, y0); + for (var m = 2; m < from.length;) { + var x1 = tmpArr[m++]; + var y1 = tmpArr[m++]; + var x2 = tmpArr[m++]; + var y2 = tmpArr[m++]; + var x3 = tmpArr[m++]; + var y3 = tmpArr[m++]; + if (x0 === x1 && y0 === y1 && x2 === x3 && y2 === y3) { + path.lineTo(x3, y3); + } + else { + path.bezierCurveTo(x1, y1, x2, y2, x3, y3); + } + x0 = x3; + y0 = y3; + } + } + } }); + } + function morphPath(fromPath, toPath, animationOpts) { + if (!fromPath || !toPath) { + return toPath; + } + var oldDone = animationOpts.done; + var oldDuring = animationOpts.during; + prepareMorphPath(fromPath, toPath); + toPath.__morphT = 0; + function restoreToPath() { + restoreMethod(toPath, 'buildPath'); + restoreMethod(toPath, 'updateTransform'); + toPath.__morphT = -1; + toPath.createPathProxy(); + toPath.dirtyShape(); + } + toPath.animateTo({ + __morphT: 1 + }, defaults({ + during: function (p) { + toPath.dirtyShape(); + oldDuring && oldDuring(p); + }, + done: function () { + restoreToPath(); + oldDone && oldDone(); + } + }, animationOpts)); + return toPath; + } + function hilbert(x, y, minX, minY, maxX, maxY) { + var bits = 16; + x = (maxX === minX) ? 0 : Math.round(32767 * (x - minX) / (maxX - minX)); + y = (maxY === minY) ? 0 : Math.round(32767 * (y - minY) / (maxY - minY)); + var d = 0; + var tmp; + for (var s = (1 << bits) / 2; s > 0; s /= 2) { + var rx = 0; + var ry = 0; + if ((x & s) > 0) { + rx = 1; + } + if ((y & s) > 0) { + ry = 1; + } + d += s * s * ((3 * rx) ^ ry); + if (ry === 0) { + if (rx === 1) { + x = s - 1 - x; + y = s - 1 - y; + } + tmp = x; + x = y; + y = tmp; + } + } + return d; + } + function sortPaths(pathList) { + var xMin = Infinity; + var yMin = Infinity; + var xMax = -Infinity; + var yMax = -Infinity; + var cps = map(pathList, function (path) { + var rect = path.getBoundingRect(); + var m = path.getComputedTransform(); + var x = rect.x + rect.width / 2 + (m ? m[4] : 0); + var y = rect.y + rect.height / 2 + (m ? m[5] : 0); + xMin = Math.min(x, xMin); + yMin = Math.min(y, yMin); + xMax = Math.max(x, xMax); + yMax = Math.max(y, yMax); + return [x, y]; + }); + var items = map(cps, function (cp, idx) { + return { + cp: cp, + z: hilbert(cp[0], cp[1], xMin, yMin, xMax, yMax), + path: pathList[idx] + }; + }); + return items.sort(function (a, b) { return a.z - b.z; }).map(function (item) { return item.path; }); + } + function defaultDividePath(param) { + return split(param.path, param.count); + } + function createEmptyReturn() { + return { + fromIndividuals: [], + toIndividuals: [], + count: 0 + }; + } + function combineMorph(fromList, toPath, animationOpts) { + var fromPathList = []; + function addFromPath(fromList) { + for (var i = 0; i < fromList.length; i++) { + var from = fromList[i]; + if (isCombineMorphing(from)) { + addFromPath(from.childrenRef()); + } + else if (from instanceof Path) { + fromPathList.push(from); + } + } + } + addFromPath(fromList); + var separateCount = fromPathList.length; + if (!separateCount) { + return createEmptyReturn(); + } + var dividePath = animationOpts.dividePath || defaultDividePath; + var toSubPathList = dividePath({ + path: toPath, count: separateCount + }); + if (toSubPathList.length !== separateCount) { + console.error('Invalid morphing: unmatched splitted path'); + return createEmptyReturn(); + } + fromPathList = sortPaths(fromPathList); + toSubPathList = sortPaths(toSubPathList); + var oldDone = animationOpts.done; + var oldDuring = animationOpts.during; + var individualDelay = animationOpts.individualDelay; + var identityTransform = new Transformable(); + for (var i = 0; i < separateCount; i++) { + var from = fromPathList[i]; + var to = toSubPathList[i]; + to.parent = toPath; + to.copyTransform(identityTransform); + if (!individualDelay) { + prepareMorphPath(from, to); + } + } + toPath.__isCombineMorphing = true; + toPath.childrenRef = function () { + return toSubPathList; + }; + function addToSubPathListToZr(zr) { + for (var i = 0; i < toSubPathList.length; i++) { + toSubPathList[i].addSelfToZr(zr); + } + } + saveAndModifyMethod(toPath, 'addSelfToZr', { + after: function (zr) { + addToSubPathListToZr(zr); + } + }); + saveAndModifyMethod(toPath, 'removeSelfFromZr', { + after: function (zr) { + for (var i = 0; i < toSubPathList.length; i++) { + toSubPathList[i].removeSelfFromZr(zr); + } + } + }); + function restoreToPath() { + toPath.__isCombineMorphing = false; + toPath.__morphT = -1; + toPath.childrenRef = null; + restoreMethod(toPath, 'addSelfToZr'); + restoreMethod(toPath, 'removeSelfFromZr'); + } + var toLen = toSubPathList.length; + if (individualDelay) { + var animating_1 = toLen; + var eachDone = function () { + animating_1--; + if (animating_1 === 0) { + restoreToPath(); + oldDone && oldDone(); + } + }; + for (var i = 0; i < toLen; i++) { + var indivdualAnimationOpts = individualDelay ? defaults({ + delay: (animationOpts.delay || 0) + individualDelay(i, toLen, fromPathList[i], toSubPathList[i]), + done: eachDone + }, animationOpts) : animationOpts; + morphPath(fromPathList[i], toSubPathList[i], indivdualAnimationOpts); + } + } + else { + toPath.__morphT = 0; + toPath.animateTo({ + __morphT: 1 + }, defaults({ + during: function (p) { + for (var i = 0; i < toLen; i++) { + var child = toSubPathList[i]; + child.__morphT = toPath.__morphT; + child.dirtyShape(); + } + oldDuring && oldDuring(p); + }, + done: function () { + restoreToPath(); + for (var i = 0; i < fromList.length; i++) { + restoreMethod(fromList[i], 'updateTransform'); + } + oldDone && oldDone(); + } + }, animationOpts)); + } + if (toPath.__zr) { + addToSubPathListToZr(toPath.__zr); + } + return { + fromIndividuals: fromPathList, + toIndividuals: toSubPathList, + count: toLen + }; + } + function separateMorph(fromPath, toPathList, animationOpts) { + var toLen = toPathList.length; + var fromPathList = []; + var dividePath = animationOpts.dividePath || defaultDividePath; + function addFromPath(fromList) { + for (var i = 0; i < fromList.length; i++) { + var from = fromList[i]; + if (isCombineMorphing(from)) { + addFromPath(from.childrenRef()); + } + else if (from instanceof Path) { + fromPathList.push(from); + } + } + } + if (isCombineMorphing(fromPath)) { + addFromPath(fromPath.childrenRef()); + var fromLen = fromPathList.length; + if (fromLen < toLen) { + var k = 0; + for (var i = fromLen; i < toLen; i++) { + fromPathList.push(clonePath(fromPathList[k++ % fromLen])); + } + } + fromPathList.length = toLen; + } + else { + fromPathList = dividePath({ path: fromPath, count: toLen }); + var fromPathTransform = fromPath.getComputedTransform(); + for (var i = 0; i < fromPathList.length; i++) { + fromPathList[i].setLocalTransform(fromPathTransform); + } + if (fromPathList.length !== toLen) { + console.error('Invalid morphing: unmatched splitted path'); + return createEmptyReturn(); + } + } + fromPathList = sortPaths(fromPathList); + toPathList = sortPaths(toPathList); + var individualDelay = animationOpts.individualDelay; + for (var i = 0; i < toLen; i++) { + var indivdualAnimationOpts = individualDelay ? defaults({ + delay: (animationOpts.delay || 0) + individualDelay(i, toLen, fromPathList[i], toPathList[i]) + }, animationOpts) : animationOpts; + morphPath(fromPathList[i], toPathList[i], indivdualAnimationOpts); + } + return { + fromIndividuals: fromPathList, + toIndividuals: toPathList, + count: toPathList.length + }; + } + + function isMultiple(elements) { + return isArray(elements[0]); + } + + function prepareMorphBatches(one, many) { + var batches = []; + var batchCount = one.length; + + for (var i = 0; i < batchCount; i++) { + batches.push({ + one: one[i], + many: [] + }); + } + + for (var i = 0; i < many.length; i++) { + var len = many[i].length; + var k = void 0; + + for (k = 0; k < len; k++) { + batches[k % batchCount].many.push(many[i][k]); + } + } + + var off = 0; // If one has more paths than each one of many. average them. + + for (var i = batchCount - 1; i >= 0; i--) { + if (!batches[i].many.length) { + var moveFrom = batches[off].many; + + if (moveFrom.length <= 1) { + // Not enough + // Start from the first one. + if (off) { + off = 0; + } else { + return batches; + } + } + + var len = moveFrom.length; + var mid = Math.ceil(len / 2); + batches[i].many = moveFrom.slice(mid, len); + batches[off].many = moveFrom.slice(0, mid); + off++; + } + } + + return batches; + } + + var pathDividers = { + clone: function (params) { + var ret = []; // Fitting the alpha + + var approxOpacity = 1 - Math.pow(1 - params.path.style.opacity, 1 / params.count); + + for (var i = 0; i < params.count; i++) { + var cloned = clonePath(params.path); + cloned.setStyle('opacity', approxOpacity); + ret.push(cloned); + } + + return ret; + }, + // Use the default divider + split: null + }; + function applyMorphAnimation(from, to, divideShape, seriesModel, dataIndex, animateOtherProps) { + if (!from.length || !to.length) { + return; + } + + var updateAnimationCfg = getAnimationConfig('update', seriesModel, dataIndex); + + if (!(updateAnimationCfg && updateAnimationCfg.duration > 0)) { + return; + } + + var animationDelay = seriesModel.getModel('universalTransition').get('delay'); + var animationCfg = Object.assign({ + // Need to setToFinal so the further calculation based on the style can be correct. + // Like emphasis color. + setToFinal: true + }, updateAnimationCfg); + var many; + var one; + + if (isMultiple(from)) { + // manyToOne + many = from; + one = to; + } + + if (isMultiple(to)) { + // oneToMany + many = to; + one = from; + } + + function morphOneBatch(batch, fromIsMany, animateIndex, animateCount, forceManyOne) { + var batchMany = batch.many; + var batchOne = batch.one; + + if (batchMany.length === 1 && !forceManyOne) { + // Is one to one + var batchFrom = fromIsMany ? batchMany[0] : batchOne; + var batchTo = fromIsMany ? batchOne : batchMany[0]; + + if (isCombineMorphing(batchFrom)) { + // Keep doing combine animation. + morphOneBatch({ + many: [batchFrom], + one: batchTo + }, true, animateIndex, animateCount, true); + } else { + var individualAnimationCfg = animationDelay ? defaults({ + delay: animationDelay(animateIndex, animateCount) + }, animationCfg) : animationCfg; + morphPath(batchFrom, batchTo, individualAnimationCfg); + animateOtherProps(batchFrom, batchTo, batchFrom, batchTo, individualAnimationCfg); + } + } else { + var separateAnimationCfg = defaults({ + dividePath: pathDividers[divideShape], + individualDelay: animationDelay && function (idx, count, fromPath, toPath) { + return animationDelay(idx + animateIndex, animateCount); + } + }, animationCfg); + + var _a = fromIsMany ? combineMorph(batchMany, batchOne, separateAnimationCfg) : separateMorph(batchOne, batchMany, separateAnimationCfg), + fromIndividuals = _a.fromIndividuals, + toIndividuals = _a.toIndividuals; + + var count = fromIndividuals.length; + + for (var k = 0; k < count; k++) { + var individualAnimationCfg = animationDelay ? defaults({ + delay: animationDelay(k, count) + }, animationCfg) : animationCfg; + animateOtherProps(fromIndividuals[k], toIndividuals[k], fromIsMany ? batchMany[k] : batch.one, fromIsMany ? batch.one : batchMany[k], individualAnimationCfg); + } + } + } + + var fromIsMany = many ? many === from // Is one to one. If the path number not match. also needs do merge and separate morphing. + : from.length > to.length; + var morphBatches = many ? prepareMorphBatches(one, many) : prepareMorphBatches(fromIsMany ? to : from, [fromIsMany ? from : to]); + var animateCount = 0; + + for (var i = 0; i < morphBatches.length; i++) { + animateCount += morphBatches[i].many.length; + } + + var animateIndex = 0; + + for (var i = 0; i < morphBatches.length; i++) { + morphOneBatch(morphBatches[i], fromIsMany, animateIndex, animateCount); + animateIndex += morphBatches[i].many.length; + } + } + function getPathList(elements) { + if (!elements) { + return []; + } + + if (isArray(elements)) { + var pathList_1 = []; + + for (var i = 0; i < elements.length; i++) { + pathList_1.push(getPathList(elements[i])); + } + + return pathList_1; + } + + var pathList = []; + elements.traverse(function (el) { + if (el instanceof Path && !el.disableMorphing && !el.invisible && !el.ignore) { + pathList.push(el); + } + }); + return pathList; + } + + var DATA_COUNT_THRESHOLD = 1e4; + var getUniversalTransitionGlobalStore = makeInner(); + + function getGroupIdDimension(data) { + var dimensions = data.dimensions; + + for (var i = 0; i < dimensions.length; i++) { + var dimInfo = data.getDimensionInfo(dimensions[i]); + + if (dimInfo && dimInfo.otherDims.itemGroupId === 0) { + return dimensions[i]; + } + } + } + + function flattenDataDiffItems(list) { + var items = []; + each(list, function (seriesInfo) { + var data = seriesInfo.data; + + if (data.count() > DATA_COUNT_THRESHOLD) { + if ("development" !== 'production') { + warn('Universal transition is disabled on large data > 10k.'); + } + + return; + } + + var indices = data.getIndices(); + var groupDim = getGroupIdDimension(data); + + for (var dataIndex = 0; dataIndex < indices.length; dataIndex++) { + items.push({ + data: data, + dim: seriesInfo.dim || groupDim, + divide: seriesInfo.divide, + dataIndex: dataIndex + }); + } + }); + return items; + } + + function fadeInElement(newEl, newSeries, newIndex) { + newEl.traverse(function (el) { + if (el instanceof Path) { + // TODO use fade in animation for target element. + initProps(el, { + style: { + opacity: 0 + } + }, newSeries, { + dataIndex: newIndex, + isFrom: true + }); + } + }); + } + + function removeEl$1(el) { + if (el.parent) { + // Bake parent transform to element. + // So it can still have proper transform to transition after it's removed. + var computedTransform = el.getComputedTransform(); + el.setLocalTransform(computedTransform); + el.parent.remove(el); + } + } + + function stopAnimation(el) { + el.stopAnimation(); + + if (el.isGroup) { + el.traverse(function (child) { + child.stopAnimation(); + }); + } + } + + function animateElementStyles(el, dataIndex, seriesModel) { + var animationConfig = getAnimationConfig('update', seriesModel, dataIndex); + animationConfig && el.traverse(function (child) { + if (child instanceof Displayable) { + var oldStyle = getOldStyle(child); + + if (oldStyle) { + child.animateFrom({ + style: oldStyle + }, animationConfig); + } + } + }); + } + + function isAllIdSame(oldDiffItems, newDiffItems) { + var len = oldDiffItems.length; + + if (len !== newDiffItems.length) { + return false; + } + + for (var i = 0; i < len; i++) { + var oldItem = oldDiffItems[i]; + var newItem = newDiffItems[i]; + + if (oldItem.data.getId(oldItem.dataIndex) !== newItem.data.getId(newItem.dataIndex)) { + return false; + } + } + + return true; + } + + function transitionBetween(oldList, newList, api) { + var oldDiffItems = flattenDataDiffItems(oldList); + var newDiffItems = flattenDataDiffItems(newList); + + function updateMorphingPathProps(from, to, rawFrom, rawTo, animationCfg) { + if (rawFrom || from) { + to.animateFrom({ + style: rawFrom && rawFrom !== from ? // dividingMethod like clone may override the style(opacity) + // So extend it to raw style. + extend(extend({}, rawFrom.style), from.style) : from.style + }, animationCfg); + } + } + + function findKeyDim(items) { + for (var i = 0; i < items.length; i++) { + if (items[i].dim) { + return items[i].dim; + } + } + } + + var oldKeyDim = findKeyDim(oldDiffItems); + var newKeyDim = findKeyDim(newDiffItems); + var hasMorphAnimation = false; + + function createKeyGetter(isOld, onlyGetId) { + return function (diffItem) { + var data = diffItem.data; + var dataIndex = diffItem.dataIndex; // TODO if specified dim + + if (onlyGetId) { + return data.getId(dataIndex); + } // Use group id as transition key by default. + // So we can achieve multiple to multiple animation like drilldown / up naturally. + // If group id not exits. Use id instead. If so, only one to one transition will be applied. + + + var dataGroupId = data.hostModel && data.hostModel.get('dataGroupId'); // If specified key dimension(itemGroupId by default). Use this same dimension from other data. + // PENDING: If only use key dimension of newData. + + var keyDim = isOld ? oldKeyDim || newKeyDim : newKeyDim || oldKeyDim; + var dimInfo = keyDim && data.getDimensionInfo(keyDim); + var dimOrdinalMeta = dimInfo && dimInfo.ordinalMeta; + + if (dimInfo) { + // Get from encode.itemGroupId. + var key = data.get(dimInfo.name, dataIndex); + + if (dimOrdinalMeta) { + return dimOrdinalMeta.categories[key] || key + ''; + } + + return key + ''; + } // Get groupId from raw item. { groupId: '' } + + + var itemVal = data.getRawDataItem(dataIndex); + + if (itemVal && itemVal.groupId) { + return itemVal.groupId + ''; + } + + return dataGroupId || data.getId(dataIndex); + }; + } // Use id if it's very likely to be an one to one animation + // It's more robust than groupId + // TODO Check if key dimension is specified. + + + var useId = isAllIdSame(oldDiffItems, newDiffItems); + var isElementStillInChart = {}; + + if (!useId) { + // We may have different diff strategy with basicTransition if we use other dimension as key. + // If so, we can't simply check if oldEl is same with newEl. We need a map to check if oldEl is still being used in the new chart. + // We can't use the elements that already being morphed. Let it keep it's original basic transition. + for (var i = 0; i < newDiffItems.length; i++) { + var newItem = newDiffItems[i]; + var el = newItem.data.getItemGraphicEl(newItem.dataIndex); + + if (el) { + isElementStillInChart[el.id] = true; + } + } + } + + function updateOneToOne(newIndex, oldIndex) { + var oldItem = oldDiffItems[oldIndex]; + var newItem = newDiffItems[newIndex]; + var newSeries = newItem.data.hostModel; // TODO Mark this elements is morphed and don't morph them anymore + + var oldEl = oldItem.data.getItemGraphicEl(oldItem.dataIndex); + var newEl = newItem.data.getItemGraphicEl(newItem.dataIndex); // Can't handle same elements. + + if (oldEl === newEl) { + newEl && animateElementStyles(newEl, newItem.dataIndex, newSeries); + return; + } + + if ( // We can't use the elements that already being morphed + oldEl && isElementStillInChart[oldEl.id]) { + return; + } + + if (newEl) { + // TODO: If keep animating the group in case + // some of the elements don't want to be morphed. + // TODO Label? + stopAnimation(newEl); + + if (oldEl) { + stopAnimation(oldEl); // If old element is doing leaving animation. stop it and remove it immediately. + + removeEl$1(oldEl); + hasMorphAnimation = true; + applyMorphAnimation(getPathList(oldEl), getPathList(newEl), newItem.divide, newSeries, newIndex, updateMorphingPathProps); + } else { + fadeInElement(newEl, newSeries, newIndex); + } + } // else keep oldEl leaving animation. + + } + + new DataDiffer(oldDiffItems, newDiffItems, createKeyGetter(true, useId), createKeyGetter(false, useId), null, 'multiple').update(updateOneToOne).updateManyToOne(function (newIndex, oldIndices) { + var newItem = newDiffItems[newIndex]; + var newData = newItem.data; + var newSeries = newData.hostModel; + var newEl = newData.getItemGraphicEl(newItem.dataIndex); + var oldElsList = filter(map(oldIndices, function (idx) { + return oldDiffItems[idx].data.getItemGraphicEl(oldDiffItems[idx].dataIndex); + }), function (oldEl) { + return oldEl && oldEl !== newEl && !isElementStillInChart[oldEl.id]; + }); + + if (newEl) { + stopAnimation(newEl); + + if (oldElsList.length) { + // If old element is doing leaving animation. stop it and remove it immediately. + each(oldElsList, function (oldEl) { + stopAnimation(oldEl); + removeEl$1(oldEl); + }); + hasMorphAnimation = true; + applyMorphAnimation(getPathList(oldElsList), getPathList(newEl), newItem.divide, newSeries, newIndex, updateMorphingPathProps); + } else { + fadeInElement(newEl, newSeries, newItem.dataIndex); + } + } // else keep oldEl leaving animation. + + }).updateOneToMany(function (newIndices, oldIndex) { + var oldItem = oldDiffItems[oldIndex]; + var oldEl = oldItem.data.getItemGraphicEl(oldItem.dataIndex); // We can't use the elements that already being morphed + + if (oldEl && isElementStillInChart[oldEl.id]) { + return; + } + + var newElsList = filter(map(newIndices, function (idx) { + return newDiffItems[idx].data.getItemGraphicEl(newDiffItems[idx].dataIndex); + }), function (el) { + return el && el !== oldEl; + }); + var newSeris = newDiffItems[newIndices[0]].data.hostModel; + + if (newElsList.length) { + each(newElsList, function (newEl) { + return stopAnimation(newEl); + }); + + if (oldEl) { + stopAnimation(oldEl); // If old element is doing leaving animation. stop it and remove it immediately. + + removeEl$1(oldEl); + hasMorphAnimation = true; + applyMorphAnimation(getPathList(oldEl), getPathList(newElsList), oldItem.divide, // Use divide on old. + newSeris, newIndices[0], updateMorphingPathProps); + } else { + each(newElsList, function (newEl) { + return fadeInElement(newEl, newSeris, newIndices[0]); + }); + } + } // else keep oldEl leaving animation. + + }).updateManyToMany(function (newIndices, oldIndices) { + // If two data are same and both have groupId. + // Normally they should be diff by id. + new DataDiffer(oldIndices, newIndices, function (rawIdx) { + return oldDiffItems[rawIdx].data.getId(oldDiffItems[rawIdx].dataIndex); + }, function (rawIdx) { + return newDiffItems[rawIdx].data.getId(newDiffItems[rawIdx].dataIndex); + }).update(function (newIndex, oldIndex) { + // Use the original index + updateOneToOne(newIndices[newIndex], oldIndices[oldIndex]); + }).execute(); + }).execute(); + + if (hasMorphAnimation) { + each(newList, function (_a) { + var data = _a.data; + var seriesModel = data.hostModel; + var view = seriesModel && api.getViewOfSeriesModel(seriesModel); + var animationCfg = getAnimationConfig('update', seriesModel, 0); // use 0 index. + + if (view && seriesModel.isAnimationEnabled() && animationCfg && animationCfg.duration > 0) { + view.group.traverse(function (el) { + if (el instanceof Path && !el.animators.length) { + // We can't accept there still exists element that has no animation + // if universalTransition is enabled + el.animateFrom({ + style: { + opacity: 0 + } + }, animationCfg); + } + }); + } + }); + } + } + + function getSeriesTransitionKey(series) { + var seriesKey = series.getModel('universalTransition').get('seriesKey'); + + if (!seriesKey) { + // Use series id by default. + return series.id; + } + + return seriesKey; + } + + function convertArraySeriesKeyToString(seriesKey) { + if (isArray(seriesKey)) { + // Order independent. + return seriesKey.sort().join(','); + } + + return seriesKey; + } + + function getDivideShapeFromData(data) { + if (data.hostModel) { + return data.hostModel.getModel('universalTransition').get('divideShape'); + } + } + + function findTransitionSeriesBatches(globalStore, params) { + var updateBatches = createHashMap(); + var oldDataMap = createHashMap(); // Map that only store key in array seriesKey. + // Which is used to query the old data when transition from one to multiple series. + + var oldDataMapForSplit = createHashMap(); + each(globalStore.oldSeries, function (series, idx) { + var oldData = globalStore.oldData[idx]; + var transitionKey = getSeriesTransitionKey(series); + var transitionKeyStr = convertArraySeriesKeyToString(transitionKey); + oldDataMap.set(transitionKeyStr, oldData); + + if (isArray(transitionKey)) { + // Same key can't in different array seriesKey. + each(transitionKey, function (key) { + oldDataMapForSplit.set(key, { + data: oldData, + key: transitionKeyStr + }); + }); + } + }); + + function checkTransitionSeriesKeyDuplicated(transitionKeyStr) { + if (updateBatches.get(transitionKeyStr)) { + warn("Duplicated seriesKey in universalTransition " + transitionKeyStr); + } + } + + each(params.updatedSeries, function (series) { + if (series.isUniversalTransitionEnabled() && series.isAnimationEnabled()) { + var newData = series.getData(); + var transitionKey = getSeriesTransitionKey(series); + var transitionKeyStr = convertArraySeriesKeyToString(transitionKey); // Only transition between series with same id. + + var oldData = oldDataMap.get(transitionKeyStr); // string transition key is the best match. + + if (oldData) { + if ("development" !== 'production') { + checkTransitionSeriesKeyDuplicated(transitionKeyStr); + } // TODO check if data is same? + + + updateBatches.set(transitionKeyStr, { + oldSeries: [{ + divide: getDivideShapeFromData(oldData), + data: oldData + }], + newSeries: [{ + divide: getDivideShapeFromData(newData), + data: newData + }] + }); + } else { + // Transition from multiple series. + if (isArray(transitionKey)) { + if ("development" !== 'production') { + checkTransitionSeriesKeyDuplicated(transitionKeyStr); + } + + var oldSeries_1 = []; + each(transitionKey, function (key) { + var oldData = oldDataMap.get(key); + + if (oldData) { + oldSeries_1.push({ + divide: getDivideShapeFromData(oldData), + data: oldData + }); + } + }); + + if (oldSeries_1.length) { + updateBatches.set(transitionKeyStr, { + oldSeries: oldSeries_1, + newSeries: [{ + data: newData, + divide: getDivideShapeFromData(newData) + }] + }); + } + } else { + // Try transition to multiple series. + var oldData_1 = oldDataMapForSplit.get(transitionKey); + + if (oldData_1) { + var batch = updateBatches.get(oldData_1.key); + + if (!batch) { + batch = { + oldSeries: [{ + data: oldData_1.data, + divide: getDivideShapeFromData(oldData_1.data) + }], + newSeries: [] + }; + updateBatches.set(oldData_1.key, batch); + } + + batch.newSeries.push({ + data: newData, + divide: getDivideShapeFromData(newData) + }); + } + } + } + } + }); + return updateBatches; + } + + function querySeries(series, finder) { + for (var i = 0; i < series.length; i++) { + var found = finder.seriesIndex != null && finder.seriesIndex === series[i].seriesIndex || finder.seriesId != null && finder.seriesId === series[i].id; + + if (found) { + return i; + } + } + } + + function transitionSeriesFromOpt(transitionOpt, globalStore, params, api) { + var from = []; + var to = []; + each(normalizeToArray(transitionOpt.from), function (finder) { + var idx = querySeries(globalStore.oldSeries, finder); + + if (idx >= 0) { + from.push({ + data: globalStore.oldData[idx], + // TODO can specify divideShape in transition. + divide: getDivideShapeFromData(globalStore.oldData[idx]), + dim: finder.dimension + }); + } + }); + each(normalizeToArray(transitionOpt.to), function (finder) { + var idx = querySeries(params.updatedSeries, finder); + + if (idx >= 0) { + var data = params.updatedSeries[idx].getData(); + to.push({ + data: data, + divide: getDivideShapeFromData(data), + dim: finder.dimension + }); + } + }); + + if (from.length > 0 && to.length > 0) { + transitionBetween(from, to, api); + } + } + + function installUniversalTransition(registers) { + registers.registerUpdateLifecycle('series:beforeupdate', function (ecMOdel, api, params) { + each(normalizeToArray(params.seriesTransition), function (transOpt) { + each(normalizeToArray(transOpt.to), function (finder) { + var series = params.updatedSeries; + + for (var i = 0; i < series.length; i++) { + if (finder.seriesIndex != null && finder.seriesIndex === series[i].seriesIndex || finder.seriesId != null && finder.seriesId === series[i].id) { + series[i][SERIES_UNIVERSAL_TRANSITION_PROP] = true; + } + } + }); + }); + }); + registers.registerUpdateLifecycle('series:transition', function (ecModel, api, params) { + // TODO api provide an namespace that can save stuff per instance + var globalStore = getUniversalTransitionGlobalStore(api); // TODO multiple to multiple series. + + if (globalStore.oldSeries && params.updatedSeries && params.optionChanged) { + // Use give transition config if its' give; + var transitionOpt = params.seriesTransition; + + if (transitionOpt) { + each(normalizeToArray(transitionOpt), function (opt) { + transitionSeriesFromOpt(opt, globalStore, params, api); + }); + } else { + // Else guess from series based on transition series key. + var updateBatches_1 = findTransitionSeriesBatches(globalStore, params); + each(updateBatches_1.keys(), function (key) { + var batch = updateBatches_1.get(key); + transitionBetween(batch.oldSeries, batch.newSeries, api); + }); + } // Reset + + + each(params.updatedSeries, function (series) { + // Reset; + if (series[SERIES_UNIVERSAL_TRANSITION_PROP]) { + series[SERIES_UNIVERSAL_TRANSITION_PROP] = false; + } + }); + } // Save all series of current update. Not only the updated one. + + + var allSeries = ecModel.getSeries(); + var savedSeries = globalStore.oldSeries = []; + var savedData = globalStore.oldData = []; + + for (var i = 0; i < allSeries.length; i++) { + var data = allSeries[i].getData(); // Only save the data that can have transition. + // Avoid large data costing too much extra memory + + if (data.count() < DATA_COUNT_THRESHOLD) { + savedSeries.push(allSeries[i]); + savedData.push(data); + } + } + }); + } + + // Render engines + // ----------------- + // Render via Canvas. + // echarts.init(dom, null, { renderer: 'canvas' }) + + use([install$1]); // Render via SVG. + // echarts.init(dom, null, { renderer: 'svg' }) + + use([install]); // ---------------- + // Charts (series) + // ---------------- + // All of the series types, for example: + // chart.setOption({ + // series: [{ + // type: 'line' // or 'bar', 'pie', ... + // }] + // }); + + use([install$2, install$3, install$4, install$6, install$8, install$a, install$b, install$c, install$d, install$e, install$f, install$h, install$i, install$j, install$k, install$l, install$m, install$n, install$o, install$p, install$q, install$r]); // ------------------- + // Coordinate systems + // ------------------- + // All of the axis modules have been included in the + // coordinate system module below, do not need to + // make extra import. + // `cartesian` coordinate system. For some historical + // reasons, it is named as grid, for example: + // chart.setOption({ + // grid: {...}, + // xAxis: {...}, + // yAxis: {...}, + // series: [{...}] + // }); + + use(install$t); // `polar` coordinate system, for example: + // chart.setOption({ + // polar: {...}, + // radiusAxis: {...}, + // angleAxis: {...}, + // series: [{ + // coordinateSystem: 'polar' + // }] + // }); + + use(install$u); // `geo` coordinate system, for example: + // chart.setOption({ + // geo: {...}, + // series: [{ + // coordinateSystem: 'geo' + // }] + // }); + + use(install$9); // `singleAxis` coordinate system (notice, it is a coordinate system + // with only one axis, work for chart like theme river), for example: + // chart.setOption({ + // singleAxis: {...} + // series: [{type: 'themeRiver', ...}] + // }); + + use(install$v); // `parallel` coordinate system, only work for parallel series, for example: + // chart.setOption({ + // parallel: {...}, + // parallelAxis: [{...}, ...], + // series: [{ + // type: 'parallel' + // }] + // }); + + use(install$g); // `calendar` coordinate system. for example, + // chart.setOptionp({ + // calendar: {...}, + // series: [{ + // coordinateSystem: 'calendar' + // }] + // ); + + use(install$w); // ------------------ + // Other components + // ------------------ + // `graphic` component, for example: + // chart.setOption({ + // graphic: {...} + // }); + + use(install$x); // `toolbox` component, for example: + // chart.setOption({ + // toolbox: {...} + // }); + + use(install$z); // `tooltip` component, for example: + // chart.setOption({ + // tooltip: {...} + // }); + + use(install$A); // `axisPointer` component, for example: + // chart.setOption({ + // tooltip: {axisPointer: {...}, ...} + // }); + // Or + // chart.setOption({ + // axisPointer: {...} + // }); + + use(install$s); // `brush` component, for example: + // chart.setOption({ + // brush: {...} + // }); + // Or + // chart.setOption({ + // tooltip: {feature: {brush: {...}} + // }) + + use(install$B); // `title` component, for example: + // chart.setOption({ + // title: {...} + // }); + + use(install$C); // `timeline` component, for example: + // chart.setOption({ + // timeline: {...} + // }); + + use(install$D); // `markPoint` component, for example: + // chart.setOption({ + // series: [{markPoint: {...}}] + // }); + + use(install$E); // `markLine` component, for example: + // chart.setOption({ + // series: [{markLine: {...}}] + // }); + + use(install$F); // `markArea` component, for example: + // chart.setOption({ + // series: [{markArea: {...}}] + // }); + + use(install$G); // `legend` component not scrollable. for example: + // chart.setOption({ + // legend: {...} + // }); + + use(install$J); // `dataZoom` component including both `dataZoomInside` and `dataZoomSlider`. + + use(install$M); // `dataZoom` component providing drag, pinch, wheel behaviors + // inside coodinate system, for example: + // chart.setOption({ + // dataZoom: {type: 'inside'} + // }); + + use(install$K); // `dataZoom` component providing a slider bar, for example: + // chart.setOption({ + // dataZoom: {type: 'slider'} + // }); + + use(install$L); // `visualMap` component including both `visualMapContinuous` and `visualMapPiecewise`. + + use(install$P); // `visualMap` component providing continuous bar, for example: + // chart.setOption({ + // visualMap: {type: 'continuous'} + // }); + + use(install$N); // `visualMap` component providing pieces bar, for example: + // chart.setOption({ + // visualMap: {type: 'piecewise'} + // }); + + use(install$O); // `aria` component providing aria, for example: + // chart.setOption({ + // aria: {...} + // }); + + use(install$Q); // dataset transform + // chart.setOption({ + // dataset: { + // transform: [] + // } + // }); + + use(install$R); + use(install$S); // universal transition + // chart.setOption({ + // series: { + // universalTransition: { enabled: true } + // } + // }) + + use(installUniversalTransition); // label layout + // chart.setOption({ + // series: { + // labelLayout: { hideOverlap: true } + // } + // }) + + use(installLabelLayout); + + exports.Axis = Axis; + exports.ChartView = ChartView; + exports.ComponentModel = ComponentModel; + exports.ComponentView = ComponentView; + exports.List = SeriesData; + exports.Model = Model; + exports.PRIORITY = PRIORITY; + exports.SeriesModel = SeriesModel; + exports.color = color; + exports.connect = connect; + exports.dataTool = dataTool; + exports.dependencies = dependencies; + exports.disConnect = disConnect; + exports.disconnect = disconnect; + exports.dispose = dispose$1; + exports.env = env; + exports.extendChartView = extendChartView; + exports.extendComponentModel = extendComponentModel; + exports.extendComponentView = extendComponentView; + exports.extendSeriesModel = extendSeriesModel; + exports.format = format$1; + exports.getCoordinateSystemDimensions = getCoordinateSystemDimensions; + exports.getInstanceByDom = getInstanceByDom; + exports.getInstanceById = getInstanceById; + exports.getMap = getMap; + exports.graphic = graphic$1; + exports.helper = helper; + exports.init = init$1; + exports.innerDrawElementOnCanvas = brushSingle; + exports.matrix = matrix; + exports.number = number; + exports.parseGeoJSON = parseGeoJSON; + exports.parseGeoJson = parseGeoJSON; + exports.registerAction = registerAction; + exports.registerCoordinateSystem = registerCoordinateSystem; + exports.registerLayout = registerLayout; + exports.registerLoading = registerLoading; + exports.registerLocale = registerLocale; + exports.registerMap = registerMap; + exports.registerPostInit = registerPostInit; + exports.registerPostUpdate = registerPostUpdate; + exports.registerPreprocessor = registerPreprocessor; + exports.registerProcessor = registerProcessor; + exports.registerTheme = registerTheme; + exports.registerTransform = registerTransform; + exports.registerUpdateLifecycle = registerUpdateLifecycle; + exports.registerVisual = registerVisual; + exports.setCanvasCreator = setCanvasCreator; + exports.setPlatformAPI = setPlatformAPI; + exports.throttle = throttle; + exports.time = time; + exports.use = use; + exports.util = util$1; + exports.vector = vector; + exports.version = version$1; + exports.zrUtil = util; + exports.zrender = zrender; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); + +layui.define('echartsTheme', function(exports) { + echarts.registerTheme('walden', layui.echartsTheme); + exports('echarts', echarts); +}); \ No newline at end of file diff --git a/static/system/component/pear/module/extends/echartsTheme.js b/static/system/component/pear/module/extends/echartsTheme.js new file mode 100644 index 0000000..c0c029b --- /dev/null +++ b/static/system/component/pear/module/extends/echartsTheme.js @@ -0,0 +1,450 @@ +layui.define(function (exports) { + exports('echartsTheme', + { + "color": [ + "#3fb1e3", + "#6be6c1", + "#626c91", + "#a0a7e6", + "#c4ebad", + "#96dee8" + ], + "backgroundColor": "rgba(252,252,252,0)", + "textStyle": {}, + "title": { + "textStyle": { + "color": "#666666" + }, + "subtextStyle": { + "color": "#999999" + } + }, + "line": { + "itemStyle": { + "borderWidth": "3" + }, + "lineStyle": { + "width": "4" + }, + "symbolSize": "10", + "symbol": "emptyCircle", + "smooth": true + }, + "radar": { + "itemStyle": { + "borderWidth": "3" + }, + "lineStyle": { + "width": "4" + }, + "symbolSize": "10", + "symbol": "emptyCircle", + "smooth": true + }, + "bar": { + "itemStyle": { + "barBorderWidth": 0, + "barBorderColor": "#ccc" + }, + "emphasis": { + "itemStyle": { + "barBorderWidth": 0, + "barBorderColor": "#ccc" + } + } + }, + "pie": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "scatter": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "boxplot": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + + }, + "emphasis": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "parallel": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "sankey": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "funnel": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "gauge": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "candlestick": { + "itemStyle": { + "color": "#e6a0d2", + "color0": "transparent", + "borderColor": "#e6a0d2", + "borderColor0": "#3fb1e3", + "borderWidth": "2" + } + }, + "graph": { + "itemStyle": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "lineStyle": { + "width": "1", + "color": "#cccccc" + }, + "symbolSize": "10", + "symbol": "emptyCircle", + "smooth": true, + "color": [ + "#3fb1e3", + "#6be6c1", + "#626c91", + "#a0a7e6", + "#c4ebad", + "#96dee8" + ], + "label": { + "color": "#ffffff" + } + }, + "map": { + "itemStyle": { + "areaColor": "#eeeeee", + "borderColor": "#aaaaaa", + "borderWidth": 0.5 + }, + "label": { + "color": "#ffffff" + }, + "emphasis": { + "itemStyle": { + "areaColor": "rgba(63,177,227,0.25)", + "borderColor": "#3fb1e3", + "borderWidth": 1 + }, + "label": { + "color": "rgb(63,177,227)" + } + } + }, + "geo": { + "itemStyle": { + "areaColor": "#eeeeee", + "borderColor": "#aaaaaa", + "borderWidth": 0.5 + }, + "label": { + "color": "#ffffff" + }, + "emphasis": { + "itemStyle": { + "areaColor": "rgba(63,177,227,0.25)", + "borderColor": "#3fb1e3", + "borderWidth": 1 + }, + "label": { + "color": "rgb(63,177,227)" + } + } + }, + "categoryAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + + "color": "#999999" + + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "valueAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "color": "#999999" + + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "logAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "color": "#999999" + + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "timeAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + + "color": "#999999" + + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "toolbox": { + "iconStyle": { + "borderColor": "#999999" + }, + "emphasis": { + "iconStyle": { + "borderColor": "#666666" + } + } + }, + "legend": { + "textStyle": { + "color": "#999999" + } + }, + "tooltip": { + "axisPointer": { + "lineStyle": { + "color": "#cccccc", + "width": 1 + }, + "crossStyle": { + "color": "#cccccc", + "width": 1 + } + } + }, + "timeline": { + "lineStyle": { + "color": "#626c91", + "width": 1 + }, + "itemStyle": { + "color": "#626c91", + "borderWidth": 1 + + }, + "controlStyle": { + "color": "#626c91", + "borderColor": "#626c91", + "borderWidth": 0.5 + }, + "checkpointStyle": { + "color": "#3fb1e3", + "borderColor": "rgba(63,177,227,0.15)" + }, + "label": { + "color": "#626c91" + }, + "emphasis": { + "itemStyle": { + "color": "#626c91" + }, + "controlStyle": { + "color": "#626c91", + "borderColor": "#626c91", + "borderWidth": 0.5 + }, + "label": { + "color": "#626c91" + } + } + }, + "visualMap": { + "color": [ + "#2a99c9", + "#afe8ff" + ] + }, + "dataZoom": { + "backgroundColor": "rgba(255,255,255,0)", + "dataBackgroundColor": "rgba(222,222,222,1)", + "fillerColor": "rgba(114,230,212,0.25)", + "handleColor": "#cccccc", + "handleSize": "100%", + "textStyle": { + "color": "#999999" + } + }, + "markPoint": { + "label": { + "color": "#ffffff" + }, + "emphasis": { + "label": { + "color": "#ffffff" + } + } + } + }); +}); \ No newline at end of file diff --git a/static/system/component/pear/module/extends/nprogress.js b/static/system/component/pear/module/extends/nprogress.js new file mode 100644 index 0000000..882039a --- /dev/null +++ b/static/system/component/pear/module/extends/nprogress.js @@ -0,0 +1,503 @@ +/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT */ + +;(function(root, factory) { + + if (typeof define === 'function' && define.amd) { + define(factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + root.NProgress = factory(); + } + +})(this, function() { + var NProgress = {}; + + NProgress.version = '0.2.0'; + + var Settings = NProgress.settings = { + minimum: 0.08, + easing: 'linear', + positionUsing: '', + speed: 200, + trickle: true, + trickleSpeed: 200, + showSpinner: true, + barSelector: '[role="bar"]', + spinnerSelector: '[role="spinner"]', + parent: 'body', + template: '
            ' + }; + + /** + * Updates configuration. + * + * NProgress.configure({ + * minimum: 0.1 + * }); + */ + NProgress.configure = function(options) { + var key, value; + for (key in options) { + value = options[key]; + if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value; + } + + return this; + }; + + /** + * Last number. + */ + + NProgress.status = null; + + /** + * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`. + * + * NProgress.set(0.4); + * NProgress.set(1.0); + */ + + NProgress.set = function(n) { + var started = NProgress.isStarted(); + + n = clamp(n, Settings.minimum, 1); + NProgress.status = (n === 1 ? null : n); + + var progress = NProgress.render(!started), + bar = progress.querySelector(Settings.barSelector), + speed = Settings.speed, + ease = Settings.easing; + + progress.offsetWidth; /* Repaint */ + + queue(function(next) { + // Set positionUsing if it hasn't already been set + if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS(); + + // Add transition + css(bar, barPositionCSS(n, speed, ease)); + + if (n === 1) { + // Fade out + css(progress, { + transition: 'none', + opacity: 1 + }); + progress.offsetWidth; /* Repaint */ + + setTimeout(function() { + css(progress, { + transition: 'all ' + speed + 'ms linear', + opacity: 0 + }); + setTimeout(function() { + NProgress.remove(); + next(); + }, speed); + }, speed); + } else { + setTimeout(next, speed); + } + }); + + return this; + }; + + NProgress.isStarted = function() { + return typeof NProgress.status === 'number'; + }; + + /** + * Shows the progress bar. + * This is the same as setting the status to 0%, except that it doesn't go backwards. + * + * NProgress.start(); + * + */ + NProgress.start = function() { + if (!NProgress.status) NProgress.set(0); + + var work = function() { + setTimeout(function() { + if (!NProgress.status) return; + NProgress.trickle(); + work(); + }, Settings.trickleSpeed); + }; + + if (Settings.trickle) work(); + + return this; + }; + + /** + * Hides the progress bar. + * This is the *sort of* the same as setting the status to 100%, with the + * difference being `done()` makes some placebo effect of some realistic motion. + * + * NProgress.done(); + * + * If `true` is passed, it will show the progress bar even if its hidden. + * + * NProgress.done(true); + */ + + NProgress.done = function(force) { + if (!force && !NProgress.status) return this; + + return NProgress.inc(0.3 + 0.5 * Math.random()).set(1); + }; + + /** + * Increments by a random amount. + */ + + NProgress.inc = function(amount) { + var n = NProgress.status; + + if (!n) { + return NProgress.start(); + } else if(n > 1) { + return; + } else { + if (typeof amount !== 'number') { + if (n >= 0 && n < 0.2) { amount = 0.1; } + else if (n >= 0.2 && n < 0.5) { amount = 0.04; } + else if (n >= 0.5 && n < 0.8) { amount = 0.02; } + else if (n >= 0.8 && n < 0.99) { amount = 0.005; } + else { amount = 0; } + } + + n = clamp(n + amount, 0, 0.994); + return NProgress.set(n); + } + }; + + NProgress.trickle = function() { + return NProgress.inc(); + }; + + /** + * Waits for all supplied jQuery promises and + * increases the progress as the promises resolve. + * + * @param $promise jQUery Promise + */ + (function() { + var initial = 0, current = 0; + + NProgress.promise = function($promise) { + if (!$promise || $promise.state() === "resolved") { + return this; + } + + if (current === 0) { + NProgress.start(); + } + + initial++; + current++; + + $promise.always(function() { + current--; + if (current === 0) { + initial = 0; + NProgress.done(); + } else { + NProgress.set((initial - current) / initial); + } + }); + + return this; + }; + + })(); + + /** + * (Internal) renders the progress bar markup based on the `template` + * setting. + */ + + NProgress.render = function(fromStart) { + if (NProgress.isRendered()) return document.getElementById('nprogress'); + + addClass(document.documentElement, 'nprogress-busy'); + + var progress = document.createElement('div'); + progress.id = 'nprogress'; + progress.innerHTML = Settings.template; + + + + var bar = progress.querySelector(Settings.barSelector), + perc = fromStart ? '-100' : toBarPerc(NProgress.status || 0), + parent = isDOM(Settings.parent) + ? Settings.parent + : document.querySelector(Settings.parent), + spinner + + css(bar, { + transition: 'all 0 linear', + transform: 'translate3d(' + perc + '%,0,0)' + }); + + if (!Settings.showSpinner) { + spinner = progress.querySelector(Settings.spinnerSelector); + spinner && removeElement(spinner); + } + + if (parent != document.body) { + addClass(parent, 'nprogress-custom-parent'); + } + + parent.appendChild(progress); + return progress; + }; + + /** + * Removes the element. Opposite of render(). + */ + + NProgress.remove = function() { + removeClass(document.documentElement, 'nprogress-busy'); + var parent = isDOM(Settings.parent) + ? Settings.parent + : document.querySelector(Settings.parent) + removeClass(parent, 'nprogress-custom-parent') + var progress = document.getElementById('nprogress'); + progress && removeElement(progress); + }; + + /** + * Checks if the progress bar is rendered. + */ + + NProgress.isRendered = function() { + return !!document.getElementById('nprogress'); + }; + + /** + * Determine which positioning CSS rule to use. + */ + + NProgress.getPositioningCSS = function() { + // Sniff on document.body.style + var bodyStyle = document.body.style; + + // Sniff prefixes + var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' : + ('MozTransform' in bodyStyle) ? 'Moz' : + ('msTransform' in bodyStyle) ? 'ms' : + ('OTransform' in bodyStyle) ? 'O' : ''; + + if (vendorPrefix + 'Perspective' in bodyStyle) { + // Modern browsers with 3D support, e.g. Webkit, IE10 + return 'translate3d'; + } else if (vendorPrefix + 'Transform' in bodyStyle) { + // Browsers without 3D support, e.g. IE9 + return 'translate'; + } else { + // Browsers without translate() support, e.g. IE7-8 + return 'margin'; + } + }; + + /** + * Helpers + */ + + function isDOM (obj) { + if (typeof HTMLElement === 'object') { + return obj instanceof HTMLElement + } + return ( + obj && + typeof obj === 'object' && + obj.nodeType === 1 && + typeof obj.nodeName === 'string' + ) + } + + function clamp(n, min, max) { + if (n < min) return min; + if (n > max) return max; + return n; + } + + /** + * (Internal) converts a percentage (`0..1`) to a bar translateX + * percentage (`-100%..0%`). + */ + + function toBarPerc(n) { + return (-1 + n) * 100; + } + + + /** + * (Internal) returns the correct CSS for changing the bar's + * position given an n percentage, and speed and ease from Settings + */ + + function barPositionCSS(n, speed, ease) { + var barCSS; + + if (Settings.positionUsing === 'translate3d') { + barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' }; + } else if (Settings.positionUsing === 'translate') { + barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' }; + } else { + barCSS = { 'margin-left': toBarPerc(n)+'%' }; + } + + barCSS.transition = 'all '+speed+'ms '+ease; + + return barCSS; + } + + /** + * (Internal) Queues a function to be executed. + */ + + var queue = (function() { + var pending = []; + + function next() { + var fn = pending.shift(); + if (fn) { + fn(next); + } + } + + return function(fn) { + pending.push(fn); + if (pending.length == 1) next(); + }; + })(); + + /** + * (Internal) Applies css properties to an element, similar to the jQuery + * css method. + * + * While this helper does assist with vendor prefixed property names, it + * does not perform any manipulation of values prior to setting styles. + */ + + var css = (function() { + var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ], + cssProps = {}; + + function camelCase(string) { + return string.replace(/^-ms-/, 'ms-').replace(/-([\da-z])/gi, function(match, letter) { + return letter.toUpperCase(); + }); + } + + function getVendorProp(name) { + var style = document.body.style; + if (name in style) return name; + + var i = cssPrefixes.length, + capName = name.charAt(0).toUpperCase() + name.slice(1), + vendorName; + while (i--) { + vendorName = cssPrefixes[i] + capName; + if (vendorName in style) return vendorName; + } + + return name; + } + + function getStyleProp(name) { + name = camelCase(name); + return cssProps[name] || (cssProps[name] = getVendorProp(name)); + } + + function applyCss(element, prop, value) { + prop = getStyleProp(prop); + element.style[prop] = value; + } + + return function(element, properties) { + var args = arguments, + prop, + value; + + if (args.length == 2) { + for (prop in properties) { + value = properties[prop]; + if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value); + } + } else { + applyCss(element, args[1], args[2]); + } + } + })(); + + /** + * (Internal) Determines if an element or space separated list of class names contains a class name. + */ + + function hasClass(element, name) { + var list = typeof element == 'string' ? element : classList(element); + return list.indexOf(' ' + name + ' ') >= 0; + } + + /** + * (Internal) Adds a class to an element. + */ + + function addClass(element, name) { + var oldList = classList(element), + newList = oldList + name; + + if (hasClass(oldList, name)) return; + + // Trim the opening space. + element.className = newList.substring(1); + } + + /** + * (Internal) Removes a class from an element. + */ + + function removeClass(element, name) { + var oldList = classList(element), + newList; + + if (!hasClass(element, name)) return; + + // Replace the class name. + newList = oldList.replace(' ' + name + ' ', ' '); + + // Trim the opening and closing spaces. + element.className = newList.substring(1, newList.length - 1); + } + + /** + * (Internal) Gets a space separated list of the class names on the element. + * The list is wrapped with a single space on each end to facilitate finding + * matches within the list. + */ + + function classList(element) { + return (' ' + (element && element.className || '') + ' ').replace(/\s+/gi, ' '); + } + + /** + * (Internal) Removes an element from the DOM. + */ + + function removeElement(element) { + element && element.parentNode && element.parentNode.removeChild(element); + } + + return NProgress; +}); + +layui.define([], function(exports) { + exports('nprogress', NProgress); +}); \ No newline at end of file diff --git a/static/system/component/pear/module/extends/popup.js b/static/system/component/pear/module/extends/popup.js new file mode 100644 index 0000000..769ed93 --- /dev/null +++ b/static/system/component/pear/module/extends/popup.js @@ -0,0 +1,47 @@ +layui.define(['layer'], function(exports) { + "use strict"; + + var MOD_NAME = 'popup', + layer = layui.layer; + + var popup = new function() { + + this.success = function(msg) { + layer.msg(msg, { + icon: 1, + time: 1000 + }) + }, + this.failure = function(msg) { + layer.msg(msg, { + icon: 2, + time: 1000 + }) + }, + this.warning = function(msg) { + layer.msg(msg, { + icon: 3, + time: 1000 + }) + }, + this.success = function(msg, callback) { + layer.msg(msg, { + icon: 1, + time: 1000 + }, callback); + }, + this.failure = function(msg, callback) { + layer.msg(msg, { + icon: 2, + time: 1000 + }, callback); + }, + this.warming = function(msg, callback) { + layer.msg(msg, { + icon: 3, + time: 1000 + }, callback); + } + }; + exports(MOD_NAME, popup); +}) diff --git a/static/system/component/pear/module/extends/toast.js b/static/system/component/pear/module/extends/toast.js new file mode 100644 index 0000000..57c8ca5 --- /dev/null +++ b/static/system/component/pear/module/extends/toast.js @@ -0,0 +1,1225 @@ +(function (root, factory) { + if(typeof define === 'function' && define.amd) { + define([], factory(root)); + } else if(typeof exports === 'object') { + module.exports = factory(root); + } else if (window.layui && layui.define) { + layui.define(function(exports){ + exports('toast',factory(root)) + }) + }else { + root.iziToast = factory(root); + } +})(typeof global !== 'undefined' ? global : window || this.window || this.global, function (root) { + + 'use strict'; + + var $iziToast = {}, + PLUGIN_NAME = 'iziToast', + BODY = document.querySelector('body'), + ISMOBILE = (/Mobi/.test(navigator.userAgent)) ? true : false, + ISCHROME = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor), + ISFIREFOX = typeof InstallTrigger !== 'undefined', + ACCEPTSTOUCH = 'ontouchstart' in document.documentElement, + POSITIONS = ['bottomRight','bottomLeft','bottomCenter','topRight','topLeft','topCenter','center'], + THEMES = { + info: { + color: 'blue', + icon: 'ico-info' + }, + success: { + color: 'green', + icon: 'ico-success' + }, + warning: { + color: 'orange', + icon: 'ico-warning' + }, + error: { + color: 'red', + icon: 'ico-error' + }, + question: { + color: 'yellow', + icon: 'ico-question' + } + }, + MOBILEWIDTH = 568, + CONFIG = {}; + + $iziToast.children = {}; + + // Default settings + var defaults = { + id: null, + class: '', + title: '', + titleColor: '', + titleSize: '', + titleLineHeight: '', + message: '', + messageColor: '', + messageSize: '', + messageLineHeight: '', + backgroundColor: '', + theme: 'light', // dark + color: '', // blue, red, green, yellow + icon: '', + iconText: '', + iconColor: '', + iconUrl: null, + image: '', + imageWidth: 50, + maxWidth: null, + zindex: null, + layout: 2, + balloon: false, + close: true, + closeOnEscape: false, + closeOnClick: false, + displayMode: 0, + position: 'topCenter', // bottomRight, bottomLeft, topRight, topLeft, topCenter, bottomCenter, center + target: '', + targetFirst: true, + timeout: 3000, // 默认3秒 + rtl: false, + animateInside: false, // 动画效果 + drag: true, + pauseOnHover: true, + resetOnHover: false, + progressBar: false, + progressBarColor: '', + progressBarEasing: 'linear', + overlay: false, + overlayClose: false, + overlayColor: 'rgba(0, 0, 0, 0.6)', + transitionIn: 'fadeInDown', // bounceInLeft, bounceInRight, bounceInUp, bounceInDown, fadeIn, fadeInDown, fadeInUp, fadeInLeft, fadeInRight, flipInX + transitionOut: 'fadeOut', // fadeOut, fadeOutUp, fadeOutDown, fadeOutLeft, fadeOutRight, flipOutX + transitionInMobile: 'bounceInDown', + transitionOutMobile: 'fadeOutUp', + buttons: {}, + inputs: {}, + onOpening: function () {}, + onOpened: function () {}, + onClosing: function () {}, + onClosed: function () {} + }; + + if(!('remove' in Element.prototype)) { + Element.prototype.remove = function() { + if(this.parentNode) { + this.parentNode.removeChild(this); + } + }; + } + + if(typeof window.CustomEvent !== 'function') { + var CustomEventPolyfill = function (event, params) { + params = params || { bubbles: false, cancelable: false, detail: undefined }; + var evt = document.createEvent('CustomEvent'); + evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); + return evt; + }; + + CustomEventPolyfill.prototype = window.Event.prototype; + + window.CustomEvent = CustomEventPolyfill; + } + + var forEach = function (collection, callback, scope) { + if(Object.prototype.toString.call(collection) === '[object Object]') { + for (var prop in collection) { + if(Object.prototype.hasOwnProperty.call(collection, prop)) { + callback.call(scope, collection[prop], prop, collection); + } + } + } else { + if(collection){ + for (var i = 0, len = collection.length; i < len; i++) { + callback.call(scope, collection[i], i, collection); + } + } + } + }; + + var extend = function (defaults, options) { + var extended = {}; + forEach(defaults, function (value, prop) { + extended[prop] = defaults[prop]; + }); + forEach(options, function (value, prop) { + extended[prop] = options[prop]; + }); + return extended; + }; + + var createFragElem = function(htmlStr) { + var frag = document.createDocumentFragment(), + temp = document.createElement('div'); + temp.innerHTML = htmlStr; + while (temp.firstChild) { + frag.appendChild(temp.firstChild); + } + return frag; + }; + + var generateId = function(params) { + var newId = btoa(encodeURIComponent(params)); + return newId.replace(/=/g, ""); + }; + + var isColor = function(color){ + if( color.substring(0,1) == '#' || color.substring(0,3) == 'rgb' || color.substring(0,3) == 'hsl' ){ + return true; + } else { + return false; + } + }; + + var isBase64 = function(str) { + try { + return btoa(atob(str)) == str; + } catch (err) { + return false; + } + }; + + var drag = function() { + + return { + move: function(toast, instance, settings, xpos) { + + var opacity, + opacityRange = 0.3, + distance = 180; + + if(xpos !== 0){ + + toast.classList.add(PLUGIN_NAME+'-dragged'); + + toast.style.transform = 'translateX('+xpos + 'px)'; + + if(xpos > 0){ + opacity = (distance-xpos) / distance; + if(opacity < opacityRange){ + instance.hide(extend(settings, { transitionOut: 'fadeOutRight', transitionOutMobile: 'fadeOutRight' }), toast, 'drag'); + } + } else { + opacity = (distance+xpos) / distance; + if(opacity < opacityRange){ + instance.hide(extend(settings, { transitionOut: 'fadeOutLeft', transitionOutMobile: 'fadeOutLeft' }), toast, 'drag'); + } + } + toast.style.opacity = opacity; + + if(opacity < opacityRange){ + + if(ISCHROME || ISFIREFOX) + toast.style.left = xpos+'px'; + + toast.parentNode.style.opacity = opacityRange; + + this.stopMoving(toast, null); + } + } + + + }, + startMoving: function(toast, instance, settings, e) { + + e = e || window.event; + var posX = ((ACCEPTSTOUCH) ? e.touches[0].clientX : e.clientX), + toastLeft = toast.style.transform.replace('px)', ''); + toastLeft = toastLeft.replace('translateX(', ''); + var offsetX = posX - toastLeft; + + if(settings.transitionIn){ + toast.classList.remove(settings.transitionIn); + } + if(settings.transitionInMobile){ + toast.classList.remove(settings.transitionInMobile); + } + toast.style.transition = ''; + + if(ACCEPTSTOUCH) { + document.ontouchmove = function(e) { + e.preventDefault(); + e = e || window.event; + var posX = e.touches[0].clientX, + finalX = posX - offsetX; + drag.move(toast, instance, settings, finalX); + }; + } else { + document.onmousemove = function(e) { + e.preventDefault(); + e = e || window.event; + var posX = e.clientX, + finalX = posX - offsetX; + drag.move(toast, instance, settings, finalX); + }; + } + + }, + stopMoving: function(toast, e) { + + if(ACCEPTSTOUCH) { + document.ontouchmove = function() {}; + } else { + document.onmousemove = function() {}; + } + + toast.style.opacity = ''; + toast.style.transform = ''; + + if(toast.classList.contains(PLUGIN_NAME+'-dragged')){ + + toast.classList.remove(PLUGIN_NAME+'-dragged'); + + toast.style.transition = 'transform 0.4s ease, opacity 0.4s ease'; + setTimeout(function() { + toast.style.transition = ''; + }, 400); + } + + } + }; + + }(); + + $iziToast.setSetting = function (ref, option, value) { + + $iziToast.children[ref][option] = value; + + }; + + $iziToast.getSetting = function (ref, option) { + + return $iziToast.children[ref][option]; + + }; + + $iziToast.destroy = function () { + + forEach(document.querySelectorAll('.'+PLUGIN_NAME+'-overlay'), function(element, index) { + element.remove(); + }); + + forEach(document.querySelectorAll('.'+PLUGIN_NAME+'-wrapper'), function(element, index) { + element.remove(); + }); + + forEach(document.querySelectorAll('.'+PLUGIN_NAME), function(element, index) { + element.remove(); + }); + + this.children = {}; + + // Remove event listeners + document.removeEventListener(PLUGIN_NAME+'-opened', {}, false); + document.removeEventListener(PLUGIN_NAME+'-opening', {}, false); + document.removeEventListener(PLUGIN_NAME+'-closing', {}, false); + document.removeEventListener(PLUGIN_NAME+'-closed', {}, false); + document.removeEventListener('keyup', {}, false); + + // Reset variables + CONFIG = {}; + }; + + /** + * Initialize Plugin + * @public + * @param {Object} options User settings + */ + $iziToast.settings = function (options) { + + // Destroy any existing initializations + $iziToast.destroy(); + + CONFIG = options; + defaults = extend(defaults, options || {}); + }; + + + /** + * Building themes functions. + * @public + * @param {Object} options User settings + */ + forEach(THEMES, function (theme, name) { + + $iziToast[name] = function (options) { + + var settings = extend(CONFIG, options || {}); + settings = extend(theme, settings || {}); + + this.show(settings); + }; + + }); + + + /** + * Do the calculation to move the progress bar + * @private + */ + $iziToast.progress = function (options, $toast, callback) { + + + var that = this, + ref = $toast.getAttribute('data-iziToast-ref'), + settings = extend(this.children[ref], options || {}), + $elem = $toast.querySelector('.'+PLUGIN_NAME+'-progressbar div'); + + return { + start: function() { + + if(typeof settings.time.REMAINING == 'undefined'){ + + $toast.classList.remove(PLUGIN_NAME+'-reseted'); + + if($elem !== null){ + $elem.style.transition = 'width '+ settings.timeout +'ms '+settings.progressBarEasing; + $elem.style.width = '0%'; + } + + settings.time.START = new Date().getTime(); + settings.time.END = settings.time.START + settings.timeout; + settings.time.TIMER = setTimeout(function() { + + clearTimeout(settings.time.TIMER); + + if(!$toast.classList.contains(PLUGIN_NAME+'-closing')){ + + that.hide(settings, $toast, 'timeout'); + + if(typeof callback === 'function'){ + callback.apply(that); + } + } + + }, settings.timeout); + that.setSetting(ref, 'time', settings.time); + } + }, + pause: function() { + + if(typeof settings.time.START !== 'undefined' && !$toast.classList.contains(PLUGIN_NAME+'-paused') && !$toast.classList.contains(PLUGIN_NAME+'-reseted')){ + + $toast.classList.add(PLUGIN_NAME+'-paused'); + + settings.time.REMAINING = settings.time.END - new Date().getTime(); + + clearTimeout(settings.time.TIMER); + + that.setSetting(ref, 'time', settings.time); + + if($elem !== null){ + var computedStyle = window.getComputedStyle($elem), + propertyWidth = computedStyle.getPropertyValue('width'); + + $elem.style.transition = 'none'; + $elem.style.width = propertyWidth; + } + + if(typeof callback === 'function'){ + setTimeout(function() { + callback.apply(that); + }, 10); + } + } + }, + resume: function() { + + if(typeof settings.time.REMAINING !== 'undefined'){ + + $toast.classList.remove(PLUGIN_NAME+'-paused'); + + if($elem !== null){ + $elem.style.transition = 'width '+ settings.time.REMAINING +'ms '+settings.progressBarEasing; + $elem.style.width = '0%'; + } + + settings.time.END = new Date().getTime() + settings.time.REMAINING; + settings.time.TIMER = setTimeout(function() { + + clearTimeout(settings.time.TIMER); + + if(!$toast.classList.contains(PLUGIN_NAME+'-closing')){ + + that.hide(settings, $toast, 'timeout'); + + if(typeof callback === 'function'){ + callback.apply(that); + } + } + + + }, settings.time.REMAINING); + + that.setSetting(ref, 'time', settings.time); + } else { + this.start(); + } + }, + reset: function(){ + + clearTimeout(settings.time.TIMER); + + delete settings.time.REMAINING; + + that.setSetting(ref, 'time', settings.time); + + $toast.classList.add(PLUGIN_NAME+'-reseted'); + + $toast.classList.remove(PLUGIN_NAME+'-paused'); + + if($elem !== null){ + $elem.style.transition = 'none'; + $elem.style.width = '100%'; + } + + if(typeof callback === 'function'){ + setTimeout(function() { + callback.apply(that); + }, 10); + } + } + }; + + }; + + + /** + * Close the specific Toast + * @public + * @param {Object} options User settings + */ + $iziToast.hide = function (options, $toast, closedBy) { + + if(typeof $toast != 'object'){ + $toast = document.querySelector($toast); + } + + var that = this, + settings = extend(this.children[$toast.getAttribute('data-iziToast-ref')], options || {}); + settings.closedBy = closedBy || null; + + delete settings.time.REMAINING; + + $toast.classList.add(PLUGIN_NAME+'-closing'); + + // Overlay + (function(){ + + var $overlay = document.querySelector('.'+PLUGIN_NAME+'-overlay'); + if($overlay !== null){ + var refs = $overlay.getAttribute('data-iziToast-ref'); + refs = refs.split(','); + var index = refs.indexOf(String(settings.ref)); + + if(index !== -1){ + refs.splice(index, 1); + } + $overlay.setAttribute('data-iziToast-ref', refs.join()); + + if(refs.length === 0){ + $overlay.classList.remove('fadeIn'); + $overlay.classList.add('fadeOut'); + setTimeout(function() { + $overlay.remove(); + }, 700); + } + } + + })(); + + if(settings.transitionIn){ + $toast.classList.remove(settings.transitionIn); + } + + if(settings.transitionInMobile){ + $toast.classList.remove(settings.transitionInMobile); + } + + if(ISMOBILE || window.innerWidth <= MOBILEWIDTH){ + if(settings.transitionOutMobile) + $toast.classList.add(settings.transitionOutMobile); + } else { + if(settings.transitionOut) + $toast.classList.add(settings.transitionOut); + } + var H = $toast.parentNode.offsetHeight; + $toast.parentNode.style.height = H+'px'; + $toast.style.pointerEvents = 'none'; + + if(!ISMOBILE || window.innerWidth > MOBILEWIDTH){ + $toast.parentNode.style.transitionDelay = '0.2s'; + } + + try { + var event = new CustomEvent(PLUGIN_NAME+'-closing', {detail: settings, bubbles: true, cancelable: true}); + document.dispatchEvent(event); + } catch(ex){ + console.warn(ex); + } + + setTimeout(function() { + + $toast.parentNode.style.height = '0px'; + $toast.parentNode.style.overflow = ''; + + setTimeout(function(){ + + delete that.children[settings.ref]; + + $toast.parentNode.remove(); + + try { + var event = new CustomEvent(PLUGIN_NAME+'-closed', {detail: settings, bubbles: true, cancelable: true}); + document.dispatchEvent(event); + } catch(ex){ + console.warn(ex); + } + + if(typeof settings.onClosed !== 'undefined'){ + settings.onClosed.apply(null, [settings, $toast, closedBy]); + } + + }, 1000); + }, 200); + + + if(typeof settings.onClosing !== 'undefined'){ + settings.onClosing.apply(null, [settings, $toast, closedBy]); + } + }; + + /** + * Create and show the Toast + * @public + * @param {Object} options User settings + */ + $iziToast.show = function (options) { + + var that = this; + + // Merge user options with defaults + var settings = extend(CONFIG, options || {}); + settings = extend(defaults, settings); + settings.time = {}; + + if(settings.id === null){ + settings.id = generateId(settings.title+settings.message+settings.color); + } + + if(settings.displayMode === 1 || settings.displayMode == 'once'){ + try { + if(document.querySelectorAll('.'+PLUGIN_NAME+'#'+settings.id).length > 0){ + return false; + } + } catch (exc) { + console.warn('['+PLUGIN_NAME+'] Could not find an element with this selector: '+'#'+settings.id+'. Try to set an valid id.'); + } + } + + if(settings.displayMode === 2 || settings.displayMode == 'replace'){ + try { + forEach(document.querySelectorAll('.'+PLUGIN_NAME+'#'+settings.id), function(element, index) { + that.hide(settings, element, 'replaced'); + }); + } catch (exc) { + console.warn('['+PLUGIN_NAME+'] Could not find an element with this selector: '+'#'+settings.id+'. Try to set an valid id.'); + } + } + + settings.ref = new Date().getTime() + Math.floor((Math.random() * 10000000) + 1); + + $iziToast.children[settings.ref] = settings; + + var $DOM = { + body: document.querySelector('body'), + overlay: document.createElement('div'), + toast: document.createElement('div'), + toastBody: document.createElement('div'), + toastTexts: document.createElement('div'), + toastCapsule: document.createElement('div'), + cover: document.createElement('div'), + buttons: document.createElement('div'), + inputs: document.createElement('div'), + icon: !settings.iconUrl ? document.createElement('i') : document.createElement('img'), + wrapper: null + }; + + $DOM.toast.setAttribute('data-iziToast-ref', settings.ref); + $DOM.toast.appendChild($DOM.toastBody); + $DOM.toastCapsule.appendChild($DOM.toast); + + // CSS Settings + (function(){ + + $DOM.toast.classList.add(PLUGIN_NAME); + $DOM.toast.classList.add(PLUGIN_NAME+'-opening'); + $DOM.toastCapsule.classList.add(PLUGIN_NAME+'-capsule'); + $DOM.toastBody.classList.add(PLUGIN_NAME + '-body'); + $DOM.toastTexts.classList.add(PLUGIN_NAME + '-texts'); + + if(ISMOBILE || window.innerWidth <= MOBILEWIDTH){ + if(settings.transitionInMobile) + $DOM.toast.classList.add(settings.transitionInMobile); + } else { + if(settings.transitionIn) + $DOM.toast.classList.add(settings.transitionIn); + } + + if(settings.class){ + var classes = settings.class.split(' '); + forEach(classes, function (value, index) { + $DOM.toast.classList.add(value); + }); + } + + if(settings.id){ $DOM.toast.id = settings.id; } + + if(settings.rtl){ + $DOM.toast.classList.add(PLUGIN_NAME + '-rtl'); + $DOM.toast.setAttribute('dir', 'rtl'); + } + + if(settings.layout > 1){ $DOM.toast.classList.add(PLUGIN_NAME+'-layout'+settings.layout); } + + if(settings.balloon){ $DOM.toast.classList.add(PLUGIN_NAME+'-balloon'); } + + if(settings.maxWidth){ + if( !isNaN(settings.maxWidth) ){ + $DOM.toast.style.maxWidth = settings.maxWidth+'px'; + } else { + $DOM.toast.style.maxWidth = settings.maxWidth; + } + } + + if(settings.theme !== '' || settings.theme !== 'light') { + + $DOM.toast.classList.add(PLUGIN_NAME+'-theme-'+settings.theme); + } + + if(settings.color) { //#, rgb, rgba, hsl + + if( isColor(settings.color) ){ + $DOM.toast.style.background = settings.color; + } else { + $DOM.toast.classList.add(PLUGIN_NAME+'-color-'+settings.color); + } + } + + if(settings.backgroundColor) { + $DOM.toast.style.background = settings.backgroundColor; + if(settings.balloon){ + $DOM.toast.style.borderColor = settings.backgroundColor; + } + } + })(); + + // Cover image + (function(){ + if(settings.image) { + $DOM.cover.classList.add(PLUGIN_NAME + '-cover'); + $DOM.cover.style.width = settings.imageWidth + 'px'; + + if(isBase64(settings.image.replace(/ /g,''))){ + $DOM.cover.style.backgroundImage = 'url(data:image/png;base64,' + settings.image.replace(/ /g,'') + ')'; + } else { + $DOM.cover.style.backgroundImage = 'url(' + settings.image + ')'; + } + + if(settings.rtl){ + $DOM.toastBody.style.marginRight = (settings.imageWidth + 10) + 'px'; + } else { + $DOM.toastBody.style.marginLeft = (settings.imageWidth + 10) + 'px'; + } + $DOM.toast.appendChild($DOM.cover); + } + })(); + + // Button close + (function(){ + if(settings.close){ + + $DOM.buttonClose = document.createElement('button'); + $DOM.buttonClose.type = 'button'; + $DOM.buttonClose.classList.add(PLUGIN_NAME + '-close'); + $DOM.buttonClose.addEventListener('click', function (e) { + var button = e.target; + that.hide(settings, $DOM.toast, 'button'); + }); + $DOM.toast.appendChild($DOM.buttonClose); + } else { + if(settings.rtl){ + $DOM.toast.style.paddingLeft = '18px'; + } else { + $DOM.toast.style.paddingRight = '18px'; + } + } + })(); + + // Progress Bar & Timeout + (function(){ + + if(settings.progressBar){ + $DOM.progressBar = document.createElement('div'); + $DOM.progressBarDiv = document.createElement('div'); + $DOM.progressBar.classList.add(PLUGIN_NAME + '-progressbar'); + $DOM.progressBarDiv.style.background = settings.progressBarColor; + $DOM.progressBar.appendChild($DOM.progressBarDiv); + $DOM.toast.appendChild($DOM.progressBar); + } + + if(settings.timeout) { + + if(settings.pauseOnHover && !settings.resetOnHover){ + + $DOM.toast.addEventListener('mouseenter', function (e) { + that.progress(settings, $DOM.toast).pause(); + }); + $DOM.toast.addEventListener('mouseleave', function (e) { + that.progress(settings, $DOM.toast).resume(); + }); + } + + if(settings.resetOnHover){ + + $DOM.toast.addEventListener('mouseenter', function (e) { + that.progress(settings, $DOM.toast).reset(); + }); + $DOM.toast.addEventListener('mouseleave', function (e) { + that.progress(settings, $DOM.toast).start(); + }); + } + } + })(); + + // Icon + (function(){ + + if(settings.iconUrl) { + + $DOM.icon.setAttribute('class', PLUGIN_NAME + '-icon'); + $DOM.icon.setAttribute('src', settings.iconUrl); + + } else if(settings.icon) { + $DOM.icon.setAttribute('class', PLUGIN_NAME + '-icon ' + settings.icon); + + if(settings.iconText){ + $DOM.icon.appendChild(document.createTextNode(settings.iconText)); + } + + if(settings.iconColor){ + $DOM.icon.style.color = settings.iconColor; + } + } + + if(settings.icon || settings.iconUrl) { + + if(settings.rtl){ + $DOM.toastBody.style.paddingRight = '33px'; + } else { + $DOM.toastBody.style.paddingLeft = '33px'; + } + + $DOM.toastBody.appendChild($DOM.icon); + } + + })(); + + // Title & Message + (function(){ + if(settings.title.length > 0) { + + $DOM.strong = document.createElement('strong'); + $DOM.strong.classList.add(PLUGIN_NAME + '-title'); + $DOM.strong.appendChild(createFragElem(settings.title)); + $DOM.toastTexts.appendChild($DOM.strong); + + if(settings.titleColor) { + $DOM.strong.style.color = settings.titleColor; + } + if(settings.titleSize) { + if( !isNaN(settings.titleSize) ){ + $DOM.strong.style.fontSize = settings.titleSize+'px'; + } else { + $DOM.strong.style.fontSize = settings.titleSize; + } + } + if(settings.titleLineHeight) { + if( !isNaN(settings.titleSize) ){ + $DOM.strong.style.lineHeight = settings.titleLineHeight+'px'; + } else { + $DOM.strong.style.lineHeight = settings.titleLineHeight; + } + } + } + + if(settings.message.length > 0) { + + $DOM.p = document.createElement('p'); + $DOM.p.classList.add(PLUGIN_NAME + '-message'); + $DOM.p.appendChild(createFragElem(settings.message)); + $DOM.toastTexts.appendChild($DOM.p); + + if(settings.messageColor) { + $DOM.p.style.color = settings.messageColor; + } + if(settings.messageSize) { + if( !isNaN(settings.titleSize) ){ + $DOM.p.style.fontSize = settings.messageSize+'px'; + } else { + $DOM.p.style.fontSize = settings.messageSize; + } + } + if(settings.messageLineHeight) { + + if( !isNaN(settings.titleSize) ){ + $DOM.p.style.lineHeight = settings.messageLineHeight+'px'; + } else { + $DOM.p.style.lineHeight = settings.messageLineHeight; + } + } + } + + if(settings.title.length > 0 && settings.message.length > 0) { + if(settings.rtl){ + $DOM.strong.style.marginLeft = '10px'; + } else if(settings.layout !== 2 && !settings.rtl) { + $DOM.strong.style.marginRight = '10px'; + } + } + })(); + + $DOM.toastBody.appendChild($DOM.toastTexts); + + // Inputs + var $inputs; + (function(){ + if(settings.inputs.length > 0) { + + $DOM.inputs.classList.add(PLUGIN_NAME + '-inputs'); + + forEach(settings.inputs, function (value, index) { + $DOM.inputs.appendChild(createFragElem(value[0])); + + $inputs = $DOM.inputs.childNodes; + + $inputs[index].classList.add(PLUGIN_NAME + '-inputs-child'); + + if(value[3]){ + setTimeout(function() { + $inputs[index].focus(); + }, 300); + } + + $inputs[index].addEventListener(value[1], function (e) { + var ts = value[2]; + return ts(that, $DOM.toast, this, e); + }); + }); + $DOM.toastBody.appendChild($DOM.inputs); + } + })(); + + // Buttons + (function(){ + if(settings.buttons.length > 0) { + + $DOM.buttons.classList.add(PLUGIN_NAME + '-buttons'); + + forEach(settings.buttons, function (value, index) { + $DOM.buttons.appendChild(createFragElem(value[0])); + + var $btns = $DOM.buttons.childNodes; + + $btns[index].classList.add(PLUGIN_NAME + '-buttons-child'); + + if(value[2]){ + setTimeout(function() { + $btns[index].focus(); + }, 300); + } + + $btns[index].addEventListener('click', function (e) { + e.preventDefault(); + var ts = value[1]; + return ts(that, $DOM.toast, this, e, $inputs); + }); + }); + } + $DOM.toastBody.appendChild($DOM.buttons); + })(); + + if(settings.message.length > 0 && (settings.inputs.length > 0 || settings.buttons.length > 0)) { + $DOM.p.style.marginBottom = '0'; + } + + if(settings.inputs.length > 0 || settings.buttons.length > 0){ + if(settings.rtl){ + $DOM.toastTexts.style.marginLeft = '10px'; + } else { + $DOM.toastTexts.style.marginRight = '10px'; + } + if(settings.inputs.length > 0 && settings.buttons.length > 0){ + if(settings.rtl){ + $DOM.inputs.style.marginLeft = '8px'; + } else { + $DOM.inputs.style.marginRight = '8px'; + } + } + } + + // Wrap + (function(){ + $DOM.toastCapsule.style.visibility = 'hidden'; + setTimeout(function() { + var H = $DOM.toast.offsetHeight; + var style = $DOM.toast.currentStyle || window.getComputedStyle($DOM.toast); + var marginTop = style.marginTop; + marginTop = marginTop.split('px'); + marginTop = parseInt(marginTop[0]); + var marginBottom = style.marginBottom; + marginBottom = marginBottom.split('px'); + marginBottom = parseInt(marginBottom[0]); + + $DOM.toastCapsule.style.visibility = ''; + $DOM.toastCapsule.style.height = (H+marginBottom+marginTop)+'px'; + + setTimeout(function() { + $DOM.toastCapsule.style.height = 'auto'; + if(settings.target){ + $DOM.toastCapsule.style.overflow = 'visible'; + } + }, 500); + + if(settings.timeout) { + that.progress(settings, $DOM.toast).start(); + } + }, 100); + })(); + + // Target + (function(){ + var position = settings.position; + + if(settings.target){ + + $DOM.wrapper = document.querySelector(settings.target); + $DOM.wrapper.classList.add(PLUGIN_NAME + '-target'); + + if(settings.targetFirst) { + $DOM.wrapper.insertBefore($DOM.toastCapsule, $DOM.wrapper.firstChild); + } else { + $DOM.wrapper.appendChild($DOM.toastCapsule); + } + + } else { + + if( POSITIONS.indexOf(settings.position) == -1 ){ + console.warn('['+PLUGIN_NAME+'] Incorrect position.\nIt can be › ' + POSITIONS); + return; + } + + if(ISMOBILE || window.innerWidth <= MOBILEWIDTH){ + if(settings.position == 'bottomLeft' || settings.position == 'bottomRight' || settings.position == 'bottomCenter'){ + position = PLUGIN_NAME+'-wrapper-bottomCenter'; + } + else if(settings.position == 'topLeft' || settings.position == 'topRight' || settings.position == 'topCenter'){ + position = PLUGIN_NAME+'-wrapper-topCenter'; + } + else { + position = PLUGIN_NAME+'-wrapper-center'; + } + } else { + position = PLUGIN_NAME+'-wrapper-'+position; + } + $DOM.wrapper = document.querySelector('.' + PLUGIN_NAME + '-wrapper.'+position); + + if(!$DOM.wrapper) { + $DOM.wrapper = document.createElement('div'); + $DOM.wrapper.classList.add(PLUGIN_NAME + '-wrapper'); + $DOM.wrapper.classList.add(position); + document.body.appendChild($DOM.wrapper); + } + if(settings.position == 'topLeft' || settings.position == 'topCenter' || settings.position == 'topRight'){ + $DOM.wrapper.insertBefore($DOM.toastCapsule, $DOM.wrapper.firstChild); + } else { + $DOM.wrapper.appendChild($DOM.toastCapsule); + } + } + + if(!isNaN(settings.zindex)) { + $DOM.wrapper.style.zIndex = settings.zindex; + } else { + console.warn('['+PLUGIN_NAME+'] Invalid zIndex.'); + } + })(); + + // Overlay + (function(){ + + if(settings.overlay) { + + if( document.querySelector('.'+PLUGIN_NAME+'-overlay.fadeIn') !== null ){ + + $DOM.overlay = document.querySelector('.'+PLUGIN_NAME+'-overlay'); + $DOM.overlay.setAttribute('data-iziToast-ref', $DOM.overlay.getAttribute('data-iziToast-ref') + ',' + settings.ref); + + if(!isNaN(settings.zindex) && settings.zindex !== null) { + $DOM.overlay.style.zIndex = settings.zindex-1; + } + + } else { + + $DOM.overlay.classList.add(PLUGIN_NAME+'-overlay'); + $DOM.overlay.classList.add('fadeIn'); + $DOM.overlay.style.background = settings.overlayColor; + $DOM.overlay.setAttribute('data-iziToast-ref', settings.ref); + if(!isNaN(settings.zindex) && settings.zindex !== null) { + $DOM.overlay.style.zIndex = settings.zindex-1; + } + document.querySelector('body').appendChild($DOM.overlay); + } + + if(settings.overlayClose) { + + $DOM.overlay.removeEventListener('click', {}); + $DOM.overlay.addEventListener('click', function (e) { + that.hide(settings, $DOM.toast, 'overlay'); + }); + } else { + $DOM.overlay.removeEventListener('click', {}); + } + } + })(); + + // Inside animations + (function(){ + if(settings.animateInside){ + $DOM.toast.classList.add(PLUGIN_NAME+'-animateInside'); + + var animationTimes = [200, 100, 300]; + if(settings.transitionIn == 'bounceInLeft' || settings.transitionIn == 'bounceInRight'){ + animationTimes = [400, 200, 400]; + } + + if(settings.title.length > 0) { + setTimeout(function(){ + $DOM.strong.classList.add('slideIn'); + }, animationTimes[0]); + } + + if(settings.message.length > 0) { + setTimeout(function(){ + $DOM.p.classList.add('slideIn'); + }, animationTimes[1]); + } + + if(settings.icon || settings.iconUrl) { + setTimeout(function(){ + $DOM.icon.classList.add('revealIn'); + }, animationTimes[2]); + } + + var counter = 150; + if(settings.buttons.length > 0 && $DOM.buttons) { + + setTimeout(function(){ + + forEach($DOM.buttons.childNodes, function(element, index) { + + setTimeout(function(){ + element.classList.add('revealIn'); + }, counter); + counter = counter + 150; + }); + + }, settings.inputs.length > 0 ? 150 : 0); + } + + if(settings.inputs.length > 0 && $DOM.inputs) { + counter = 150; + forEach($DOM.inputs.childNodes, function(element, index) { + + setTimeout(function(){ + element.classList.add('revealIn'); + }, counter); + counter = counter + 150; + }); + } + } + })(); + + settings.onOpening.apply(null, [settings, $DOM.toast]); + + try { + var event = new CustomEvent(PLUGIN_NAME + '-opening', {detail: settings, bubbles: true, cancelable: true}); + document.dispatchEvent(event); + } catch(ex){ + console.warn(ex); + } + + setTimeout(function() { + + $DOM.toast.classList.remove(PLUGIN_NAME+'-opening'); + $DOM.toast.classList.add(PLUGIN_NAME+'-opened'); + + try { + var event = new CustomEvent(PLUGIN_NAME + '-opened', {detail: settings, bubbles: true, cancelable: true}); + document.dispatchEvent(event); + } catch(ex){ + console.warn(ex); + } + + settings.onOpened.apply(null, [settings, $DOM.toast]); + }, 1000); + + if(settings.drag){ + + if(ACCEPTSTOUCH) { + + $DOM.toast.addEventListener('touchstart', function(e) { + drag.startMoving(this, that, settings, e); + }, false); + + $DOM.toast.addEventListener('touchend', function(e) { + drag.stopMoving(this, e); + }, false); + } else { + + $DOM.toast.addEventListener('mousedown', function(e) { + e.preventDefault(); + drag.startMoving(this, that, settings, e); + }, false); + + $DOM.toast.addEventListener('mouseup', function(e) { + e.preventDefault(); + drag.stopMoving(this, e); + }, false); + } + } + + if(settings.closeOnEscape) { + + document.addEventListener('keyup', function (evt) { + evt = evt || window.event; + if(evt.keyCode == 27) { + that.hide(settings, $DOM.toast, 'esc'); + } + }); + } + + if(settings.closeOnClick) { + $DOM.toast.addEventListener('click', function (evt) { + that.hide(settings, $DOM.toast, 'toast'); + }); + } + + that.toast = $DOM.toast; + }; + return $iziToast; +}); \ No newline at end of file diff --git a/static/system/component/pear/module/extends/yaml.js b/static/system/component/pear/module/extends/yaml.js new file mode 100644 index 0000000..77eefb8 --- /dev/null +++ b/static/system/component/pear/module/extends/yaml.js @@ -0,0 +1,2057 @@ +layui.define(['jquery', 'element'], function (exports) { + "use strict"; + + var MOD_NAME = 'yaml'; + + var yaml = new function () { + this.parse = function (yamlStr) { + return YAML.parse(yamlStr); + } + this.load = function (path) { + return YAML.load(path); + } + } + exports(MOD_NAME, yaml); +}); + + +(function () { + function r(e, n, t) { + function o(i, f) { + if (!n[i]) { + if (!e[i]) { + var c = "function" == typeof require && require; + if (!f && c) return c(i, !0); + if (u) return u(i, !0); + var a = new Error("Cannot find module '" + i + "'"); + throw a.code = "MODULE_NOT_FOUND", a + } + var p = n[i] = { + exports: {} + }; + e[i][0].call(p.exports, function (r) { + var n = e[i][1][r]; + return o(n || r) + }, p, p.exports, r, e, n, t) + } + return n[i].exports + } + for (var u = "function" == typeof require && require, i = 0; i < t.length; i++) o(t[i]); + return o + } + return r +})()({ + 1: [function (require, module, exports) { + var Dumper, Inline, Utils; + + Utils = require('./Utils'); + + Inline = require('./Inline'); + + Dumper = (function () { + function Dumper() { } + + Dumper.indentation = 4; + + Dumper.prototype.dump = function (input, inline, indent, exceptionOnInvalidType, objectEncoder) { + var i, key, len, output, prefix, value, willBeInlined; + if (inline == null) { + inline = 0; + } + if (indent == null) { + indent = 0; + } + if (exceptionOnInvalidType == null) { + exceptionOnInvalidType = false; + } + if (objectEncoder == null) { + objectEncoder = null; + } + output = ''; + if (typeof input === 'function') { + return output; + } + prefix = (indent ? Utils.strRepeat(' ', indent) : ''); + if (inline <= 0 || typeof input !== 'object' || input instanceof Date || Utils.isEmpty(input)) { + output += prefix + Inline.dump(input, exceptionOnInvalidType, objectEncoder); + } else { + if (input instanceof Array) { + for (i = 0, len = input.length; i < len; i++) { + value = input[i]; + willBeInlined = inline - 1 <= 0 || typeof value !== 'object' || Utils.isEmpty(value); + output += prefix + '-' + (willBeInlined ? ' ' : "\n") + this.dump(value, inline - 1, (willBeInlined ? 0 : + indent + this.indentation), exceptionOnInvalidType, objectEncoder) + (willBeInlined ? "\n" : ''); + } + } else { + for (key in input) { + value = input[key]; + willBeInlined = inline - 1 <= 0 || typeof value !== 'object' || Utils.isEmpty(value); + output += prefix + Inline.dump(key, exceptionOnInvalidType, objectEncoder) + ':' + (willBeInlined ? ' ' : + "\n") + this.dump(value, inline - 1, (willBeInlined ? 0 : indent + this.indentation), + exceptionOnInvalidType, objectEncoder) + (willBeInlined ? "\n" : ''); + } + } + } + return output; + }; + + return Dumper; + + })(); + + module.exports = Dumper; + + + }, { + "./Inline": 6, + "./Utils": 10 + }], + 2: [function (require, module, exports) { + var Escaper, Pattern; + + Pattern = require('./Pattern'); + + Escaper = (function () { + var ch; + + function Escaper() { } + + Escaper.LIST_ESCAPEES = ['\\', '\\\\', '\\"', '"', "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", + "\x07", "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f", "\x10", "\x11", "\x12", "\x13", + "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f", (ch = String.fromCharCode) + (0x0085), ch(0x00A0), ch(0x2028), ch(0x2029) + ]; + + Escaper.LIST_ESCAPED = ['\\\\', '\\"', '\\"', '\\"', "\\0", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", + "\\x06", "\\a", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "\\x0e", "\\x0f", "\\x10", "\\x11", "\\x12", + "\\x13", "\\x14", "\\x15", "\\x16", "\\x17", "\\x18", "\\x19", "\\x1a", "\\e", "\\x1c", "\\x1d", "\\x1e", + "\\x1f", "\\N", "\\_", "\\L", "\\P" + ]; + + Escaper.MAPPING_ESCAPEES_TO_ESCAPED = (function () { + var i, j, mapping, ref; + mapping = {}; + for (i = j = 0, ref = Escaper.LIST_ESCAPEES.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { + mapping[Escaper.LIST_ESCAPEES[i]] = Escaper.LIST_ESCAPED[i]; + } + return mapping; + })(); + + Escaper.PATTERN_CHARACTERS_TO_ESCAPE = new Pattern('[\\x00-\\x1f]|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9'); + + Escaper.PATTERN_MAPPING_ESCAPEES = new Pattern(Escaper.LIST_ESCAPEES.join('|').split('\\').join('\\\\')); + + Escaper.PATTERN_SINGLE_QUOTING = new Pattern('[\\s\'":{}[\\],&*#?]|^[-?|<>=!%@`]'); + + Escaper.requiresDoubleQuoting = function (value) { + return this.PATTERN_CHARACTERS_TO_ESCAPE.test(value); + }; + + Escaper.escapeWithDoubleQuotes = function (value) { + var result; + result = this.PATTERN_MAPPING_ESCAPEES.replace(value, (function (_this) { + return function (str) { + return _this.MAPPING_ESCAPEES_TO_ESCAPED[str]; + }; + })(this)); + return '"' + result + '"'; + }; + + Escaper.requiresSingleQuoting = function (value) { + return this.PATTERN_SINGLE_QUOTING.test(value); + }; + + Escaper.escapeWithSingleQuotes = function (value) { + return "'" + value.replace(/'/g, "''") + "'"; + }; + + return Escaper; + + })(); + + module.exports = Escaper; + + + }, { + "./Pattern": 8 + }], + 3: [function (require, module, exports) { + var DumpException, + extend = function (child, parent) { + for (var key in parent) { + if (hasProp.call(parent, key)) child[key] = parent[key]; + } + + function ctor() { + this.constructor = child; + } + ctor.prototype = parent.prototype; + child.prototype = new ctor(); + child.__super__ = parent.prototype; + return child; + }, + hasProp = {}.hasOwnProperty; + + DumpException = (function (superClass) { + extend(DumpException, superClass); + + function DumpException(message, parsedLine, snippet) { + DumpException.__super__.constructor.call(this, message); + this.message = message; + this.parsedLine = parsedLine; + this.snippet = snippet; + } + + DumpException.prototype.toString = function () { + if ((this.parsedLine != null) && (this.snippet != null)) { + return ' ' + this.message + ' (line ' + this.parsedLine + ': \'' + this.snippet + '\')'; + } else { + return ' ' + this.message; + } + }; + + return DumpException; + + })(Error); + + module.exports = DumpException; + + + }, {}], + 4: [function (require, module, exports) { + var ParseException, + extend = function (child, parent) { + for (var key in parent) { + if (hasProp.call(parent, key)) child[key] = parent[key]; + } + + function ctor() { + this.constructor = child; + } + ctor.prototype = parent.prototype; + child.prototype = new ctor(); + child.__super__ = parent.prototype; + return child; + }, + hasProp = {}.hasOwnProperty; + + ParseException = (function (superClass) { + extend(ParseException, superClass); + + function ParseException(message, parsedLine, snippet) { + ParseException.__super__.constructor.call(this, message); + this.message = message; + this.parsedLine = parsedLine; + this.snippet = snippet; + } + + ParseException.prototype.toString = function () { + if ((this.parsedLine != null) && (this.snippet != null)) { + return ' ' + this.message + ' (line ' + this.parsedLine + ': \'' + this.snippet + '\')'; + } else { + return ' ' + this.message; + } + }; + + return ParseException; + + })(Error); + + module.exports = ParseException; + + + }, {}], + 5: [function (require, module, exports) { + var ParseMore, + extend = function (child, parent) { + for (var key in parent) { + if (hasProp.call(parent, key)) child[key] = parent[key]; + } + + function ctor() { + this.constructor = child; + } + ctor.prototype = parent.prototype; + child.prototype = new ctor(); + child.__super__ = parent.prototype; + return child; + }, + hasProp = {}.hasOwnProperty; + + ParseMore = (function (superClass) { + extend(ParseMore, superClass); + + function ParseMore(message, parsedLine, snippet) { + ParseMore.__super__.constructor.call(this, message); + this.message = message; + this.parsedLine = parsedLine; + this.snippet = snippet; + } + + ParseMore.prototype.toString = function () { + if ((this.parsedLine != null) && (this.snippet != null)) { + return ' ' + this.message + ' (line ' + this.parsedLine + ': \'' + this.snippet + '\')'; + } else { + return ' ' + this.message; + } + }; + + return ParseMore; + + })(Error); + + module.exports = ParseMore; + + + }, {}], + 6: [function (require, module, exports) { + var DumpException, Escaper, Inline, ParseException, ParseMore, Pattern, Unescaper, Utils, + indexOf = [].indexOf || function (item) { + for (var i = 0, l = this.length; i < l; i++) { + if (i in this && this[i] === item) return i; + } + return -1; + }; + + Pattern = require('./Pattern'); + + Unescaper = require('./Unescaper'); + + Escaper = require('./Escaper'); + + Utils = require('./Utils'); + + ParseException = require('./Exception/ParseException'); + + ParseMore = require('./Exception/ParseMore'); + + DumpException = require('./Exception/DumpException'); + + Inline = (function () { + function Inline() { } + + Inline.REGEX_QUOTED_STRING = '(?:"(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\']*(?:\'\'[^\']*)*)\')'; + + Inline.PATTERN_TRAILING_COMMENTS = new Pattern('^\\s*#.*$'); + + Inline.PATTERN_QUOTED_SCALAR = new Pattern('^' + Inline.REGEX_QUOTED_STRING); + + Inline.PATTERN_THOUSAND_NUMERIC_SCALAR = new Pattern('^(-|\\+)?[0-9,]+(\\.[0-9]+)?$'); + + Inline.PATTERN_SCALAR_BY_DELIMITERS = {}; + + Inline.settings = {}; + + Inline.configure = function (exceptionOnInvalidType, objectDecoder) { + if (exceptionOnInvalidType == null) { + exceptionOnInvalidType = null; + } + if (objectDecoder == null) { + objectDecoder = null; + } + this.settings.exceptionOnInvalidType = exceptionOnInvalidType; + this.settings.objectDecoder = objectDecoder; + }; + + Inline.parse = function (value, exceptionOnInvalidType, objectDecoder) { + var context, result; + if (exceptionOnInvalidType == null) { + exceptionOnInvalidType = false; + } + if (objectDecoder == null) { + objectDecoder = null; + } + this.settings.exceptionOnInvalidType = exceptionOnInvalidType; + this.settings.objectDecoder = objectDecoder; + if (value == null) { + return ''; + } + value = Utils.trim(value); + if (0 === value.length) { + return ''; + } + context = { + exceptionOnInvalidType: exceptionOnInvalidType, + objectDecoder: objectDecoder, + i: 0 + }; + switch (value.charAt(0)) { + case '[': + result = this.parseSequence(value, context); + ++context.i; + break; + case '{': + result = this.parseMapping(value, context); + ++context.i; + break; + default: + result = this.parseScalar(value, null, ['"', "'"], context); + } + if (this.PATTERN_TRAILING_COMMENTS.replace(value.slice(context.i), '') !== '') { + throw new ParseException('Unexpected characters near "' + value.slice(context.i) + '".'); + } + return result; + }; + + Inline.dump = function (value, exceptionOnInvalidType, objectEncoder) { + var ref, result, type; + if (exceptionOnInvalidType == null) { + exceptionOnInvalidType = false; + } + if (objectEncoder == null) { + objectEncoder = null; + } + if (value == null) { + return 'null'; + } + type = typeof value; + if (type === 'object') { + if (value instanceof Date) { + return value.toISOString(); + } else if (objectEncoder != null) { + result = objectEncoder(value); + if (typeof result === 'string' || (result != null)) { + return result; + } + } + return this.dumpObject(value); + } + if (type === 'boolean') { + return (value ? 'true' : 'false'); + } + if (Utils.isDigits(value)) { + return (type === 'string' ? "'" + value + "'" : String(parseInt(value))); + } + if (Utils.isNumeric(value)) { + return (type === 'string' ? "'" + value + "'" : String(parseFloat(value))); + } + if (type === 'number') { + return (value === Infinity ? '.Inf' : (value === -Infinity ? '-.Inf' : (isNaN(value) ? '.NaN' : value))); + } + if (Escaper.requiresDoubleQuoting(value)) { + return Escaper.escapeWithDoubleQuotes(value); + } + if (Escaper.requiresSingleQuoting(value)) { + return Escaper.escapeWithSingleQuotes(value); + } + if ('' === value) { + return '""'; + } + if (Utils.PATTERN_DATE.test(value)) { + return "'" + value + "'"; + } + if ((ref = value.toLowerCase()) === 'null' || ref === '~' || ref === 'true' || ref === 'false') { + return "'" + value + "'"; + } + return value; + }; + + Inline.dumpObject = function (value, exceptionOnInvalidType, objectSupport) { + var j, key, len1, output, val; + if (objectSupport == null) { + objectSupport = null; + } + if (value instanceof Array) { + output = []; + for (j = 0, len1 = value.length; j < len1; j++) { + val = value[j]; + output.push(this.dump(val)); + } + return '[' + output.join(', ') + ']'; + } else { + output = []; + for (key in value) { + val = value[key]; + output.push(this.dump(key) + ': ' + this.dump(val)); + } + return '{' + output.join(', ') + '}'; + } + }; + + Inline.parseScalar = function (scalar, delimiters, stringDelimiters, context, evaluate) { + var i, joinedDelimiters, match, output, pattern, ref, ref1, strpos, tmp; + if (delimiters == null) { + delimiters = null; + } + if (stringDelimiters == null) { + stringDelimiters = ['"', "'"]; + } + if (context == null) { + context = null; + } + if (evaluate == null) { + evaluate = true; + } + if (context == null) { + context = { + exceptionOnInvalidType: this.settings.exceptionOnInvalidType, + objectDecoder: this.settings.objectDecoder, + i: 0 + }; + } + i = context.i; + if (ref = scalar.charAt(i), indexOf.call(stringDelimiters, ref) >= 0) { + output = this.parseQuotedScalar(scalar, context); + i = context.i; + if (delimiters != null) { + tmp = Utils.ltrim(scalar.slice(i), ' '); + if (!(ref1 = tmp.charAt(0), indexOf.call(delimiters, ref1) >= 0)) { + throw new ParseException('Unexpected characters (' + scalar.slice(i) + ').'); + } + } + } else { + if (!delimiters) { + output = scalar.slice(i); + i += output.length; + strpos = output.indexOf(' #'); + if (strpos !== -1) { + output = Utils.rtrim(output.slice(0, strpos)); + } + } else { + joinedDelimiters = delimiters.join('|'); + pattern = this.PATTERN_SCALAR_BY_DELIMITERS[joinedDelimiters]; + if (pattern == null) { + pattern = new Pattern('^(.+?)(' + joinedDelimiters + ')'); + this.PATTERN_SCALAR_BY_DELIMITERS[joinedDelimiters] = pattern; + } + if (match = pattern.exec(scalar.slice(i))) { + output = match[1]; + i += output.length; + } else { + throw new ParseException('Malformed inline YAML string (' + scalar + ').'); + } + } + if (evaluate) { + output = this.evaluateScalar(output, context); + } + } + context.i = i; + return output; + }; + + Inline.parseQuotedScalar = function (scalar, context) { + var i, match, output; + i = context.i; + if (!(match = this.PATTERN_QUOTED_SCALAR.exec(scalar.slice(i)))) { + throw new ParseMore('Malformed inline YAML string (' + scalar.slice(i) + ').'); + } + output = match[0].substr(1, match[0].length - 2); + if ('"' === scalar.charAt(i)) { + output = Unescaper.unescapeDoubleQuotedString(output); + } else { + output = Unescaper.unescapeSingleQuotedString(output); + } + i += match[0].length; + context.i = i; + return output; + }; + + Inline.parseSequence = function (sequence, context) { + var e, error, i, isQuoted, len, output, ref, value; + output = []; + len = sequence.length; + i = context.i; + i += 1; + while (i < len) { + context.i = i; + switch (sequence.charAt(i)) { + case '[': + output.push(this.parseSequence(sequence, context)); + i = context.i; + break; + case '{': + output.push(this.parseMapping(sequence, context)); + i = context.i; + break; + case ']': + return output; + case ',': + case ' ': + case "\n": + break; + default: + isQuoted = ((ref = sequence.charAt(i)) === '"' || ref === "'"); + value = this.parseScalar(sequence, [',', ']'], ['"', "'"], context); + i = context.i; + if (!isQuoted && typeof value === 'string' && (value.indexOf(': ') !== -1 || value.indexOf(":\n") !== -1)) { + try { + value = this.parseMapping('{' + value + '}'); + } catch (error) { + e = error; + } + } + output.push(value); + --i; + } + ++i; + } + throw new ParseMore('Malformed inline YAML string ' + sequence); + }; + + Inline.parseMapping = function (mapping, context) { + var done, i, key, len, output, shouldContinueWhileLoop, value; + output = {}; + len = mapping.length; + i = context.i; + i += 1; + shouldContinueWhileLoop = false; + while (i < len) { + context.i = i; + switch (mapping.charAt(i)) { + case ' ': + case ',': + case "\n": + ++i; + context.i = i; + shouldContinueWhileLoop = true; + break; + case '}': + return output; + } + if (shouldContinueWhileLoop) { + shouldContinueWhileLoop = false; + continue; + } + key = this.parseScalar(mapping, [':', ' ', "\n"], ['"', "'"], context, false); + i = context.i; + done = false; + while (i < len) { + context.i = i; + switch (mapping.charAt(i)) { + case '[': + value = this.parseSequence(mapping, context); + i = context.i; + if (output[key] === void 0) { + output[key] = value; + } + done = true; + break; + case '{': + value = this.parseMapping(mapping, context); + i = context.i; + if (output[key] === void 0) { + output[key] = value; + } + done = true; + break; + case ':': + case ' ': + case "\n": + break; + default: + value = this.parseScalar(mapping, [',', '}'], ['"', "'"], context); + i = context.i; + if (output[key] === void 0) { + output[key] = value; + } + done = true; + --i; + } + ++i; + if (done) { + break; + } + } + } + throw new ParseMore('Malformed inline YAML string ' + mapping); + }; + + Inline.evaluateScalar = function (scalar, context) { + var cast, date, exceptionOnInvalidType, firstChar, firstSpace, firstWord, objectDecoder, raw, scalarLower, + subValue, trimmedScalar; + scalar = Utils.trim(scalar); + scalarLower = scalar.toLowerCase(); + switch (scalarLower) { + case 'null': + case '': + case '~': + return null; + case 'true': + return true; + case 'false': + return false; + case '.inf': + return Infinity; + case '.nan': + return NaN; + case '-.inf': + return Infinity; + default: + firstChar = scalarLower.charAt(0); + switch (firstChar) { + case '!': + firstSpace = scalar.indexOf(' '); + if (firstSpace === -1) { + firstWord = scalarLower; + } else { + firstWord = scalarLower.slice(0, firstSpace); + } + switch (firstWord) { + case '!': + if (firstSpace !== -1) { + return parseInt(this.parseScalar(scalar.slice(2))); + } + return null; + case '!str': + return Utils.ltrim(scalar.slice(4)); + case '!!str': + return Utils.ltrim(scalar.slice(5)); + case '!!int': + return parseInt(this.parseScalar(scalar.slice(5))); + case '!!bool': + return Utils.parseBoolean(this.parseScalar(scalar.slice(6)), false); + case '!!float': + return parseFloat(this.parseScalar(scalar.slice(7))); + case '!!timestamp': + return Utils.stringToDate(Utils.ltrim(scalar.slice(11))); + default: + if (context == null) { + context = { + exceptionOnInvalidType: this.settings.exceptionOnInvalidType, + objectDecoder: this.settings.objectDecoder, + i: 0 + }; + } + objectDecoder = context.objectDecoder, exceptionOnInvalidType = context.exceptionOnInvalidType; + if (objectDecoder) { + trimmedScalar = Utils.rtrim(scalar); + firstSpace = trimmedScalar.indexOf(' '); + if (firstSpace === -1) { + return objectDecoder(trimmedScalar, null); + } else { + subValue = Utils.ltrim(trimmedScalar.slice(firstSpace + 1)); + if (!(subValue.length > 0)) { + subValue = null; + } + return objectDecoder(trimmedScalar.slice(0, firstSpace), subValue); + } + } + if (exceptionOnInvalidType) { + throw new ParseException('Custom object support when parsing a YAML file has been disabled.'); + } + return null; + } + break; + case '0': + if ('0x' === scalar.slice(0, 2)) { + return Utils.hexDec(scalar); + } else if (Utils.isDigits(scalar)) { + return Utils.octDec(scalar); + } else if (Utils.isNumeric(scalar)) { + return parseFloat(scalar); + } else { + return scalar; + } + break; + case '+': + if (Utils.isDigits(scalar)) { + raw = scalar; + cast = parseInt(raw); + if (raw === String(cast)) { + return cast; + } else { + return raw; + } + } else if (Utils.isNumeric(scalar)) { + return parseFloat(scalar); + } else if (this.PATTERN_THOUSAND_NUMERIC_SCALAR.test(scalar)) { + return parseFloat(scalar.replace(',', '')); + } + return scalar; + case '-': + if (Utils.isDigits(scalar.slice(1))) { + if ('0' === scalar.charAt(1)) { + return -Utils.octDec(scalar.slice(1)); + } else { + raw = scalar.slice(1); + cast = parseInt(raw); + if (raw === String(cast)) { + return -cast; + } else { + return -raw; + } + } + } else if (Utils.isNumeric(scalar)) { + return parseFloat(scalar); + } else if (this.PATTERN_THOUSAND_NUMERIC_SCALAR.test(scalar)) { + return parseFloat(scalar.replace(',', '')); + } + return scalar; + default: + if (date = Utils.stringToDate(scalar)) { + return date; + } else if (Utils.isNumeric(scalar)) { + return parseFloat(scalar); + } else if (this.PATTERN_THOUSAND_NUMERIC_SCALAR.test(scalar)) { + return parseFloat(scalar.replace(',', '')); + } + return scalar; + } + } + }; + + return Inline; + + })(); + + module.exports = Inline; + + + }, { + "./Escaper": 2, + "./Exception/DumpException": 3, + "./Exception/ParseException": 4, + "./Exception/ParseMore": 5, + "./Pattern": 8, + "./Unescaper": 9, + "./Utils": 10 + }], + 7: [function (require, module, exports) { + var Inline, ParseException, ParseMore, Parser, Pattern, Utils; + + Inline = require('./Inline'); + + Pattern = require('./Pattern'); + + Utils = require('./Utils'); + + ParseException = require('./Exception/ParseException'); + + ParseMore = require('./Exception/ParseMore'); + + Parser = (function () { + Parser.prototype.PATTERN_FOLDED_SCALAR_ALL = new Pattern( + '^(?:(?![^\\|>]*)\\s+)?(?\\||>)(?\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(? +#.*)?$' + ); + + Parser.prototype.PATTERN_FOLDED_SCALAR_END = new Pattern( + '(?\\||>)(?\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(? +#.*)?$'); + + Parser.prototype.PATTERN_SEQUENCE_ITEM = new Pattern('^\\-((?\\s+)(?.+?))?\\s*$'); + + Parser.prototype.PATTERN_ANCHOR_VALUE = new Pattern('^&(?[^ ]+) *(?.*)'); + + Parser.prototype.PATTERN_COMPACT_NOTATION = new Pattern('^(?' + Inline.REGEX_QUOTED_STRING + + '|[^ \'"\\{\\[].*?) *\\:(\\s+(?.+?))?\\s*$'); + + Parser.prototype.PATTERN_MAPPING_ITEM = new Pattern('^(?' + Inline.REGEX_QUOTED_STRING + + '|[^ \'"\\[\\{].*?) *\\:(\\s+(?.+?))?\\s*$'); + + Parser.prototype.PATTERN_DECIMAL = new Pattern('\\d+'); + + Parser.prototype.PATTERN_INDENT_SPACES = new Pattern('^ +'); + + Parser.prototype.PATTERN_TRAILING_LINES = new Pattern('(\n*)$'); + + Parser.prototype.PATTERN_YAML_HEADER = new Pattern('^\\%YAML[: ][\\d\\.]+.*\n', 'm'); + + Parser.prototype.PATTERN_LEADING_COMMENTS = new Pattern('^(\\#.*?\n)+', 'm'); + + Parser.prototype.PATTERN_DOCUMENT_MARKER_START = new Pattern('^\\-\\-\\-.*?\n', 'm'); + + Parser.prototype.PATTERN_DOCUMENT_MARKER_END = new Pattern('^\\.\\.\\.\\s*$', 'm'); + + Parser.prototype.PATTERN_FOLDED_SCALAR_BY_INDENTATION = {}; + + Parser.prototype.CONTEXT_NONE = 0; + + Parser.prototype.CONTEXT_SEQUENCE = 1; + + Parser.prototype.CONTEXT_MAPPING = 2; + + function Parser(offset) { + this.offset = offset != null ? offset : 0; + this.lines = []; + this.currentLineNb = -1; + this.currentLine = ''; + this.refs = {}; + } + + Parser.prototype.parse = function (value, exceptionOnInvalidType, objectDecoder) { + var alias, allowOverwrite, block, c, context, data, e, error, error1, error2, first, i, indent, isRef, j, k, + key, l, lastKey, len, len1, len2, len3, lineCount, m, matches, mergeNode, n, name, parsed, parsedItem, + parser, ref, ref1, ref2, refName, refValue, val, values; + if (exceptionOnInvalidType == null) { + exceptionOnInvalidType = false; + } + if (objectDecoder == null) { + objectDecoder = null; + } + this.currentLineNb = -1; + this.currentLine = ''; + this.lines = this.cleanup(value).split("\n"); + data = null; + context = this.CONTEXT_NONE; + allowOverwrite = false; + while (this.moveToNextLine()) { + if (this.isCurrentLineEmpty()) { + continue; + } + if ("\t" === this.currentLine[0]) { + throw new ParseException('A YAML file cannot contain tabs as indentation.', this.getRealCurrentLineNb() + 1, + this.currentLine); + } + isRef = mergeNode = false; + if (values = this.PATTERN_SEQUENCE_ITEM.exec(this.currentLine)) { + if (this.CONTEXT_MAPPING === context) { + throw new ParseException('You cannot define a sequence item when in a mapping'); + } + context = this.CONTEXT_SEQUENCE; + if (data == null) { + data = []; + } + if ((values.value != null) && (matches = this.PATTERN_ANCHOR_VALUE.exec(values.value))) { + isRef = matches.ref; + values.value = matches.value; + } + if (!(values.value != null) || '' === Utils.trim(values.value, ' ') || Utils.ltrim(values.value, ' ').indexOf( + '#') === 0) { + if (this.currentLineNb < this.lines.length - 1 && !this.isNextLineUnIndentedCollection()) { + c = this.getRealCurrentLineNb() + 1; + parser = new Parser(c); + parser.refs = this.refs; + data.push(parser.parse(this.getNextEmbedBlock(null, true), exceptionOnInvalidType, objectDecoder)); + } else { + data.push(null); + } + } else { + if (((ref = values.leadspaces) != null ? ref.length : void 0) && (matches = this.PATTERN_COMPACT_NOTATION.exec( + values.value))) { + c = this.getRealCurrentLineNb(); + parser = new Parser(c); + parser.refs = this.refs; + block = values.value; + indent = this.getCurrentLineIndentation(); + if (this.isNextLineIndented(false)) { + block += "\n" + this.getNextEmbedBlock(indent + values.leadspaces.length + 1, true); + } + data.push(parser.parse(block, exceptionOnInvalidType, objectDecoder)); + } else { + data.push(this.parseValue(values.value, exceptionOnInvalidType, objectDecoder)); + } + } + } else if ((values = this.PATTERN_MAPPING_ITEM.exec(this.currentLine)) && values.key.indexOf(' #') === -1) { + if (this.CONTEXT_SEQUENCE === context) { + throw new ParseException('You cannot define a mapping item when in a sequence'); + } + context = this.CONTEXT_MAPPING; + if (data == null) { + data = {}; + } + Inline.configure(exceptionOnInvalidType, objectDecoder); + try { + key = Inline.parseScalar(values.key); + } catch (error) { + e = error; + e.parsedLine = this.getRealCurrentLineNb() + 1; + e.snippet = this.currentLine; + throw e; + } + if ('<<' === key) { + mergeNode = true; + allowOverwrite = true; + if (((ref1 = values.value) != null ? ref1.indexOf('*') : void 0) === 0) { + refName = values.value.slice(1); + if (this.refs[refName] == null) { + throw new ParseException('Reference "' + refName + '" does not exist.', this.getRealCurrentLineNb() + 1, + this.currentLine); + } + refValue = this.refs[refName]; + if (typeof refValue !== 'object') { + throw new ParseException('YAML merge keys used with a scalar value instead of an object.', this.getRealCurrentLineNb() + + 1, this.currentLine); + } + if (refValue instanceof Array) { + for (i = j = 0, len = refValue.length; j < len; i = ++j) { + value = refValue[i]; + if (data[name = String(i)] == null) { + data[name] = value; + } + } + } else { + for (key in refValue) { + value = refValue[key]; + if (data[key] == null) { + data[key] = value; + } + } + } + } else { + if ((values.value != null) && values.value !== '') { + value = values.value; + } else { + value = this.getNextEmbedBlock(); + } + c = this.getRealCurrentLineNb() + 1; + parser = new Parser(c); + parser.refs = this.refs; + parsed = parser.parse(value, exceptionOnInvalidType); + if (typeof parsed !== 'object') { + throw new ParseException('YAML merge keys used with a scalar value instead of an object.', this.getRealCurrentLineNb() + + 1, this.currentLine); + } + if (parsed instanceof Array) { + for (l = 0, len1 = parsed.length; l < len1; l++) { + parsedItem = parsed[l]; + if (typeof parsedItem !== 'object') { + throw new ParseException('Merge items must be objects.', this.getRealCurrentLineNb() + 1, parsedItem); + } + if (parsedItem instanceof Array) { + for (i = m = 0, len2 = parsedItem.length; m < len2; i = ++m) { + value = parsedItem[i]; + k = String(i); + if (!data.hasOwnProperty(k)) { + data[k] = value; + } + } + } else { + for (key in parsedItem) { + value = parsedItem[key]; + if (!data.hasOwnProperty(key)) { + data[key] = value; + } + } + } + } + } else { + for (key in parsed) { + value = parsed[key]; + if (!data.hasOwnProperty(key)) { + data[key] = value; + } + } + } + } + } else if ((values.value != null) && (matches = this.PATTERN_ANCHOR_VALUE.exec(values.value))) { + isRef = matches.ref; + values.value = matches.value; + } + if (mergeNode) { + + } else if (!(values.value != null) || '' === Utils.trim(values.value, ' ') || Utils.ltrim(values.value, ' ') + .indexOf('#') === 0) { + if (!(this.isNextLineIndented()) && !(this.isNextLineUnIndentedCollection())) { + if (allowOverwrite || data[key] === void 0) { + data[key] = null; + } + } else { + c = this.getRealCurrentLineNb() + 1; + parser = new Parser(c); + parser.refs = this.refs; + val = parser.parse(this.getNextEmbedBlock(), exceptionOnInvalidType, objectDecoder); + if (allowOverwrite || data[key] === void 0) { + data[key] = val; + } + } + } else { + val = this.parseValue(values.value, exceptionOnInvalidType, objectDecoder); + if (allowOverwrite || data[key] === void 0) { + data[key] = val; + } + } + } else { + lineCount = this.lines.length; + if (1 === lineCount || (2 === lineCount && Utils.isEmpty(this.lines[1]))) { + try { + value = Inline.parse(this.lines[0], exceptionOnInvalidType, objectDecoder); + } catch (error1) { + e = error1; + e.parsedLine = this.getRealCurrentLineNb() + 1; + e.snippet = this.currentLine; + throw e; + } + if (typeof value === 'object') { + if (value instanceof Array) { + first = value[0]; + } else { + for (key in value) { + first = value[key]; + break; + } + } + if (typeof first === 'string' && first.indexOf('*') === 0) { + data = []; + for (n = 0, len3 = value.length; n < len3; n++) { + alias = value[n]; + data.push(this.refs[alias.slice(1)]); + } + value = data; + } + } + return value; + } else if ((ref2 = Utils.ltrim(value).charAt(0)) === '[' || ref2 === '{') { + try { + return Inline.parse(value, exceptionOnInvalidType, objectDecoder); + } catch (error2) { + e = error2; + e.parsedLine = this.getRealCurrentLineNb() + 1; + e.snippet = this.currentLine; + throw e; + } + } + throw new ParseException('Unable to parse.', this.getRealCurrentLineNb() + 1, this.currentLine); + } + if (isRef) { + if (data instanceof Array) { + this.refs[isRef] = data[data.length - 1]; + } else { + lastKey = null; + for (key in data) { + lastKey = key; + } + this.refs[isRef] = data[lastKey]; + } + } + } + if (Utils.isEmpty(data)) { + return null; + } else { + return data; + } + }; + + Parser.prototype.getRealCurrentLineNb = function () { + return this.currentLineNb + this.offset; + }; + + Parser.prototype.getCurrentLineIndentation = function () { + return this.currentLine.length - Utils.ltrim(this.currentLine, ' ').length; + }; + + Parser.prototype.getNextEmbedBlock = function (indentation, includeUnindentedCollection) { + var data, indent, isItUnindentedCollection, newIndent, removeComments, removeCommentsPattern, + unindentedEmbedBlock; + if (indentation == null) { + indentation = null; + } + if (includeUnindentedCollection == null) { + includeUnindentedCollection = false; + } + this.moveToNextLine(); + if (indentation == null) { + newIndent = this.getCurrentLineIndentation(); + unindentedEmbedBlock = this.isStringUnIndentedCollectionItem(this.currentLine); + if (!(this.isCurrentLineEmpty()) && 0 === newIndent && !unindentedEmbedBlock) { + throw new ParseException('Indentation problem.', this.getRealCurrentLineNb() + 1, this.currentLine); + } + } else { + newIndent = indentation; + } + data = [this.currentLine.slice(newIndent)]; + if (!includeUnindentedCollection) { + isItUnindentedCollection = this.isStringUnIndentedCollectionItem(this.currentLine); + } + removeCommentsPattern = this.PATTERN_FOLDED_SCALAR_END; + removeComments = !removeCommentsPattern.test(this.currentLine); + while (this.moveToNextLine()) { + indent = this.getCurrentLineIndentation(); + if (indent === newIndent) { + removeComments = !removeCommentsPattern.test(this.currentLine); + } + if (removeComments && this.isCurrentLineComment()) { + continue; + } + if (this.isCurrentLineBlank()) { + data.push(this.currentLine.slice(newIndent)); + continue; + } + if (isItUnindentedCollection && !this.isStringUnIndentedCollectionItem(this.currentLine) && indent === + newIndent) { + this.moveToPreviousLine(); + break; + } + if (indent >= newIndent) { + data.push(this.currentLine.slice(newIndent)); + } else if (Utils.ltrim(this.currentLine).charAt(0) === '#') { + + } else if (0 === indent) { + this.moveToPreviousLine(); + break; + } else { + throw new ParseException('Indentation problem.', this.getRealCurrentLineNb() + 1, this.currentLine); + } + } + return data.join("\n"); + }; + + Parser.prototype.moveToNextLine = function () { + if (this.currentLineNb >= this.lines.length - 1) { + return false; + } + this.currentLine = this.lines[++this.currentLineNb]; + return true; + }; + + Parser.prototype.moveToPreviousLine = function () { + this.currentLine = this.lines[--this.currentLineNb]; + }; + + Parser.prototype.parseValue = function (value, exceptionOnInvalidType, objectDecoder) { + var e, error, foldedIndent, matches, modifiers, pos, ref, ref1, val; + if (0 === value.indexOf('*')) { + pos = value.indexOf('#'); + if (pos !== -1) { + value = value.substr(1, pos - 2); + } else { + value = value.slice(1); + } + if (this.refs[value] === void 0) { + throw new ParseException('Reference "' + value + '" does not exist.', this.currentLine); + } + return this.refs[value]; + } + if (matches = this.PATTERN_FOLDED_SCALAR_ALL.exec(value)) { + modifiers = (ref = matches.modifiers) != null ? ref : ''; + foldedIndent = Math.abs(parseInt(modifiers)); + if (isNaN(foldedIndent)) { + foldedIndent = 0; + } + val = this.parseFoldedScalar(matches.separator, this.PATTERN_DECIMAL.replace(modifiers, ''), foldedIndent); + if (matches.type != null) { + Inline.configure(exceptionOnInvalidType, objectDecoder); + return Inline.parseScalar(matches.type + ' ' + val); + } else { + return val; + } + } + if ((ref1 = value.charAt(0)) === '[' || ref1 === '{' || ref1 === '"' || ref1 === "'") { + while (true) { + try { + return Inline.parse(value, exceptionOnInvalidType, objectDecoder); + } catch (error) { + e = error; + if (e instanceof ParseMore && this.moveToNextLine()) { + value += "\n" + Utils.trim(this.currentLine, ' '); + } else { + e.parsedLine = this.getRealCurrentLineNb() + 1; + e.snippet = this.currentLine; + throw e; + } + } + } + } else { + if (this.isNextLineIndented()) { + value += "\n" + this.getNextEmbedBlock(); + } + return Inline.parse(value, exceptionOnInvalidType, objectDecoder); + } + }; + + Parser.prototype.parseFoldedScalar = function (separator, indicator, indentation) { + var isCurrentLineBlank, j, len, line, matches, newText, notEOF, pattern, ref, text; + if (indicator == null) { + indicator = ''; + } + if (indentation == null) { + indentation = 0; + } + notEOF = this.moveToNextLine(); + if (!notEOF) { + return ''; + } + isCurrentLineBlank = this.isCurrentLineBlank(); + text = ''; + while (notEOF && isCurrentLineBlank) { + if (notEOF = this.moveToNextLine()) { + text += "\n"; + isCurrentLineBlank = this.isCurrentLineBlank(); + } + } + if (0 === indentation) { + if (matches = this.PATTERN_INDENT_SPACES.exec(this.currentLine)) { + indentation = matches[0].length; + } + } + if (indentation > 0) { + pattern = this.PATTERN_FOLDED_SCALAR_BY_INDENTATION[indentation]; + if (pattern == null) { + pattern = new Pattern('^ {' + indentation + '}(.*)$'); + Parser.prototype.PATTERN_FOLDED_SCALAR_BY_INDENTATION[indentation] = pattern; + } + while (notEOF && (isCurrentLineBlank || (matches = pattern.exec(this.currentLine)))) { + if (isCurrentLineBlank) { + text += this.currentLine.slice(indentation); + } else { + text += matches[1]; + } + if (notEOF = this.moveToNextLine()) { + text += "\n"; + isCurrentLineBlank = this.isCurrentLineBlank(); + } + } + } else if (notEOF) { + text += "\n"; + } + if (notEOF) { + this.moveToPreviousLine(); + } + if ('>' === separator) { + newText = ''; + ref = text.split("\n"); + for (j = 0, len = ref.length; j < len; j++) { + line = ref[j]; + if (line.length === 0 || line.charAt(0) === ' ') { + newText = Utils.rtrim(newText, ' ') + line + "\n"; + } else { + newText += line + ' '; + } + } + text = newText; + } + if ('+' !== indicator) { + text = Utils.rtrim(text); + } + if ('' === indicator) { + text = this.PATTERN_TRAILING_LINES.replace(text, "\n"); + } else if ('-' === indicator) { + text = this.PATTERN_TRAILING_LINES.replace(text, ''); + } + return text; + }; + + Parser.prototype.isNextLineIndented = function (ignoreComments) { + var EOF, currentIndentation, ret; + if (ignoreComments == null) { + ignoreComments = true; + } + currentIndentation = this.getCurrentLineIndentation(); + EOF = !this.moveToNextLine(); + if (ignoreComments) { + while (!EOF && this.isCurrentLineEmpty()) { + EOF = !this.moveToNextLine(); + } + } else { + while (!EOF && this.isCurrentLineBlank()) { + EOF = !this.moveToNextLine(); + } + } + if (EOF) { + return false; + } + ret = false; + if (this.getCurrentLineIndentation() > currentIndentation) { + ret = true; + } + this.moveToPreviousLine(); + return ret; + }; + + Parser.prototype.isCurrentLineEmpty = function () { + var trimmedLine; + trimmedLine = Utils.trim(this.currentLine, ' '); + return trimmedLine.length === 0 || trimmedLine.charAt(0) === '#'; + }; + + Parser.prototype.isCurrentLineBlank = function () { + return '' === Utils.trim(this.currentLine, ' '); + }; + + Parser.prototype.isCurrentLineComment = function () { + var ltrimmedLine; + ltrimmedLine = Utils.ltrim(this.currentLine, ' '); + return ltrimmedLine.charAt(0) === '#'; + }; + + Parser.prototype.cleanup = function (value) { + var count, i, indent, j, l, len, len1, line, lines, ref, ref1, ref2, smallestIndent, trimmedValue; + if (value.indexOf("\r") !== -1) { + value = value.split("\r\n").join("\n").split("\r").join("\n"); + } + count = 0; + ref = this.PATTERN_YAML_HEADER.replaceAll(value, ''), value = ref[0], count = ref[1]; + this.offset += count; + ref1 = this.PATTERN_LEADING_COMMENTS.replaceAll(value, '', 1), trimmedValue = ref1[0], count = ref1[1]; + if (count === 1) { + this.offset += Utils.subStrCount(value, "\n") - Utils.subStrCount(trimmedValue, "\n"); + value = trimmedValue; + } + ref2 = this.PATTERN_DOCUMENT_MARKER_START.replaceAll(value, '', 1), trimmedValue = ref2[0], count = ref2[1]; + if (count === 1) { + this.offset += Utils.subStrCount(value, "\n") - Utils.subStrCount(trimmedValue, "\n"); + value = trimmedValue; + value = this.PATTERN_DOCUMENT_MARKER_END.replace(value, ''); + } + lines = value.split("\n"); + smallestIndent = -1; + for (j = 0, len = lines.length; j < len; j++) { + line = lines[j]; + if (Utils.trim(line, ' ').length === 0) { + continue; + } + indent = line.length - Utils.ltrim(line).length; + if (smallestIndent === -1 || indent < smallestIndent) { + smallestIndent = indent; + } + } + if (smallestIndent > 0) { + for (i = l = 0, len1 = lines.length; l < len1; i = ++l) { + line = lines[i]; + lines[i] = line.slice(smallestIndent); + } + value = lines.join("\n"); + } + return value; + }; + + Parser.prototype.isNextLineUnIndentedCollection = function (currentIndentation) { + var notEOF, ret; + if (currentIndentation == null) { + currentIndentation = null; + } + if (currentIndentation == null) { + currentIndentation = this.getCurrentLineIndentation(); + } + notEOF = this.moveToNextLine(); + while (notEOF && this.isCurrentLineEmpty()) { + notEOF = this.moveToNextLine(); + } + if (false === notEOF) { + return false; + } + ret = false; + if (this.getCurrentLineIndentation() === currentIndentation && this.isStringUnIndentedCollectionItem(this.currentLine)) { + ret = true; + } + this.moveToPreviousLine(); + return ret; + }; + + Parser.prototype.isStringUnIndentedCollectionItem = function () { + return this.currentLine === '-' || this.currentLine.slice(0, 2) === '- '; + }; + + return Parser; + + })(); + + module.exports = Parser; + + + }, { + "./Exception/ParseException": 4, + "./Exception/ParseMore": 5, + "./Inline": 6, + "./Pattern": 8, + "./Utils": 10 + }], + 8: [function (require, module, exports) { + var Pattern; + + Pattern = (function () { + Pattern.prototype.regex = null; + + Pattern.prototype.rawRegex = null; + + Pattern.prototype.cleanedRegex = null; + + Pattern.prototype.mapping = null; + + function Pattern(rawRegex, modifiers) { + var _char, capturingBracketNumber, cleanedRegex, i, len, mapping, name, part, subChar; + if (modifiers == null) { + modifiers = ''; + } + cleanedRegex = ''; + len = rawRegex.length; + mapping = null; + capturingBracketNumber = 0; + i = 0; + while (i < len) { + _char = rawRegex.charAt(i); + if (_char === '\\') { + cleanedRegex += rawRegex.slice(i, +(i + 1) + 1 || 9e9); + i++; + } else if (_char === '(') { + if (i < len - 2) { + part = rawRegex.slice(i, +(i + 2) + 1 || 9e9); + if (part === '(?:') { + i += 2; + cleanedRegex += part; + } else if (part === '(?<') { + capturingBracketNumber++; + i += 2; + name = ''; + while (i + 1 < len) { + subChar = rawRegex.charAt(i + 1); + if (subChar === '>') { + cleanedRegex += '('; + i++; + if (name.length > 0) { + if (mapping == null) { + mapping = {}; + } + mapping[name] = capturingBracketNumber; + } + break; + } else { + name += subChar; + } + i++; + } + } else { + cleanedRegex += _char; + capturingBracketNumber++; + } + } else { + cleanedRegex += _char; + } + } else { + cleanedRegex += _char; + } + i++; + } + this.rawRegex = rawRegex; + this.cleanedRegex = cleanedRegex; + this.regex = new RegExp(this.cleanedRegex, 'g' + modifiers.replace('g', '')); + this.mapping = mapping; + } + + Pattern.prototype.exec = function (str) { + var index, matches, name, ref; + this.regex.lastIndex = 0; + matches = this.regex.exec(str); + if (matches == null) { + return null; + } + if (this.mapping != null) { + ref = this.mapping; + for (name in ref) { + index = ref[name]; + matches[name] = matches[index]; + } + } + return matches; + }; + + Pattern.prototype.test = function (str) { + this.regex.lastIndex = 0; + return this.regex.test(str); + }; + + Pattern.prototype.replace = function (str, replacement) { + this.regex.lastIndex = 0; + return str.replace(this.regex, replacement); + }; + + Pattern.prototype.replaceAll = function (str, replacement, limit) { + var count; + if (limit == null) { + limit = 0; + } + this.regex.lastIndex = 0; + count = 0; + while (this.regex.test(str) && (limit === 0 || count < limit)) { + this.regex.lastIndex = 0; + str = str.replace(this.regex, replacement); + count++; + } + return [str, count]; + }; + + return Pattern; + + })(); + + module.exports = Pattern; + + + }, {}], + 9: [function (require, module, exports) { + var Pattern, Unescaper, Utils; + + Utils = require('./Utils'); + + Pattern = require('./Pattern'); + + Unescaper = (function () { + function Unescaper() { } + + Unescaper.PATTERN_ESCAPED_CHARACTER = new Pattern( + '\\\\([0abt\tnvfre "\\/\\\\N_LP]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})'); + + Unescaper.unescapeSingleQuotedString = function (value) { + return value.replace(/\'\'/g, '\''); + }; + + Unescaper.unescapeDoubleQuotedString = function (value) { + if (this._unescapeCallback == null) { + this._unescapeCallback = (function (_this) { + return function (str) { + return _this.unescapeCharacter(str); + }; + })(this); + } + return this.PATTERN_ESCAPED_CHARACTER.replace(value, this._unescapeCallback); + }; + + Unescaper.unescapeCharacter = function (value) { + var ch; + ch = String.fromCharCode; + switch (value.charAt(1)) { + case '0': + return ch(0); + case 'a': + return ch(7); + case 'b': + return ch(8); + case 't': + return "\t"; + case "\t": + return "\t"; + case 'n': + return "\n"; + case 'v': + return ch(11); + case 'f': + return ch(12); + case 'r': + return ch(13); + case 'e': + return ch(27); + case ' ': + return ' '; + case '"': + return '"'; + case '/': + return '/'; + case '\\': + return '\\'; + case 'N': + return ch(0x0085); + case '_': + return ch(0x00A0); + case 'L': + return ch(0x2028); + case 'P': + return ch(0x2029); + case 'x': + return Utils.utf8chr(Utils.hexDec(value.substr(2, 2))); + case 'u': + return Utils.utf8chr(Utils.hexDec(value.substr(2, 4))); + case 'U': + return Utils.utf8chr(Utils.hexDec(value.substr(2, 8))); + default: + return ''; + } + }; + + return Unescaper; + + })(); + + module.exports = Unescaper; + + + }, { + "./Pattern": 8, + "./Utils": 10 + }], + 10: [function (require, module, exports) { + var Pattern, Utils, + hasProp = {}.hasOwnProperty; + + Pattern = require('./Pattern'); + + Utils = (function () { + function Utils() { } + + Utils.REGEX_LEFT_TRIM_BY_CHAR = {}; + + Utils.REGEX_RIGHT_TRIM_BY_CHAR = {}; + + Utils.REGEX_SPACES = /\s+/g; + + Utils.REGEX_DIGITS = /^\d+$/; + + Utils.REGEX_OCTAL = /[^0-7]/gi; + + Utils.REGEX_HEXADECIMAL = /[^a-f0-9]/gi; + + Utils.PATTERN_DATE = new Pattern('^' + '(?[0-9][0-9][0-9][0-9])' + '-(?[0-9][0-9]?)' + + '-(?[0-9][0-9]?)' + '(?:(?:[Tt]|[ \t]+)' + '(?[0-9][0-9]?)' + ':(?[0-9][0-9])' + + ':(?[0-9][0-9])' + '(?:\.(?[0-9]*))?' + + '(?:[ \t]*(?Z|(?[-+])(?[0-9][0-9]?)' + '(?::(?[0-9][0-9]))?))?)?' + '$', 'i' + ); + + Utils.LOCAL_TIMEZONE_OFFSET = new Date().getTimezoneOffset() * 60 * 1000; + + Utils.trim = function (str, _char) { + var regexLeft, regexRight; + if (_char == null) { + _char = '\\s'; + } + regexLeft = this.REGEX_LEFT_TRIM_BY_CHAR[_char]; + if (regexLeft == null) { + this.REGEX_LEFT_TRIM_BY_CHAR[_char] = regexLeft = new RegExp('^' + _char + '' + _char + '*'); + } + regexLeft.lastIndex = 0; + regexRight = this.REGEX_RIGHT_TRIM_BY_CHAR[_char]; + if (regexRight == null) { + this.REGEX_RIGHT_TRIM_BY_CHAR[_char] = regexRight = new RegExp(_char + '' + _char + '*$'); + } + regexRight.lastIndex = 0; + return str.replace(regexLeft, '').replace(regexRight, ''); + }; + + Utils.ltrim = function (str, _char) { + var regexLeft; + if (_char == null) { + _char = '\\s'; + } + regexLeft = this.REGEX_LEFT_TRIM_BY_CHAR[_char]; + if (regexLeft == null) { + this.REGEX_LEFT_TRIM_BY_CHAR[_char] = regexLeft = new RegExp('^' + _char + '' + _char + '*'); + } + regexLeft.lastIndex = 0; + return str.replace(regexLeft, ''); + }; + + Utils.rtrim = function (str, _char) { + var regexRight; + if (_char == null) { + _char = '\\s'; + } + regexRight = this.REGEX_RIGHT_TRIM_BY_CHAR[_char]; + if (regexRight == null) { + this.REGEX_RIGHT_TRIM_BY_CHAR[_char] = regexRight = new RegExp(_char + '' + _char + '*$'); + } + regexRight.lastIndex = 0; + return str.replace(regexRight, ''); + }; + + Utils.isEmpty = function (value) { + return !value || value === '' || value === '0' || (value instanceof Array && value.length === 0) || this.isEmptyObject( + value); + }; + + Utils.isEmptyObject = function (value) { + var k; + return value instanceof Object && ((function () { + var results; + results = []; + for (k in value) { + if (!hasProp.call(value, k)) continue; + results.push(k); + } + return results; + })()).length === 0; + }; + + Utils.subStrCount = function (string, subString, start, length) { + var c, i, j, len, ref, sublen; + c = 0; + string = '' + string; + subString = '' + subString; + if (start != null) { + string = string.slice(start); + } + if (length != null) { + string = string.slice(0, length); + } + len = string.length; + sublen = subString.length; + for (i = j = 0, ref = len; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { + if (subString === string.slice(i, sublen)) { + c++; + i += sublen - 1; + } + } + return c; + }; + + Utils.isDigits = function (input) { + this.REGEX_DIGITS.lastIndex = 0; + return this.REGEX_DIGITS.test(input); + }; + + Utils.octDec = function (input) { + this.REGEX_OCTAL.lastIndex = 0; + return parseInt((input + '').replace(this.REGEX_OCTAL, ''), 8); + }; + + Utils.hexDec = function (input) { + this.REGEX_HEXADECIMAL.lastIndex = 0; + input = this.trim(input); + if ((input + '').slice(0, 2) === '0x') { + input = (input + '').slice(2); + } + return parseInt((input + '').replace(this.REGEX_HEXADECIMAL, ''), 16); + }; + + Utils.utf8chr = function (c) { + var ch; + ch = String.fromCharCode; + if (0x80 > (c %= 0x200000)) { + return ch(c); + } + if (0x800 > c) { + return ch(0xC0 | c >> 6) + ch(0x80 | c & 0x3F); + } + if (0x10000 > c) { + return ch(0xE0 | c >> 12) + ch(0x80 | c >> 6 & 0x3F) + ch(0x80 | c & 0x3F); + } + return ch(0xF0 | c >> 18) + ch(0x80 | c >> 12 & 0x3F) + ch(0x80 | c >> 6 & 0x3F) + ch(0x80 | c & 0x3F); + }; + + Utils.parseBoolean = function (input, strict) { + var lowerInput; + if (strict == null) { + strict = true; + } + if (typeof input === 'string') { + lowerInput = input.toLowerCase(); + if (!strict) { + if (lowerInput === 'no') { + return false; + } + } + if (lowerInput === '0') { + return false; + } + if (lowerInput === 'false') { + return false; + } + if (lowerInput === '') { + return false; + } + return true; + } + return !!input; + }; + + Utils.isNumeric = function (input) { + this.REGEX_SPACES.lastIndex = 0; + return typeof input === 'number' || typeof input === 'string' && !isNaN(input) && input.replace(this.REGEX_SPACES, + '') !== ''; + }; + + Utils.stringToDate = function (str) { + var date, day, fraction, hour, info, minute, month, second, tz_hour, tz_minute, tz_offset, year; + if (!(str != null ? str.length : void 0)) { + return null; + } + info = this.PATTERN_DATE.exec(str); + if (!info) { + return null; + } + year = parseInt(info.year, 10); + month = parseInt(info.month, 10) - 1; + day = parseInt(info.day, 10); + if (info.hour == null) { + date = new Date(Date.UTC(year, month, day)); + return date; + } + hour = parseInt(info.hour, 10); + minute = parseInt(info.minute, 10); + second = parseInt(info.second, 10); + if (info.fraction != null) { + fraction = info.fraction.slice(0, 3); + while (fraction.length < 3) { + fraction += '0'; + } + fraction = parseInt(fraction, 10); + } else { + fraction = 0; + } + if (info.tz != null) { + tz_hour = parseInt(info.tz_hour, 10); + if (info.tz_minute != null) { + tz_minute = parseInt(info.tz_minute, 10); + } else { + tz_minute = 0; + } + tz_offset = (tz_hour * 60 + tz_minute) * 60000; + if ('-' === info.tz_sign) { + tz_offset *= -1; + } + } + date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)); + if (tz_offset) { + date.setTime(date.getTime() - tz_offset); + } + return date; + }; + + Utils.strRepeat = function (str, number) { + var i, res; + res = ''; + i = 0; + while (i < number) { + res += str; + i++; + } + return res; + }; + + Utils.getStringFromFile = function (path, callback) { + var data, fs, j, len1, name, ref, req, xhr; + if (callback == null) { + callback = null; + } + xhr = null; + if (typeof window !== "undefined" && window !== null) { + if (window.XMLHttpRequest) { + xhr = new XMLHttpRequest(); + } else if (window.ActiveXObject) { + ref = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP", "Microsoft.XMLHTTP"]; + for (j = 0, len1 = ref.length; j < len1; j++) { + name = ref[j]; + try { + xhr = new ActiveXObject(name); + } catch (undefined) { } + } + } + } + if (xhr != null) { + if (callback != null) { + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200 || xhr.status === 0) { + return callback(xhr.responseText); + } else { + return callback(null); + } + } + }; + xhr.open('GET', path, true); + return xhr.send(null); + } else { + xhr.open('GET', path, false); + xhr.send(null); + if (xhr.status === 200 || xhr.status === 0) { + return xhr.responseText; + } + return null; + } + } else { + req = require; + fs = req('fs'); + if (callback != null) { + return fs.readFile(path, function (err, data) { + if (err) { + return callback(null); + } else { + return callback(String(data)); + } + }); + } else { + data = fs.readFileSync(path); + if (data != null) { + return String(data); + } + return null; + } + } + }; + + return Utils; + + })(); + + module.exports = Utils; + + + }, { + "./Pattern": 8 + }], + 11: [function (require, module, exports) { + var Dumper, Parser, Utils, Yaml; + + Parser = require('./Parser'); + + Dumper = require('./Dumper'); + + Utils = require('./Utils'); + + Yaml = (function () { + function Yaml() { } + + Yaml.parse = function (input, exceptionOnInvalidType, objectDecoder) { + if (exceptionOnInvalidType == null) { + exceptionOnInvalidType = false; + } + if (objectDecoder == null) { + objectDecoder = null; + } + return new Parser().parse(input, exceptionOnInvalidType, objectDecoder); + }; + + Yaml.parseFile = function (path, callback, exceptionOnInvalidType, objectDecoder) { + var input; + if (callback == null) { + callback = null; + } + if (exceptionOnInvalidType == null) { + exceptionOnInvalidType = false; + } + if (objectDecoder == null) { + objectDecoder = null; + } + if (callback != null) { + return Utils.getStringFromFile(path, (function (_this) { + return function (input) { + var result; + result = null; + if (input != null) { + result = _this.parse(input, exceptionOnInvalidType, objectDecoder); + } + callback(result); + }; + })(this)); + } else { + input = Utils.getStringFromFile(path); + if (input != null) { + return this.parse(input, exceptionOnInvalidType, objectDecoder); + } + return null; + } + }; + + Yaml.dump = function (input, inline, indent, exceptionOnInvalidType, objectEncoder) { + var yaml; + if (inline == null) { + inline = 2; + } + if (indent == null) { + indent = 4; + } + if (exceptionOnInvalidType == null) { + exceptionOnInvalidType = false; + } + if (objectEncoder == null) { + objectEncoder = null; + } + yaml = new Dumper(); + yaml.indentation = indent; + return yaml.dump(input, inline, 0, exceptionOnInvalidType, objectEncoder); + }; + + Yaml.stringify = function (input, inline, indent, exceptionOnInvalidType, objectEncoder) { + return this.dump(input, inline, indent, exceptionOnInvalidType, objectEncoder); + }; + + Yaml.load = function (path, callback, exceptionOnInvalidType, objectDecoder) { + return this.parseFile(path, callback, exceptionOnInvalidType, objectDecoder); + }; + + return Yaml; + + })(); + + if (typeof window !== "undefined" && window !== null) { + window.YAML = Yaml; + } + + if (typeof window === "undefined" || window === null) { + this.YAML = Yaml; + } + + module.exports = Yaml; + + + }, { + "./Dumper": 1, + "./Parser": 7, + "./Utils": 10 + }] +}, {}, [11]); diff --git a/static/system/component/pear/module/fullscreen.js b/static/system/component/pear/module/fullscreen.js index a0f3b4d..ff8a192 100644 --- a/static/system/component/pear/module/fullscreen.js +++ b/static/system/component/pear/module/fullscreen.js @@ -1,35 +1,39 @@ -layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'menu', 'frame', 'theme', 'convert'], - function(exports) { - "use strict"; +layui.define(['jquery', 'element'], + function (exports) { + var $ = layui.jquery; var defer = $.Deferred(); - var fullScreen = new function() { + var fullScreen = new function () { + this.func = null; - this.onFullchange = function(func){ + + this.onFullchange = function (func) { this.func = func; - var evts = ['fullscreenchange','webkitfullscreenchange','mozfullscreenchange','MSFullscreenChange']; - for(var i=0;ia"); $("#" + this.option.elem).find(".layui-nav-itemed").removeClass("layui-nav-itemed"); @@ -238,13 +243,13 @@ layui.define(['table', 'jquery', 'element'], function (exports) { }, 400); var that = this; $("#" + this.option.elem) - .promise() - .done(function () { - isHoverMenu(true, config); - if (that.option.control) { - rationalizeHeaderControlWidth(that.option); - } - }) + .promise() + .done(function () { + isHoverMenu(true, config); + if (that.option.control) { + rationalizeHeaderControlWidth(that.option); + } + }) } } @@ -278,13 +283,12 @@ layui.define(['table', 'jquery', 'element'], function (exports) { } } element.init(); - downShow(option); option.done(); } function createMenu(option) { var menuHtml = '
              ' + '" class="layui-nav arrow pear-menu layui-nav-tree pear-nav-tree" ' + (option.accordion ? "lay-accordion" : "") + '>' $.each(option.data, function (i, item) { var content = '
            • '; if (i == option.defaultOpen) { @@ -304,7 +308,7 @@ layui.define(['table', 'jquery', 'element'], function (exports) { '" ' + target + '>' + item.title + ''; } else if (item.type == 1) { - content += '' + item.title + ''; @@ -374,7 +378,7 @@ layui.define(['table', 'jquery', 'element'], function (exports) { ''; } else if (note.type == 1) { // 创 建 菜 单 结 构 - content += '' + note.title + ''; @@ -433,7 +437,7 @@ layui.define(['table', 'jquery', 'element'], function (exports) { '">' + note.title + ''; } else if (note.type == 1) { // 创 建 菜 单 结 构 - content += '' + note.title + ''; } @@ -450,49 +454,6 @@ layui.define(['table', 'jquery', 'element'], function (exports) { return content; } - function downShow(option) { - $("body #" + option.elem).on("click", "a[menu-type='0']", function () { - if (!$("#" + option.elem).is(".pear-nav-mini")) { - var superEle = $(this).parent(); - var ele = $(this).next('.layui-nav-child'); - var heights = ele.children("dd").length * 48; - - if ($(this).parent().is(".layui-nav-itemed")) { - if (option.accordion) { - var currentDom = $(this).parent().siblings('.layui-nav-itemed').children('.layui-nav-child'); - currentDom.animate({ - height: '0px' - }, 240, function () { - currentDom.css({ - height: "auto", - }); - $(this).parent().removeClass("layui-nav-itemed"); - $(this).find('.layui-nav-itemed').removeClass("layui-nav-itemed"); - }); - } - ele.height(0); - ele.animate({ - height: heights + "px" - }, 240, function () { - ele.css({ - height: "auto" - }); - }); - } else { - $(this).parent().addClass("layui-nav-itemed"); - ele.animate({ - height: "0px" - }, 240, function () { - ele.css({ - height: "auto" - }); - $(this).parent().removeClass("layui-nav-itemed"); - }); - } - } - }) - } - /** 二 级 悬 浮 菜 单*/ function isHoverMenu(b, option) { if (b) { @@ -557,15 +518,16 @@ layui.define(['table', 'jquery', 'element'], function (exports) { $("#" + option.control + " .control").css({ "width": rationalizeWidth, "transition": "width .15s" }); } - function rationalizeHeaderControlWidthAuto(option){ + function rationalizeHeaderControlWidthAuto(option) { $(window).on('resize', function () { rationalizeHeaderControlWidth(option); }) - $(document).ready(function () { - rationalizeHeaderControlWidth(option); + setTimeout(() => { + rationalizeHeaderControlWidth(option); + }, 1000); }); } - exports(MOD_NAME, new pearMenu()); -}) + exports(MOD_NAME, new menu()); +}) \ No newline at end of file diff --git a/static/system/component/pear/module/menuSearch.js b/static/system/component/pear/module/menuSearch.js new file mode 100644 index 0000000..41775ba --- /dev/null +++ b/static/system/component/pear/module/menuSearch.js @@ -0,0 +1,233 @@ +layui.define(['jquery', 'tools'], function (exports) { + "use strict"; + + /** + * @since Pear Admin 4.0 + * + * Button component + * */ + var MOD_NAME = 'menuSearch', + tools = layui.tools, + $ = layui.jquery; + + var menuSearch = function (opt) { + this.option = opt; + }; + + /** + * @since Pear Admin 4.0 + * + * Button start loading + * */ + menuSearch.prototype.render = function (opt) { + + var options = { + select: opt.select, + elem: opt.elem, + dataProvider: opt.dataProvider, + } + + $('body').on("click", options.elem, function () { + + var _html = [ + `` + ].join(''); + + layer.open({ + type: 1, + offset: "10%", + area: ['600px'], + title: false, + closeBtn: 0, + shadeClose: true, + anim: 0, + move: false, + content: _html, + success: function (layero, layeridx) { + + var $layer = layero; + var $content = $(layero).children('.layui-layer-content'); + var $input = $(".menu-search-input-wrapper input"); + var $noData = $(".menu-search-no-data"); + var $list = $(".menu-search-list"); + var menuData = options.dataProvider(); + + $layer.css("border-radius", "6px"); + $input.off("focus").focus(); + + // 搜索输入事件 + $input.off("input").on("input", tools.debounce(function () { + var keywords = $input.val().trim(); + var filteredMenus = filterHandle(menuData, keywords); + + if (filteredMenus.length) { + var tiledMenus = tiledHandle(filteredMenus); + var listHtml = createList(tiledMenus); + $noData.css("display", "none"); + $list.html("").append(listHtml).children(":first").addClass("this") + } else { + $list.html(""); + $noData.css("display", "flex"); + } + var currentHeight = $(".menu-search-content").outerHeight() + $layer.css("height", currentHeight); + $content.css("height", currentHeight); + }, 500) + ) + + // 列表点击事件 + $list.off("click").on("click", "li", function () { + var id = $(this).attr("smenu-id"); + var title = $(this).attr("smenu-title"); + var url = $(this).attr("smenu-url"); + var type = $(this).attr("smenu-type"); + var openType = $(this).attr("smenu-open-type"); + + options.select({ id, title, url, type, openType }); + + layer.close(layeridx); + }) + + $list.off('mouseenter').on("mouseenter", "li", function () { + $(".menu-search-list li.this").removeClass("this"); + $(this).addClass("this"); + }).off("mouseleave").on("mouseleave", "li", function () { + $(this).removeClass("this"); + }) + + // 监听键盘事件 + $('.menu-search-content').off("keydown").keydown(function (e) { + if (e.keyCode === 13 || e.keyCode === 32) { + e.preventDefault(); + var that = $(".menu-search-list li.this"); + var id = that.attr("smenu-id"); + var title = that.attr("smenu-title"); + var url = that.attr("smenu-url"); + var type = that.attr("smenu-type"); + var openType = that.attr("smenu-open-type"); + + options.select({ id, title, url, type, openType }); + + layer.close(layeridx); + } else if (e.keyCode === 38) { + e.preventDefault(); + var prevEl = $(".menu-search-list li.this").prev(); + $(".menu-search-list li.this").removeClass("this"); + if (prevEl.length !== 0) { + prevEl.addClass("this"); + } else { + $list.children().last().addClass("this"); + } + } else if (e.keyCode === 40) { + e.preventDefault(); + var nextEl = $(".menu-search-list li.this").next(); + $(".menu-search-list li.this").removeClass("this"); + if (nextEl.length !== 0) { + nextEl.addClass("this"); + } else { + $list.children().first().addClass("this"); + } + } else if (e.keyCode === 27) { + e.preventDefault(); + layer.close(layeridx); + } + }) + } + }) + }); + + return new menuSearch(options); + } + + /** + * @since Pear Admin 4.0 + * + * 创建结果列表 + */ + var createList = function (data) { + var listHtml = ''; + $.each(data, function (index, item) { + listHtml += `
            • + ${item.path} + +
            • ` + }) + return listHtml; + } + + /** + * @since Pear Admin 4.0 + * + * Tree 转 path 列表 + */ + var tiledHandle = function (data) { + var tiledMenus = []; + var treeTiled = function (data, content) { + var path = ""; + var separator = " / "; + if (!content) content = ""; + $.each(data, function (index, item) { + if (item.children && item.children.length) { + path += content + item.title + separator; + var childPath = treeTiled(item.children, path); + path += childPath; + if (!childPath) path = ""; // 重置路径 + } else { + path += content + item.title + tiledMenus.push({ path: path, info: item }); + path = ""; //重置路径 + } + }) + return path; + }; + treeTiled(data); + + return tiledMenus; + } + + /** + * @since Pear Admin 4.0 + * + * 查询匹配算法 + */ + var filterHandle = function (filterData, val) { + if (!val) return []; + var filteredMenus = []; + filterData = $.extend(true, {}, filterData); + $.each(filterData, function (index, item) { + if (item.children && item.children.length) { + var children = filterHandle(item.children, val) + var obj = $.extend({}, item, { children: children }); + if (children && children.length) { + filteredMenus.push(obj); + } else if (item.title.indexOf(val) >= 0) { + item.children = []; // 父级匹配但子级不匹配,就去除子级 + filteredMenus.push($.extend({}, item)); + } + } else if (item.title.indexOf(val) >= 0) { + filteredMenus.push(item); + } + }) + return filteredMenus; + } + + exports(MOD_NAME, new menuSearch()); +}); diff --git a/static/system/component/pear/module/messageCenter.js b/static/system/component/pear/module/messageCenter.js new file mode 100644 index 0000000..c7535cb --- /dev/null +++ b/static/system/component/pear/module/messageCenter.js @@ -0,0 +1,85 @@ +layui.define(['table', 'jquery', 'element', 'dropdown'], function (exports) { + "use strict"; + + var MOD_NAME = 'messageCenter', + $ = layui.jquery, + dropdown = layui.dropdown; + + var message = function (opt) { + this.option = opt; + }; + + message.prototype.render = function (opt) { + var option = { + elem: opt.elem, + url: opt.url ? opt.url : false, + height: opt.height, + data: opt.data + } + if (option.url != false) { + $.get(option.url, function (result) { + const { code, success, data } = result; + $(`${opt.elem}`).append(`
            • + +
            • `); + if (code == 200 || success) { + option.data = data; + dropdown.render({ + elem: option.elem, + align: "center", + content: createHtml(option), + }) + } + }); + } + return new message(option); + } + + message.prototype.click = function (callback) { + $("*[notice-id]").click(function (event) { + event.preventDefault(); + var id = $(this).attr("notice-id"); + var title = $(this).attr("notice-title"); + var context = $(this).attr("notice-context"); + var form = $(this).attr("notice-form"); + callback(id, title, context, form); + }) + } + + function createHtml(option) { + + var count = 0; + var notice = '
              ' + var noticeTitle = '
                '; + var noticeContent = '
                '; + + $.each(option.data, function (i, item) { + + noticeTitle += `
              • ${item.title}
              • `; + noticeContent += '
                '; + + + $.each(item.children, function (i, note) { + count++; + noticeContent += '
                '; + + noticeContent += '
                ' + note.title + '
                ' + + '
                ' + note.time + '
                ' + + '
                '; + }) + + noticeContent += '
                '; + }) + + noticeTitle += '
              '; + noticeContent += '
              '; + notice += noticeTitle; + notice += noticeContent; + notice += "
            " + + return notice; + } + + exports(MOD_NAME, new message()); +}) \ No newline at end of file diff --git a/static/system/component/pear/module/page.js b/static/system/component/pear/module/page.js new file mode 100644 index 0000000..52ff2ef --- /dev/null +++ b/static/system/component/pear/module/page.js @@ -0,0 +1,119 @@ +layui.define(['jquery', 'element'], function (exports) { + "use strict"; + + var $ = layui.jquery; + var element = layui.element; + + var page = function (opt) { + this.option = opt; + }; + + /** + * @since Pear Admin 4.0 + * + * 创建 Page 页面 + */ + page.prototype.render = function (opt) { + var option = { + elem: opt.elem, + url: opt.url, + width: opt.width || "100%", + height: opt.height || "100%", + title: opt.title + } + renderContent(option); + return new page(option); + } + + /** + * @since Pear Admin 4.0 + * + * 切换 Page 页面 + */ + page.prototype.changePage = function (options) { + const $frame = $(`#${this.option.elem} .pear-page-content`); + if (options.type === "_iframe") { + $frame.html(``); + } else { + $.ajax({ + url: options.href, + type: 'get', + dataType: 'html', + success: function (data) { + $frame.html(data) + }, + error: function (xhr) { + return layer.msg('Status:' + xhr.status + ',' + xhr.statusText + ',请稍后再试!'); + } + }); + } + $frame.attr("type", options.type); + $frame.attr("href", options.href); + } + + page.prototype.refresh = function (loading) { + var $frameLoad = $(`#${this.option.elem} .pear-page-loading`); + var $frame = $(`#${this.option.elem} .pear-page-content`); + if (loading) { + $frameLoad.css({ + display: 'block' + }); + } + if ($frame.attr("type") === "_iframe") { + $frame.html(``); + const $contentFrame = $frame.find("iframe"); + $contentFrame.on("load", () => { + $frameLoad.fadeOut(1000); + }) + } else { + $.ajax({ + type: 'get', + url: $frame.attr("href"), + dataType: 'html', + success: function (data) { + $frame.html(data) + $frameLoad.fadeOut(1000); + element.init(); + }, + error: function (xhr) { + return layer.msg('Status:' + xhr.status + ',' + xhr.statusText + ',请稍后再试!'); + } + }); + } + } + + function renderContent(option) { + $("#" + option.elem).html(` +
            +
            +
            +
            + + + + +
            +
            +
            `); + + var $frame = $("#" + option.elem).find(".pear-page-content"); + + if (option.type === "_iframe") { + $frame.html(``); + } else { + $.ajax({ + url: option.url, + type: 'get', + dataType: 'html', + success: function (data) { + $frame.html(data); + }, + error: function (xhr) { + return layer.msg('Status:' + xhr.status + ',' + xhr.statusText + ',请稍后再试!'); + } + }); + } + } + + exports('page', new page()); +}); \ No newline at end of file diff --git a/static/system/component/pear/module/tabPage.js b/static/system/component/pear/module/tabPage.js new file mode 100644 index 0000000..91c2bc1 --- /dev/null +++ b/static/system/component/pear/module/tabPage.js @@ -0,0 +1,656 @@ +layui.define(['jquery', 'element', 'dropdown'], function (exports) { + "use strict"; + + var MOD_NAME = 'tabPage', + $ = layui.jquery, + dropdown = layui.dropdown, + element = layui.element; + + var tabPage = function (opt) { + this.option = opt; + }; + + var tabData = new Array(); + var tabDataCurrent = 0; + var contextTabDOM; + + tabPage.prototype.render = function (opt) { + + var option = { + elem: opt.elem, + data: opt.data, + index: opt.index, + tool: opt.tool || true, + roll: opt.roll || true, + success: opt.success ? opt.success : function (id) { }, + session: opt.session ? opt.session : false, + preload: opt.preload ? opt.preload : false, + height: opt.height || "100%", + width: opt.width || "100%", + closeEvent: opt.closeEvent, + tabMax: opt.tabMax, + } + + if (option.session) { + if (sessionStorage.getItem(option.elem + "-pear-tab-page-data") != null) { + tabData = JSON.parse(sessionStorage.getItem(option.elem + "-pear-tab-page-data")); + option.data = JSON.parse(sessionStorage.getItem(option.elem + "-pear-tab-page-data")); + tabDataCurrent = sessionStorage.getItem(option.elem + "-pear-tab-page-data-current"); + tabData.forEach(function (item, index) { + if (item.id == tabDataCurrent) { + option.index = index; + } + }) + } else { + tabData = opt.data; + } + } + + var lastIndex; + var tab = createTab(option); + $("#" + option.elem).html(tab); + $(".layui-tab[lay-filter='" + option.elem + "'] .layui-tab-prev").click(function () { + rollPage("left", option); + }) + $(".layui-tab[lay-filter='" + option.elem + "'] .layui-tab-next").click(function () { + rollPage("right", option); + }) + element.init(); + + $("#" + option.elem).width(opt.width); + $("#" + option.elem).height(opt.height); + $("#" + option.elem).css({ + position: "relative" + }); + + closeEvent(option); + + option.success(sessionStorage.getItem(option.elem + "-pear-tab-page-data-current")); + + dropdown.render({ + elem: `#${option.elem} .layui-tab-control > .layui-icon-down`, + trigger: 'hover', + data: [{ + title: '关 闭 当 前', + id: 1 + }, { + title: '关 闭 其 他', + id: 2 + }, { + title: '关 闭 全 部', + id: 3 + }], + click: function (obj) { + + const id = obj.id; + + if (id === 1) { + var currentTab = $(".layui-tab[lay-filter='" + option.elem + + "'] .layui-tab-title .layui-this"); + if (currentTab.find("span").is(".able-close")) { + var currentId = currentTab.attr("lay-id"); + tabDelete(option.elem, currentId, option.closeEvent, option); + } else { + layer.msg("当前页面不允许关闭", { + icon: 3, + time: 1000 + }) + } + } else if (id === 2) { + var currentId = $(".layui-tab[lay-filter='" + option.elem + + "'] .layui-tab-title .layui-this").attr("lay-id"); + var tabtitle = $(".layui-tab[lay-filter='" + option.elem + "'] .layui-tab-title li"); + $.each(tabtitle, function (i) { + if ($(this).attr("lay-id") != currentId) { + if ($(this).find("span").is(".able-close")) { + tabDelete(option.elem, $(this).attr("lay-id"), option.closeEvent, + option); + } + } + }) + } else { + var currentId = $(".layui-tab[lay-filter='" + option.elem + + "'] .layui-tab-title .layui-this").attr("lay-id"); + var tabtitle = $(".layui-tab[lay-filter='" + option.elem + "'] .layui-tab-title li"); + $.each(tabtitle, function (i) { + if ($(this).find("span").is(".able-close")) { + tabDelete(option.elem, $(this).attr("lay-id"), option.closeEvent, option); + } + }) + } + + } + }) + + $("body .layui-tab[lay-filter='" + option.elem + "'] .layui-tab-title").on("contextmenu", "li", + function (e) { + var top = e.clientY; + var left = e.clientX; + var menuWidth = 100; + var menu = `
              +
            • 关闭当前
            • +
            • 关闭其他
            • +
            • 关闭所有
            • +
            `; + + contextTabDOM = $(this); + var isOutsideBounds = (left + menuWidth) > $(window).width(); + if (isOutsideBounds) { + left = $(window).width() - menuWidth; + } + + layer.open({ + type: 1, + title: false, + shade: false, + skin: 'pear-tab-page-menu', + closeBtn: false, + area: [menuWidth + 'px', '108px'], + fixed: true, + anim: false, + isOutAnim: false, + offset: [top, left], + content: menu, + success: function (layero, index) { + layer.close(lastIndex); + lastIndex = index; + menuEvent(option, index); + var timer; + $(layero).on('mouseout', function () { + timer = setTimeout(function () { + layer.close(index); + }, 30) + }); + + $(layero).on('mouseover', function () { + clearTimeout(timer); + }); + + $(layero).on('contextmenu', function () { + return false; + }) + } + }); + return false; + }) + + mousewheelAndTouchmoveHandler(option) + return new tabPage(option); + } + + tabPage.prototype.click = function (callback) { + var option = this.option; + var elem = this.option.elem; + element.on('tab(' + this.option.elem + ')', function (data) { + var id = $("#" + elem + " .layui-tab-title .layui-this").attr("lay-id"); + sessionStorage.setItem(option.elem + "-pear-tab-page-data-current", id); + callback(id); + }); + } + + tabPage.prototype.positionTab = function () { + var $tabTitle = $('.layui-tab[lay-filter=' + this.option.elem + '] .layui-tab-title'); + var autoLeft = 0; + $tabTitle.children("li").each(function () { + if ($(this).hasClass('layui-this')) { + return false; + } else { + autoLeft += $(this).outerWidth(); + } + }); + $tabTitle.animate({ + scrollLeft: autoLeft - $tabTitle.width() / 3 + }, 200); + } + + tabPage.prototype.clear = function () { + sessionStorage.removeItem(this.option.elem + "-pear-tab-page-data"); + sessionStorage.removeItem(this.option.elem + "-pear-tab-page-data-current"); + } + + tabPage.prototype.changeTabTitleById = function (id, title) { + var currentTab = $(".layui-tab[lay-filter='" + this.option.elem + "'] .layui-tab-title [lay-id='" + id + "'] .title"); + currentTab.html(title); + } + + /** + * @since Pear Admin 4.0 + * + * 删除指定选项卡 + * + * @param id 编号 + */ + tabPage.prototype.removeTab = function (id) { + var elem = this.option.elem; + if (id != undefined) { + var currentTab = $(".layui-tab[lay-filter='" + elem + "'] .layui-tab-title [lay-id='" + id + "']"); + if (currentTab.find("span").is(".able-close")) { + tabDelete(elem, id, () => { }); + } + } else { + var tabtitle = $(".layui-tab[lay-filter='" + elem + "'] .layui-tab-title li"); + $.each(tabtitle, function () { + if ($(this).find("span").is(".able-close")) { + tabDelete(elem, $(this).attr("lay-id"), () => { }); + } + }) + } + } + + /** + * @since Pear Admin 4.0 + * + * 删除其他选项卡 + */ + tabPage.prototype.removeOtherTab = function () { + var elem = this.option.elem; + var currentId = $(".layui-tab[lay-filter='" + elem + "'] .layui-tab-title .layui-this").attr("lay-id"); + var tabtitle = $(".layui-tab[lay-filter='" + elem + "'] .layui-tab-title li"); + $.each(tabtitle, function () { + if ($(this).attr("lay-id") != currentId) { + if ($(this).find("span").is(".able-close")) { + tabDelete(elem, $(this).attr("lay-id"), () => { }); + } + } + }) + } + + /** + * @since Pear Admin 4.0 + * + * 删除选中选项卡 + */ + tabPage.prototype.removeCurrentTab = function () { + var currentTab = $(".layui-tab[lay-filter='" + this.option.elem + "'] .layui-tab-title .layui-this"); + if (currentTab.find("span").is(".able-close")) { + var currentId = currentTab.attr("lay-id"); + tabDelete(this.option.elem, currentId, () => { }); + } + } + + /** + * @since Pear Admin 4.0 + * + * 切换选项卡 + * + * @param opt 内容 + */ + tabPage.prototype.changePage = function (opt) { + + var title = ` + ${opt.title} + `; + + if ($(".layui-tab[lay-filter='" + this.option.elem + "'] .layui-tab-title li[lay-id]").length <= + 0) { + + var that = this; + + if (opt.type === "_iframe") { + + element.tabAdd(this.option.elem, { + id: opt.id, + title: title, + content: `` + }); + + } else { + + $.ajax({ + url: opt.url, + type: 'get', + dataType: 'html', + async: false, + success: function (data) { + element.tabAdd(that.option.elem, { + id: opt.id, + title: title, + content: `
            ${data}
            `, + }); + }, + error: function (xhr, textstatus, thrown) { + return layer.msg('Status:' + xhr.status + ',' + xhr.statusText + ',请稍后再试!'); + } + }); + } + + tabData.push(opt); + sessionStorage.setItem(that.option.elem + "-pear-tab-page-data", JSON.stringify(tabData)); + sessionStorage.setItem(that.option.elem + "-pear-tab-page-data-current", opt.id); + + } else { + + var isData = false; + $.each($(".layui-tab[lay-filter='" + this.option.elem + "'] .layui-tab-title li[lay-id]"), + function () { + if ($(this).attr("lay-id") == opt.id) { + isData = true; + } + }) + + if (isData == false) { + + if (this.option.tabMax != false) { + if ($(".layui-tab[lay-filter='" + this.option.elem + "'] .layui-tab-title li[lay-id]") + .length >= this.option.tabMax) { + layer.msg("最多打开" + this.option.tabMax + "个标签页", { + icon: 2, + time: 1000, + shift: 6 + }); + return false; + } + } + + var that = this; + if (opt.type === "_iframe") { + element.tabAdd(this.option.elem, { + id: opt.id, + title: title, + content: `` + }); + } else { + $.ajax({ + url: opt.url, + type: 'get', + dataType: 'html', + async: false, + success: function (data) { + element.tabAdd(that.option.elem, { + id: opt.id, + title: title, + content: `
            ${data}
            `, + }); + }, + error: function (xhr, textstatus, thrown) { + return layer.msg('Status:' + xhr.status + ',' + xhr.statusText + ',请稍后再试!'); + } + }); + } + tabData.push(opt); + sessionStorage.setItem(that.option.elem + "-pear-tab-page-data", JSON.stringify(tabData)); + sessionStorage.setItem(that.option.elem + "-pear-tab-page-data-current", opt.id); + } + } + element.tabChange(this.option.elem, opt.id); + sessionStorage.setItem(this.option.elem + "-pear-tab-page-data-current", opt.id); + } + + /** + * 刷新当前选型卡 + * + * @param time 动画时长 + */ + tabPage.prototype.refresh = function (time) { + + var $iframe = $(".layui-tab[lay-filter='" + this.option.elem + "'] .layui-tab-content .layui-show > div[data-frameid]"); + var $iframeLoad; + + if (time != false && time != 0) { + $iframeLoad = $("#" + this.option.elem).find(".pear-tab-page-loading"); + $iframeLoad.css({ + display: "block" + }); + } + + if ($iframe.attr("type") === "_iframe") { + $iframe.attr("src", $iframe.attr("src")); + $iframe.on("load", function () { + $iframeLoad.fadeOut(1000, function () { + $iframeLoad.css({ + display: "none" + }); + }); + }) + } else { + $.ajax({ + url: $iframe.attr("src"), + type: 'get', + dataType: 'html', + success: function (data) { + $iframe.html(data); + if ($iframeLoad != undefined) { + $iframeLoad.fadeOut(1000, function () { + $iframeLoad.css({ + display: "none" + }); + }); + } + }, + error: function (xhr) { + return layer.msg('Status:' + xhr.status + ',' + xhr.statusText + ',请稍后再试!'); + } + }); + } + } + + function tabDelete(elem, id, callback) { + var tabTitle = $(".layui-tab[lay-filter='" + elem + "']").find(".layui-tab-title"); + var removeTab = tabTitle.find("li[lay-id='" + id + "']"); + var nextNode = removeTab.next("li"); + if (!removeTab.hasClass("layui-this")) { + removeTab.remove(); + var tabContent = $(".layui-tab[lay-filter='" + elem + "']").find("*[id='" + id + "']") + .parent(); + tabContent.remove(); + + tabData = JSON.parse(sessionStorage.getItem(elem + "-pear-tab-page-data")); + tabDataCurrent = sessionStorage.getItem(elem + "-pear-tab-page-data-current"); + tabData = tabData.filter(function (item) { + return item.id != id; + }) + sessionStorage.setItem(elem + "-pear-tab-page-data", JSON.stringify(tabData)); + return false; + } + + var currId; + if (nextNode.length) { + nextNode.addClass("layui-this"); + currId = nextNode.attr("lay-id"); + $("#" + elem + " [id='" + currId + "']").parent().addClass("layui-show"); + } else { + var prevNode = removeTab.prev("li"); + prevNode.addClass("layui-this"); + currId = prevNode.attr("lay-id"); + $("#" + elem + " [id='" + currId + "']").parent().addClass("layui-show"); + } + callback(currId); + tabData = JSON.parse(sessionStorage.getItem(elem + "-pear-tab-page-data")); + tabDataCurrent = sessionStorage.getItem(elem + "-pear-tab-page-data-current"); + tabData = tabData.filter(function (item) { + return item.id != id; + }) + sessionStorage.setItem(elem + "-pear-tab-page-data", JSON.stringify(tabData)); + sessionStorage.setItem(elem + "-pear-tab-page-data-current", currId); + removeTab.remove(); + var tabContent = $(".layui-tab[lay-filter='" + elem + "']").find("*[id='" + id + "']").parent(); + tabContent.remove(); + } + + /** + * @since Pear Admin 4.0 + */ + function createTab(option) { + + var type = ""; + if (option.roll == true) { + type = "layui-tab-roll"; + } + if (option.tool != false) { + type = "layui-tab-tool"; + } + if (option.roll == true && option.tool != false) { + type = "layui-tab-rollTool"; + } + var tab = '
            '; + + var headers = '
              '; + var content = '
              '; + var loading = '
              ' + var control = `
              +
            • +
            • +
            • +
              `; + + // 处 理 选 项 卡 头 部 + var index = 0; + + $.each(option.data, function (i, item) { + + var titleItem = `
            • + + + ${item.title} + +
            • + `; + + headers += titleItem; + + if (item.type === "_iframe") { + + content += `
              ` + + } else { + + $.ajax({ + url: item.url, + type: 'get', + dataType: 'html', + async: false, + success: function (data) { + content += `
              ${data}
              `; + }, + error: function (xhr) { + return layer.msg('Status:' + xhr.status + ',' + xhr.statusText + ',请稍后再试!'); + } + }); + } + + index++; + }); + + headers += '
            '; + content += '
            '; + + tab += headers; + tab += control; + tab += content; + tab += loading; + tab += ''; + tab += '' + return tab; + } + + function rollPage(d, option) { + var $tabTitle = $('#' + option.elem + ' .layui-tab-title'); + var left = $tabTitle.scrollLeft(); + if ('left' === d) { + $tabTitle.animate({ + scrollLeft: left - 450 + }, 200); + } else { + $tabTitle.animate({ + scrollLeft: left + 450 + }, 200); + } + } + + function closeEvent(option) { + $(".layui-tab[lay-filter='" + option.elem + "']") + .on("click", ".layui-tab-close", function () { + var layid = $(this).parent().attr("lay-id"); + tabDelete(option.elem, layid, option.closeEvent, option); + }) + .on("mousedown", ".layui-tab-title li", function (e) { + if (e.buttons === 4 && $(this).find("span").is(".able-close")) { + tabDelete(option.elem, $(this).attr("lay-id"), option.closeEvent, option); + } + }); + } + + function menuEvent(option, index) { + + $("#" + option.elem + "closeThis").click(function () { + var currentTab = contextTabDOM; + + if (currentTab.find("span").is(".able-close")) { + var currentId = currentTab.attr("lay-id"); + tabDelete(option.elem, currentId, option.closeEvent, option); + } else { + layer.msg("当前页面不允许关闭", { + icon: 3, + time: 800 + }) + } + layer.close(index); + }) + + $("#" + option.elem + "closeOther").click(function () { + var currentId = contextTabDOM.attr("lay-id"); + var tabtitle = $(".layui-tab[lay-filter='" + option.elem + "'] .layui-tab-title li"); + $.each(tabtitle, function (i) { + if ($(this).attr("lay-id") != currentId) { + if ($(this).find("span").is(".able-close")) { + tabDelete(option.elem, $(this).attr("lay-id"), option.closeEvent, + option); + } + } + }) + layer.close(index); + }) + + $("#" + option.elem + "closeAll").click(function () { + var tabtitle = $(".layui-tab[lay-filter='" + option.elem + "'] .layui-tab-title li"); + $.each(tabtitle, function (i) { + if ($(this).find("span").is(".able-close")) { + tabDelete(option.elem, $(this).attr("lay-id"), option.closeEvent, option); + } + }) + layer.close(index); + }) + } + + function mousewheelAndTouchmoveHandler(option) { + var $bodyTab = $("body .layui-tab[lay-filter='" + option.elem + "'] .layui-tab-title") + var $tabTitle = $('#' + option.elem + ' .layui-tab-title'); + var mouseScrollStep = 100 + // 鼠标滚轮 + $bodyTab.on("mousewheel DOMMouseScroll", function (e) { + e.originalEvent.preventDefault() + var delta = (e.originalEvent.wheelDelta && (e.originalEvent.wheelDelta > 0 ? "top" : + "down")) || // chrome & ie + (e.originalEvent.detail && (e.originalEvent.detail > 0 ? "down" : "top")); // firefox + var scrollLeft = $tabTitle.scrollLeft(); + + if (delta === "top") { + scrollLeft -= mouseScrollStep + } else if (delta === "down") { + scrollLeft += mouseScrollStep + } + $tabTitle.scrollLeft(scrollLeft) + }); + + // 触摸移动 + var touchX = 0; + $bodyTab.on("touchstart", function (e) { + var touch = e.originalEvent.targetTouches[0]; + touchX = touch.pageX + }) + + $bodyTab.on("touchmove", function (e) { + var event = e.originalEvent; + if (event.targetTouches.length > 1) return; + event.preventDefault(); + var touch = event.targetTouches[0]; + var distanceX = touchX - touch.pageX + var scrollLeft = $tabTitle.scrollLeft(); + touchX = touch.pageX + $tabTitle.scrollLeft(scrollLeft += distanceX) + }); + } + + exports(MOD_NAME, new tabPage()); +}) diff --git a/static/system/component/pear/module/tools.js b/static/system/component/pear/module/tools.js new file mode 100644 index 0000000..373ac01 --- /dev/null +++ b/static/system/component/pear/module/tools.js @@ -0,0 +1,40 @@ +layui.define(['jquery', 'element'], + function (exports) { + + var $ = layui.jquery; + var tools = new function () { + + /** + * @since 防抖算法 + * + * @param fn 要执行的方法 + * @param time 防抖时间参数 + */ + this.debounce = function (fn, time) { + var timer = null + return function () { + var arguments = arguments[0] + if (timer) { + clearTimeout(timer) + } + timer = setTimeout(function () { + fn(arguments) + }, time) + } + } + + // image 转 base64 + this.imageToBase64 = function (img) { + var canvas = document.createElement("canvas"); + canvas.width = img.width; + canvas.height = img.height; + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0, img.width, img.height); + var ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase(); + var dataURL = canvas.toDataURL("image/" + ext); + return dataURL; + } + }; + + exports('tools', tools); + }) diff --git a/static/system/component/pear/pear.js b/static/system/component/pear/pear.js index 236631c..8e42332 100644 --- a/static/system/component/pear/pear.js +++ b/static/system/component/pear/pear.js @@ -7,45 +7,23 @@ window.rootPath = (function (src) { layui.config({ base: rootPath + "module/", - version: "3.40.0" + version: "4.0.3" }).extend({ - admin: "admin", // 框架布局组件 - common: "common", // 公共方法封装 - menu: "menu", // 数据菜单组件 - frame: "frame", // 内容页面组件 - tab: "tab", // 多选项卡组件 - echarts: "echarts", // 数据图表组件 - echartsTheme: "echartsTheme",// 数据图表主题 - encrypt: "encrypt", // 数据加密组件 - select: "select", // 下拉多选组件 - drawer: "drawer", // 抽屉弹层组件 - notice: "notice", // 消息提示组件 - step:"step", // 分布表单组件 - tag:"tag", // 多标签页组件 - popup:"popup", // 弹层封装 - treetable:"treetable", // 树状表格 - dtree:"dtree", // 树结构 - tinymce:"tinymce/tinymce", // 编辑器 - area:"area", // 省市级联 - count:"count", // 数字滚动 - topBar: "topBar", // 置顶组件 - button: "button", // 加载按钮 - design: "design", // 表单设计 - card: "card", // 数据卡片组件 - loading: "loading", // 加载组件 - cropper:"cropper", // 裁剪组件 - convert:"convert", // 数据转换 - yaml:"yaml", // yaml 解析组件 - context: "context", // 上下文组件 - http: "http", // 网络请求组件 - theme: "theme", // 主题转换 - message: "message", // 通知组件 - toast: "toast", // 消息通知 - iconPicker: "iconPicker", // 图标选择 - nprogress: "nprogress", // 进度过渡 - watermark:"watermark/watermark", //水印组件 - fullscreen:"fullscreen", //全屏组件 - popover:"popover/popover" //汽泡组件 -}).use(['layer', 'theme'], function () { - layui.theme.changeTheme(window, false); -}); \ No newline at end of file + admin: "admin", + page: "page", + tabPage: "tabPage", + menu: "menu", + fullscreen: "fullscreen", + messageCenter: "messageCenter", + menuSearch: "menuSearch", + button: "button", + tools: "tools", + popup: "extends/popup", + count: "extends/count", + toast: "extends/toast", + nprogress: "extends/nprogress", + echarts: "extends/echarts", + echartsTheme: "extends/echartsTheme", + yaml: "extends/yaml", + dtree: "dtree" +}).use([], function () { }); \ No newline at end of file diff --git a/templates/system/analysis/main.html b/templates/system/analysis/main.html new file mode 100644 index 0000000..05bb688 --- /dev/null +++ b/templates/system/analysis/main.html @@ -0,0 +1,394 @@ + + + + + + 分析页 + + + + + + + +
            +
            +
            +
            +
            今日访问
            +
            +
            +
            + 0 +
            +
            + + + + + + + +
            +
            +
            +
            +
            +
            +
            +
            提交次数
            +
            +
            +
            + 0 +
            +
            + + + + + + + +
            +
            +
            +
            +
            +
            +
            +
            下载数量
            +
            +
            +
            + 0 +
            +
            + + + + + + + +
            +
            +
            +
            +
            +
            +
            +
            流量统计
            +
            +
            +
            + 0 +
            +
            + + + + + + +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            + +
            +
            最初,Layui 在爱与期许中孵化。
            +
            +
            +
            + +
            +
            最初,Layui 在爱与期许中孵化。
            +
            +
            +
            + +
            +
            最初,Layui 在爱与期许中孵化。
            +
            +
            +
            + +
            +
            最初,Layui 在爱与期许中孵化。
            +
            +
            +
            + +
            +
            最初,Layui 在爱与期许中孵化。
            +
            +
            +
            + +
            +
            最初,Layui 在爱与期许中孵化。
            +
            +
            +
            + +
            +
            最初,Layui 在爱与期许中孵化。
            +
            +
            +
            +
            + +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +

            就眠儀式 在 讨论区 回答了 夏娜 提出得问题 +

            + 昨天 +
            +
            +
            +
            +
            +

            就眠儀式 在 讨论区 回答了 夏娜 提出得问题 +

            + 昨天 +
            +
            +
            +
            +
            +

            就眠儀式 在 讨论区 回答了 夏娜 提出得问题 +

            + 昨天 +
            +
            +
            +
            +
            +

            就眠儀式 在 讨论区 回答了 夏娜 提出得问题 +

            + 昨天 +
            +
            +
            +
            +
            +

            就眠儀式 在 讨论区 回答了 夏娜 提出得问题 +

            + 昨天 +
            +
            +
            +
            +
            + +
            +
            +
            +
            +
            + +
            +
            Hello Word
            +
            +
            +
            +
            + 寄语 +
            +
            + 原想将澎湃的爱平平稳稳放置你手心,奈何我徒有一股蛮劲,只顾向你跑去,一个不稳跌的满身脏兮兮。试图爬起的我, + 心想你会不会笑我 " 献爱献的这样笨拙, 怎么不知避开爱里的埋伏 " +
            +
            +
            +
            +
            + + + + \ No newline at end of file diff --git a/templates/system/common/footer.html b/templates/system/common/footer.html index 2d2d7c7..5547b5c 100644 --- a/templates/system/common/footer.html +++ b/templates/system/common/footer.html @@ -1,2 +1,9 @@ + + - \ No newline at end of file + + diff --git a/templates/system/common/header.html b/templates/system/common/header.html index 7782dc7..7e08b6a 100644 --- a/templates/system/common/header.html +++ b/templates/system/common/header.html @@ -2,4 +2,12 @@ - \ No newline at end of file + + + + + diff --git a/templates/system/console/console.html b/templates/system/console/console.html deleted file mode 100644 index 26e758b..0000000 --- a/templates/system/console/console.html +++ /dev/null @@ -1,413 +0,0 @@ - - - - 首页 - {% include 'system/common/header.html' %} - - - - - - -
            -
            -
            -
            -
            今日访问
            -
            -
            -
            - 0 -
            -
            - - - - - - - - - - -
            -
            -
            -
            -
            -
            -
            -
            提交次数
            -
            -
            -
            - 0 -
            -
            - - - - - - - - - - - - - -
            -
            -
            -
            -
            -
            -
            -
            下载数量
            -
            -
            -
            - 0 -
            -
            - - - - - - - - - - -
            -
            -
            -
            -
            -
            -
            -
            流量统计
            -
            -
            -
            - 0 -
            -
            - - - - - - - - - - - -
            -
            -
            -
            -
            -
            -
            -
            -
            -
            -
            -
            -
            -
            -
            -
            -
            动态
            -
            -
            -
            -
            -
            -

            七彩枫叶 在 Pear - Admin 专区 回答问题

            - 几秒前 -
            -
            -
            -
            -
            -

            简 在 Pear - Admin 专区 进行了 提问 -

            - 2天前 -
            -
            -
            -
            -
            -

            恒宇少年 将 Pear - Admin 更新至 2.3.0 版本

            - 7天前 -
            -
            -
            -
            -
            -

            如花 在 Pear - Admin 社区 发布了 建议

            - 7天前 -
            -
            -
            -
            -
            -

            就眠仪式 在 Pear - Admin 社区 发布了 建议

            - 8天前 -
            -
            -
            -
            -
            -

            贤心 在 Pear - Admin 专区 进行了 提问 -

            - 8天前 -
            -
            -
            -
            -
            -
            -
            -
            -
            最近更新
            -
            -
              -
            • 优化代码格式2020-06-04 11:28
            • -
            • 新增消息组件2020-06-01 04:23
            • -
            • 移动端兼容2020-05-22 21:38
            • -
            • 系统布局优化2020-05-15 14:26
            • -
            • 兼容多系统菜单模式2020-05-13 16:32
            • -
            • 兼容多标签页切换2019-12-9 14:58
            • -
            • 扩展下拉组件2019-12-7 9:06
            • -
            • 扩展卡片样式2019-12-1 10:26
            • -
            -
            -
            -
            -
            - 链接 -
            -
            - 官 网 -
            - 下 载 -
            - 后 端 -
            -
            -
            -
            -
            - -{% include 'system/common/footer.html' %} - - - \ No newline at end of file diff --git a/templates/system/index.html b/templates/system/index.html index c5baabd..2e2ecb7 100644 --- a/templates/system/index.html +++ b/templates/system/index.html @@ -1,10 +1,12 @@ - {% include 'system/common/header.html' %} - Pear Admin Flask - - + Pear Admin 4.0 + + {% include 'system/common/header.html' %} + + + @@ -29,9 +31,8 @@
            • -
            • -
            • +
            • @@ -56,7 +57,7 @@
              -
              +
              @@ -65,20 +66,11 @@
              - +
              -
              +
              @@ -88,22 +80,23 @@
              - {% include 'system/common/footer.html' %} + + + \ No newline at end of file diff --git a/templates/system/login.html b/templates/system/login.html index 63ffa51..e69de29 100644 --- a/templates/system/login.html +++ b/templates/system/login.html @@ -1,106 +0,0 @@ - - - - 登录 - {% include 'system/common/header.html' %} - - - -
              -
              - -
              Pear Admin
              -
              - 明 湖 区 最 具 影 响 力 的 设 计 规 范 之 一 -
              -
              -
              - -
              -
              - -
              -
              - - -
              -
              - -
              -
              - -
              -
              -{% include 'system/common/footer.html' %} - - - - \ No newline at end of file diff --git a/templates/system/login_rename.html b/templates/system/login_rename.html new file mode 100644 index 0000000..71397fb --- /dev/null +++ b/templates/system/login_rename.html @@ -0,0 +1,106 @@ + + + + 登录 + {% include 'system/common/header.html' %} + + + +
              +
              + +
              Pear Admin
              +
              + 明 湖 区 最 具 影 响 力 的 设 计 规 范 之 一 +
              +
              +
              + +
              +
              + +
              +
              + + +
              +
              + +
              +
              + +
              +
              +{% include 'system/common/footer.html' %} + + + + \ No newline at end of file diff --git a/templates/system/user/add.html b/templates/system/user/add.html index bb90b22..c86cce9 100644 --- a/templates/system/user/add.html +++ b/templates/system/user/add.html @@ -12,25 +12,32 @@
              -
              -
              -
              +
              + +
              +
                +
                +
                +
                @@ -48,11 +55,11 @@
                - - @@ -61,9 +68,22 @@ {% include 'system/common/footer.html' %} - + \ No newline at end of file diff --git a/templates/system/user/center.html b/templates/system/user/center.html index 8d12efe..5ecd94a 100644 --- a/templates/system/user/center.html +++ b/templates/system/user/center.html @@ -2,7 +2,6 @@ 个人中心 - {% include 'system/common/header.html' %} + + \ No newline at end of file diff --git a/templates/system/index.html b/templates/system/index.html index d606f22..f5db1cc 100644 --- a/templates/system/index.html +++ b/templates/system/index.html @@ -1,138 +1,161 @@ - - Pear Admin 4.0 - - {% include 'system/common/header.html' %} - - - - - - - -
                - -
                - - - -
                  -
                • -
                • -
                - -
                - - -
                - -
                - - - -
                -
                -
                -
                - -
                - -
                -
                - - - -
                - -
                - -
                -
                -
                - -
                - -
                - - - - - + + + - + }) + return true + } + } + }) + }) + }) + + \ No newline at end of file -- Gitee From fa7e62b12b4b4ad049aa35e34984c6835acf65f5 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Tue, 21 Jan 2025 12:07:37 +0800 Subject: [PATCH 09/36] =?UTF-8?q?Update:=20=EF=BC=88=E6=AD=A5=E9=AA=A4?= =?UTF-8?q?=E5=A4=87=E4=BB=BD=EF=BC=89=E9=83=A8=E9=97=A8=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/view/system/dept.py | 49 ++++++++---- applications/view/system/power.py | 1 + templates/system/dept/main.html | 122 ++++++++++++++++++++++++------ templates/system/power/main.html | 3 +- 4 files changed, 135 insertions(+), 40 deletions(-) diff --git a/applications/view/system/dept.py b/applications/view/system/dept.py index 13082e1..eaf3108 100644 --- a/applications/view/system/dept.py +++ b/applications/view/system/dept.py @@ -11,8 +11,6 @@ from applications.schemas import DeptSchema bp = Blueprint('dept', __name__, url_prefix='/dept') -# Todo: 部门管理后端 - @bp.get('/') @authorize("system:dept:main", log=True) def main(): @@ -79,7 +77,7 @@ def save(): ) r = db.session.add(dept) db.session.commit() - return success_api(msg="成功") + return success_api(msg="添加部门成功") @bp.get('/edit') @@ -100,7 +98,7 @@ def enable(): d = Dept.query.filter_by(id=id).update({"status": enable}) if d: db.session.commit() - return success_api(msg="启用成功") + return success_api(msg="启用部门成功") return fail_api(msg="出错啦") return fail_api(msg="数据错误") @@ -115,7 +113,7 @@ def dis_enable(): d = Dept.query.filter_by(id=id).update({"status": enable}) if d: db.session.commit() - return success_api(msg="禁用成功") + return success_api(msg="禁用部门成功") return fail_api(msg="出错啦") return fail_api(msg="数据错误") @@ -137,20 +135,45 @@ def update(): } d = Dept.query.filter_by(id=id).update(data) if not d: - return fail_api(msg="更新失败") + return fail_api(msg="更新部门失败") db.session.commit() - return success_api(msg="更新成功") + return success_api(msg="更新部门成功") @bp.delete('/remove/') @authorize("system:dept:remove", log=True) def remove(_id): d = Dept.query.filter_by(id=_id).delete() + if not d: - return fail_api(msg="删除失败") - res = User.query.filter_by(dept_id=_id).update({"dept_id": None}) + return fail_api(msg="删除部门失败") + + User.query.filter_by(dept_id=_id).update({"dept_id": None}) + db.session.commit() + + return success_api(msg="删除部门成功") + +# 批量删除 +@bp.delete('/batchRemove') +@authorize("system:dept:remove", log=True) +def batch_remove(): + ids = request.form.getlist('ids[]') + + if not ids: + return fail_api(msg="未提供删除 ID") + + for id in ids: + + if not id.isdigit(): + db.session.rollback() + return fail_api(msg="参数提供错误") + + d = Dept.query.filter_by(id=id).delete() + + if not d: + return fail_api(msg="删除部门失败") + + User.query.filter_by(dept_id=id).update({"dept_id": None}) + db.session.commit() - if res: - return success_api(msg="删除成功") - else: - return fail_api(msg="删除失败") + return success_api(msg="删除部门成功") \ No newline at end of file diff --git a/applications/view/system/power.py b/applications/view/system/power.py index fa838cb..9f0e03c 100644 --- a/applications/view/system/power.py +++ b/applications/view/system/power.py @@ -167,6 +167,7 @@ def remove(id): r = Power.query.filter_by(id=id).delete() db.session.commit() + if r: return success_api(msg="删除成功") else: diff --git a/templates/system/dept/main.html b/templates/system/dept/main.html index 1c1f164..6358b56 100644 --- a/templates/system/dept/main.html +++ b/templates/system/dept/main.html @@ -102,36 +102,66 @@ {field: 'sort', title: '排序', width: 50}, {title: '操作', templet: '#dept-bar', width: 150, align: 'center'} ] - ] + ], + done: function (res, curr, count, origin) { + treeTable.expandAll('dept-table', true) + } }) } form.on('submit(dept-query)', function (data) { - var keyword = data.field.deptName - var $tds = $('#dept-table').next('.treeTable').find('.layui-table-body tbody tr td') - if (!keyword) { - $tds.css('background-color', 'transparent') - layer.msg('请输入关键字', {icon: 5}) - return + var keyword = data.field.deptName; + + if (!keyword) { + layer.msg('搜索内容为空', { + icon: 3, + time: 1000 + }) + return false; } - var searchCount = 0 - $tds.each(function () { - $(this).css('background-color', 'transparent') - if ($(this).text().indexOf(keyword) >= 0) { - $(this).css('background-color', 'rgba(250,230,160,0.5)') - if (searchCount === 0) { - $('body,html').stop(true) - $('body,html').animate({scrollTop: $(this).offset().top - 150}, 500) + + treeTable.checkAllNodes('dept-table', false); + + var expandNotes = []; + + treeTable.getNodesByFilter('dept-table', function (item) { + if (item.dept_name.indexOf(keyword) !== -1) { + treeTable.setRowChecked('dept-table', {index: item, checked: true}); + + // 遍历其全部父元素 + var parent_id = item.parent_id; + + while (parent_id !== 0) { + + if (!expandNotes.includes(parent_id)) { + expandNotes.push(item.LAY_DATA_INDEX); + } + + item = treeTable.getNodeById('dept-table', item.parent_id).data; + parent_id = item.parent_id; } - searchCount++ + + + if (!expandNotes.includes(parent_id)) { + expandNotes.push(item.LAY_DATA_INDEX); + } + + return true; } + + }) - if (searchCount === 0) { - layer.msg('没有匹配结果', {icon: 5}) - } else { - treeTable.expandAll('#dept-table') - } - return false + + treeTable.expandAll('dept-table', false); + + expandNotes.forEach(function (note_id) { + treeTable.expandNode('dept-table', { + index: note_id, + expandFlag: true + }); + }) + + return false; }) render() @@ -150,8 +180,7 @@ } else if (obj.event === 'refresh') { window.refresh() } else if (obj.event === 'batchRemove') { - {#window.batchRemove(obj)#} - console.log(table.checkStatus(obj.config.id).data) + window.batchRemove(obj) } }) @@ -212,7 +241,7 @@ layer.close(loading) if (result.success) { popup.success(result.msg, function () { - obj.del() + treeTable.removeNode('dept-table', obj.data.LAY_DATA_INDEX) }) } else { popup.failure(result.msg) @@ -221,6 +250,49 @@ }) }) } + + window.batchRemove = function (obj) { + let data = treeTable.checkStatus(obj.config.id).data + if (data.length === 0) { + layer.msg('未选中数据', { + icon: 3, + time: 1000 + }) + return false + } + var ids = [] + var hasCheck = treeTable.checkStatus('dept-table') + var hasCheckData = hasCheck.data + if (hasCheckData.length > 0) { + $.each(hasCheckData, function (index, element) { + ids.push(element.id) + }) + } + layer.confirm('确定要删除选中部门', { + icon: 3, + title: '提示' + }, function (index) { + layer.close(index) + let loading = layer.load() + $.ajax({ + url: MODULE_PATH + 'batchRemove', + data: {ids: ids}, + dataType: 'json', + type: 'delete', + success: function (result) { + layer.close(loading) + if (result.success) { + popup.success(result.msg, function () { + treeTable.reload('dept-table'); + }) + } else { + popup.failure(result.msg) + } + } + }) + }) + } + }) \ No newline at end of file diff --git a/templates/system/power/main.html b/templates/system/power/main.html index b8acda3..af96ea6 100644 --- a/templates/system/power/main.html +++ b/templates/system/power/main.html @@ -248,8 +248,7 @@ layer.close(loading) if (result.success) { popup.success(result.msg, function () { - console.log(obj) - obj.del() + treeTable.removeNode('power-table', obj.data.LAY_DATA_INDEX) }) } else { popup.failure(result.msg) -- Gitee From 3bb59d3786d1fb6186ddc2a9cc22cc3ab7222ead Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Tue, 21 Jan 2025 16:09:27 +0800 Subject: [PATCH 10/36] =?UTF-8?q?Update:=20=EF=BC=88=E6=AD=A5=E9=AA=A4?= =?UTF-8?q?=E5=A4=87=E4=BB=BD=EF=BC=89=E4=BF=AE=E5=A4=8D=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E5=86=85=E7=BD=AE=E6=A0=87=E7=AD=BE=E9=A1=B5=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/view/system/log.py | 11 +- .../system/component/pear/module/tabPage.js | 2 +- templates/system/admin_log/main.html | 121 +++++++++--------- 3 files changed, 68 insertions(+), 66 deletions(-) diff --git a/applications/view/system/log.py b/applications/view/system/log.py index 9f85c02..bad5444 100644 --- a/applications/view/system/log.py +++ b/applications/view/system/log.py @@ -22,9 +22,11 @@ def index(): def login_log(): # orm查询 # 使用分页获取data需要.items - log = AdminLog.query.filter_by(url='/passport/login').order_by(desc(AdminLog.create_time)).layui_paginate() + log = AdminLog.query.filter( + AdminLog.url != '/passport/login' + ).order_by(desc(AdminLog.create_time)).layui_paginate() count = log.total - return table_api(data= model_to_dicts(schema=LogOutSchema, data=log.items), count=count) + return table_api(data=model_to_dicts(schema=LogOutSchema, data=log.items), count=count) # 操作日志 @@ -33,8 +35,9 @@ def login_log(): def operate_log(): # orm查询 # 使用分页获取data需要.items - log = AdminLog.query.filter( - AdminLog.url != '/passport/login').order_by( + log = AdminLog.query.filter_by( + url='/passport/login' + ).order_by( desc(AdminLog.create_time)).layui_paginate() count = log.total return table_api(data=model_to_dicts(schema=LogOutSchema, data=log.items), count=count) diff --git a/static/system/component/pear/module/tabPage.js b/static/system/component/pear/module/tabPage.js index 91c2bc1..9598d53 100644 --- a/static/system/component/pear/module/tabPage.js +++ b/static/system/component/pear/module/tabPage.js @@ -383,7 +383,7 @@ layui.define(['jquery', 'element', 'dropdown'], function (exports) { */ tabPage.prototype.refresh = function (time) { - var $iframe = $(".layui-tab[lay-filter='" + this.option.elem + "'] .layui-tab-content .layui-show > div[data-frameid]"); + var $iframe = $(".layui-tab[lay-filter='" + this.option.elem + "'] .layui-tab-content .layui-show > div[data-frameid], iframe[data-frameid]"); var $iframeLoad; if (time != false && time != 0) { diff --git a/templates/system/admin_log/main.html b/templates/system/admin_log/main.html index 4b56702..7acb5bb 100644 --- a/templates/system/admin_log/main.html +++ b/templates/system/admin_log/main.html @@ -3,7 +3,6 @@ 日志 {% include 'system/common/header.html' %} - @@ -40,74 +39,74 @@ {% include 'system/common/footer.html' %} \ No newline at end of file -- Gitee From de36a9936a85a763ebe640411486d965d07a0381 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Tue, 21 Jan 2025 20:58:37 +0800 Subject: [PATCH 11/36] =?UTF-8?q?Update:=20=EF=BC=88=E6=AD=A5=E9=AA=A4?= =?UTF-8?q?=E5=A4=87=E4=BB=BD=EF=BC=89=E5=AE=8C=E5=96=84=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E7=9B=91=E6=8E=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/common/admin.py | 2 +- applications/common/utils/cache.py | 56 ++++ .../utils/{gen_captcha.py => captcha.py} | 2 +- .../common/utils/fonts/{1.ttf => captcha.ttf} | Bin applications/common/utils/validate.py | 52 ++-- applications/view/system/monitor.py | 163 ++++++++--- static/system/admin/css/other/monitor.css | 187 ++++++++++++ static/system/component/pear/css/pear.css | 3 +- templates/system/common/memory.html | 13 - templates/system/monitor.html | 272 +++++++++++++----- 10 files changed, 583 insertions(+), 167 deletions(-) create mode 100644 applications/common/utils/cache.py rename applications/common/utils/{gen_captcha.py => captcha.py} (98%) rename applications/common/utils/fonts/{1.ttf => captcha.ttf} (100%) create mode 100644 static/system/admin/css/other/monitor.css delete mode 100644 templates/system/common/memory.html diff --git a/applications/common/admin.py b/applications/common/admin.py index 1b7155e..4550d7d 100644 --- a/applications/common/admin.py +++ b/applications/common/admin.py @@ -2,7 +2,7 @@ from io import BytesIO from flask import session, make_response -from applications.common.utils.gen_captcha import vieCode +from applications.common.utils.captcha import vieCode # 生成验证码 diff --git a/applications/common/utils/cache.py b/applications/common/utils/cache.py new file mode 100644 index 0000000..cc130f8 --- /dev/null +++ b/applications/common/utils/cache.py @@ -0,0 +1,56 @@ +import time + +cache_dict = {} + + +def cache_set_internal(key, value, expired=5): + """ + 程序内部实现的记录缓存,用于简单、体量不大的缓存记录,在程序结束后销毁。对于高速、体量大的环境请配置 Redis 等服务自行记录。 + 记录缓存,存储键值对,并记录当前时间作为缓存的时间戳。 + + :param key: 键 + :param value: 值 + :param expired: 过期时间(秒),默认5秒 + """ + cache_dict[key] = { + 'value': value, + 'expired_time': time.time() + expired + } + + +def cache_get_internal(key): + """ + 获取缓存,根据键从缓存中获取值,并检查是否过期。 + + :param key: 键 + :return: 如果缓存存在且未过期,返回缓存的值;否则返回 None + """ + if key in cache_dict: + cache_item = cache_dict[key] + if time.time() < cache_item['expired_time']: + return cache_item['value'] + else: + # 如果缓存已过期,删除该缓存 + del cache_dict[key] + return None + + +def cache_auto_internal(key, call, expired=5): + """ + 如果缓存存在直接返回缓存内容,缓存不存在或者过期执行 call 函数,并取得返回值记录并返回。 + + :param key: 键 + :param call: 获取新值的地方 + :param expired: 过期时间(秒),默认5秒 + """ + + data = cache_get_internal(key) + + if data is not None: + return data + + data = call() + cache_set_internal(key, data, expired) + + return data + diff --git a/applications/common/utils/gen_captcha.py b/applications/common/utils/captcha.py similarity index 98% rename from applications/common/utils/gen_captcha.py rename to applications/common/utils/captcha.py index c72738c..83145b5 100644 --- a/applications/common/utils/gen_captcha.py +++ b/applications/common/utils/captcha.py @@ -14,7 +14,7 @@ class vieCode: __inCurve = True # 是否画干扰线 __inNoise = True # 是否画干扰点 __type = 2 # 验证码类型 1、纯字母 2、数字字母混合 - __fontPatn = 'applications/common/utils/fonts/1.ttf' # 字体 + __fontPatn = 'applications/common/utils/fonts/captcha.ttf' # 字体 def GetCodeImage(self, size=80, length=4): '''获取验证码图片 diff --git a/applications/common/utils/fonts/1.ttf b/applications/common/utils/fonts/captcha.ttf similarity index 100% rename from applications/common/utils/fonts/1.ttf rename to applications/common/utils/fonts/captcha.ttf diff --git a/applications/common/utils/validate.py b/applications/common/utils/validate.py index 882baf5..8d90948 100644 --- a/applications/common/utils/validate.py +++ b/applications/common/utils/validate.py @@ -11,7 +11,7 @@ def str_escape(s): between = validators.between -''' +""" 验证数字是否介于最小值和/或最大值之间。 这将适用于任何类似的类型,如浮点数、小数和日期,而不仅仅是整数。 between(value, min=None, max=None) @@ -35,10 +35,10 @@ between(value, min=None, max=None) ... min=datetime(1999, 11, 11) ... ) True -''' +""" domain = validators.domain -''' +""" 返回给定值是否为有效域 如果值是有效域名,则此函数返回 True ,否则返回 ValidationFailure domain(value) @@ -49,10 +49,10 @@ domain(value) >>> domain('example.com/') ValidationFailure(func=domain, ...) -''' +""" email = validators.email -''' +""" 验证电子邮件地址。验证成功时返回 True ,验证失败时返回 >>> email('someone@example.com') @@ -60,10 +60,10 @@ email = validators.email >>> email('bogus@@') ValidationFailure(func=email, ...) -''' +""" iban = validators.iban -''' +""" 返回给定值是否为有效的IBAN代码。 如果值是有效的IBAN,则此函数返回 True ,否则返回 ValidationFailure 。 @@ -72,10 +72,10 @@ iban = validators.iban >>> iban('123456') ValidationFailure(func=iban, ...) -''' +""" ipv4 = validators.ipv4 -''' +""" 返回给定值是否为有效的IPv4地址。 >>> ipv4('123.0.0.7') @@ -83,20 +83,20 @@ ipv4 = validators.ipv4 >>> ipv4('900.80.70.11') ValidationFailure(func=ipv4, args={'value': '900.80.70.11'}) -''' +""" ipv6 = validators.ipv6 -''' +""" 返回给定值是否为有效的IP版本6地址。 >>> ipv6('abcd:ef::42:1') True >>> ipv6('abc.0.0.1') ValidationFailure(func=ipv6, args={'value': 'abc.0.0.1'}) -''' +""" length = validators.length -''' +""" 返回给定字符串的长度是否在指定范围内。 >>> length('something', min=2) True @@ -106,10 +106,10 @@ length = validators.length >>> length('something', max=5) ValidationFailure(func=length, ...) -''' +""" mac_address = validators.mac_address -''' +""" 返回给定值是否为有效MAC地址。 如果该值是有效的MAC地址,则此函数返回 True ,否则返回 ValidationFailure 。 @@ -118,10 +118,10 @@ mac_address = validators.mac_address >>> mac_address('00:00:00:00:00') ValidationFailure(func=mac_address, args={'value': '00:00:00:00:00'}) -''' +""" slug = validators.slug -''' +""" 验证给定值是否为有效的块。 有效的短信息只能包含字母数字字符、连字符和下划线。 >>> slug('my.slug') @@ -129,15 +129,15 @@ slug = validators.slug >>> slug('my-slug-2134') True -''' +""" #truthy = validators.truthy -''' +""" 验证给定值不是错误值。 -''' +""" url = validators.url -''' +""" 返回给定值是否为有效URL。 如果值是有效URL,则此函数返回 True ,否则返回 ValidationFailure 。 @@ -152,10 +152,10 @@ url = validators.url >>> url('http://10.0.0.1', public=True) ValidationFailure(func=url, ...) -''' +""" uuid = validators.uuid -''' +""" 返回给定值是否为有效UUID。 如果值是有效的UUID,则此函数返回 True ,否则返回 ValidationFailure 。 @@ -164,7 +164,7 @@ uuid = validators.uuid >>> uuid('2bc1c94f 0deb-43e9-92a1-4775189ec9f8') ValidationFailure(func=uuid, ...) -''' +""" @validator @@ -172,7 +172,7 @@ def even(value): return not (value % 2) -''' +""" 一个装饰器,它使给定的函数验证器 每当给定函数被调用并返回 False 值时,这个装饰器返回 ValidationFailure 对象。 >>> @validator @@ -184,4 +184,4 @@ True >>> even(5) ValidationFailure(func=even, args={'value': 5}) -''' +""" diff --git a/applications/view/system/monitor.py b/applications/view/system/monitor.py index 972d49c..ac295d2 100644 --- a/applications/view/system/monitor.py +++ b/applications/view/system/monitor.py @@ -1,47 +1,33 @@ import os -import platform import re import sys import time +import psutil +import platform + from datetime import datetime -import psutil -from flask import Blueprint, render_template, jsonify +from flask import Blueprint, render_template +from applications.common.utils.http import table_api, success_api from applications.common.utils.rights import authorize +from applications.common.utils.cache import cache_auto_internal -bp = Blueprint('adminMonitor', __name__, url_prefix='/monitor') +bp = Blueprint('adminMonitor', __name__, url_prefix='/monitor') -# 系统监控 -@bp.get('/') -@authorize("system:monitor:main") -def main(): - # 主机名称 - hostname = platform.node() - # 系统版本 - system_version = platform.platform() - # python版本 - python_version = platform.python_version() - # 逻辑cpu数量 - cpu_count = psutil.cpu_count() - # cpu使用率 - cpus_percent = psutil.cpu_percent(interval=0.1, percpu=False) # percpu 获取主使用率 - # 内存 - memory_information = psutil.virtual_memory() - # 内存使用率 - memory_usage = memory_information.percent - memory_used: int = memory_information.used - memory_total: int = memory_information.total - memory_free: int = memory_information.free - # 磁盘信息 +def get_disk_partitions_list(): disk_partitions_list = [] # 判断是否在容器中 if not os.path.exists('/.dockerenv'): disk_partitions = psutil.disk_partitions() for i in disk_partitions: - a = psutil.disk_usage(i.device) + try: + a = psutil.disk_usage(i.device) + except PermissionError: + continue + disk_partitions_dict = { 'device': i.device, 'fstype': i.fstype, @@ -51,30 +37,58 @@ def main(): 'percent': a.percent } disk_partitions_list.append(disk_partitions_dict) + else: + try: + usage = psutil.disk_usage('/') + except PermissionError: + pass + + disk_partitions_list.append({ + 'device': '/', # 设备名称(根文件系统) + 'fstype': psutil.disk_partitions()[0].fstype, # 文件系统类型 + 'total': usage.total, # 总容量(字节) + 'used': usage.used, # 已用空间(字节) + 'free': usage.free, # 可用空间(字节) + 'percent': usage.percent # 使用百分比 + }) + + return disk_partitions_list + +def get_basic_info(): + # 主机名称 + hostname = platform.node() + # 系统版本 + system_version = platform.platform() + # Python 版本 + python_version = platform.python_version() # 开机时间 boot_time = datetime.fromtimestamp(psutil.boot_time()).replace(microsecond=0) up_time = datetime.now().replace(microsecond=0) - boot_time up_time_list = re.split(r':', str(up_time)) - up_time_format = " {} 小时{} 分钟{} 秒".format(up_time_list[0], up_time_list[1], up_time_list[2]) + up_time_format = "{} 小时 {} 分钟 {} 秒".format(up_time_list[0], up_time_list[1], up_time_list[2]) + up_time_format = up_time_format.replace("days,", "天") + + return { + 'hostname': hostname, + 'system_version': system_version, + 'python_version': python_version, + 'boot_time': boot_time, + 'up_time_format': up_time_format + } + +# 系统监控 +@bp.get('/') +@authorize("system:monitor:main") +def main(): + # 当前时间 time_now = time.strftime('%H:%M:%S ', time.localtime(time.time())) return render_template( 'system/monitor.html', - hostname=hostname, - system_version=system_version, - python_version=python_version, - cpus_percent=cpus_percent, - memory_usage=memory_usage, - cpu_count=cpu_count, - memory_used=memory_used, - memory_total=memory_total, - memory_free=memory_free, - boot_time=boot_time, - up_time_format=up_time_format, - disk_partitions_list=disk_partitions_list, - time_now=time_now + time_now=time_now, + **get_basic_info() ) @@ -82,19 +96,74 @@ def main(): @bp.get('/polling') @authorize("system:monitor:main") def ajax_polling(): - # 获取cpu使用率 - cpus_percent = psutil.cpu_percent(interval=0.1, percpu=False) # percpu 获取主使用率 - # 获取内存使用率 - memory_information = psutil.virtual_memory() + # 获取 CPU 核心数 + cpu_count = cache_auto_internal('cpu_count', lambda: psutil.cpu_count(), expired=999999999) + + # 获取 CPU 使用率 + cpus_percent = cache_auto_internal('cpus_percent', + lambda: psutil.cpu_percent(interval=1, percpu=False), + expired=5) + + # 每个 CPU 的使用率 + cpu_percent_per_core = cache_auto_internal('cpu_percent_per_core', + lambda: list(enumerate(psutil.cpu_percent(interval=1, percpu=True))), + expired=5) + + # 获取空闲率、等待率 + cpu_times_percent = cache_auto_internal('cpu_times_percent', + lambda: psutil.cpu_times_percent(interval=1, percpu=False), + expired=5) + + # 内存信息 + memory_information = cache_auto_internal('memory_information', + psutil.virtual_memory, + expired=5) + + # 硬盘信息 + disk_partitions_list = cache_auto_internal('disk_partitions_list', + get_disk_partitions_list, + expired=5) + + # 系统信息 + basic_info = cache_auto_internal('basic_info', + get_basic_info, + expired=5) + memory_usage = memory_information.percent - time_now = time.strftime('%H:%M:%S ', time.localtime(time.time())) - return jsonify(cups_percent=cpus_percent, memory_used=memory_usage, time_now=time_now) + memory_used = memory_information.used + memory_total = memory_information.total + memory_free = memory_information.free + + cpu_idle_percent = cpu_times_percent.idle + if hasattr(cpu_times_percent, 'iowait'): + cpu_wait_percent = cpu_times_percent.iowait + else: + cpu_wait_percent = "-" + + return table_api(msg="请求成功", + count=0, + data={ + 'cpu_count': cpu_count, + 'cpus_percent': cpus_percent, + 'cpu_idle_percent': cpu_idle_percent, + 'cpu_wait_percent': cpu_wait_percent, + 'cpu_percent_per_core': cpu_percent_per_core, + 'memory_used': memory_used, + 'memory_total': memory_total, + 'memory_free': memory_free, + 'memory_usage': memory_usage, + 'disk_partitions_list': disk_partitions_list, + 'time_now': time.strftime('%H:%M:%S', time.localtime(time.time())), + 'basic_info': basic_info + }) # 关闭程序 @bp.get('/kill') @authorize("system:monitor:main") def kill(): + # 注:若是多 worker 则不生效 + return success_api(msg="关闭命令已发送,请修改代码以生效。") for proc in psutil.process_iter(): if proc.pid == os.getpid(): proc.kill() diff --git a/static/system/admin/css/other/monitor.css b/static/system/admin/css/other/monitor.css new file mode 100644 index 0000000..687b22c --- /dev/null +++ b/static/system/admin/css/other/monitor.css @@ -0,0 +1,187 @@ +.pear-container { + background-color: whitesmoke; + margin: 10px; +} + +.pear-card { + width: 100%; + height: 66px; + background-color: #F8F8F8; + display: inline-block; + border-radius: 5px; + text-align: center; + margin-bottom: 3px; +} + +.pear-card:hover, +.pear-card2:hover { + box-shadow: 2px 0 8px 0 lightgray !important; +} + +.pear-card2 { + width: 100%; + height: 90px; + background-color: #F8F8F8; + display: inline-block; + border-radius: 5px; + text-align: center; + margin-bottom: 3px; +} + +.pear-card2 i { + font-size: 30px; + height: 90px; + line-height: 90px; +} + +.pear-card i { + font-size: 30px; + height: 66px; + line-height: 66px; +} + +.layui-col-md3 { + text-align: center; +} + +.pear-card-title { + margin-top: 3px; +} + +.person img { + width: 90px; + height: 90px; + border-radius: 4px; + margin-top: 8px; + margin-left: 8px; +} + +.pear-card2 .count { + color: var(--global-primary-color); + font-size: 30px; + margin-top: 12px; +} + +.pear-card2 .title { + color: gray; + font-size: 14px; + margin-top: 14px; +} + +.pear-card-status { + padding: 0 10px 10px; +} + +.pear-card-status li { + position: relative; + padding: 10px 0; + border-bottom: 1px solid #EEE; +} + +.pear-card-status li h3 { + padding-bottom: 5px; + font-weight: 700; +} + +.pear-card-status li p { + padding-bottom: 10px; + padding-top: 3px; +} + +.pear-card-status li > span { + color: #999; + height: 24px; + line-height: 24px; +} + +.pear-reply { + position: absolute; + right: 20px; + height: 24px; + line-height: 24px; +} + +.person .title { + font-size: 17px; + font-weight: 600; + margin-left: 18px; + margin-top: 16px; + position: absolute; + display: inline-block; +} + +.person .desc { + font-size: 16px; + font-weight: 600; + margin-left: 115px; + margin-top: -30px; + position: absolute; + display: inline-block; +} + +#tooltip { + opacity: 0; /* 默认完全透明 */ + transition: opacity 0.3s ease-in-out; /* 添加淡入淡出动画 */ + position: absolute; + border-radius: 5px; + padding: 10px; + z-index: 1000; +} + +#tooltip.show { + opacity: 1; /* 完全显示 */ +} + +#tooltip .layui-card-body ul { + display: grid; /* 启用 Grid 布局 */ + grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); /* 自动填充列 */ + gap: 5px; /* 设置子元素之间的间距 */ + padding: 0; /* 移除默认的 ul 内边距 */ + margin: 0; /* 移除默认的 ul 外边距 */ + list-style: none; /* 移除列表项的默认样式 */ +} + +#tooltip .layui-card-body ul li span { + width: 8em; + background-color: #E7EEFC !important; + color: #6197F8 !important; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); +} + +.progress-ring { + position: relative; + display: inline-block; + width: 120px; + height: 120px; + text-align: center; +} + +.progress-ring .circle { + transform: rotate(-90deg); +} + +.progress-ring .circle-bg { + fill: none; + stroke: #e6e6e6; /* 背景色 */ + stroke-width: 8; /* 环的宽度(细一点) */ +} + +.progress-ring .circle-progress { + fill: none; + stroke: var(--global-primary-color); /* 使用 CSS 变量 */ + stroke-width: 8; /* 环的宽度(细一点) */ + stroke-dasharray: 339.292; + stroke-dashoffset: calc(339.292 - (339.292 * var(--progress) / 100)); + transition: stroke-dashoffset 1s; +} + +.progress-ring .progress-text { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 18px; + font-weight: bold; + color: #333; +} + diff --git a/static/system/component/pear/css/pear.css b/static/system/component/pear/css/pear.css index 82ca512..ca73968 100644 --- a/static/system/component/pear/css/pear.css +++ b/static/system/component/pear/css/pear.css @@ -14,4 +14,5 @@ @import url("module/dtree/font/dtreefont.css"); @import url("module/dtree/dtree.css"); @import url("module/layer.css"); -@import url("module/layout.css"); \ No newline at end of file +@import url("module/layout.css"); +@import url("module/popover.min.css"); \ No newline at end of file diff --git a/templates/system/common/memory.html b/templates/system/common/memory.html deleted file mode 100644 index d7a0821..0000000 --- a/templates/system/common/memory.html +++ /dev/null @@ -1,13 +0,0 @@ -{% macro memory_format(memory) %} - {%- if memory > 1024 ** 4 * 2 -%} - {{- (memory / 1024 ** 4) | round(2) -}}TB - {% elif memory > 1024 ** 3 * 2 %} - {{- (memory / 1024 ** 3) | round(2) -}}GB - {% elif memory > 1024 ** 2 * 2 %} - {{- (memory / 1024 ** 2) | round(2) -}}MB - {% elif memory > 1024 ** 1 * 2 %} - {{- (memory / 1024 ** 1) | round(2) -}}KB - {% else %} - {{- memory -}}B - {% endif %} -{% endmacro %} \ No newline at end of file diff --git a/templates/system/monitor.html b/templates/system/monitor.html index 4e6aac9..22ac9f8 100644 --- a/templates/system/monitor.html +++ b/templates/system/monitor.html @@ -1,16 +1,15 @@ -{% from 'system/common/memory.html' import memory_format %} 首页 {% include 'system/common/header.html' %} - +
                -
                +
                主机信息 @@ -20,25 +19,25 @@
                核心数
                -
                {{ cpu_count }}
                +
                -
                空闲率
                -
                +
                -%
                等待率
                -
                +
                -%
                使用率
                -
                {{ cpus_percent }}%
                +
                -%
                @@ -55,25 +54,25 @@
                空闲内存
                -
                {{ memory_format(memory_free) }}
                +
                -
                最大内存
                -
                {{ memory_format(memory_total) }}
                +
                -
                已用内存
                -
                {{ memory_format(memory_used) }}
                +
                -
                内存使用
                -
                {{ memory_usage }}%
                +
                -%
                @@ -93,27 +92,6 @@
                -
                -
                磁盘信息
                -
                -
                  - {% for disk in disk_partitions_list %} -
                • -

                  {{ disk.device }}

                  -

                  {{ disk.fstype }}

                  - 磁盘大小: {{ memory_format(disk.total) }}   - 空闲大小: {{ memory_format(disk.free) }}   -
                  -
                  - 已经使用: {{ memory_format(disk.used) }}   - 使用率: {{ disk.percent }}% -
                  - 详情 -
                • - {% endfor %} -
                -
                -
                主机信息
                @@ -127,47 +105,135 @@ 名称 - {{ hostname }} + {{ hostname }} 系统 - {{ system_version }} + {{ system_version }} 开机时间 - {{ boot_time }} + {{ boot_time }} 运行时长 - {{ up_time_format }} + {{ up_time_format }} - python版本 - {{ python_version }} + Python 版本 + {{ python_version }} 程序操作 关闭程序 + class="layui-btn layui-btn-xs layui-btn-primary">关闭程序
                +
                +
                磁盘信息
                +
                + 加载中...... +
                +
                + +
                +
                +
                + 加载中...... +
                +
                +
                + + {% include 'system/common/footer.html' %} diff --git a/templates/system/dict/add.html b/templates/system/dict/add.html index 8e579d8..276cc02 100644 --- a/templates/system/dict/add.html +++ b/templates/system/dict/add.html @@ -12,14 +12,14 @@
                -
                -
                @@ -41,12 +41,12 @@
                - - diff --git a/templates/system/dict/data/add.html b/templates/system/dict/data/add.html index 2579d6b..3feb617 100644 --- a/templates/system/dict/data/add.html +++ b/templates/system/dict/data/add.html @@ -28,7 +28,7 @@
                + autocomplete="off" placeholder="请输入标识" class="layui-input">
                @@ -49,12 +49,12 @@
                - - diff --git a/templates/system/dict/data/edit.html b/templates/system/dict/data/edit.html index 4f33615..ce09040 100644 --- a/templates/system/dict/data/edit.html +++ b/templates/system/dict/data/edit.html @@ -19,21 +19,21 @@
                + autocomplete="off" placeholder="请输入标签" class="layui-input">
                + autocomplete="off" placeholder="请输入值" class="layui-input">
                + lay-verify="title" autocomplete="off" placeholder="请输入标识" class="layui-input">
                @@ -49,7 +49,8 @@
                + class="layui-textarea" + >{% if dict_data.remark %}{{ dict_data.remark }}{% endif %}
                @@ -57,12 +58,12 @@
                - - @@ -71,31 +72,31 @@ {% include 'system/common/footer.html' %} diff --git a/templates/system/dict/edit.html b/templates/system/dict/edit.html index 2271c36..858151d 100644 --- a/templates/system/dict/edit.html +++ b/templates/system/dict/edit.html @@ -12,22 +12,22 @@
                -
                - +
                + lay-verify="required" autocomplete="off" placeholder="请输入标识" class="layui-input">
                @@ -42,8 +42,11 @@
                - +
                @@ -51,12 +54,12 @@
                - - @@ -65,31 +68,31 @@ {% include 'system/common/footer.html' %} diff --git a/templates/system/dict/main.html b/templates/system/dict/main.html index b84534a..807b2f3 100644 --- a/templates/system/dict/main.html +++ b/templates/system/dict/main.html @@ -10,16 +10,17 @@
                -
                +
                - - @@ -38,29 +39,32 @@
                - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + +
                +
                @@ -69,48 +73,51 @@ @@ -121,254 +128,346 @@ {% include 'system/common/footer.html' %} \ No newline at end of file diff --git a/templates/system/monitor.html b/templates/system/monitor.html index 22ac9f8..c12e379 100644 --- a/templates/system/monitor.html +++ b/templates/system/monitor.html @@ -12,7 +12,7 @@
                - 主机信息 + 主机监控
                @@ -95,7 +95,7 @@
                主机信息
                - +
                @@ -244,7 +244,6 @@ }) - let bgColor = "#fff"; let color = [ "#0090FF", "#36CE9E", @@ -269,7 +268,7 @@ let echartData = []; var option = { - backgroundColor: bgColor, + backgroundColor: 'transparent', color: color, legend: { right: 10, @@ -286,6 +285,7 @@ } }, grid: { + backgroundColor: 'transparent', top: 100, containLabel: true }, -- Gitee From ed1f402c04f50ab8b92c860facfeb5cd5577b2db Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Fri, 24 Jan 2025 18:01:02 +0800 Subject: [PATCH 13/36] =?UTF-8?q?Update:=20=EF=BC=88=E6=AD=A5=E9=AA=A4?= =?UTF-8?q?=E5=A4=87=E4=BB=BD=EF=BC=89=E5=AE=8C=E5=96=84=E9=82=AE=E4=BB=B6?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E3=80=81=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E7=9A=84=E9=A1=B5=E9=9D=A2=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/view/system/mail.py | 2 +- templates/system/mail/add.html | 6 +++--- templates/system/mail/main.html | 14 +++++++------- templates/system/photo/photo.html | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/applications/view/system/mail.py b/applications/view/system/mail.py index 0ad03c6..01ec31a 100644 --- a/applications/view/system/mail.py +++ b/applications/view/system/mail.py @@ -20,7 +20,7 @@ def main(): return render_template('system/mail/main.html') -# 用户分页查询 +# 用户分页查询 @bp.get('/data') @authorize("system:mail:main") def data(): diff --git a/templates/system/mail/add.html b/templates/system/mail/add.html index a420915..6c5c305 100644 --- a/templates/system/mail/add.html +++ b/templates/system/mail/add.html @@ -34,11 +34,11 @@
                - - @@ -53,7 +53,7 @@ form.on('submit(mail-save)', function (data) { let loading = layer.load() $.ajax({ - url: '/admin/mail/save', + url: '/system/mail/save', data: JSON.stringify(data.field), dataType: 'json', contentType: 'application/json', diff --git a/templates/system/mail/main.html b/templates/system/mail/main.html index 44be20e..09f66fd 100644 --- a/templates/system/mail/main.html +++ b/templates/system/mail/main.html @@ -10,7 +10,7 @@
                -
                +
                @@ -23,11 +23,11 @@
                - - @@ -47,13 +47,13 @@ {# 表格操作 #} diff --git a/templates/system/photo/photo.html b/templates/system/photo/photo.html index 132d438..9ea907c 100644 --- a/templates/system/photo/photo.html +++ b/templates/system/photo/photo.html @@ -13,13 +13,13 @@ -- Gitee From e27fa53ec8c5cff88f91964b1e93f0f1ef2405bd Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Fri, 24 Jan 2025 18:02:49 +0800 Subject: [PATCH 14/36] =?UTF-8?q?Update:=20=E5=90=8C=E6=AD=A5=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E6=A1=86=E6=9E=B6=E4=B8=8E=20Pear=20Admin=204.0=20?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=EF=BC=8C=E5=AE=8C=E5=96=84=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/system/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/system/index.html b/templates/system/index.html index f5db1cc..d024767 100644 --- a/templates/system/index.html +++ b/templates/system/index.html @@ -1,7 +1,7 @@ - Pear Admin 4.0 + Pear Admin Flask {% include 'system/common/header.html' %} -- Gitee From f9ad03880563778ff2b4890e832500096bb755cd Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Fri, 24 Jan 2025 18:37:40 +0800 Subject: [PATCH 15/36] =?UTF-8?q?Update:=20=E5=A2=9E=E5=8A=A0=E4=B8=BB?= =?UTF-8?q?=E9=A1=B5=E9=A1=B5=E8=84=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/system/index.html | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/templates/system/index.html b/templates/system/index.html index d024767..ee0f8b4 100644 --- a/templates/system/index.html +++ b/templates/system/index.html @@ -67,7 +67,16 @@
                - +
                -- Gitee From 3c4377915b9ca4313f2cffb76e0f20aa9fd8fe79 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Fri, 24 Jan 2025 18:44:53 +0800 Subject: [PATCH 16/36] =?UTF-8?q?Update:=20=E5=A2=9E=E5=8A=A0=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E6=B6=88=E6=81=AF=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/view/system/rights.py | 112 ++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/applications/view/system/rights.py b/applications/view/system/rights.py index c1a107f..2087da4 100644 --- a/applications/view/system/rights.py +++ b/applications/view/system/rights.py @@ -4,6 +4,7 @@ from collections import OrderedDict from flask import jsonify, current_app, Blueprint, render_template from flask_login import login_required, current_user +from ...common.utils.http import table_api from ...models import Power from ...schemas import PowerOutSchema @@ -85,10 +86,118 @@ def configs(): "keepLoad": 0, # 布局顶部主题 "autoHead": False - }, header=False) + }, header={ + 'message': '/system/rights/message' + }) return jsonify(config) +# 消息 +@bp.get('/message') +@login_required +def message(): + return dict(code=200, + data=[ + { + "id": 1, + "title": "通知", + "children": [ + { + "id": 11, + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png", + "title": "你收到了 14 份新周报", + "context": "这是消息内容。", + "form": "就眠仪式", + "time": "刚刚" + }, + { + "id": 12, + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png", + "title": "曲妮妮 已通过第三轮面试", + "context": "这是消息内容。", + "form": "就眠仪式", + "time": "刚刚" + }, + { + "id": 11, + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png", + "title": "可以区分多种通知类型", + "context": "这是消息内容。", + "form": "就眠仪式", + "time": "刚刚" + }, + { + "id": 12, + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png", + "title": "左侧图标用于区分不同的类型", + "context": "这是消息内容。", + "form": "就眠仪式", + "time": "刚刚" + }, + { + "id": 11, + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png", + "title": "内容不要超过两行字", + "context": "这是消息内容。", + "form": "就眠仪式", + "time": "刚刚" + } + ] + }, + { + "id": 2, + "title": "消息", + "children": [ + { + "id": 11, + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png", + "title": "你收到了 14 份新周报", + "context": "这是消息内容。", + "form": "就眠仪式", + "time": "刚刚" + }, + { + "id": 12, + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png", + "title": "曲妮妮 已通过第三轮面试", + "context": "这是消息内容。", + "form": "就眠仪式", + "time": "刚刚" + }, + { + "id": 11, + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png", + "title": "可以区分多种通知类型", + "context": "这是消息内容。", + "form": "就眠仪式", + "time": "刚刚" + }, + { + "id": 12, + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png", + "title": "左侧图标用于区分不同的类型", + "context": "这是消息内容。", + "form": "就眠仪式", + "time": "刚刚" + }, + { + "id": 11, + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png", + "title": "内容不要超过两行字", + "context": "这是消息内容。", + "form": "就眠仪式", + "time": "刚刚" + } + ] + }, + { + "id": 3, + "title": "代办", + "children": [] + } + ]) + + # 菜单 @bp.get('/menu') @login_required @@ -148,6 +257,7 @@ def menu(): menu_dict[_dict['parent_id']].append(_dict) return jsonify(sorted(menu_dict.get(0), key=lambda item: item['sort'])) + # 控制台页面 @bp.get('/welcome') @login_required -- Gitee From 2ee703d2ebb48556b9fcdcfd7bb1c4bc95fcd6cf Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Fri, 24 Jan 2025 19:13:41 +0800 Subject: [PATCH 17/36] =?UTF-8?q?=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E8=BF=9B=E8=A1=8C=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/view/system/passport.py | 2 +- static/system/admin/css/other/error.css | 76 +++++++++++++++++++++++++ templates/errors/403.html | 4 +- templates/errors/404.html | 4 +- templates/errors/500.html | 6 +- 5 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 static/system/admin/css/other/error.css diff --git a/applications/view/system/passport.py b/applications/view/system/passport.py index 503cc47..acb21bd 100644 --- a/applications/view/system/passport.py +++ b/applications/view/system/passport.py @@ -21,7 +21,7 @@ def get_captcha(): @bp.get('/login') def login(): if current_user.is_authenticated: - return redirect(url_for('system.index')) + return redirect(url_for('index.index')) return render_template('system/login.html') diff --git a/static/system/admin/css/other/error.css b/static/system/admin/css/other/error.css new file mode 100644 index 0000000..37d4c0e --- /dev/null +++ b/static/system/admin/css/other/error.css @@ -0,0 +1,76 @@ +* { + padding: 0; + margin: 0; + font-size: 0.38rem; +} + +ul { + list-style: none; +} + +a { + text-decoration: none; + -webkit-tap-highlight-color: transparent +} + +.clearfix:after { + content: ''; + width: 0; + height: 0; + display: block; + clear: both; +} + +html { + height: 100%; + width: 100%; +} + +body { + font-size: 0.28rem; + height: 100%; + width: 100%; + display: flex; + flex-direction: column; + position: relative; + background-color: white !important; +} + +.content { + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 100%; + text-align: center; +} + +.content>img { + height: 300px; + max-width: 370px; + margin-right: 180px; +} + +.content>* { + display: inline-block; +} + +.content-r { + vertical-align: top; +} + +.content-r>h1 { + font-size: 72px; + color: #434e59; + margin-bottom: 24px; + font-weight: 600; +} + +.content-r>p { + font-size: 20px; + color: rgba(0, 0, 0, .45); + margin-bottom: 16px; +} + +button { + margin-top: 20px; +} diff --git a/templates/errors/403.html b/templates/errors/403.html index d3124d0..65eb941 100644 --- a/templates/errors/403.html +++ b/templates/errors/403.html @@ -3,7 +3,7 @@ - + {% include 'system/common/header.html' %} @@ -12,7 +12,7 @@

                403

                抱歉,你无权访问该页面

                - +
                diff --git a/templates/errors/404.html b/templates/errors/404.html index 10ebcdd..4200625 100644 --- a/templates/errors/404.html +++ b/templates/errors/404.html @@ -3,7 +3,7 @@ - + {% include 'system/common/header.html' %} @@ -12,7 +12,7 @@

                404

                抱歉,你访问的页面不存在或仍在开发中

                - +
                diff --git a/templates/errors/500.html b/templates/errors/500.html index e5b4130..45b5f85 100644 --- a/templates/errors/500.html +++ b/templates/errors/500.html @@ -2,8 +2,8 @@ - - + 500 + {% include 'system/common/header.html' %} admin/ @@ -12,7 +12,7 @@

                500

                抱歉,服务器出错了

                - +
                -- Gitee From de644f0f3407e39316bb3152fa5851d021cc3069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E8=BE=B0=E5=A4=A7=E6=B5=B7?= <2317903+shaodj@user.noreply.gitee.com> Date: Fri, 24 Jan 2025 22:33:09 +0000 Subject: [PATCH 18/36] update applications/models/admin_dept.py. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 星辰大海 <2317903+shaodj@user.noreply.gitee.com> --- applications/models/admin_dept.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/models/admin_dept.py b/applications/models/admin_dept.py index 7ecb516..8ecd7c9 100644 --- a/applications/models/admin_dept.py +++ b/applications/models/admin_dept.py @@ -15,4 +15,4 @@ class Dept(db.Model): remark = db.Column(db.Text, comment="备注") address = db.Column(db.String(255), comment="详细地址") create_at = db.Column(db.DateTime, default=datetime.datetime.now, comment='创建时间') - update_at = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment='创建时间') \ No newline at end of file + update_at = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment='更新时间') \ No newline at end of file -- Gitee From 8a99864b4186e0fb48f74834d6c7dd2fedc4131a Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Sat, 25 Jan 2025 09:51:02 +0800 Subject: [PATCH 19/36] =?UTF-8?q?=E5=88=A0=E9=99=A4=E7=94=A8=E4=BA=8E?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=9A=84=20print?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/view/system/dict.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/view/system/dict.py b/applications/view/system/dict.py index d07cfa3..2c7d75e 100644 --- a/applications/view/system/dict.py +++ b/applications/view/system/dict.py @@ -279,7 +279,7 @@ def dict_type_batch_remove(): @authorize("system:dict:remove", log=True) def dict_data_batch_remove(): ids = request.form.getlist('ids[]') - print(ids) + for _id in ids: res = curd.delete_one_by_id(model=DictData, id=_id) if not res: -- Gitee From ba7cc426288401c333ac329f6f4fe1eebdf63773 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Sat, 25 Jan 2025 10:07:31 +0800 Subject: [PATCH 20/36] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E6=9D=83=E9=99=90=E5=9C=B0=E5=9D=80=E7=9B=B4=E6=8E=A5?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E8=B7=B3=E8=BD=AC=E4=B9=8B=E5=90=8E=E7=9A=84?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=EF=BC=8C=E9=98=B2=E6=AD=A2=20https=20?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/common/script/admin.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/applications/common/script/admin.py b/applications/common/script/admin.py index 83ece0c..826ddfa 100644 --- a/applications/common/script/admin.py +++ b/applications/common/script/admin.py @@ -174,7 +174,7 @@ powerdata = [ name='角色管理', type='1', code='system:role:main', - url='/system/role', + url='/system/role/', open_type='_iframe', parent_id='1', icon='layui-icon layui-icon-username', @@ -187,7 +187,7 @@ powerdata = [ name='系统监控', type='1', code='system:monitor:main', - url='/system/monitor', + url='/system/monitor/', open_type='_iframe', parent_id='1', icon='layui-icon layui-icon-vercode', @@ -200,7 +200,7 @@ powerdata = [ name='日志管理', type='1', code='system:log:main', - url='/system/log', + url='/system/log/', open_type='_iframe', parent_id='1', icon='layui-icon layui-icon-read', @@ -226,7 +226,7 @@ powerdata = [ name='图片上传', type='1', code='system:file:main', - url='/system/file', + url='/system/file/', open_type='_iframe', parent_id='17', icon='layui-icon layui-icon-camera', @@ -395,7 +395,7 @@ powerdata = [ name='数据字典', type='1', code='system:dict:main', - url='/system/dict', + url='/system/dict/', open_type='_iframe', parent_id='1', icon='layui-icon layui-icon-console', @@ -447,7 +447,7 @@ powerdata = [ name='部门管理', type='1', code='system:dept:main', - url='/system/dept', + url='/system/dept/', open_type='_iframe', parent_id='1', icon='layui-icon layui-icon-group', @@ -499,7 +499,7 @@ powerdata = [ name='邮件管理', type='1', code='system:mail:main', - url='/system/mail', + url='/system/mail/', open_type='_iframe', parent_id='1', icon='layui-icon ', -- Gitee From 184c4ad80db255b68ba824ce0472824eeb4462cc Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Sat, 25 Jan 2025 14:03:37 +0800 Subject: [PATCH 21/36] =?UTF-8?q?=E6=9B=B4=E6=AD=A3=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E4=B8=8E=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/common/utils/upload.py | 2 +- applications/config.py | 65 ++++++------- dockerdata/config.py | 91 +++++++------------ .../templates/helloworld_index.html | 4 +- plugins/replacePage/__init__.py | 4 +- .../templates/replacePage_index.html | 4 +- 6 files changed, 69 insertions(+), 101 deletions(-) diff --git a/applications/common/utils/upload.py b/applications/common/utils/upload.py index c5d361d..c38242e 100644 --- a/applications/common/utils/upload.py +++ b/applications/common/utils/upload.py @@ -17,7 +17,7 @@ def get_photo(page, limit): def upload_one(photo, mime): filename = photos.save(photo) - file_url = '/_uploads/photos/'+filename + file_url = '/_uploads/photos/' + filename # file_url = photos.url(filename) upload_url = current_app.config.get("UPLOADED_PHOTOS_DEST") size = os.path.getsize(upload_url + '/' + filename) diff --git a/applications/config.py b/applications/config.py index e8e3bdf..b5369f0 100644 --- a/applications/config.py +++ b/applications/config.py @@ -2,13 +2,13 @@ import logging from datetime import timedelta -# from urllib.parse import quote_plus as urlquote - - class BaseConfig: + # 超级管理员账号 SUPERADMIN = 'admin' + # 系统名称 SYSTEM_NAME = 'Pear Admin' + # 主题面板的链接列表配置 SYSTEM_PANEL_LINKS = [ { @@ -28,42 +28,14 @@ class BaseConfig: } ] + # 上传图片目标文件夹 UPLOADED_PHOTOS_DEST = 'static/upload' - UPLOADED_FILES_ALLOW = ['gif', 'jpg'] + UPLOADED_FILES_ALLOW = ['gif', 'jpg', 'jpeg', 'png', 'webp'] UPLOADS_AUTOSERVE = True - # JSON配置 + # JSON 配置 JSON_AS_ASCII = False - SECRET_KEY = "pear-system-flask" - - # mysql 配置 - # MYSQL_USERNAME = "root" - # MYSQL_PASSWORD = "123456" - # MYSQL_HOST = "127.0.0.1" - # MYSQL_PORT = 3306 - # MYSQL_DATABASE = "PearAdminFlask" - - # 数据库的配置信息 - SQLALCHEMY_DATABASE_URI = 'sqlite:///../pear.db' - # SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{MYSQL_USERNAME}:{urlquote(MYSQL_PASSWORD)}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}?charset=utf8mb4" - - # 默认日志等级 - LOG_LEVEL = logging.WARN - """ - flask-mail配置 - """ - MAIL_SERVER = 'smtp.qq.com' - MAIL_USE_TLS = False - MAIL_USE_SSL = True - MAIL_PORT = 465 - MAIL_USERNAME = '123@qq.com' - MAIL_PASSWORD = 'XXXXX' # 生成的授权码 - MAIL_DEFAULT_SENDER = MAIL_USERNAME - - # 插件配置,填写插件的文件名名称,默认不启用插件。 - PLUGIN_ENABLE_FOLDERS = [] - # 配置多个数据库连接的连接串写法示例 # HOSTNAME: 指数据库的IP地址、USERNAME:指数据库登录的用户名、PASSWORD:指数据库登录密码、PORT:指数据库开放的端口、DATABASE:指需要连接的数据库名称 # MSSQL: f"mssql+pymssql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=cp936" @@ -83,13 +55,30 @@ class BaseConfig: # 'testOracle': 'oracle+cx_oracle://test:123456@192.168.1.1:1521/test', # 'testSQLite': 'sqlite:///database.db # } - """ - session - """ + # 数据库的配置信息 + SQLALCHEMY_DATABASE_URI = 'sqlite:///../pear.db' + + # 默认日志等级 + LOG_LEVEL = logging.WARN + + # 发信设置 + MAIL_SERVER = 'smtp.qq.com' + MAIL_USE_TLS = False + MAIL_USE_SSL = True + MAIL_PORT = 465 + MAIL_USERNAME = '123@qq.com' + MAIL_PASSWORD = 'XXXXX' # 生成的授权码 + MAIL_DEFAULT_SENDER = MAIL_USERNAME + + # 插件配置,填写插件的文件名名称,默认不启用插件。 + PLUGIN_ENABLE_FOLDERS = [] + + # Session 设置 PERMANENT_SESSION_LIFETIME = timedelta(days=7) - SESSION_TYPE = "filesystem" # 默认使用文件系统来保存会话 + SESSION_TYPE = "filesystem" # 默认使用文件系统来保存会话 SESSION_PERMANENT = False # 会话是否持久化 SESSION_USE_SIGNER = True # 是否对发送到浏览器上 session 的 cookie 值进行加密 + SECRET_KEY = "pear-system-flask" diff --git a/dockerdata/config.py b/dockerdata/config.py index f5933a6..b5369f0 100644 --- a/dockerdata/config.py +++ b/dockerdata/config.py @@ -1,18 +1,14 @@ import logging -from urllib.parse import quote_plus as urlquote - -from apscheduler.executors.pool import ThreadPoolExecutor -from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore +from datetime import timedelta class BaseConfig: - DEBUG = True - HOST = '127.0.0.1' - PORT = 5000 - - SUPERADMIN = 'system' + # 超级管理员账号 + SUPERADMIN = 'admin' + # 系统名称 SYSTEM_NAME = 'Pear Admin' + # 主题面板的链接列表配置 SYSTEM_PANEL_LINKS = [ { @@ -32,61 +28,18 @@ class BaseConfig: } ] + # 上传图片目标文件夹 UPLOADED_PHOTOS_DEST = 'static/upload' - UPLOADED_FILES_ALLOW = ['gif', 'jpg'] + UPLOADED_FILES_ALLOW = ['gif', 'jpg', 'jpeg', 'png', 'webp'] UPLOADS_AUTOSERVE = True - # JSON配置 + # JSON 配置 JSON_AS_ASCII = False - SECRET_KEY = "pear-system-flask" - - # redis配置 - REDIS_HOST = "127.0.0.1" - REDIS_PORT = 6379 - - # mysql 配置 - MYSQL_USERNAME = "root" - MYSQL_PASSWORD = "123456" - MYSQL_HOST = "172.10.1.31" - MYSQL_PORT = 3306 - MYSQL_DATABASE = "PearAdminFlask" - - # mysql 数据库的配置信息 - SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{MYSQL_USERNAME}:{urlquote(MYSQL_PASSWORD)}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}?charset=utf8mb4" - - # 默认日志等级 - LOG_LEVEL = logging.WARN - # - MAIL_SERVER = 'smtp.qq.com' - MAIL_USE_TLS = False - MAIL_USE_SSL = True - MAIL_PORT = 465 - MAIL_USERNAME = '123@qq.com' - MAIL_PASSWORD = 'XXXXX' # 生成的授权码 - MAIL_DEFAULT_SENDER = MAIL_USERNAME - - # 設置 APSCHEDULER 參數 - SCHEDULER_API_ENABLED = False - SCHEDULER_JOBSTORES: dict = { - 'default': SQLAlchemyJobStore( - url=f'mysql+pymysql://{MYSQL_USERNAME}:{MYSQL_PASSWORD}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}') - } - SCHEDULER_EXECUTORS: dict = { - 'default': ThreadPoolExecutor(20) - } - SCHEDULER_JOB_DEFAULTS: dict = { - 'coalesce': False, - 'max_instances': 3 - } - - # 插件配置 - PLUGIN_ENABLE_FOLDERS = ["helloworld"] - # 配置多个数据库连接的连接串写法示例 # HOSTNAME: 指数据库的IP地址、USERNAME:指数据库登录的用户名、PASSWORD:指数据库登录密码、PORT:指数据库开放的端口、DATABASE:指需要连接的数据库名称 # MSSQL: f"mssql+pymssql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=cp936" - # MySQL: f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8" + # MySQL: f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4" # Oracle: f"oracle+cx_oracle://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}" # SQLite "sqlite:/// database.db" # Postgres f"postgresql+psycopg2://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}" @@ -103,3 +56,29 @@ class BaseConfig: # 'testSQLite': 'sqlite:///database.db # } + # 数据库的配置信息 + SQLALCHEMY_DATABASE_URI = 'sqlite:///../pear.db' + + # 默认日志等级 + LOG_LEVEL = logging.WARN + + # 发信设置 + MAIL_SERVER = 'smtp.qq.com' + MAIL_USE_TLS = False + MAIL_USE_SSL = True + MAIL_PORT = 465 + MAIL_USERNAME = '123@qq.com' + MAIL_PASSWORD = 'XXXXX' # 生成的授权码 + MAIL_DEFAULT_SENDER = MAIL_USERNAME + + # 插件配置,填写插件的文件名名称,默认不启用插件。 + PLUGIN_ENABLE_FOLDERS = [] + + # Session 设置 + PERMANENT_SESSION_LIFETIME = timedelta(days=7) + + SESSION_TYPE = "filesystem" # 默认使用文件系统来保存会话 + SESSION_PERMANENT = False # 会话是否持久化 + SESSION_USE_SIGNER = True # 是否对发送到浏览器上 session 的 cookie 值进行加密 + + SECRET_KEY = "pear-system-flask" diff --git a/plugins/helloworld/templates/helloworld_index.html b/plugins/helloworld/templates/helloworld_index.html index 266f34c..6878fa4 100644 --- a/plugins/helloworld/templates/helloworld_index.html +++ b/plugins/helloworld/templates/helloworld_index.html @@ -27,10 +27,10 @@
                diff --git a/plugins/replacePage/__init__.py b/plugins/replacePage/__init__.py index 6e4cd7e..b9922f9 100644 --- a/plugins/replacePage/__init__.py +++ b/plugins/replacePage/__init__.py @@ -20,7 +20,7 @@ def event_init(app: Flask): return render_template_string(f.read()) # Index.index 是主页的视图函数对应的名称,原视图函数位于 applications/view/index/index.py - del app.view_functions['Index.index'] # 释放原视图函数 - app.view_functions['Index.index'] = new_index # 替换原视图函数 + del app.view_functions['index.index'] # 释放原视图函数 + app.view_functions['index.index'] = new_index # 替换原视图函数 \ No newline at end of file diff --git a/plugins/replacePage/templates/replacePage_index.html b/plugins/replacePage/templates/replacePage_index.html index b964434..55b7195 100644 --- a/plugins/replacePage/templates/replacePage_index.html +++ b/plugins/replacePage/templates/replacePage_index.html @@ -27,10 +27,10 @@
                -- Gitee From 40d0ea956d7bb7a69833a5819dc84cfa5a36be74 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Sat, 25 Jan 2025 14:08:43 +0800 Subject: [PATCH 22/36] =?UTF-8?q?=E6=9B=B4=E6=AD=A3=20docker=20=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dockerdata/config.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dockerdata/config.py b/dockerdata/config.py index b5369f0..b398d99 100644 --- a/dockerdata/config.py +++ b/dockerdata/config.py @@ -1,5 +1,6 @@ import logging from datetime import timedelta +from urllib.parse import quote_plus as urlquote class BaseConfig: @@ -57,7 +58,14 @@ class BaseConfig: # } # 数据库的配置信息 - SQLALCHEMY_DATABASE_URI = 'sqlite:///../pear.db' + MYSQL_USERNAME = "root" + MYSQL_PASSWORD = "123456" + MYSQL_HOST = "172.10.1.31" + MYSQL_PORT = 3306 + MYSQL_DATABASE = "PearAdminFlask" + + # mysql 数据库的配置信息 + SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{MYSQL_USERNAME}:{urlquote(MYSQL_PASSWORD)}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}?charset=utf8mb4" # 默认日志等级 LOG_LEVEL = logging.WARN -- Gitee From 145ccbfb3e9a100dfd5f8a66e850693d4fa72243 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Sun, 26 Jan 2025 16:04:05 +0800 Subject: [PATCH 23/36] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9D=83=E9=99=90?= =?UTF-8?q?=E6=8C=89=E9=92=AE=E7=B1=BB=E5=9E=8B=E6=B7=BB=E5=8A=A0=E9=97=AE?= =?UTF-8?q?=E9=A2=98=EF=BC=8C=E4=BF=AE=E5=A4=8D=E6=97=A5=E5=BF=97=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E8=A1=A8=E6=A0=BC=E6=9C=AA=E5=AF=B9=E9=BD=90=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 17 ++++++++++++---- Dockerfile | 26 ++++++++++++++++-------- app.py | 1 - docker-compose.yaml | 17 ++++++++++++++++ dockercompose.yaml | 30 ---------------------------- dockerdata/start.sh | 26 +++--------------------- templates/system/admin_log/main.html | 2 +- templates/system/power/add.html | 4 ++-- 8 files changed, 54 insertions(+), 69 deletions(-) create mode 100644 docker-compose.yaml delete mode 100644 dockercompose.yaml diff --git a/.dockerignore b/.dockerignore index 1571289..b859899 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,8 +1,17 @@ -#build时候不会copy以下文件 +# 构建的相关文件 dockerdata docker-compose.yml Dockerfile.server README.md -!dockerdata/config.py -!dockerdata/start.sh -!dockerdata/gunicorn.conf.py \ No newline at end of file + +# Python 相关文件 +migrations/ +instance/ +flask_session/ +venv/ +.idea/ +*.log +*.db + +# 允许拷贝的文件 +!dockerdata/start.sh \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 2dde1e5..3e5612c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,28 @@ -FROM pearadminflask/python3.7-flask:pillow +FROM python:3.11-bookworm +# 复制项目文件 +RUN mkdir -p /app COPY . /app/ -COPY dockerdata/start.sh /app/ -COPY dockerdata/gunicorn.conf.py /app/ +COPY ./dockerdata/start.sh /app/start.sh WORKDIR /app/ +# 设置必备项 ENV TIME_ZONE Asia/Shanghai -ENV PIPURL "https://pypi.tuna.tsinghua.edu.cn/simple/ --trusted-host pypi.douban.com" RUN echo "${TIME_ZONE}" > /etc/timezone \ && ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime -RUN apk update && apk add mysql-client -RUN chmod +x start.sh -RUN sed -i 's/MYSQL_HOST = "127.0.0.1"/MYSQL_HOST = "mysql"/' applications/config.py -RUN sed -i 's/REDIS_HOST = "127.0.0.1"/REDIS_HOST = "redis"/' applications/config.py +# 安装必备库 +RUN python3 -m pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/ + +# 初始化数据库 +RUN flask db init +RUN flask db migrate +RUN flask db upgrade +RUN flask admin init + +# 运行命令 +RUN chmod +x start.sh + +# 保持执行 CMD /bin/sh diff --git a/app.py b/app.py index d7cfec3..a5622a5 100644 --- a/app.py +++ b/app.py @@ -2,6 +2,5 @@ from applications import create_app app = create_app() - if __name__ == '__main__': app.run() diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..c7172c3 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,17 @@ +version: '3' +services: + flask: + build: + context: . + dockerfile: Dockerfile + container_name: flask + ports: + - "5000:5000" + restart: always + command: sh -c "/app/start.sh" + networks: + - my_bridge_network + +networks: + my_bridge_network: + driver: bridge \ No newline at end of file diff --git a/dockercompose.yaml b/dockercompose.yaml deleted file mode 100644 index 6ca9424..0000000 --- a/dockercompose.yaml +++ /dev/null @@ -1,30 +0,0 @@ -version: '3' -services: - redis: - image: redis - container_name: redis - ports: - - "63799:6379" - mysql: - image: mysql - container_name: mysql - environment: - MYSQL_ROOT_PASSWORD: 123456 - LANG: C.UTF-8 - TZ: Asia/Shanghai - MYSQL_CHARSET: utf8mb4 - MYSQL_COLLATION: utf8mb4_unicode_ci - ports: - - "3306:3306" - flask: - build: - context: . - dockerfile: Dockerfile - container_name: flask - ports: - - "8000:8000" - depends_on: - - redis - - mysql - restart: always - command: sh -c "./start.sh" diff --git a/dockerdata/start.sh b/dockerdata/start.sh index 54dfe08..c2d76af 100644 --- a/dockerdata/start.sh +++ b/dockerdata/start.sh @@ -1,25 +1,5 @@ #!/bin/bash -# Wait for MySQL container to be ready -echo "Waiting for MySQL container to start..." -until mysql -h mysql -uroot -p123456 -e ";" 2>/dev/null; do - echo "MySQL container not ready, sleeping for 5 seconds..." - sleep 5 -done -echo "MySQL container started successfully!" - -# to start create the dababase -echo " start to create the databse... " -mysql -uroot -p123456 -hmysql -e 'CREATE DATABASE PearAdminFlask DEFAULT CHARSET UTF8;' - - -# Initialize Flask database -echo "Initializing Flask database..." -flask db init -flask db migrate -flask db upgrade -flask admin init - -# Start gunicorn application -echo "Starting gunicorn application..." -exec gunicorn -c gunicorn.conf.py "applications:create_app()" \ No newline at end of file +# 运行程序 +echo "Starting application..." +python3 app.py \ No newline at end of file diff --git a/templates/system/admin_log/main.html b/templates/system/admin_log/main.html index 7acb5bb..ff205b6 100644 --- a/templates/system/admin_log/main.html +++ b/templates/system/admin_log/main.html @@ -72,7 +72,7 @@ elem: '#log-login-table', url: MODULE_PATH + 'loginLog', page: true, - cols: cols, + cols: JSON.parse(JSON.stringify(cols)), // 复制对象 skin: 'line', toolbar: false }) diff --git a/templates/system/power/add.html b/templates/system/power/add.html index 188a193..f80a5d9 100644 --- a/templates/system/power/add.html +++ b/templates/system/power/add.html @@ -26,7 +26,7 @@
                + class="layui-input">
                @@ -41,7 +41,7 @@
                + class="layui-input">
                -- Gitee From c9b08a07f435833984b3cc5d014c86f8c2f9cee5 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Sun, 26 Jan 2025 16:12:59 +0800 Subject: [PATCH 24/36] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E7=9A=84=E6=8C=89=E9=92=AE=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/system/dept/main.html | 4 ++-- templates/system/dict/main.html | 4 ++-- templates/system/mail/main.html | 4 ++-- templates/system/power/main.html | 4 ++-- templates/system/role/main.html | 4 ++-- templates/system/user/main.html | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/templates/system/dept/main.html b/templates/system/dept/main.html index 6358b56..e3e394f 100644 --- a/templates/system/dept/main.html +++ b/templates/system/dept/main.html @@ -13,11 +13,11 @@
                - - diff --git a/templates/system/dict/main.html b/templates/system/dict/main.html index 807b2f3..9d117fe 100644 --- a/templates/system/dict/main.html +++ b/templates/system/dict/main.html @@ -15,12 +15,12 @@
                - - diff --git a/templates/system/mail/main.html b/templates/system/mail/main.html index 09f66fd..46293ee 100644 --- a/templates/system/mail/main.html +++ b/templates/system/mail/main.html @@ -23,11 +23,11 @@
                - - diff --git a/templates/system/power/main.html b/templates/system/power/main.html index af96ea6..9e63353 100644 --- a/templates/system/power/main.html +++ b/templates/system/power/main.html @@ -13,11 +13,11 @@
                - - diff --git a/templates/system/role/main.html b/templates/system/role/main.html index 20f92ad..09ed2eb 100644 --- a/templates/system/role/main.html +++ b/templates/system/role/main.html @@ -17,11 +17,11 @@
                - - diff --git a/templates/system/user/main.html b/templates/system/user/main.html index da7e5e5..9c8a746 100644 --- a/templates/system/user/main.html +++ b/templates/system/user/main.html @@ -19,11 +19,11 @@
                - - -- Gitee From fa6cc470638de5da44a581962e48f863a8b8d0f8 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Sun, 26 Jan 2025 16:38:32 +0800 Subject: [PATCH 25/36] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20docker=20=E6=9E=84?= =?UTF-8?q?=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 2 - Dockerfile => dockerdata/Dockerfile | 3 + dockerdata/Dockerfile.all | 26 ------ dockerdata/Dockerfile.flask | 14 --- dockerdata/Dockerfile.server | 15 --- dockerdata/config.py | 92 ------------------- .../docker-compose.yaml | 8 +- dockerdata/docker-compose.yml | 40 -------- dockerdata/gunicorn.conf.py | 19 ---- dockerdata/mysql/initdb/init.sql | 1 - dockerdata/mysql/my.cnf | 31 ------- dockerdata/requirements.txt | 14 --- dockerdata/restart_mysql_data.sh | 4 - dockerdata/start.sh | 6 +- migrate.sh | 1 - run.sh | 1 - 16 files changed, 12 insertions(+), 265 deletions(-) rename Dockerfile => dockerdata/Dockerfile (86%) delete mode 100644 dockerdata/Dockerfile.all delete mode 100644 dockerdata/Dockerfile.flask delete mode 100644 dockerdata/Dockerfile.server delete mode 100644 dockerdata/config.py rename docker-compose.yaml => dockerdata/docker-compose.yaml (66%) delete mode 100644 dockerdata/docker-compose.yml delete mode 100644 dockerdata/gunicorn.conf.py delete mode 100755 dockerdata/mysql/initdb/init.sql delete mode 100644 dockerdata/mysql/my.cnf delete mode 100644 dockerdata/requirements.txt delete mode 100644 dockerdata/restart_mysql_data.sh delete mode 100644 migrate.sh delete mode 100755 run.sh diff --git a/.dockerignore b/.dockerignore index b859899..b3b37a4 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,7 +1,5 @@ # 构建的相关文件 dockerdata -docker-compose.yml -Dockerfile.server README.md # Python 相关文件 diff --git a/Dockerfile b/dockerdata/Dockerfile similarity index 86% rename from Dockerfile rename to dockerdata/Dockerfile index 3e5612c..16d4530 100644 --- a/Dockerfile +++ b/dockerdata/Dockerfile @@ -15,6 +15,9 @@ RUN echo "${TIME_ZONE}" > /etc/timezone \ # 安装必备库 RUN python3 -m pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/ +# 安装 +RUN python3 -m pip install gunicorn -i https://pypi.tuna.tsinghua.edu.cn/simple/ + # 初始化数据库 RUN flask db init RUN flask db migrate diff --git a/dockerdata/Dockerfile.all b/dockerdata/Dockerfile.all deleted file mode 100644 index 5811537..0000000 --- a/dockerdata/Dockerfile.all +++ /dev/null @@ -1,26 +0,0 @@ -FROM python:3.7-alpine - -COPY . /app/ -COPY dockerdata/config.py /app/applications/ -COPY dockerdata/start.sh /app/ - -WORKDIR /app/ - -ENV TIME_ZONE Asia/Shanghai -ENV PIPURL "https://pypi.tuna.tsinghua.edu.cn/simple/ --trusted-host pypi.douban.com" - -RUN apk update \ - && apk add --virtual mysqlclient-build gcc python3-dev musl-dev \ - && apk add --no-cache mariadb-dev \ - && apk add --virtual system-build linux-headers libffi-dev \ - && apk add --no-cache jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \ - && apk add --no-cache bash bash-doc bash-completion \ - && apk add --no-cache libxslt-dev tzdata g++ -RUN echo "${TIME_ZONE}" > /etc/timezone \ - && ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime -RUN pip --no-cache-dir install -i ${PIPURL} --upgrade pip \ - && pip --no-cache-dir install -i ${PIPURL} -r requirements.txt \ - && pip --no-cache-dir install -i ${PIPURL} gunicorn \ - && chmod +x /app/start.sh - -CMD ./start.sh diff --git a/dockerdata/Dockerfile.flask b/dockerdata/Dockerfile.flask deleted file mode 100644 index 3a19ed6..0000000 --- a/dockerdata/Dockerfile.flask +++ /dev/null @@ -1,14 +0,0 @@ -FROM python:3.7-alpine - -ENV PIPURL "https://pypi.tuna.tsinghua.edu.cn/simple/ --trusted-host pypi.douban.com" -RUN apk update \ - && apk add --virtual mysqlclient-build gcc python3-dev musl-dev \ - && apk add --no-cache mariadb-dev \ - && apk add --virtual system-build linux-headers libffi-dev \ - && apk add --no-cache jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \ - && apk add --no-cache bash bash-doc bash-completion \ - && apk add --no-cache libxslt-dev tzdata g++ -COPY requirements.txt /requirements.txt -RUN pip --no-cache-dir install -i ${PIPURL} --upgrade pip \ - && pip --no-cache-dir install -i ${PIPURL} -r /requirements.txt \ - && pip --no-cache-dir install -i ${PIPURL} gunicorn diff --git a/dockerdata/Dockerfile.server b/dockerdata/Dockerfile.server deleted file mode 100644 index 01465bb..0000000 --- a/dockerdata/Dockerfile.server +++ /dev/null @@ -1,15 +0,0 @@ -FROM pearadminflask/python3.7-flask:pillow - -COPY . /app/ -COPY dockerdata/config.py /app/applications/ -COPY dockerdata/start.sh /app - -WORKDIR /app/ - -ENV TIME_ZONE Asia/Shanghai - -RUN echo "${TIME_ZONE}" > /etc/timezone \ - && ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime \ - && chmod +x /app/start.sh - -CMD ./start.sh diff --git a/dockerdata/config.py b/dockerdata/config.py deleted file mode 100644 index b398d99..0000000 --- a/dockerdata/config.py +++ /dev/null @@ -1,92 +0,0 @@ -import logging -from datetime import timedelta -from urllib.parse import quote_plus as urlquote - - -class BaseConfig: - # 超级管理员账号 - SUPERADMIN = 'admin' - - # 系统名称 - SYSTEM_NAME = 'Pear Admin' - - # 主题面板的链接列表配置 - SYSTEM_PANEL_LINKS = [ - { - "icon": "layui-icon layui-icon-auz", - "title": "官方网站", - "href": "http://www.pearadmin.com" - }, - { - "icon": "layui-icon layui-icon-auz", - "title": "开发文档", - "href": "http://www.pearadmin.com" - }, - { - "icon": "layui-icon layui-icon-auz", - "title": "开源地址", - "href": "https://gitee.com/Jmysy/Pear-Admin-Layui" - } - ] - - # 上传图片目标文件夹 - UPLOADED_PHOTOS_DEST = 'static/upload' - UPLOADED_FILES_ALLOW = ['gif', 'jpg', 'jpeg', 'png', 'webp'] - UPLOADS_AUTOSERVE = True - - # JSON 配置 - JSON_AS_ASCII = False - - # 配置多个数据库连接的连接串写法示例 - # HOSTNAME: 指数据库的IP地址、USERNAME:指数据库登录的用户名、PASSWORD:指数据库登录密码、PORT:指数据库开放的端口、DATABASE:指需要连接的数据库名称 - # MSSQL: f"mssql+pymssql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=cp936" - # MySQL: f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4" - # Oracle: f"oracle+cx_oracle://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}" - # SQLite "sqlite:/// database.db" - # Postgres f"postgresql+psycopg2://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}" - # Oracle的第二种连接方式 - # dsnStr = cx_Oracle.makedsn({HOSTNAME}, 1521, service_name='orcl') - # connect_str = "oracle://%s:%s@%s" % ('{USERNAME}', ' {PASSWORD}', dsnStr) - - # 在SQLALCHEMY_BINDS 中设置:'{数据库连接别名}': '{连接串}' - # 最后在models的数据模型class中,在__tablename__前设置 __bind_key__ = '{数据库连接别名}' 即可,表示该数据模型不使用默认的数据库连接,改用“SQLALCHEMY_BINDS”中设置的其他数据库连接 - # SQLALCHEMY_BINDS = { - # 'testMySQL': 'mysql+pymysql://test:123456@192.168.1.1:3306/test?charset=utf8', - # 'testMsSQL': 'mssql+pymssql://test:123456@192.168.1.1:1433/test?charset=cp936', - # 'testOracle': 'oracle+cx_oracle://test:123456@192.168.1.1:1521/test', - # 'testSQLite': 'sqlite:///database.db - # } - - # 数据库的配置信息 - MYSQL_USERNAME = "root" - MYSQL_PASSWORD = "123456" - MYSQL_HOST = "172.10.1.31" - MYSQL_PORT = 3306 - MYSQL_DATABASE = "PearAdminFlask" - - # mysql 数据库的配置信息 - SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{MYSQL_USERNAME}:{urlquote(MYSQL_PASSWORD)}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}?charset=utf8mb4" - - # 默认日志等级 - LOG_LEVEL = logging.WARN - - # 发信设置 - MAIL_SERVER = 'smtp.qq.com' - MAIL_USE_TLS = False - MAIL_USE_SSL = True - MAIL_PORT = 465 - MAIL_USERNAME = '123@qq.com' - MAIL_PASSWORD = 'XXXXX' # 生成的授权码 - MAIL_DEFAULT_SENDER = MAIL_USERNAME - - # 插件配置,填写插件的文件名名称,默认不启用插件。 - PLUGIN_ENABLE_FOLDERS = [] - - # Session 设置 - PERMANENT_SESSION_LIFETIME = timedelta(days=7) - - SESSION_TYPE = "filesystem" # 默认使用文件系统来保存会话 - SESSION_PERMANENT = False # 会话是否持久化 - SESSION_USE_SIGNER = True # 是否对发送到浏览器上 session 的 cookie 值进行加密 - - SECRET_KEY = "pear-system-flask" diff --git a/docker-compose.yaml b/dockerdata/docker-compose.yaml similarity index 66% rename from docker-compose.yaml rename to dockerdata/docker-compose.yaml index c7172c3..7d357d8 100644 --- a/docker-compose.yaml +++ b/dockerdata/docker-compose.yaml @@ -2,16 +2,16 @@ version: '3' services: flask: build: - context: . - dockerfile: Dockerfile + context: .. + dockerfile: dockerdata/Dockerfile container_name: flask ports: - "5000:5000" restart: always command: sh -c "/app/start.sh" networks: - - my_bridge_network + - bridge_network networks: - my_bridge_network: + bridge_network: driver: bridge \ No newline at end of file diff --git a/dockerdata/docker-compose.yml b/dockerdata/docker-compose.yml deleted file mode 100644 index 0faa82c..0000000 --- a/dockerdata/docker-compose.yml +++ /dev/null @@ -1,40 +0,0 @@ -version: '3' -services: - mysql: - image: "mysql:5.7" - container_name: mysql - restart: always - ports: - - "3306:3306" - volumes: - - "./dockerdata/mysql/data:/var/lib/mysql" - - "./dockerdata/mysql/initdb:/docker-entrypoint-initdb.d" - environment: - LANG: C.UTF-8 - TZ: Asia/Shanghai - MYSQL_ROOT_PASSWORD: 123456 - command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci - networks: - flask-network: - ipv4_address: 172.10.1.31 - - flask: - build: - context: . - dockerfile: Dockerfile.server - container_name: flask - restart: always - ports: - - "8000:8000" - depends_on: - - mysql - networks: - flask-network: - ipv4_address: 172.10.1.11 - -networks: - flask-network: - driver: bridge - ipam: - config: - - subnet: 172.10.0.0/16 diff --git a/dockerdata/gunicorn.conf.py b/dockerdata/gunicorn.conf.py deleted file mode 100644 index 4aa61bf..0000000 --- a/dockerdata/gunicorn.conf.py +++ /dev/null @@ -1,19 +0,0 @@ -import os -import multiprocessing - -bind = '0.0.0.0:8000' -backlog = 512 -chdir = os.path.dirname(os.path.abspath(__file__)) -timeout = 30 -worker_class = 'sync' - -workers = multiprocessing.cpu_count() * 2 + 1 -threads = 2 -loglevel = 'info' -access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"' - -if not os.path.exists('logs'): - os.mkdir('logs') - -accesslog = os.path.join(chdir, "logs/gunicorn_access.log") -errorlog = os.path.join(chdir, "logs/gunicorn_error.log") diff --git a/dockerdata/mysql/initdb/init.sql b/dockerdata/mysql/initdb/init.sql deleted file mode 100755 index 3cfad21..0000000 --- a/dockerdata/mysql/initdb/init.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE DATABASE PearAdminFlask DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;; diff --git a/dockerdata/mysql/my.cnf b/dockerdata/mysql/my.cnf deleted file mode 100644 index c998cb0..0000000 --- a/dockerdata/mysql/my.cnf +++ /dev/null @@ -1,31 +0,0 @@ -[mysql] - -default-character-set=utf8 - -[client] - -default-character-set = utf8 - -[mysqld] -server_id = 1 -# 开启二进制日志 -log-bin = mysql-bin -# 只保留7天的二进制日志,以防磁盘被日志占满 -expire-logs-days = 7 -# 二进制日志自动删除的天数,默认值为0,表示“没有自动删除”,启动时和二进制日志循环时可能删除 -expire_logs_days = 7 -# 设置编码与字符集 -init_connect='SET collation_connection = utf8_unicode_ci' -init_connect='SET NAMES utf8' -character-set-server=utf8 -collation-server=utf8_unicode_ci -# 设置错误日志路径 -log-error = /usr/local/mysql/log/error.log -# 设置查询日志路径 -general_log = on -general_log_file = /usr/local/mysql/log/mysql.log -#开启慢查询日志路径 -slow_query_log = on -long_query_time = 3 -log-queries-not-using-indexes = on -slow-query-log-file = /usr/local/mysql/log/slowquery.log diff --git a/dockerdata/requirements.txt b/dockerdata/requirements.txt deleted file mode 100644 index 34a80f2..0000000 --- a/dockerdata/requirements.txt +++ /dev/null @@ -1,14 +0,0 @@ -Flask -Flask-APScheduler -Flask-Migrate -Flask-Login -Flask_Reuploaded -Flask-SQLAlchemy -flask-marshmallow -marshmallow-sqlalchemy -PyMySQL -psutil -Flask-Mail -Pillow -validators -cryptography \ No newline at end of file diff --git a/dockerdata/restart_mysql_data.sh b/dockerdata/restart_mysql_data.sh deleted file mode 100644 index 99858ed..0000000 --- a/dockerdata/restart_mysql_data.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -rm -rf /root/pear-admin-flask/dockerdata/mysql/data/ -docker exec mysql /bin/bash -c "mysql -uroot -p123456 -e 'drop database IF EXISTS PearAdminFlask;CREATE DATABASE PearAdminFlask DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;'" -docker exec flask /bin/sh -c "rm -rf migrations ; sh /app/start.sh" \ No newline at end of file diff --git a/dockerdata/start.sh b/dockerdata/start.sh index c2d76af..1171931 100644 --- a/dockerdata/start.sh +++ b/dockerdata/start.sh @@ -1,5 +1,9 @@ #!/bin/bash +# 这里可以设置同步时间等操作 + # 运行程序 echo "Starting application..." -python3 app.py \ No newline at end of file + +# 这里可以修改运行命令 +gunicorn -b 0.0.0.0:5000 app:app \ No newline at end of file diff --git a/migrate.sh b/migrate.sh deleted file mode 100644 index e3cb307..0000000 --- a/migrate.sh +++ /dev/null @@ -1 +0,0 @@ -flask db migrate && flask db upgrade \ No newline at end of file diff --git a/run.sh b/run.sh deleted file mode 100755 index aded26a..0000000 --- a/run.sh +++ /dev/null @@ -1 +0,0 @@ -flask --app app.py run -h 0.0.0.0 -p 8000 --debug \ No newline at end of file -- Gitee From de4f2c6d52d2972dbd3d2aded8ee10ba28f0f2d9 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Sun, 26 Jan 2025 20:45:54 +0800 Subject: [PATCH 26/36] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=BF=AB=E9=80=9F?= =?UTF-8?q?=E5=BC=80=E5=A7=8B=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 30 ++--- docs/Makefile | 20 ++++ docs/detail.md | 44 ------- docs/install.md | 114 ------------------ docs/list.md | 43 ------- docs/make.bat | 2 + docs/requirements.txt | 3 + docs/source/_static/login.png | Bin 0 -> 264567 bytes docs/source/conf.py | 28 +++++ docs/source/function/index.rst | 9 ++ docs/source/function/utils/cache.rst | 2 + docs/source/function/utils/index.rst | 8 ++ docs/source/index.rst | 23 ++++ docs/source/welcome/index.rst | 11 ++ docs/source/welcome/instruction.rst | 150 ++++++++++++++++++++++++ docs/source/welcome/migration.rst | 98 ++++++++++++++++ docs/source/welcome/quickstart.rst | 169 +++++++++++++++++++++++++++ docs/source/welcome/update.rst | 55 +++++++++ 18 files changed, 593 insertions(+), 216 deletions(-) create mode 100644 docs/Makefile delete mode 100644 docs/detail.md delete mode 100644 docs/install.md delete mode 100644 docs/list.md create mode 100644 docs/make.bat create mode 100644 docs/requirements.txt create mode 100644 docs/source/_static/login.png create mode 100644 docs/source/conf.py create mode 100644 docs/source/function/index.rst create mode 100644 docs/source/function/utils/cache.rst create mode 100644 docs/source/function/utils/index.rst create mode 100644 docs/source/index.rst create mode 100644 docs/source/welcome/index.rst create mode 100644 docs/source/welcome/instruction.rst create mode 100644 docs/source/welcome/migration.rst create mode 100644 docs/source/welcome/quickstart.rst create mode 100644 docs/source/welcome/update.rst diff --git a/README.md b/README.md index f688d28..9b3953c 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Pear Admin Layui Version - Python Version + Python Version Mysql Version @@ -59,7 +59,7 @@ Pear Admin Flask 基于 Flask 的后台管理系统,拥抱应用广泛的pytho # 版本支持情况 -经过测试,此项目的(master分支)运行要求是 `>= Python 3.8` ,推荐使用 `Python 3.9`。 +经过测试,此项目的(master分支)运行要求是 `>= Python 3.8` ,推荐使用 `Python 3.11`。 > **💡提示** 由于 Flask 中使用的 Werkzeug 模块更新,Flask 官方并未进行更新,所以可能会出现 ImportError 。 > 此类情况的出现可以通过正确安装 `requirements.txt` 中的模块(以及其对应版本)解决。 @@ -69,19 +69,19 @@ Pear Admin Flask 基于 Flask 的后台管理系统,拥抱应用广泛的pytho ## 应用结构 ```应用结构 -Pear Admin Flask -├─applications # 应用 -│ ├─extensions # 注册插件 -│ ├─models # 数据模型 -│ ├─static # 静态资源文件 -│ ├─templates # 静态模板文件 -│ └─views # 视图部分 -│ ├─admin # 后台管理视图模块 -│ └─index # 前台视图模块 +Pear Admin Flask (master) +├─applications # 项目核心模块 +│ ├─common # 公共模块(初始化数据库、公用函数) +│ ├─extensions # 注册项目插件 +│ ├─schemas # 序列化模型 +│ ├─models # 数据库模型 +│ ├─views # 视图部分 +│ ├─config.py # 项目配置 +│ └─__init__.py # 项目初始化入口 ├─docs # 文档说明 -├─migrations # 迁移文件记录 -├─requirement # 依赖文件 -└─.env # 项目的配置文件 +├─static # 静态资源文件 +├─templates # 静态模板文件 +└─app.py # 程序入口 ``` ## 资源结构 @@ -159,7 +159,7 @@ python -m venv venv # 进入虚拟环境下 venv\Scripts\activate.bat # Windows 提示命令符 venv\Scripts\Activate.ps1 # Windows Powershell -. venv/bin/activate # Linux +source venv/bin/activate # Linux # 使用 pip 安装 pip install -r requirements.txt diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..92dd33a --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/detail.md b/docs/detail.md deleted file mode 100644 index 7d60398..0000000 --- a/docs/detail.md +++ /dev/null @@ -1,44 +0,0 @@ -## 项目介绍 :id=start - -欢迎阅读 Pear Admin Flask 的开发文档!Pear Admin Flask 是一个基于 Flask 的后台管理系统,拥抱应用广泛的 Python 语言,通过使用本系统,即可快速构建你的功能业务。 - -项目旨在为 Python 开发者提供一个后台管理系统的模板,成为您构建信息管理系统、物联网后台等应用时灵活、简单的工具。 - -同时,Pear Admin Flask 项目也是一个对于 Python 初学者友好的项目。此项目处于开发初期,欢迎各位 Python 爱好者加入到 Pear Admin Flask 项目建设中来。如果您在使用此项目的过程中,发现项目代码存在问题,请在 Gitee 上提交 PR ,一起开源共建! - -接下来,我们将会为您详细介绍该项目搭建方法与开发架构。 - -> 如果对项目有不理解的地方欢迎加入我们的讨论群。 - -![QQ群](assets/qqgroup.jpg) - -> 微信群不定期在qq群更新二维码。 - -![开始使用](assets/界面演示.jpeg) - -**[master分支版本](https://gitee.com/pear-admin/pear-admin-flask/tree/master/)** - -flask 2.0.1 + flask-sqlalchemy + 权限验证 + Flask-APScheduler 定时任务 + marshmallow 序列化与数据验证 - -master 分支为主分支,是功能最全、页面最多的分支。 - -![开始使用](assets/界面演示.jpeg) - -## 下载使用 :id=download - - -#### 1. 官网地址 - -官网提供稳定版本的 Release 发行版本 [前往](http://www.pearadmin.com) - -![官方网址](assets/官网地址.jpg) - -#### 2. 源码仓库 - -如果你需要最新代码,请前往 Gitee 仓库 [前往](https://gitee.com/pear-admin/pear-admin-flask) - -![源码仓库](assets/源码仓库.jpg) - - -如果您完成了这一步,请参阅[下载安装](install.md)章节。 - diff --git a/docs/install.md b/docs/install.md deleted file mode 100644 index c4b2002..0000000 --- a/docs/install.md +++ /dev/null @@ -1,114 +0,0 @@ -### 环境要求 :id=install -- Python >= 3.6 -- Mysql >= 5.7.0 - -### 安装配置 - -#### 克隆远程仓库 - -您可以使用 git 来克隆远程仓库: - -```shell -# 进入项目主目录 -cd Pear Admin Flask - -# 使用 git 克隆远程仓库 -git clone https://gitee.com/pear-admin/pear-admin-flask.git - -# 切换分支 -git checkout master # master, main or mini -``` - -或者直接前往 Pear Admin Flask 项目的[Gitee 主页](https://gitee.com/pear-admin/pear-admin-flask)下载项目仓库。 - -#### 搭建开发环境 - -我们推荐使用 Python 的虚拟环境来开发该项目,这样便于项目的迁移与二次开发。当然,您也可以选择使用原 Python 环境。 - -如果你想创建 Python 虚拟环境,你可以使用下面的命令行: - -```shell -# 在当前目录的venv文件夹创建虚拟环境 -python -m venv venv - -# Windows 激活虚拟环境 -.\test_env\Scripts\Activate.ps1 - -# Linux 和 Mac 激活虚拟环境 -source ./test_env/bin/activate -``` - -**如果在创建虚拟环境时报错 “ModuleNotFoundError” ,这说明您的 Python 版本小于 3.3 。** - -#### 安装项目依赖 - -```shell -# 使用 pip 安装必要模块(对于 master 分支) -pip install -r requirements.txt - -# 使用 pip 安装必要模块(对于 mini 分支) -pip install -r requirement.txt -``` - -或者您可以尝试: - -```shell -# 使用 pip 安装必要模块 -python -m pip install -r requirement.txt -``` - -#### 配置数据库 - -在 `applications/config.py` 中配置好数据库。 - -> 由于结构与目录调整,我们简化了项目结构,废弃了文件 ```.flaskenv``` ,请使用 config.py 配置程序。 - -并使用以下命令生成数据库文件: - -```shell -# 初始化数据库 -flask db init -flask db migrate -flask db upgrade -flask admin init -``` - -#### 运行项目 - -```shell -# windows -run.bat - -# linux -./run.sh -``` - -#### 使用docker-compose运行项目 - -```shell -# 安装docker-compose -curl -L https://github.com/docker/compose/releases/download/1.26.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose -chmod +x /usr/local/bin/docker-compose -ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose - -docker-compose --version -docker-compose up -d # -d后台运行 -docker-compose stop # 停止启动 -docker-compose down # 清除容器 - -dockerdata/config.py # 配置文件 -dockerdata/mysql/initdb/ # MySQL初始化数据在 -rm -rf dockerdata/mysql/{log,data}/* # down掉容器后启动需要清除删除log,dat -``` - -### 二次开发 - -恭喜!现在您已经成功搭建并运行了 Pear Admin Flask ,是时候参与开发了: - -请阅读: - -+ Pear Admin Flask [目录结构](list.md) 章节 -+ Pear Admin Flask [开发函数](function.md) 章节 -+ Pear Admin Flask [插件开发](plugin.md) 章节 - -其它章节等待更新。 diff --git a/docs/list.md b/docs/list.md deleted file mode 100644 index 891fa73..0000000 --- a/docs/list.md +++ /dev/null @@ -1,43 +0,0 @@ -## 应用结构 :id=config -```应用结构 -Pear Admin Flask -├─applications # 应用 -│ ├─configs # 配置文件 -│ │ ├─ common.py # 普通配置 -│ │ └─ config.py # 配置文件对象 -│ ├─extensions # 注册插件 -│ ├─models # 数据模型 -│ ├─static # 静态资源文件 -│ ├─templates # 静态模板文件 -│ └─views # 视图部分 -│ ├─admin # 后台管理视图模块 -│ └─index # 前台视图模块 -├─docs # 文档说明 -├─migrations # 迁移文件记录 -├─requirement # 依赖文件 -└─.env # 项目的配置文件 -``` - -## 资源结构 :id=static -```资源结构 -Pear Admin Flask -├─static # 项目设定的 Flask 资源文件夹 -│ ├─admin # pear admin flask 的后端资源文件(与 pear admin layui 同步) -│ ├─index # pear admin flask 的前端资源文件 -│ └─upload # 用户上传保存目录 -└─templates # 项目设定的 Flask 模板文件夹 - ├─admin # pear admin flask 的后端管理页面模板 - │ ├─admin_log # 日志页面 - │ ├─common # 基本模板页面(头部模板与页脚模板) - │ ├─console # 系统监控页面模板 - │ ├─dept # 部门管理页面模板 - │ ├─dict # 数据自动页面模板 - │ ├─mail # 邮件管理页面模板 - │ ├─photo # 图片上传页面模板 - │ ├─power # 权限(菜单)管理页面模板 - │ ├─role # 角色管理页面模板 - │ ├─task # 任务设置页面模板 - │ └─user # 用户管理页面模板 - ├─errors # 错误页面模板 - └─index # 主页模板 -``` \ No newline at end of file diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..b01af03 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,2 @@ +del _build /s /q +sphinx-build .\source .\_build \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..27eabc6 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,3 @@ +sphinx>=5 +docutils<=0.21 +sphinx-rtd-theme \ No newline at end of file diff --git a/docs/source/_static/login.png b/docs/source/_static/login.png new file mode 100644 index 0000000000000000000000000000000000000000..430271bb0e94a0c0cc951c4ee1deddf3427e0eb4 GIT binary patch literal 264567 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%0Dk#ec_JD%tc_M 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 z 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

                ljO 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 +
                +
                +

                + Pear Admin Flask +

                +

                + 开 箱 即 用 的 Flask 快 速 开 发 平 台 +

                + +
                +

                + + Pear Admin Layui Version + + + Python Version + + + Mysql Version + +

                + +
                + +
                + +项目简介 +--------------- + +Pear Admin Flask 基于 Flask 的后台管理系统,拥抱应用广泛的python语言,通过使用本系统,即可快速构建你的功能业务 +项目旨在为 python 开发者提供一个后台管理系统的模板,可以快速构建信息管理系统。 + +项目使用 flask-sqlalchemy + 权限验证 + marshmallow 序列化与数据验证,以此方式集成了若干不同的功能。 + +内置功能 +---------- + +- **用户管理**:用户是系统操作者,该功能主要完成系统用户配置。 +- **权限管理**:配置系统菜单,操作权限,按钮权限标识等。 +- **角色管理**:角色菜单权限分配。 +- **操作日志**:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 +- **登录日志**:系统登录日志记录查询包含登录异常。 +- **服务监控**:监视当前系统 CPU、内存、磁盘、Python 版本、运行时长等相关信息。 +- **文件上传**:图片上传示例。 + +项目分支说明 +--------------- + +.. warning:: + Pear Admin Flask 不仅仅只提供一种对于 Pear Admin 后端的实现方式,所以提供了不同的分支版本,不同分支版本各有其优劣,并且由不同的开发者维护 + +.. list-table:: + :header-rows: 1 + + * - 分支名称 + - 特点 + * - `master `_ + - 功能齐全,处于开发阶段,代码量较大。 + * - `main `_ + - 功能精简,代码量小,处于开发阶段,易于维护。 + * - `mini `_ + - 不再更新,是最初版本的镜像 + +版本支持情况 +--------------- + +经过测试,此项目的(master分支)运行要求是 ``>= Python 3.8`` ,推荐使用 ``Python 3.11``。 + +.. tip:: + 由于 Flask 中使用的 Werkzeug 模块更新,Flask 官方并未进行更新,所以可能会出现 ImportError 。 + 截止至 2025 年 1 月 26 日,若使用项目中 **requirements.txt** 不会出现该错误。 + +此类情况的出现可以通过正确安装 **requirements.txt** 中的模块(以及其对应版本)解决。 + + +目录架构 +-------------- + +应用结构 +~~~~~~~~~~ + +.. code-block:: bash + + Pear Admin Flask (master) + ├─applications # 项目核心模块 + │ ├─common # 公共模块(初始化数据库、公用函数) + │ ├─extensions # 注册项目插件 + │ ├─schemas # 序列化模型 + │ ├─models # 数据库模型 + │ ├─views # 视图部分 + │ ├─config.py # 项目配置 + │ └─__init__.py # 项目初始化入口 + ├─docs # 文档说明 + ├─static # 静态资源文件 + ├─templates # 静态模板文件 + └─app.py # 程序入口 + +资源结构 +~~~~~~~~~~ + +.. code-block:: bash + + Pear Admin Flask (master) + ├─static # 项目设定的 Flask 资源文件夹 + │ ├─admin # pear admin flask 的后端资源文件(与 pear admin layui 同步) + │ ├─index # pear admin flask 的前端资源文件 + │ └─upload # 用户上传保存目录 + └─templates # 项目设定的 Flask 模板文件夹 + ├─admin # pear admin flask 的后端管理页面模板 + │ ├─admin_log # 日志页面 + │ ├─common # 基本模板页面(头部模板与页脚模板) + │ ├─console # 系统监控页面模板 + │ ├─dept # 部门管理页面模板 + │ ├─dict # 数据自动页面模板 + │ ├─mail # 邮件管理页面模板 + │ ├─photo # 图片上传页面模板 + │ ├─power # 权限(菜单)管理页面模板 + │ ├─role # 角色管理页面模板 + │ ├─task # 任务设置页面模板 + │ └─user # 用户管理页面模板 + ├─errors # 错误页面模板 + └─index # 主页模板 + +开发资源 +------------- + +由于项目依赖多个开源项目,而此开发文档并不会全进行涉足,所以提供如下的链接共大家开发参考: + +* 前端页面设计可以参考 `layui 原生态 · 开源 极简模块化 Web UI 组件库 `_ 。 +* 后端 Flask 学习可以参考官方的 `Flask 开发文档 `_ 。 +* Pear Admin 框架的源码可以查看 `Pear Admin 开源仓库 `_ 。 +* 开发时可以选择 `PyCharm `_ 作为集成开发环境 。 \ No newline at end of file diff --git a/docs/source/welcome/migration.rst b/docs/source/welcome/migration.rst new file mode 100644 index 0000000..0d9f0c2 --- /dev/null +++ b/docs/source/welcome/migration.rst @@ -0,0 +1,98 @@ +.. _migration: + +从旧项目迁移 +================= + +由于 `Pear Admin Layui `_ 框架(下面将会称其为 “主项目”)的更新获得了更好的性能与新的功能, +此项目 Pear Admin Flask 作为主项目的附属项目将会在一定时间进行迁移与同步。由于主项目的更新,此项目的部分功能被弃用这大大增加了同步的难度,所以在一段时间 +内,此项目并未有同步的打算。为了获得性能更新,此项目于 2025 的新年前后开始逐步将项目代码进行同步与完善,迫不得已舍去了部分功能,这为以往基于此项目的作品更新 +加大了难度,所以便有了此迁移章节。各位开发者,如果您想要同步自己原先以项目为基础的作品,请阅读该章节。 + +.. _migration1: + +迁移到 v2.0.0-4.0.5 版本 +---------------------------- + +更正验证码生成模块引用 +~~~~~~~~~~~~~~~~~~~~~~ + +由于 ``applications/common/utils/gen_captcha.py`` 更名为 ``applications/common/utils/captcha.py`` ,需要修改导入引用。 + +例如: + +.. code-block:: python + + from applications.common.utils.gen_captcha import vieCode + +更正为: + +.. code-block:: python + + from applications.common.utils.captcha import vieCode + + +后台首页路径修改 +~~~~~~~~~~~~~~~~~~~~~~ + +由于为了对齐主项目,``system/console/console.html`` 更名为 ``system/analysis/main.html``,前端页面需要进行修改。 + +例如: + +.. code-block:: html + + + +更正为: + +.. code-block:: html + + + + +公用模板修改 +~~~~~~~~~~~~~~~~~~~~~~~~ + +移除了 ``templates/system/common/memory.html`` ,该文件原先仅用于系统监控页面,现在换为 JavaScript 函数进行换算。 +详情参阅模板文件 ``templates/system/monitor.html`` + + +移除 Pear Button 模块 +~~~~~~~~~~~~~~~~~~~~~~~~ + +由于主项目不再使用 Pear Button 而直接使用 Layui Button。所以需要将所有的按钮 class 中的 “pear-btn” 变为 “layui-btn”。 +(附属的 pear-btn-* 也要修改,建议是直接搜索替换。) + + +例如: + +.. code-block:: html + + + + +改为: + +.. code-block:: html + + + + +.. tip:: + + 你会注意到修改之后的 layui-btn-primary 属性添加在了 “重置” 按钮上,而不是 “查询” 按钮上, + 这是因为 layui-btn-primary 是默认白色的,而不加 layui-btn-primary 属性是跟随主题色的。这里需要特别注意一下。 + + + diff --git a/docs/source/welcome/quickstart.rst b/docs/source/welcome/quickstart.rst new file mode 100644 index 0000000..0be2f7d --- /dev/null +++ b/docs/source/welcome/quickstart.rst @@ -0,0 +1,169 @@ +快速开始 +========================= + +此章节将介绍 Pear Admin Flask 搭建的方法,将会 Python 搭建与 Docker 自动构建两种方法。 + +克隆仓库 +----------------- + +.. code-block:: bash + + git clone https://gitee.com/pear-admin/pear-admin-flask + cd pear-admin-flask # 进入到项目目录 + +Python 部署 +----------------- + +创建虚拟环境 +~~~~~~~~~~~~~~~~ + +推荐使用虚拟环境,如果您不想使用虚拟环境请跳过这一步。 + +.. code-block:: bash + + python -m venv venv + + venv\Scripts\activate.bat # Windows 提示命令符 + venv\Scripts\Activate.ps1 # Windows Powershell + source venv/bin/activate # Linux + + +安装必要模块 +~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + # 使用 pip 安装 + pip install -r requirements.txt + + # 另外,如果上述无效,你可以选择以模块的方式调用 pip + python -m pip install -r requirements.txt + +设置配置文件 +~~~~~~~~~~~~~~~~ + +打开文件 `applications/config.py` 进行编辑,在其中配置数据库等相关信息,默认采用的是 sqlite3 存储项目数据。 + +.. code-block:: python + + # 数据库的配置信息 + SQLALCHEMY_DATABASE_URI = 'sqlite:///../pear.db' + +.. important:: + + 注意!在实际项目中一定要修改 SECRET_KEY 参数!否则存在 Cookie 中的 session 被破解的情况。 + +初始化数据库 +~~~~~~~~~~~~~~~~ + +随后需要初始化数据库。 + +.. code-block:: bash + + flask db init + flask db migrate + flask db upgrade + flask admin init + +运行项目(调试模式) +~~~~~~~~~~~~~~~~~~~~~~~~~ + +可以使用 flask 对项目进行调试运行。此方式仅用于生产环境。 + +.. code-block:: bash + + flask run + + # 或者使用 + python app.py + + +发布项目 +~~~~~~~~~~~~~~~~~~~~~~~~~ + +推荐使用 `gunicorn` 对项目进行发布。 + +.. code-block:: bash + + pip install gunicorn # 安装 gunicorn + + # 运行项目 + gunicorn -b 0.0.0.0:5000 app:app + + +如果部分平台(如 Windows)不能使用 `gunicorn` 可以尝试使用 `pywsgi` 。 + +.. code-block:: bash + + pip install gevent # 安装 gevent + +并修改 app.py 文件为: + +.. code-block:: python + + from applications import create_app + + from gevent import pywsgi + + app = create_app() + + if __name__ == '__main__': + # app.run() + server = pywsgi.WSGIServer(('0.0.0.0', 7000), app) + server.serve_forever() + +随后在控制台中: + +.. code-block:: bash + + # 运行项目 + python app.py + +Docker 部署 +------------------- + +设置配置文件 +~~~~~~~~~~~~~~~~ + +打开文件 `applications/config.py` 进行编辑,在其中配置数据库等相关信息,默认采用的是 sqlite3 存储项目数据。 + +.. code-block:: python + + # 数据库的配置信息 + SQLALCHEMY_DATABASE_URI = 'sqlite:///../pear.db' + +.. important:: + + 注意!在实际项目中一定要修改 SECRET_KEY 参数!否则存在 Cookie 中的 session 被破解的情况。 + +部署 +~~~~~~~~~~~~~~~~ + +随后确保 docker 环境已经安装,并在控制台中输入(目录要切换到项目根目录): + +.. code-block:: bash + + docker-compose -f dockerdata/docker-compose.yaml up + +.. tip:: + + 你可以在 `dockerdata/docker-compose.yaml` 和 `dockerdata/Dockerfile` 中调整映射的端口,和项目默认开发的端口与行为。 + 容器每次重启会执行 `dockerdata/start.sh` ,故可以在其中配置 Docker 容器的系统。 + + +浏览项目 +------------------ + +| + +.. image:: ../_static/login.png + :align: center + +| + +打开 `http://127.0.0.1:5000` (在未调整端口配置的情况下),可以打开项目的登录页面,默认的用户名与密码分别为 ``admin`` 与 ``123456`` 。 + +.. tip:: + + 旧版的登录页面保留在了 `templates/system/login_old.html` 。 + diff --git a/docs/source/welcome/update.rst b/docs/source/welcome/update.rst new file mode 100644 index 0000000..7ab5799 --- /dev/null +++ b/docs/source/welcome/update.rst @@ -0,0 +1,55 @@ +.. _update: + +更新日志 +================ + +此章节展示更新说明。 + +版本号说明 +---------------------- + +版本号由主版本号、次版本号、修订号和 Pear Admin Layui 版本号组成。 + +2025 年 1 月 26 日(v2.0.0-4.0.5) +------------------------------------ + +.. important:: + + 同步与迁移查看 :ref:`migration1` 章节。 + +* 权限管理(后台框架)增加 组件(_component) 打开方式,根据 Pear Admin Layui ,此方式将会将目标页面作为 div 嵌入框架内部。 +* 权限管理完善批量删除的功能(先前没有实现)。 +* 增加 权限管理、角色管理 等添加、更新路由的参数效验。(先前参数输错会导致程序崩溃) +* 修改增加编辑页面中的 sort(排序) 参数的输入框为数字输入。 +* 修改编辑页面的默认留空文本。将默认的“请输入标题”改为更合理的内容。 +* 修改了权限名称中对于 “权限编辑” 权限的标注错误。 +* 修复没有子部门的公司无法删除的问题 +* 修复操作日志和登录日志接口查询相反和接口匹配错误的问题 +* 系统监控改为异步操作,并完善系统监控的功能 +* 删除字典时会一并删除字典值(特性更新) +* 流程修改,超级管理员也会被记录日志 +* 修复邮件发送设置后台路由错误的问题 +* 后台首页文件修改,system/console/console.html --> system/analysis/main.html +* 验证码生成模块重命名 gen_captcha --> captcha +* 移除文件 system/common/memory.html(此原先仅作用于系统监控) +* 移除前端框架模块 botton.js (pear-btn) ,故前端页面中的 pear-btn 需要替换为 layui-btn ( 直接搜索替换,其附属的 pear-btn- 都要替换* ) +* 保留了前端框架中未使用的模块(在 Pear Admin Layui 已经移除),但是默认不启用,需要自行在 static/system/component/pear/pear.js 和 static/system/component/pear/css/pear.css 添加 +* 加入了程序缓存模块,applications/common/utils/cache.py +* 增加后台消息接口 +* 系统监控中对硬盘的获取,如果是在 docker 中就获取根目录的数据 +* 更正登录之后重定向由于路由更改从而设置错误的问题 + +已知问题以及解决方式 +~~~~~~~~~~~~~~~~~~~~~~~ + +主项目 Pear Admin Layui 存在如下的问题: + +* 对于组件式嵌入页面(_component),存在 JavaScript 无法解绑的问题,由于无法解除 JavaScript 注册,可能会因为不同页面的同标识的按钮绑定到同一个事件。 +* 主项目无法对子页面(iframe)同步更新主题色和修改夜间模式。 +* 主项目无法刷新以 iframe 嵌入的子页面。 + +对此给出的解决方法如下: + +* 仅后台主页和个人资料页面使用组件方式嵌入,其余使用 iframe 嵌入。 +* 在框架中添加 JavaScript 脚本,用于通知所有子 iframe 改变颜色。 +* 修改 admin.js 并提交 PR,等待主项目合并。 \ No newline at end of file -- Gitee From 0db36a621881ae12e8877ba5f9df2c7af8325cca Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Mon, 27 Jan 2025 11:16:26 +0800 Subject: [PATCH 27/36] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E4=B8=8E=E6=9B=B4=E6=96=B0=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/common/admin_log.py | 55 ++-- applications/common/utils/cache.py | 1 - applications/common/utils/captcha.py | 64 +++-- applications/common/utils/http.py | 27 +- applications/common/utils/mail.py | 73 +++-- applications/common/utils/rights.py | 4 +- applications/common/utils/validate.py | 367 ++++++++++++++---------- applications/view/system/mail.py | 18 +- applications/view/system/passport.py | 1 + docs/source/function/utils/cache.rst | 63 +++- docs/source/function/utils/captcha.rst | 114 ++++++++ docs/source/function/utils/http.rst | 39 +++ docs/source/function/utils/index.rst | 8 + docs/source/function/utils/mail.rst | 60 ++++ docs/source/function/utils/rights.rst | 61 ++++ docs/source/function/utils/upload.rst | 34 +++ docs/source/function/utils/validate.rst | 231 +++++++++++++++ 17 files changed, 949 insertions(+), 271 deletions(-) create mode 100644 docs/source/function/utils/captcha.rst create mode 100644 docs/source/function/utils/http.rst create mode 100644 docs/source/function/utils/mail.rst create mode 100644 docs/source/function/utils/rights.rst create mode 100644 docs/source/function/utils/upload.rst create mode 100644 docs/source/function/utils/validate.rst diff --git a/applications/common/admin_log.py b/applications/common/admin_log.py index a75080d..ea1298f 100644 --- a/applications/common/admin_log.py +++ b/applications/common/admin_log.py @@ -5,16 +5,15 @@ from applications.extensions import db from applications.models import AdminLog -def login_log(request, uid, is_access): +def normal_log(method, url, ip, user_agent, desc, uid, is_access): info = { - 'method': request.method, - 'url': request.path, - 'ip': request.remote_addr, - 'user_agent': str_escape(request.headers.get('User-Agent')), - 'desc': str_escape(request.form.get('username')), + 'method': method, + 'url': url, + 'ip': ip, + 'user_agent': user_agent, + 'desc': desc, 'uid': uid, 'success': int(is_access) - } log = AdminLog( url=info.get('url'), @@ -26,33 +25,25 @@ def login_log(request, uid, is_access): success=info.get('success') ) db.session.add(log) - db.session.flush() db.session.commit() return log.id -def admin_log(request, is_access): +def login_log(request, uid, is_access): + method = request.method + url = request.path + ip = request.remote_addr + user_agent = str_escape(request.headers.get('User-Agent')) + desc = str_escape(request.form.get('username')) + return normal_log(method, url, ip, user_agent, desc, uid, is_access) + + +def admin_log(request, is_access, desc=None): + method = request.method + url = request.path + ip = request.remote_addr + user_agent = str_escape(request.headers.get('User-Agent')) request_data = request.json if request.headers.get('Content-Type') == 'application/json' else request.values - info = { - 'method': request.method, - 'url': request.path, - 'ip': request.remote_addr, - 'user_agent': str_escape(request.headers.get('User-Agent')), - 'desc': str_escape(str(dict(request_data))), - 'uid': current_user.id, - 'success': int(is_access) - - } - log = AdminLog( - url=info.get('url'), - ip=info.get('ip'), - user_agent=info.get('user_agent'), - desc=info.get('desc'), - uid=info.get('uid'), - method=info.get('method'), - success=info.get('success') - ) - db.session.add(log) - db.session.commit() - - return log.id + if desc is None: + desc = str_escape(str(dict(request_data))) + return normal_log(method, url, ip, user_agent, desc, current_user.id, is_access) diff --git a/applications/common/utils/cache.py b/applications/common/utils/cache.py index cc130f8..9faf638 100644 --- a/applications/common/utils/cache.py +++ b/applications/common/utils/cache.py @@ -53,4 +53,3 @@ def cache_auto_internal(key, call, expired=5): cache_set_internal(key, data, expired) return data - diff --git a/applications/common/utils/captcha.py b/applications/common/utils/captcha.py index 83145b5..06917b3 100644 --- a/applications/common/utils/captcha.py +++ b/applications/common/utils/captcha.py @@ -7,20 +7,23 @@ class vieCode: __width = 120 # 画布宽度 __heigth = 45 # 画布高度 __length = 4 # 验证码长度 - __draw = None # 画布 - __img = None # 图片资源 + __draw = None # 画布对象 + __img = None # 图片对象 __code = None # 验证码字符 __str = None # 自定义验证码字符集 - __inCurve = True # 是否画干扰线 - __inNoise = True # 是否画干扰点 - __type = 2 # 验证码类型 1、纯字母 2、数字字母混合 - __fontPatn = 'applications/common/utils/fonts/captcha.ttf' # 字体 + __inCurve = True # 是否绘制干扰曲线 + __inNoise = True # 是否绘制干扰点 + __type = 2 # 验证码类型:1-纯字母,2-数字字母混合 + __fontPatn = 'applications/common/utils/fonts/captcha.ttf' # 字体路径 def GetCodeImage(self, size=80, length=4): - '''获取验证码图片 - @param int size 验证码大小 - @param int length 验证码长度 - ''' + """ + 生成验证码图片及其对应的验证码字符。 + + :param size: 验证码字体大小,默认为 80。 + :param length: 验证码字符长度,默认为 4。 + :return: 返回验证码图片对象和验证码字符。 + """ # 准备基础数据 self.__length = length self.__fontSize = size @@ -37,14 +40,18 @@ class vieCode: return self.__img, self.__code def __cerateFilter(self): - '''模糊处理''' + """ + 对验证码图片进行模糊处理,增加识别难度。 + """ self.__img = self.__img.filter(ImageFilter.BLUR) filter = ImageFilter.ModeFilter(8) self.__img = self.__img.filter(filter) def __createCode(self): - '''创建验证码字符''' - # 是否自定义字符集合 + """ + 生成验证码字符。 + """ + # 是否使用自定义字符集 if not self.__str: # 源文本 number = "3456789" @@ -55,32 +62,37 @@ class vieCode: else: self.__str = srcLetter + srcUpper + number - # 构造验证码 + # 随机生成验证码字符 self.__code = random.sample(self.__str, self.__length) def __createImage(self): - '''创建画布''' + """ + 创建画布并设置背景颜色。 + """ bgColor = (random.randint(200, 255), random.randint(200, 255), random.randint(200, 255)) self.__img = Image.new('RGB', (self.__width, self.__heigth), bgColor) self.__draw = ImageDraw.Draw(self.__img) def __createNoise(self): - '''画干扰点''' + """ + 在验证码图片上绘制干扰点。 + """ if not self.__inNoise: return font = ImageFont.truetype(self.__fontPatn, int(self.__fontSize / 1.5)) for i in range(5): - # 杂点颜色 + # 干扰点颜色 noiseColor = (random.randint(150, 200), random.randint(150, 200), random.randint(150, 200)) putStr = random.sample(self.__str, 2) for j in range(2): - # 绘杂点 + # 绘制干扰点 size = (random.randint(-10, self.__width), random.randint(-10, self.__heigth)) self.__draw.text(size, putStr[j], font=font, fill=noiseColor) - pass def __createCurve(self): - '''画干扰线''' + """ + 在验证码图片上绘制干扰曲线。 + """ if not self.__inCurve: return x = y = 0 @@ -93,7 +105,7 @@ class vieCode: xend = random.randint(self.__width / 2, self.__width * 2) w = (2 * math.pi) / t - # 画曲线 + # 绘制曲线 color = (random.randint(30, 150), random.randint(30, 150), random.randint(30, 150)) for x in range(xend): if w != 0: @@ -107,15 +119,17 @@ class vieCode: i -= i def __printString(self): - '''打印验证码字符串''' + """ + 在画布上打印验证码字符。 + """ font = ImageFont.truetype(self.__fontPatn, self.__fontSize) x = 0 - # 打印字符到画板 + # 打印字符到画布 for i in range(self.__length): # 设置字体随机颜色 color = (random.randint(30, 150), random.randint(30, 150), random.randint(30, 150)) - # 计算座标 + # 计算坐标 x = random.uniform(self.__fontSize * i * 0.95, self.__fontSize * i * 1.1) y = self.__fontSize * random.uniform(0.3, 0.5) # 打印字符 - self.__draw.text((x, y), self.__code[i], font=font, fill=color) + self.__draw.text((x, y), self.__code[i], font=font, fill=color) \ No newline at end of file diff --git a/applications/common/utils/http.py b/applications/common/utils/http.py index 680df5f..91a8051 100644 --- a/applications/common/utils/http.py +++ b/applications/common/utils/http.py @@ -2,23 +2,40 @@ from flask import jsonify def success_api(msg: str = "成功"): - """ 成功响应 默认值“成功” """ + """ + 返回成功的 API 响应。 + + :param msg: 成功消息内容,默认为 "成功"。 + :return: 返回 JSON 格式的响应,包含 `success` 和 `msg` 字段。 + """ return jsonify(success=True, msg=msg) def fail_api(msg: str = "失败"): - """ 失败响应 默认值“失败” """ + """ + 返回失败的 API 响应。 + + :param msg: 失败消息内容,默认为 "失败"。 + :return: 返回 JSON 格式的响应,包含 `success` 和 `msg` 字段。 + """ return jsonify(success=False, msg=msg) def table_api(msg: str = "", count=0, data=None, limit=10): - """ 动态表格渲染响应 """ + """ + 返回动态表格渲染所需的 API 响应。 + + :param msg: 响应消息内容,默认为空字符串。 + :param count: 数据总数,默认为 0。 + :param data: 表格数据,默认为 None。 + :param limit: 每页数据条数,默认为 10。 + :return: 返回 JSON 格式的响应,包含 `msg`、`code`、`data`、`count` 和 `limit` 字段。 + """ res = { 'msg': msg, 'code': 0, 'data': data, 'count': count, 'limit': limit - } - return jsonify(res) + return jsonify(res) \ No newline at end of file diff --git a/applications/common/utils/mail.py b/applications/common/utils/mail.py index ecb29bb..b03158e 100644 --- a/applications/common/utils/mail.py +++ b/applications/common/utils/mail.py @@ -1,5 +1,5 @@ """ -集成了对 Pear Admin Flask 二次开发的的邮件操作,并给了相对应的示例。 +集成了对 Pear Admin Flask 二次开发的邮件操作模块,并提供了相应的示例。 """ from flask import current_app from flask_mail import Message @@ -7,32 +7,31 @@ from flask_mail import Message from applications.common.curd import model_to_dicts from applications.common.helper import ModelFilter from applications.extensions import db, flask_mail -from applications.extensions.init_mail import mail from applications.models import Mail from applications.schemas import MailOutSchema def get_all(receiver=None, subject=None, content=None): """ - 获取邮件 + 获取邮件列表,支持根据接收者、主题和内容进行筛选。 - 返回的列表中的字典构造如下:: + 返回的列表中的字典结构如下:: { - "content": "", # html内容 - "create_at": "2022-12-25T10:51:17", # 时间 + "content": "", # HTML 内容 + "create_at": "2022-12-25T10:51:17", # 创建时间 "id": 17, # 邮件ID - "realname": "超级管理", # 创建者 + "realname": "超级管理", # 创建者姓名 "receiver": "", # 接收者 - "subject": "" # 主题 + "subject": "" # 邮件主题 } - :param receiver: 发送者 - :param subject: 邮件标题 - :param content: 邮件内容 - :return: 列表 + :param receiver: 接收者邮箱地址,支持模糊查询。 + :param subject: 邮件主题,支持模糊查询。 + :param content: 邮件内容,支持模糊查询。 + :return: 返回符合条件的邮件列表。 """ - # 查询参数构造 + # 构造查询条件 mf = ModelFilter() if receiver: mf.contains(field_name="receiver", value=receiver) @@ -40,31 +39,27 @@ def get_all(receiver=None, subject=None, content=None): mf.contains(field_name="subject", value=subject) if content: mf.exact(field_name="content", value=content) - # orm查询 - # 使用分页获取data需要.items + + # 查询邮件数据并分页 mail = Mail.query.filter(mf.get_filter(Mail)).layui_paginate() return model_to_dicts(schema=MailOutSchema, data=mail.items) def add(receiver, subject, content, user_id): """ - 发送一封邮件,若发送成功立刻提交数据库。 - - :param receiver: 接收者 多个用英文分号隔开 - :param subject: 邮件主题 - :param content: 邮件 html - :param user_id: 发送用户ID(谁发送的?) 可以用 from flask_login import current_user ; current_user.id 来表示当前登录用户 - :return: 成功与否 + 发送一封邮件,并将发送记录保存到数据库。 **该方法被邮件发送的视图函数调用。** + + :param receiver: 接收者邮箱地址,多个邮箱用英文分号隔开。 + :param subject: 邮件主题。 + :param content: 邮件内容(HTML 格式)。 + :param user_id: 发送者用户ID,表示谁发送了这封邮件。 + 可以使用 `from flask_login import current_user; current_user.id` 获取当前登录用户的ID。 + :return: 发送成功返回 True,失败报错。 """ - try: - msg = Message(subject=subject, recipients=receiver.split(";"), html=content) - flask_mail.send(msg) - except BaseException as e: - current_app.log_exception(e) - return False + send_mail(subject=subject, recipients=receiver.split(";"), content=content) + # 保存邮件记录到数据库 mail = Mail(receiver=receiver, subject=subject, content=content, user_id=user_id) - db.session.add(mail) db.session.commit() return True @@ -72,10 +67,10 @@ def add(receiver, subject, content, user_id): def delete(id): """ - 删除邮件记录,立刻写入数据库。 + 删除指定的邮件记录。 - :param id: 邮件ID - :return: 成功与否 + :param id: 邮件ID。 + :return: 删除成功返回 True,失败返回 False。 """ res = Mail.query.filter_by(id=id).delete() if not res: @@ -83,14 +78,16 @@ def delete(id): db.session.commit() return True + def send_mail(subject, recipients, content): - """原发送邮件函数,不会记录邮件发送记录 + """ + 发送邮件(不记录发送日志)。 - 失败报错,请注意使用 try 拦截。 + 注意:如果发送失败会抛出异常,请使用 try-except 进行捕获。 - :param subject: 主题 - :param recipients: 接收者 多个用英文分号隔开 - :param content: 邮件 html + :param subject: 邮件主题。 + :param recipients: 接收者邮箱地址,多个邮箱用英文分号隔开。 + :param content: 邮件内容(HTML 格式)。 """ message = Message(subject=subject, recipients=recipients, html=content) - mail.send(message) + flask_mail.send(message) diff --git a/applications/common/utils/rights.py b/applications/common/utils/rights.py index 640a129..c498c2f 100644 --- a/applications/common/utils/rights.py +++ b/applications/common/utils/rights.py @@ -5,7 +5,9 @@ from applications.common.admin_log import admin_log def authorize(power: str, log: bool = False): - """用户权限判断,用于判断目前会话用户是否拥有访问权限 + """ + 用户权限判断,用于判断目前会话用户是否拥有访问权限。 + 在模板中有与之对应的全局非修饰函数 authorize ,此函数定义位于 `applications/extensions/init_template_directives.py` 。 :param power: 权限标识 :type power: str diff --git a/applications/common/utils/validate.py b/applications/common/utils/validate.py index 8d90948..086cbd0 100644 --- a/applications/common/utils/validate.py +++ b/applications/common/utils/validate.py @@ -1,187 +1,240 @@ -# xss过滤 +# XSS 过滤 import validators from markupsafe import escape from validators import validator def str_escape(s): + """ + 对字符串进行 XSS 过滤,返回转义后的安全字符串。 + + :param s: 需要转义的字符串。 + :return: 返回转义后的字符串,如果输入为空则返回 None。 + """ if not s: return None return str(escape(s)) -between = validators.between -""" -验证数字是否介于最小值和/或最大值之间。 -这将适用于任何类似的类型,如浮点数、小数和日期,而不仅仅是整数。 -between(value, min=None, max=None) +def between(*args, **kwargs): + """ + 验证数字是否介于最小值和最大值之间。 + 适用于整数、浮点数、小数和日期等类型。 - min-数字的最小必需值。如果未提供,则不会检查最小值。 - max-数字的最大值。如果未提供,将不检查最大值。 + :param value: 需要验证的数字。 + :param min: 数字的最小值(可选)。 + :param max: 数字的最大值(可选)。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 - >>> from datetime import datetime - + 示例: >>> between(5, min=2) True - + >>> between(13.2, min=13, max=14) True - + >>> between(500, max=400) ValidationFailure(func=between, args=...) - - >>> between( - ... datetime(2000, 11, 11), - ... min=datetime(1999, 11, 11) - ... ) - True -""" - -domain = validators.domain -""" -返回给定值是否为有效域 -如果值是有效域名,则此函数返回 True ,否则返回 ValidationFailure -domain(value) - value-要验证的属性域字符串 - + """ + return validators.between(*args, **kwargs) + + +def domain(*args, **kwargs): + """ + 验证给定值是否为有效的域名。 + + :param value: 需要验证的域名字符串。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + 示例: >>> domain('example.com') True - + >>> domain('example.com/') ValidationFailure(func=domain, ...) -""" - -email = validators.email -""" - 验证电子邮件地址。验证成功时返回 True ,验证失败时返回 - - >>> email('someone@example.com') - True - - >>> email('bogus@@') - ValidationFailure(func=email, ...) -""" - -iban = validators.iban -""" -返回给定值是否为有效的IBAN代码。 -如果值是有效的IBAN,则此函数返回 True ,否则返回 ValidationFailure 。 - - >>> iban('DE29100500001061045672') - True - - >>> iban('123456') - ValidationFailure(func=iban, ...) -""" - -ipv4 = validators.ipv4 -""" -返回给定值是否为有效的IPv4地址。 - - >>> ipv4('123.0.0.7') - True - - >>> ipv4('900.80.70.11') - ValidationFailure(func=ipv4, args={'value': '900.80.70.11'}) -""" - -ipv6 = validators.ipv6 -""" -返回给定值是否为有效的IP版本6地址。 - >>> ipv6('abcd:ef::42:1') - True - - >>> ipv6('abc.0.0.1') - ValidationFailure(func=ipv6, args={'value': 'abc.0.0.1'}) -""" - -length = validators.length -""" -返回给定字符串的长度是否在指定范围内。 - >>> length('something', min=2) - True - - >>> length('something', min=9, max=9) - True - - >>> length('something', max=5) - ValidationFailure(func=length, ...) -""" - -mac_address = validators.mac_address -""" -返回给定值是否为有效MAC地址。 -如果该值是有效的MAC地址,则此函数返回 True ,否则返回 ValidationFailure 。 - - >>> mac_address('01:23:45:67:ab:CD') - True - - >>> mac_address('00:00:00:00:00') - ValidationFailure(func=mac_address, args={'value': '00:00:00:00:00'}) -""" - -slug = validators.slug -""" -验证给定值是否为有效的块。 -有效的短信息只能包含字母数字字符、连字符和下划线。 - >>> slug('my.slug') - ValidationFailure(func=slug, args={'value': 'my.slug'}) - - >>> slug('my-slug-2134') - True -""" - -#truthy = validators.truthy -""" -验证给定值不是错误值。 -""" - -url = validators.url -""" -返回给定值是否为有效URL。 -如果值是有效URL,则此函数返回 True ,否则返回 ValidationFailure 。 - - >>> url('http://foobar.dk') - True - - >>> url('http://10.0.0.1') - True - - >>> url('http://foobar.d') - ValidationFailure(func=url, ...) - - >>> url('http://10.0.0.1', public=True) - ValidationFailure(func=url, ...) -""" - -uuid = validators.uuid -""" -返回给定值是否为有效UUID。 -如果值是有效的UUID,则此函数返回 True ,否则返回 ValidationFailure 。 - - >>> uuid('2bc1c94f-0deb-43e9-92a1-4775189ec9f8') - True - - >>> uuid('2bc1c94f 0deb-43e9-92a1-4775189ec9f8') - ValidationFailure(func=uuid, ...) -""" + """ + return validators.domain(*args, **kwargs) + + +def email(*args, **kwargs): + """ + 验证给定值是否为有效的电子邮件地址。 + + :param value: 需要验证的电子邮件地址。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + 示例: + >>> email('someone@example.com') + True + + >>> email('bogus@@') + ValidationFailure(func=email, ...) + """ + return validators.email(*args, **kwargs) + + +def iban(*args, **kwargs): + """ + 验证给定值是否为有效的 IBAN 代码。 + + :param value: 需要验证的 IBAN 代码。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + 示例: + >>> iban('DE29100500001061045672') + True + + >>> iban('123456') + ValidationFailure(func=iban, ...) + """ + return validators.iban(*args, **kwargs) + + +def ipv4(*args, **kwargs): + """ + 验证给定值是否为有效的 IPv4 地址。 + + :param value: 需要验证的 IPv4 地址。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + 示例: + >>> ipv4('123.0.0.7') + True + + >>> ipv4('900.80.70.11') + ValidationFailure(func=ipv4, args={'value': '900.80.70.11'}) + """ + return validators.ipv4(*args, **kwargs) + + +def ipv6(*args, **kwargs): + """ + 验证给定值是否为有效的 IPv6 地址。 + + :param value: 需要验证的 IPv6 地址。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + 示例: + >>> ipv6('abcd:ef::42:1') + True + + >>> ipv6('abc.0.0.1') + ValidationFailure(func=ipv6, args={'value': 'abc.0.0.1'}) + """ + return validators.ipv6(*args, **kwargs) + + +def length(*args, **kwargs): + """ + 验证给定字符串的长度是否在指定范围内。 + + :param value: 需要验证的字符串。 + :param min: 字符串的最小长度(可选)。 + :param max: 字符串的最大长度(可选)。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + 示例: + >>> length('something', min=2) + True + + >>> length('something', min=9, max=9) + True + + >>> length('something', max=5) + ValidationFailure(func=length, ...) + """ + return validators.length(*args, **kwargs) + + +def mac_address(*args, **kwargs): + """ + 验证给定值是否为有效的 MAC 地址。 + + :param value: 需要验证的 MAC 地址。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + 示例: + >>> mac_address('01:23:45:67:ab:CD') + True + + >>> mac_address('00:00:00:00:00') + ValidationFailure(func=mac_address, args={'value': '00:00:00:00:00'}) + """ + return validators.mac_address(*args, **kwargs) + + +def slug(*args, **kwargs): + """ + 验证给定值是否为有效的 Slug 格式。 + 有效的 Slug 只能包含字母数字字符、连字符和下划线。 + + :param value: 需要验证的字符串。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + 示例: + >>> slug('my.slug') + ValidationFailure(func=slug, args={'value': 'my.slug'}) + + >>> slug('my-slug-2134') + True + """ + return validators.slug(*args, **kwargs) + + +def url(*args, **kwargs): + """ + 验证给定值是否为有效的 URL。 + + :param value: 需要验证的 URL。 + :param public: 是否仅允许公共 URL(可选)。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + 示例: + >>> url('http://foobar.dk') + True + + >>> url('http://10.0.0.1') + True + + >>> url('http://foobar.d') + ValidationFailure(func=url, ...) + + >>> url('http://10.0.0.1', public=True) + ValidationFailure(func=url, ...) + """ + return validators.url(*args, **kwargs) + + +def uuid(*args, **kwargs): + """ + 验证给定值是否为有效的 UUID。 + + :param value: 需要验证的 UUID。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + 示例: + >>> uuid('2bc1c94f-0deb-43e9-92a1-4775189ec9f8') + True + + >>> uuid('2bc1c94f 0deb-43e9-92a1-4775189ec9f8') + ValidationFailure(func=uuid, ...) + """ + return validators.uuid(*args, **kwargs) @validator def even(value): - return not (value % 2) + """ + 验证给定值是否为偶数。 + :param value: 需要验证的数字。 + :return: 如果是偶数返回 True,否则返回 ValidationFailure。 -""" -一个装饰器,它使给定的函数验证器 -每当给定函数被调用并返回 False 值时,这个装饰器返回 ValidationFailure 对象。 ->>> @validator -... def even(value): -... return not (value % 2) - ->>> even(4) -True + 示例: + >>> even(4) + True ->>> even(5) -ValidationFailure(func=even, args={'value': 5}) -""" + >>> even(5) + ValidationFailure(func=even, args={'value': 5}) + """ + return not (value % 2) \ No newline at end of file diff --git a/applications/view/system/mail.py b/applications/view/system/mail.py index 01ec31a..51f3f16 100644 --- a/applications/view/system/mail.py +++ b/applications/view/system/mail.py @@ -1,14 +1,16 @@ from flask import Blueprint, render_template, request, current_app from flask_login import current_user -from flask_mail import Message + from applications.common.curd import model_to_dicts from applications.common.helper import ModelFilter from applications.common.utils.http import table_api, fail_api, success_api from applications.common.utils.rights import authorize from applications.common.utils.validate import str_escape -from applications.extensions import db, flask_mail +from applications.extensions import db from applications.models import Mail from applications.schemas import MailOutSchema +from applications.common.utils import mail +from applications.common.admin_log import admin_log bp = Blueprint('adminMail', __name__, url_prefix='/mail') @@ -61,17 +63,13 @@ def save(): user_id = current_user.id try: - msg = Message(subject=subject, recipients=receiver.split(";"), body=content) - flask_mail.send(msg) + if mail.add(receiver=receiver, subject=subject, content=content, user_id=user_id): + return success_api(msg="增加成功") except Exception as e: current_app.log_exception(e) - return fail_api(msg="发送失败,请检查邮件配置或发送人邮箱是否写错") - - mail = Mail(receiver=receiver, subject=subject, content=content, user_id=user_id) + admin_log(request, False, desc="发送日志失败:" + str(e)) - db.session.add(mail) - db.session.commit() - return success_api(msg="增加成功") + return success_api(msg="发送失败,请检查日志。") # 删除用户 diff --git a/applications/view/system/passport.py b/applications/view/system/passport.py index acb21bd..6004981 100644 --- a/applications/view/system/passport.py +++ b/applications/view/system/passport.py @@ -75,6 +75,7 @@ def login_post(): # session['role'] = [roles] return success_api(msg="登录成功") + login_log(request, uid=user.id, is_access=False) return fail_api(msg="用户名或密码错误") diff --git a/docs/source/function/utils/cache.rst b/docs/source/function/utils/cache.rst index 839f6bf..5d6d087 100644 --- a/docs/source/function/utils/cache.rst +++ b/docs/source/function/utils/cache.rst @@ -1,2 +1,61 @@ -程序缓存模块 -===================== \ No newline at end of file +:mod:`cache` -- 应用缓存模块 +================================ + +:mod:`cache` 模块源代码在文件夹 `applications/common/utils/cache.py` 下,主要用于简单的程序数据缓存。 + +目前此模块仅启用应用程序缓存,暂时没有联动 Redis 等数据库缓存的功能,后续有意向添加。您可以在自己的项目中添加相关的函数,当然也非常欢迎提交 PR ,一起完善项目。 + +.. warning:: + + 此模块目前仅用于简单的缓存记录,不能记录大量的、持久的缓存。缓存内容存在内存中,在程序结束后清空!具体的例子是 `系统监控` 页面,用于缓存 5 秒内的 CPU 与内存 + 的监控数据。 + +.. module:: cache + +变量 +----------- + +.. py:data:: cache_dict + + 一个字典,用于存放缓存数据与缓存的过期时间戳。 + +函数 +----------- + +.. function:: cache_set_internal(key, value, expired=5) + + 程序内部实现的记录缓存,用于简单、体量不大的缓存记录,在程序结束后销毁。对于高速、体量大的环境请配置 Redis 等服务自行记录。 + 记录缓存,存储键值对,并记录当前时间作为缓存的时间戳。 + + :param key: 键 + :param value: 值 + :param expired: 过期时间(秒),默认5秒 + +.. function:: cache_get_internal(key) + + 获取缓存,根据键从缓存中获取值,并检查是否过期。 + + :param key: 键 + :return: 如果缓存存在且未过期,返回缓存的值;否则返回 None + +.. function:: cache_auto_internal(key, call, expired=5) + + 如果缓存存在直接返回缓存内容,缓存不存在或者过期执行 call 函数,并取得返回值记录并返回。 + + :param key: 键 + :param call: 获取新值的地方 + :param expired: 过期时间(秒),默认5秒 + + **示例:** + + .. code-block:: python + + from application.common.utils.cache import cache_auto_internal + + def fetch_data(): + # 模拟从数据库或接口获取数据 + return "new_data" + + # 使用 cache_auto_internal 获取缓存或调用 fetch_data 获取新值 + result = cache_auto_internal("my_key", fetch_data, expired=10) + print(result) # 输出: "new_data"(如果缓存不存在或已过期) \ No newline at end of file diff --git a/docs/source/function/utils/captcha.rst b/docs/source/function/utils/captcha.rst new file mode 100644 index 0000000..0838a6d --- /dev/null +++ b/docs/source/function/utils/captcha.rst @@ -0,0 +1,114 @@ +:mod:`captcha` -- 验证码生成模块 +================================== + +:mod:`captcha` 模块源代码在文件夹 `applications/common/utils/captcha.py` 下,主要用于生成验证码图片。 + +.. module:: captcha + +类 +------ + +.. class:: vieCode + + 生成验证码图片。 + + .. py:attribute:: __fontSize + :type: int + + 字体大小,默认为 20。 + + .. py:attribute:: __width + :type: int + + 画布宽度,默认为 120。 + + .. py:attribute:: __heigth + :type: int + + 画布高度,默认为 45。 + + .. py:attribute:: __length + :type: int + + 验证码长度,默认为 4。 + + .. py:attribute:: __draw + :type: ImageDraw.Draw + + 画布对象。 + + .. py:attribute:: __img + :type: Image.Image + + 图片对象。 + + .. py:attribute:: __code + :type: list + + 验证码字符。 + + .. py:attribute:: __str + :type: str + + 自定义验证码字符集。 + + .. py:attribute:: __inCurve + :type: bool + + 是否绘制干扰曲线,默认为 True。 + + .. py:attribute:: __inNoise + :type: bool + + 是否绘制干扰点,默认为 True。 + + .. py:attribute:: __type + :type: int + + 验证码类型:1-纯字母,2-数字字母混合,默认为 2。 + + .. py:attribute:: __fontPatn + :type: str + + 字体路径,默认为 ``applications/common/utils/fonts/captcha.ttf``。 + + .. method:: GetCodeImage(size=80, length=4) + + 生成验证码图片及其对应的验证码字符。 + + :param size: 验证码字体大小,默认为 80。 + :param length: 验证码字符长度,默认为 4。 + :return: 返回验证码图片对象和验证码字符。 + + **示例:** + + .. code-block:: python + + vc = vieCode() + img, code = vc.GetCodeImage(size=60, length=6) + img.show() # 显示验证码图片 + print("验证码:", code) # 输出验证码字符 + + .. method:: __cerateFilter() + + 对验证码图片进行模糊处理,增加识别难度。 + + .. method:: __createCode() + + 生成验证码字符。 + + .. method:: __createImage() + + 创建画布并设置背景颜色。 + + .. method:: __createNoise() + + 在验证码图片上绘制干扰点。 + + .. method:: __createCurve() + + 在验证码图片上绘制干扰曲线。 + + .. method:: __printString() + + 在画布上打印验证码字符。 \ No newline at end of file diff --git a/docs/source/function/utils/http.rst b/docs/source/function/utils/http.rst new file mode 100644 index 0000000..7d89bfc --- /dev/null +++ b/docs/source/function/utils/http.rst @@ -0,0 +1,39 @@ +:mod:`http` -- JSON 响应正文生成模块 +======================================= + +:mod:`http` 模块源代码在文件夹 `applications/common/utils/http.py` 下,主要用于生成 JSON 格式的响应正文。 + +对于大部分 JSON 格式响应的数据,请尽量遵循响应格式规范。如此方便后续前后端的分离和项目的构建。 + +.. module:: http + +函数 +------------ + +.. function:: success_api(msg: str = "成功") + + 返回成功的 API 响应。 + + :param msg: 成功消息内容,默认为 "成功"。 + :return: 返回 JSON 格式的响应,包含 `success` 和 `msg` 字段。 + + +.. function:: fail_api(msg: str = "失败") + + 返回失败的 API 响应。 + + :param msg: 失败消息内容,默认为 "失败"。 + :return: 返回 JSON 格式的响应,包含 `success` 和 `msg` 字段。 + + +.. function:: table_api(msg: str = "", count=0, data=None, limit=10) + + 返回动态表格渲染所需的 API 响应。 + + :param msg: 响应消息内容,默认为空字符串。 + :param count: 数据总数,默认为 0。 + :param data: 表格数据,默认为 None。 + :param limit: 每页数据条数,默认为 10。 + :return: 返回 JSON 格式的响应,包含 `msg`、`code`、`data`、`count` 和 `limit` 字段。 + + diff --git a/docs/source/function/utils/index.rst b/docs/source/function/utils/index.rst index 50c0807..b85744f 100644 --- a/docs/source/function/utils/index.rst +++ b/docs/source/function/utils/index.rst @@ -1,3 +1,5 @@ +.. module:: applications.common.utils + .. title:: 辅助函数 目录索引 @@ -6,3 +8,9 @@ :maxdepth: 1 cache + captcha + http + mail + rights + upload + validate \ No newline at end of file diff --git a/docs/source/function/utils/mail.rst b/docs/source/function/utils/mail.rst new file mode 100644 index 0000000..78a09bd --- /dev/null +++ b/docs/source/function/utils/mail.rst @@ -0,0 +1,60 @@ +:mod:`mail` -- 邮件模块 +================================== + +:mod:`mail` 模块源代码在文件夹 `applications/common/utils/mail.py` 下,主要用于邮件的发送。 + +.. module:: mail + +函数 +--------------- + +.. function:: get_all(receiver=None, subject=None, content=None) + + 获取邮件列表,支持根据接收者、主题和内容进行筛选。 + + 返回的列表中的字典结构如下:: + + { + "content": "", # HTML 内容 + "create_at": "2022-12-25T10:51:17", # 创建时间 + "id": 17, # 邮件ID + "realname": "超级管理", # 创建者姓名 + "receiver": "", # 接收者 + "subject": "" # 邮件主题 + } + + :param receiver: 接收者邮箱地址,支持模糊查询。 + :param subject: 邮件主题,支持模糊查询。 + :param content: 邮件内容,支持模糊查询。 + :return: 返回符合条件的邮件列表。 + + +.. function:: add(receiver, subject, content, user_id) + + 发送一封邮件,并将发送记录保存到数据库。 **该方法被邮件发送的视图函数调用。** + + :param receiver: 接收者邮箱地址,多个邮箱用英文分号隔开。 + :param subject: 邮件主题。 + :param content: 邮件内容(HTML 格式)。 + :param user_id: 发送者用户ID,表示谁发送了这封邮件。 + 可以使用 `from flask_login import current_user; current_user.id` 获取当前登录用户的ID。 + :return: 发送成功返回 True,失败报错。 + + +.. function:: delete(id) + + 删除指定的邮件记录。 + + :param id: 邮件ID。 + :return: 删除成功返回 True,失败返回 False。 + + +.. function:: send_mail(subject, recipients, content) + + 发送邮件(不记录发送日志)。 + + 注意:如果发送失败会抛出异常,请使用 try-except 进行捕获。 + + :param subject: 邮件主题。 + :param recipients: 接收者邮箱地址,多个邮箱用英文分号隔开。 + :param content: 邮件内容(HTML 格式)。 \ No newline at end of file diff --git a/docs/source/function/utils/rights.rst b/docs/source/function/utils/rights.rst new file mode 100644 index 0000000..7dd2019 --- /dev/null +++ b/docs/source/function/utils/rights.rst @@ -0,0 +1,61 @@ +:mod:`rights` -- 权限验证模块 +================================== + +:mod:`rights` 模块源代码在文件夹 `applications/common/utils/rights.py` 下,主要用于权限验证。 + +.. module:: rights + +函数 +--------------- + +.. function:: authorize(power: str, log: bool = False) + + 用户权限判断,用于判断目前会话用户是否拥有访问权限。此函数是一个修饰器,可用于修饰视图函数。 + 在模板中有与之对应的全局非修饰函数 authorize ,此函数定义位于 `applications/extensions/init_template_directives.py` 。 + 示例中将会展示两种方式的用法。 + + :param power: 权限标识 + :type power: str + :param log: 是否记录日志,默认为 False + :type log: bool, optional + + **修饰函数示例:** + + .. code-block:: python + + @app.route("/test") + @authorize("system:power:remove", log=True) + def test_index(): + return 'You are allowed.' + + + **在前端模板中:** + + .. code-block:: html + + {% if authorize("system:user:edit") %} + + {% endif %} + + + .. important:: + + `if authorize("system:user:edit")` 的方式仅适用于 **前端模板渲染** ,不得用于后端代码判断。 + 如果后端想要使用,请使用 **power in session.get('permissions')** 来判断, `power` 是 `权限标识` 。 + + .. code-block:: python + + from flask import session + + ... + + @bp.get('/test') + def test(): + if 'system:user:edit' in session.get('permissions'): + ... + + ... + + diff --git a/docs/source/function/utils/upload.rst b/docs/source/function/utils/upload.rst new file mode 100644 index 0000000..4f3b989 --- /dev/null +++ b/docs/source/function/utils/upload.rst @@ -0,0 +1,34 @@ +:mod:`upload` -- 文件上传模块 +================================== + +:mod:`upload` 模块源代码在文件夹 `applications/common/utils/upload.py` 下,主要用于文件上传,目前主要用于图片上传。 + +.. module:: upload + +函数 +--------------- + +.. function:: get_photo(page, limit) + + 分页获取图片列表,并按创建时间降序排列。 + + :param page: 当前页码。 + :param limit: 每页显示的图片数量。 + :return: 返回图片列表和图片总数。 + + +.. function:: upload_one(photo, mime) + + 上传一张图片,并保存图片信息到数据库。 + + :param photo: 图片文件对象。 + :param mime: 图片的 MIME 类型。 + :return: 返回图片的访问 URL。 + + +.. function:: delete_photo_by_id(_id) + + 根据图片 ID 删除图片及其记录。 + + :param _id: 图片 ID。 + :return: 返回删除操作的结果(数据库中删除的个数,成功非0)。 \ No newline at end of file diff --git a/docs/source/function/utils/validate.rst b/docs/source/function/utils/validate.rst new file mode 100644 index 0000000..6bb62cd --- /dev/null +++ b/docs/source/function/utils/validate.rst @@ -0,0 +1,231 @@ +:mod:`validate` -- 效验模块 +================================== + +:mod:`validate` 模块源代码在文件夹 `applications/common/utils/rights.py` 下,主要用于数据效验与过滤。 + +.. module:: validate + +函数 +------------- + +.. function:: str_escape(s) + + 对字符串进行 XSS 过滤,返回转义后的安全字符串。 + + :param s: 需要转义的字符串。 + :return: 返回转义后的字符串,如果输入为空则返回 None。 + + +.. function:: between(*args, **kwargs) + + 验证数字是否介于最小值和最大值之间。 + 适用于整数、浮点数、小数和日期等类型。 + + :param value: 需要验证的数字。 + :param min: 数字的最小值(可选)。 + :param max: 数字的最大值(可选)。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + **示例:** + + .. code-block:: python + + from applications.common.utils.validate import between + + between(5, min=2) # True + between(13.2, min=13, max=14) # True + between(500, max=400) # ValidationFailure(func=between, args=...) + + +.. function:: domain(*args, **kwargs) + + 验证给定值是否为有效的域名。 + + :param value: 需要验证的域名字符串。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + **示例:** + + .. code-block:: python + + from applications.common.utils.validate import domain + + domain('example.com') # True + domain('example.com/') # ValidationFailure(func=domain, ...) + + +.. function:: email(*args, **kwargs) + + 验证给定值是否为有效的电子邮件地址。 + + :param value: 需要验证的电子邮件地址。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + **示例:** + + .. code-block:: python + + from applications.common.utils.validate import email + + email('someone@example.com') # True + email('bogus@@') # ValidationFailure(func=email, ...) + + +.. function:: iban(*args, **kwargs) + + 验证给定值是否为有效的 IBAN 代码。 + + :param value: 需要验证的 IBAN 代码。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + **示例:** + + .. code-block:: python + + from applications.common.utils.validate import iban + + iban('DE29100500001061045672') # True + iban('123456') # ValidationFailure(func=iban, ...) + + +.. function:: ipv4(*args, **kwargs) + + 验证给定值是否为有效的 IPv4 地址。 + + :param value: 需要验证的 IPv4 地址。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + **示例:** + + .. code-block:: python + + from applications.common.utils.validate import ipv4 + + ipv4('123.0.0.7') # True + ipv4('900.80.70.11') # ValidationFailure(func=ipv4, args={'value': '900.80.70.11'}) + + +.. function:: ipv6(*args, **kwargs) + + 验证给定值是否为有效的 IPv6 地址。 + + :param value: 需要验证的 IPv6 地址。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + **示例:** + + .. code-block:: python + + from applications.common.utils.validate import ipv6 + + ipv6('abcd:ef::42:1') # True + ipv6('abc.0.0.1') # ValidationFailure(func=ipv6, args={'value': 'abc.0.0.1'}) + + +.. function:: length(*args, **kwargs) + + 验证给定字符串的长度是否在指定范围内。 + + :param value: 需要验证的字符串。 + :param min: 字符串的最小长度(可选)。 + :param max: 字符串的最大长度(可选)。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + **示例:** + + .. code-block:: python + + from applications.common.utils.validate import length + + length('something', min=2) # True + length('something', min=9, max=9) # True + length('something', max=5) # ValidationFailure(func=length, ...) + + +.. function:: mac_address(*args, **kwargs) + + 验证给定值是否为有效的 MAC 地址。 + + :param value: 需要验证的 MAC 地址。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + **示例:** + + .. code-block:: python + + from applications.common.utils.validate import mac_address + + mac_address('01:23:45:67:ab:CD') # True + mac_address('00:00:00:00:00') # ValidationFailure(func=mac_address, args={'value': '00:00:00:00:00'}) + + +.. function:: slug(*args, **kwargs) + + 验证给定值是否为有效的 Slug 格式。 + 有效的 Slug 只能包含字母数字字符、连字符和下划线。 + + :param value: 需要验证的字符串。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + **示例:** + + .. code-block:: python + + from applications.common.utils.validate import slug + + slug('my.slug') # ValidationFailure(func=slug, args={'value': 'my.slug'}) + slug('my-slug-2134') # True + + +.. function:: url(*args, **kwargs) + + 验证给定值是否为有效的 URL。 + + :param value: 需要验证的 URL。 + :param public: 是否仅允许公共 URL(可选)。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + **示例:** + + .. code-block:: python + + from applications.common.utils.validate import url + + url('http://foobar.dk') # True + url('http://10.0.0.1') # True + url('http://foobar.d') # ValidationFailure(func=url, ...) + url('http://10.0.0.1', public=True) # ValidationFailure(func=url, ...) + + +.. function:: uuid(*args, **kwargs) + + 验证给定值是否为有效的 UUID。 + + :param value: 需要验证的 UUID。 + :return: 如果验证成功返回 True,否则返回 ValidationFailure。 + + **示例:** + + .. code-block:: python + + from applications.common.utils.validate import uuid + + uuid('2bc1c94f-0deb-43e9-92a1-4775189ec9f8') # True + uuid('2bc1c94f 0deb-43e9-92a1-4775189ec9f8') # ValidationFailure(func=uuid, ...) + + +.. function:: even(value) + + 验证给定值是否为偶数。 + + :param value: 需要验证的数字。 + :return: 如果是偶数返回 True,否则返回 ValidationFailure。 + + **示例:** + + .. code-block:: python + + from applications.common.utils.validate import even + + even(4) # True + even(5) # ValidationFailure(func=even, args={'value': 5}) \ No newline at end of file -- Gitee From 155af93c7782286530e4a13229d969e244c07dd5 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Mon, 27 Jan 2025 11:30:59 +0800 Subject: [PATCH 28/36] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E4=B8=8E=E5=90=88=E5=B9=B6=20admin=5Flog=20?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/common/admin.py | 88 +++++++++++++++++++++++-- applications/common/admin_log.py | 49 -------------- applications/common/utils/rights.py | 2 +- applications/view/system/mail.py | 2 +- applications/view/system/passport.py | 7 +- docs/source/function/admin.rst | 49 ++++++++++++++ docs/source/function/index.rst | 11 ++++ docs/source/function/utils/index.rst | 2 - docs/source/function/utils/validate.rst | 2 +- docs/source/welcome/migration.rst | 15 +++++ docs/source/welcome/update.rst | 2 + 11 files changed, 166 insertions(+), 63 deletions(-) delete mode 100644 applications/common/admin_log.py create mode 100644 docs/source/function/admin.rst diff --git a/applications/common/admin.py b/applications/common/admin.py index 4550d7d..2c1b62d 100644 --- a/applications/common/admin.py +++ b/applications/common/admin.py @@ -1,18 +1,96 @@ from io import BytesIO +from flask import make_response +from flask_login import current_user -from flask import session, make_response - +from applications.common.utils.validate import str_escape from applications.common.utils.captcha import vieCode +from applications.extensions import db +from applications.models import AdminLog -# 生成验证码 def get_captcha(): + """ + 生成验证码图片及其对应的验证码字符串。 + + :return: 返回验证码图片的响应对象和验证码字符串。 + """ image, code = vieCode().GetCodeImage() code = ''.join(code).lower() out = BytesIO() - # session["code"] = code image.save(out, 'png') out.seek(0) resp = make_response(out.read()) resp.content_type = 'image/png' - return resp, code \ No newline at end of file + return resp, code + + +def normal_log(method, url, ip, user_agent, desc, uid, is_access): + """ + 记录通用日志信息到数据库。 + + :param method: 请求方法(如 GET、POST)。 + :param url: 请求的 URL。 + :param ip: 客户端的 IP 地址。 + :param user_agent: 客户端的 User-Agent 信息。 + :param desc: 日志描述信息。 + :param uid: 用户 ID。 + :param is_access: 是否成功访问(True 或 False)。 + :return: 返回日志记录的 ID。 + """ + info = { + 'method': method, + 'url': url, + 'ip': ip, + 'user_agent': user_agent, + 'desc': desc, + 'uid': uid, + 'success': int(is_access) + } + log = AdminLog( + url=info.get('url'), + ip=info.get('ip'), + user_agent=info.get('user_agent'), + desc=info.get('desc'), + uid=info.get('uid'), + method=info.get('method'), + success=info.get('success') + ) + db.session.add(log) + db.session.commit() + return log.id + + +def login_log(request, uid, is_access): + """ + 记录用户登录日志。 + + :param request: Flask 请求对象。 + :param uid: 用户 ID。 + :param is_access: 是否成功登录(True 或 False)。 + :return: 返回日志记录的 ID。 + """ + method = request.method + url = request.path + ip = request.remote_addr + user_agent = str_escape(request.headers.get('User-Agent')) + desc = str_escape(request.form.get('username')) + return normal_log(method, url, ip, user_agent, desc, uid, is_access) + + +def admin_log(request, is_access, desc=None): + """ + 记录管理员操作日志。 + + :param request: Flask 请求对象。 + :param is_access: 是否成功操作(True 或 False)。 + :param desc: 日志描述信息(可选)。如果未提供,则从请求数据中提取。 + :return: 返回日志记录的 ID。 + """ + method = request.method + url = request.path + ip = request.remote_addr + user_agent = str_escape(request.headers.get('User-Agent')) + request_data = request.json if request.headers.get('Content-Type') == 'application/json' else request.values + if desc is None: + desc = str_escape(str(dict(request_data))) + return normal_log(method, url, ip, user_agent, desc, current_user.id, is_access) diff --git a/applications/common/admin_log.py b/applications/common/admin_log.py deleted file mode 100644 index ea1298f..0000000 --- a/applications/common/admin_log.py +++ /dev/null @@ -1,49 +0,0 @@ -from flask_login import current_user - -from applications.common.utils.validate import str_escape -from applications.extensions import db -from applications.models import AdminLog - - -def normal_log(method, url, ip, user_agent, desc, uid, is_access): - info = { - 'method': method, - 'url': url, - 'ip': ip, - 'user_agent': user_agent, - 'desc': desc, - 'uid': uid, - 'success': int(is_access) - } - log = AdminLog( - url=info.get('url'), - ip=info.get('ip'), - user_agent=info.get('user_agent'), - desc=info.get('desc'), - uid=info.get('uid'), - method=info.get('method'), - success=info.get('success') - ) - db.session.add(log) - db.session.commit() - return log.id - - -def login_log(request, uid, is_access): - method = request.method - url = request.path - ip = request.remote_addr - user_agent = str_escape(request.headers.get('User-Agent')) - desc = str_escape(request.form.get('username')) - return normal_log(method, url, ip, user_agent, desc, uid, is_access) - - -def admin_log(request, is_access, desc=None): - method = request.method - url = request.path - ip = request.remote_addr - user_agent = str_escape(request.headers.get('User-Agent')) - request_data = request.json if request.headers.get('Content-Type') == 'application/json' else request.values - if desc is None: - desc = str_escape(str(dict(request_data))) - return normal_log(method, url, ip, user_agent, desc, current_user.id, is_access) diff --git a/applications/common/utils/rights.py b/applications/common/utils/rights.py index c498c2f..bb48725 100644 --- a/applications/common/utils/rights.py +++ b/applications/common/utils/rights.py @@ -1,7 +1,7 @@ from functools import wraps from flask import abort, request, jsonify, session, current_app from flask_login import login_required, current_user -from applications.common.admin_log import admin_log +from applications.common.admin import admin_log def authorize(power: str, log: bool = False): diff --git a/applications/view/system/mail.py b/applications/view/system/mail.py index 51f3f16..17e4fc1 100644 --- a/applications/view/system/mail.py +++ b/applications/view/system/mail.py @@ -10,7 +10,7 @@ from applications.extensions import db from applications.models import Mail from applications.schemas import MailOutSchema from applications.common.utils import mail -from applications.common.admin_log import admin_log +from applications.common.admin import admin_log bp = Blueprint('adminMail', __name__, url_prefix='/mail') diff --git a/applications/view/system/passport.py b/applications/view/system/passport.py index 6004981..3b53d55 100644 --- a/applications/view/system/passport.py +++ b/applications/view/system/passport.py @@ -1,8 +1,7 @@ from flask import Blueprint, session, redirect, url_for, render_template, request from flask_login import current_user, login_user, login_required, logout_user -from applications.common import admin as index_curd -from applications.common.admin_log import login_log +from applications.common.admin import get_captcha, login_log from applications.common.utils.http import fail_api, success_api from applications.models import User @@ -11,8 +10,8 @@ bp = Blueprint('passport', __name__, url_prefix='/passport') # 获取验证码 @bp.get('/getCaptcha') -def get_captcha(): - resp, code = index_curd.get_captcha() +def captcha(): + resp, code = get_captcha() session["code"] = code return resp diff --git a/docs/source/function/admin.rst b/docs/source/function/admin.rst new file mode 100644 index 0000000..b23d1a9 --- /dev/null +++ b/docs/source/function/admin.rst @@ -0,0 +1,49 @@ +:mod:`admin` -- 后台函数模块 +======================================= + +:mod:`admin` 模块源代码在文件夹 `applications/common/admin.py` 下,主要集结了一些常用的后台需要频繁调用的函数。 + +.. module:: admin + +函数 +------------- + +.. function:: get_captcha() + + 生成验证码图片及其对应的验证码字符串。 + + :return: 返回验证码图片的响应对象和验证码字符串。 + + +.. function:: normal_log(method, url, ip, user_agent, desc, uid, is_access) + + 记录通用日志信息到数据库。 + + :param method: 请求方法(如 GET、POST)。 + :param url: 请求的 URL。 + :param ip: 客户端的 IP 地址。 + :param user_agent: 客户端的 User-Agent 信息。 + :param desc: 日志描述信息。 + :param uid: 用户 ID。 + :param is_access: 是否成功访问(True 或 False)。 + :return: 返回日志记录的 ID。 + + +.. function:: login_log(request, uid, is_access) + + 记录用户登录日志。 + + :param request: Flask 请求对象。 + :param uid: 用户 ID。 + :param is_access: 是否成功登录(True 或 False)。 + :return: 返回日志记录的 ID。 + + +.. function:: admin_log(request, is_access, desc=None) + + 记录管理员操作日志。 + + :param request: Flask 请求对象。 + :param is_access: 是否成功操作(True 或 False)。 + :param desc: 日志描述信息(可选)。如果未提供,则从请求数据中提取。 + :return: 返回日志记录的 ID。 \ No newline at end of file diff --git a/docs/source/function/index.rst b/docs/source/function/index.rst index 2031ba7..b567811 100644 --- a/docs/source/function/index.rst +++ b/docs/source/function/index.rst @@ -2,6 +2,17 @@ 目录索引 +公共函数 +------------ + +.. toctree:: + :maxdepth: 1 + + admin + +辅助函数 +------------ + .. toctree:: :maxdepth: 1 diff --git a/docs/source/function/utils/index.rst b/docs/source/function/utils/index.rst index b85744f..17cbaf5 100644 --- a/docs/source/function/utils/index.rst +++ b/docs/source/function/utils/index.rst @@ -1,5 +1,3 @@ -.. module:: applications.common.utils - .. title:: 辅助函数 目录索引 diff --git a/docs/source/function/utils/validate.rst b/docs/source/function/utils/validate.rst index 6bb62cd..b6048bd 100644 --- a/docs/source/function/utils/validate.rst +++ b/docs/source/function/utils/validate.rst @@ -1,7 +1,7 @@ :mod:`validate` -- 效验模块 ================================== -:mod:`validate` 模块源代码在文件夹 `applications/common/utils/rights.py` 下,主要用于数据效验与过滤。 +:mod:`validate` 模块源代码在文件夹 `applications/common/utils/validate.py` 下,主要用于数据效验与过滤。 .. module:: validate diff --git a/docs/source/welcome/migration.rst b/docs/source/welcome/migration.rst index 0d9f0c2..2481b9d 100644 --- a/docs/source/welcome/migration.rst +++ b/docs/source/welcome/migration.rst @@ -94,5 +94,20 @@ 你会注意到修改之后的 layui-btn-primary 属性添加在了 “重置” 按钮上,而不是 “查询” 按钮上, 这是因为 layui-btn-primary 是默认白色的,而不加 layui-btn-primary 属性是跟随主题色的。这里需要特别注意一下。 +合并日志模块 +~~~~~~~~~~~~~~~~~~~~ +为了减少冗余,将 applications/common/admin_log.py 与 applications/common/admin.py 合并,仅留下 applications/common/admin.py 。 + +例如: + +.. code-block:: python + + from applications.common.admin_log import admin_log + +改为: + +.. code-block:: python + + from applications.common.admin import admin_log \ No newline at end of file diff --git a/docs/source/welcome/update.rst b/docs/source/welcome/update.rst index 7ab5799..039c1ee 100644 --- a/docs/source/welcome/update.rst +++ b/docs/source/welcome/update.rst @@ -38,6 +38,8 @@ * 增加后台消息接口 * 系统监控中对硬盘的获取,如果是在 docker 中就获取根目录的数据 * 更正登录之后重定向由于路由更改从而设置错误的问题 +* 将 applications/common/admin_log.py 与 applications/common/admin.py 合并,仅留下 applications/common/admin.py +* 优化代码结构,新增函数 `normal_log` 减少代码复用 已知问题以及解决方式 ~~~~~~~~~~~~~~~~~~~~~~~ -- Gitee From 5153daf7da8ca6e5b939aa07cd503105e366e6d3 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Mon, 27 Jan 2025 19:48:27 +0800 Subject: [PATCH 29/36] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +- applications/common/curd.py | 87 ++++-- applications/common/helper.py | 101 ++++--- applications/extensions/init_sqlalchemy.py | 10 +- docs/function.md | 279 ------------------ docs/model.md | 50 ---- docs/plugin.md | 47 --- docs/{assets => source/_static}/1.jpg | Bin docs/{assets => source/_static}/2.jpg | Bin docs/{assets => source/_static}/3.jpg | Bin docs/{assets => source/_static}/4.jpg | Bin docs/{assets => source/_static}/5.jpg | Bin docs/{assets => source/_static}/6.jpg | Bin docs/source/_static/helloworld.png | Bin 0 -> 23768 bytes docs/source/_static/plugin_run.png | Bin 0 -> 11529 bytes docs/{assets => source/_static}/qqgroup.jpg | Bin ...0\347\275\221\345\234\260\345\235\200.jpg" | Bin ...0\347\240\201\344\273\223\345\272\223.jpg" | Bin ...\351\235\242\346\274\224\347\244\272.jpeg" | Bin docs/source/function/admin.rst | 28 +- docs/source/function/curd.rst | 90 ++++++ docs/source/function/helper.rst | 121 ++++++++ docs/source/function/index.rst | 2 + docs/source/function/utils/cache.rst | 2 +- docs/source/function/utils/captcha.rst | 2 +- docs/source/function/utils/http.rst | 22 +- docs/source/function/utils/index.rst | 2 +- docs/source/function/utils/mail.rst | 27 +- docs/source/function/utils/rights.rst | 6 +- docs/source/function/utils/upload.rst | 2 +- docs/source/function/utils/validate.rst | 2 +- docs/source/index.rst | 6 + docs/source/practices/index.rst | 9 + docs/source/practices/plugin.rst | 129 ++++++++ docs/source/practices/trick.rst | 199 +++++++++++++ plugins/helloworld/__init__.py | 3 +- plugins/helloworld/main.py | 8 +- plugins/realip/__init__.py | 27 +- plugins/realip/console.py | 89 ------ 39 files changed, 766 insertions(+), 592 deletions(-) delete mode 100644 docs/function.md delete mode 100644 docs/model.md delete mode 100644 docs/plugin.md rename docs/{assets => source/_static}/1.jpg (100%) rename docs/{assets => source/_static}/2.jpg (100%) rename docs/{assets => source/_static}/3.jpg (100%) rename docs/{assets => source/_static}/4.jpg (100%) rename docs/{assets => source/_static}/5.jpg (100%) rename docs/{assets => source/_static}/6.jpg (100%) create mode 100644 docs/source/_static/helloworld.png create mode 100644 docs/source/_static/plugin_run.png rename docs/{assets => source/_static}/qqgroup.jpg (100%) rename "docs/assets/\345\256\230\347\275\221\345\234\260\345\235\200.jpg" => "docs/source/_static/\345\256\230\347\275\221\345\234\260\345\235\200.jpg" (100%) rename "docs/assets/\346\272\220\347\240\201\344\273\223\345\272\223.jpg" => "docs/source/_static/\346\272\220\347\240\201\344\273\223\345\272\223.jpg" (100%) rename "docs/assets/\347\225\214\351\235\242\346\274\224\347\244\272.jpeg" => "docs/source/_static/\347\225\214\351\235\242\346\274\224\347\244\272.jpeg" (100%) create mode 100644 docs/source/function/curd.rst create mode 100644 docs/source/function/helper.rst create mode 100644 docs/source/practices/index.rst create mode 100644 docs/source/practices/plugin.rst create mode 100644 docs/source/practices/trick.rst delete mode 100644 plugins/realip/console.py diff --git a/README.md b/README.md index 9b3953c..79e85b7 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ 开 箱 即 用 的 Flask 快 速 开 发 平 台 - [预览](https://pear.lovepikachu.top/) | [官网](http://www.pearadmin.com/) | [群聊](docs/assets/qqgroup.jpg) | [文档](docs/detail.md) + [预览](https://pear.lovepikachu.top/) | [官网](http://www.pearadmin.com/) | [群聊](docs/source/_static/qqgroup.jpg) | [文档](docs/detail.md)

                @@ -221,9 +221,9 @@ docker-compose -f dockercompose.yaml down | | | | ---------------------- | ---------------------- | -| ![](docs/assets/1.jpg) | ![](docs/assets/2.jpg) | -| ![](docs/assets/3.jpg) | ![](docs/assets/4.jpg) | -| ![](docs/assets/5.jpg) | ![](docs/assets/6.jpg) | +| ![](docs/source/_static/1.jpg) | ![](docs/source/_static/2.jpg) | +| ![](docs/source/_static/3.jpg) | ![](docs/assets/4.jpg) | +| ![](ddocs/source/_static/5.jpg) | ![](docs/source/_static/6.jpg) | # 其他说明 diff --git a/applications/common/curd.py b/applications/common/curd.py index 9a4f16c..95a8909 100644 --- a/applications/common/curd.py +++ b/applications/common/curd.py @@ -1,31 +1,39 @@ import datetime - from marshmallow import Schema from marshmallow_sqlalchemy import SQLAlchemyAutoSchema - from applications.extensions import db, ma class LogicalDeleteMixin(object): """ - class Test(db.Model,LogicalDeleteMixin): - __tablename__ = 'admin_test' - id = db.Column(db.Integer, primary_key=True, comment='角色ID') + 逻辑删除混入类,为模型提供软删除功能。 + + 示例: + class Test(db.Model, LogicalDeleteMixin): + __tablename__ = 'admin_test' + id = db.Column(db.Integer, primary_key=True, comment='角色ID') - Test.query.filter_by(id=1).soft_delete() - Test.query.logic_all() + # 软删除 + Test.query.filter_by(id=1).soft_delete() + + # 查询所有未删除的记录 + Test.query.logic_all() """ create_at = db.Column(db.DateTime, default=datetime.datetime.now, comment='创建时间') - update_at = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment='创建时间') + update_at = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment='更新时间') delete_at = db.Column(db.DateTime, comment='删除时间') def auto_model_jsonify(data, model: db.Model): """ - 不需要建立schemas,直接使用orm的定义模型进行序列化 - 基本功能,待完善 - 示例 - power_data = curd.auto_model_jsonify(model=Dept, data=dept) + 自动序列化模型数据为 JSON 格式,无需手动定义 Schema。 + + 示例: + power_data = curd.auto_model_jsonify(model=Dept, data=dept) + + :param data: 需要序列化的 SQLAlchemy 查询结果。 + :param model: SQLAlchemy 模型类。 + :return: 返回序列化后的 JSON 数据。 """ def get_model(): return model @@ -33,49 +41,60 @@ def auto_model_jsonify(data, model: db.Model): class AutoSchema(SQLAlchemyAutoSchema): class Meta(Schema): model = get_model() - include_fk = True - include_relationships = True - load_instance = True + include_fk = True # 包含外键 + include_relationships = True # 包含关联关系 + load_instance = True # 反序列化时加载为模型实例 - common_schema = AutoSchema(many=True) # 用已继承ma.ModelSchema类的自定制类生成序列化类 + common_schema = AutoSchema(many=True) # 支持序列化多个对象 output = common_schema.dump(data) return output def model_to_dicts(schema: ma.Schema, data): """ - :param schema: schema类 - :param model: sqlalchemy查询结果 - :return: 返回单个查询结果 + 使用指定的 Schema 序列化 SQLAlchemy 查询结果。 + + :param schema: Marshmallow Schema 类。 + :param data: SQLAlchemy 查询结果。 + :return: 返回序列化后的数据,返回字典。 """ - # 如果是分页器返回,需要传入model.items - common_schema = schema(many=True) # 用已继承ma.ModelSchema类的自定制类生成序列化类 - output = common_schema.dump(data) # 生成可序列化对象 + common_schema = schema(many=True) # 支持序列化多个对象 + output = common_schema.dump(data) return output def get_one_by_id(model: db.Model, id): """ - :param model: 模型类 - :param id: id - :return: 返回单个查询结果 + 根据 ID 查询单个记录。 + + :param model: SQLAlchemy 模型类。 + :param id: 记录的主键 ID。 + :return: 返回查询到的记录,如果未找到则返回 None。 """ return model.query.filter_by(id=id).first() def delete_one_by_id(model: db.Model, id): """ - :param model: 模型类 - :param id: id - :return: 返回单个查询结果 + 根据 ID 删除单个记录。 + + :param model: SQLAlchemy 模型类。 + :param id: 记录的主键 ID。 + :return: 返回删除操作影响的行数。 """ r = model.query.filter_by(id=id).delete() db.session.commit() return r -# 启动状态 def enable_status(model: db.Model, id): + """ + 启用指定 ID 的记录。 + + :param model: SQLAlchemy 模型类。 + :param id: 记录的主键 ID。 + :return: 如果操作成功返回 True,否则返回 False。 + """ enable = 1 role = model.query.filter_by(id=id).update({"enable": enable}) if role: @@ -84,11 +103,17 @@ def enable_status(model: db.Model, id): return False -# 停用状态 def disable_status(model: db.Model, id): + """ + 停用指定 ID 的记录。 + + :param model: SQLAlchemy 模型类。 + :param id: 记录的主键 ID。 + :return: 如果操作成功返回 True,否则返回 False。 + """ enable = 0 role = model.query.filter_by(id=id).update({"enable": enable}) if role: db.session.commit() return True - return False + return False \ No newline at end of file diff --git a/applications/common/helper.py b/applications/common/helper.py index da69071..6b82cb8 100644 --- a/applications/common/helper.py +++ b/applications/common/helper.py @@ -1,112 +1,131 @@ from sqlalchemy import and_ - from applications.extensions import db class ModelFilter: """ - orm多参数构造器 + ORM 多条件查询构造器,支持多种查询条件组合。 + + 示例: + mf = ModelFilter() + mf.exact('name', 'John') + mf.vague('email', 'example.com') + query = User.query.filter(mf.get_filter(User)) """ - filter_field = {} - filter_list = [] + filter_field = {} # 存储字段过滤条件 + filter_list = [] # 存储最终的过滤条件列表 - type_exact = "exact" - type_neq = "neq" - type_greater = "greater" - type_less = "less" - type_vague = "vague" - type_contains = "contains" - type_between = "between" + # 查询类型常量 + type_exact = "exact" # 精确匹配 + type_neq = "neq" # 不等于 + type_greater = "greater" # 大于 + type_less = "less" # 小于 + type_vague = "vague" # 模糊匹配 + type_contains = "contains" # 包含 + type_between = "between" # 范围查询 def __init__(self): + """初始化过滤条件存储字典和列表。""" self.filter_field = {} self.filter_list = [] def exact(self, field_name, value): """ - 准确查询字段 - :param field_name: 模型字段名称 - :param value: 值 + 添加精确匹配条件。 + + :param field_name: 模型字段名称。 + :param value: 匹配的值。 """ if value and value != '': self.filter_field[field_name] = {"data": value, "type": self.type_exact} def neq(self, field_name, value): """ - 不等于查询字段 - :param field_name: 模型字段名称 - :param value: 值 + 添加不等于条件。 + + :param field_name: 模型字段名称。 + :param value: 不匹配的值。 """ if value and value != '': self.filter_field[field_name] = {"data": value, "type": self.type_neq} def greater(self, field_name, value): """ - 大于查询字段 - :param field_name: 模型字段名称 - :param value: 值 + 添加大于条件。 + + :param field_name: 模型字段名称。 + :param value: 大于的值。 """ if value and value != '': self.filter_field[field_name] = {"data": value, "type": self.type_greater} def less(self, field_name, value): """ - 小于查询字段 - :param field_name: 模型字段名称 - :param value: 值 + 添加小于条件。 + + :param field_name: 模型字段名称。 + :param value: 小于的值。 """ if value and value != '': self.filter_field[field_name] = {"data": value, "type": self.type_less} def vague(self, field_name, value: str): """ - 模糊查询字段 - :param field_name: 模型字段名称 - :param value: 值 + 添加模糊匹配条件(左右模糊)。 + + :param field_name: 模型字段名称。 + :param value: 模糊匹配的值。 """ if value and value != '': self.filter_field[field_name] = {"data": ('%' + value + '%'), "type": self.type_vague} def left_vague(self, field_name, value: str): """ - 左模糊查询字段 - :param field_name: 模型字段名称 - :param value: 值 + 添加左模糊匹配条件。 + + :param field_name: 模型字段名称。 + :param value: 左模糊匹配的值。 """ if value and value != '': self.filter_field[field_name] = {"data": ('%' + value), "type": self.type_vague} def right_vague(self, field_name, value: str): """ - 左模糊查询字段 - :param field_name: 模型字段名称 - :param value: 值 + 添加右模糊匹配条件。 + + :param field_name: 模型字段名称。 + :param value: 右模糊匹配的值。 """ if value and value != '': self.filter_field[field_name] = {"data": (value + '%'), "type": self.type_vague} def contains(self, field_name, value: str): """ - 包含查询字段 - :param field_name: 模型字段名称 - :param value: 值 + 添加包含条件。 + + :param field_name: 模型字段名称。 + :param value: 包含的值。 """ if value and value != '': self.filter_field[field_name] = {"data": value, "type": self.type_contains} def between(self, field_name, value1, value2): """ - 范围查询字段 - :param field_name: 模型字段名称 - :param value: 值 + 添加范围查询条件。 + + :param field_name: 模型字段名称。 + :param value1: 范围起始值。 + :param value2: 范围结束值。 """ if value1 and value2 and value1 != '' and value2 != '': self.filter_field[field_name] = {"data": [value1, value2], "type": self.type_between} def get_filter(self, model: db.Model): """ - 获取过滤条件 - :param model: 模型字段名称 + 获取最终的 SQLAlchemy 过滤条件。 + + :param model: SQLAlchemy 模型类。 + :return: 返回组合后的过滤条件。 """ for k, v in self.filter_field.items(): if v.get("type") == self.type_vague: @@ -123,4 +142,4 @@ class ModelFilter: self.filter_list.append(getattr(model, k) < v.get("data")) if v.get("type") == self.type_between: self.filter_list.append(getattr(model, k).between(v.get("data")[0], v.get("data")[1])) - return and_(*self.filter_list) + return and_(*self.filter_list) \ No newline at end of file diff --git a/applications/extensions/init_sqlalchemy.py b/applications/extensions/init_sqlalchemy.py index d128c22..729ce6e 100644 --- a/applications/extensions/init_sqlalchemy.py +++ b/applications/extensions/init_sqlalchemy.py @@ -60,9 +60,13 @@ class Query(BaseQuery): def all_json(self, schema: Marshmallow().Schema): return schema(many=True).dump(self.all()) - def layui_paginate(self): - return self.paginate(page=request.args.get('page', type=int), - per_page=request.args.get('limit', type=int), + def layui_paginate(self, page=None, limit=None): + if page is None: + page = request.args.get('page', type=int) + if limit is None: + limit = request.args.get('limit', type=int) + return self.paginate(page=page, + per_page=limit, error_out=False) def layui_paginate_json(self, schema: Marshmallow().Schema): diff --git a/docs/function.md b/docs/function.md deleted file mode 100644 index f419276..0000000 --- a/docs/function.md +++ /dev/null @@ -1,279 +0,0 @@ -## 用户权限判断 - -Pear Admin Flask 项目中集成很多实用的功能,为了便于二次开发,同样也提供了许多便于开发的自定义函数。 - -Pear Admin Flask 项目支持多用户,不同用户有不同的权限,此处将介绍 Pear Admin Flask 中的权限管理函数的用法。 - -### 函数原型 - -函数调用位于项目代码 ```applications/common/utils/rights.py``` 中,函数原型如下: - -```python -def authorize(power: str, log: bool = False): - """ - 用户权限判断,用于判断目前会话用户是否拥有访问权限 - - :param power: 权限标识 - :type power: str - :param log: 是否记录日志, defaults to False - :type log: bool, optional - """ - ... -``` - -### 基本用法 - -+ 后端用法 - -```python -from applications.common.utils.rights import authorize - -@app.route("/test") -@authorize("system:power:remove", log=True) -def test_index(): - return 'You are allowed.' -``` - -> 使用装饰器 @authorize时需要注意,该装饰器需要写在 @app.route之后 - -+ 前端用法 - -在前端中,例如增加,删除按钮,对于没有编辑权限的用户不显示的话,可以使用 - - `{% **if** authorize("admin:user:edit") %}` - - `{% endif %}` - -例如 - -```python - {% if authorize("system:user:edit") %} - - {% endif %} - {% if authorize("system:user:remove") %} - - {% endif %} -``` - -## Schema 序列化 - -项目中时常会涉及到数据库的读写,在读入数据时可以采用SQLalchemy,将模型查询的数据对象转化为字典。 - -> Schema 是序列化类,我们把他放在了models文件里,因为觉得没有必要新建一个文件夹叫 Schema ,也方便看着模型写序列化类。 - -```python -# 例如 -class DeptSchema(ma.Schema): # 序列化类 - deptId = fields.Integer(attribute="id") - parentId = fields.Integer(attribute="parent_id") - deptName = fields.Str(attribute="dept_name") - leader = fields.Str() - phone = fields.Str() - email = fields.Str() - address = fields.Str() - status = fields.Str() - sort = fields.Str() -``` - -> 这一部分有问题的话请看 marshmallow 文档 - -### 模型到字典 - -#### 函数原型 - -函数调用位于项目代码 ```applications/common/curd.py``` 中,函数原型如下: - -``` -def model_to_dicts(schema: ma.Schema, data): - """ - 将模型查询的数据对象转化为字典 - - :param schema: schema类 - :param model: sqlalchemy查询结果 - :return: 返回单个查询结果 - """ - ... -``` - -#### 基本用法 - -+ model写的是查询后的对象 - -```python -from applications.common import curd -from applications.models import Dept -from applications.schemas import DeptOutSchema - -def test(): # 某函数内 - dept = Dept.query.order_by(Dept.sort).all() - res = curd.model_to_dicts(Schema=DeptOutSchema, model=dept) -``` - -## 查询多字段构造器 - -```python -# 准确查询字段 -# 不等于查询字段 -# 大于查询字段 -# 小于查询字段 -# 模糊查询字段(%+xxx+%) -# 左模糊 (% + xxx) -# 右模糊查询字段(xxx+ %) -# 包含查询字段 -# 范围查询字段 -# 查询 -``` - -## xss过滤 - -### 函数原型 - -函数调用位于项目代码 ```applications/common/utils/validate.py``` 中,函数原型如下: - -``` -def str_escape(s: str) -> str: - """ - xss过滤,内部采用flask自带的过滤函数。 - 与原过滤函数不同的是此过滤函数将在 s 为 None 时返回 None。 - - :param s: 要过滤的字符串 - :type s: str - :return: s 为 None 时返回 None,否则过滤字符串后返回。 - :rtype: str - """ - ... -``` - -### 使用方法 - -```python -from applications.common.utils.validate import str_escape -real_name = xss_escape(request.args.get('realName', type=str)) -``` - - -## 邮件发送 - -+ 原邮件发送函数 - -### 函数原型 - -函数调用位于项目代码 ```applications/common/utils/mail.py``` 中,函数原型如下: - -``` -def send_mail(subject, recipients, content): - """原发送邮件函数,不会记录邮件发送记录 - - 失败报错,请注意使用 try 拦截。 - - :param subject: 主题 - :param recipients: 接收者 多个用英文分号隔开 - :param content: 邮件 html - """ - ... -``` - -### 示例代码 - -```python -#在.flaskenv中配置邮箱 -from applications.common.utils import mail - -mail.send_mail("subject", "test@test.com", "

                Hello

                ") -``` - -+ 基于二次开发的邮件发送函数 - -### 函数原型 - -函数调用位于项目代码 ```applications/common/utils/mail.py``` 中,函数原型如下: - -``` -def add(receiver, subject, content, user_id): - """ - 发送一封邮件,若发送成功立刻提交数据库。 - - :param receiver: 接收者 多个用英文逗号隔开 - :param subject: 邮件主题 - :param content: 邮件 html - :param user_id: 发送用户ID(谁发送的?) 可以用 from flask_login import current_user ; current_user.id 来表示当前登录用户 - :return: 成功与否 - """ - ... -``` - -### 示例代码 - -```python -#在.flaskenv中配置邮箱 -from applications.common.utils import mail - -mail.add("test@test.com", "subject", "

                Hello

                ", current_user) -``` - - - -## 返回格式 - -> 后端响应时我们推荐使用规定的API响应格式。 - -### 函数原型 - -函数调用位于项目代码 ```applications/common/utils/http.py``` 中,函数原型如下: - -``` -def success_api(msg: str = "成功"): - """ 成功响应 默认值“成功” """ - return jsonify(success=True, msg=msg) - - -def fail_api(msg: str = "失败"): - """ 失败响应 默认值“失败” """ - return jsonify(success=False, msg=msg) - - -def table_api(msg: str = "", count=0, data=None, limit=10): - """ 动态表格渲染响应 """ - res = { - 'msg': msg, - 'code': 0, - 'data': data, - 'count': count, - 'limit': limit - - } - return jsonify(res) -``` - -### 示例代码 - -```python -from applications.common.utils.http import success_api, fail_api, table_api - -@admin_log.get('/operateLog') -@authorize("system:log:main") -def operate_log(): - # orm查询 - # 使用分页获取data需要.items - log = AdminLog.query.filter( - AdminLog.url != '/passport/login').order_by( - desc(AdminLog.create_time)).layui_paginate() - count = log.total - return table_api(data=model_to_dicts(schema=LogOutSchema, data=log.items), count=count) -``` - -```python -from applications.common.utils.http import success_api, fail_api, table_api - -@admin_power.post('/save') -@authorize("system:power:add", log=True) -def save(): - ... # 若干操作 - if success: - return success_api(msg="成功") - return fail_api(msg="成功") -``` diff --git a/docs/model.md b/docs/model.md deleted file mode 100644 index 52bf177..0000000 --- a/docs/model.md +++ /dev/null @@ -1,50 +0,0 @@ -## 模型/数据库和序列化 -### 数据库连接 - -项目采用flask-sqlalchemy,支持多数据库连接,默认sqlite - -HOSTNAME: 指数据库的IP地址 -USERNAME:指数据库登录的用户名 -PASSWORD:指数据库登录密码 -PORT:指数据库开放的端口 -DATABASE:指需要连接的数据库名称 -#### mssql -``` -MSSQL: f"mssql+pymssql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=cp936" -``` -#### msyql -``` -$ pip install pymysql - -# 手动在mysql中创建数据库,并将配置文件中的url配置如下示例 - -SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4" -``` -#### Oracle -``` -Oracle: f"oracle+cx_oracle://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}" -``` -#### SQLite -``` -SQLite "sqlite:/// database.db" -``` -#### Postgres -``` -Postgres f"postgresql+psycopg2://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}" -``` - - -### 序列化 - -推荐使用这种自动类型的 -```python -from flask_marshmallow.sqla import SQLAlchemyAutoSchema -from applications.models import 你的模型类 -class RoleOutSchema(SQLAlchemyAutoSchema): - class Meta: - model = 你的模型类 # table = models.Album.__table__ - # include_relationships = True # 输出模型对象时同时对外键,是否也一并进行处理 - include_fk = True # 序列化阶段是否也一并返回主键 - # fields= ["id","name"] # 启动的字段列表 - # exclude = ["id","name"] # 排除字段列表 -``` diff --git a/docs/plugin.md b/docs/plugin.md deleted file mode 100644 index 9ccb1d4..0000000 --- a/docs/plugin.md +++ /dev/null @@ -1,47 +0,0 @@ -### 说明 - -插件功能旨在最大限度不修改原框架的前提下添加新功能,我们提供了三个示例插件。 - - -### 插件配置 - -将插件文件夹放置在 ```applications/config.py``` 文件夹中,并且在 .flaskenv 中配置。再配置项中填入插件的文件夹名,已 json 格式写入其中。 - -```python -# 插件配置 -PLUGIN_ENABLE_FOLDERS = ["helloworld"] -``` - -### 插件目录 - -``` -Plugin -│ __init__.json -└─ __init__.py -``` - -这是一个非常简单的插件。 - -### 插件信息 - -插件信息保存在 ```__init__.py``` 中,以测试插件“helloword”为例。插件的数据应该不少于下面三项: - -```json -{ - "plugin_name": "Hello World", - "plugin_version": "1.0.0.1", - "plugin_description": "一个测试的插件。" -} -``` - -### 插件格式 - -插件的入口点为 ```__init__.py``` 文件,在插件被启用后,程序启动时此 Python 文件中的 ```event_init``` 函数。代码如下: - -```python -from flask import Flask - -def event_init(app: Flask): - """初始化完成时会调用这里""" - print("加载完毕后,我会输出一句话。") -``` \ No newline at end of file diff --git a/docs/assets/1.jpg b/docs/source/_static/1.jpg similarity index 100% rename from docs/assets/1.jpg rename to docs/source/_static/1.jpg diff --git a/docs/assets/2.jpg b/docs/source/_static/2.jpg similarity index 100% rename from docs/assets/2.jpg rename to docs/source/_static/2.jpg diff --git a/docs/assets/3.jpg b/docs/source/_static/3.jpg similarity index 100% rename from docs/assets/3.jpg rename to docs/source/_static/3.jpg diff --git a/docs/assets/4.jpg b/docs/source/_static/4.jpg similarity index 100% rename from docs/assets/4.jpg rename to docs/source/_static/4.jpg diff --git a/docs/assets/5.jpg b/docs/source/_static/5.jpg similarity index 100% rename from docs/assets/5.jpg rename to docs/source/_static/5.jpg diff --git a/docs/assets/6.jpg b/docs/source/_static/6.jpg similarity index 100% rename from docs/assets/6.jpg rename to docs/source/_static/6.jpg diff --git a/docs/source/_static/helloworld.png b/docs/source/_static/helloworld.png new file mode 100644 index 0000000000000000000000000000000000000000..d9e6805581f8af7c03ac73fecb93a29ebf81df19 GIT binary patch literal 23768 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 Zx+xXq6`1x)w$Ir6?&F2=tUGb~#y@QS$s_;( literal 0 HcmV?d00001 diff --git a/docs/source/_static/plugin_run.png b/docs/source/_static/plugin_run.png new file mode 100644 index 0000000000000000000000000000000000000000..20bfca072ae60ee9c5687d2d070f5e37c6845215 GIT binary patch literal 11529 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 EKQ=HudjJ3c literal 0 HcmV?d00001 diff --git a/docs/assets/qqgroup.jpg b/docs/source/_static/qqgroup.jpg similarity index 100% rename from docs/assets/qqgroup.jpg rename to docs/source/_static/qqgroup.jpg diff --git "a/docs/assets/\345\256\230\347\275\221\345\234\260\345\235\200.jpg" "b/docs/source/_static/\345\256\230\347\275\221\345\234\260\345\235\200.jpg" similarity index 100% rename from "docs/assets/\345\256\230\347\275\221\345\234\260\345\235\200.jpg" rename to "docs/source/_static/\345\256\230\347\275\221\345\234\260\345\235\200.jpg" diff --git "a/docs/assets/\346\272\220\347\240\201\344\273\223\345\272\223.jpg" "b/docs/source/_static/\346\272\220\347\240\201\344\273\223\345\272\223.jpg" similarity index 100% rename from "docs/assets/\346\272\220\347\240\201\344\273\223\345\272\223.jpg" rename to "docs/source/_static/\346\272\220\347\240\201\344\273\223\345\272\223.jpg" diff --git "a/docs/assets/\347\225\214\351\235\242\346\274\224\347\244\272.jpeg" "b/docs/source/_static/\347\225\214\351\235\242\346\274\224\347\244\272.jpeg" similarity index 100% rename from "docs/assets/\347\225\214\351\235\242\346\274\224\347\244\272.jpeg" rename to "docs/source/_static/\347\225\214\351\235\242\346\274\224\347\244\272.jpeg" diff --git a/docs/source/function/admin.rst b/docs/source/function/admin.rst index b23d1a9..8e74ddb 100644 --- a/docs/source/function/admin.rst +++ b/docs/source/function/admin.rst @@ -1,7 +1,7 @@ :mod:`admin` -- 后台函数模块 ======================================= -:mod:`admin` 模块源代码在文件夹 `applications/common/admin.py` 下,主要集结了一些常用的后台需要频繁调用的函数。 +:mod:`admin` 模块源代码在文件 `applications/common/admin.py` 下,主要集结了一些常用的后台需要频繁调用的函数。 .. module:: admin @@ -10,9 +10,21 @@ .. function:: get_captcha() - 生成验证码图片及其对应的验证码字符串。 + 生成验证码图片及其对应的验证码字符串。 - :return: 返回验证码图片的响应对象和验证码字符串。 + :return: 返回验证码图片的响应对象和验证码字符串。 + + **示例:** + + .. code-block:: python + + from applications.common.admin import get_captcha + + @bp.get('/getCaptcha') + def captcha(): + resp, code = get_captcha() + session["code"] = code + return resp .. function:: normal_log(method, url, ip, user_agent, desc, uid, is_access) @@ -31,12 +43,12 @@ .. function:: login_log(request, uid, is_access) - 记录用户登录日志。 + 记录用户登录日志。 - :param request: Flask 请求对象。 - :param uid: 用户 ID。 - :param is_access: 是否成功登录(True 或 False)。 - :return: 返回日志记录的 ID。 + :param request: Flask 请求对象。 + :param uid: 用户 ID。 + :param is_access: 是否成功登录(True 或 False)。 + :return: 返回日志记录的 ID。 .. function:: admin_log(request, is_access, desc=None) diff --git a/docs/source/function/curd.rst b/docs/source/function/curd.rst new file mode 100644 index 0000000..2e6e8a6 --- /dev/null +++ b/docs/source/function/curd.rst @@ -0,0 +1,90 @@ +:mod:`curd` -- 简单增删改查模块 +======================================= + +:mod:`curd` 模块源代码在文件 `applications/common/curd.py` 下,主要集结了一些简单实用的增删改查。 + +.. module:: curd + +类 +------- + +.. class:: LogicalDeleteMixin + + 逻辑删除混入类,为模型提供软删除功能。 + + **示例:** + + .. code-block:: python + + class Test(db.Model, LogicalDeleteMixin): + __tablename__ = 'admin_test' + id = db.Column(db.Integer, primary_key=True, comment='角色ID') + + # 软删除 + Test.query.filter_by(id=1).soft_delete() + + # 查询所有未删除的记录 + Test.query.logic_all() + + +函数 +-------------- + +.. function:: auto_model_jsonify(data, model: db.Model) + + 自动序列化模型数据为 JSON 格式,无需手动定义 Schema。 + + **示例:** + + .. code-block:: python + + power_data = curd.auto_model_jsonify(model=Dept, data=dept) + + :param data: 需要序列化的 SQLAlchemy 查询结果。 + :param model: SQLAlchemy 模型类。 + :return: 返回序列化后的 JSON 数据。 + + +.. function:: model_to_dicts(schema: ma.Schema, data) + + 使用指定的 Schema 序列化 SQLAlchemy 查询结果。 + + :param schema: Marshmallow Schema 类。 + :param data: SQLAlchemy 查询结果。 + :return: 返回序列化后的数据,返回字典。 + + +.. function:: get_one_by_id(model: db.Model, id) + + 根据 ID 查询单个记录。 + + :param model: SQLAlchemy 模型类。 + :param id: 记录的主键 ID。 + :return: 返回查询到的记录,如果未找到则返回 None。 + + +.. function:: delete_one_by_id(model: db.Model, id) + + 根据 ID 删除单个记录。 + + :param model: SQLAlchemy 模型类。 + :param id: 记录的主键 ID。 + :return: 返回删除操作影响的行数。 + + +.. function:: enable_status(model: db.Model, id) + + 启用指定 ID 的记录。 + + :param model: SQLAlchemy 模型类。 + :param id: 记录的主键 ID。 + :return: 如果操作成功返回 True,否则返回 False。 + + +.. function:: disable_status(model: db.Model, id) + + 停用指定 ID 的记录。 + + :param model: SQLAlchemy 模型类。 + :param id: 记录的主键 ID。 + :return: 如果操作成功返回 True,否则返回 False。 \ No newline at end of file diff --git a/docs/source/function/helper.rst b/docs/source/function/helper.rst new file mode 100644 index 0000000..9795748 --- /dev/null +++ b/docs/source/function/helper.rst @@ -0,0 +1,121 @@ +.. _字段构造模块: + +:mod:`helper` -- 字段构造模块 +======================================= + +:mod:`helper` 模块源代码在文件 `applications/common/helper.py` 下,主要集结了一些常用的字段构造方法。 + +.. module:: helper + +类 +-------- + +.. class:: ModelFilter + + ORM 多条件查询构造器,支持多种查询条件组合。 + + **示例:** + + .. code-block:: python + + from applications.common.helper import ModelFilter + mf = ModelFilter() + mf.exact('name', 'John') # 添加精确匹配条件 + mf.vague('email', 'example.com') # 添加模糊匹配条件 + query = User.query.filter(mf.get_filter(User)) + + + .. attribute:: filter_field + + 存储字段过滤条件的字典。 + + + .. attribute:: filter_list + + 存储最终的过滤条件列表。 + + + .. method:: __init__() + + 初始化过滤条件存储字典和列表。 + + + .. method:: exact(field_name, value) + + 添加精确匹配条件。 + + :param field_name: 模型字段名称。 + :param value: 匹配的值。 + + + .. method:: neq(field_name, value) + + 添加不等于条件。 + + :param field_name: 模型字段名称。 + :param value: 不匹配的值。 + + + .. method:: greater(field_name, value) + + 添加大于条件。 + + :param field_name: 模型字段名称。 + :param value: 大于的值。 + + + .. method:: less(field_name, value) + + 添加小于条件。 + + :param field_name: 模型字段名称。 + :param value: 小于的值。 + + + .. method:: vague(field_name, value: str) + + 添加模糊匹配条件(左右模糊)。 + + :param field_name: 模型字段名称。 + :param value: 模糊匹配的值。 + + + .. method:: left_vague(field_name, value: str) + + 添加左模糊匹配条件。 + + :param field_name: 模型字段名称。 + :param value: 左模糊匹配的值。 + + + .. method:: right_vague(field_name, value: str) + + 添加右模糊匹配条件。 + + :param field_name: 模型字段名称。 + :param value: 右模糊匹配的值。 + + + .. method:: contains(field_name, value: str) + + 添加包含条件。 + + :param field_name: 模型字段名称。 + :param value: 包含的值。 + + + .. method:: between(field_name, value1, value2) + + 添加范围查询条件。 + + :param field_name: 模型字段名称。 + :param value1: 范围起始值。 + :param value2: 范围结束值。 + + + .. method:: get_filter(model: db.Model) + + 获取最终的 SQLAlchemy 过滤条件。 + + :param model: SQLAlchemy 模型类。 + :return: 返回组合后的过滤条件。 \ No newline at end of file diff --git a/docs/source/function/index.rst b/docs/source/function/index.rst index b567811..ac13421 100644 --- a/docs/source/function/index.rst +++ b/docs/source/function/index.rst @@ -9,6 +9,8 @@ :maxdepth: 1 admin + curd + helper 辅助函数 ------------ diff --git a/docs/source/function/utils/cache.rst b/docs/source/function/utils/cache.rst index 5d6d087..044f876 100644 --- a/docs/source/function/utils/cache.rst +++ b/docs/source/function/utils/cache.rst @@ -1,7 +1,7 @@ :mod:`cache` -- 应用缓存模块 ================================ -:mod:`cache` 模块源代码在文件夹 `applications/common/utils/cache.py` 下,主要用于简单的程序数据缓存。 +:mod:`cache` 模块源代码在文件 `applications/common/utils/cache.py` 下,主要用于简单的程序数据缓存。 目前此模块仅启用应用程序缓存,暂时没有联动 Redis 等数据库缓存的功能,后续有意向添加。您可以在自己的项目中添加相关的函数,当然也非常欢迎提交 PR ,一起完善项目。 diff --git a/docs/source/function/utils/captcha.rst b/docs/source/function/utils/captcha.rst index 0838a6d..85722d3 100644 --- a/docs/source/function/utils/captcha.rst +++ b/docs/source/function/utils/captcha.rst @@ -1,7 +1,7 @@ :mod:`captcha` -- 验证码生成模块 ================================== -:mod:`captcha` 模块源代码在文件夹 `applications/common/utils/captcha.py` 下,主要用于生成验证码图片。 +:mod:`captcha` 模块源代码在文件 `applications/common/utils/captcha.py` 下,主要用于生成验证码图片。 .. module:: captcha diff --git a/docs/source/function/utils/http.rst b/docs/source/function/utils/http.rst index 7d89bfc..858b029 100644 --- a/docs/source/function/utils/http.rst +++ b/docs/source/function/utils/http.rst @@ -1,7 +1,9 @@ +.. _JSON 响应正文生成模块: + :mod:`http` -- JSON 响应正文生成模块 ======================================= -:mod:`http` 模块源代码在文件夹 `applications/common/utils/http.py` 下,主要用于生成 JSON 格式的响应正文。 +:mod:`http` 模块源代码在文件 `applications/common/utils/http.py` 下,主要用于生成 JSON 格式的响应正文。 对于大部分 JSON 格式响应的数据,请尽量遵循响应格式规范。如此方便后续前后端的分离和项目的构建。 @@ -36,4 +38,22 @@ :param limit: 每页数据条数,默认为 10。 :return: 返回 JSON 格式的响应,包含 `msg`、`code`、`data`、`count` 和 `limit` 字段。 +**示例:** + +.. code-block:: python + + from applications.common.utils.http import success_api, fail_api + + @bp.get('/init') + def init(): + if ...: + return success_api(msg="初始化成功") + return fail_api(msg="初始化失败") + +.. code-block:: python + + from applications.common.utils.http import table_api + @bp.get('/data') + def data(): + return table_api(data=[], total=0) diff --git a/docs/source/function/utils/index.rst b/docs/source/function/utils/index.rst index 17cbaf5..36decf2 100644 --- a/docs/source/function/utils/index.rst +++ b/docs/source/function/utils/index.rst @@ -3,7 +3,7 @@ 目录索引 .. toctree:: - :maxdepth: 1 + :maxdepth: 2 cache captcha diff --git a/docs/source/function/utils/mail.rst b/docs/source/function/utils/mail.rst index 78a09bd..6814d79 100644 --- a/docs/source/function/utils/mail.rst +++ b/docs/source/function/utils/mail.rst @@ -1,7 +1,11 @@ +.. _邮件模块: + :mod:`mail` -- 邮件模块 ================================== -:mod:`mail` 模块源代码在文件夹 `applications/common/utils/mail.py` 下,主要用于邮件的发送。 +:mod:`mail` 模块源代码在文件 `applications/common/utils/mail.py` 下,主要用于邮件的发送。 + +使用前,需要正确在 `applications/config.py` 中配置 SMTP 服务器。 .. module:: mail @@ -31,14 +35,23 @@ .. function:: add(receiver, subject, content, user_id) - 发送一封邮件,并将发送记录保存到数据库。 **该方法被邮件发送的视图函数调用。** + 发送一封邮件,并将发送记录保存到数据库。 **该方法被邮件发送的视图函数调用。** - :param receiver: 接收者邮箱地址,多个邮箱用英文分号隔开。 - :param subject: 邮件主题。 - :param content: 邮件内容(HTML 格式)。 - :param user_id: 发送者用户ID,表示谁发送了这封邮件。 + :param receiver: 接收者邮箱地址,多个邮箱用英文分号隔开。 + :param subject: 邮件主题。 + :param content: 邮件内容(HTML 格式)。 + :param user_id: 发送者用户ID,表示谁发送了这封邮件。 可以使用 `from flask_login import current_user; current_user.id` 获取当前登录用户的ID。 - :return: 发送成功返回 True,失败报错。 + :return: 发送成功返回 True,失败报错。 + + **示例** + + .. code-block:: python + + from flask_login import current_user + from applications.common.utils import mail + + mail.add("test@test.com", "subject", "

                Hello

                ", current_user.id) .. function:: delete(id) diff --git a/docs/source/function/utils/rights.rst b/docs/source/function/utils/rights.rst index 7dd2019..8c9f77e 100644 --- a/docs/source/function/utils/rights.rst +++ b/docs/source/function/utils/rights.rst @@ -1,7 +1,9 @@ +.. _权限验证模块: + :mod:`rights` -- 权限验证模块 ================================== -:mod:`rights` 模块源代码在文件夹 `applications/common/utils/rights.py` 下,主要用于权限验证。 +:mod:`rights` 模块源代码在文件 `applications/common/utils/rights.py` 下,主要用于权限验证。 .. module:: rights @@ -23,6 +25,8 @@ .. code-block:: python + from applications.common.utils.rights import authorize + @app.route("/test") @authorize("system:power:remove", log=True) def test_index(): diff --git a/docs/source/function/utils/upload.rst b/docs/source/function/utils/upload.rst index 4f3b989..522a069 100644 --- a/docs/source/function/utils/upload.rst +++ b/docs/source/function/utils/upload.rst @@ -1,7 +1,7 @@ :mod:`upload` -- 文件上传模块 ================================== -:mod:`upload` 模块源代码在文件夹 `applications/common/utils/upload.py` 下,主要用于文件上传,目前主要用于图片上传。 +:mod:`upload` 模块源代码在文件 `applications/common/utils/upload.py` 下,主要用于文件上传,目前主要用于图片上传。 .. module:: upload diff --git a/docs/source/function/utils/validate.rst b/docs/source/function/utils/validate.rst index b6048bd..b4647cc 100644 --- a/docs/source/function/utils/validate.rst +++ b/docs/source/function/utils/validate.rst @@ -1,7 +1,7 @@ :mod:`validate` -- 效验模块 ================================== -:mod:`validate` 模块源代码在文件夹 `applications/common/utils/validate.py` 下,主要用于数据效验与过滤。 +:mod:`validate` 模块源代码在文件 `applications/common/utils/validate.py` 下,主要用于数据效验与过滤。 .. module:: validate diff --git a/docs/source/index.rst b/docs/source/index.rst index 1a19ccb..81855f9 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -21,3 +21,9 @@ function/index +.. toctree:: + :maxdepth: 1 + :caption: 最佳实践 + + practices/index + diff --git a/docs/source/practices/index.rst b/docs/source/practices/index.rst new file mode 100644 index 0000000..7b9d61f --- /dev/null +++ b/docs/source/practices/index.rst @@ -0,0 +1,9 @@ +.. title:: 最佳实践 + +目录索引 + +.. toctree:: + :maxdepth: 1 + + plugin + trick \ No newline at end of file diff --git a/docs/source/practices/plugin.rst b/docs/source/practices/plugin.rst new file mode 100644 index 0000000..d74d15f --- /dev/null +++ b/docs/source/practices/plugin.rst @@ -0,0 +1,129 @@ +插件开发 +================= + +插件功能旨在最大限度不修改原框架的前提下添加新功能,并可以像程序原有框架一样进行流程注册,而且不需要修改任何程序框架原有代码(仅在配置文件中设置即可)。 + +所有插件放置在 `plugins` 文件夹中,项目提供了三个示例插件,分别是 `helloworld` 、 `realip` 和 `replacePage` ,分别用于示例页面的注册、修改 Flask 上下文和页面替换。 + +像项目自带的用户管理、部门管理等基本功能属于程序自身的“功能插件”,对于大多数衍生项目来说,多的是修改字符串和删除部分不需要的功能, +而插件开发主要可以用于添加自己的视图函数和功能,可以完美于项目融合,增加可拓展性。 + +插件的启用 +----------------- + +插件需要在 `applications/config.py` 中配置,你会找到如下的内容: + +.. code-block:: python + + PLUGIN_ENABLE_FOLDERS = [] + +而在目录 `plugins` 中,你会发现存在 文件夹名称 为 `helloworld` 、 `realip` 和 `replacePage` 三个插件。比如我们想要启用 `helloworld` 插件, +仅需要做如下修改: + +.. code-block:: python + + PLUGIN_ENABLE_FOLDERS = ["helloworld"] + +假设有多个插件,只要依次在列表 `PLUGIN_ENABLE_FOLDERS` 中填入插件的文件夹名称即可。**注意:填写的先后顺序会影响插件加载的前后顺序,越前面的插件越早被加载。** + +假设插件启用成功,你将会在控制台收到如下的提示: + +.. code-block:: bash + + * Plugin: Loaded plugin: Hello World . + +| + +.. image:: ../_static/plugin_run.png + :align: center + +| + +`helloworld` 插件启用之后,你可以访问 `http://127.0.0.1:5000/hello_world/` 来请求到新添加的页面。你会发现添加页面变的简单,仅需要修改一下设置项就行了。 + +| + +.. image:: ../_static/helloworld.png + :align: center + +| + +插件的目录架构 +------------------- + +插件的目录架构如下: + +.. code-block:: bash + + Plugin + │ __init__.json + └─ __init__.py + +这是一个插件基本的目录架构,插件信息保存在 `__init__.json` 中,其本质是一个包含如下 JSON 字符串的文本文件: + +.. code-block:: json + + { + "plugin_name": "Hello World", + "plugin_version": "1.0.0.1", + "plugin_description": "一个测试的插件。" + } + +这个 JSON 文件中,记录了基本的插件名称与插件版本,以及插件的介绍,请确保一个插件至少包含上述的三个字段,因为这三个字段会被项目所读取并在加载成功之后展示在控制台。 + +编写插件入口 +------------------- + +插件入口位于 `__init__.py` 中,请确保 `__init__.py` 文件一定包含 `event_init(app: Flask)` 函数,如下: + +.. code-block:: python + + def event_init(app: Flask): + pass + +这个函数将会在插件加载时被调用,并传入项目的 `Flask` 对象,此后你可以像一般使用 Flask 一样添加视图函数。例如: + +.. code-block:: python + + def event_init(app: Flask): + @app.get('/test') + def test(): + return "这是测试页面" + +**当然,不推荐这样直接使用 Flask 对象创建视图函数,更妥当的做法是通过注册蓝图的方式来添加视图函数。您可以这样做:** + +在您编写的插件目录下建立一个 `main.py` 文件,并在该文件中添加蓝图: + +.. code-block:: python + + from flask import render_template, Blueprint + + # 创建蓝图 + helloworld_blueprint = Blueprint('hello_world', __name__, + template_folder='templates', + static_folder="static", + url_prefix="/hello_world") + + @helloworld_blueprint.route("/") + def index(): + return render_template("helloworld_index.html") + +而后在 `__init__.py` 中注册该蓝图: + +.. code-block:: python + + from flask import Flask + from .main import helloworld_blueprint + + + def event_init(app: Flask): + """初始化完成时会调用这里""" + app.register_blueprint(helloworld_blueprint) + +这样可以使目录架构更加清晰。 + +.. important:: + + 注意不要直接在 `__init__.py` 的 `event_init` 函数外直接写存在阻塞的代码,不然项目 Flask 将不能初始化完成。 + + diff --git a/docs/source/practices/trick.rst b/docs/source/practices/trick.rst new file mode 100644 index 0000000..f3a9510 --- /dev/null +++ b/docs/source/practices/trick.rst @@ -0,0 +1,199 @@ +开发技巧 +=================== + +开发 Web 过程中需要用到许多技巧来加速开发,本章节将介绍开发的小技巧与一些需要注意的细节。 + +配置数据库 +----------- + +项目采用 flask-sqlalchemy,支持多数据库连接,默认是使用 sqlite 的,可以在 `applications/config.py` 中配置,如果需要连接其他数据库需要可以参考: + +* HOSTNAME: 指数据库的IP地址 +* USERNAME:指数据库登录的用户名 +* PASSWORD:指数据库登录密码 +* PORT:指数据库开放的端口 +* DATABASE:指需要连接的数据库名称 + +.. code-block:: python + + # MSSQL + SQLALCHEMY_DATABASE_URI = f"mssql+pymssql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=cp936" + + # mysql + SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4" + + # Oracle + SQLALCHEMY_DATABASE_URI = f"oracle+cx_oracle://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}" + + # SQLite + SQLALCHEMY_DATABASE_URI = "sqlite://../database.db" + + # Postgres + SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}" + +.. important:: + + 使用不同的数据库需要安装另外的库,比如 mysql 要安装 pymysql 库(不同平台可能名称不一样),请自行查询资料而后进行配置。 + +权限效验 +------------ + +在开发后台管理模板的过程中会涉及到权限效验,即访问控制。Pear Admin Flask 中提供了方便的函数用于进行权限效验。详情请查看 :ref:`权限验证模块` 章节。 + +Schema 序列化 +--------------- + +项目中时常会涉及到数据库的读写,在读入数据时采用 SQLAlchemy,将模型查询的数据对象转化为字典,以此方便与前端页面进行数据交换。 + +.. important:: + + Schema 模型放在了 `applications/schemas` 文件夹中,与 `applications/models` 中的数据库模型对应(准确来说是序列化为字典的配置)。 + +进行序列化时,常常会用到 `applications/common/curd.py` 中的 `model_to_dicts` 函数,下面是一个常见的用法。 + +.. code-block:: python + + from applications.models import Dept + from applications.common import curd + from applications.schemas import DeptSchema + + dept = Dept.query.order_by(Dept.sort).all() + power_data = curd.model_to_dicts(schema=DeptSchema, data=dept) # 此处 power_data 将会是一个列表,存储了部门的数据字典 + +在自己撰写 Schema 模型时,推荐使用自动化类型转化: + +.. code-block:: python + + from flask_marshmallow.sqla import SQLAlchemyAutoSchema + from applications.models import 你的模型类 + class RoleOutSchema(SQLAlchemyAutoSchema): + class Meta: + model = 你的模型类 # table = models.Album.__table__ + # include_relationships = True # 输出模型对象时同时对外键,是否也一并进行处理 + include_fk = True # 序列化阶段是否也一并返回主键 + # fields= ["id","name"] # 启动的字段列表 + # exclude = ["id","name"] # 排除字段列表 + + +与 layui 的数据格式同步 +------------------------------ + +项目的前端页面基于 layui 框架,在一些数据展示页面(如:layui 动态表格)需要与 layui 框架进行快速的数据交换。比如前端会传入 limit 和 page 参数 +用于限定数据展示的范围。故项目中在 SQLAlchemy 中添加了专有的查询函数。详情可以查看文件 `applications/extensions/init_sqlalchemy.py` 。 +下面是对 `Query` 类的解释。 + +.. class:: Query(BaseQuery) + + 自定义查询类,扩展了 BaseQuery 的功能,支持软删除、逻辑查询、分页和序列化。 + + **示例:** + + .. code-block:: python + + # 软删除 + User.query.filter_by(id=1).soft_delete() + + # 查询所有未删除的记录 + users = User.query.logic_all() + + # 分页查询并返回 JSON 数据 + data, total, page, per_page = User.query.layui_paginate_json(UserSchema) + + + .. method:: soft_delete() + + 软删除当前查询结果集中的记录。 + + :return: 返回更新操作影响的行数。 + + + .. method:: logic_all() + + 查询所有未删除的记录。 + + :return: 返回未删除的记录列表。 + + + .. method:: all_json(schema: Schema) + + 将查询结果序列化为 JSON 格式。 + + :param schema: Marshmallow Schema 类。 + :return: 返回序列化后的 JSON 数据。 + + + .. method:: layui_paginate(page=None, limit=None) + + 分页查询,适用于 Layui 表格。 + + **需要注意的是,如果不提供 page 和 limit 则该函数必须在视图函数中使用,该函数会自动获取 GET 请求中的 limit 和 page 参数构成查询。** + + :return: 返回分页对象。 + + **示例:** + + .. code-block:: python + + # 查询邮件数据并分页 + mail = Mail.query.filter(mf.get_filter(Mail)).layui_paginate() + return model_to_dicts(schema=MailOutSchema, data=mail.items) + + + .. method:: layui_paginate_json(schema: Schema) + + 分页查询并返回 JSON 格式数据,适用于 Layui 表格。 + + :param schema: Marshmallow Schema 类。 + :return: 返回包含序列化数据、总数、当前页码和每页条数的元组。 + + + .. method:: layui_paginate_db_json() + + 分页查询并返回数据库原始数据的 JSON 格式,适用于 Layui 表格。 + + :return: 返回包含序列化数据和总数的元组。 + + **示例:** + + .. code-block:: python + + db.query(User.name).layui_paginate_db_json() + + +进行字段构造 +----------------------- + +提炼数据时常常会用到准确匹配或者模糊匹配,又或者是进行多条件大小比较的匹配,此时可以通过字段构造来解决。项目中提供了字段构造的类位于 +`applications/common/helper.py` 。详情查看 :ref:`字段构造模块` 章节。 + + +响应合适的响应数据 +----------------------- + +在进行 JSON 数据响应时,应该注重响应的 JSON 格式类型,一般情况下,项目的 JSON 响应会形如: + +.. code-block:: json + + { + "code": 0, + "msg": "请求成功", + "data": [], + "count": 0, + "limit": 0 + } + +其中,`data` 、 `total` 和 `limit` 字段是可选的,仅在传输数据的时候存在。项目提供了生成统一响应格式的函数,位于 `applications/common/utils/http.py` 。 +详情查看 :ref:`JSON 响应正文生成模块` 章节。 + + +发送硬件 +----------------------- + +程序提供了发送邮件的模块,前提是需要正确在 `applications/config.py` 中配置 SMTP 服务器。详情查看 ref:`邮件模块` 章节。 + +.. code-block:: python + + from flask_login import current_user + from applications.common.utils import mail + + mail.add("test@test.com", "subject", "

                Hello

                ", current_user.id) \ No newline at end of file diff --git a/plugins/helloworld/__init__.py b/plugins/helloworld/__init__.py index d6b218e..a875cce 100644 --- a/plugins/helloworld/__init__.py +++ b/plugins/helloworld/__init__.py @@ -10,6 +10,7 @@ from .main import helloworld_blueprint dir_path = os.path.dirname(__file__).replace("\\", "/") folder_name = dir_path[dir_path.rfind("/") + 1:] # 插件文件夹名称 + def event_init(app: Flask): """初始化完成时会调用这里""" - app.register_blueprint(helloworld_blueprint) \ No newline at end of file + app.register_blueprint(helloworld_blueprint) diff --git a/plugins/helloworld/main.py b/plugins/helloworld/main.py index f559210..2622ab5 100644 --- a/plugins/helloworld/main.py +++ b/plugins/helloworld/main.py @@ -1,10 +1,12 @@ from flask import render_template, Blueprint # 创建蓝图 -helloworld_blueprint = Blueprint('hello_world', __name__, template_folder='templates', static_folder="static", - url_prefix="/hello_world") +helloworld_blueprint = Blueprint('hello_world', __name__, + template_folder='templates', + static_folder="static", + url_prefix="/hello_world") + @helloworld_blueprint.route("/") def index(): return render_template("helloworld_index.html") - diff --git a/plugins/realip/__init__.py b/plugins/realip/__init__.py index 50e18b4..7d36e01 100644 --- a/plugins/realip/__init__.py +++ b/plugins/realip/__init__.py @@ -4,38 +4,21 @@ import os import logging from flask import Flask, request -from . import console # 获取插件所在的目录(结尾没有分割符号) dir_path = os.path.dirname(__file__).replace("\\", "/") folder_name = dir_path[dir_path.rfind("/") + 1:] # 插件文件夹名称 + def event_init(app: Flask): """初始化完成时会调用这里""" - # 移除原有的输出日志 - app.logger = None - log = logging.getLogger('werkzeug') - log.setLevel(logging.ERROR) - + # 更改IP地址,只有在最新版的flask中才能生效 @app.before_request def before_request(): request.remote_addr = get_user_ip(request) - - - # 使用自定义的日志输出 - @app.after_request - def after_request(rep): - if rep.status_code == 200: - console.success(f"{request.remote_addr} -- {request.full_path} 200") - elif rep.status_code == 404: - console.error(f"{request.remote_addr} -- {request.full_path} 404") - elif rep.status_code == 500: - console.warning(f"{request.remote_addr} -- {request.full_path} 500") - else: - console.info(f"{request.remote_addr} -- {request.full_path} {rep.status_code}") - return rep - + + def get_user_ip(request): """获取用户真实IP""" if 'HTTP_X_FORWARDED_FOR' in request.headers: @@ -54,4 +37,4 @@ def get_user_ip(request): return request.headers['REMOTE_ADDR'] elif 'X-Forwarded-For' in request.headers: return request.headers['X-Forwarded-For'] - return request.remote_addr \ No newline at end of file + return request.remote_addr diff --git a/plugins/realip/console.py b/plugins/realip/console.py deleted file mode 100644 index a6fe37b..0000000 --- a/plugins/realip/console.py +++ /dev/null @@ -1,89 +0,0 @@ -""" -输出控制台日志 -""" -import sys -import time -import ctypes - -NONE = "\033[m" -RED = "\033[0;32;31m" -LIGHT_RED = "\033[1;31m" -GREEN = "\033[0;32;32m" -LIGHT_GREEN = "\033[1;32m" -BLUE = "\033[0;32;34m" -LIGHT_BLUE = "\033[1;34m" -DARY_GRAY = "\033[1;30m" -CYAN = "\033[0;36m" -LIGHT_CYAN = "\033[1;36m" -PURPLE = "\033[0;35m" -LIGHT_PURPLE = "\033[1;35m" -BROWN = "\033[0;33m" -YELLOW = "\033[1;33m" -LIGHT_GRAY = "\033[0;37m" -WHITE = "\033[1;37m" - -# 开启 Windows 下对于 ESC控制符 的支持 -if sys.platform == "win32": - kernel32 = ctypes.windll.kernel32 - kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7) - - -def _print(level, msg): - time_ = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) - - level_name = {10: "Plain", - 11: "Log", - 12: "Info", - 13: "Debug", - 14: "Success", - 15: "Warning", - 16: "Error"} - - color = {10: NONE, - 11: LIGHT_CYAN, - 12: LIGHT_BLUE, - 13: PURPLE, - 14: GREEN, - 15: YELLOW, - 16: RED} - - print(f'{color.get(level, NONE)}[{time_}]({level_name.get(level, "Plain")}):', msg, f"{NONE}") - - -def plain(*args, sep=' '): - msg = sep.join(str(_) for _ in args) - _print(10, msg) - - -def log(*args, sep=' '): - msg = sep.join(str(_) for _ in args) - _print(11, msg) - - -def info(*args, sep=' '): - msg = sep.join(str(_) for _ in args) - _print(12, msg) - - -def debug(*args, sep=' '): - msg = sep.join(str(_) for _ in args) - _print(13, msg) - - -def success(*args, sep=' '): - msg = sep.join(str(_) for _ in args) - _print(14, msg) - - -def warn(*args): - warning(*args) - - -def warning(*args, sep=' '): - msg = sep.join(str(_) for _ in args) - _print(15, msg) - - -def error(*args, sep=' '): - msg = sep.join(str(_) for _ in args) - _print(16, msg) -- Gitee From feed91dcd02452870c181fef66321ee5158dbaa1 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Mon, 27 Jan 2025 20:41:22 +0800 Subject: [PATCH 30/36] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E6=9C=80=E4=BD=B3=E5=AE=9E=E8=B7=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/source/practices/frontend.rst | 79 ++++++++++++++++++++++++++++++ docs/source/practices/index.rst | 3 +- docs/source/practices/plugin.rst | 7 ++- plugins/helloworld/__init__.json | 5 -- 4 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 docs/source/practices/frontend.rst delete mode 100644 plugins/helloworld/__init__.json diff --git a/docs/source/practices/frontend.rst b/docs/source/practices/frontend.rst new file mode 100644 index 0000000..f85f58c --- /dev/null +++ b/docs/source/practices/frontend.rst @@ -0,0 +1,79 @@ +前端页面编写 +======================== + +Pear Admin Flask 并没有实现前后端分离,因为存在部分页面的数据是直接通过模板渲染的方式直接渲染在 HTML 中的。但我们将展示给用户浏览器里的页面都称为前端。 + +公用模板文件 +-------------------- + +项目使用 Flask 搭建,其所有模板文件均存放在 `templates` 文件夹中。公用模板文件保存在 `templates/system/common` ,分别是: + +* header.html -- 头部包含文件,包含了后台页面通用的 css 文件 +* footer.html -- 页脚包含文件,包含了后台页面通用的 js 文件 + +在写后台内嵌页面时,可以参考下面的模板: + +.. code-block:: html + + + + + 这是标题 + {% include 'system/common/header.html' %} + + + + + + + + {% include 'system/common/footer.html' %} + + + +.. note:: + + 需要注意的是,`header.html` 和 `footer.html` 包含了主题色和夜间模式切换的脚本,如果不想包含这两个文件的话, + 还想进行主题色和夜间模式切换可能需要自行添加脚本。(可以参考这两个文件中的内容) + +正确的后台页面嵌入方式 +----------------------- + +Pear Admin Layui 主项目更新之后,提供了 组件式嵌入(_component) 和 iframe嵌入(_iframe) 两种方式。在编写前端页面时, +不同的嵌入方式有所不同,各有优劣。 + +对于组件式嵌入,可以提供更良好的用户体验,如果页面不存在则会弹出 404 提示信息,对于iframe嵌入,则会直接打开(即使不存在)。 + +.. important:: + **使用组件式嵌入时,上述的参考模板不在需要包含 header.html 和 footer.html 文件,如果包含这两个文件会直接影响到后台框架页面的排版和脚本调用!** + +经过测试,组件式嵌入仅适合于唯一且静态的页面,不建议在其中 **添加事件绑定的脚本** ,因为组件式嵌入会将页面内容直接嵌入 div 元素中, +并动态执行脚本,但是执行的脚本绑定的事件并不会因为页面关闭而销毁。简单说明就是,假设脚本中存在计时器,计时器不会在组件式嵌入的页面销毁之后而销毁。 + +所以在 Pear Admin Flask 项目中,仅首页(后台数据统计页面)和个人资料页面使用组件式嵌入,其余均使用iframe嵌入。 + +关于主题色和夜间模式 +----------------------- + +如果开发的是后台管理页面,主题色和夜间模式是必要的,这样可以增加观感。 +Pear Admin Layui 的控制主题色逻辑是通过设置全局的 css 属性:`--global-primary-color` + +比如对于 `.layui-btn` : + +.. code-block:: css + + .layui-btn { + background-color: var(--global-primary-color); + } + +所以,如果您添加了自定义元素,并想要其跟随主题色变化,请确保引用了 `--global-primary-color` 属性。 + +对于夜间模式,本质上就是修改 body 的 class ,使其添加上 `pear-admin-dark` ,比如 `.layui-btn` 的夜间模式 css 为: + +.. code-block:: css + + .pear-admin-dark .layui-btn { + color: #ffffff; + border-color: #4C4D4F; + } + diff --git a/docs/source/practices/index.rst b/docs/source/practices/index.rst index 7b9d61f..94e78c2 100644 --- a/docs/source/practices/index.rst +++ b/docs/source/practices/index.rst @@ -6,4 +6,5 @@ :maxdepth: 1 plugin - trick \ No newline at end of file + trick + frontend \ No newline at end of file diff --git a/docs/source/practices/plugin.rst b/docs/source/practices/plugin.rst index d74d15f..8716732 100644 --- a/docs/source/practices/plugin.rst +++ b/docs/source/practices/plugin.rst @@ -69,7 +69,7 @@ "plugin_description": "一个测试的插件。" } -这个 JSON 文件中,记录了基本的插件名称与插件版本,以及插件的介绍,请确保一个插件至少包含上述的三个字段,因为这三个字段会被项目所读取并在加载成功之后展示在控制台。 +这个 JSON 文件中,记录了基本的插件名称与插件版本,以及插件的介绍。**在更新之后,此文件可以不存在,插件的名称默认为文件夹名。** 编写插件入口 ------------------- @@ -126,4 +126,9 @@ 注意不要直接在 `__init__.py` 的 `event_init` 函数外直接写存在阻塞的代码,不然项目 Flask 将不能初始化完成。 +.. note:: + 在编写插件的前端模板(template)时,请尽量将模板文件放在项目根目录的 `templates` 文件中,这样可以保持良好的项目架构。 + 当然另一种做法是像 helloworld 插件那样,直接放在插件目录的 templates 中,但是一定要做好模板名称的区分, + 因为 flask 默认找模板行为是从根目录开始找的,如果根目录 templates 和插件目录的 templates 中存在的模板重名, + 则会优先使用根目录 templates 的模板文件。 \ No newline at end of file diff --git a/plugins/helloworld/__init__.json b/plugins/helloworld/__init__.json deleted file mode 100644 index 1373e2d..0000000 --- a/plugins/helloworld/__init__.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "plugin_name": "Hello World", - "plugin_version": "1.0.0.1", - "plugin_description": "一个测试的插件。" -} \ No newline at end of file -- Gitee From da5917344ef39cc23ef11de07b08211dda051d82 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Mon, 27 Jan 2025 21:34:42 +0800 Subject: [PATCH 31/36] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= =?UTF-8?q?=EF=BC=8C=E5=AE=8C=E5=96=84=E6=8F=92=E4=BB=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/__init__.py | 1 + applications/common/script/__init__.py | 2 + applications/common/script/admin.py | 2 +- applications/extensions/__init__.py | 8 ++- .../init_plugins.py} | 53 ++++++++++++++----- applications/view/__init__.py | 6 ++- docs/source/practices/plugin.rst | 19 +++++-- plugins/helloworld/__init__.json | 5 ++ plugins/helloworld/__init__.py | 22 ++++++++ 9 files changed, 98 insertions(+), 20 deletions(-) rename applications/{view/plugin/__init__.py => extensions/init_plugins.py} (46%) create mode 100644 plugins/helloworld/__init__.json diff --git a/applications/__init__.py b/applications/__init__.py index af5bb8e..d2b460b 100644 --- a/applications/__init__.py +++ b/applications/__init__.py @@ -8,6 +8,7 @@ from applications.view import init_bps def create_app(): app = Flask(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + # 引入配置 app.config.from_object(BaseConfig) diff --git a/applications/common/script/__init__.py b/applications/common/script/__init__.py index 81450ef..3801751 100644 --- a/applications/common/script/__init__.py +++ b/applications/common/script/__init__.py @@ -1,7 +1,9 @@ from flask import Flask from .admin import admin_cli +from applications.extensions.init_plugins import broadcast_execute def init_script(app: Flask): app.cli.add_command(admin_cli) + broadcast_execute(app, 'event_finish') diff --git a/applications/common/script/admin.py b/applications/common/script/admin.py index 826ddfa..11fc43b 100644 --- a/applications/common/script/admin.py +++ b/applications/common/script/admin.py @@ -572,4 +572,4 @@ def init_db(): print("用户角色数据存入") add_role_power() print("角色权限数据存入") - print("数据初始化完成,请使用run脚本运行") + print("数据初始化完成,请使用run脚本运行") diff --git a/applications/extensions/__init__.py b/applications/extensions/__init__.py index fe9762c..b1f9913 100644 --- a/applications/extensions/__init__.py +++ b/applications/extensions/__init__.py @@ -7,9 +7,15 @@ from .init_mail import init_mail, mail as flask_mail from .init_upload import init_upload from .init_migrate import init_migrate from .init_session import init_session +from .init_plugins import register_plugin, broadcast_execute def init_plugs(app: Flask) -> None: + # 注册插件 + register_plugin(app) + broadcast_execute(app, 'event_begin') + + # 注册 Flask 功能 init_login_manager(app) init_databases(app) init_template_directives(app) @@ -17,4 +23,4 @@ def init_plugs(app: Flask) -> None: init_mail(app) init_upload(app) init_migrate(app) - init_session(app) \ No newline at end of file + init_session(app) diff --git a/applications/view/plugin/__init__.py b/applications/extensions/init_plugins.py similarity index 46% rename from applications/view/plugin/__init__.py rename to applications/extensions/init_plugins.py index 7d16edd..80d1264 100644 --- a/applications/view/plugin/__init__.py +++ b/applications/extensions/init_plugins.py @@ -1,34 +1,61 @@ +import os + from flask import Flask from flask import Blueprint + import json -import traceback import importlib + plugin_bp = Blueprint('plugin', __name__, url_prefix='/plugin') + PLUGIN_ENABLE_FOLDERS = [] +PLUGIN_IMPORTLIB = [] -def register_plugin_views(app: Flask): +def register_plugin(app: Flask): + """ + 获取所有插件并加载 + """ global PLUGIN_ENABLE_FOLDERS app.register_blueprint(plugin_bp) # 载入插件过程 # plugin_folder 配置的是插件的文件夹名 PLUGIN_ENABLE_FOLDERS = app.config['PLUGIN_ENABLE_FOLDERS'] + for plugin_folder in PLUGIN_ENABLE_FOLDERS: - plugin_info = {} + + plugin_info = { + 'plugin_name': plugin_folder + } + + try: + if os.path.exists("plugins/" + plugin_folder + "/__init__.json"): + with open("plugins/" + plugin_folder + "/__init__.json", "r", encoding='utf-8') as f: + plugin_info = json.loads(f.read()) + + # 将插件全部载入 + PLUGIN_IMPORTLIB.append(importlib.import_module('plugins.' + plugin_folder)) + + print(f" * Plugin: Loaded plugin: {plugin_info['plugin_name']} .") + except BaseException as e: + info = f" * Plugin: Crash a error when loading {plugin_info['plugin_name'] if len(plugin_info) != 0 else 'plugin'} :" + "\n" + app.logger.error(info) + app.logger.exception(e) + + +def broadcast_execute(app: Flask, function_name): + for plugin in PLUGIN_IMPORTLIB: + try: - with open("plugins/" + plugin_folder + "/__init__.json", "r", encoding='utf-8') as f: - plugin_info = json.loads(f.read()) # 初始化完成事件 try: - getattr(importlib.import_module('plugins.' + plugin_folder), "event_init")(app) + getattr(plugin, function_name)(app) except AttributeError: # 没有插件启用事件就不调用 pass - print(f" * Plugin: Loaded plugin: {plugin_info['plugin_name']} .") except BaseException as e: - info = f" * Plugin: Crash a error when loading {plugin_info['plugin_name'] if len(plugin_info) != 0 else 'plugin'} :" + "\n" - info += 'str(Exception):\t' + str(Exception) + "\n" - info += 'str(e):\t\t' + str(e) + "\n" - info += 'repr(e):\t' + repr(e) + "\n" - info += 'traceback.format_exc():\n%s' + traceback.format_exc() - print(info) + app.logger.exception(e) + + if function_name == 'event_finish': + with app.app_context(): + broadcast_execute(app, 'event_context') \ No newline at end of file diff --git a/applications/view/__init__.py b/applications/view/__init__.py index e1fb713..3e71f71 100644 --- a/applications/view/__init__.py +++ b/applications/view/__init__.py @@ -1,7 +1,9 @@ from applications.view.system import register_system_bps -from applications.view.plugin import register_plugin_views +from applications.extensions.init_plugins import broadcast_execute def init_bps(app): register_system_bps(app) - register_plugin_views(app) + + # 插件初始化函数 + broadcast_execute(app, 'event_init') diff --git a/docs/source/practices/plugin.rst b/docs/source/practices/plugin.rst index 8716732..321bfb8 100644 --- a/docs/source/practices/plugin.rst +++ b/docs/source/practices/plugin.rst @@ -71,10 +71,10 @@ 这个 JSON 文件中,记录了基本的插件名称与插件版本,以及插件的介绍。**在更新之后,此文件可以不存在,插件的名称默认为文件夹名。** -编写插件入口 +编写插件事件 ------------------- -插件入口位于 `__init__.py` 中,请确保 `__init__.py` 文件一定包含 `event_init(app: Flask)` 函数,如下: +插件入口位于 `__init__.py` 中,一般来说请确保 `__init__.py` 文件包含 `event_init(app: Flask)` 函数,如下: .. code-block:: python @@ -122,9 +122,22 @@ 这样可以使目录架构更加清晰。 +另外,插件还有其他三个事件: + +.. code-block:: python + + def event_begin(app: Flask): # 在项目所有功能注册之前调用 + pass + + def event_finish(app: Flask): # 在项目所有功能注册之后调用(插件已经加载完毕) + pass + + def event_context(app: Flask): # Flask 初始化完成,等待第一个请求之前,等同于 with app.app_context(): + pass + .. important:: - 注意不要直接在 `__init__.py` 的 `event_init` 函数外直接写存在阻塞的代码,不然项目 Flask 将不能初始化完成。 + 注意不要直接在 `__init__.py` 的函数外直接写存在阻塞的代码,不然项目 Flask 将不能初始化完成。 .. note:: diff --git a/plugins/helloworld/__init__.json b/plugins/helloworld/__init__.json new file mode 100644 index 0000000..1373e2d --- /dev/null +++ b/plugins/helloworld/__init__.json @@ -0,0 +1,5 @@ +{ + "plugin_name": "Hello World", + "plugin_version": "1.0.0.1", + "plugin_description": "一个测试的插件。" +} \ No newline at end of file diff --git a/plugins/helloworld/__init__.py b/plugins/helloworld/__init__.py index a875cce..c6c6fc1 100644 --- a/plugins/helloworld/__init__.py +++ b/plugins/helloworld/__init__.py @@ -6,11 +6,33 @@ import os from flask import Flask from .main import helloworld_blueprint +from applications.models import Dept +from applications.common import curd +from applications.schemas import DeptSchema + # 获取插件所在的目录(结尾没有分割符号) dir_path = os.path.dirname(__file__).replace("\\", "/") folder_name = dir_path[dir_path.rfind("/") + 1:] # 插件文件夹名称 +def event_begin(app: Flask): # 在项目所有功能注册之前调用 + print("所有功能初始化之前加载") + + def event_init(app: Flask): """初始化完成时会调用这里""" + print("初始插件初始化视图") app.register_blueprint(helloworld_blueprint) + + +def event_finish(app: Flask): # 在项目所有功能注册之后调用(插件已经加载完毕) + print("所有初始化完毕") + + +def event_context(app: Flask): # Flask 初始化完成,等待第一个请求之前,等同于 with app.app_context(): + print("第一个请求来之前加载") + + dept = Dept.query.order_by(Dept.sort).all() + power_data = curd.model_to_dicts(schema=DeptSchema, data=dept) + + print(power_data) -- Gitee From 41bda82c60e24f3535d661bdc54d6ea842bdb747 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Tue, 28 Jan 2025 17:47:41 +0800 Subject: [PATCH 32/36] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E4=B8=8E=E8=B0=83=E6=95=B4=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E9=A1=B9=E7=9B=AE=E6=9E=B6=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- applications/extensions/__init__.py | 6 +- ...46\265\201\347\250\213\345\233\276.drawio" | 247 ++++++++++++++++++ ...0\346\265\201\347\250\213\345\233\276.png" | Bin 0 -> 847125 bytes docs/source/practices/backend.rst | 27 ++ docs/source/practices/index.rst | 3 +- docs/source/practices/plugin.rst | 5 + docs/source/practices/trick.rst | 7 +- docs/source/welcome/instruction.rst | 2 +- docs/source/welcome/migration.rst | 19 +- docs/source/welcome/update.rst | 2 + plugins/helloworld/__init__.py | 3 +- templates/system/login.html | 2 +- 13 files changed, 316 insertions(+), 9 deletions(-) create mode 100644 "docs/source/_static/Pear Admin Flask \345\220\257\345\212\250\346\265\201\347\250\213\345\233\276.drawio" create mode 100644 "docs/source/_static/Pear Admin Flask \345\220\257\345\212\250\346\265\201\347\250\213\345\233\276.png" create mode 100644 docs/source/practices/backend.rst diff --git a/README.md b/README.md index 79e85b7..4edbbe0 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@

                - Pear Admin Layui Version + Pear Admin Layui Version Python Version diff --git a/applications/extensions/__init__.py b/applications/extensions/__init__.py index b1f9913..8849131 100644 --- a/applications/extensions/__init__.py +++ b/applications/extensions/__init__.py @@ -18,9 +18,11 @@ def init_plugs(app: Flask) -> None: # 注册 Flask 功能 init_login_manager(app) init_databases(app) - init_template_directives(app) - init_error_views(app) init_mail(app) init_upload(app) init_migrate(app) init_session(app) + + # 系统蓝图相关 + init_template_directives(app) + init_error_views(app) diff --git "a/docs/source/_static/Pear Admin Flask \345\220\257\345\212\250\346\265\201\347\250\213\345\233\276.drawio" "b/docs/source/_static/Pear Admin Flask \345\220\257\345\212\250\346\265\201\347\250\213\345\233\276.drawio" new file mode 100644 index 0000000..ffb2f75 --- /dev/null +++ "b/docs/source/_static/Pear Admin Flask \345\220\257\345\212\250\346\265\201\347\250\213\345\233\276.drawio" @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/docs/source/_static/Pear Admin Flask \345\220\257\345\212\250\346\265\201\347\250\213\345\233\276.png" "b/docs/source/_static/Pear Admin Flask \345\220\257\345\212\250\346\265\201\347\250\213\345\233\276.png" new file mode 100644 index 0000000000000000000000000000000000000000..2d7a71eed65a02aa2d5e3ed3750bd3a61b0c2955 GIT binary patch literal 847125 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%0AM!;$pEfJrR31kE?ptU`jfFY}wxRb$$&7WOc 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%0DMccg9QWv;S&Kr8^^o@;? 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

                ~*s`G3?(L;on2hUWtP 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 A%>V!Z delta 349727 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

              • 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

                B>iIi3j=)gl)3jsJScNw}5DyL)^I_rd7HX^K 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 z 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

                >s)9=F!%6JN?WZaqZ@S0?w&)v9u; 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 diff --git "a/docs/source/_static/\345\205\221\346\215\242\347\240\201\346\267\273\345\212\240\351\241\265\351\235\242.png" "b/docs/source/_static/\345\205\221\346\215\242\347\240\201\346\267\273\345\212\240\351\241\265\351\235\242.png" new file mode 100644 index 0000000000000000000000000000000000000000..f51f41b40a63ba8b2be0ade4c0b0b32f1b18d300 GIT binary patch literal 8962 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 literal 0 HcmV?d00001 diff --git "a/docs/source/_static/\345\205\221\346\215\242\347\240\201\347\256\241\347\220\206\351\241\265\351\235\242.png" "b/docs/source/_static/\345\205\221\346\215\242\347\240\201\347\256\241\347\220\206\351\241\265\351\235\242.png" new file mode 100644 index 0000000000000000000000000000000000000000..a907c60d1f8cd665df4085b7fd79d8df6b22f6ad GIT binary patch literal 28409 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 literal 0 HcmV?d00001 diff --git a/docs/source/conf.py b/docs/source/conf.py index b9732fc..33746dc 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -26,3 +26,7 @@ language = 'zh_CN' html_theme = 'sphinx_rtd_theme' html_static_path = ['_static'] + +suppress_warnings = [ + 'misc.highlighting_failure' # 忽略代码块高亮失败警告 +] \ No newline at end of file diff --git a/docs/source/function/curd.rst b/docs/source/function/curd.rst index 2e6e8a6..755a067 100644 --- a/docs/source/function/curd.rst +++ b/docs/source/function/curd.rst @@ -1,3 +1,5 @@ +.. _简单增删改查模块: + :mod:`curd` -- 简单增删改查模块 ======================================= diff --git a/docs/source/function/helper.rst b/docs/source/function/helper.rst index 9795748..572e54b 100644 --- a/docs/source/function/helper.rst +++ b/docs/source/function/helper.rst @@ -39,6 +39,14 @@ 初始化过滤条件存储字典和列表。 + .. method:: escape_like(value: str, escape_char: str = '\\') + + 转义LIKE查询中的特殊字符(%, _ 和转义字符本身) + + :param value: 需要转义的原始字符串 + :param escape_char: 转义字符(默认反斜杠) + :return: 转义后的安全字符串 + .. method:: exact(field_name, value) diff --git a/docs/source/function/index.rst b/docs/source/function/index.rst index ac13421..25bd111 100644 --- a/docs/source/function/index.rst +++ b/docs/source/function/index.rst @@ -2,7 +2,7 @@ 目录索引 -公共函数 +公共模块 ------------ .. toctree:: @@ -12,7 +12,7 @@ curd helper -辅助函数 +辅助模块 ------------ .. toctree:: diff --git a/docs/source/function/utils/index.rst b/docs/source/function/utils/index.rst index 36decf2..1206f1c 100644 --- a/docs/source/function/utils/index.rst +++ b/docs/source/function/utils/index.rst @@ -1,4 +1,4 @@ -.. title:: 辅助函数 +.. title:: 辅助模块 目录索引 diff --git a/docs/source/practices/backend.rst b/docs/source/practices/backend.rst index 2e4b95a..00bcdcd 100644 --- a/docs/source/practices/backend.rst +++ b/docs/source/practices/backend.rst @@ -1,7 +1,13 @@ +.. _后端页面编写: + 后端页面编写 ====================== -该章节将介绍如何在 Pear Admin Flask 中编写一个新后端页面,此章节将会以编写积分兑奖系统为例,编写一个兑换码管理的后台页面。 +该章节将介绍如何在 Pear Admin Flask 中编写一个新后端页面,此章节将会以编写兑换码管理页面为例,编写一个兑换码管理的后台页面。 + +.. note:: + + 前端页面制作,请参考 :ref:`简单前端页面示例` 章节。 .. _项目初始化逻辑: @@ -22,6 +28,468 @@ 由此可以看出,我们想要添加自己的后端页面,可以在 “注册项目的视图函数”(蓝框) 的地方添加,当然,同样页面可以作为插件的方式接入以提高项目的拓展性。 下面将介绍如何在这两种方式下添加自己的后台页面。 +设计数据库 +----------------------- + +兑换码一定是保存在数据库中的,我们现在要求改程序至少有以下几个功能: + +* 可以通过 flask admin init 或者等价的命令初始化数据库 +* 数据库存在统一管理的模型 +* 数据库的内容方便数据转化 + +数据的字段可以定为: + +* id -- 唯一主键 +* key -- 兑换码 +* content -- 具体的内容 +* enable -- 是否启用 +* used -- 是否使用 +* create_at -- 创建时间 + +根据上述需求,我们可以设计出这样一个数据库 Model : + +.. code-block:: python + + import datetime + from applications.extensions import db + + + class Gift(db.Model): + __tablename__ = 'admin_gift' + id = db.Column(db.Integer, primary_key=True, comment="唯一ID") + key = db.Column(db.String(50), comment="兑换码") + content = db.Column(db.String(), comment="具体的内容") + enable = db.Column(db.Integer, default=0, comment='是否启用') + used = db.Column(db.Integer, default=0, comment='是否已经使用') + create_at = db.Column(db.DateTime, default=datetime.datetime.now, comment='创建时间') + +我们将该文件命名为 `admin_gift.py` 放置在 `applications/models/admin_gift.py` ,而后为了使程序可以调用到这个模型, +需要在 `applications/models/__init__.py` 中导入这个模型。 + + +.. code-block:: python + + from .admin_gift import Gift + +.. note:: + + 由于 Gift 模型是 db.Model 的子类,在使用 `flask db init` 等命令行初始化数据库时,自动对 Gift 表进行创建,前提是这个类已经被 Python 加载, + 换而言之,Python 会自动将 db.Model 的子类作为数据库的一部分,加入到数据库初始化中。 + + +初始化数据库 +----------------------- + +通过上面的操作,我们已经成功将数据库中的 admin_gift 表进行创建。现在我们希望在使用 `flask admin init` 的时候,可以将我们已经定义的数据写入到数据表中。 + +在 `applications/common/script` 目录中,撰写了默认数据的写入脚本(也就是 Flask 启动最后加载的项目), +我们要做的是在 `applications/common/script/admin.py` 中添加自己需要的数据,我们可以对其进行修改,添加如下的代码: + +.. code-block:: python + + ... + from applications.models import Gift + + ... + now_time = datetime.datetime.now() + ... + powerdata = [ + ... + Power( + id=60, + name='兑换码管理', + type='1', + code='system:gift:main', + url='/system/gift/', + open_type='_iframe', + parent_id='1', + icon='layui-icon layui-icon layui-icon layui-icon-diamond', + sort=8, + create_time=now_time, + enable=1 + ), Power( + id=61, + name='兑换码添加', + type='2', + code='system:gift:add', + url='', + open_type='', + parent_id='60', + icon='', + sort=0, + create_time=now_time, + enable=1 + ), Power( + id=62, + name='兑换码删除', + type='2', + code='system:gift:remove', + url='', + open_type='', + parent_id='60', + icon='', + sort=0, + create_time=now_time, + enable=1 + ), Power( + id=63, + name='兑换码编辑', + type='2', + code='system:gift:edit', + url='', + open_type='', + parent_id='60', + icon='', + sort=0, + create_time=now_time, + enable=1 + ), + ... + ] + giftdata = [ + Gift( + id=0, + key='myTestCode', + content='8折优惠', + enable=1, + used=0, + create_at=now_time + ), + Gift( + id=1, + key='DisableCode', + content='1折优惠', + enable=0, + used=0, + create_at=now_time + ) + ] + + ... + def add_role_power(): + admin_powers = Power.query.filter(Power.id.in_([1, 3, 4, 9, 12, 13, 17, 18, 44, 48, 60])).all() + ... + + @admin_cli.command("init") + def init_db(): + ... + db.session.add_all(giftdata) + ... + +这样就可以将数据库内容写入了。 + +.. note:: + + powerdata 中添加了对兑换码的操作权限,可以先去“权限管理”中添加,而后再从数据中抄取。 + 或者忽略初始化时对 powerdata 的添加,在初始化之后,手动在权限管理中添加。 + +使用 Schema 序列化 +--------------------------- + +与前端交互大多用的是 JSON 格式的数据,这就涉及到将数据库查询的结果对象(Query)转化为 JSON 这一步骤。 +我们可以使用 flask_marshmallow 中的 SQLAlchemyAutoSchema 将数据库查询对象转换为 JSON 格式。 + +创建文件 `applications/schemas/admin_gift.py` ,并继承 SQLAlchemyAutoSchema ,更改其中的目标模型为我们创建的 Gift 模型。 + +.. code-block:: python + + from flask_marshmallow.sqla import SQLAlchemyAutoSchema + from applications.models import Gift + + + class GiftSchema(SQLAlchemyAutoSchema): + class Meta: + model = Gift # table = models.Album.__table__ + include_fk = True # 序列化阶段是否也一并返回主键 + +.. note:: + + 更多序列化参数可以参考 :ref:`Schema 序列化` 章节。 + +随后,在 `applications/schemas/__init__.py` 引用, + +.. code-block:: python + + ... + from .admin_gift import GiftSchema + +这一步不是必须的,但是应通过这一步的引用,可以在蓝图页面中,方便的使用 `from applications.schemas import *` 的方式导入。 + +编写后端视图函数 +----------------------- + +注册蓝图 +~~~~~~~~~~~~~~ + +接着我们需要设计后端的数据增删改查部分的视图函数,创建文件 `applications/view/system/gift.py` ,并写上基本的蓝图初始化逻辑: + +.. code-block:: python + + from flask import Blueprint + + bp = Blueprint('gift', __name__, url_prefix='/gift') + +根据流程图,我们需要在 `applications/view/system/__init__.py` 中,注册 `gift.py` 的蓝图: + +.. code-block:: + + ... + from applications.view.system.gift import bp as gift_bp + ... + + def register_system_bps(app: Flask): + ... + system_bp.register_blueprint(gift_bp) + ... + + +.. _编写数据获取路由: + +编写数据获取路由 +~~~~~~~~~~~~~~~~~~~~ + +.. important:: + + 因为目标是让前端 layui 的动态表格获取数据,而根据 layui 的文档,表格将会提供 limit 和 page 两个查询参数来进行分页查询,所以要对 limit 和 page 进行处理。 + +现在开始编写数据获取路由,路由是以 JSON 格式响应数据库中 `admin_gift` 的数据,下面提供一种实现方法: + +.. code-block:: python + + from flask import Blueprint + + from applications.models import Gift + from applications.schemas import GiftSchema + from applications.extensions import db + + from applications.common.utils.http import table_api + from applications.common.utils.rights import authorize + + bp = Blueprint('gift', __name__, url_prefix='/gift') + + + @bp.get('/data') + @authorize("system:gift:main") + def data(): + + query = db.session.query(Gift).layui_paginate() + + return table_api( + data=GiftSchema(many=True).dump(query), + count=query.total, + limit=query.per_page + ) + +可以发现,在没有搜索的情况下,正确处理前端的分页查询,实际上只有简单 5 行代码就可以完成(自动处理了 limit 和 page 参数), +另外,也可以采用已经封装好的 `layui_paginate_json` 方法: + +.. code-block:: python + + ... + @bp.get('/data') + @authorize("system:gift:main") + def data(): + + data, total, page, limit = db.session.query(Gift).layui_paginate_json(GiftSchema) + + return table_api( + data=data, + count=total, + limit=limit + ) + +`layui_paginate_json` 函数完成了分页、解析与转化,适用于一些比较简单数据转化场景。 + +.. warning:: + + 对于任何形式的后台管理员路由,切记不要忘记添加 `authorize` 装饰函数对请求效验权限!!!!!! + +.. note:: + + 对于 layui_paginate 方法定义,可以查看 :ref:`与 layui 的数据格式同步` 章节。 + +访问路由 `/system/gift/data` 可以获得如下数据: + +.. code-block:: json + + { + "code": 0, + "count": 2, + "data": [ + { + "content": "8折优惠", + "create_at": "2025-01-28T19:10:48.607165", + "enable": 1, + "id": 0, + "key": "myTestCode", + "used": 0 + }, + { + "content": "1折优惠", + "create_at": "2025-01-28T19:10:48.607165", + "enable": 0, + "id": 1, + "key": "DisableCode", + "used": 0 + } + ], + "limit": 10, + "msg": "" + } + +随后,我们加入查询: + +.. code-block:: python + + ... + @bp.get('/data') + @authorize("system:gift:main") + def data(): + key = request.args.get('key', type=str) + + mf = ModelFilter() + if key: + mf.vague('key', key) # 模糊查询 + + data, total, page, limit = db.session.query(Gift).filter(mf.get_filter(Gift)).layui_paginate_json(GiftSchema) + + return table_api( + data=data, + count=total, + limit=limit + ) + +.. _编写启用与禁用视图函数: + +编写启用与禁用视图函数 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +启用与禁用的基本思路是通过 ID 筛选到合适的记录行并设置其 enable 为 1 或者 0。在设计数据库时,我们有意将表示启用禁用字段设置为 `enable` 以此可以使用项目已经封装好的函数。 + +.. code-block:: python + + from applications.common.curd import enable_status, disable_status + + @bp.put('/enable') + @authorize("system:gift:edit") + def enable_api(): + data = request.get_json(force=True) + + if enable_status(Gift, data.get('id')): + return success_api(msg="启用成功") + + return success_api(msg="启用失败") + + + @bp.put('/disable') + @authorize("system:gift:edit") + def disable_api(): + req_json = request.get_json(force=True) + + if disable_status(Gift, req_json.get('id')): + return success_api(msg="禁用成功") + + return success_api(msg="禁用失败") + +.. note:: + + 对于上述的 `enable_status` `disable_status` 函数,可以参考文档 :ref:`简单增删改查模块` 章节。 + +数据的修改经历如下步骤:获取目标兑换码 ID、获取对应修改的新数据、应用修改,而数据的添加仅没有“获取目标兑换码 ID”这一步骤。 + +我们先来撰写添加这一部分的视图函数, + +编写删除视图函数 +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +删除的视图函数,实则和启用禁用是一样的,这里直接给出代码: + +.. code-block:: python + + @bp.delete('/remove/') + @authorize("system:gift:remove") + def remove_api(_id): + + if delete_one_by_id(Gift, _id): + return success_api(msg="删除成功") + + return success_api(msg="删除失败") + + +你会注意到,由于 `curd` 模块的封装,使编写路由变的简洁。 + +.. _编写增加视图函数: + +编写增加视图函数 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +添加视图函数经历下面几个步骤:获取参数、效验参数、写入数据库。 + +.. code-block:: python + + @bp.post('/save') + @authorize("system:gift:add", log=True) + def save(): + req_json = request.get_json(force=True) + + data = { + 'key': req_json.get('key'), + 'content': req_json.get('content'), + 'enable': req_json.get('enable'), + 'used': 0 + } + + # 效验参数 + if not all(list(data.keys())): + return fail_api(msg="参数不全") + + if not data['enable'].isdigit(): + return fail_api(msg="参数 enable 错误") + + try: + db.session.add(Gift(**data)) + db.session.commit() + return success_api(msg="添加成功") + except Exception as e: + return fail_api(msg="添加失败") + +.. important:: + + 效验参数是必不可少的,要尽可能一切不相信用户的输入。 + +.. _编写修改视图函数: + +编写修改视图函数 +~~~~~~~~~~~~~~~~~~~~~~~~ + +修改视图函数的编写就照葫芦画瓢即可,代码如下: + +.. code-block:: python + + @bp.post('/update') + @authorize("system:gift:edit", log=True) + def update(): + req_json = request.get_json(force=True) + + _id = req_json.get('id') + + data = { + 'key': req_json.get('key'), + 'content': req_json.get('content'), + 'enable': req_json.get('enable'), + 'used': 0 + } + # 效验参数 + if not all(list(data.keys())): + return fail_api(msg="参数不全") + if not data['enable'].isdigit(): + return fail_api(msg="参数 enable 错误") + try: + db.session.query(Gift).filter(Gift.id == _id).update(data) + db.session.commit() + return success_api(msg="编辑成功") + except Exception as e: + return fail_api(msg="编辑失败") diff --git a/docs/source/practices/frontend.rst b/docs/source/practices/frontend.rst index f85f58c..791ca48 100644 --- a/docs/source/practices/frontend.rst +++ b/docs/source/practices/frontend.rst @@ -77,3 +77,481 @@ Pear Admin Layui 的控制主题色逻辑是通过设置全局的 css 属性:` border-color: #4C4D4F; } + +.. _简单前端页面示例: + +简单前端页面示例 +------------------------- + +此部分我们来以制作一个兑换码管理的前端页面为例。 + +.. note:: + + 配套后端的制作可以查看 :ref:`后端页面编写` 章节。 + +规划模板存放位置 +~~~~~~~~~~~~~~~~~~ + +模板一般存放在 `templates/system` 的目录下,该目录下的每一个子文件(夹)都是一个特定功能的实现的网页模板。 + +我们在其中创建一个 `gift` 文件夹,并放入 `main.html` 、`add.html` 和 `edit.html` 。 + +| + +.. image:: ../_static/规划模板存放位置.png + :align: center + +| + +加入动态表格与查询表单 +~~~~~~~~~~~~~~~~~~~~~~~~ + +随后,我们可以制作一个写一个简单的页面,设想是页面中存在一个查询表单和一个动态表格: + +.. code-block:: html + + + + + 兑换码管理 + {% include 'system/common/header.html' %} + + + + {# 查询表单 #} +

                +
                + +
                + +
                + +
                + + +
                + +
                +
                + + {# 用户表格 #} +
                +
                +
                +
              • 属性
                +
                +
                +
                + + + + {% raw %} + + + + + + {% endraw %} + + + + + + + + + {% include 'system/common/footer.html' %} + + + + +注意还要在 Python 中加上渲染路由: + +.. code-block:: python + + @bp.get('/') + @authorize("system:gift:main") + def index(): + return render_template('system/gift/main.html') + +前端的效果如下: + +| + +.. image:: ../_static/兑换码管理页面.png + :align: center + +| + +完善查询功能 +~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + + 查询数据库的视图函数可以参考 :ref:`编写数据获取路由` 章节。 + +接着,我们完善查询功能,确保获取的路由在有查询功能之后,我们在前端编写表单提交的处理。 + +.. code-block:: javascript + + layui.use(['table', 'form'], function () { + ... + let form = layui.form; + + ... + // 表单查询 + form.on('submit(gift-query)', function (data) { + table.reload('gift-table', {where: data.field}) + return false; + }) + } + +监听启用和禁用事件 +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +在动态表格中存在启用与禁用的切换开关,我们需要对开关进行监听,在用户切换开关状态时,自动在数据库中设置兑换码的启用与禁用状态。 + +.. note:: + + 后台视图函数,参考 :ref:`编写启用与禁用视图函数` 章节。 + +.. code-block:: python + + let $ = layui.jquery; + ley popup = layui.popup; + ... + + // 启用与禁用 + form.on('switch(gift-enable)', function (obj) { + let operate; + if (obj.elem.checked) { + operate = 'enable' + } else { + operate = 'disable' + } + let loading = layer.load() + $.ajax({ + url: '/system/gift/' + operate, + data: JSON.stringify({id: this.value}), + dataType: 'json', + contentType: 'application/json', + type: 'put', + success: function (result) { + layer.close(loading) + if (result.success) { + popup.success(result.msg) + } else { + popup.failure(result.msg) + } + } + }) + }) + +.. important:: + + 如果对前端编写存在问题,可以自行查阅 `layui 官方文档 `_ ,需要注意的是,由于页面中的组件元素增多, + 最好使用准确无误的表示区分这些表单组件,以便在监听时正确绑定到事件。 + +监听删除数据事件 +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +删除数据事件就与监听启用禁用其实是同理的,这里直接给出代码, + +.. code-block:: javascript + + // 表格各行工具事件 + table.on('tool(gift-table)', function (obj) { + if (obj.event === 'remove') { + + layer.confirm('确定要删除该兑换码?', {icon: 3, title: '提示'}, function (index) { + layer.close(index) + let loading = layer.load() + $.ajax({ + url: '/system/gift/remove/' + obj.data['id'], + dataType: 'json', + type: 'delete', + success: function (result) { + layer.close(loading) + if (result.success) { + popup.success(result.msg, function () { + obj.del() + }) + } else { + popup.failure(result.msg) + } + } + }) + }) + + } else if (obj.event === 'edit') { + // 待定 + } + }) + + +编写新建与编辑页面 +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + + 对应的视图函数,可以查看 :ref:`编写增加视图函数` 章节。 + +编写这一部分涉及到设计表单,编辑实际上就是已经填好值的新建页面。由于目前项目暂未进行前后端分离,所以为了方便直接使用模板渲染的方式,直接将内容渲染到编辑页面上。 +这就导致需要保留这两个略微有差别的页面,后续的更新,将会尝试将渲染的方式剥离项目,直接动态请求,可以实现动态分离。 + +此处给出表单页面基本的写法,所有的新建页面表单可以参考这个模板: + +.. code-block:: html + + + + + 激活码管理 + {% include 'system/common/header.html' %} + + +
                +
                +
                +
                + +
                +
                +
                +
                +
                + + +
                +
                +
                + {% include 'system/common/footer.html' %} + + + + + +撰写表单的工作较为简单,代码如下: + +.. code-block:: html + +
                + +
                + +
                +
                + +
                + +
                + +
                +
                + +
                + +
                + + +
                +
                + +注意还要在管理页面加上窗口弹出的绑定: + +.. code-block:: javascript + + // 顶部工具栏 + table.on('toolbar(gift-table)', function (obj) { + if (obj.event === 'add') { + layer.open({ + type: 2, + title: '新增', + shade: 0.1, + area: ['550px', '550px'], + content: '/system/gift/add' + }) + } + }) + +| + +.. image:: ../_static/兑换码添加页面.png + :align: center + +| + + +现在编写编辑页面,编辑页面相较于新建页面仅有两个区别:增加了 ID 编辑框、修改了提交的地址,最重要的是将后端传入的内容渲染到页面上。 + +我们先编写如下的路由视图: + +.. code-block:: python + + @bp.get('/edit/') + @authorize("system:gift:edit", log=True) + def edit(_id): + gift = get_one_by_id(Gift, _id) + return render_template('system/gift/edit.html', gift=gift) + +绑定编辑事件(就是在上面 “// 待定” 的地方添加内容): + +.. code-block:: javascript + + } else if (obj.event === 'edit') { + + layer.open({ + type: 2, + title: '修改', + shade: 0.1, + area: ['550px', '500px'], + content: '/system/gift/edit/' + obj.data['id'] + }) + + } + +设计新表单: + +.. code-block:: html + +
                + +
                + +
                +
                + +
                + +
                + +
                +
                + +
                + +
                + +
                +
                + +
                + +
                + + +
                +
                + +.. important:: + + 要注意把内容渲染到网页上哦,其中 id 字段设置为禁用。随后不要忘记,将表单的提交地址改为 `/system/gift/update` 。 + +.. note:: + + 对应的视图函数,可以查看 :ref:`编写修改视图函数` 章节。 + + + + diff --git a/docs/source/practices/plugin.rst b/docs/source/practices/plugin.rst index 56874fc..a2590c0 100644 --- a/docs/source/practices/plugin.rst +++ b/docs/source/practices/plugin.rst @@ -6,7 +6,7 @@ 所有插件放置在 `plugins` 文件夹中,项目提供了三个示例插件,分别是 `helloworld` 、 `realip` 和 `replacePage` ,分别用于示例页面的注册、修改 Flask 上下文和页面替换。 像项目自带的用户管理、部门管理等基本功能属于程序自身的“功能插件”,对于大多数衍生项目来说,多的是修改字符串和删除部分不需要的功能, -而插件开发主要可以用于添加自己的视图函数和功能,可以完美于项目融合,增加可拓展性。 +而插件开发主要可以用于添加自己的视图函数和功能,可以完美于项目融合,增加可拓展性,尤其是用于既想保留原项目功能又想填写新功能的项目开发。 插件的启用 ----------------- diff --git a/docs/source/practices/trick.rst b/docs/source/practices/trick.rst index f823a0f..1d12611 100644 --- a/docs/source/practices/trick.rst +++ b/docs/source/practices/trick.rst @@ -40,11 +40,18 @@ 在 Pear Admin Flask 中,菜单的管理归属于 “权限管理” ,这样做的原因是为了使不同用户可以使用不同的访问控制。所以需要修改菜单,需要在 “权限管理” 页面编辑即可。 +配置后台站内消息 +------------------- + +后台站内消息是异步获取的,其路由在 `applications/view/system/rights.py` 的 `message` 函数中,后续会考虑写入数据库,并添加管理函数进行统一的管理。 + 权限效验 ------------ 在开发后台管理模板的过程中会涉及到权限效验,即访问控制。Pear Admin Flask 中提供了方便的函数用于进行权限效验。详情请查看 :ref:`权限验证模块` 章节。 +.. _Schema 序列化: + Schema 序列化 --------------- @@ -79,6 +86,12 @@ Schema 序列化 # fields= ["id","name"] # 启动的字段列表 # exclude = ["id","name"] # 排除字段列表 +.. note:: + + 更多参数可以参考官方文档对其的解释,链接如下:`SQLAlchemyAutoSchema `_ + + +.. _与 layui 的数据格式同步: 与 layui 的数据格式同步 ------------------------------ @@ -133,6 +146,8 @@ Schema 序列化 **需要注意的是,如果不提供 page 和 limit 则该函数必须在视图函数中使用,该函数会自动获取 GET 请求中的 limit 和 page 参数构成查询。** + :param page: 页码 + :param limit: 页数据个数 :return: 返回分页对象。 **示例:** @@ -144,25 +159,30 @@ Schema 序列化 return model_to_dicts(schema=MailOutSchema, data=mail.items) - .. method:: layui_paginate_json(schema: Schema) + .. method:: layui_paginate_json(schema: Schema, page=None, limit=None) - 分页查询并返回 JSON 格式数据,适用于 Layui 表格。 + 分页查询并通过 Marshmallow Schema 类 转化为 JSON,适用于 Layui 表格。 :param schema: Marshmallow Schema 类。 + :param page: 页码 + :param limit: 页数据个数 :return: 返回包含序列化数据、总数、当前页码和每页条数的元组。 - .. method:: layui_paginate_db_json() + .. method:: layui_paginate_db_json(page=None, limit=None) 分页查询并返回数据库原始数据的 JSON 格式,适用于 Layui 表格。 - :return: 返回包含序列化数据和总数的元组。 + :param page: 页码 + :param limit: 页数据个数 + :return: 返回包含序列化数据(列表)、总数、当前页码和每页条数的元组。 **示例:** .. code-block:: python - db.query(User.name).layui_paginate_db_json() + >> db.session.query(Gift.id, Gift.key).layui_paginate_db_json() + ([{'id': 0, 'key': 'myTestCode'}, {'id': 1, 'key': 'DisableCode'}], 2, 1, 10) 进行字段构造 diff --git a/docs/source/welcome/update.rst b/docs/source/welcome/update.rst index 84b5cbb..2b34038 100644 --- a/docs/source/welcome/update.rst +++ b/docs/source/welcome/update.rst @@ -42,6 +42,7 @@ * 优化代码结构,新增函数 `normal_log` 减少代码复用 * 添加了新插件的事件 * 修改了验证码生成路由 +* 为 ModelFilter 增加了字符转义 已知问题以及解决方式 ~~~~~~~~~~~~~~~~~~~~~~~ -- Gitee From 552bf779247640b596894d33b7bef6f66149bdca Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Thu, 30 Jan 2025 16:56:12 +0800 Subject: [PATCH 34/36] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E5=B9=B6=E6=B7=BB=E5=8A=A0=E7=A4=BA=E4=BE=8B=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/config.py | 2 +- ...6\345\275\225\350\247\204\345\210\222.png" | Bin 0 -> 25299 bytes ...3\345\212\240\350\217\234\345\215\225.png" | Bin 0 -> 16779 bytes docs/source/practices/backend.rst | 5 + docs/source/practices/frontend.rst | 2 + docs/source/practices/plugin.rst | 233 +++++++++++++++++- plugins/giftManager/__init__.py | 12 + plugins/giftManager/cli/__init__.py | 96 ++++++++ plugins/giftManager/models/__init__.py | 12 + plugins/giftManager/schemas/__init__.py | 12 + .../templates/system/gift/add.html | 84 +++++++ .../templates/system/gift/edit.html | 91 +++++++ .../templates/system/gift/main.html | 205 +++++++++++++++ plugins/giftManager/view/gift.py | 142 +++++++++++ 14 files changed, 891 insertions(+), 5 deletions(-) create mode 100644 "docs/source/_static/\346\217\222\344\273\266\347\233\256\345\275\225\350\247\204\345\210\222.png" create mode 100644 "docs/source/_static/\346\267\273\345\212\240\350\217\234\345\215\225.png" create mode 100644 plugins/giftManager/__init__.py create mode 100644 plugins/giftManager/cli/__init__.py create mode 100644 plugins/giftManager/models/__init__.py create mode 100644 plugins/giftManager/schemas/__init__.py create mode 100644 plugins/giftManager/templates/system/gift/add.html create mode 100644 plugins/giftManager/templates/system/gift/edit.html create mode 100644 plugins/giftManager/templates/system/gift/main.html create mode 100644 plugins/giftManager/view/gift.py diff --git a/applications/config.py b/applications/config.py index b5369f0..6f5b4a2 100644 --- a/applications/config.py +++ b/applications/config.py @@ -72,7 +72,7 @@ class BaseConfig: MAIL_DEFAULT_SENDER = MAIL_USERNAME # 插件配置,填写插件的文件名名称,默认不启用插件。 - PLUGIN_ENABLE_FOLDERS = [] + PLUGIN_ENABLE_FOLDERS = ["giftManager"] # Session 设置 PERMANENT_SESSION_LIFETIME = timedelta(days=7) diff --git "a/docs/source/_static/\346\217\222\344\273\266\347\233\256\345\275\225\350\247\204\345\210\222.png" "b/docs/source/_static/\346\217\222\344\273\266\347\233\256\345\275\225\350\247\204\345\210\222.png" new file mode 100644 index 0000000000000000000000000000000000000000..4a48ba76eebb91c360222f36ddbf87b8412f4a07 GIT binary patch literal 25299 zcmdSBby$?&_cjV5AT3BEC831$fV6~2N;Blp(jXu)ASod!Aq@i3If&8&2nZq!-8D!J zNW&1)?}PgJ{`#Ev{Bf@LoWHz$X2;rlueJ8N*Sa?m8qb~*;nU({U|+AM_Y$j@!z?fG}~hLoUcD}2nN$tP{WNo===k6jN~Be4 z1nrAlE&*gK{l4@49`G*(HVPXf&|cdKP3+RNbwcI8KfTeq41aO7vQgQpsfU9RsH&xl z=J`qIeOT1`$ZfMkk|i(m{(GOJ6)nS20saSjcY1O4dWq-aQEXeZjfBdv zgdj@gchG@M$>Z^+(_RG07^k#Xp86PR&*dWGij5MOyE|A>~Ob z7^V`XVZ$R|lQvM)VeYB5i%g34xJao&;?IM;l291p0qj>Pa zo(TCvz2A%2T631?LnSFyXvJ&7I$S=0deD)rEqVj2t$HRHaGl@&T8 zU}Y|{{4RDh2JgEBV6l`j$a<)*bPE>&TVWy5o-0~G#7lH?Z8lVs1|tsNI(33z`A?sF zPza0JDC>Kt9~BCbcS@e1C>FT};PHJX#KPsza^+H~0zY#Mz%BD-9q6LVt{{;3h>VF| z@n=t3;Cwys^+-KOG$k;yzCkz^`bL}>N5(|fEi?*|lu{_HX@EK`e@2e#OZzzKATXmr z9eqY2ob2?*cKc;jgA66|$=WV~2k!n43dZIH2VjNTTr2my;6pQOdK&o-pts_6@09L;dYe-VBZQaM%`m$$ zbU`pGH=Bd&Umo}pbkGhzPjdCB!mxU6pHWBlOG&l2rrNP9@ON8I13p;FfQjKq`jn+H zJvT-gE6cSz5xeo*sQ^pEcw7?%m}AZ~ATWl8lNkg9qgWU)G7KHMR4Tv=sb!^k?Jt*z zsMl|{sr%iqB1|9uZqbO@&FS$R;^XK4Yu=y4Dj|d2nBC?s;D~Hc1wRy9EM$a#b!MMa zi7sJSC5Q>b&cEWXlS<~!{~Eo&9E}yHv_1wWS=3FZ;43n_djlQ(t}Qdz^%jCa3&$P5 zi#;YUcHQh?ES5$ z=)AYt`chSf+ibL{A_jlj*8dM)%8NY69KxsYyOB~GT(Y@$TD+*&4cqAhezmc=Uy{PV z_ekQA7$`N$jm#TyPFj3Bmf^9I=W7dgBR1dFbQCj+gJ<)rT9hsS_@QmZTmihUw`Fvw z&^O=Scs#@G7UoFxQrh|Qap``+t0Yf5z~5DnkAq8ucB&~Hwx?ZrWk~X!Ob|1JkNDh< zvg&v;>3;H3>;0tow+Uf3iLfZo<~VSPIZ|z6?!{3yL^oyVAIqlLGW5eovq$}&>SyW% zS28T`Z{z>$2V#U>cz#HVPfytHaUe3d$3?N3X7Zmy-hQ9ZY=U%`jq>fNton;p?_kzM zFbryQ%mQwjQPO>ZK5G(G*A9=c$kN8BR!c`6?(chyR#NSAs!5?jp=Ey;nE_btMzIO+ zvTnNf`?_4$nOuTyVI92Rn>H-sVxVtYkfcAu_p;vB91HiK#Z}uuyxI{N1il|j%lGwH z$pak|vC(03{6(yzA+%cV4J_DCT3nVg$SJzSiYT7!#Cu;X1q=>NvTnTVY~-r+M!yX( zB|Ur4a`5wtzo;#7g(=ah4Q}og!HoyX1@46HTRKD=nR>SpHix9oQpYQUUrveGC6sU8 z`nfN{crgI)*h(?wEPEoSR?K{ury#pDE3x3l86CDxeKF|!1vlUzo8fZ#TL<#lucp`~ z=}h7{WcGm(L3oed22zDLK7;&VKAHXoFCFSob~_qEW-m*$0(lI=%NY5}ToO-Ee-C6; z*2H`E&QXhOKXx57W+O^8uO3Ql#Y(jgRrS zJK#4@Y@jAQCeOFz9l%a8DXWK(^JHr#@~e!-KP(4dpi4!E!|hVRk}FCisUn1_RQalG zsCQO2pjglu2U{_h%9U1x5a=W{T9EhGva=P56yZyS@aN0?(RDY=_AT;=O-(MVFB#jb zh_O%=H?LRpbydfgne?-GIq5-oTUC<7=UVU45`KwFO6Fp{;mJMdND1S!sBo%qCgN%o3+03tr$tR+}imld7{@;7YEIb z4Yz4HdhE}7?YuSFP--@O|jMMPv-6?c^`hD!yHn-B3K@tli0tTdE z>x1dKRXhn?z3_ETM(LZhoJkVr-`|!Mt()e4gS{scLl&772RI(Y{&u=)J$)s6G8uXD zOug3hG5b-vHVoRIMh$SAg6m9-s|6P=O3l0_Xj{ZtKButk_3*>SP6Gt?N!u~BAZWsUN_ZiOK z5xq-KvaHn=%hymY{6DKpuZK#K>LiB_(UF9JrjrDS+NIm?96(KzdfA$LQpMT~$5Ww- z#ArS8Yt0BneNOJ1(Oh55__}K*ucj-?jZGReRG~bv%a<0d&gRo6kTjx~b)>6~C#fT* zN~4BFg2FD*&J|rj>9+j9;YX-&Y6egCColHwy|d=WLK>wWu)JD#hKTJ-ra%(jKt00s zXW|}RpCEo;$w8>*J?#&Wk9WQaFm!k^zG+I)b8r1aJ{QQT#HhYC{FG_`boA|Iaep|os|c@G zV>zm&R)*zDlW%A8?~ZcWKv=-LK2=t_P6?(apX|Z8Jh6Lg`jJ{owh$@df+u;hglPML z^$RyNk9A#lAapJW+MDOp{{umB+=qM-mxFttGmdGknJXG&j*MMAQwWO*pBT~r!?5d| ze}uY-y`p<$fZj)zk4Kq9=8F8O7EmVcD-?}#HBVC~uu~_}3dcKVAo>l*(uBov!f8oC zf)wf6mDCYJFjctWw-IwAqUQz1FhA;T?SVe{d0dCZmRn!%aoKBIXUJuY_#xwKs7WBy zB(2t)09sq)J2obg&9|(QVdeKj5jZzv^!~tTqlRbMlyj2_>;26cXPj8nR)$anV{8q( zbjZYO7o|b!XO#1l7l`|p8jLl{LUhz3Pgk$lDl{*Ua&o6_Y@x@@pirjX6NuF5O&2{aXtGCwPt0|)5hskkeViC(MMsuX&Df^ zIF=IMb6c9bg(AX2c@+3w6f+wWIVBw4$qg9E+M%Cx_t&nQwJMlBt$7TH&a!Vq|DZe( zifm4Sd}yJ2ZemQ)=V^57?ooX99Vg`0Ju;Gw$f7mSX}%NF)An(66Hq3jEK9CLUIP^iN9Z_A*btGWLkw zjT~>?D^Xv=rZ{(gv`vkrp@cJL^K`e_CK!M0K9)xn@8$7TDbn&?x=EN=e-Kp80Dcjz z%B`=7^1JFJiX53Y;qg_$1|sU|o2Z%*VH*uv;pnN?BtpUz2$k~fES|Gy8M&)LU)-a+ zTLVySwmWM-cXyqAat4iJPD=&8NjdpSb~z7w&aVUKp((TI1S&7l@z~h=(;|`ET%Vuh!4Y6T&@hhwfCu22wJT?oOpS$ z{q41`po^xDOlam92o_(%H)~I*1r@zFq*)`1o#Pn@-J+ht8FpTJcLe=3v(scP6 zGWTh1lLc$GLAP62A5kWK2JVClxZKY7a`)v&651k$u!^TMZ)k{rfqO=CIg)SnZ#f4X zkBV^^a3!_0>lJHYp^|*@__1D zX3Tg@25E3gc~iuwb=-kPkeVT1Op0*8e?*ZP!=66%g-*+ST&+F%?w|NUxX%G%en)IP zZGLD$cA7c5v>(`WOvFZ{IkM%+h*j2CnmlNQT2H%vec|cxO2)CBv-xZN#vF&_S&wT8 z48OoDqhFZ^sd7KCO)Ss8WhnyFDoQYW*)kS61|J>ZJL3!ol_qh#;nT|0#u&bV^01x| z792Q3MS$K)52}z{_ffL4V2)0R`Yyx)Ol^mWZggAv!QBDRpIea}S;GV@QZS+k8lJTi zpS%bJ(v*BKE;a4K_ow{=axFJ0*u9l1x?F`|_}(hdy(#{Vko;{O`O}m(y-ZJF@OA$9 z);IxMpTn#{d*~<-DXwFo_3%78l}wX{;l5WD12aAJ(xoX+9!AS(wE_!rG=szmq-ygK zU%O+oXKjye0+GRMQS7DLz~w`TB9E5)&kgb+ePxhhCahh&BthcG>?M}y;Al*A@Sa>& z+A#_*)@waelzqzf$9LZh7Q-+x{g1QU7% zIm&%fb$9BQ!k{S_?^EIJ?v3TeUJ6p;D*ArsI_0y0DzH^-k(Xgl+Z`O+zlp(=IGPAu zd8!kKiI4VGS?jxx*-hcfwAL+5tQl4v* z9d8-l3;QL{%751cbGTJ)^nh^jy4VD(key6wy~XDXZ3q@ay^B=7q2rfv2* ztHzd5c-=}ZWkyQ+2J*b0WYuttibtF9ahGBn{JmO>-j!?#?}!9ZHcN$)+3GX?()+cq zDJG7CF`}UQVXmg>pKS$QXMD`34`(6CVNg@C>s8MVmyrpMMuVG%S{r7>}rBC$sil{cdpXn8-Nv#t=C3%!5T@-Pj8Mj_~ z{66X))ZvZ4vg+{+7==OQzLuhE75XO{^Qy#X8){|hd}d6QHQ!nPqjD|KJXffJp0m^I zCTQ~;E=NrYHyW&F7K3n05KNZ1{;viJ_ia22MuB*sD-&@Pm4OCasbxJn?Ll?ZK3^M4 z5j!!VlWv;w%|8S>F|4AwQ$;poMcH!Me=Cb+s>lNl9d44nU#z7h8&48Bomal!Q2d_v>T)scXT{gAe&`a7vHT*PO3pYG!awpX^Tmr? z%|y>!3Inp{k%Tq=4f9?xy-LIton7%0sj=76@a57@`X_APQVemswisn9MH*N{ahL)D zf5`f%vqiPluckKI9I{o&<%wYC)xa*LWX`!Ej2_0)T?{5|rd-r+OUkfW*BrvKf3WfE z&6jZ@7o%Q^Ce&~M%P|RF{ds(+0^XKv(yyyKL%KqjwrCgWOCx%O5%G1%ZB>*?u-2m{ zIBF@dlV6j~FJZJBMU2y-I1P`rk9u6HmJWV9h3#j&-H|~a(iMv0a}oW!a0?ZbkWBm> zOJ_u=1^-VoJ}QjubR*VSE!2t=!Sb=U!CcyLmw~@=xtz=4m3jD5%BwT`R4?x9&Iwr- zr%dX^`>%~pxsC6lPlfYw+g4w`w~w=R4bjarvHclh5LOo>;BtxfZ<|nvAi6-_7M7*e z%Kd?HEh2x_2sIQSuu=b`c zl1pS@ld{JBao7kd#&VNd|d(SD|AT0+%Hx z)$lveTyv%DH7>`XpXAs@j1XDj(G>+{W*Ic6ca;m?WE3vT(=w9MVqFfM`=JbGNVngb zB+=>g&`Q4qFEqeuy><#NuT=DP8mWkO>!ohc{FE&bkpU(_RWorG;eYl@txLYXj9G;{ zdm1E0S4?Sc$%uZqEoeA#Bv4d*sH;%hmcIDogvh?XsRji-~SAb)512*~f(PG3)1Q3sJq%p+ub%i;rgEm#e4e zv=B?SWS(OzBjK=MC>G3>v?-_EDwNRMLt-PU=G{Art}~(l?V*f&2(By5S0P`nfi|E5 z$+QV;x3x~&->4Gda&$L@O*Mqw#Tv^;73YecT(<74a6puMp8|gZ6qsEBrmc=~2ybWHZtX%&&XvrS5ueL9UN%3q} zWWMciQuvUiDiKI%9uVQun++`LOA$pkIfbmhnCOO^E+DfO0VDv3-3eOW-)I(y! z`^c=TMVvE%3`R>z+}d%{XWnKqs%<~naM!W?T~U~*3cqVqJMosbeQc23K$`SaWbOnR zB)KZ$(W|D{Q(;QLD$%*1(#EqyGrS0+qPitD-7D1qZ5U+_Vbzy>uHOMab^5ZiwJpkz zeZOVT97yUu+dqBHAqDZ^D4$(+oGilC;Nf$*Yxulk8I{$%kW-#`Yb9N0oRIq4j2IsRbzG$ zJeb$ms}|>T(fR^k5UTOyVOTfxZ8iM<#lRb#I1I<#)~`Ps$IigD0jZIi6v)e29R{5Z|i_}&#Qhdbco>4x7qiNt1+HY-)){*D_I(lw3D)nl z%7+A@@uHk-TqT@aOnD+K)xv{HcuzxJ(bGGVId?diuO5KjCxkD(S*rT>5CD#~qOXUm z%n=N)az2)rK`cCWUQXE%(w>GR#j93r1Nt*K(;lmbhkK1+g(B@o!AYXq22p%ESEFxz za(+A~NucwJ^`wYs$^Ce>b~#7o<-A$fj0tFQmkqQfuGaiHo#f%e%&Q2d283R3-4A(Y z4*U1LmdjhlTDsFRtnwEQ&)GVKDA8JemXiV>ALD8rjM(@8n`AUx+woyUmWBi4ooKNJ z=+5P=F(6twYK-k9uGUN}&wr60Mp-#-+h2OZUyM%`erC;eN!+I78F?`if@`{(lpzF0 zKI(O&c^G)`vXkmULN3>hPr_s4$=pMjFo(W4X;7|r>sDpM5GIW3?i<61a#c<)>f-DQ zxWv^RC!fj7*ml@^ld+Lp0Wz_3aLN+d<2f$5P0|MdR-W59Qt41m-Z|Zxb!c4$ff(y8 znMHPxGnCy@mS!N{V?()#E;MV)Dc-_Oz2#- zyh2O$J#@USLiMsQp{X*911HD+e-~-n+eBg((*iKLsWuIY6j3jSo(DmE9%ooxsNTCn zVE)cnwXo!$0cRgQ>gD6L^MVct{b{l2j5J^M%^&M0$I<`+z9_v=Rq`;)I_wo5r|NEk zVGNLjq}WYH>~j8{#RUo^dM*oc8|>MzBo*!FoSQX<;ayp5#>F*&%=kcNUDm{P7+fH< zgACX}*SdXsyKb#XU>RriJQDK-?lrUqFzRn;T}b^GT3h_Z-jRQ?_kY)*gbrN_X76Tr z<-dZ50buU?=wL@6;M$X`$nY929q3MZ(9N2tr?-^+4P*31jWYyRk_L&}XW{IoZt=`W z@0-G9${U3P5rVJ}FL2C)IntotPgrD1nOJHJj^BtN)PDqo`B=d7G7Vew+{&FC=Tt|v#wqC9W zi@a~TFonz>)*bUERgkUv2Ar)NL*}p6MGRNi&7KVGtZg}6WBHEJAn4Da*`5ZM2_%5l zSK!!^3CPPNb!qqXTIGLNsPv?M+v2y1yc~m(I92=_Shd1A26WHTY8L*rI%v#SL4l3s znDN#20fCLFkB8pzwQB(4F4ye;3Z1=I;M{qAbZzN1bR`Q%TXnrsmKf;dsI$Ky_rH`Z z!Tr4gwNSj@b!`YTAHSpM)d&Dv_hd^&U;fIf3cES)^L##VsHmoadq~Jp@`K3t3es>5 zf_nAqB*Jy7f&P)_dHy@tFb_~Lg^2R1{0DACV`_@k@pz~^%SB5CEiJAB@!KQp)_`qk zDWl2d6kxRcLQv7GQhT=*kdU+Z%Z04EepC~FzTF$632>5i_>-n>M#)5%ZHl*3-aRC_ zo-h8c_t0@4^m!u*T`h!Y`q@a=e>qaNE&f4>&sDou?=oJT)ZzNUoS;7VsO<@rBT4_^SfXW;aN3 z#5ef+I76NhvFGTpni`R}LNHG*6_f(B0q0^v>Kebk>)XKIPntgLff}&CUmdfBax}Rn z_ViGC^f<~X8u_Aa(fCP5cWAqqchyRke)l-&qYFFhttNAzdo&x-bsAJa^9@ z3v$`Bh*;})!2F|eBk*ngz72xdlPH){cLVP$U4sy)d!-e)xwwL|paA+A>K=vI$4UfG z%KmE$DG|QkOibB>c(&-`EMmgaHRSAh&X(sj;y7+xj)gt&h$MU+@4K>BQUJ||#vpHe zq;!dq2r>NPcby+H0P-#^LEwPXD3)*U6GUv@{Ox{I_n+T+`Qcl&tERsq8cR{ce_%F! zPx@lMeq+_i9@bXmx0Y!n63M;6itT}H%7HqABTS6zO4;Jg2Xmd~CS^6kyVyB3SA3pU z-_%KrPNf=UDN)^9FL+3mz2~Jo2qauKs5fbyN2+5VdwTqcs<3~0)9%@kD&qarIqx^| zQ8R}5c?ES3JQ`R6$AjLwEFYl~*JCO@Dzjz+hn9~#$h`{V%vHyz zF0-}WJ#~s;_yXSsPz{Jvq|?}D@5kZ`p&dyh!xD!)RcGE(bN9?r7D|(_ZCn67rGs(3-Lpv%DL({-^ z;PJP7Fwbnm?~l6^-V{*rxvczcPJ|YF{t$HTUKd6XdqZJAM<69wp1qUY3F7c&BQ!O| zVPcK19iE{#C8G2TqdRpyhhaWDgK0ek=kXd+=dqf(0D_JLz-kIBh4o~pnC%ex5y4hM zG;L$FFl-jIOlEN#z{UH=d!FOgsG*0 zMFa;s?TwJrL6@#K|MD;;^c(+x!(n<9^rVug+^>aPWPmF?x3-6j1U$J2Flw%)H0o1P z2DLPGQWZl8^^6Uy+pv2=E#BxxDy4%_G~RxpWAO31n=#|rnCh47E-=?$;^9O0uNX^7 zF!wQ<&lAK;zxetxq8?t?odNZ91QnC0XDnmdFN-VdOVI)W<+ZL_IEn1{OB!*D zaVdR2rLoCdTGch=7nY7UCtQ)2BsGJYs%M>sc zPZHQuqJDU^i{fwnUb)czbx8asu-`$KqUMZDfjB^IShIm+-24YMz&d*Z<^T1yLRA@( zC*`4*h5tebMzyAOTwa?{RUXM}2Wcj-uhhns5N~rQaPT2uVFj?OKsmeb`%{G`&Azn| z;*m+(aXJ8u{MT}9ETHi~$2Ez^(KgHCpkc#9EgVt@pjg7UWP(9Zv8hv_+7rNHo}jp5W^0cfCfge!j@=9aG=BzF#Or%|f5LGMb^@a$(zu%8?;+ zOz6qWBr>9yxjgZ2DNsfmQ!c)0Ouf7$A=v2PQX3Jzm0IW-q#a;&w%lcoKUziAAU`fx zyvUfVl4;4ldiz~278gN>iJf3Fc=y!);waJ&2PKL=(F?XecpwrOR3cjNqPpP8VR{inWm{Os@~>dyT*mK^muFfmW!{;W>1@Nt)?Y+9vf8Tt%)Ptwd=u0PdG=aw^oVcH|Exw*gFhV0 zLVUOBwv47+cJ<3nSV%F;sm{&beq>7dg^CqEd2NS(_$etwjE7AlNvVqX@xoQ5d|dpX z3yBI^Wb7`B(B+$pSa$$n3hK?W5YcsgeqRx_3Is^Vi-v~k0c!oeGL?O1r?!_07hf$Q z4~;8^GIi0G8WcRl$Gv*z^s@0iqYKAqvZj zdl@z7J9FbVj9!5_tWA5r|C+*E5(|x4OL{A_%?}2uuDn}7oc-kgK}mQjeNEBpFSLz! zV%idZW|u9}bkSmj()KPp8JCRemlF7rWfbc8x)Xl-DL@y&g~pNb5vikE>I>|;D;)R| z2=>T>fO0Z;^1*c0%-rR6iHBCT9;aVug+?w8g6o*<&E&v&>4E{)Ke8b;ew9`ij?<8D zDR&quz0fsqN(WofAqoh@IvyXcXyK}@12rX}Y`ak9qUGI2#a0h_8+)|>`L)G>6FTvN z{fSfh1iYR7Ww~H$UPtKX*Q^)7irD}pNQgdqn9jbz+E3l*;G{*_)eahK<(-GCyA#lT z9mX~hw3w(7?!?d`0$e~mFLzu7Hug1{!h92@yRJh<*juLnp#MWbL`#o(jJ-9!td;{H z#u#AlQ#E}EbPLp?Z;9k!7;Bn!!-gzP{}zh{KR`tRN{FTZQ$d)1J6`XfG3?R>4oAI` zY4+KQ`Px+ML9uyI-7j?U3%aAzzi}*bUw=;gLPgGfOc}=~ZnSaECl`n<#Z~0BGXN?sWx%fKG zX0I>YFXXRX3I1u|VFo$uxjFTE0QL_aj01?Ze8^%GGyp2^U4upA*70+wCqReXO844- zS8@>ij!{#lE63oygma5OQQ!y9J^~C3gFn>&|H{&}N5a(}Ci=LvEKcKM6dSCO7u*?> z@W8xP1XPMw4~iI1F#>6AhKDnjrwATX1F#qW!LkAI;|kZ4l!4w)RDpc!-{Je(??0?^ z4a{DS!o=$WTCICKGGm?QTYr8uMIL=^?f=z2|6R|cqZt-(65iT;iG*dWtd+^>$o3eKqR%VOukT0``1vS8a^%rQA`S z;OB_+hiAVlrbc)00TNq{;HGPE?+IQYD>nM*fX88n@ZviJAn_k)rwEEq!%52xn&N4R zou+us%IQPf;5E^I+x~YoUqSId=rx8IsQI!?x%O{zv9hf#!E20b?mgMZ?@6te&n;KZ zD#pd{$QXvh1?I_JCKcqKc4CG89rQmU*v7#X#IspAL~(a=uzqVW)C(ylK21f=iPhra zoiSZ{QLtRV={~Y@CLuDMy`e4sd9Y|Yv^Xzxa!}fbz4a+?%9wRhFQf2In~VP=Fj4&v zH~$+<0IB$Iwb#aT48g?>A-f!o36_v(}`%UQmU5QOIVMC)p_pf0m1K}smw_1IUSSl8_9}sk+j=H9jAS6a0 z0nh4vj0B|lN_b|!j|w23!?u6=uGC~-U3@HB?xXqe zw?tg_T1T*$_qT)we7vqBgAb*BE;}c_5`DjJp>d=KGDG@&+dIGcg^2}Kp$+`!{>0jW7&uRzMHADeM{^D!&ov#2hl}YN6w2Z|6sSikv@>afsCBfCp^YjfXYd$F@ zKyVKtgv0$!Feux5f4LV1|LETVs>Y)Z&-d^T_Q6Hf+&NO&SMdSgmEPNIK*L~$f)9*> z_7n_(H3INcT-+1+6b1TRwzg$@av)f=!b@|9oS5;i>!^|?r1xK~Ab1)^Thy(Vga5A~ z%^@FLrq)eNXKYySy@@{~x!gTS6Xb0XupD=svRM=oB96`sg^sXRpzn-|Pw~5`?^GZ4 z|ExBa0f_e8BrN~IPpIBa74euIP{(*Q#sA;X^2rtcA%;-+o%J^Zv=%O6r^6T;D?)(2 zK{fU1H%Wa5?&0~Fx2n{!Q-%C|VyQ&kp~3!%EL*-yltxyUv}Zmui$6)b&VG^22f+^W3)_#y*uIu(NhX zUfsvg`zs~D<#&5u3PBkEBLLMh+y4XddZK5(3vt*=jlLR}gX;3XH%XHN%= zy~CgOFhy4bUREeg00!ospPWAAw1*fO>fOh51ErnaGgLwwg8IZoJeNiAf-SZUYP`xe zf@B&1qmC?3o3PxEsW5?Qp$?yXm!AHl_N0qd+CE#MmJCIdU&2ZE&K#1_5|l&@G={MM zeX9epMr^DU6gt@&-_aJu)O}j2QHw9=5+Y=dw2JWZzY(W~_6d4r=`c~23Z$PySvNw+-+x1C&`3dZ>wnt1QG7628TDsj}ikUuG=gH)r7 z{Ge{UkQMxUh6b=!8mM_g7$Hh6@^ins#tsk*w{MdfT+{JO8a6+%>MI&~{Z&1pPM?1s z-MGu37$3(ZE}r161As|S1Cw_ED{$K8JTsfgzzli7zg>W_{$}rmf3PwJ`o?WW;4=g8 zre?401aA@Z|I`OPx{bGl7rzh<(yb^l1DerCQ{vJx9ze{aJW1jpwYU5|#T06J5$0fZ zN2Awj^ZX{jg|FZ=mu7Fx_v+lcGw@#g>a-N}x_WFr|Fbo} z{g*WdypmQ%`1wLtSaPey@ zzL{p~H7qGDb8!Q$@G;-($K+n37VrWCpp13vk?OR=PhQl-eIBE%O|Kig$-k4T^k+7s z8yvrl%o0M;VPD4i?v*)GIq?)w6Y|tLA>$Uyp-M0&S~;APkiG*>@qrRp%iAyTXSOG? zPnsZ45KVtV2Y4Sh$p9Ls0%O??=dshG(lUOS=wwV$FK)n^Z6H>3 zS|195ft~_I7B*M3PpwNHM@&0hm&p=vv$T9Jx+Op=*4zb>ZrEgr-v!{ z>h84R^2qp4okbVgi#}cSI8~Cw0cOP5+Ecj7+Hc)NF0R#IX_BZp>1FL=Jm$9D@x^PIf?W= zfBj_QFg}nXx5_M$_gI_}J#UTY`8%%AP37E7&kv^(&w_T7=sc;CiMVHkfwc~6G@u@8 zy>Fq_i@b$S=b}k=N@N>OibYk_s5%S%?aM6>JzzeK)m{%8wvds_4j8`TV@Or>XGlTC zR2eC~3aYNWhY&AW_1R!o(kx|u<;dq!ptyp-`4X?wukH--lbPR5Kiz%yu}aq{3FLBI z9brU#;(}*beL%c-a{uD1EH^qqU02>%QTOd7s%Olr1jC>Ore6Z$?SN0^yV|3dQO_Z= z>U2fqNvzNQ($QniFY4ZiU1V$%&b;F$wS15QO!Qu;-r@p`@20uO+X0JfMLc=SJHMCU zZ!C)D)IrMSR)BAXzqZXH{`$D7rW8;_lkBwA2iST$wwB!G4|4;~dl}VSTBgoJ&D5bB!&&n)YzURKagWe@Ko9N4 ztYs#}{HwH6AJMD3jeBMamD>U`$+t=}r##e-!%iF+W~)xy+A7EZRL>O(T-3(Bnq{b=iI&llq z>M!aW^;coCy*tFHhi`TIH^r>oRC+%Q99KeZJ9;iQ3LmC%aA{mmp%cT|i*Nb0)0Px~ zwog@qD2O(mY3g$jAI-{ux?8ZrH((E6kIlIDqCt`3teXt()i1*Yu*7Y^gmxgi`}ls;XAVi(auV02u!# z3;q``C)KNvqSHyAbfwO@-)V%R#iN4tQpE0V=@saV&5oOEBFc-i?-;awq1prZA!wf3=QujicJd`d9*;^} zkfHZIY0V)>PH?rmWk5^%`qPNXfb@sx9`!{X3!L|^XgJ*cGDs3&;hg$ZxDGDlzu&lj zIBOQmdDjVols65~UOMiu5_Y6zFzx0q33$ZqrAhDw?(s|)QHChMP7!3%Hmal*1a=$C z&Yt4S`ZItimWVg~$v?t;cbEU23g_y5s$%?$QEj5MXOOq)Kj5`N87Xw*o$zVDQ6*-N zFJj9Lp=Bu8gm}SPlFRVniQBEYT!z;8?==~7Co^7SH&J~zD838d9QTDis!11dVUnkO zj!Gv_t9wb06(yG_;Ie0SuSLl%hq99kaj-qwvIZkAKKx}JoI%1p;l70pXFz1oBs8}dx|fSd z_N=T}=%$F_P==R2GecVB8^3CO_47X1uGv ziBfWa&1=9z)mV_;Bak@JTarywNS_E?99g@Sj^J`}%9|-Y<7c;q3`jGl`0iiAH-|sO zj@V6{XNBDtvj<-CII!-k;YUHSjD998EEW*^V}B%XDg1=9fUj(+94`8To>37rqqc*Px+9OcP;4SyLGVEx9# z5pqUP_woVlK91QWJWeIzoY+Xee?qMLb08G+jXLM5jR9)q5HxG6)i=a=0=iWHwbq0+ zqv!03KK&kKQPqVbjE8(vn_S5iEwdb#O#ML_>No8e5-bGoGT=MGyptNdnYSdjpkfOxsZ7JyRx zO36P3T<~$H4T||KqFmJLmtKB-Rz`At=>y0CNX%n=#r+*Q{eSKQaG$R02OLV`biqo> z<}FuSTNr?=^ax*br}dOr00WUB^WR*C5A2W&3v*P*Bt#<9NvjsfHHNzYop=2U+#t`l z;~Yfdtbg&tY~qIm3AjnO=h63xM zRo@AT&*m$a9wW(!cND-wMNRBdg(T}xeln-e3CIv=+b>L1->ruxS-maQk>%4~JCUfL z^wq(^f7+Eql$$-y-d57WPx}a}rBzr`Ptp~w76JTbMSN47r2OXuHa9cNn}35>sZVg< zv0_F9&usPA`YQI^>q}8P@n^5qN+?CeYY@z`Mf>@kgK;^Dx_JZAnZXoeOZO#bMYqX-gzeCf=NN?Q% zXYw#ZiWLc<`mo`uHVmJf`U6#+8uS*X!gAE3L@F+*#B@3aUF#}vRm#j-B{Ixu@1n5n zu+YzgzJ4N7*4?34)ujl6K7>Aa0!8=b`Vrhwi-Mc%``NNk4F6gug}A8f|F=^ z+-L0-Zvz=A!fOY1s1|ANDXDg^&M^5NptT_wfZvgCk<3(i#Mc*JH7W4=i}guGPsC7J zkA%6BWpherZYQb+@H~9H#eQZ;$Kgk8LE@+f=FKUswa-~SV=7n$1iLAMM_fM&SOV2~ z$w{L&cn%8qD-~}@`qgg(1^mEYKhAINU0d+~Up{!Td{S!o@JYvoS!KY3JxrFzAbp zbzIygoYg(I>&DlJ6!dT5pUfPv|KZ;sK8%u@Z$jk~aUH`lYOM;(A78fwLLY9fQEooo zZfZUk1>2wN#z#rIR%0!`U?KILI12JVO;pvauw#$Mv=tY&FgjMoHN&)>wB*2I^XZ-^FE>`)0`OD$Gxcbnu#)a8A*DB zzxDa`5`{Ld39ck%)f3hEudUsi+q8cD=Eq&)jdMEfX#~}GL2X7lwVbj%Oy9M*3yhXL zt4m&$6omnP7ANfJb;la>d$i(xPPz-n#yLT|6y-h7!e1!#s?y(gnawV!`#2EIy`F<# zK9k%ik2O@B)U>inQ2W`w|HpeH7icTv1w+uGsW0Zg?>ZV4pdbfP0yVCdj9#K@-tsL3 zYKM`lzEwc{kAhGyaZ(A_d0qxe+h(M?LUDIFebok1pNH5Y%+SHD`U_zO=Rs|be??Ur zDq)8%au_i?^$iZ5*$n|TImEXQ>qAJUx{=&~;*i4m#}G)Em9pGr<9XU%7nI$4Gcq=Q zH$*;Hg375T0~HC1?(hpI>Wyb>W!A0f@bkGCfFsT`b7w z>Yx;MV}0hCI?nm#bH@943A}vOPN?oq!keOWq4!5MDpjpq(;4B?n8B$G&$$ zLm=oVOyW4KJfN>{>G0#-Tf8f%S`fW065E!f1Y6>0ssFLlZ*BcO)vs&rR!N(K=c2UK zDniy@lFUxj6mX9n{PCMv_SB|*LV+t?4Lvy>ahM;|p3U%lT(rAwD1e@1Hl#Ozr1a2$ z4(m6Y?thk}`p#uLOvd7oi<4R~E|@8=q{;ZD@UE*{tS!sT6XQ#>XQ`&@!wLovhymv> z3F~|5t$HeV7?SvTeOWwMb;>%`m^PEfU;O}t*>y&gYwEHYH~!f;+YWKN0$+7};=Oq~ zU;6F+HNuB)c#xMyF&2+SJ_&3XX-PuwmK$~BXI>nz?mPAKAV*uQ#ZL!eH^4BRF_GG7 z^#?K{vu1sm-Solo2=s!g%4mOi?xkI=K2KW}w?P#1wzAV(<*lW-qHsjyg23ob&Qsgp z=sNqK&krpx_FhO1+95elK5&Q4cyCJo))D`780u9Wr#roKi{U*v%A17{m5u$T?=hRE zQ}M8KQXmn&9dg_FESCS{j}n+(6%T!p^Kq!X=JvY%9_z=!<;aZsREyZh>DxFg_LC8&;1@C8i)nm+nu@IxD*Xo znC9^8`|xe|VbNA`Pv>!|kN*fJ2fwycKjAY=dBxO>ck);}o^w`qurtR$TVDw+u)Lq0 zLA{eK4ha$e#aQ?=G(b4MH_*bbkFWCE@hYE)+>%9p7Cgz{1pd}Zg&VdpvPt5Q765a{ zO+S&ku#(BT`8^}^&12!z^&Y5XGeF-A)d+2rKC4-6s)HW1Wvz&G#zbkxiO`B{(jHzh zpXekN!wXbq2k$RHJK(c_@UxgmvcdSNgaS@dLKkG4dNuS1H`MZ^Hmgk4yXl&H#BYc4+!024KbQ6;=P6}R^!#99R&w-h~q zRnkoFl?Dw)CwgWMJ9CRk_w|O7T>P9@i(nW7-Y2Eiz?F=rHf^Ehjkbd2BZv; zdMjNItU%Ro>ulc2*xKGp3Y5TaVnBEJsDNZ`Yb=`EANYWd{WT6?y#=M2%wF*%h8(-dY|~f*2fHwP58WVs7GqULl{LJr37}z2#h-8HcdP{P3*-|vpFGY_k3{tC8Vu@WyT6<%()G-axgs)a(<%Ov*hx2S zr%jhfw`d6Ie45qRyPZ+hT@y^&U-a;7^V*wlf2rDtT);eZJzW}mKvKnE^tX|bb#~4A zdq6SsE>nq=5F_UEs0%=|h9sUk6BEp5lgwM^7VW3d(=nJn|7TqW!41a!q}AlB>*+-~ zO9hV{h&CbU?ewQwt*;XX2&KwLp8MPoCF)UXDp&xmaq5GZR>RYXxO;iyiias=qsnM@ z5otsIm_qBe)*Z%FnO&9KPkiiM;sbzv!*&*$?wvfA?VV6S6CEuwVV~EG5vPI>T%c;? z%00_9BUwAe)B$!@y5B~a-i3p{gfuoV%E4Wxtkp=krC?m#gVI^LL^c9&HoTS#xz2L8 zyP%I(3GDbGe*2*lgU)=mZaycEjq+{yN;h4*ds@!)Yiy>Ao)`&Jwe8TUq}DlCz*#A{ z3|ycO!*hvx>eoHhJ~#j|>Ok=8%oPQ+hf|v94a1UBh~&SK#JM$=B7E>igmQ!5)*9$3 z`8Y|wYT9rk0(E+GVPGiM#$q{pB4!)ePpqCN4`ff2ICxg6Z;6xhw=yU1s!Bz@dGPO$ zCZzE!nIS10@(*DEHHl16H%)$Yk+$Ktx%l+5SZ^D4;z0{J?0$b}p3_>rC;1cd9x`_L zOJ1kq+|JO4@3UG~13s~bJzF9OeCzl?P>IP}ldxR7*f3dK>sSN|Uv8JN~#DcN{kNcTipeXTx5IaWG z&T_OsyfJhb1vTO-2puO%tX^13^^qPJAgO4XQU5fEbrT$X&)j?Q909PRUC%0e-nJ^- z8Pdsqb&5iG7_etsUg1pef@sxyc`U9HhmWI^&&Sm2#%DP!ek6+vHww^|sC%e;JQmZI zc@E4<9v!3r1%u;FL7nQS*C}H}kGdJu>Tgt+TAz-L(r0_T#;)8H^cGo-gpM$2LkMb` zsXn8Hpcz9Y;uP4ljz^CdpGZi_+0A$u)Tb9<_KXO`+*xl?^{@nouXxv$7z9Y7R$1FJ zhcABT<&ua>TGs3@Ih&bUJn(_NJa97<+`%|UYlqC+eja|z>Q}wG%~o%09rXGLC8kGj zKp6#W2UWi=N-|^83q=%-Q)j zhv{U#*E3QQ45?^Dx>ZS|o}?oGQNV-wSCt?K%=BQn|J(JisWFJl&RIr6tu3 zx(WTCmG3PUIVCm6Uh{IRZ)2ucytGiP;#0=9>|+#)UGqFPKPv)wcQhz3X}i4Vx$l_Y zY-cZX6!m3h)~HRTeY)EZs#M0~^4AkjJ~gW+(D}}$JAPq|7mM-8MgD#@9!TWR>=nRm z*SzvhV7lcAT3MJvaCoG_zGAPl`9OO*=-u8BlgiUNM%RHj`4D{yrfAT6N;lXi(XgCe z216m#4~vgkTbJE#OZ23^s*Kose4tm!$+%*x$rhkAVF}$MW=B)y3rGK`h?WnA5eX(2 z+UiOiB7t)8xG?D6=&!EtCwNu3Jqr`#%GtTP4Cyl-MP?7@IM=w~jt`g~--YtAT$B4u zL;V9sc_IKa>i9Do&H12(c;xX`O+f9bDsjamj|DN_qnkv=v)RGylX1`COb5eq!u$N%A5L&1ncT#h91pMd0WglyS1w%em2C%OLj8@8S!&6RQuR*p35 z?t~lym>SI~AZh%1u@Livi<79FYw3aZN`7$(5~2xwdw@2&a04acsk!&!870fMqYw=M zy8+D7??5^67p?T>XTq=6bAT*OjY8w|eCEpe7d*>de{jpTecWH_d=|PyUdrae(8P^Y zZ}t#+4tgHzDEGxyt|v9riVEBX9%BsSjwj(A6t63~~#<@4p1(ExuS0rSO7ugObfp z*Xppmb34==Uvn!oIOizg%aS5=yQtHz1S$?Te<(rol{oL2s^w-h9>>sWWo=f?MAg6s zO-twR&s~izp?Rs>*p%8y^t_G>q}q`jGr;i?ujg0hKR$>&Pdy!&bG;oD1;s5-dtP@P z8%{66Ef*y0c@d!uJw*)s8XZyXX;X~wLNPno%%876+uuMK3FXs6vo^F}dJ0bx9Pds( z&!hKV`U+=nDo(^C3KN2JMFngR(`6C?Bxr8wjKUlH%gN@fTg-1WvWYdOB1wLPxy~={ zzr$FQI!%ShE``eG*YZ~?5Ox6-nKd={KD81jkGs}@^aq=zyl4LlP53AITih2qKbgqO z9T-XM7n^w0yZ9`(;HQMV5c%~b>%9sViwv_FNx|*bV$G_uVi6uoM=S4)-8PRM7yK)m z8cf(`l7vF#)vahgLW!!^($J`8j-c(L9dYhHW6`(55e2#j+f*Gtr~`Ah{^aK>e_ILV znJ=jrDW)|4{{RK6(3qnD3+ECteQLAcO54M|pSjxmrN6&6KyR{Ws5}r~7L3rFZ12EL zSL7{DW2|Nf>5EH(R<-^?QkN0^Sl2JU?p)t)O)3>?30iqjJH30>P=dWUV{_!2Dw@>| zr&c8?tIhjqPF|L+RhuZKAmYNjZDkoE?UmE&Fn#kfF^CJ3D1F;j4U6a+phw(Ak9ByY z^sD={zovgagQ>oy|MGkdVy!H%M+Kuw3F5_-ua#gZYB+d{36Hg7_vu@EdYAF*smQiu zLrsyPZ+54BSuIh8k-7jO`>E;xsO3s0;r|<5d!+@jwWfD#K7K4`XDq}J=#ml%8*nVj zY70p$V^SO=X7i(0mPLFvk7hQw?WfZ-TW5o%PHTn>BHn2 zbZ5=^QIHGfQ?F{t!4ra09YL8JqhV85Sx)_r!ADTd#!6qm2(&Z!9+DXwG=+qA`}%t_ z2d6zUg_<8+>sZ*Qh+1ZIbpOos==*F>b%`@z$kuE)3vnqcqcWOUf;R6WFRN z6E)rk)6Mr{2SWM^#@w`Qywla`LL3%E-y8^iWFZb zWSJ$9bGD{v>#DRfdra(PeZ0a)s}VM>59G>&HllmO{K_|IHtvI;x|V>a28k=3QnmA7 zPOH0f5B4p6ELzg8>t0f}b7l5paYB@y&9Iu_BF6Z}RMWI);El44=C1Nr!nawE!lpXb zotUNEIMys?>eb`A3IEOhDd?tQQ*xaLat_;Xw`SW^slC;^BkO}@b!!$)S6Ss7&d9zw zMnmxQVj^;I4k`3)1sUx_SoLqJJ2K-x=|2|nN@a6VL}hUGQM6y`oL1eSTK}9U^!xf$ zUNkGHiZK`|=R%fVKw9+h^JQ2Koi$k^9h+rl*V`uH(SQiO{`W=2&N|&|7`hU+m_ul? zZD!o-*p$5RZMXSB`5gV1l!1YPZWUZ%VP&SHi}NEEnR+-Co}yG!8JL6Y!B*N38Pyp6 zHh677QQaRI0LwoUO0O+|p=4ZyEd~@idk8M@Ry384+mM-L!cLz1Qjy`*^Mr0tU{wSo zdv8z<2542?32G&V$)qwFX5KxsIlZv6tC1=fSo|_}E3fOiNBXY9F37$(_o?=VZmx*v z*9lT0DXPpf{I~;%SU$!<$0WRGm!hSFW#esI*Z30ogGG6pL96s2H0;w+l6M<%aef<>I<|LsJtdPTrjHWk~u+ zax{L#TM_j(_LO41Ei$c=Lm{U2&7t(cl$OWygGdtM=3vrvuItWng@QB>p}gHNhsG~^ z8D?m3s=rbB)VHX7{*ldZEp7vI1x-7sX@d#%6{hsm`loydn?6LrJt41nM3|JC*CG%n z_cBm=XNiHofcr`x0dU`)XJz@NGri?oz09<8hsigQ>?%K!s~vboGwwrIYF`|1(qk;i z&N3(tv#J>pQ@@4B8ZeCY@BF!pNg|2i1e&@Cl3y=B#G@D5JU5pT`{}+I+UcV{aT=9Z zGaXG+MEvbW??2VQWBHaq10#Z@*|H(4yVDvxhYFu4@xa@jgxij^^Q5_)@PU>1D?7_i zW7=t3mrxp`EIjcfzE(0DvAhXO#V42#X9mbbZ6jUqUM%8rFmD7S45;`THRWFBnx>eZ zTotG?sXK8=sPU*XL3;@TiK@yj23-cKVie6Q+BcpjSvDwLue&t3qzqOC zPZ_vHZ*)2?<|smFl0JZ**!bSRKYdU8E;#`+HMNm%$qG0KS*`VnMyipg)P@g2hau*l`D6;D^dYmta zvK{;OuNZ=VJ*nOK|NY6oBvjwc%}rXmYoq@&aRKGD%Uu!VZ7*LQcbCCk8^glGdt7tw zSGOtl5J{keF+lFP5A?{3J+61SGZtNnOEolQI!Z%Hc7*tr7PMLvEN!mH;`|y{?wN;p z3m2sEJ7et%o$*YxUWAvAeA>vZMJx;`jz~e9uagb#fD-jgwUB&#eC)M+pJp;Amoc+Y zVQ5CGdpnK0#Ds)43r*U@VNeJJGML2CRr#WvTEi*t3ZL$PPTPjvA-t$iB6&r@FNmb| zqEwiCsN7?LLpUlKr;khDyVmpvS^d&g)&@=#JCp;x+jI3Xn|=p9 zbXh@8FA&Pqm~PkA`~XhWF+C2f66XK=>Ce8FKf5mujX z`O;xqb2k62oI*Xlt*6T;?I%&bP6n?`^pP%=4>ESH8Vws=_dhH^nb(Vt`4MM>O&*60 z4GpH#66<|uD+z`R4X%tn!hP(ZcR09>VeQb(s_N=ez50rRf`Tt!zLb<8vm=DEh>!Tj zuTNS|1kZ`Hzp#1zvN?}#@H{RuKmny80|ZCO*gE14Eb{W83_w0V>V;Rxk@6+TaH#H2fct(Ag9j}#RewCbxt={LkW2qx?NT<{wId5gHnED_= zfO&T(CW3Kj$@xd;;l!fnHFpMn{+#6O7i2J{kNGH0^jd~rOJ=5Mykbssv(NSA84V51 zQ8Pmy2qYwe%nGH{fVcYHC?r%{Pn8+ArlX>5P+F$y#EW$^mN$v*+w?@!_+8Zc>1u1s z62-IVd!8Mv1c#$IWB{We3+H?t2Txis0dHcj-5UT;aO9&&H;37}WEruQXj@5M#?zq> zr3=c(#YK-+^d+$7w^s34{cL-W=G$Vi^CJhBzo+fhipOGm9c;=lJ5II1=f_2D3J%?1 z8ULP-qei>M_(QCjoCl8{J^F0;jT0O}C2XLfA!*oAA%%ZVJP$L$xa#KhK7DySes;JN zlMH$XqK1rgKwB(cltkz1H@QbS%S^2^qt6TpU4%JfQ}RjB=C7(3D2@vCX4)6WZhw3P z7DReHj(s4~lT=T=a_fD{k%x z+KAX-6RRo%On4|U^XB$8rQw5jNdIOxaYJJxGWfd0JRWV1)?VsM6E1S|C65sO(``=I z0i4R!Rhx7Zx8hRQZ@Go(3FSh3-%E@JtL7)m-pX*#bFnlHP{FLNt#w-h{|emA~k z+rEgZhYugRy1H^UNzYRWFlv^#ucf(NGN6G7aT|lc(tWCPK0gCUP*>Gi^c$*-zM>XM z#T|QdeN)R<+DI~r7JCwCx-P?4Ra<)lUJOoD;QD6ZZY)O+DJ?Daonm~^-XKstzR`_@grv5rsvCj=B6ts%By3z*SXfK< zvRmp5Kl;$}>FrRut%1N#(g~>;jC$XrY^q@Im$GN4OA(eJnU1}mxd{dbmu!)_U(8jI z{k32`&nJ`B({*|#<6BIEV{QGZv5BFHyfKovI`{CU;o3@jBJ}5Q)`a+p|Ndyw7IQK?--kBq~Ur2kIIc%=!(n zS-a=QTT^BF@`k$S9Ryua%Iw-acoYVqDP$O9nf%H8;LxU2CGjt(7ZAOo@2X}YX&#YN zE)}usp^3#T4z@2~lvOx=bA(FbS){^C3nS7CU=;D#g28YDgYo z@+WteBV+AIj9jy|vAi_fp#ssN3NQlN{DmSvTpCrmB7su*CraH*8{0;gkm0KDCFv&8 zb4j`{SlwQhxku*i;AtoaGzjCYWjj_;XH0M}R78Yqtii((>MM)ru24#idu29QWLZa8 z5;ud$%}pH`IDqG8qGwEt%mj@^_Kp_gmG!W)St&87jXX$S3T(b$gOnCN#|sFYZzRBw zcxghyjXK8y-%PaeZ+;2R$qr46=4iDn1;J)h+X?y0Y`#5y8(R=LRz3#@E~WbS)DzeTC-I&ry*QcOZ+IL(l7H0AF6iQXF5b)DmA`*k!@yx-Gj?w@yNxjCwZW)~xP%15My{W27=aj2;&W?C zXf;olo!sIE#JB_sd;H5~7f*{hs21D_J?MF_qpRyWf1eei&=Q;m^|<7Awh5ju%}8za z+uodQ++||cNGS0%=dh*4-z@gwk)mRwr)aX(Q z?NNmja9E{-yOQLtQL$e$Oc3O+Y$Sra))?HyB=Z8bQ(;R!QPyce8R&06tP$a$ydmKq zB1h7s8x_}V>iWIa-180!khE|gqt4G{$;;hv+l5l{uWu#X*k{^o+v=*?W0*ZmR0)RrUxWjX>ojhPFzuX!08zFK-344E;U{olHr9 zSy9+%9oxg!G>Qr)(MR4Zx*U+(bkPYIvMIbf! z`70Zm@`RyG zJT!0TlW{`t9_S&ZVzfSJX=seJ2{|px=tM6*W#xgVC0K@O9@ z?@|qhjj_ft?`+qZPD&}+ZX<$;! z1F-B_I_+iu{RortF)FgzQ|@yO*mLK%Y5qScPp_{^d%a-f6WG?nJoznoh_=l+B9O=( zY6vcW2*#)umr7Ul z1FoQ>3%@*T5~0)T*!A9L2cx<2^;F!pGqK-&?-*f%U?1V{z3B#xhbF`HYhW~x?6TsG zq;q-~UoP6C!Nad$)YiNv(mKe+?#Y7h)_|_C5MwCQ$n-R?-}R;I)};0W5m5VY0-}J5 z`|E%r6x@ZAT6eNyNCn((Kh3{#L5fS`a0c^I%g7Zc#_!n8)m?P?eXcp&q4G7e8LPE- zHH@ABfzCuB9c9_sCN?$-Wz_iN*wwUJxI{seAftnyLgHaVJy<68qW*T9zuZn_FmjK| zuY2Zi&eq}Nv(gui^p8MilEB-uG|siz#C7!b9|~>>2la#68{hIOKEbO^R>T#;Pwar3 z&qbf*KByZV0PiYO+W=2cGQV4GG_oo61Ofu#M!&Z{&wPV8%4MBPI-Ux~a{8`c{t(oS zuT9c;c?aMrAY;JT8}&UvDW5<4t~C95ku)l$K?n53-Vvo-0I5-&-029@LmhZtqQV12SqC0E*}Ua6PUtn?{_(pCh5F;HA$kF!7xD&ZnA#9?RLGhV<@!D?t4OR_{=Lt$eebL0sS4*?Rukt-kI6C z8j{U6?d)W80K>^+_4zq?bH)g?05OUnseuWJWVX9HMZ%LwzArGWaQmUx%Art;|BgRv z-~G_pix#)F+_flhiUnx+Wh9!3)qCAs(4NulmqnnNpY85)<<#ZQBJ5+InaJU9Ytpar znE^wm`uzhYJ55JTq(hO5@jF+wH!q|+$3NM}v0tQE&M}yoY?sQD08QTo-*$t#YaML< zI7d8r#)4gN};V(74!vQTwn~Ru#lZ2vH16e*q(l=*Tp6`Zqj76a%YB!+a@pf zi5uyMR{9dWJUz?w>PKg1XQ!szjyET+ude~<|FG@>ZB!^qB)Xj@^U@nhR#Vc%&Ce%_ zpM1S{*0v_YuD<$3v#-VNT+OsLX&fay+igDd@N2cX_wLOiGlbo`H*N81Mi4~ABMH&bx%^T~H{ zL{FDaYK7`rt)E73s(JE$P~|V0wQuGXl%PD$+wkjtb#L48ZZp+;7~2|^?~i_FmptL; zW`i6)+rs?1Ts%I_w=JLk)iUEgw>{s*f@{l}dbe&a58^cWaMdl9T>Q2j?qBWf(VeOV zj|XES0-H2K4z-l|c73Mm&#v-H68=Bo%| ztxFi@P)umGhEP^kKh3_`xm;YUAbckP`s?#lFHKAaGpX_%i({qDfmtB*+wvWWiJ)WY zL#H149nNK<77-llS9*9r7>iF4Bp`||TTe~&=&%kR{@pcR@8VeDtA@k!o5CYr4xjxD zI;AgT&e!M4X|uIvDWGNSzZ+AHHfV&Tr=Q8M4N^{%fp}5>>d|3jm0jF7OC{0G+bt#X zcOSfIOLcRZ5?8!p2tkjj|C;rT8~;{~-qAA${z&Hv7KosrASESbKF3F$&k)lwQVJx~vz;kdY%+POZc7BB6Y1CCme$5GY8N+#|W76qlH+uOB>vf^Uh z3e%n}$!o+{N&{1&O&oz zef`<`NH#z;GrSzvhclCt$}bYs+I zsy|b$DbD}!2O0)8Aqfcp3@C+tFE!U^7r8k(ZDwl}R~sT9PfSgDF<=)*WQd*Jr>Oq{ z%t4mV#Bc>TOC^)*yZwN5fG?g5;qGTAE)+u@B6idXfgM0QH8YYU@ET~ zFd%hx^*3+oY^E!K!8QuHaby`C_A-{geiMyOy$Z+L<_rT)9Bmz)naN4ww;;xKDr4Ye z!@zkQi%!Pr(lgpUp^ojP+ZOqYkiUk8U>@5;R6F}~o4vk`QCY(0Xj`Nf^C4BgGMI!=uK8y?I^^W?WSs2FGgEpvy2-%E2%Nr> zLKB41MN9c{=(4U$6C1ijt7Che2D@mWcW5vGB?4?)T}MYpQ*&~5wvYGf>gp)|skNJ1 ztwD??%zBEYq5<`W9s}2qDd5-ERJoSAdgN@+2i#O1$E>2FkZV>6q5F~QDI&3{Nm#1T zd|%i^l2T{l;98;Q+iD|)S4R?@#ql42Tkn84NZ$okTwd^--AH6KVuhoRxiXExW@C$&S5l!)sdJb1v#$;o8Ul=x{eUC`_3DcNRu>os4v zxnRuw^y$%kbw;1g!PqAnPkv;8Lmj!&^WnkU%fWoD1#81bcr zh1vii90dYknh^1EX-lUlxC);{@yGr zL={a&YHBe|4n3K0$3krD7;VFFM9E-;t^-jhvNi;Wob?(qXCfZ z@NM=Oz7N8JI-xVqW(K4mE18ZC{?hS!VS&jvJErs`b0{2QdM+M}J>dPLP&sU-itjEp zgfv)RR<@@jl;rsGnKbnEo`r?QFb8Q6y{>2t&J-=m(89)LlK97K$Fvo zoFhmp5J&TqGzmYAxmAB4Nh7nY0&J<5wnP))rjqD0)wSQ??%V@6ib47Y;;=|DCLfpH z@9Iju5`1Q2NqTbcxx|khqw(7wj%sd1r4R-pyDDV@QH4_s{UtJF*V+ReqD}V6EGP0z z^jn_mcMW;Tt( zYpu=620V)@@3#-aW^`7;Zdd2WG%Sm+r_K)7u8_b@)dY;lQbtQlOZWm=dE{kcVIf1T z?ElG4ULH#W+mGAiaa*sKKinfrLCI3>k$@RX4t&G4-O<$Nqc(DLYpebnG06nsGtSuA zH7nf4x$iMInQ&8N8owMoMaJ?k8k)maQ~%x z_>*rWa+uQQ!S@TX(_crGY35n(?`!HK-6P1z$gm#^6oe3hvGKtP5$lI9Z0`1UcK64Y z2pqTj^D@YJ{uo~>HkT`8J!6HSDCROkz}y*Wlt(>@^x`nJo?QVMA4h!lL+WZdD^{Sl z4-_(-HEfe*6*Zg=2>2(kIOguZeF8bhVDxp*xqo}w@a|}@J%_w{^~!1#%9{RynYr1e zX9<_T9oyZ6zN%8U3AnyEzwq<(cMNP2qM@N}O_rtrc)d_9-!w@$ug*Or?PWa(wzR>? zUi6OtehM(FicNw=PzP3(Ua)l1;QYGkA?O(b6|i2GSq76u7P34MHx3~h<1Creanv$LZ- zej%sB$+-b!bRZrQjE+Sdx#{ZWcJWX}_|2DgHZ?Unilr(pwFrvx$(qyt&W$r)SHcD+ zK0BXk8gK(tUK@GTJWQfOv{NgjVtVGP%F}g!LCoIf$d|&nJnKb)-jg2|+2*Q;f=mI8 z5GaP_C}FQkSxh_}9SgF;--XhnSzucGXf?&y>OF3w&P{(<~{k zXCo(7p8#55e$bMrno^-?csm06VW{K*%GYji*FBU`En|J8dLLoO)y%#GMQO@gWB^r3 zX_YN$NZM(nhue{UqMbr?QdbG7@cY9)bAO40yX$xSuG8srgh%pC)1A6PD=*QFl%|3e z^f8ZdlDZ(tzxntS{NA?d6X2rFXJf+3!lyPi{$a^GfvT(0JLyi(hV=-gb=t97LvBQ1 zghtg(`Uw=bF_jIhhcAyR`ZF>DCUo5HZjrIG;3nR*l0!x8(j>u*)1fq_trROBu5iLz z9!e^!gbQhyihTjgM&}*Nf{(ln3TCU8YIf{8{S3@9$G-T>G^W$T6NR_WFw={lWgJ>p zIyqYH<1ZFZuFyfm5aJDucYjL*ik+EhX zYJLK*k$&UA~6orW7-l&!@)6?!q5WQh!pRL{io6;wtSTDxT8j6Q}c?dk<}o@ER4XgRP1HwlN zp(xU#)jvt_xc&4g`c5Uqk*YI(Ulu(0sT$Hn)ELNpDF3)TAo2y%9XxyPqkq0LW|3)l zZ_!-bLG@Fq-|4waT1$xKjDZ8K-)a?~^NDz*K5T1aV`FD$aBjN*-6~Kg23_Sn{Jp@_ zrC}ieu~E~~uX=QTfH2{U}YMy@8N6M%# zQkyIroYv6C=BLS*2j94|@I__~A z>pQGDG~^89STmcbc|~h)dOA)J%y+3nGqL&%r|)Up(SF+^lJO)N(k)FdbkckDw|dD3fBedGZkpLRd{Em{b(dxqVd??yCsxSYVX%OPX>MD!Cq z#&3Tx4P!T{_SF;d4`ut>xI!b~yr1wLFZi-PunUKR6Sj-Nl7(gYnAIL7r-SX359k%D z4EBvTgU`hT#Z20pC!hwr%i50KXp)+I&IVixSU@KHHfaCMf$7mB<&mg`%`p`qJ!gRQ zI=Oyo^Bhwxj{P<~RFSE{W4u}2b2_q@+lM=QBb!W4Jq5c+kCH`+`X#`yV>f z`trz4Jq=2Wp-@_O-aNE_;C=1C_UrU#q03kp8}9wTl$MCF(Pz+JhAe0A2@{W%#S6UH zth{J^!4E}w>NbOV$h-^0j;We$mZBV8m9%IOBy|}@`*1q@D|oGr4jG#3KV5LOlH;v~ zxGM}(3ykB9TBkTShU<2{vI_jfLBg+$f#0b4+&7z8<>$LlC4w~F2W;n%>m>Ej# zZ?Af9Kk2AL(KycL_M8UbUlLQ43ywY*8J=M8ry&MkwhEM$5qQR~o+;jtG)pl)^_irm zaZUnQid{dLeev`a-ORIjJ#k+!U)8iH)>D-hdIYMK@nNlx`Nb)>hz#okl;7v%!{4fq zv^dVs@SXdRhPMM5yg$PVq)t3#p`SOoUi50YY-E~s#NwFWrLuj1%im&M=7dTEDbYlq znMlq`1C0{#&;N9hUlPpC8+1L_32g})rWIC{O>$pg`2bhR7=?^3rei-R=2Q+|;?(yl zNtG+9i50SFK#-jY7QSigVjtMD3!=5EfwOK*8Nc~k1Ix}l3e^byz~|LzLSRqZ9~=>= zBrmm?Fz=jl3Qw{_n~UY$8nc)~yvYH<2ue3NAbFw{`#H~+1 z;C!tm$dP4Vq%605XwW>9LquD$7BL2$Z~#%TRC0!1^69Hr^9M|6*ndyPI}Cv~mw!C#R& z~f8jG zH4=MRjJ6tfKX5~!I&%TiHO{}J{XcPu1}Z`QOD6|`ivQY2LZCK=zZB5_2VPAgY(~s3 z3H;Kyl?|#2Ap$q;BNs_e5ja-n*9vQeboj>^-gBg+>91!_e_iEaUe8TeJB#6gsQ(e~ zW1d!hWHN3(k&USP>O!y)`yn=TMkScj`ds{^m`F%4{pLV!*ITYjnABb|a58IBW`eLv z%1L@KpG%e$1r+s1CWbwp`TG2u=dLau{~v$ZLNaur!ay2f(`tqSdh%}@t>wd;n^ZOL z#rUqt2WQuU-nn!)z>klPT>e~@?`NVE%|W+X@T53@qQskBA1C(cqFBq$XQNpzL|aIi z)Cc(t!pH4(Yx}$o42H~QYifWK3&=dVzXotgcV|OmV^5N)X!2{Uaj0Z1knRxp=4pWu z6NG`dc=r9i<=9nl4)f_KhJk;$V(KG+T#L=T@EMNfDTm5!1k^Endk;t1`*G_T{NLA` zPx3~Z57ZOrJZCqKCp;I|ullqkJ(rCO4WD`#oPTbI>V;pHR|-b0qc^Wy_I8|b(2rPa zkOHaQWT5{_8A8mJ>}_Cc04+$HKB>aN!P%Xz%+JZm0c>woRaG@LkdvMHfq?!(78paP z9E}-RzAI1ci69>eZg|%iA|a$@Khxf)4~RY>oPTy>ac0`xz4vGsA)%qgMMY35VWsc7 zlY5z&nZ~mnf@qzGY%NPHDamE}_`inHOrm1q0Auat^kOWGKnSAfy{ z;lb6z2E#1{y+!-oUTn~bg_D3I8G6F}u9i(fmHc~kzG8|q1Mbg9pnM4ELNtB!L=yAT zYo^=&{15bLVk^;daqFM;1ej&SAo-0uucR_aYs!JLg4DH8P z6j&$=L_M>x&@xZn*49>EpVDV4W&zMZm6>M|2t!RxDHO|%(cJRpUt|H8sv<>xM+J`9 zm_f|H#4dh*4_q6{Kuk=~V5yEwO=%ezl*y;u*TxQa)(BMWwl9OSbwHil`>Bf4c`4W3 zNmDpR8Xm2fKcxeZpl;rjm9C!}P4ejaM= zYu~hgw{XF0w>dv=AFv{5sj5~0;%>24c~RbPEe-Gt8>py=+R-Ffu8>Mq@j;m4b}%t=pkYb~uP4Bay` z!p&>i*4N;LnCAjd0W;GB&^RWt%Hu$aJ0@&?BNm%m?$pDYwNT@|Y>-G5-C)2UQr_M^A%gw-i z#5xD0f`=-FvZ~haikPrZ&D>0g4QXMF9maZ z3TElY{PYlH%2wVGJowUuUQ<=lu&1fGlr)P5l0mNeHm_y`WKmJk_duMJlao+JhHi8~mK3~cy;SdP zSF>}0S=-wi=I9UnkWF+x70AC*xT$;!(JIp$AK(z>dQ1F8u|MnMh|M!yo?&5uvQn!`fxF;WJg3!6d_#Z9-=F}ZT ztKm>nN|P7_$TFh@UZCWIK!6I_9bSjoi7Wle~wjDjjTN(2E7ycEq0)P0-RmNh0uisgM+5U z#YMntrdX2xj_h*pJC5viffArzG2MlANLl2MH2Pk7u8;!0cwjLN>j;5sXlgn|(L=s1kLw=a13<&=_mJMUHPOyiYj?OHUkOCxiZL#`}N_#3wTpU~AuCvvm{5p6NC)v=`v6wpL z5T&Y*Up&8|XoE&kZXJ^>dUY@D7n(vsLdd!8*3T#!)ZL9j3}TaPDofdEH&bxg{i$-Y>c2+Q`4&iwTYGQa#Slrkn0K9Zkl zopt@R3BGS#^qr&E}uSy0A)IsQd}Uv;{N4UrKd#n`r`&R z3}y(kwnG_SBXd}JP*Ra*trnj-Pyya8aN zc!e|4r8+cHVahjWd=M9=NT_@X?ixyc8PTlzOm|Ybjv?N3utYqG>iN(Np!Mw;-P&9E zg>rkEBJ|bN)ZRm+uuIK=ybs`cvu`=0EsF;&02xp!-&12Cy(FjAxR$;n+Z#7Y@VY%L zIe*$AFIt#QGCx~gS=f{DWd~H*bCdVvWdEh*f`J3`mnQ;ki2QR7 zA^#8~oy^p!d$B>U8__R*x!Lt&8#c;HdXPxx?X09NrMoJDwbazIX}3=ogGWb4ROy%g%kg-Xf;5N~%bgjR(&la-?yC6*C8;=sG#?hXmT8uxY&5VWaSF&Zg(I1cO+hc+vQE(e?ZFo&*t0~L2NBZTzjd(}b7rV{@ zz=k3sAyGqDZI--C?1rIW#}oiLUcT?U$M~?1k{{xIzL5`XsUu}Yza9aL&x6UYLVd$? zy!3w=Y@-w^(1P7m8^>d>8Pf3AAsUgJ54aW{PmCL!JQt=3@D~cqx27@)Nqdt9CxKlw z6{^e)s_uGa3s1!n)F&XmKXH+o!%z}9a9I4NaqIt@oOZnVVbi<8N2j3%dMEQoWQtL9c+#oSAkN=Aj0p54x0|8`S7IDBx1AGiwTwWithM4U6RaVg9fnqP6;l*fga-I z3w+(ju)C)>LtbGdiYv-;pW`dLX}iy-N7b_QVa@19Fkq?ie|!4gp#yougW!XMgO(N{ z?MTwgB?+F$5BhSSttmp&oOtX8#)j&;)!U3<1g&YY?)z+NI{ZLQ$H4=Ei57Z@*nIn@ z3%#j=dG6@U%*-V|KS<>AAH0n>)AMq&+>kY0F7^JcbI(kD4wcd9Rx-p~0)E@2g7MZb0)UL9M#^fD?bp^7)Bv#pKrh8iU|^tDsgCQec@R5M-a2Kk3y< zTNohay)-8PTwVXKvsF>Rd+~pfUIRj=r>EyXu1b;Z?mP~_Wp!}xw`~hh6KER2(p;1C z^NNGdu}1y>oz3VraDE#=pE(zs{3T?U1VG5Xi;If`5Z=D^3Icd=qiN)cnRPe;_X{dj zZ*Olwi;Wq3rQ7ZTuk)(+uW9p&Hpd#kGy~|&fW@-+1BSvRuzPTofe6o6&WP70HG;jm z)mkfXZzKBzIjsiZpEqyb0LBwt-A1pIoz>OVZ0QJytE@=ZqP9~d3scJZfp zB7$&C7-^Gj(?AuAPPSf~NEJ2hC7f`DooqEduhR-xJJ2m|$>uX3Of3ZLI1CI7OiX$; zHrhb4x%%@I>7z&R7M}~`bmfLuYfg?S;QjE8c}ku4pL>T))fd0e0>+`71fW#QK51RG z11QzHCa@{d^DIm(Gl5~@vO0URDnP$ED~lVK17mG_4>x=I?}%3AKSaw5I5k2lV$XoO z#+Zc>Lr;Cc+k-#|!`N_5fb22=wTCiypo$AF5X!~HHQXX~Scs))IrM#NRw0%6cAz;gqX zsW37ybZ?uA-cw5DQ31-XZb+UYlpQZ$|6xwPyt2iIYEQ?`1T>V@mxvrGg;M2i+*XTR z6_j&(7v0&W@Gf!*hFe(UZ;$Fn|5%LZEUj&ACpb1znhOfnPxqIOJOPIsaNBi|7>+NQ z85$xghlIAyvZ>k$|6`|-uNJU)(yUpT09`5{bD!iOt;zb4B+$wE(tJ@Mo<%q70|G^} zYs*GJ8AdQ$n5v+mbV9*jP5p|7UGT<(%>?ip5&S#95uSp%`5KTM25utd;utgPbRdrm zhzN(V9I6cu$+?FAV+zC+qVMJ9C0C9A-|R+JSWI<_L%A;gRr^JjZZ5Ds%zuqs0!B_j zp$C|b0Jp~mx*_>bw|)N)n)?wqrx5^Z%IzgSL09m+_3Cs29^Cm>zt(gQZjS(DgX>nA zL30tw1}8T+Ku5;>{F%NmKvs2OL41r*1fM~IHIIS$#+hQyhO<9?htg**sbI=-$+Ijf zl*)(&;C2UrUjGKL(g|^lTJdplaj~)EKpEQPZ7WAKo=e5vMh-hQ1DAY<;8WLAi~`g}@+ zao{}UNC$8%`E9)Y(L)SZ00OS5MhPgM%N`va9czPWDR1U2ZEU=^tEXOw0o82->4Fy+ z!l$AR7t~U~hdDig;@Dl%=&vu!?mOSRmsc40`ECd3Od67>+gs0XApkgaYf6LCVR=u^2QJtWohg z`L`g*Zy8J)a46_7n0~nfYx_@`i}V0zpaeHL;2&aPZi3s&ff{gZ0JE;G zsR7vKucM<9h^(b6=Qo7sR%vo_^1I~ourwY;#U>&(O(xmx?d^u101|%M3iy5vJtBE& zp$mHR36H;7yB{#?(URPH*#0)zsD%J^kX@Kr^9Ps;vH+eX8wC~_D0pPLT6jc87TrOR z`EwqCm2uw@1BulN^`W@@$^apep&!HSyd@-*Qz|h5R@T#G9%MLxA20FS@0iILHC^Z` zD=aLernfa8O3!`t#rXT(t3le6Ij>Jdb#5>!!w2o8UYS?lafF%Z>18*pIPVqG1`m#8 zOPeJLgQW(5ax%5E@WiY!l_C;q@jrf;I|9VtWEZA)=!DOLg<{OXEOsGjdQ#7f47~yQ z3IzHAd>F7gC^bdF0l~09mcPY4tE%bc7O?c}uezV^;@7izHcUBi%hFzjCy;NH zSgO8UJcMaS>G(gSg4-Ht#CH%%t zs?P%W2w*HQsoSVM_+5g(Oh%rWR`q=cEeP#7(*ptXJRPH5+3Dm&%gPUB)^f-rOeT+} z>TgVxRI?m_%>A#IZehG(_B1Z3)|#VN+0a@1zE` zq2A`uU4dVMjwOjQzp3H_GPVaHjcx>@^8zw~gc%ZO?>?b`K&A?R@ICMdGTKD>T}lEx ch3ws+ + + + 兑换码添加 + {% include 'system/common/header.html' %} + + +
                +
                +
                +
                + + +
                + +
                + +
                +
                + +
                + +
                + +
                +
                + +
                + +
                + + +
                +
                + +
                +
                +
                +
                +
                + + +
                +
                +
                +{% include 'system/common/footer.html' %} + + + + \ No newline at end of file diff --git a/plugins/giftManager/templates/system/gift/edit.html b/plugins/giftManager/templates/system/gift/edit.html new file mode 100644 index 0000000..30ac3dc --- /dev/null +++ b/plugins/giftManager/templates/system/gift/edit.html @@ -0,0 +1,91 @@ + + + + 兑换码编辑 + {% include 'system/common/header.html' %} + + +
                +
                +
                +
                + +
                + +
                + +
                +
                + +
                + +
                + +
                +
                + +
                + +
                + +
                +
                + +
                + +
                + + +
                +
                + +
                +
                +
                +
                +
                + + +
                +
                +
                +{% include 'system/common/footer.html' %} + + + + \ No newline at end of file diff --git a/plugins/giftManager/templates/system/gift/main.html b/plugins/giftManager/templates/system/gift/main.html new file mode 100644 index 0000000..c654202 --- /dev/null +++ b/plugins/giftManager/templates/system/gift/main.html @@ -0,0 +1,205 @@ + + + + 兑换码管理 + {% include 'system/common/header.html' %} + + + +{# 查询表单 #} +
                +
                +
                +
                + +
                + +
                + + +
                +
                +
                +
                + +{# 用户表格 #} +
                +
                +
                +
                +
                +
                +
                + + + +{% raw %} + + + + + +{% endraw %} + + + + + + + + +{% include 'system/common/footer.html' %} + + + \ No newline at end of file diff --git a/plugins/giftManager/view/gift.py b/plugins/giftManager/view/gift.py new file mode 100644 index 0000000..cc4dfd2 --- /dev/null +++ b/plugins/giftManager/view/gift.py @@ -0,0 +1,142 @@ +import os + +from flask import Blueprint, request, render_template + +from ..models import Gift +from ..schemas import GiftSchema +from applications.extensions import db + +from applications.common.helper import ModelFilter +from applications.common.curd import enable_status, disable_status, delete_one_by_id, get_one_by_id +from applications.common.utils.http import table_api, success_api, fail_api +from applications.common.utils.rights import authorize + +# 获取插件所在的目录(结尾没有分割符号) +dir_path = os.path.dirname(__file__).replace("\\", "/") + +bp = Blueprint('gift', __name__, url_prefix='/system/gift', + template_folder=dir_path + '/../templates') + + +@bp.get('/') +@authorize("system:gift:main") +def index(): + return render_template('system/gift/main.html') + + +@bp.get('/add') +@authorize("system:gift:main") +def add(): + return render_template('system/gift/add.html') + + +@bp.get('/data') +@authorize("system:gift:main") +def data(): + key = request.args.get('key', type=str) + + mf = ModelFilter() + if key: + mf.vague('key', key) # 模糊查询 + + data, total, page, limit = db.session.query(Gift).filter(mf.get_filter(Gift)).layui_paginate_json(GiftSchema) + + return table_api( + data=data, + count=total, + limit=limit + ) + + +@bp.put('/enable') +@authorize("system:gift:edit") +def enable_api(): + data = request.get_json(force=True) + + if enable_status(Gift, data.get('id')): + return success_api(msg="启用成功") + + return success_api(msg="启用失败") + + +@bp.put('/disable') +@authorize("system:gift:edit") +def disable_api(): + req_json = request.get_json(force=True) + + if disable_status(Gift, req_json.get('id')): + return success_api(msg="禁用成功") + + return success_api(msg="禁用失败") + + +@bp.delete('/remove/') +@authorize("system:gift:remove") +def remove_api(_id): + if delete_one_by_id(Gift, _id): + return success_api(msg="删除成功") + + return success_api(msg="删除失败") + + +@bp.post('/save') +@authorize("system:gift:add", log=True) +def save(): + req_json = request.get_json(force=True) + + data = { + 'key': req_json.get('key'), + 'content': req_json.get('content'), + 'enable': req_json.get('enable'), + 'used': 0 + } + + # 效验参数 + if not all(list(data.keys())): + return fail_api(msg="参数不全") + + if not data['enable'].isdigit(): + return fail_api(msg="参数 enable 错误") + + try: + db.session.add(Gift(**data)) + db.session.commit() + return success_api(msg="添加成功") + except Exception as e: + return fail_api(msg="添加失败") + + +@bp.get('/edit/') +@authorize("system:gift:edit", log=True) +def edit(_id): + gift = get_one_by_id(Gift, _id) + return render_template('system/gift/edit.html', gift=gift) + + +@bp.post('/update') +@authorize("system:gift:edit", log=True) +def update(): + req_json = request.get_json(force=True) + + _id = req_json.get('id') + + data = { + 'key': req_json.get('key'), + 'content': req_json.get('content'), + 'enable': req_json.get('enable'), + 'used': 0 + } + + # 效验参数 + if not all(list(data.keys())): + return fail_api(msg="参数不全") + + if not data['enable'].isdigit(): + return fail_api(msg="参数 enable 错误") + + try: + db.session.query(Gift).filter(Gift.id == _id).update(data) + db.session.commit() + return success_api(msg="编辑成功") + except Exception as e: + return fail_api(msg="编辑失败") -- Gitee From c5b70d90fb3877e06783b765462620c728eefd76 Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Thu, 30 Jan 2025 17:04:30 +0800 Subject: [PATCH 35/36] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E4=B8=8E=E9=A2=84=E8=A7=88=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- docs/source/_static/feature.png | Bin 0 -> 335880 bytes docs/source/welcome/instruction.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 docs/source/_static/feature.png diff --git a/README.md b/README.md index 4edbbe0..c052033 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ 开 箱 即 用 的 Flask 快 速 开 发 平 台 - [预览](https://pear.lovepikachu.top/) | [官网](http://www.pearadmin.com/) | [群聊](docs/source/_static/qqgroup.jpg) | [文档](docs/detail.md) + [预览](https://pear.lovepikachu.top/) | [官网](http://www.pearadmin.com/) | [群聊](docs/source/_static/qqgroup.jpg) | [文档](https://lab.lovepikachu.top/document/pear-admin-flask)

                @@ -24,7 +24,7 @@

                - +
                # 项目简介 diff --git a/docs/source/_static/feature.png b/docs/source/_static/feature.png new file mode 100644 index 0000000000000000000000000000000000000000..3cf8e3052acc61d4ab4cf2e839bc411a85927f34 GIT binary patch literal 335880 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 literal 0 HcmV?d00001 diff --git a/docs/source/welcome/instruction.rst b/docs/source/welcome/instruction.rst index fb64bbf..a10b226 100644 --- a/docs/source/welcome/instruction.rst +++ b/docs/source/welcome/instruction.rst @@ -39,7 +39,7 @@

                nrZ8BP>NiPI)JWELK+Bmwi=T) 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≤D%A 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 zⅈP;g95w8DrbXS=ut|Y%XynrT@yPb1#R%j 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

                - +
                项目简介 -- Gitee From 23db487356f88834be0048513b39911a99974afc Mon Sep 17 00:00:00 2001 From: wojiaoyishang Date: Fri, 31 Jan 2025 10:51:11 +0800 Subject: [PATCH 36/36] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E6=9E=84=E5=BB=BA=E7=AB=A0=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- applications/config.py | 2 +- docs/source/practices/backend.rst | 2 +- docs/source/practices/plugin.rst | 4 ++-- docs/source/welcome/docs.rst | 24 ++++++++++++++++++++++++ docs/source/welcome/index.rst | 1 + 5 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 docs/source/welcome/docs.rst diff --git a/applications/config.py b/applications/config.py index 6f5b4a2..b5369f0 100644 --- a/applications/config.py +++ b/applications/config.py @@ -72,7 +72,7 @@ class BaseConfig: MAIL_DEFAULT_SENDER = MAIL_USERNAME # 插件配置,填写插件的文件名名称,默认不启用插件。 - PLUGIN_ENABLE_FOLDERS = ["giftManager"] + PLUGIN_ENABLE_FOLDERS = [] # Session 设置 PERMANENT_SESSION_LIFETIME = timedelta(days=7) diff --git a/docs/source/practices/backend.rst b/docs/source/practices/backend.rst index b5ac66f..a2ebfd5 100644 --- a/docs/source/practices/backend.rst +++ b/docs/source/practices/backend.rst @@ -20,7 +20,7 @@ | .. image:: ../_static/Pear\ Admin\ Flask\ 启动流程图.png - :target: ../_static/Pear\ Admin\ Flask\ 启动流程图.png + :target: ../_images/Pear\ Admin\ Flask\ 启动流程图.png :align: center | diff --git a/docs/source/practices/plugin.rst b/docs/source/practices/plugin.rst index 0d17a7f..aeec736 100644 --- a/docs/source/practices/plugin.rst +++ b/docs/source/practices/plugin.rst @@ -3,7 +3,7 @@ 插件功能旨在最大限度不修改原框架的前提下添加新功能,并可以像程序原有框架一样进行流程注册,而且不需要修改任何程序框架原有代码(仅在配置文件中设置即可)。 -所有插件放置在 `plugins` 文件夹中,项目提供了三个示例插件,分别是 `helloworld` 、 `realip` 、 `replacePage` 和 `giftManager`, +所有插件放置在 `plugins` 文件夹中,项目提供了四个示例插件,分别是 `helloworld` 、 `realip` 、 `replacePage` 和 `giftManager`, 分别用于示例页面的注册、修改 Flask 上下文、页面替换和新功能接入。 像项目自带的用户管理、部门管理等基本功能属于程序自身的“功能插件”,对于大多数衍生项目来说,多的是修改字符串和删除部分不需要的功能, @@ -18,7 +18,7 @@ PLUGIN_ENABLE_FOLDERS = [] -而在目录 `plugins` 中,你会发现存在 文件夹名称 为 `helloworld` 、 `realip` 、 `replacePage` 和 `giftManager` 三个插件。 +而在目录 `plugins` 中,你会发现存在 文件夹名称 为 `helloworld` 、 `realip` 、 `replacePage` 和 `giftManager` 四个插件。 比如我们想要启用 `helloworld` 插件,仅需要做如下修改: .. code-block:: python diff --git a/docs/source/welcome/docs.rst b/docs/source/welcome/docs.rst new file mode 100644 index 0000000..18070d3 --- /dev/null +++ b/docs/source/welcome/docs.rst @@ -0,0 +1,24 @@ +构建文档 +================== + +本章节讲述如何构建文档,构建文档使用到 Python 中的 sphinx 工具,需要使用 Python 进行安装。 + +安装必要依赖 +~~~~~~~~~~~~~~~ + +文档位置位于 `docs` 文件夹,所以先切换到 `docs` 文件。 + +.. code-block:: bash + + cd docs + pip install -r requirements.txt + +构建文档 +~~~~~~~~~~~~~~~ + +使用 `sphinx-build .\source .\_build` 进行构建文档。 + +编辑文档 +~~~~~~~~~~~~~~~ + +如果修改文档,请在 `source` 中修改并重新构建。 \ No newline at end of file diff --git a/docs/source/welcome/index.rst b/docs/source/welcome/index.rst index 1cf9565..b7db015 100644 --- a/docs/source/welcome/index.rst +++ b/docs/source/welcome/index.rst @@ -9,3 +9,4 @@ update quickstart migration + docs -- Gitee