diff --git a/Projects/README.md b/Projects/README.md index 55c6da00..c6103360 100644 --- a/Projects/README.md +++ b/Projects/README.md @@ -1 +1,119 @@ -## 请在此创建个人作品目录,最终提交 Pull Request 至官方仓库。 +> ## 你说的都对:**Klive-exer** + +## 项目介绍 + +### 项目背景 + +    随着人们生活水平的高速发展,智能交互已经不断的进入人们的生活。酒店服务业作为人们休闲娱乐的重要载体,对生活水平提高的实际应用和发展提供了温床。而且随着人工智能技术的提高,《智慧酒店的现状和发展趋势》一文中指出:发展智慧酒店可谓是酒店业发展的必然趋势,智慧酒店的发展除了是酒店自身更久的生存下去,更是和旅游业、城市的飞速发展相辅相成。 + +### 项目内容 + +- 本系统为提高酒店对客户的服务,聚焦于智慧酒店中的健身诉求,着重以私人虚拟健身教练为主,具体研究开发如下: + + 1.系统计划应用CMU所提出的新型人体姿态估计算法——OpenPose 姿态识别来改善现有酒店智能化模式,从健身方面提升客户体验。 + + 2.系统为 Web 应用,基于传统 SSM 框架和 Flask 微型 Web 服务集成功能,并仅依赖单一摄像头实现对人体姿态点的检测,力求降低对硬件设备的依赖。 + + 3.系统用户可以通过选择不同健身课程来查看相关具体信息,并通过深度学习算法将标准姿态与用户动作相匹配,给以相应的检测反馈,同时还包括健身后圈子交流共享等服务。 + +> 部分数据来源为keep,仅供个人学习,非商用 + +### 所用技术 +- Mockplus摹客原型设计工具 +- PowerDesigner数据库设计工具 +- IDEA和PyCharm开发工具 +- SSM组合框架&Flask微型Web框架 +- OpenPose人体姿态识别开源库 +- 流加载、SHA1加密 +- 融云IM即时通讯SDK + +### 模块简介与视图 + +- 用户登录和注册 + +
+ 登录 + 注册 + 找回密码 +
+ +- 用户数据收集 + +
+ 信息采集 + 课程选择 +
+ +- 课程模块 + +
+ 课程模块 + 课程模块 + 课程模块 +
+ +- 姿态检测和训练矫正 + +
+ 计划 + 训练模块 + 训练模块 + 训练模块 +
+ +- 数据统计 + +
+ 数据统计 +
+ +- 圈子交流 + +
+ 交流 + 交流 + 交流 +
+ +- 个人信息 + +
+ 个人信息 + 个人信息 +
+ +### SDK使用 + +在圈子交流模块,使用了融云IM即时通讯SDK实现了对每个课程创建讨论组,用户可随心交流。 + +## 商业价值 + +    本系统研究既具有理论研究价值,也具有重要的实际应用价值和现实指导意义。系统实际上就是为解决“酒店智能化低”、“硬件设备昂贵”、“重建设,轻应用”等一系列问题而立意。在市场应用方面,本课题具有相对完整的系统和管理方案,调研并结合了当地多种类型酒店对于人工智能的需求和意见,由于私人虚拟健身教练这一市场空白,系统能够为现有的高端酒店提供低成本高回报的使用价值,对丰富酒店健身模块具有极其重要的指导作用。同时系统实现了人体姿态识别技术的应用落地,通过深度学习算法将识别结果同功能相衔接,也具有参考价值。 + +## 不足与展望 + +    系统目前仍具有一些不足,主要表现在算法应用方面。在姿态检测模块,由于系统需要不间断的向算法服务器发送http请求,并且后台算法需要启动模型处理,反馈给前端的画面展示不太流畅,但仍在用户接受范围之内。而对于课程的添加方面,本系统由于设计原因未给出相应功能接口。 + +## 如何安装和启动 + +- 项目为Springboot项目,需要提前有maven环境安装,并且导入项目后使用pom导入依赖包 +- 在sql文件中导入数据库 +- 启动springboot后,浏览器输入 http://localhost:8088/Klive/main 进入主界面 + +## Q&A + +### 1.为何我无法启动项目 + +答:项目本身拥有众多jar包,并且使用Mybatis与后台数据库相连接,需要在导入pom所有依赖后,在properties文件中修改数据库连接信息等。 + +### 2.为何我启动项目后,无法登陆 + +答:系统本身具有注册功能,为真实的网站项目,需要先进行注册成功后才能登陆,**需要真实手机号**。 + +### 3.为何我登录成功后,系统大部分显示没有内容 + +答:为防止数据泄露,数据库文件中仅包含有数据结构,不含数据,需要在表**class_info**中添加数据 + +### 4.为何我无法使用项目姿态识别功能 + +答:项目算法端部署于flask上,由于算法模型巨大无法上传github,所以该演示项目中不包含实际算法处理。 diff --git a/Projects/images/gr1.png b/Projects/images/gr1.png new file mode 100644 index 00000000..ce7ddac4 Binary files /dev/null and b/Projects/images/gr1.png differ diff --git a/Projects/images/gr2.png b/Projects/images/gr2.png new file mode 100644 index 00000000..879c90d7 Binary files /dev/null and b/Projects/images/gr2.png differ diff --git a/Projects/images/jc1.png b/Projects/images/jc1.png new file mode 100644 index 00000000..dbc3dbe5 Binary files /dev/null and b/Projects/images/jc1.png differ diff --git a/Projects/images/jc2.png b/Projects/images/jc2.png new file mode 100644 index 00000000..f1d72430 Binary files /dev/null and b/Projects/images/jc2.png differ diff --git a/Projects/images/jc3.png b/Projects/images/jc3.png new file mode 100644 index 00000000..f2b0a8f4 Binary files /dev/null and b/Projects/images/jc3.png differ diff --git a/Projects/images/jc4.png b/Projects/images/jc4.png new file mode 100644 index 00000000..03a92383 Binary files /dev/null and b/Projects/images/jc4.png differ diff --git a/Projects/images/jl1.png b/Projects/images/jl1.png new file mode 100644 index 00000000..66b3760a Binary files /dev/null and b/Projects/images/jl1.png differ diff --git a/Projects/images/jl2.png b/Projects/images/jl2.png new file mode 100644 index 00000000..129069bb Binary files /dev/null and b/Projects/images/jl2.png differ diff --git a/Projects/images/jl3.png b/Projects/images/jl3.png new file mode 100644 index 00000000..96cdc50c Binary files /dev/null and b/Projects/images/jl3.png differ diff --git a/Projects/images/js1.png b/Projects/images/js1.png new file mode 100644 index 00000000..57a9590a Binary files /dev/null and b/Projects/images/js1.png differ diff --git a/Projects/images/js2.png b/Projects/images/js2.png new file mode 100644 index 00000000..3097bc5b Binary files /dev/null and b/Projects/images/js2.png differ diff --git a/Projects/images/js3.png b/Projects/images/js3.png new file mode 100644 index 00000000..2956c574 Binary files /dev/null and b/Projects/images/js3.png differ diff --git a/Projects/images/k1.png b/Projects/images/k1.png new file mode 100644 index 00000000..66199678 Binary files /dev/null and b/Projects/images/k1.png differ diff --git a/Projects/images/k2.png b/Projects/images/k2.png new file mode 100644 index 00000000..9132ff59 Binary files /dev/null and b/Projects/images/k2.png differ diff --git a/Projects/images/k3.png b/Projects/images/k3.png new file mode 100644 index 00000000..b3325893 Binary files /dev/null and b/Projects/images/k3.png differ diff --git a/Projects/images/k4.png b/Projects/images/k4.png new file mode 100644 index 00000000..ff96a2ff Binary files /dev/null and b/Projects/images/k4.png differ diff --git a/Projects/images/k5.png b/Projects/images/k5.png new file mode 100644 index 00000000..824d6d28 Binary files /dev/null and b/Projects/images/k5.png differ diff --git a/Projects/images/readme.md b/Projects/images/readme.md new file mode 100644 index 00000000..ff3ef51a --- /dev/null +++ b/Projects/images/readme.md @@ -0,0 +1 @@ +这里存放了介绍中的各种图片 diff --git a/Projects/images/tj1.png b/Projects/images/tj1.png new file mode 100644 index 00000000..bbc02e0b Binary files /dev/null and b/Projects/images/tj1.png differ diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/.gitignore" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/.gitignore" new file mode 100644 index 00000000..a2a3040a --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/.gitignore" @@ -0,0 +1,31 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/.mvn/wrapper/MavenWrapperDownloader.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/.mvn/wrapper/MavenWrapperDownloader.java" new file mode 100644 index 00000000..a45eb6ba --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/.mvn/wrapper/MavenWrapperDownloader.java" @@ -0,0 +1,118 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed 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 + * + * https://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. + */ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/.mvn/wrapper/maven-wrapper.jar" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/.mvn/wrapper/maven-wrapper.jar" new file mode 100644 index 00000000..2cc7d4a5 Binary files /dev/null and "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/.mvn/wrapper/maven-wrapper.jar" differ diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/.mvn/wrapper/maven-wrapper.properties" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/.mvn/wrapper/maven-wrapper.properties" new file mode 100644 index 00000000..642d572c --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/.mvn/wrapper/maven-wrapper.properties" @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/mvnw" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/mvnw" new file mode 100644 index 00000000..a16b5431 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/mvnw" @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# 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 +# +# https://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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/mvnw.cmd" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/mvnw.cmd" new file mode 100644 index 00000000..c8d43372 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/mvnw.cmd" @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/pom.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/pom.xml" new file mode 100644 index 00000000..432a5053 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/pom.xml" @@ -0,0 +1,191 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.5.RELEASE + + + com.AiHome + aihomesys + 0.0.1-SNAPSHOT + aihomesys + Demo project for Spring Boot + + + 11 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.session + spring-session-core + + + + cn.rongcloud.im + server-sdk-java + 3.1.6 + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + com.zhenzikj + zhenzisms + 1.0.4 + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + org.mybatis + mybatis + 3.5.3 + + + + commons-fileupload + commons-fileupload + 1.3.3 + + + org.apache.poi + poi-ooxml + 3.17 + + + com.alibaba + fastjson + 1.2.32 + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 1.3.2 + + + + + org.python + jython-standalone + 2.7.1 + + + + + mysql + mysql-connector-java + 8.0.13 + + + org.apache.tomcat.embed + tomcat-embed-jasper + provided + 9.0.27 + + + + javax.servlet + jstl + + + + org.springframework.boot + spring-boot-devtools + + + + + com.google.code.gson + gson + 2.8.5 + + + + + org.apache.commons + commons-lang3 + 3.8.1 + + + + + org.apache.taglibs + taglibs-standard-impl + 1.2.5 + + + + + + AiHome + + + org.springframework.boot + spring-boot-maven-plugin + 1.4.2.RELEASE + + + com.KlivexerApplication + + + + + + + src/main/java + + **/** + + + + src/main/resources + + **/** + + false + + + src/main/webapp + + **/** + + META-INF/resources + false + + + + + + diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/readme.md" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/readme.md" new file mode 100644 index 00000000..0e917eee --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/readme.md" @@ -0,0 +1,119 @@ +> ## 你说的都对:**Klive-exer** + +## 项目介绍 + +### 项目背景 + +    随着人们生活水平的高速发展,智能交互已经不断的进入人们的生活。酒店服务业作为人们休闲娱乐的重要载体,对生活水平提高的实际应用和发展提供了温床。而且随着人工智能技术的提高,《智慧酒店的现状和发展趋势》一文中指出:发展智慧酒店可谓是酒店业发展的必然趋势,智慧酒店的发展除了是酒店自身更久的生存下去,更是和旅游业、城市的飞速发展相辅相成。 + +### 项目内容 + +- 本系统为提高酒店对客户的服务,聚焦于智慧酒店中的健身诉求,着重以私人虚拟健身教练为主,具体研究开发如下: + + 1.系统计划应用CMU所提出的新型人体姿态估计算法——OpenPose 姿态识别来改善现有酒店智能化模式,从健身方面提升客户体验。 + + 2.系统为 Web 应用,基于传统 SSM 框架和 Flask 微型 Web 服务集成功能,并仅依赖单一摄像头实现对人体姿态点的检测,力求降低对硬件设备的依赖。 + + 3.系统用户可以通过选择不同健身课程来查看相关具体信息,并通过深度学习算法将标准姿态与用户动作相匹配,给以相应的检测反馈,同时还包括健身后圈子交流共享等服务。 + +> 部分数据来源为keep,仅供个人学习,非商用 + +### 所用技术 +- Mockplus摹客原型设计工具 +- PowerDesigner数据库设计工具 +- IDEA和PyCharm开发工具 +- SSM组合框架&Flask微型Web框架 +- OpenPose人体姿态识别开源库 +- 流加载、SHA1加密 +- 融云IM即时通讯SDK + +### 模块简介与视图 + +- 用户登录和注册 + +
+ 登录 + 注册 + 找回密码 +
+ +- 用户数据收集 + +
+ 信息采集 + 课程选择 +
+ +- 课程模块 + +
+ 课程模块 + 课程模块 + 课程模块 +
+ +- 姿态检测和训练矫正 + +
+ 计划 + 训练模块 + 训练模块 + 训练模块 +
+ +- 数据统计 + +
+ 数据统计 +
+ +- 圈子交流 + +
+ 交流 + 交流 + 交流 +
+ +- 个人信息 + +
+ 个人信息 + 个人信息 +
+ +### SDK使用 + +在圈子交流模块,使用了融云IM即时通讯SDK实现了对每个课程创建讨论组,用户可随心交流。 + +## 商业价值 + +    本系统研究既具有理论研究价值,也具有重要的实际应用价值和现实指导意义。系统实际上就是为解决“酒店智能化低”、“硬件设备昂贵”、“重建设,轻应用”等一系列问题而立意。在市场应用方面,本课题具有相对完整的系统和管理方案,调研并结合了当地多种类型酒店对于人工智能的需求和意见,由于私人虚拟健身教练这一市场空白,系统能够为现有的高端酒店提供低成本高回报的使用价值,对丰富酒店健身模块具有极其重要的指导作用。同时系统实现了人体姿态识别技术的应用落地,通过深度学习算法将识别结果同功能相衔接,也具有参考价值。 + +## 不足与展望 + +    系统目前仍具有一些不足,主要表现在算法应用方面。在姿态检测模块,由于系统需要不间断的向算法服务器发送http请求,并且后台算法需要启动模型处理,反馈给前端的画面展示不太流畅,但仍在用户接受范围之内。而对于课程的添加方面,本系统由于设计原因未给出相应功能接口。 + +## 如何安装和启动 + +- 项目为Springboot项目,需要提前有maven环境安装,并且导入项目后使用pom导入依赖包 +- 在sql文件中导入数据库 +- 启动springboot后,浏览器输入 http://localhost:8088/Klive/main 进入主界面 + +## Q&A + +### 1.为何我无法启动项目 + +答:项目本身拥有众多jar包,并且使用Mybatis与后台数据库相连接,需要在导入pom所有依赖后,在properties文件中修改数据库连接信息等。 + +### 2.为何我启动项目后,无法登陆 + +答:系统本身具有注册功能,为真实的网站项目,需要先进行注册成功后才能登陆,**需要真实手机号**。 + +### 3.为何我登录成功后,系统大部分显示没有内容 + +答:为防止数据泄露,数据库文件中仅包含有数据结构,不含数据,需要在表**class_info**中添加数据 + +### 4.为何我无法使用项目姿态识别功能 + +答:项目算法端部署于flask上,由于算法模型巨大无法上传github,所以该演示项目中不包含实际算法处理。 diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/sql/aihome.sql" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/sql/aihome.sql" new file mode 100644 index 00000000..ac0b4f74 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/sql/aihome.sql" @@ -0,0 +1,274 @@ +/* +Navicat MySQL Data Transfer + +Source Server : aihome +Source Server Version : 80013 +Source Host : localhost:3306 +Source Database : aihome + +Target Server Type : MYSQL +Target Server Version : 80013 +File Encoding : 65001 + +Date: 2020-10-10 20:20:08 +*/ + +SET FOREIGN_KEY_CHECKS=0; + +-- ---------------------------- +-- Table structure for action_info +-- ---------------------------- +DROP TABLE IF EXISTS `action_info`; +CREATE TABLE `action_info` ( + `actionId` int(11) NOT NULL AUTO_INCREMENT, + `classId` int(11) NOT NULL, + `actionName` varchar(255) DEFAULT NULL, + `actionImg` varchar(255) DEFAULT NULL, + `actionUrl` varchar(255) DEFAULT NULL, + `actionTime` varchar(255) DEFAULT NULL, + `actionPoints` varchar(255) DEFAULT NULL, + `actionSteps` varchar(255) DEFAULT NULL, + `actionBreak` varchar(255) DEFAULT NULL, + `actionFeel` varchar(255) DEFAULT NULL, + `actionError` varchar(255) DEFAULT NULL, + `actionValid` int(11) DEFAULT '0', + PRIMARY KEY (`actionId`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for circle_content +-- ---------------------------- +DROP TABLE IF EXISTS `circle_content`; +CREATE TABLE `circle_content` ( + `conId` int(11) NOT NULL AUTO_INCREMENT, + `userId` varchar(11) NOT NULL COMMENT '用户id', + `fkId` int(11) DEFAULT NULL COMMENT '父id', + `fkType` int(1) NOT NULL DEFAULT '0' COMMENT '评论类型,0无父id,1课程id,2父评论id', + `conTime` varchar(25) DEFAULT NULL, + `conImg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `conCont` varchar(255) DEFAULT NULL, + `conGood` int(11) NOT NULL DEFAULT '0', + `conContNum` int(11) NOT NULL DEFAULT '0', + `conValid` int(1) NOT NULL DEFAULT '0' COMMENT '0为有效,1为违法', + PRIMARY KEY (`conId`), + KEY `circle_content_ibfk_1` (`userId`) +) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for class_info +-- ---------------------------- +DROP TABLE IF EXISTS `class_info`; +CREATE TABLE `class_info` ( + `classId` int(11) NOT NULL AUTO_INCREMENT, + `className` varchar(255) NOT NULL, + `classImg` varchar(255) NOT NULL, + `classUrl` varchar(255) NOT NULL, + `classFatB` varchar(25) NOT NULL, + `classTime` varchar(25) DEFAULT NULL, + `classLevel` varchar(25) DEFAULT NULL, + `createTime` varchar(25) DEFAULT NULL, + `classPeriod` varchar(25) DEFAULT NULL, + `classValid` int(1) NOT NULL DEFAULT '0', + `classTitle` varchar(255) DEFAULT NULL, + `classLabel` varchar(255) DEFAULT NULL, + `classIntro` varchar(255) DEFAULT NULL, + `classType` varchar(255) DEFAULT NULL, + `classIntended` varchar(255) DEFAULT NULL, + `classTaboo` varchar(255) DEFAULT NULL, + `classReady` varchar(255) DEFAULT NULL, + `classBodyreac` varchar(255) DEFAULT NULL, + `classSug` varchar(255) DEFAULT NULL, + `classTrainnumber` int(11) DEFAULT '0', + PRIMARY KEY (`classId`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for fitness_record +-- ---------------------------- +DROP TABLE IF EXISTS `fitness_record`; +CREATE TABLE `fitness_record` ( + `frId` int(11) NOT NULL AUTO_INCREMENT, + `userId` varchar(11) NOT NULL, + `recordTime` varchar(25) DEFAULT '', + `fitnessTime` int(11) DEFAULT '0' COMMENT '运动时长(second)', + `cumFatB` int(11) unsigned zerofill DEFAULT '00000000000' COMMENT '当次运动消耗', + `fkId` int(11) NOT NULL, + `fkType` int(1) NOT NULL DEFAULT '0' COMMENT '0为课程,1为动作', + `score` double(11,2) DEFAULT '0.00', + PRIMARY KEY (`frId`) +) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for food_ku +-- ---------------------------- +DROP TABLE IF EXISTS `food_ku`; +CREATE TABLE `food_ku` ( + `foodId` int(11) NOT NULL AUTO_INCREMENT, + `hotelId` int(8) NOT NULL, + `foodName` varchar(25) NOT NULL, + `foodType` varchar(25) DEFAULT NULL, + `foodCacul` varchar(25) DEFAULT NULL, + `foodContent` varchar(25) DEFAULT NULL, + `foodFatB` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`foodId`) +) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for hotel_info +-- ---------------------------- +DROP TABLE IF EXISTS `hotel_info`; +CREATE TABLE `hotel_info` ( + `hotelId` int(8) NOT NULL, + `hotelName` varchar(25) DEFAULT NULL, + `hotelNotice` varchar(255) DEFAULT NULL, + `hotelLocation` varchar(255) DEFAULT NULL, + PRIMARY KEY (`hotelId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for label_type +-- ---------------------------- +DROP TABLE IF EXISTS `label_type`; +CREATE TABLE `label_type` ( + `typeId` int(11) NOT NULL AUTO_INCREMENT, + `typeName` varchar(25) NOT NULL, + `typeCount` int(11) DEFAULT '0' COMMENT '记录选择类型的人数', + `isValid` int(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`typeId`) +) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for meal_info +-- ---------------------------- +DROP TABLE IF EXISTS `meal_info`; +CREATE TABLE `meal_info` ( + `mealId` int(11) NOT NULL AUTO_INCREMENT, + `stapleId` int(11) NOT NULL COMMENT '主食', + `MEMId` int(11) NOT NULL COMMENT '肉蛋奶', + `VFId` int(11) NOT NULL COMMENT '蔬果', + `GreaseId` int(11) NOT NULL COMMENT '油脂', + `OtherId` int(11) DEFAULT NULL COMMENT '其他', + `hotelId` int(8) NOT NULL, + `mealType` int(1) NOT NULL DEFAULT '0' COMMENT '0-早餐,1-午餐,2-晚餐', + PRIMARY KEY (`mealId`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for user_enroll +-- ---------------------------- +DROP TABLE IF EXISTS `user_enroll`; +CREATE TABLE `user_enroll` ( + `userId` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `passWord` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `userName` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '', + `userImg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, + `hotelId` int(8) DEFAULT NULL, + `userType` int(1) NOT NULL, + `loginTime` varchar(25) DEFAULT NULL, + `enrollTime` varchar(25) DEFAULT NULL, + `enableInfoco` int(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`userId`), + KEY `userId` (`userId`,`userName`), + KEY `userId_2` (`userId`), + KEY `userId_3` (`userId`,`userName`,`userImg`), + KEY `userName` (`userName`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for user_follow +-- ---------------------------- +DROP TABLE IF EXISTS `user_follow`; +CREATE TABLE `user_follow` ( + `followId` int(11) NOT NULL AUTO_INCREMENT, + `fuserId` varchar(11) NOT NULL, + `fuseredId` varchar(11) NOT NULL, + `followTime` varchar(25) DEFAULT NULL, + `followValid` int(1) NOT NULL DEFAULT '0' COMMENT '0为有效,1为违法', + PRIMARY KEY (`followId`), + KEY `fuserId` (`fuserId`), + KEY `fuseredId` (`fuseredId`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for user_good +-- ---------------------------- +DROP TABLE IF EXISTS `user_good`; +CREATE TABLE `user_good` ( + `goodId` int(11) NOT NULL AUTO_INCREMENT, + `userId` varchar(11) NOT NULL, + `conId` int(11) NOT NULL, + `goodTime` varchar(25) DEFAULT NULL, + `goodValid` int(1) NOT NULL DEFAULT '0' COMMENT '0为有效,1为违法', + PRIMARY KEY (`goodId`), + KEY `userId` (`userId`) +) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for user_info +-- ---------------------------- +DROP TABLE IF EXISTS `user_info`; +CREATE TABLE `user_info` ( + `infoId` int(11) NOT NULL AUTO_INCREMENT, + `userId` varchar(11) NOT NULL, + `sex` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '', + `age` varchar(25) DEFAULT NULL, + `height` double(11,2) DEFAULT '0.00' COMMENT 'cm', + `weight` double(11,2) DEFAULT '0.00' COMMENT 'kg', + `bust` double(11,2) DEFAULT '0.00' COMMENT 'cm', + `waist` double(11,2) DEFAULT '0.00' COMMENT 'cm', + `hipline` double(11,2) DEFAULT '0.00' COMMENT '臀围cm', + `BMI` double(11,2) DEFAULT '0.00', + `RHR` int(11) DEFAULT '0' COMMENT '每分钟心跳次数', + `MHR` int(11) DEFAULT '0' COMMENT '每分钟最大心跳次数', + `modifyTime` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '0', + `trainDay` int(11) DEFAULT '0', + `todayIsTrain` int(1) DEFAULT '0', + PRIMARY KEY (`infoId`) +) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for user_label +-- ---------------------------- +DROP TABLE IF EXISTS `user_label`; +CREATE TABLE `user_label` ( + `ulId` int(11) NOT NULL AUTO_INCREMENT, + `userId` varchar(11) NOT NULL, + `typeId` int(11) NOT NULL, + `typeName` varchar(25) NOT NULL, + PRIMARY KEY (`ulId`) +) ENGINE=InnoDB AUTO_INCREMENT=45 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for user_plan +-- ---------------------------- +DROP TABLE IF EXISTS `user_plan`; +CREATE TABLE `user_plan` ( + `planId` int(11) NOT NULL AUTO_INCREMENT, + `userId` varchar(11) NOT NULL, + `classId` int(11) NOT NULL, + `comTime` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '0' COMMENT '用户已经完成的课时', + `todayComplete` int(1) NOT NULL DEFAULT '0' COMMENT '该课程今日是否完成', + `isComplete` int(1) NOT NULL DEFAULT '0' COMMENT '是否完成整个课时', + `subTime` varchar(25) NOT NULL COMMENT '用户订阅课程时间', + `todayTime` varchar(25) DEFAULT NULL COMMENT '今日完成时间(每日更新', + `totalFatB` int(25) DEFAULT '0', + PRIMARY KEY (`planId`) +) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Event structure for updateUserInfo +-- ---------------------------- +DROP EVENT IF EXISTS `updateUserInfo`; +DELIMITER ;; +CREATE DEFINER=`root`@`localhost` EVENT `updateUserInfo` ON SCHEDULE EVERY 1 DAY STARTS '2020-04-12 00:00:00' ON COMPLETION NOT PRESERVE ENABLE DO UPDATE user_info SET todayIsTrain = 0 +;; +DELIMITER ; + +-- ---------------------------- +-- Event structure for updateUserPlan +-- ---------------------------- +DROP EVENT IF EXISTS `updateUserPlan`; +DELIMITER ;; +CREATE DEFINER=`root`@`localhost` EVENT `updateUserPlan` ON SCHEDULE EVERY 1 DAY STARTS '2020-04-12 00:00:00' ON COMPLETION NOT PRESERVE ENABLE DO UPDATE user_plan SET todayComplete = 0 , todayTime = NULL WHERE isComplete = 0 +;; +DELIMITER ; diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/KlivexerApplication.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/KlivexerApplication.java" new file mode 100644 index 00000000..3e102dd7 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/KlivexerApplication.java" @@ -0,0 +1,44 @@ +package com; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Bean; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +@MapperScan("com.aihome.aihomesys.dao") +@SpringBootApplication(exclude = SecurityAutoConfiguration.class) +public class KlivexerApplication extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { + return builder.sources(KlivexerApplication.class); + } + public static void main(String[] args) { + SpringApplication.run(KlivexerApplication.class, args); + } + @Bean + public CorsFilter corsFilter() { + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + final CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); // 允许cookies跨域 + config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin + config.addAllowedHeader("*");// #允许访问的头信息,*表示全部 + config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了 + config.addAllowedMethod("OPTIONS");// 允许提交请求的方法,*表示全部允许 + config.addAllowedMethod("HEAD"); + config.addAllowedMethod("GET");// 允许Get的请求方法 + config.addAllowedMethod("PUT"); + config.addAllowedMethod("POST"); + config.addAllowedMethod("DELETE"); + config.addAllowedMethod("PATCH"); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/base/IBaseDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/base/IBaseDao.java" new file mode 100644 index 00000000..d466e398 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/base/IBaseDao.java" @@ -0,0 +1,48 @@ +package com.aihome.aihomesys.base; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +public interface IBaseDao { + /** + * 获取所有对象列表 + */ + List findAll(); + + /** + * 根据条件Map集合获取对象列表 + */ + List listByConditions(Map map); + + /** + * 根据条件Map集合获取总数量 + */ + Long countByConditions(Map map); + + /** + * 根据主键获取对象 + */ + T findById(PK id); + + /** + * 插入对象 + */ + int insert(T object); + + /** + * 插入List集合对象 + */ + int insertList(List object); + + /** + * 修改对象 + */ + int update(T object); + + /** + * 根据主键ID删除一条数据 + */ + int deleteById(PK id); + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/AdminController.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/AdminController.java" new file mode 100644 index 00000000..0cfff921 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/AdminController.java" @@ -0,0 +1,193 @@ +package com.aihome.aihomesys.controller; + +import com.aihome.aihomesys.service.FoodKuServices; +import com.aihome.aihomesys.service.HotelInfoServices; +import com.aihome.aihomesys.service.MealInfoServices; +import com.aihome.aihomesys.service.UserEnrollService; +import com.aihome.aihomesys.vo.FoodKu; +import com.aihome.aihomesys.vo.HotelInfo; +import com.aihome.aihomesys.vo.MealInfo; +import com.aihome.aihomesys.vo.UserEnroll; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import javax.validation.constraints.Null; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Controller +@RequestMapping(value = "/admin") +public class AdminController { + + @Autowired + UserEnrollService userEnrollService = new UserEnrollService(); + @Autowired + HotelInfoServices hotelInfoServices = new HotelInfoServices(); + @Autowired + MealInfoServices mealInfoServices = new MealInfoServices(); + @Autowired + FoodKuServices foodKuServices = new FoodKuServices(); + + @RequestMapping("/getUserList") + @ResponseBody + public Object userRefind(@RequestBody Map result) { + Map mapper = new HashMap<>(); + try { + List listuser = this.userEnrollService.selectAll(); + mapper.put("code","0"); + mapper.put("msg","查询成功"); + mapper.put("count",listuser.size()); + mapper.put("data",listuser); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + return mapper; + } + + @RequestMapping("/getMealList") + @ResponseBody + public Object getMealList(@RequestBody Map result) { + Map mapper = new HashMap<>(); + try { + List listmeal = this.mealInfoServices.getMealList(result); + if(listmeal.size()>0){ + for(int i=0;i result) { + Map mapper = new HashMap<>(); + try { + HotelInfo hotelInfo = this.hotelInfoServices.getHotelInfo(result); + mapper.put("code","0"); + mapper.put("msg","获取酒店信息成功"); + mapper.put("hotelInfo",hotelInfo); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + return mapper; + } + + @RequestMapping("/setHotelInfo") + @ResponseBody + public Object setHotelInfo(@RequestBody Map result) { + Map mapper = new HashMap<>(); + try { + this.hotelInfoServices.setHotelInfo(result); + mapper.put("code","0"); + mapper.put("msg","公告已更新..."); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + return mapper; + } + + @RequestMapping("/getHotelFoodKu") + @ResponseBody + public Object getHotelFoodKu(@RequestBody Map result) { + Map mapper = new HashMap<>(); + try { + int hotelId = Integer.valueOf(result.get("hotelId").toString()); + List listfood = this.foodKuServices.selectFoodListByHotel(hotelId); + mapper.put("code","0"); + mapper.put("msg","查询成功"); + mapper.put("count",listfood.size()); + mapper.put("data",listfood); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + return mapper; + } + + @RequestMapping(value = "/statistics") + public String statics(){ + return "admin/statistics"; + } + + @RequestMapping(value = "/foodku") + public String foodku(String userId,Map mapper){ + Map result = new HashMap<>(); + result.put("userId",userId); + try { + HotelInfo hotelInfo = this.hotelInfoServices.getHotelInfo(result); + mapper.put("code","0"); + mapper.put("hotelInfo",hotelInfo); + return "admin/foodku"; + } catch (Exception e) { + e.printStackTrace(); + return "error/error"; + } + } + + @RequestMapping(value = "/foodService") + public String foodService(String userId,Map mapper){ + Map result = new HashMap<>(); + result.put("userId",userId); + try { + HotelInfo hotelInfo = this.hotelInfoServices.getHotelInfo(result); + mapper.put("code","0"); + mapper.put("hotelInfo",hotelInfo); + return "admin/foodService"; + } catch (Exception e) { + e.printStackTrace(); + return "error/error"; + } + } + + @RequestMapping(value = "/foodre") + public String foodre(){ + return "admin/foodRecom"; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/CircleController.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/CircleController.java" new file mode 100644 index 00000000..ce039cad --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/CircleController.java" @@ -0,0 +1,428 @@ +package com.aihome.aihomesys.controller; + +import com.aihome.aihomesys.service.*; +import com.aihome.aihomesys.vo.*; +import com.aihome.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Controller +@RequestMapping(value = "/circle") +public class CircleController { + + @Autowired + UserEnrollService userEnrollService = new UserEnrollService(); + + @Autowired + CircleContentServices circleContentServices = new CircleContentServices(); + + @Autowired + UserFollowServices userFollowServices = new UserFollowServices(); + + @Autowired + UserPlanService userPlanService = new UserPlanService(); + + @Autowired + UserGoodServices userGoodServices = new UserGoodServices(); + + @GetMapping + public String circle(String userId,Map mapper){ + if(userId!=null){ + try { + //统计数值 + int myfollow = this.userFollowServices.countMyFollow(userId); + int followme = this.userFollowServices.countFollowMe(userId); + int planclass = this.userPlanService.countMyClassNum(userId); + //个人情况 + UserEnroll myinfo = this.userEnrollService.findById(userId); + { + mapper.put("myfollow",myfollow); + mapper.put("followme",followme); + mapper.put("planclass",planclass); + mapper.put("myinfo",myinfo); + } + return "comm/userfram/circle"; + } catch (Exception e) { + e.printStackTrace(); + return "error/error"; + } + }else { + return "error/error"; + } + } + + @RequestMapping(value = "/getContent",produces = { "application/json;charset=UTF-8" }) + @ResponseBody + public Object getContent(@RequestBody Map result){ + Map mapper = new HashMap<>(); + if(result.get("userId")==null||result.get("type")==null){ + mapper.put("code","1"); + mapper.put("msg","参数异常"); + }else { + //分页处理 + int page = Integer.valueOf(result.get("page").toString()); + int number = Integer.valueOf(result.get("number").toString()); + result.put("page",(page-1)*number); + result.put("number",number); + try { + int type = Integer.valueOf(result.get("type").toString()); + if(type==0){ //热门 + List circleContents = this.circleContentServices.getHot(result); + //是否点赞 + for(int i=0;i temp = new HashMap<>(); + temp.put("userId",result.get("userId")); + temp.put("conId",circleContents.get(i).getConId()); + circleContents.get(i).setIsGood(this.userGoodServices.isGood(temp)); + } + //分页处理 + int pagesAll = this.circleContentServices.countHot(result); + int pages = pagesAll%number==0?(pagesAll/number):(pagesAll/number)+1; + mapper.put("pages",pages); + mapper.put("code","0"); + mapper.put("msg","查询成功"); + mapper.put("circleContents",circleContents); + }else if (type==1){ //关注 + List circleContents = this.circleContentServices.getFollow(result); + for(int i=0;i temp = new HashMap<>(); + temp.put("userId",result.get("userId")); + temp.put("conId",circleContents.get(i).getConId()); + circleContents.get(i).setIsGood(this.userGoodServices.isGood(temp)); + } + //分页处理 + int pagesAll = this.circleContentServices.countFollow(result); + int pages = pagesAll%number==0?(pagesAll/number):(pagesAll/number)+1; + mapper.put("pages",pages); + mapper.put("code","0"); + mapper.put("msg","查询成功"); + mapper.put("circleContents",circleContents); + }else if (type==2){ //我的 + List circleContents = this.circleContentServices.getMycont(result); + for(int i=0;i temp = new HashMap<>(); + temp.put("userId",result.get("userId")); + temp.put("conId",circleContents.get(i).getConId()); + circleContents.get(i).setIsGood(this.userGoodServices.isGood(temp)); + } + //分页处理 + int pagesAll = this.circleContentServices.countMycont(result); + int pages = pagesAll%number==0?(pagesAll/number):(pagesAll/number)+1; + mapper.put("pages",pages); + mapper.put("code","0"); + mapper.put("msg","查询成功"); + mapper.put("circleContents",circleContents); + }else if(type==3){ //搜索 + mapper.put("code","1"); + mapper.put("msg","参数异常"); + }else { + mapper.put("code","1"); + mapper.put("msg","参数异常"); + } + } catch (NumberFormatException e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错啦"); + } + } + return mapper; + } + + @RequestMapping(value = "/getSearchContent",produces = { "application/json;charset=UTF-8" }) + @ResponseBody + public Object getSearchContent(@RequestBody Map result){ + Map mapper = new HashMap<>(); + if(result.get("userId")==null||result.get("val")==null){ + mapper.put("code","1"); + mapper.put("msg","参数异常"); + }else { + try { + List circleContents = this.circleContentServices.getSearchItems(result); + for(int i=0;i temp = new HashMap<>(); + temp.put("userId",result.get("userId")); + temp.put("conId",circleContents.get(i).getConId()); + circleContents.get(i).setIsGood(this.userGoodServices.isGood(temp)); + } + mapper.put("code","0"); + mapper.put("msg","查询成功"); + mapper.put("circleContents",circleContents); + } catch (NumberFormatException e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错啦"); + } + } + return mapper; + } + + @RequestMapping(value = "/getFollow",produces = { "application/json;charset=UTF-8" }) + @ResponseBody + public Object getFollow(@RequestBody Map result){ + Map mapper = new HashMap<>(); + if(result.get("userId")==null&&result.get("type")==null){ + mapper.put("code","1"); + mapper.put("msg","参数异常"); + }else { + try { + int type = Integer.valueOf(result.get("type").toString()); + String userId = result.get("userId").toString(); + if(type==0){ //我关注的 + List myFollows = this.userFollowServices.selectMyFollow(userId); + for(int i=0;i followme = this.userFollowServices.selectFollowMe(userId); + for(int i=0;i result){ + Map mapper = new HashMap<>(); + if(result.get("userId")==null||result.get("type")==null||result.get("otherId")==null){ + mapper.put("code","1"); + mapper.put("msg","参数异常"); + }else { + try { + int type = Integer.valueOf(result.get("type").toString()); + String userId = result.get("userId").toString(); + String otherId = result.get("otherId").toString(); + if(type==0){ //ta关注的 + List myFollows = this.userFollowServices.selectMyFollow(otherId); + //我是否关注 + for(int i=0;i followme = this.userFollowServices.selectFollowMe(otherId); + //我是否关注 + for(int i=0;i mapper = new HashMap<>(); + MultipartFile img = file; + if(img.isEmpty()||userId.isEmpty()){ + mapper.put("code", "1"); + mapper.put("msg", "服务器出错"); + }else{ + String fileName = userId+"_"+DateUtils.getCurTime2Number(); + File dest = new File(new File(realPath).getAbsolutePath()+ "/../../resources/static/images/contentImgs/" + fileName+".png"); + if (!dest.getParentFile().exists()) { + dest.getParentFile().mkdirs(); + } + try { + file.transferTo(dest); // 保存文件 + mapper.put("code", "0"); + mapper.put("msg", "上传成功"); + mapper.put("filename",fileName+".png"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code", "1"); + mapper.put("msg", "服务器出错"); + } + } + return mapper; + } + + @RequestMapping(value = "/setContent",produces = { "application/json;charset=UTF-8" }) + @ResponseBody + public Object setContent(@RequestBody Map result){ + Map mapper = new HashMap<>(); + if(result.get("userId")==null){ + mapper.put("code","1"); + mapper.put("msg","参数异常"); + }else { + //获取用户信息 + try { + UserEnroll userEnroll = this.userEnrollService.findById(result.get("userId").toString()); + if(userEnroll==null){ + mapper.put("code","1"); + mapper.put("msg","违法用户"); + }else { + result.put("userName",userEnroll.getUserName()); + result.put("userImg",userEnroll.getUserAva()); + result.put("conTime",DateUtils.getCurTime()); + this.circleContentServices.insert(result); + if(Integer.valueOf(result.get("fkType").toString())==2){ //更新评论数据库 + this.circleContentServices.contAdd(result); + } + mapper.put("code","0"); + mapper.put("msg","发布成功"); + } + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错啦..."); + } + } + return mapper; + } + + + @RequestMapping(value = "/details") + public String circledetails(String userId,String conId,Map mapper){ + if(userId!=null&&conId!=null){ + try { + //统计数值 + int myfollow = 0; + int followme = 0; + int planclass = 0; + //圈子内容 + CircleContent circleContent = this.circleContentServices.getUserCont(Integer.valueOf(conId)); + UserEnroll myinfo = new UserEnroll(); + if(circleContent!=null){ + myfollow = this.userFollowServices.countMyFollow(circleContent.getUserId()); + followme = this.userFollowServices.countFollowMe(circleContent.getUserId()); + planclass = this.userPlanService.countMyClassNum(circleContent.getUserId()); + //个人情况 + myinfo = this.userEnrollService.findById(circleContent.getUserId()); + //是否点赞 + Map temp = new HashMap<>(); + temp.put("userId",userId); + temp.put("conId",conId); + circleContent.setIsGood(this.userGoodServices.isGood(temp)); + }else { + return "error/error"; + } + //获取图片list + String[] imglist = circleContent.getConImg().split(","); + //获取评论内容 + List contents = this.circleContentServices.getUsers2Contents(Integer.valueOf(conId)); + //判断是否获赞 + for(int i =0;i temp2 = new HashMap<>(); + temp2.put("userId",userId); + temp2.put("conId",contents.get(i).getConId()); + contents.get(i).setIsGood(this.userGoodServices.isGood(temp2)); + } + mapper.put("myfollow",myfollow); + mapper.put("followme",followme); + mapper.put("planclass",planclass); + mapper.put("myinfo",myinfo); + mapper.put("cc",circleContent); + mapper.put("imglist",imglist); + mapper.put("contents",contents); + return "comm/userfram/circledetails"; + } catch (Exception e) { + e.printStackTrace(); + return "error/error"; + } + }else { + return "error/error"; + } + } + + @RequestMapping(value = "/goodAction",produces = { "application/json;charset=UTF-8" }) + @ResponseBody + public Object goodAction(@RequestBody Map result){ + Map mapper = new HashMap<>(); + if(result.get("userId")==null||result.get("conId")==null||result.get("flag")==null){ + mapper.put("code","1"); + mapper.put("msg","参数异常"); + }else { + //获取用户信息 + String userId = result.get("userId").toString(); + UserEnroll myinfo = this.userEnrollService.findById(userId); + //获取文章信息 + int conId = Integer.valueOf(result.get("conId").toString()); + CircleContent circleContent = this.circleContentServices.getUserCont(conId); + if(myinfo!=null&&circleContent!=null){ + int flag=Integer.valueOf(result.get("flag").toString()); + Map temp = new HashMap<>(); + temp.put("userId",myinfo.getUserId()); + temp.put("userName",myinfo.getUserName()); + temp.put("userImg",myinfo.getUserAva()); + temp.put("conId",circleContent.getConId()); + temp.put("conCont",circleContent.getConCont()); + temp.put("goodTime",DateUtils.getCurTime()); + if(flag==0){ //加点赞 + this.userGoodServices.insertGood(temp); + this.circleContentServices.goodAdd(temp); + mapper.put("code","0"); + mapper.put("msg","点赞成功"); + }else if(flag==1){ //减点赞 + this.userGoodServices.deleteGood(temp); + this.circleContentServices.goodSub(temp); + mapper.put("code","0"); + mapper.put("msg","取消成功"); + }else { + mapper.put("code","1"); + mapper.put("msg","参数异常"); + } + }else{ + mapper.put("code","1"); + mapper.put("msg","用户信息获取错误"); + } + } + return mapper; + } + + @RequestMapping(value = "/upload") + public String circleupload(){ + return "comm/userfram/circleform"; + } + + @RequestMapping(value = "/classCircle") + public String classCircle(){ + return "comm/userfram/classCircle"; + } + + @RequestMapping(value = "/chatRoom") + public String chatRoom(){ + return "comm/userfram/chatroom"; + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/CourseRecmmoController.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/CourseRecmmoController.java" new file mode 100644 index 00000000..974f2939 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/CourseRecmmoController.java" @@ -0,0 +1,318 @@ +package com.aihome.aihomesys.controller; + +import com.aihome.aihomesys.service.*; +import com.aihome.aihomesys.vo.*; +import com.aihome.component.ComputingUnit; +import com.aihome.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Controller +@RequestMapping(value = "courses") +public class CourseRecmmoController { + + @Autowired + UserInfoService userInfoService = new UserInfoService(); + @Autowired + UserEnrollService userEnrollService = new UserEnrollService(); + @Autowired + LabelTypeService labelTypeService = new LabelTypeService(); + @Autowired + UserLabelServices userLabelServices = new UserLabelServices(); + @Autowired + ClassInfoService classInfoService = new ClassInfoService(); + @Autowired + ActionInfoServices actionInfoServices = new ActionInfoServices(); + @Autowired + CircleContentServices circleContentServices = new CircleContentServices(); + @Autowired + UserGoodServices userGoodServices = new UserGoodServices(); + + ComputingUnit computingUnit = new ComputingUnit(); + + @RequestMapping(value = "skipInsert") + @ResponseBody + public Object skipInsert(@RequestBody Map result){ + Map mapper = new HashMap<>(); + if(result.get("userId")!=""&&result.get("userId")!=null){ + //先判断是否存在 + try { + int isIn = this.userInfoService.counById(result); + if(isIn==0){ + result.put("modifyTime", DateUtils.getCurTime()); + int re = this.userInfoService.skipinsert(result); + mapper.put("code","0"); + mapper.put("msg","数据存取成功"); + }else{ //存在就update + result.put("modifyTime", DateUtils.getCurTime()); + this.userInfoService.skipUpdate(result); + mapper.put("code","0"); + mapper.put("msg","数据存取成功"); + } + this.userEnrollService.eableUpdate(result); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + }else { + mapper.put("code","1"); + mapper.put("msg","有异常数值"); + } + return mapper; + } + + @RequestMapping(value = "infoInsert") + @ResponseBody + public Object infoInsert(@RequestBody Map result){ + Map mapper = new HashMap<>(); + if(result.get("userId")!=""&&result.get("userId")!=null){ + result.put("modifyTime", DateUtils.getCurTime()); + result.put("BMI",computingUnit.BMICom(result.get("height"),result.get("weight"))); + //先判断是否存在 + try { + int isIn = this.userInfoService.counById(result); + if(isIn==0){ + int re = this.userInfoService.infoinsert(result); + }else{ //存在就update + this.userInfoService.infoUpdate(result); + } + this.userEnrollService.eableUpdate(result); + mapper.put("code","0"); + mapper.put("msg","数据存取成功"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + }else { + mapper.put("code","1"); + mapper.put("msg","有异常数值"); + } + return mapper; + } + + @RequestMapping(value = "getLabelList") + @ResponseBody + public Object getLabelList(){ + Map mapper = new HashMap<>(); + try { + List list = this.labelTypeService.getAll(); + mapper.put("code","0"); + mapper.put("list",list); + mapper.put("msg","列表拉取成功"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器异常"); + } + return mapper; + } + + @RequestMapping(value = "setUserLabel") + @ResponseBody + public Object setUserLabel(@RequestBody Map result){ + Map mapper = new HashMap<>(); + try { + List list = (List)result.get("list"); + this.userLabelServices.insertBeach(list); + mapper.put("code","0"); + mapper.put("msg","数据存取成功"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器异常"); + } + return mapper; + } + + +// @RequestMapping(value = "info-user") +// public String getUser(){ +// return "comm/getinfo/info-user"; +// } + + @RequestMapping(value = "info-fav") + public String getUserage(){ + return "comm/getinfo/info-fav"; + } + + @RequestMapping(value = "inner-recomm") + public String innerrecomm(String userId,Map mapper){ + //取用户label + List userLabel = this.userLabelServices.getAll(userId); + //获取用户推荐课程list + List labellist = new ArrayList<>(); + if(!userLabel.isEmpty()){ + for (int i=0;i classinfo = new HashMap<>(); + Map tem = new HashMap<>(); + String typename = userLabel.get(i).getTypeName(); + tem.put("classLabel",typename); + List classInfos = this.classInfoService.selectByKeys(tem); + if(!classInfos.isEmpty()){ + classinfo.put("typeName",typename); + classinfo.put("data",classInfos); + labellist.add(classinfo); + } + tem.clear(); + } + mapper.put("labellist",labellist); + return "comm/coursefav/recomm"; + } + return "error/error"; + } + + @RequestMapping(value = "getUserRecommInfo") + @ResponseBody + public Object getUserRecommInfo(@RequestBody Map result){ + Map mapper = new HashMap<>(); + String userId = result.get("userId").toString(); + if(userId==null){ + mapper.put("code","2"); + mapper.put("msg","未获得用户信息"); + }else { + try { + //取用户信息 + UserEnroll userEnroll = this.userEnrollService.findById(userId); + //取用户info + UserInfo userInfo = this.userInfoService.findById(userId); + //取用户label + List userLabel = this.userLabelServices.getAll(userId); + mapper.put("userEnroll",userEnroll); + mapper.put("userInfo",userInfo); + mapper.put("userLabel",userLabel); + mapper.put("code","0"); + mapper.put("msg","拉取数据成功"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器异常"); + } + } + return mapper; + } + + @RequestMapping(value = "getTabClass") + @ResponseBody + public Object getTabClass(@RequestBody Map res){ + Map mapper = new HashMap<>(); + //请求后台数据 + if(res.get("classTitle")!=""&&res.get("classTitle")!=null){ + List classlist = new ArrayList<>(); + String title = res.get("classTitle").toString(); + //分页处理 + int page = Integer.valueOf(res.get("page").toString()); + int number = Integer.valueOf(res.get("number").toString()); + res.put("page",(page-1)*number); + res.put("number",number); + try { + if(title.equals("全部")){ + classlist = this.classInfoService.getAll(res); + int pagesAll = this.classInfoService.getAllCounts(); + int pages = pagesAll%number==0?(pagesAll/number):(pagesAll/number)+1; + mapper.put("pages",pages); + }else{ + classlist = this.classInfoService.selectBytitles(res); + int pagesAll = this.classInfoService.countByTitle(res); + int pages = pagesAll%number==0?(pagesAll/number):(pagesAll/number)+1; + mapper.put("pages",pages); + } + mapper.put("classList",classlist); + mapper.put("code","0"); + mapper.put("msg","请求成功"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器错误"); + } + }else{ + mapper.put("code","2"); + mapper.put("msg","未获取的参数"); + } + return mapper; + } + + @RequestMapping(value = "getSearchItems") + @ResponseBody + public Object getSearchItems(@RequestBody Map res){ + Map mapper = new HashMap<>(); + //请求后台数据 + if(res.get("val")!=""&&res.get("val")!=null){ + List classlist = new ArrayList<>(); + String text = res.get("val").toString(); + try { + classlist = this.classInfoService.getSearch(text); + mapper.put("classList",classlist); + mapper.put("code","0"); + mapper.put("msg","请求成功"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器错误"); + } + }else{ + mapper.put("code","2"); + mapper.put("msg","未获取的参数"); + } + return mapper; + } + + @RequestMapping(value = "inner-allc") + public String innerallc(){ + return "comm/coursefav/allcourse"; + } + + @RequestMapping(value = "inner-intro") + public String innerintro(String userId,String classId,Map mapper){ + if(userId!=null&&classId!=null){ + Map map = new HashMap<>(); + map.put("classId",classId); + try { + ClassInfo classInfo = this.classInfoService.selectById(map); + int acnum = this.actionInfoServices.countById(map); + if(acnum>0){ + List actionInfos = this.actionInfoServices.selectByclassId(map); + mapper.put("actionlist",actionInfos); + } + if(classInfo==null){ + mapper.put("code","1"); + mapper.put("msg","异常参数"); + }else { + //获取用户评论信息 + List circleContents = this.circleContentServices.fromClass2Content(Integer.valueOf(classId)); + for(int i=0;i temp = new HashMap<>(); + temp.put("userId",userId); + temp.put("conId",circleContents.get(i).getConId()); + circleContents.get(i).setIsGood(this.userGoodServices.isGood(temp)); + String[] imglist = circleContents.get(i).getConImg().split(","); + circleContents.get(i).setImglist(imglist); + } + mapper.put("code","0"); + mapper.put("msg","请求数据成功"); + mapper.put("classInfo",classInfo); + mapper.put("acnum",acnum); + mapper.put("cc",circleContents); + } + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器异常"); + } + }else{ + mapper.put("code","1"); + mapper.put("msg","缺少必要参数"); + } + return "comm/coursefav/courseintro"; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/ErrorController.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/ErrorController.java" new file mode 100644 index 00000000..25751ae9 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/ErrorController.java" @@ -0,0 +1,35 @@ +package com.aihome.aihomesys.controller; +import com.aihome.aihomesys.service.UserEnrollService; +import com.aihome.aihomesys.vo.UserEnroll; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import java.util.List; + +@Controller +@RequestMapping("/hello") +public class ErrorController { + + @Autowired + private UserEnrollService userEnrollService; + + private List userEnrolls; + + Logger logger = LoggerFactory.getLogger(getClass()); + + @GetMapping + public String welcome() { + return "error/error"; + } + + @RequestMapping("get") + public List hello(){ + userEnrolls = this.userEnrollService.selectAll(); + return userEnrolls; + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/LoginMainController.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/LoginMainController.java" new file mode 100644 index 00000000..a6ec52ad --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/LoginMainController.java" @@ -0,0 +1,381 @@ +package com.aihome.aihomesys.controller; + +import com.aihome.aihomesys.service.HotelInfoServices; +import com.aihome.aihomesys.service.UserEnrollService; +import com.aihome.aihomesys.vo.UserEnroll; +import com.aihome.component.ZhenziyunService; +import com.aihome.utils.ConstantUtils; +import com.aihome.utils.DateUtils; +import com.aihome.utils.ShaUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +@Controller +@RequestMapping(value = "/main") +public class LoginMainController { + + @Autowired + UserEnrollService userEnrollService = new UserEnrollService(); + @Autowired + HotelInfoServices hotelInfoServices = new HotelInfoServices(); + + Logger logger = LoggerFactory.getLogger(getClass()); + ZhenziyunService zhenziyunService = new ZhenziyunService(); + + @GetMapping + public String welcome() { + return "main"; + } + + @RequestMapping("/signOut") + public String signout(HttpServletRequest request) { + //移除session + request.getSession().removeAttribute(ConstantUtils.USER_SESSION_KEY); + return "main"; + } + + @RequestMapping("/getCode") + @ResponseBody + public Object getCode(@RequestBody Map result) { + Map mapper = new HashMap<>(); + if(!result.get("phonefram").isEmpty()){ + //先验证是否重复注册 + int isIn = 0; + try { + Map qur = new HashMap<>(); + qur.put("userId",result.get("phonefram")); + isIn = userEnrollService.countById(qur); + if(isIn == 0){ + //发送验证码 + String code = zhenziyunService.randomCode(); + try { + zhenziyunService.sendMesg(result.get("phonefram"),code); + mapper.put("code","0"); + mapper.put("pcode",code); + mapper.put("msg","验证码已发送"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + }else { + mapper.put("code","1"); + mapper.put("msg","手机号已被注册"); + } + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + }else{ + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + return mapper; + } + + @RequestMapping("/getCode_refind") + @ResponseBody + public Object getCode_refind(@RequestBody Map result){ + Map mapper = new HashMap<>(); + if(!result.get("phonefram").isEmpty()){ + //先验证是否存在 + int isIn = 0; + try { + Map qur = new HashMap<>(); + qur.put("userId",result.get("phonefram")); + isIn = userEnrollService.countById(qur); + if(isIn == 1){ + String code = zhenziyunService.randomCode(); + try { + zhenziyunService.sendMesg(result.get("phonefram"),code); + mapper.put("code","0"); + mapper.put("pcode",code); + mapper.put("msg","验证码已发送"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + }else { + mapper.put("code","1"); + mapper.put("msg","账号未被注册,请先注册"); + } + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + }else{ + mapper.put("code","1"); + mapper.put("msg","未获取手机号"); + } + return mapper; + } + + @RequestMapping("/userEnroll") + @ResponseBody + public Object userEnroll(@RequestBody Map result,HttpServletRequest request) { + Map mapper = new HashMap<>(); + if(!result.isEmpty()){ + try { + UserEnroll userEnroll = new UserEnroll(); + { + userEnroll.setUserId(result.get("phonefram")); + userEnroll.setPassword(result.get("userpass")); + userEnroll.setUserName(result.get("username")); + userEnroll.setUserType(0); + String curtime = DateUtils.getCurTime(); + userEnroll.setEnrollTime(curtime); + userEnroll.setLoginTime(curtime); + } + userEnrollService.userEnroll(userEnroll); + //存储session + request.getSession().setAttribute(ConstantUtils.USER_SESSION_KEY,result.get("phonefram")); + mapper.put("code","0"); + mapper.put("msg","注册成功"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器异常"); + } + }else{ + mapper.put("code","1"); + mapper.put("msg","有异常数值"); + } + return mapper; + } + + @RequestMapping("/userLogin") + @ResponseBody + public Object userLogin(@RequestBody Map result,HttpServletRequest request) { + Map mapper = new HashMap<>(); + if(result.isEmpty()){ + mapper.put("code","1"); + mapper.put("msg","有异常数值"); + }else{ + try { + //查询是否存在账户 + if(userEnrollService.countById(result)==0){ + mapper.put("code","1"); + mapper.put("msg","账号不存在"); + }else{ + String realpass = userEnrollService.loginCheck(result); + if(realpass.equals(result.get("passWord"))){ + //修改登录时间 + Map time = new HashMap<>();{ + time.put("userId",result.get("userId")); + time.put("loginTime",DateUtils.getCurTime()); + } + userEnrollService.loginTimeUpdate(time); + //存储session + request.getSession().setAttribute(ConstantUtils.USER_SESSION_KEY,time.get("userId")); + mapper.put("code","0"); + mapper.put("msg","登录成功"); + + }else{ + mapper.put("code","1"); + mapper.put("msg","账号密码错误"); + } + } + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + } + return mapper; + } + + @RequestMapping("/loginAdmin") + @ResponseBody + public Object loginAdmin(@RequestBody Map result,HttpServletRequest request) { + Map mapper = new HashMap<>(); + Map mapperr = new HashMap<>(); + if(result.isEmpty()){ + mapperr.put("code","1"); + mapperr.put("msg","有异常数值"); + }else{ + try { + //查询是否存在 + mapper.put("userId",result.get("adminId").toString()); + mapper.put("passWord",result.get("adminPass").toString()); + //查询是否存在账户 + if(userEnrollService.countById(mapper)==0){ + mapperr.put("code","1"); + mapperr.put("msg","账号不存在"); + }else{ + String realpass = userEnrollService.loginCheck(mapper); + if(realpass.equals(mapper.get("passWord"))){ + //修改登录时间 + Map time = new HashMap<>();{ + time.put("userId",mapper.get("userId")); + time.put("loginTime",DateUtils.getCurTime()); + } + userEnrollService.loginTimeUpdate(time); + //存储session + request.getSession().setAttribute(ConstantUtils.USER_SESSION_KEY,time.get("userId")); + mapperr.put("code","0"); + mapperr.put("msg","登录成功"); + + }else{ + mapperr.put("code","1"); + mapperr.put("msg","账号密码错误"); + } + } + } catch (Exception e) { + e.printStackTrace(); + mapperr.put("code","1"); + mapperr.put("msg","服务器出错"); + } + } + return mapperr; + } + + @RequestMapping("/adminEnroll") + @ResponseBody + public Object adminEnroll(@RequestBody Map result,HttpServletRequest request) { + Map mapper = new HashMap<>(); + Map mapperr = new HashMap<>(); + if(!result.isEmpty()){ + try { + mapper.put("userId",result.get("userid").toString()); + int userIs = this.userEnrollService.countById(mapper); + if(userIs==0){ + //判断酒店绑定码是否正确 + int isIn = this.hotelInfoServices.isIn(Long.valueOf(result.get("hotelid").toString())); + if(isIn == 1){ + UserEnroll userEnroll = new UserEnroll(); + { + userEnroll.setUserId(result.get("userid").toString()); + userEnroll.setPassword(result.get("password").toString()); + String username = "admin_"+result.get("userid").toString(); + userEnroll.setUserName(username); + userEnroll.setHotelId(Integer.valueOf(result.get("hotelid").toString())); + userEnroll.setUserType(1); + String curtime = DateUtils.getCurTime(); + userEnroll.setEnrollTime(curtime); + userEnroll.setLoginTime(curtime); + } + userEnrollService.userEnroll(userEnroll); + //存储session + request.getSession().setAttribute(ConstantUtils.USER_SESSION_KEY,result.get("userid")); + mapperr.put("code","0"); + mapperr.put("msg","注册成功"); + }else { + mapperr.put("code","1"); + mapperr.put("msg","酒店不存在"); + } + }else { + mapperr.put("code","1"); + mapperr.put("msg","用户名已存在"); + } + } catch (Exception e) { + e.printStackTrace(); + mapperr.put("code","1"); + mapperr.put("msg","服务器异常"); + } + }else{ + mapperr.put("code","1"); + mapperr.put("msg","有异常数值"); + } + return mapperr; + } + + @RequestMapping("/userRefind") + @ResponseBody + public Object userRefind(@RequestBody Map result,HttpServletRequest request) { + Map mapper = new HashMap<>(); + if(result.isEmpty()){ + mapper.put("code","1"); + mapper.put("msg","有异常数值"); + }else{ + try { + //查询是否存在账户 + if(userEnrollService.countById(result)==0){ + mapper.put("code","1"); + mapper.put("msg","账号不存在"); + }else{ + userEnrollService.passUpdate(result); + request.getSession().setAttribute(ConstantUtils.USER_SESSION_KEY,result.get("userId")); + mapper.put("code","0"); + mapper.put("msg","密码已重置"); + } + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + } + return mapper; + } + + @RequestMapping(value = "/index-regs") + public String reg() { return "register/regfram"; } + @RequestMapping(value = "/index-find") + public String findPass(){ return "register/refindfram"; } + + @RequestMapping(value = "/login-success") + public String sucsNavto(String userId,HttpServletRequest request){ + Map mapper = new HashMap<>(); + if(userId!=""&&userId!=null&&request.getSession().getAttribute(ConstantUtils.USER_SESSION_KEY)!=null){ + mapper.put("userId",userId); + try { + int isfirst = this.userEnrollService.getIsFirstLogin(mapper); + if(isfirst==0){ + return "comm/getinfo/info-user"; + }else { + return "tabs/tabfram"; + } + } catch (Exception e) { + return "error/error"; + } + } + return "main"; + } + + @RequestMapping(value = "/admin-frame") + public String adminframe(String adminId,HttpServletRequest request){ + Map mapper = new HashMap<>(); + if(adminId!=""&&adminId!=null&&request.getSession().getAttribute(ConstantUtils.USER_SESSION_KEY)!=null){ + mapper.put("userId",adminId); + try { + return "tabs/adminfram"; + } catch (Exception e) { + return "error/error"; + } + } + return "main"; + } + + @RequestMapping("/getUserInfo") + @ResponseBody + public Object getUserInfo(@RequestBody Map result) { + Map mapper = new HashMap<>(); + if(result.isEmpty()){ + mapper.put("code","1"); + mapper.put("msg","有异常数值"); + }else{ + try { + UserEnroll userEnroll = this.userEnrollService.findById(result.get("userId").toString()); + mapper.put("code","0"); + mapper.put("userEnroll",userEnroll); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + } + return mapper; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/PadFramController.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/PadFramController.java" new file mode 100644 index 00000000..4a100456 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/PadFramController.java" @@ -0,0 +1,466 @@ +package com.aihome.aihomesys.controller; + +import com.aihome.aihomesys.service.*; +import com.aihome.aihomesys.vo.*; +import com.aihome.component.ComputingUnit; +import com.aihome.utils.DateUtils; +import org.apache.ibatis.annotations.Param; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Controller +@RequestMapping("/padding") +public class PadFramController { + @Autowired + UserEnrollService userEnrollService = new UserEnrollService(); + + @Autowired + UserInfoService userInfoService = new UserInfoService(); + + @Autowired + ClassInfoService classInfoService = new ClassInfoService(); + + @Autowired + UserPlanService userPlanService = new UserPlanService(); + + @Autowired + CircleContentServices circleContentServices = new CircleContentServices(); + + @Autowired + UserFollowServices userFollowServices = new UserFollowServices(); + + @Autowired + UserGoodServices userGoodServices = new UserGoodServices(); + + @Autowired + FitnessRecordServices fitnessRecordServices = new FitnessRecordServices(); + + @Autowired + HotelInfoServices hotelInfoServices = new HotelInfoServices(); + + @Autowired + MealInfoServices mealInfoServices = new MealInfoServices(); + + @Autowired + FoodKuServices foodKuServices = new FoodKuServices(); + + ComputingUnit computingUnit = new ComputingUnit(); + + @RequestMapping(value = "pad-statistics") + public String padstatistics(String userId,Map mapper){ + if(userId==null||userId==""){ + return "error/error"; + } + //获取用户基本数据 + try { + UserInfo userInfo = this.userInfoService.findById(userId); + int FitnessTime = 0,CumFatB = 0,CumFatBToday = 0,CumDay = 0,Perfect = 0,Good = 0,Bad = 0; + { + FitnessTime = this.fitnessRecordServices.countFitnessTime(userId)/60; + CumFatB = this.fitnessRecordServices.countCumFatB(userId); + CumFatBToday = this.fitnessRecordServices.countCumFatBToday(userId); + CumDay = this.fitnessRecordServices.countCumday(userId); + Perfect = this.fitnessRecordServices.countPerfect(userId); + Good = this.fitnessRecordServices.countGood(userId); + Bad = this.fitnessRecordServices.countBad(userId); + } + mapper.put("userInfo",userInfo); + mapper.put("FitnessTime",FitnessTime); + mapper.put("CumFatB",CumFatB); + mapper.put("CumFatBToday",CumFatBToday); + mapper.put("CumDay",CumDay); + mapper.put("Perfect",Perfect); + mapper.put("Good",Good); + mapper.put("Bad",Bad); + return "comm/paddingfram/statistics"; + } catch (Exception e) { + e.printStackTrace(); + return "error/error"; + } + } + + @RequestMapping(value = "pad-userinfo") + public String paduserinfo(String userId, Map mapper){ + if (userId==""||userId==null){ + return "error/error"; + }else { + try { + Map temp = new HashMap<>(); + //获取用户基本信息 + UserEnroll userEnroll = this.userEnrollService.findById(userId); + //获取用户健身数据 + UserInfo userInfo = this.userInfoService.findById(userId); + //获取用户选择课程信息 + List ClassInfo = this.classInfoService.selectByUserId(userId); + //获取用户动态 + temp.put("userId",userId); + List circleContents = this.circleContentServices.getMycontAndCallback(temp); + for(int i=0;i temp2 = new HashMap<>(); + temp2.put("userId",userId); + temp2.put("conId",circleContents.get(i).getConId()); + circleContents.get(i).setIsGood(this.userGoodServices.isGood(temp2)); + if(!circleContents.get(i).getConImg().isEmpty()){ + String[] imglist = circleContents.get(i).getConImg().split(","); + circleContents.get(i).setImglist(imglist); + } + } + //统计数值 + int myfollow = this.userFollowServices.countMyFollow(userId); + int followme = this.userFollowServices.countFollowMe(userId); + int planclass = this.userPlanService.countMyClassNum(userId); + { + mapper.put("myfollow",myfollow); + mapper.put("followme",followme); + mapper.put("planclass",planclass); + mapper.put("userEnroll",userEnroll); + mapper.put("userInfo",userInfo); + mapper.put("ClassInfo",ClassInfo); + mapper.put("cc",circleContents); + } + } catch (Exception e) { + e.printStackTrace(); + return "error/error"; + } + } + return "comm/paddingfram/userinfo"; + } + + @RequestMapping(value = "pad-otherInfo") + public String padotherInfo(String userId, String otherId,Map mapper){ + if (otherId==""||otherId==null){ + return "error/error"; + }else { + try { + Map temp = new HashMap<>(); + //获取用户基本信息 + UserEnroll userEnroll = this.userEnrollService.findById(otherId); + //获取用户健身数据 + UserInfo userInfo = this.userInfoService.findById(otherId); + //获取用户选择课程信息 + List ClassInfo = this.classInfoService.selectByUserId(otherId); + //获取用户动态 + temp.put("userId",otherId); + List circleContents = this.circleContentServices.getMycontAndCallback(temp); + for(int i=0;i temp2 = new HashMap<>(); + temp2.put("userId",otherId); + temp2.put("conId",circleContents.get(i).getConId()); + circleContents.get(i).setIsGood(this.userGoodServices.isGood(temp2)); + if(!circleContents.get(i).getConImg().isEmpty()){ + String[] imglist = circleContents.get(i).getConImg().split(","); + circleContents.get(i).setImglist(imglist); + } + } + //统计数值 + int myfollow = this.userFollowServices.countMyFollow(otherId); + int followme = this.userFollowServices.countFollowMe(otherId); + int planclass = this.userPlanService.countMyClassNum(otherId); + int isfollowta = this.userFollowServices.isFollow(userId,otherId); + { + mapper.put("myfollow",myfollow); + mapper.put("followme",followme); + mapper.put("planclass",planclass); + mapper.put("userEnroll",userEnroll); + mapper.put("userInfo",userInfo); + mapper.put("ClassInfo",ClassInfo); + mapper.put("isfollowta",isfollowta); + mapper.put("cc",circleContents); + } + } catch (Exception e) { + e.printStackTrace(); + return "error/error"; + } + } + return "comm/paddingfram/otherUserPage"; + } + + @RequestMapping(value = "/followAction",produces = { "application/json;charset=UTF-8" }) + @ResponseBody + public Object goodAction(@RequestBody Map result){ + Map mapper = new HashMap<>(); + if(result.get("userId")==null||result.get("otherId")==null||result.get("flag")==null){ + mapper.put("code","1"); + mapper.put("msg","参数异常"); + }else { + int flag =Integer.valueOf(result.get("flag").toString()); + Map temp = new HashMap<>(); + temp.put("fuserId",result.get("userId")); + temp.put("fuseredId",result.get("otherId")); + if(flag==0){ //关注 + temp.put("followTime", DateUtils.getCurTime()); + this.userFollowServices.setFollow(temp); + mapper.put("code","0"); + mapper.put("msg","关注成功"); + }else if(flag==1){ //取消 + this.userFollowServices.deleteFollow(temp); + mapper.put("code","0"); + mapper.put("msg","取消成功"); + }else { + mapper.put("code","1"); + mapper.put("msg","参数异常"); + } + } + return mapper; + } + + @RequestMapping(value = "pad-food") + public String padfood(String userId,Map mapper){ + Map result = new HashMap<>(); + result.put("userId",userId); + try { + HotelInfo hotelInfo = this.hotelInfoServices.getHotelInfo(result); + int totalFabt = this.fitnessRecordServices.countCumFatBToday(userId); + mapper.put("code","0"); + mapper.put("hotelInfo",hotelInfo); + mapper.put("totalFabt",totalFabt); + return "comm/paddingfram/foodpro"; + } catch (Exception e) { + e.printStackTrace(); + return "error/error"; + } + } + + @RequestMapping(value = "/getMealList",produces = { "application/json;charset=UTF-8" }) + @ResponseBody + public Object getMealList(@RequestBody Map result){ + Map mapper = new HashMap<>(); + if(result.get("userId")==null||result.get("hotelId")==null){ + mapper.put("code","1"); + mapper.put("msg","参数异常"); + }else { + + MealInfo zao = null; + try { + zao = this.mealInfoServices.getCommMeal(result); + int tempFatb = 0; + + FoodKu staple = this.foodKuServices.selectById(zao.getStapleId()); + zao.setStapleName(staple.getFoodName()); + zao.setStapleCacul(staple.getFoodContent()); + tempFatb+=staple.getFoodFatB(); + + FoodKu MEM = this.foodKuServices.selectById(zao.getMEMId()); + zao.setMEMName(MEM.getFoodName()); + zao.setMEMCacul(MEM.getFoodContent()); + tempFatb+=MEM.getFoodFatB(); + + FoodKu VF = this.foodKuServices.selectById(zao.getVFId()); + zao.setVFName(VF.getFoodName()); + zao.setVFCacul(VF.getFoodContent()); + tempFatb+=VF.getFoodFatB(); + + FoodKu Grease = this.foodKuServices.selectById(zao.getGreaseId()); + zao.setGreaseName(Grease.getFoodName()); + zao.setGreaseCacul(Grease.getFoodContent()); + tempFatb+=Grease.getFoodFatB(); + + FoodKu other = this.foodKuServices.selectById(zao.getOtherId()); + if(other!=null){ + zao.setOtherName(other.getFoodName()); + zao.setOtherCacul(other.getFoodContent()); + tempFatb+=other.getFoodFatB(); + } + zao.setTotalFatB(tempFatb); + mapper.put("code", "0"); + mapper.put("msg", "查询成功"); + mapper.put("mealInfo",zao); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错啦"); + } + } + return mapper; + } + + @RequestMapping(value = "pad-foodku") + public String padfoodku(String userId,Map mapper){ + Map result = new HashMap<>(); + result.put("userId",userId); + try { + HotelInfo hotelInfo = this.hotelInfoServices.getHotelInfo(result); + int totalFabt = this.fitnessRecordServices.countCumFatBToday(userId); + mapper.put("code","0"); + mapper.put("hotelInfo",hotelInfo); + mapper.put("totalFabt",totalFabt); + return "comm/paddingfram/foodku"; + } catch (Exception e) { + e.printStackTrace(); + return "error/error"; + } + } + + @RequestMapping(value = "/getFoodku",produces = { "application/json;charset=UTF-8" }) + @ResponseBody + public Object getFoodku(@RequestBody Map result){ + Map mapper = new HashMap<>(); + if(result.get("hotelId")==null){ + mapper.put("code","1"); + mapper.put("msg","参数异常"); + }else { + List foodlist = null; + try { + foodlist = this.foodKuServices.selectFoodListByHotel(Integer.valueOf(result.get("hotelId").toString())); + mapper.put("code", "0"); + mapper.put("msg", "查询成功"); + mapper.put("foodlist",foodlist); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错啦"); + } + } + return mapper; + } + + @RequestMapping(value = "pad-select") + public String padselect(String userId,Map mapper){ + Map result = new HashMap<>(); + result.put("userId",userId); + try { + HotelInfo hotelInfo = this.hotelInfoServices.getHotelInfo(result); + mapper.put("hotelInfo",hotelInfo); + return "comm/paddingfram/selectFood"; + } catch (Exception e) { + e.printStackTrace(); + return "error/error"; + } + } + + @RequestMapping(value = "pad-changeinfo") + public String padchangeinfo(String userId,Map mapper){ + if(userId==""||userId==null){ + return "error/error"; + } + try { + UserEnroll userEnroll = this.userEnrollService.findById(userId); + UserInfo userInfo = this.userInfoService.findById(userId); + mapper.put("userEnroll",userEnroll); + mapper.put("userInfo",userInfo); + return "comm/paddingfram/changeInfo"; + } catch (Exception e) { + e.printStackTrace(); + return "error/error"; + } + } + + @RequestMapping(value = "/uploadImg",produces = { "application/json;charset=UTF-8" }) + @ResponseBody + public Object uploadImg(@RequestParam("file") MultipartFile file, HttpServletRequest req){ + String userId = req.getParameter("userId"); + String realPath=req.getServletContext().getRealPath("/uploadImg"); + Map mapper = new HashMap<>(); + MultipartFile img = file; + if(img.isEmpty()||userId.isEmpty()){ + mapper.put("code", "1"); + mapper.put("msg", "服务器出错"); + }else{ + String fileName = "nav_"+userId+"_"+DateUtils.getCurTime2Number(); + File dest = new File(new File(realPath).getAbsolutePath()+ "/../../resources/static/images/nav/" + userId + "/" + fileName+".png"); + if (!dest.getParentFile().exists()) { + dest.getParentFile().mkdirs(); + } + try { + file.transferTo(dest); // 保存文件 + String userAva = userId+"/"+fileName+".png"; + //修改数据库 + this.userEnrollService.userAvaUpdate(userId,userAva); + mapper.put("code", "0"); + mapper.put("msg", "上传成功"); + mapper.put("filename",userAva); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code", "1"); + mapper.put("msg", "服务器出错"); + } + } + return mapper; + } + + @RequestMapping(value = "infoInsert") + @ResponseBody + public Object infoInsert(@RequestBody Map result){ + Map mapper = new HashMap<>(); + if(result.get("userId")!=""&&result.get("userId")!=null){ + result.put("modifyTime", DateUtils.getCurTime()); + result.put("BMI",computingUnit.BMICom(result.get("height"),result.get("weight"))); + try { + this.userInfoService.infoUpdate(result); + this.userEnrollService.userNameUpdate(result); + mapper.put("code","0"); + mapper.put("msg","数据存取成功"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器出错"); + } + }else { + mapper.put("code","1"); + mapper.put("msg","有异常数值"); + } + return mapper; + } + + @RequestMapping(value = "/getEchartsData") + @ResponseBody + public Object getEchartsData(@RequestBody Map result){ + Map mapper = new HashMap<>(); + if(result.get("userId")==null||result.get("userId")==""){ + mapper.put("code","1"); + mapper.put("msg","参数错误"); + }else{ + //获取前一周 + String userId = result.get("userId").toString(); + try { + List datalist = DateUtils.getLastWeek(DateUtils.getCurTime()); + List weekplan = new ArrayList<>(); + List weektime = new ArrayList<>(); + List weekFatB = new ArrayList<>(); + List period = new ArrayList<>(); + for(int i=datalist.size()-1;i>=0;i--){ + //获取当天数据 + int plannum = this.fitnessRecordServices.countEchartPlan(userId,datalist.get(i)); + weekplan.add(plannum); + int timenum = this.fitnessRecordServices.countEchartFitnessTime(userId,datalist.get(i))/60; + weektime.add(timenum); + int FatB = this.fitnessRecordServices.countEchartFatB(userId,datalist.get(i)); + weekFatB.add(FatB); + } + //每天健身时段 + { + period.add(this.fitnessRecordServices.count69(userId)); + period.add(this.fitnessRecordServices.count912(userId)); + period.add(this.fitnessRecordServices.count1215(userId)); + period.add(this.fitnessRecordServices.count1518(userId)); + period.add(this.fitnessRecordServices.count1821(userId)); + period.add(this.fitnessRecordServices.count210(userId)); + period.add(this.fitnessRecordServices.count0after(userId)); + } + mapper.put("code","0"); + mapper.put("msg","数据拉取成功"); + mapper.put("weekplan",weekplan); + mapper.put("weektime",weektime); + mapper.put("weekFatB",weekFatB); + mapper.put("period",period); + } catch (ParseException e) { + e.printStackTrace(); + } + } + + return mapper; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/PlanCoreController.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/PlanCoreController.java" new file mode 100644 index 00000000..da53458b --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/PlanCoreController.java" @@ -0,0 +1,308 @@ +package com.aihome.aihomesys.controller; + +import com.aihome.aihomesys.service.*; +import com.aihome.aihomesys.vo.ActionInfo; +import com.aihome.aihomesys.vo.CircleContent; +import com.aihome.aihomesys.vo.ClassInfo; +import com.aihome.aihomesys.vo.UserPlan; +import com.aihome.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartResolver; +import org.springframework.web.multipart.commons.CommonsMultipartResolver; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Controller +@RequestMapping(value = "plan") +public class PlanCoreController { + @Autowired + ClassInfoService classInfoService = new ClassInfoService(); + @Autowired + UserPlanService userPlanService = new UserPlanService(); + @Autowired + UserEnrollService userEnrollService = new UserEnrollService(); + @Autowired + UserInfoService userInfoService = new UserInfoService(); + @Autowired + ActionInfoServices actionInfoServices = new ActionInfoServices(); + @Autowired + CircleContentServices circleContentServices = new CircleContentServices(); + @Autowired + UserGoodServices userGoodServices = new UserGoodServices(); + @Autowired + FitnessRecordServices fitnessRecordServices = new FitnessRecordServices(); + + @RequestMapping(value = "userSubc") + @ResponseBody + public Object userSubc(@RequestBody Map res){ + Map mapper = new HashMap<>(); + if(res.get("userId").equals("")||res.get("classId").equals("")){ + mapper.put("code","1"); + mapper.put("msg","违法参数"); + }else { + //添加信息 + String userId = res.get("userId").toString(); + int classId = (int)res.get("classId"); + //先判断是否存在 + int isIn = 0; + try { + isIn = this.userPlanService.countById(res); + if(isIn == 0) { + //获取课程信息 + try { + ClassInfo classInfo = this.classInfoService.selectById(res); + if(classInfo!=null){ + res.put("className",classInfo.getClassName()); + res.put("classImg",classInfo.getClassImg()); + res.put("classTime",classInfo.getClassTime()); + res.put("subTime", DateUtils.getCurTime()); + this.userPlanService.infoinsert(res); + //修改订阅人数 + this.classInfoService.updateSub(res); + mapper.put("code","0"); + mapper.put("msg","成功订阅"); + }else { + mapper.put("code","1"); + mapper.put("msg","未获得课程信息"); + } + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器错误"); + } + }else{ + mapper.put("code","1"); + mapper.put("msg","重复订阅"); + } + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器错误"); + } + } + return mapper; + } + + @RequestMapping(value = "/start") + public String planStart(String userId,Map mapper){ + Map res = new HashMap<>(); + res.put("userId",userId); + if(userId!=null&&userId!=""){ + //获取用户数据 + List todaylist = null; + List mylist = null; + try { + todaylist = this.userPlanService.selectTodayTask(res); + mylist = this.userPlanService.selectMyTask(res); + //计算表头数据 + { + int cumfitness = this.userInfoService.findById(userId).getTrainDay(); + int todayTime = todaylist.size(); + int allmyTime = 0; + for(int i=0;i mapper = new HashMap<>(); + try { + List randaction = this.actionInfoServices.randGetpos(); + mapper.put("code","0"); + mapper.put("randaction",randaction); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code", "1"); + mapper.put("msg", "服务器出错"); + } + return mapper; + } + + @RequestMapping(value = "/start-whole") + public String planWhole(String userId,String classId,Map mapper){ + if (userId!=null&&classId!=null){ + //获取课程参数 + Map res = new HashMap<>(); + res.put("userId",userId); + res.put("classId",classId); + try { + //获取课程参数 + ClassInfo classInfo = this.classInfoService.selectById(res); + //获取课程所拥有动作信息 + List al = this.actionInfoServices.selectByclassId(res); + //获取用户评论信息 + List circleContents = this.circleContentServices.fromClass2Content(Integer.valueOf(classId)); + for(int i=0;i temp = new HashMap<>(); + temp.put("userId",userId); + temp.put("conId",circleContents.get(i).getConId()); + circleContents.get(i).setIsGood(this.userGoodServices.isGood(temp)); + String[] imglist = circleContents.get(i).getConImg().split(","); + circleContents.get(i).setImglist(imglist); + } + int acNumber = 0; + mapper.put("code","0"); + mapper.put("classInfo",classInfo); + mapper.put("actionInfo",al); + acNumber = al.size(); + mapper.put("acNumber",acNumber); + mapper.put("cc",circleContents); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + return "error/error"; + } + } + return "comm/planfram/planwhole"; + } + + @RequestMapping(value = "/start-pose") + public String planPose(String userId,String actionId,Map mapper){ + if(userId!=null&&actionId!=null){ + //获取动作参数 + Map res = new HashMap<>(); + res.put("actionId",actionId); + ActionInfo actionInfo = null; + try { + actionInfo = this.actionInfoServices.selectById(res); + mapper.put("code","0"); + mapper.put("actionInfo",actionInfo); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + return "comm/planfram/planpose"; + } + } + return "comm/planfram/planpose"; + } + + @RequestMapping(value = "/uploadAction",produces = { "application/json;charset=UTF-8" }) + @ResponseBody + public Object uploadAction(@RequestParam("file") MultipartFile file){ + Map mapper = new HashMap<>(); + MultipartFile img = file; + if(img.isEmpty()){ + mapper.put("code", "1"); + mapper.put("msg", "服务器出错"); + }else{ + String fileName = file.getOriginalFilename(); + File dest = new File(new File("D:\\test").getAbsolutePath()+ "/" + fileName+".png"); + if (!dest.getParentFile().exists()) { + dest.getParentFile().mkdirs(); + } + try { + file.transferTo(dest); // 保存文件 + mapper.put("code", "0"); + mapper.put("msg", "上传成功"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code", "1"); + mapper.put("msg", "服务器出错"); + } + } + return mapper; + } + + @RequestMapping(value = "updateUserPlan") + @ResponseBody + public Object updateUserPlan(@RequestBody Map result){ + Map mapper = new HashMap<>(); + String userId = result.get("userId").toString(); + int classId =Integer.valueOf(result.get("classId").toString()); + if(userId==null||classId==0){ + mapper.put("code","2"); + mapper.put("msg","未获得用户信息"); + }else { + try { + //查看今日是否已经完成训练记录 + if(this.userInfoService.todayIsTrain(result)==0){ + this.userInfoService.trainUpdate(result); + } + //查看今日是否完成计划 + int isComToday = this.userPlanService.countTodayIsCom(result); + if(isComToday==0){ + result.put("todayTime",DateUtils.getCurTime()); + result.put("recordTime",DateUtils.getCurTime()); + this.userPlanService.updateOneClass(result); + this.fitnessRecordServices.recordInsert(result); + //判断是否已经完成整个课程 + UserPlan userPlan = this.userPlanService.selectByClassIdAndUserId(result); + if(Integer.valueOf(userPlan.getComTime().toString())==Integer.valueOf(userPlan.getClassTime().toString())){ + this.userPlanService.updateIsCom(result); + mapper.put("code","0_2"); + mapper.put("msg","恭喜您,已完成全部课程系列,为您燃脂:"+userPlan.getTotalFatB()+"Kcal!"); + }else{ + mapper.put("code","0_3"); + mapper.put("msg","恭喜您,已完成今日课程,燃脂:"+userPlan.getTotalFatB()+"Kcal!继续努力吧!"); + } + }else { + result.put("todayTime",DateUtils.getCurTime()); + result.put("recordTime",DateUtils.getCurTime()); + this.userPlanService.updateFatB(result); + this.fitnessRecordServices.recordInsert(result); + mapper.put("code","0_1"); + mapper.put("msg","今日已完成课程,燃脂:"+result.get("totalFatB")+"Kcal!继续努力吧!"); + } + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器异常"); + } + } + return mapper; + } + + @RequestMapping(value = "updatePoseRecord") + @ResponseBody + public Object updatePoseRecord(@RequestBody Map result){ + Map mapper = new HashMap<>(); + String userId = result.get("userId").toString(); + int actionId =Integer.valueOf(result.get("fkId").toString()); + if(userId==null||actionId==0){ + mapper.put("code","2"); + mapper.put("msg","未获得用户信息,运动记录上传失败..."); + }else { + try { + result.put("recordTime",DateUtils.getCurTime()); + this.fitnessRecordServices.recordInsert(result); + mapper.put("code","0"); + mapper.put("msg","运动记录已上传"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","服务器异常,运动记录上传失败..."); + } + } + return mapper; + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/getTokenController.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/getTokenController.java" new file mode 100644 index 00000000..cf287c77 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/getTokenController.java" @@ -0,0 +1,46 @@ +package com.aihome.aihomesys.controller; + +import io.rong.RongCloud; +import io.rong.methods.user.User; +import io.rong.models.response.TokenResult; +import io.rong.models.user.UserModel; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.HashMap; +import java.util.Map; + +@Controller +@RequestMapping(value = "/adam") +public class getTokenController { + private String appKey = "sfci50a7sx7ti"; + private String appSecret = "GWSSPy6nYP"; + + @RequestMapping("/getToken") + @ResponseBody + public Object getToken(@RequestBody Map result){ + Map mapper = new HashMap<>(); + try { + RongCloud rongCloud = RongCloud.getInstance(appKey, appSecret); + User user = rongCloud.user; + String userName = result.get("username").toString(); + UserModel userModel = new UserModel() + .setId(userName) + .setName(userName) + .setPortrait("http://www.rongcloud.cn/images/logo.png"); + TokenResult tokenResult = null; + tokenResult = user.register(userModel); + mapper.put("tokenResult",tokenResult); + mapper.put("code","0"); + mapper.put("msg","登录成功"); + } catch (Exception e) { + e.printStackTrace(); + mapper.put("code","1"); + mapper.put("msg","登录失败"); + } + return mapper; + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/testController.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/testController.java" new file mode 100644 index 00000000..893ac4f2 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/controller/testController.java" @@ -0,0 +1,14 @@ +package com.aihome.aihomesys.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping(value = "/test") +public class testController { + @GetMapping + public String circle(){ + return "comm/test/video"; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IActionInfoDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IActionInfoDao.java" new file mode 100644 index 00000000..3efae05e --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IActionInfoDao.java" @@ -0,0 +1,18 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.ActionInfo; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Repository +public interface IActionInfoDao extends IBaseDao { + List selectByclassId(Map map); + List getAllitems(); + int countById(Map map); + List randGetpos(); + ActionInfo selectById(Map map); +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/ICircleContentDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/ICircleContentDao.java" new file mode 100644 index 00000000..e81feeef --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/ICircleContentDao.java" @@ -0,0 +1,28 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.CircleContent; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Repository +public interface ICircleContentDao extends IBaseDao { + int insertCont(Map map); + List getHot(Map map); + int countHot(Map map); + List getFollow(Map map); + int countFollow(Map map); + List getMycont(Map map); + int countMycont(Map map); + CircleContent getUserCont(int conId); + List getUsers2Contents(int conId); + void contAdd(Map map); + void goodAdd(Map map); + void goodSub(Map map); + List fromClass2Content(int classId); + List getMycontAndCallback(Map map); + List getSearchItems(Map map); +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IClassInfoDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IClassInfoDao.java" new file mode 100644 index 00000000..9ef08329 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IClassInfoDao.java" @@ -0,0 +1,29 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.ClassInfo; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; +@Repository +public interface IClassInfoDao extends IBaseDao { + + List selectByKeys(Map map); + + List getAllitems(Map map); + int getAllCounts(); + + List selectByTitle(Map map); + int countByTitle(Map map); + + ClassInfo selectById(Map map); + + void updateSub(Map map); + + List selectByUserId(String userId); + + List getSearch(String val); + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IFitnessRecordDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IFitnessRecordDao.java" new file mode 100644 index 00000000..2a35f874 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IFitnessRecordDao.java" @@ -0,0 +1,33 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.ActionInfo; +import com.aihome.aihomesys.vo.FitnessRecord; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Repository +public interface IFitnessRecordDao extends IBaseDao { + void recordInsert(Map mapper); + int countFitnessTime(String userId); + int countCumFatB(String userId); + int countCumFatBToday(String userId); + int countCumday(String userId); + int countPerfect(String userId); + int countGood(String userId); + int countBad(String userId); + int countEchartFatB(String userId,String recordTime); + int countEchartFitnessTime(String userId,String recordTime); + int countEchartPlan(String userId,String recordTime); + + int count69(String userId); + int count912(String userId); + int count1215(String userId); + int count1518(String userId); + int count1821(String userId); + int count210(String userId); + int count0after(String userId); +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IFoodKuDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IFoodKuDao.java" new file mode 100644 index 00000000..626454dc --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IFoodKuDao.java" @@ -0,0 +1,17 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.ActionInfo; +import com.aihome.aihomesys.vo.FoodKu; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Repository +public interface IFoodKuDao extends IBaseDao { + FoodKu selectById(int foodId); + + List selectFoodListByHotel(int hotelId); +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IHotelInfoDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IHotelInfoDao.java" new file mode 100644 index 00000000..04052457 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IHotelInfoDao.java" @@ -0,0 +1,19 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.ActionInfo; +import com.aihome.aihomesys.vo.HotelInfo; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Repository +public interface IHotelInfoDao extends IBaseDao { + int isIn(long hotelId); + + HotelInfo getHotelInfo(Map result); + + void setHotelInfo(Map result); +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/ILabelTypeDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/ILabelTypeDao.java" new file mode 100644 index 00000000..fc6cecea --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/ILabelTypeDao.java" @@ -0,0 +1,13 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.LabelType; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.List; + +@Repository +public interface ILabelTypeDao extends IBaseDao { + List getAllitems(); +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IMealInfoDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IMealInfoDao.java" new file mode 100644 index 00000000..3e6b5785 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IMealInfoDao.java" @@ -0,0 +1,17 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.ActionInfo; +import com.aihome.aihomesys.vo.MealInfo; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Repository +public interface IMealInfoDao extends IBaseDao { + List getMealList(Map result); + + MealInfo getCommMeal(Map result); +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserEnrollDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserEnrollDao.java" new file mode 100644 index 00000000..a12eaa5c --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserEnrollDao.java" @@ -0,0 +1,24 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.UserEnroll; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Repository +public interface IUserEnrollDao extends IBaseDao { + List getAllitems(); + int countById(Map mapper); + void loginTimeUpdate(Map mapper); + String loginCheck(Map mapper); + void passUpdate(Map mapper); + int enableInfoco(Map mapper); + void eableUpdate(Map mapper); + void userAvaUpdate(String userId,String userAva); + void userNameUpdate(Map map); +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserFollowDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserFollowDao.java" new file mode 100644 index 00000000..b79b7a6f --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserFollowDao.java" @@ -0,0 +1,20 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.UserFollow; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Repository +public interface IUserFollowDao extends IBaseDao { + List selectMyFollow(Map map); + List selectFollowMe(Map map); + int countMyFollow(Map map); + int countFollowMe(Map map); + int isFollow(String fuserId,String fuseredId); + void setFollow(Map map); + void deleteFollow(Map map); +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserGoodDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserGoodDao.java" new file mode 100644 index 00000000..6375a854 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserGoodDao.java" @@ -0,0 +1,18 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.UserGood; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.Map; + +@Repository +public interface IUserGoodDao extends IBaseDao { + int isGood(Map map); + + void insertGood(Map map); + + void deleteGood(Map map); + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserInfoDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserInfoDao.java" new file mode 100644 index 00000000..aac7a96a --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserInfoDao.java" @@ -0,0 +1,20 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.UserEnroll; +import com.aihome.aihomesys.vo.UserInfo; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.Map; + +@Repository +public interface IUserInfoDao extends IBaseDao { + int skipinsert(Map map); + int infoinsert(Map map); + int countById(Map mapper); + void skipUpdate(Map mapper); + void infoUpdate(Map mapper); + int todayIsTrain(Map mapper); + void trainUpdate(Map mapper); +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserLabelDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserLabelDao.java" new file mode 100644 index 00000000..4461a8ef --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserLabelDao.java" @@ -0,0 +1,15 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.UserLabel; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.List; + +@Repository +public interface IUserLabelDao extends IBaseDao { + int insertForeach(List list); + List getAllitems(String userId); +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserPlanDao.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserPlanDao.java" new file mode 100644 index 00000000..f1917b8b --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/dao/IUserPlanDao.java" @@ -0,0 +1,24 @@ +package com.aihome.aihomesys.dao; + +import com.aihome.aihomesys.base.IBaseDao; +import com.aihome.aihomesys.vo.ActionInfo; +import com.aihome.aihomesys.vo.UserPlan; +import org.springframework.stereotype.Repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Repository +public interface IUserPlanDao extends IBaseDao { + void infoinsert(Map map); + int countById(Map map); + List selectTodayTask(Map map); + List selectMyTask(Map map); + int countTodayIsCom(Map map); + void updateOneClass(Map map); + void updateIsCom(Map map); + UserPlan selectByClassIdAndUserId(Mapmap); + void updateFatB(Mapmap); + int countMyClassNum(String userId); +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/ActionInfoServices.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/ActionInfoServices.java" new file mode 100644 index 00000000..a8e342ba --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/ActionInfoServices.java" @@ -0,0 +1,27 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.IActionInfoDao; +import com.aihome.aihomesys.vo.ActionInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class ActionInfoServices { + @Autowired + IActionInfoDao iActionInfoDao; + + public List selectByclassId(Map map){ + return this.iActionInfoDao.selectByclassId(map); + } + + public int countById(Map map){ + return this.iActionInfoDao.countById(map); + } + + public List randGetpos(){return this.iActionInfoDao.randGetpos();} + + public ActionInfo selectById(Map map){return this.iActionInfoDao.selectById(map);} +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/CircleContentServices.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/CircleContentServices.java" new file mode 100644 index 00000000..1469add6 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/CircleContentServices.java" @@ -0,0 +1,80 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.ICircleContentDao; +import com.aihome.aihomesys.vo.CircleContent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class CircleContentServices { + @Autowired + ICircleContentDao iCircleContentDao; + + public int insert(Map map){ + return this.iCircleContentDao.insertCont(map); + } + + public List getHot(Map map){ + return this.iCircleContentDao.getHot(map); + } + public int countHot(Map map){ + return this.iCircleContentDao.countHot(map); + } + + public List getFollow(Map map){ + Map re = new HashMap<>(); + re.put("fuserId",map.get("userId")); + re.put("page",map.get("page")); + re.put("number",map.get("number")); + return this.iCircleContentDao.getFollow(re); + } + public int countFollow(Map map){ + Map re = new HashMap<>(); + re.put("fuserId",map.get("userId")); + return this.iCircleContentDao.countFollow(map); + } + + public List getMycont(Map map){ + return this.iCircleContentDao.getMycont(map); + } + public int countMycont(Map map){ + return this.iCircleContentDao.countMycont(map); + } + + public CircleContent getUserCont(int conId){ + return this.iCircleContentDao.getUserCont(conId); + } + + public List getUsers2Contents(int contId){ + return this.iCircleContentDao.getUsers2Contents(contId); + } + + public void contAdd(Map map){ + this.iCircleContentDao.contAdd(map); + } + + public void goodAdd(Map map){ + this.iCircleContentDao.goodAdd(map); + } + + public void goodSub(Map map){ + this.iCircleContentDao.goodSub(map); + } + + public List fromClass2Content(int classId){ + return this.iCircleContentDao.fromClass2Content(classId); + }; + + public List getMycontAndCallback(Map map){ + return this.iCircleContentDao.getMycontAndCallback(map); + }; + + public List getSearchItems(Map map){ + return this.iCircleContentDao.getSearchItems(map); + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/ClassInfoService.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/ClassInfoService.java" new file mode 100644 index 00000000..be80b99a --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/ClassInfoService.java" @@ -0,0 +1,50 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.IClassInfoDao; +import com.aihome.aihomesys.vo.ClassInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class ClassInfoService { + + @Autowired + IClassInfoDao iClassInfoDao; + + public List selectByKeys(Map map){ + return this.iClassInfoDao.selectByKeys(map); + } + + public List getAll(Map map){ + return this.iClassInfoDao.getAllitems(map); + } + public int getAllCounts(){ + return this.iClassInfoDao.getAllCounts(); + } + + public List selectBytitles(Map map){ + return this.iClassInfoDao.selectByTitle(map); + } + public int countByTitle(Map map){ + return this.iClassInfoDao.countByTitle(map); + }; + + public ClassInfo selectById(Map map) { + return this.iClassInfoDao.selectById(map); + } + + public void updateSub(Map map){ this.iClassInfoDao.updateSub(map);} + + public List selectByUserId(String userId){ + return this.iClassInfoDao.selectByUserId(userId); + } + + public List getSearch(String val){ + return this.iClassInfoDao.getSearch(val); + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/FitnessRecordServices.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/FitnessRecordServices.java" new file mode 100644 index 00000000..b5d917e9 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/FitnessRecordServices.java" @@ -0,0 +1,83 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.IActionInfoDao; +import com.aihome.aihomesys.dao.IFitnessRecordDao; +import com.aihome.aihomesys.vo.ActionInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class FitnessRecordServices { + @Autowired + IFitnessRecordDao iFitnessRecordDao; + + public void recordInsert(Map mapper){ + this.iFitnessRecordDao.recordInsert(mapper); + } + + public int countFitnessTime(String userId){ + return this.iFitnessRecordDao.countFitnessTime(userId); + } + + public int countCumFatB(String userId){ + return this.iFitnessRecordDao.countCumFatB(userId); + } + + public int countCumFatBToday(String userId){ + return this.iFitnessRecordDao.countCumFatBToday(userId); + } + + public int countCumday(String userId){ + return this.iFitnessRecordDao.countCumday(userId); + } + + public int countPerfect(String userId){ + return this.iFitnessRecordDao.countPerfect(userId); + } + + public int countGood(String userId){ + return this.iFitnessRecordDao.countGood(userId); + } + + public int countBad(String userId){ + return this.iFitnessRecordDao.countBad(userId); + } + + public int countEchartFatB(String userId,String recordTime){ + return this.iFitnessRecordDao.countEchartFatB(userId,recordTime); + } + + public int countEchartFitnessTime(String userId,String recordTime){ + return this.iFitnessRecordDao.countEchartFitnessTime(userId,recordTime); + } + + public int countEchartPlan(String userId,String recordTime){ + return this.iFitnessRecordDao.countEchartPlan(userId,recordTime); + } + + public int count69(String userId){ + return this.iFitnessRecordDao.count69(userId); + } + public int count912(String userId){ + return this.iFitnessRecordDao.count912(userId); + } + public int count1215(String userId){ + return this.iFitnessRecordDao.count1215(userId); + } + public int count1518(String userId){ + return this.iFitnessRecordDao.count1518(userId); + } + public int count1821(String userId){ + return this.iFitnessRecordDao.count1821(userId); + } + public int count210(String userId){ + return this.iFitnessRecordDao.count210(userId); + } + public int count0after(String userId){ + return this.iFitnessRecordDao.count0after(userId); + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/FoodKuServices.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/FoodKuServices.java" new file mode 100644 index 00000000..bd300c58 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/FoodKuServices.java" @@ -0,0 +1,26 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.IActionInfoDao; +import com.aihome.aihomesys.dao.IFoodKuDao; +import com.aihome.aihomesys.vo.ActionInfo; +import com.aihome.aihomesys.vo.FoodKu; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class FoodKuServices { + @Autowired + IFoodKuDao iFoodKuDao; + + public FoodKu selectById(int foodId){ + return this.iFoodKuDao.selectById(foodId); + } + + public List selectFoodListByHotel(int hotelId){ + return this.iFoodKuDao.selectFoodListByHotel(hotelId); + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/HotelInfoServices.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/HotelInfoServices.java" new file mode 100644 index 00000000..e05ec317 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/HotelInfoServices.java" @@ -0,0 +1,29 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.IActionInfoDao; +import com.aihome.aihomesys.dao.IHotelInfoDao; +import com.aihome.aihomesys.vo.ActionInfo; +import com.aihome.aihomesys.vo.HotelInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class HotelInfoServices { + @Autowired + IHotelInfoDao iHotelInfoDao; + + public int isIn(long hotelId){ + return this.iHotelInfoDao.isIn(hotelId); + } + + public HotelInfo getHotelInfo(Map result) { + return this.iHotelInfoDao.getHotelInfo(result); + } + + public void setHotelInfo(Map result) { + this.iHotelInfoDao.setHotelInfo(result); + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/LabelTypeService.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/LabelTypeService.java" new file mode 100644 index 00000000..c3a05d80 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/LabelTypeService.java" @@ -0,0 +1,19 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.ILabelTypeDao; +import com.aihome.aihomesys.vo.LabelType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class LabelTypeService { + + @Autowired + ILabelTypeDao iLabelTypeDao; + + public List getAll(){ + return this.iLabelTypeDao.getAllitems(); + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/MealInfoServices.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/MealInfoServices.java" new file mode 100644 index 00000000..117c1162 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/MealInfoServices.java" @@ -0,0 +1,25 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.IActionInfoDao; +import com.aihome.aihomesys.dao.IMealInfoDao; +import com.aihome.aihomesys.vo.ActionInfo; +import com.aihome.aihomesys.vo.MealInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class MealInfoServices { + @Autowired + IMealInfoDao iMealInfoDao; + + public List getMealList(Map result) { + return this.iMealInfoDao.getMealList(result); + } + + public MealInfo getCommMeal(Map result) { + return this.iMealInfoDao.getCommMeal(result); + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserEnrollService.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserEnrollService.java" new file mode 100644 index 00000000..2d1f7600 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserEnrollService.java" @@ -0,0 +1,58 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.IUserEnrollDao; +import com.aihome.aihomesys.vo.UserEnroll; +import org.apache.catalina.User; +import org.apache.tomcat.util.buf.UEncoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class UserEnrollService { + + @Autowired + IUserEnrollDao userEnrollDao; + + public List selectAll(){ + List list = this.userEnrollDao.getAllitems(); + return list; + } + + public int userEnroll(UserEnroll userEnroll){ + return this.userEnrollDao.insert(userEnroll); + } + + public int countById(Map map){ + return this.userEnrollDao.countById(map); + } + + public String loginCheck(Map map){ + return this.userEnrollDao.loginCheck(map); + } + + public void loginTimeUpdate(Map map){ + this.userEnrollDao.loginTimeUpdate(map); + } + + public void passUpdate(Map map){ + this.userEnrollDao.passUpdate(map); + } + + public void eableUpdate(Map map){ this.userEnrollDao.eableUpdate(map); } + + public int getIsFirstLogin(Map map){return this.userEnrollDao.enableInfoco(map);} + + public UserEnroll findById(String userId){return this.userEnrollDao.findById(userId);} + + public void userAvaUpdate(String userId,String userAva){ + this.userEnrollDao.userAvaUpdate(userId,userAva); + } + + public void userNameUpdate(Map mapper){ + this.userEnrollDao.userNameUpdate(mapper); + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserFollowServices.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserFollowServices.java" new file mode 100644 index 00000000..2531843f --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserFollowServices.java" @@ -0,0 +1,54 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.ICircleContentDao; +import com.aihome.aihomesys.dao.IUserFollowDao; +import com.aihome.aihomesys.vo.UserFollow; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class UserFollowServices { + @Autowired + IUserFollowDao iUserFollowDao; + + public List selectMyFollow(String userId){ + Map map = new HashMap<>(); + map.put("fuserId",userId); + return this.iUserFollowDao.selectMyFollow(map); + } + + public List selectFollowMe(String userId){ + Map map = new HashMap<>(); + map.put("fuseredId",userId); + return this.iUserFollowDao.selectFollowMe(map); + } + + public int countMyFollow(String userId){ + Map map = new HashMap<>(); + map.put("fuserId",userId); + return this.iUserFollowDao.countMyFollow(map); + } + + public int countFollowMe(String userId){ + Map map = new HashMap<>(); + map.put("fuseredId",userId); + return this.iUserFollowDao.countFollowMe(map); + } + + public int isFollow(String fuserId,String fuseredId){ + return this.iUserFollowDao.isFollow(fuserId,fuseredId); + } + + public void setFollow(Map map){ + this.iUserFollowDao.setFollow(map); + } + + public void deleteFollow(Map map){ + this.iUserFollowDao.deleteFollow(map); + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserGoodServices.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserGoodServices.java" new file mode 100644 index 00000000..22b9f048 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserGoodServices.java" @@ -0,0 +1,26 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.IUserFollowDao; +import com.aihome.aihomesys.dao.IUserGoodDao; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Service +public class UserGoodServices { + @Autowired + IUserGoodDao iUserGoodDao; + + public int isGood(Map map){ + return this.iUserGoodDao.isGood(map); + } + + public void insertGood(Map map){ + this.iUserGoodDao.insertGood(map); + } + + public void deleteGood(Map map){ + this.iUserGoodDao.deleteGood(map); + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserInfoService.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserInfoService.java" new file mode 100644 index 00000000..0f01eede --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserInfoService.java" @@ -0,0 +1,44 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.IUserInfoDao; +import com.aihome.aihomesys.vo.UserInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Service +public class UserInfoService { + @Autowired + IUserInfoDao iUserInfoDao; + + public int skipinsert(Map map){ + return this.iUserInfoDao.skipinsert(map); + } + + public int infoinsert(Map map){ + return this.iUserInfoDao.infoinsert(map); + } + + public int counById(Map map){ + return this.iUserInfoDao.countById(map); + } + + public void skipUpdate(Map map){ + this.iUserInfoDao.skipUpdate(map); + } + + public void infoUpdate(Map map){ + this.iUserInfoDao.infoUpdate(map); + } + + public UserInfo findById(String userId){return this.iUserInfoDao.findById(userId);} + + public int todayIsTrain(Map mapper){ + return this.iUserInfoDao.todayIsTrain(mapper); + }; + + public void trainUpdate(Map mapper){ + this.iUserInfoDao.trainUpdate(mapper); + }; +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserLabelServices.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserLabelServices.java" new file mode 100644 index 00000000..c46eed64 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserLabelServices.java" @@ -0,0 +1,22 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.IUserLabelDao; +import com.aihome.aihomesys.vo.UserLabel; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class UserLabelServices { + @Autowired + IUserLabelDao iUserLabelDao; + + public List getAll(String userId){ + return this.iUserLabelDao.getAllitems(userId); + } + + public int insertBeach(List list){ + return this.iUserLabelDao.insertForeach(list); + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserPlanService.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserPlanService.java" new file mode 100644 index 00000000..80a28877 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/service/UserPlanService.java" @@ -0,0 +1,56 @@ +package com.aihome.aihomesys.service; + +import com.aihome.aihomesys.dao.IUserInfoDao; +import com.aihome.aihomesys.dao.IUserPlanDao; +import com.aihome.aihomesys.vo.UserInfo; +import com.aihome.aihomesys.vo.UserPlan; +import com.fasterxml.jackson.databind.util.ObjectBuffer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class UserPlanService { + @Autowired + IUserPlanDao iUserPlanDao; + + public void infoinsert(Map map){ + this.iUserPlanDao.infoinsert(map); + } + + public int countById(Map map){ + return this.iUserPlanDao.countById(map); + } + + public int countMyClassNum(String userId){ + return this.iUserPlanDao.countMyClassNum(userId); + } + + public List selectTodayTask(Map map){ + return this.iUserPlanDao.selectTodayTask(map); + } + + public List selectMyTask(Map map){ + return this.iUserPlanDao.selectMyTask(map); + } + + public int countTodayIsCom(Map map){ + return this.iUserPlanDao.countTodayIsCom(map); + }; + public void updateOneClass(Map map){ + this.iUserPlanDao.updateOneClass(map); + }; + public void updateIsCom(Map map){ + this.iUserPlanDao.updateIsCom(map); + }; + + public UserPlan selectByClassIdAndUserId(Mapmap){ + return this.iUserPlanDao.selectByClassIdAndUserId(map); + }; + + public void updateFatB(Mapmap){ + this.iUserPlanDao.updateFatB(map); + }; +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/ActionInfo.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/ActionInfo.java" new file mode 100644 index 00000000..687105e6 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/ActionInfo.java" @@ -0,0 +1,120 @@ +package com.aihome.aihomesys.vo; + +public class ActionInfo { + private int actionId; + private int classId; + private String actionName; + private String actionImg; + private String actionUrl; + private String actionTime; + private String actionPoints; + private String actionSteps; + private String actionBreak; + private String actionFeel; + private String actionError; + + public int getActionId() { + return actionId; + } + + public void setActionId(int actionId) { + this.actionId = actionId; + } + + public int getClassId() { + return classId; + } + + public void setClassId(int classId) { + this.classId = classId; + } + + public String getActionName() { + return actionName; + } + + public void setActionName(String actionName) { + this.actionName = actionName; + } + + public String getActionImg() { + return actionImg; + } + + public void setActionImg(String actionImg) { + this.actionImg = actionImg; + } + + public String getActionUrl() { + return actionUrl; + } + + public void setActionUrl(String actionUrl) { + this.actionUrl = actionUrl; + } + + public String getActionTime() { + return actionTime; + } + + public void setActionTime(String actionTime) { + this.actionTime = actionTime; + } + + public String getActionPoints() { + return actionPoints; + } + + public void setActionPoints(String actionPoints) { + this.actionPoints = actionPoints; + } + + public String getActionSteps() { + return actionSteps; + } + + public void setActionSteps(String actionSteps) { + this.actionSteps = actionSteps; + } + + public String getActionBreak() { + return actionBreak; + } + + public void setActionBreak(String actionBreak) { + this.actionBreak = actionBreak; + } + + public String getActionFeel() { + return actionFeel; + } + + public void setActionFeel(String actionFeel) { + this.actionFeel = actionFeel; + } + + public String getActionError() { + return actionError; + } + + public void setActionError(String actionError) { + this.actionError = actionError; + } + + @Override + public String toString() { + return "ActionInfo{" + + "actionId=" + actionId + + ", classId=" + classId + + ", actionName='" + actionName + '\'' + + ", actionImg='" + actionImg + '\'' + + ", actionUrl='" + actionUrl + '\'' + + ", actionTime='" + actionTime + '\'' + + ", actionPoints='" + actionPoints + '\'' + + ", actionSteps='" + actionSteps + '\'' + + ", actionBreak='" + actionBreak + '\'' + + ", actionFeel='" + actionFeel + '\'' + + ", actionError='" + actionError + '\'' + + '}'; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/CircleContent.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/CircleContent.java" new file mode 100644 index 00000000..4f8a1d89 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/CircleContent.java" @@ -0,0 +1,152 @@ +package com.aihome.aihomesys.vo; + +import java.util.Arrays; + +public class CircleContent { + private int conId; + private String userId; + private int fkId; + private int fkType; + private String userName; + private String userImg; + private String conTime; + private String conImg; + private String conCont; + private int conGood; + private int conValid; + private int conContNum; + private int isGood; + private String[] imglist; + + @Override + public String toString() { + return "CircleContent{" + + "conId=" + conId + + ", userId='" + userId + '\'' + + ", fkId=" + fkId + + ", fkType=" + fkType + + ", userName='" + userName + '\'' + + ", userImg='" + userImg + '\'' + + ", conTime='" + conTime + '\'' + + ", conImg='" + conImg + '\'' + + ", conCont='" + conCont + '\'' + + ", conGood=" + conGood + + ", conValid=" + conValid + + ", conContNum=" + conContNum + + ", isGood=" + isGood + + ", imglist=" + Arrays.toString(imglist) + + '}'; + } + + public int getIsGood() { + return isGood; + } + + public void setIsGood(int isGood) { + this.isGood = isGood; + } + + public int getConContNum() { + return conContNum; + } + + public void setConContNum(int conContNum) { + this.conContNum = conContNum; + } + + public int getConId() { + return conId; + } + + public void setConId(int conId) { + this.conId = conId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public int getFkId() { + return fkId; + } + + public void setFkId(int fkId) { + this.fkId = fkId; + } + + public int getFkType() { + return fkType; + } + + public void setFkType(int fkType) { + this.fkType = fkType; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getUserImg() { + return userImg; + } + + public void setUserImg(String userImg) { + this.userImg = userImg; + } + + public String getConTime() { + return conTime; + } + + public void setConTime(String conTime) { + this.conTime = conTime; + } + + public String getConImg() { + return conImg; + } + + public void setConImg(String conImg) { + this.conImg = conImg; + } + + public String getConCont() { + return conCont; + } + + public void setConCont(String conCont) { + this.conCont = conCont; + } + + public int getConGood() { + return conGood; + } + + public void setConGood(int conGood) { + this.conGood = conGood; + } + + public int getConValid() { + return conValid; + } + + public void setConValid(int conValid) { + this.conValid = conValid; + } + + public String[] getImglist() { + return imglist; + } + + public void setImglist(String[] imglist) { + this.imglist = imglist; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/ClassInfo.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/ClassInfo.java" new file mode 100644 index 00000000..75014c01 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/ClassInfo.java" @@ -0,0 +1,210 @@ +package com.aihome.aihomesys.vo; + +public class ClassInfo { + private int classId; + private String className; + private String classImg; + private String classUrl; + private String classFatB; + private String classTime; + private String classLevel; + private String createTime; + private String classPeriod; + private int classValid; + private String classTitle; + private String classLabel; + private String classIntro; + private String classType; + private String classIntended; + private String classTaboo; + private String classReady; + private String classBodyreac; + private String classSug; + private int classTrainnumber; + + public int getClassId() { + return classId; + } + + public void setClassId(int classId) { + this.classId = classId; + } + + public String getClassName() { + return className; + } + + public void setClassName(String className) { + this.className = className; + } + + public String getClassImg() { + return classImg; + } + + public void setClassImg(String classImg) { + this.classImg = classImg; + } + + public String getClassUrl() { + return classUrl; + } + + public void setClassUrl(String classUrl) { + this.classUrl = classUrl; + } + + public String getClassFatB() { + return classFatB; + } + + public void setClassFatB(String classFatB) { + this.classFatB = classFatB; + } + + public String getClassTime() { + return classTime; + } + + public void setClassTime(String classTime) { + this.classTime = classTime; + } + + public String getClassLevel() { + return classLevel; + } + + public void setClassLevel(String classLevel) { + this.classLevel = classLevel; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getClassPeriod() { + return classPeriod; + } + + public void setClassPeriod(String classPeriod) { + this.classPeriod = classPeriod; + } + + public int getClassValid() { + return classValid; + } + + public void setClassValid(int classValid) { + this.classValid = classValid; + } + + public String getClassTitle() { + return classTitle; + } + + public void setClassTitle(String classTitle) { + this.classTitle = classTitle; + } + + public String getClassLabel() { + return classLabel; + } + + public void setClassLabel(String classLabel) { + this.classLabel = classLabel; + } + + public String getClassIntro() { + return classIntro; + } + + public void setClassIntro(String classIntro) { + this.classIntro = classIntro; + } + + public String getClassType() { + return classType; + } + + public void setClassType(String classType) { + this.classType = classType; + } + + public String getClassIntended() { + return classIntended; + } + + public void setClassIntended(String classIntended) { + this.classIntended = classIntended; + } + + public String getClassTaboo() { + return classTaboo; + } + + public void setClassTaboo(String classTaboo) { + this.classTaboo = classTaboo; + } + + public String getClassReady() { + return classReady; + } + + public void setClassReady(String classReady) { + this.classReady = classReady; + } + + public String getClassBodyreac() { + return classBodyreac; + } + + public void setClassBodyreac(String classBodyreac) { + this.classBodyreac = classBodyreac; + } + + public String getClassSug() { + return classSug; + } + + public void setClassSug(String classSug) { + this.classSug = classSug; + } + + public int getClassTrainnumber() { + return classTrainnumber; + } + + public void setClassTrainnumber(int classTrainnumber) { + this.classTrainnumber = classTrainnumber; + } + + @Override + public String toString() { + return "ClassInfo{" + + "classId=" + classId + + ", className='" + className + '\'' + + ", classImg='" + classImg + '\'' + + ", classUrl='" + classUrl + '\'' + + ", classFatB='" + classFatB + '\'' + + ", classTime='" + classTime + '\'' + + ", classLevel='" + classLevel + '\'' + + ", createTime='" + createTime + '\'' + + ", classPeriod='" + classPeriod + '\'' + + ", classValid=" + classValid + + ", classTitle='" + classTitle + '\'' + + ", classLabel='" + classLabel + '\'' + + ", classIntro='" + classIntro + '\'' + + ", classType='" + classType + '\'' + + ", classIntended='" + classIntended + '\'' + + ", classTaboo='" + classTaboo + '\'' + + ", classReady='" + classReady + '\'' + + ", classBodyreac='" + classBodyreac + '\'' + + ", classSug='" + classSug + '\'' + + ", classTrainnumber=" + classTrainnumber + + '}'; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/FitnessRecord.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/FitnessRecord.java" new file mode 100644 index 00000000..03e9ddc5 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/FitnessRecord.java" @@ -0,0 +1,90 @@ +package com.aihome.aihomesys.vo; + +public class FitnessRecord { + private int frId; + private String userId; + private String recordTime; + private int fitnessTime; + private int cumFatB; + private int fkId; + private int fkType; + private double score; + + @Override + public String toString() { + return "FitnessRecord{" + + "frId=" + frId + + ", userId='" + userId + '\'' + + ", recordTime='" + recordTime + '\'' + + ", fitnessTime=" + fitnessTime + + ", cumFatB=" + cumFatB + + ", fkId=" + fkId + + ", fkType=" + fkType + + ", score=" + score + + '}'; + } + + public int getFrId() { + return frId; + } + + public void setFrId(int frId) { + this.frId = frId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getRecordTime() { + return recordTime; + } + + public void setRecordTime(String recordTime) { + this.recordTime = recordTime; + } + + public int getFitnessTime() { + return fitnessTime; + } + + public void setFitnessTime(int fitnessTime) { + this.fitnessTime = fitnessTime; + } + + public int getCumFatB() { + return cumFatB; + } + + public void setCumFatB(int cumFatB) { + this.cumFatB = cumFatB; + } + + public int getFkId() { + return fkId; + } + + public void setFkId(int fkId) { + this.fkId = fkId; + } + + public int getFkType() { + return fkType; + } + + public void setFkType(int fkType) { + this.fkType = fkType; + } + + public double getScore() { + return score; + } + + public void setScore(double score) { + this.score = score; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/FoodKu.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/FoodKu.java" new file mode 100644 index 00000000..13c52d26 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/FoodKu.java" @@ -0,0 +1,80 @@ +package com.aihome.aihomesys.vo; + +public class FoodKu { + private int foodId; + private int hotelId; + private String foodName; + private String foodType; + private String foodCacul; + private String foodContent; + private int foodFatB; + + @Override + public String toString() { + return "FoodKu{" + + "foodId=" + foodId + + ", hotelId=" + hotelId + + ", foodName='" + foodName + '\'' + + ", foodType='" + foodType + '\'' + + ", foodCacul='" + foodCacul + '\'' + + ", foodContent='" + foodContent + '\'' + + ", foodFatB=" + foodFatB + + '}'; + } + + public int getFoodId() { + return foodId; + } + + public void setFoodId(int foodId) { + this.foodId = foodId; + } + + public int getHotelId() { + return hotelId; + } + + public void setHotelId(int hotelId) { + this.hotelId = hotelId; + } + + public String getFoodType() { + return foodType; + } + + public void setFoodType(String foodType) { + this.foodType = foodType; + } + + public String getFoodCacul() { + return foodCacul; + } + + public void setFoodCacul(String foodCacul) { + this.foodCacul = foodCacul; + } + + public String getFoodContent() { + return foodContent; + } + + public void setFoodContent(String foodContent) { + this.foodContent = foodContent; + } + + public int getFoodFatB() { + return foodFatB; + } + + public void setFoodFatB(int foodFatB) { + this.foodFatB = foodFatB; + } + + public String getFoodName() { + return foodName; + } + + public void setFoodName(String foodName) { + this.foodName = foodName; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/HotelInfo.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/HotelInfo.java" new file mode 100644 index 00000000..18bc175a --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/HotelInfo.java" @@ -0,0 +1,50 @@ +package com.aihome.aihomesys.vo; + +public class HotelInfo { + private int hotelId; + private String hotelName; + private String hotelNotice; + private String hotelLocation; + + @Override + public String toString() { + return "HotelInfo{" + + "hotelId=" + hotelId + + ", hotelName='" + hotelName + '\'' + + ", hotelNotice='" + hotelNotice + '\'' + + ", hotelLocation='" + hotelLocation + '\'' + + '}'; + } + + public int getHotelId() { + return hotelId; + } + + public void setHotelId(int hotelId) { + this.hotelId = hotelId; + } + + public String getHotelName() { + return hotelName; + } + + public void setHotelName(String hotelName) { + this.hotelName = hotelName; + } + + public String getHotelNotice() { + return hotelNotice; + } + + public void setHotelNotice(String hotelNotice) { + this.hotelNotice = hotelNotice; + } + + public String getHotelLocation() { + return hotelLocation; + } + + public void setHotelLocation(String hotelLocation) { + this.hotelLocation = hotelLocation; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/LabelType.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/LabelType.java" new file mode 100644 index 00000000..794f171f --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/LabelType.java" @@ -0,0 +1,50 @@ +package com.aihome.aihomesys.vo; + +public class LabelType { + private int typeId; + private String typeName; + private int typeCount; + private int isValid; + + public int getTypeId() { + return typeId; + } + + public void setTypeId(int typeId) { + this.typeId = typeId; + } + + public String getTypeName() { + return typeName; + } + + public void setTypeName(String typeName) { + this.typeName = typeName; + } + + public int getTypeCount() { + return typeCount; + } + + public void setTypeCount(int typeCount) { + this.typeCount = typeCount; + } + + public int getIsValid() { + return isValid; + } + + public void setIsValid(int isValid) { + this.isValid = isValid; + } + + @Override + public String toString() { + return "LabelType{" + + "typeId=" + typeId + + ", typeName=" + typeName + + ", typeCount=" + typeCount + + ", isValid=" + isValid + + '}'; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/MealInfo.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/MealInfo.java" new file mode 100644 index 00000000..737d252c --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/MealInfo.java" @@ -0,0 +1,200 @@ +package com.aihome.aihomesys.vo; + +public class MealInfo { + private int mealId; + private int stapleId; + private String stapleName; + private String stapleCacul; + private int MEMId; + private String MEMName; + private String MEMCacul; + private int VFId; + private String VFName; + private String VFCacul; + private int GreaseId; + private String GreaseName; + private String GreaseCacul; + private int OtherId; + private String OtherName; + private String OtherCacul; + private int totalFatB; + private int hotelId; + private int mealType; + + @Override + public String toString() { + return "MealInfo{" + + "mealId=" + mealId + + ", stapleId=" + stapleId + + ", stapleName='" + stapleName + '\'' + + ", stapleCacul='" + stapleCacul + '\'' + + ", MEMId=" + MEMId + + ", MEMName='" + MEMName + '\'' + + ", MEMCacul='" + MEMCacul + '\'' + + ", VFId=" + VFId + + ", VFName='" + VFName + '\'' + + ", VFCacul='" + VFCacul + '\'' + + ", GreaseId=" + GreaseId + + ", GreaseName='" + GreaseName + '\'' + + ", GreaseCacul='" + GreaseCacul + '\'' + + ", OtherId=" + OtherId + + ", OtherName='" + OtherName + '\'' + + ", OtherCacul='" + OtherCacul + '\'' + + ", totalFatB=" + totalFatB + + ", hotelId=" + hotelId + + ", mealType=" + mealType + + '}'; + } + + public int getMealId() { + return mealId; + } + + public void setMealId(int mealId) { + this.mealId = mealId; + } + + public int getStapleId() { + return stapleId; + } + + public void setStapleId(int stapleId) { + this.stapleId = stapleId; + } + + public String getStapleName() { + return stapleName; + } + + public void setStapleName(String stapleName) { + this.stapleName = stapleName; + } + + public String getStapleCacul() { + return stapleCacul; + } + + public void setStapleCacul(String stapleCacul) { + this.stapleCacul = stapleCacul; + } + + public int getMEMId() { + return MEMId; + } + + public void setMEMId(int MEMId) { + this.MEMId = MEMId; + } + + public String getMEMName() { + return MEMName; + } + + public void setMEMName(String MEMName) { + this.MEMName = MEMName; + } + + public String getMEMCacul() { + return MEMCacul; + } + + public void setMEMCacul(String MEMCacul) { + this.MEMCacul = MEMCacul; + } + + public int getVFId() { + return VFId; + } + + public void setVFId(int VFId) { + this.VFId = VFId; + } + + public String getVFName() { + return VFName; + } + + public void setVFName(String VFName) { + this.VFName = VFName; + } + + public String getVFCacul() { + return VFCacul; + } + + public void setVFCacul(String VFCacul) { + this.VFCacul = VFCacul; + } + + public int getGreaseId() { + return GreaseId; + } + + public void setGreaseId(int greaseId) { + GreaseId = greaseId; + } + + public String getGreaseName() { + return GreaseName; + } + + public void setGreaseName(String greaseName) { + GreaseName = greaseName; + } + + public String getGreaseCacul() { + return GreaseCacul; + } + + public void setGreaseCacul(String greaseCacul) { + GreaseCacul = greaseCacul; + } + + public int getOtherId() { + return OtherId; + } + + public void setOtherId(int otherId) { + OtherId = otherId; + } + + public String getOtherName() { + return OtherName; + } + + public void setOtherName(String otherName) { + OtherName = otherName; + } + + public String getOtherCacul() { + return OtherCacul; + } + + public void setOtherCacul(String otherCacul) { + OtherCacul = otherCacul; + } + + public int getHotelId() { + return hotelId; + } + + public void setHotelId(int hotelId) { + this.hotelId = hotelId; + } + + public int getMealType() { + return mealType; + } + + public void setMealType(int mealType) { + this.mealType = mealType; + } + + public int getTotalFatB() { + return totalFatB; + } + + public void setTotalFatB(int totalFatB) { + this.totalFatB = totalFatB; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserEnroll.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserEnroll.java" new file mode 100644 index 00000000..90fec361 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserEnroll.java" @@ -0,0 +1,106 @@ +package com.aihome.aihomesys.vo; + +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +public class UserEnroll { + private String userId; + private String userAva; + private String userName; + private String password; + private long hotelId; + private long userType; + private String loginTime; + private String enrollTime; + private int enableInfoco; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserAva() { + return userAva; + } + + public void setUserAva(String userAva) { + this.userAva = userAva; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public long getHotelId() { + return hotelId; + } + + public void setHotelId(long hotelId) { + this.hotelId = hotelId; + } + + public long getUserType() { + return userType; + } + + public void setUserType(long userType) { + this.userType = userType; + } + + public String getLoginTime() { + return loginTime; + } + + public void setLoginTime(String loginTime) { + this.loginTime = loginTime; + } + + public String getEnrollTime() { + return enrollTime; + } + + public void setEnrollTime(String enrollTime) { + this.enrollTime = enrollTime; + } + + public int getEnableInfoco() { + return enableInfoco; + } + + public void setEnableInfoco(int enableInfoco) { + this.enableInfoco = enableInfoco; + } + + @Override + public String toString() { + return "UserEnroll{" + + "userId='" + userId + '\'' + + ", userAva='" + userAva + '\'' + + ", userName='" + userName + '\'' + + ", password='" + password + '\'' + + ", hotelId=" + hotelId + + ", userType=" + userType + + ", loginTime='" + loginTime + '\'' + + ", enrollTime='" + enrollTime + '\'' + + ", enableInfoco='" + enableInfoco + '\'' + + '}'; + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserFollow.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserFollow.java" new file mode 100644 index 00000000..81401271 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserFollow.java" @@ -0,0 +1,110 @@ +package com.aihome.aihomesys.vo; + +public class UserFollow { + private int followId; + private String fuserId; + private String fuserName; + private String fuserImg; + private String fuseredId; + private String fuseredName; + private String fuseredImg; + private String followTime; + private int followValid; + private int isFollowed; + + @Override + public String toString() { + return "UserFollow{" + + "followId=" + followId + + ", fuserId='" + fuserId + '\'' + + ", fuserName='" + fuserName + '\'' + + ", fuserImg='" + fuserImg + '\'' + + ", fuseredId='" + fuseredId + '\'' + + ", fuseredName='" + fuseredName + '\'' + + ", fuseredImg='" + fuseredImg + '\'' + + ", followTime='" + followTime + '\'' + + ", followValid=" + followValid + + ", isFollowed=" + isFollowed + + '}'; + } + + public int getFollowId() { + return followId; + } + + public void setFollowId(int followId) { + this.followId = followId; + } + + public String getFuserId() { + return fuserId; + } + + public void setFuserId(String fuserId) { + this.fuserId = fuserId; + } + + public String getFuserName() { + return fuserName; + } + + public void setFuserName(String fuserName) { + this.fuserName = fuserName; + } + + public String getFuserImg() { + return fuserImg; + } + + public void setFuserImg(String fuserImg) { + this.fuserImg = fuserImg; + } + + public String getFuseredId() { + return fuseredId; + } + + public void setFuseredId(String fuseredId) { + this.fuseredId = fuseredId; + } + + public String getFuseredName() { + return fuseredName; + } + + public void setFuseredName(String fuseredName) { + this.fuseredName = fuseredName; + } + + public String getFuseredImg() { + return fuseredImg; + } + + public void setFuseredImg(String fuseredImg) { + this.fuseredImg = fuseredImg; + } + + public String getFollowTime() { + return followTime; + } + + public void setFollowTime(String followTime) { + this.followTime = followTime; + } + + public int getFollowValid() { + return followValid; + } + + public void setFollowValid(int followValid) { + this.followValid = followValid; + } + + public int getIsFollowed() { + return isFollowed; + } + + public void setIsFollowed(int isFollowed) { + this.isFollowed = isFollowed; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserGood.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserGood.java" new file mode 100644 index 00000000..2c2560d9 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserGood.java" @@ -0,0 +1,90 @@ +package com.aihome.aihomesys.vo; + +public class UserGood { + private int goodId; + private String userId; + private String userName; + private String userImg; + private int conId; + private String conCont; + private String goodTime; + private int goodValid; + + @Override + public String toString() { + return "UserGood{" + + "goodId=" + goodId + + ", userId='" + userId + '\'' + + ", userName='" + userName + '\'' + + ", userImg='" + userImg + '\'' + + ", conId=" + conId + + ", conCont='" + conCont + '\'' + + ", goodTime='" + goodTime + '\'' + + ", goodValid=" + goodValid + + '}'; + } + + public int getGoodId() { + return goodId; + } + + public void setGoodId(int goodId) { + this.goodId = goodId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getUserImg() { + return userImg; + } + + public void setUserImg(String userImg) { + this.userImg = userImg; + } + + public int getConId() { + return conId; + } + + public void setConId(int conId) { + this.conId = conId; + } + + public String getConCont() { + return conCont; + } + + public void setConCont(String conCont) { + this.conCont = conCont; + } + + public String getGoodTime() { + return goodTime; + } + + public void setGoodTime(String goodTime) { + this.goodTime = goodTime; + } + + public int getGoodValid() { + return goodValid; + } + + public void setGoodValid(int goodValid) { + this.goodValid = goodValid; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserInfo.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserInfo.java" new file mode 100644 index 00000000..dd8614b8 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserInfo.java" @@ -0,0 +1,160 @@ +package com.aihome.aihomesys.vo; + +public class UserInfo { + private int infoId; + private String userId; + private String sex; + private String age; + private double height; + private double weight; + private double bust; + private double waist; + private double hipline; + private double BMI; + private int RHR; + private int MHR; + private String modifyTime; + private int trainDay; + private int todayIsTrain; + + public int getTrainDay() { + return trainDay; + } + + public void setTrainDay(int trainDay) { + this.trainDay = trainDay; + } + + public int getTodayIsTrain() { + return todayIsTrain; + } + + public void setTodayIsTrain(int todayIsTrain) { + this.todayIsTrain = todayIsTrain; + } + + public int getInfoId() { + return infoId; + } + + public void setInfoId(int infoId) { + this.infoId = infoId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getSex() { + return sex; + } + + public void setSex(String sex) { + this.sex = sex; + } + + public String getAge() { + return age; + } + + public void setAge(String age) { + this.age = age; + } + + public double getHeight() { + return height; + } + + public void setHeight(double height) { + this.height = height; + } + + public double getWeight() { + return weight; + } + + public void setWeight(double weight) { + this.weight = weight; + } + + public double getBust() { + return bust; + } + + public void setBust(double bust) { + this.bust = bust; + } + + public double getWaist() { + return waist; + } + + public void setWaist(double waist) { + this.waist = waist; + } + + public double getHipline() { + return hipline; + } + + public void setHipline(double hipline) { + this.hipline = hipline; + } + + public double getBMI() { + return BMI; + } + + public void setBMI(double BMI) { + this.BMI = BMI; + } + + public int getRHR() { + return RHR; + } + + public void setRHR(int RHR) { + this.RHR = RHR; + } + + public int getMHR() { + return MHR; + } + + public void setMHR(int MHR) { + this.MHR = MHR; + } + + public String getModifyTime() { + return modifyTime; + } + + public void setModifyTime(String modifyTime) { + this.modifyTime = modifyTime; + } + + @Override + public String toString() { + return "UserInfo{" + + "infoId=" + infoId + + ", userId='" + userId + '\'' + + ", sex='" + sex + '\'' + + ", age='" + age + '\'' + + ", height=" + height + + ", weight=" + weight + + ", bust=" + bust + + ", waist=" + waist + + ", hipline=" + hipline + + ", BMI=" + BMI + + ", RHR=" + RHR + + ", MHR=" + MHR + + ", modifyTime='" + modifyTime + '\'' + + ", trainDay=" + trainDay + + ", todayIsTrain=" + todayIsTrain + + '}'; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserLabel.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserLabel.java" new file mode 100644 index 00000000..16375d68 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserLabel.java" @@ -0,0 +1,50 @@ +package com.aihome.aihomesys.vo; + +public class UserLabel { + private int ulId; + private String userId; + private int typeId; + private String typeName; + + public int getUlId() { + return ulId; + } + + public void setUlId(int ulId) { + this.ulId = ulId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public int getTypeId() { + return typeId; + } + + public void setTypeId(int typeId) { + this.typeId = typeId; + } + + public String getTypeName() { + return typeName; + } + + public void setTypeName(String typeName) { + this.typeName = typeName; + } + + @Override + public String toString() { + return "UserLabel{" + + "ulId=" + ulId + + ", userId='" + userId + '\'' + + ", typeId=" + typeId + + ", typeName='" + typeName + '\'' + + '}'; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserPlan.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserPlan.java" new file mode 100644 index 00000000..a5728a9e --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/aihomesys/vo/UserPlan.java" @@ -0,0 +1,130 @@ +package com.aihome.aihomesys.vo; + +public class UserPlan { + private int planId; + private String userId; + private int classId; + private String className; + private String classImg; + private String comTime; + private String classTime; + private int isComplete; + private String subTime; + private String todayTime; + private int totalFatB; + private int todayComplete; + + @Override + public String toString() { + return "UserPlan{" + + "planId=" + planId + + ", userId='" + userId + '\'' + + ", classId=" + classId + + ", className='" + className + '\'' + + ", classImg='" + classImg + '\'' + + ", comTime='" + comTime + '\'' + + ", classTime='" + classTime + '\'' + + ", isComplete=" + isComplete + + ", subTime='" + subTime + '\'' + + ", todayTime='" + todayTime + '\'' + + ", totalFatB='" + totalFatB + '\'' + + ", todayComplete=" + todayComplete + + '}'; + } + + public int getPlanId() { + return planId; + } + + public void setPlanId(int planId) { + this.planId = planId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public int getClassId() { + return classId; + } + + public void setClassId(int classId) { + this.classId = classId; + } + + public String getClassName() { + return className; + } + + public void setClassName(String className) { + this.className = className; + } + + public String getClassImg() { + return classImg; + } + + public void setClassImg(String classImg) { + this.classImg = classImg; + } + + public String getComTime() { + return comTime; + } + + public void setComTime(String comTime) { + this.comTime = comTime; + } + + public String getClassTime() { + return classTime; + } + + public void setClassTime(String classTime) { + this.classTime = classTime; + } + + public int getIsComplete() { + return isComplete; + } + + public void setIsComplete(int isComplete) { + this.isComplete = isComplete; + } + + public String getSubTime() { + return subTime; + } + + public void setSubTime(String subTime) { + this.subTime = subTime; + } + + public String getTodayTime() { + return todayTime; + } + + public void setTodayTime(String todayTime) { + this.todayTime = todayTime; + } + + public int getTotalFatB() { + return totalFatB; + } + + public void setTotalFatB(int totalFatB) { + this.totalFatB = totalFatB; + } + + public int getTodayComplete() { + return todayComplete; + } + + public void setTodayComplete(int todayComplete) { + this.todayComplete = todayComplete; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/component/ComputingUnit.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/component/ComputingUnit.java" new file mode 100644 index 00000000..fbaf7ed7 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/component/ComputingUnit.java" @@ -0,0 +1,26 @@ +package com.aihome.component; + +import com.aihome.utils.DoubleUtils; + +public class ComputingUnit { + + public double BMICom(Object height,Object weight){ + Double hh = Double.parseDouble(height.toString()); + double h = (hh==null?0:hh); + Double ww = Double.parseDouble(weight.toString()); + double w = (ww==null?0:ww); + if(h==0){ + return 0; + }else { + double hw = h/100; + double BMI = w/(hw*hw); + return Double.parseDouble(String.format("%.1f",BMI)); + } + } + + public static void main(String[] args) { + ComputingUnit computingUnit = new ComputingUnit(); + System.out.println(computingUnit.BMICom(177,74)); + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/component/ZhenziyunService.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/component/ZhenziyunService.java" new file mode 100644 index 00000000..7a4abc2f --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/component/ZhenziyunService.java" @@ -0,0 +1,35 @@ +package com.aihome.component; + +import com.zhenzi.sms.ZhenziSmsClient;; +import java.util.Map; +import java.util.HashMap; + +public class ZhenziyunService { + // 位数,默认是6位 + private final static long w = 1000000; + + private String apiUrl = "https://sms_developer.zhenzikj.com"; + private String appId = "104984"; + private String appSecret = "5829d771-6ca4-4f8e-bb8e-73f451b72a0d"; + + public String sendMesg(String phone,String code) throws Exception{ + ZhenziSmsClient client = new ZhenziSmsClient(apiUrl, appId, appSecret); + Map params = new HashMap(); + params.put("message", "欢迎您注册Ai佳智能健身系统,本次注册验证码为: "+code+",请在1分钟内完成注册。"); + params.put("number", phone); + return client.send(params); + } + + public String randomCode() { + long r = 0; + r = (long) ((Math.random() + 1) * w); + return String.valueOf(r).substring(1); + } + +// public static void main(String[] args) throws Exception{ +// ZhenziyunService zhenziyunService = new ZhenziyunService(); +// String code = zhenziyunService.randomCode(); +// System.out.println(zhenziyunService.sendMesg("15893939016",code)); +// } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/jythonplug/pythonRunTest.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/jythonplug/pythonRunTest.java" new file mode 100644 index 00000000..858e37d3 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/jythonplug/pythonRunTest.java" @@ -0,0 +1,11 @@ +package com.aihome.jythonplug; + +import org.python.util.PythonInterpreter; + +public class pythonRunTest { + public static void main(String[] args) { + PythonInterpreter pi = new PythonInterpreter(); + pi.exec("a='test'"); + pi.exec("print(a)"); + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/ConstantUtils.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/ConstantUtils.java" new file mode 100644 index 00000000..00663b0b --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/ConstantUtils.java" @@ -0,0 +1,5 @@ +package com.aihome.utils; + +public class ConstantUtils { + public final static String USER_SESSION_KEY = "null"; +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/DateUtils.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/DateUtils.java" new file mode 100644 index 00000000..112094b9 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/DateUtils.java" @@ -0,0 +1,391 @@ +package com.aihome.utils; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +public class DateUtils { + +private DateUtils(){} + + public static final String DATE_FROMAT = "yyyy-MM-dd"; + + public static final String DATE_FROMAT_CN = "yyyy-MM-dd HH:mm:ss"; + + public static final String DATE_NUMBER_CN = "yyyyMMddHHmmss"; + + public static final String DATE_FROMAT_EN = "dd/MM/yyyy HH:mm:ss"; + + public static final String DATE_FROMAT_CHINA = "yyyy年MM月dd日HH:mm"; + /** + * 获得格式化对象 + * @param pattern + * @return + */ + public static DateFormat getDateFormat(String pattern) { + return new SimpleDateFormat(pattern); + } + + /** + * 获得当前时间 + * + * @return + */ + public static String getCurDateTime(String fromatStr) { + DateFormat df = new SimpleDateFormat(fromatStr); + return df.format(new Date().getTime()); + } + + /** + * 时间加减 + * + * @param amount + * @return + */ + public static Date dateSub(int amount) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(new Date()); + calendar.add(Calendar.DATE, amount); + return calendar.getTime(); + } + + // 按格式取系统日期 + public static String getDateWithYMD() { + Calendar now = Calendar.getInstance(); + int month = now.get(Calendar.MONTH) + 1; + int day = now.get(Calendar.DAY_OF_MONTH); + int year = now.get(Calendar.YEAR); + String date = year + "-" + month + "-" + day; + return date; + } + + /** + * 获得前天 + * + * @return + */ + public static String getdayBeforeYesterday() { + Date date = new Date();// 取时间 + Calendar calendar = new GregorianCalendar(); + calendar.setTime(date); + calendar.add(Calendar.DATE, -2);// + date = calendar.getTime(); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + String dateString = formatter.format(date); + return dateString; + } + + /** + * 根据输入的日期字符串 和 提前天数 , * 获得 指定日期提前几天的日期对象 * + * + * @param dateString + * 日期对象 ,格式如1-31-1900 * + * @param beforeDays + * 倒推的天数 + * @return 指定日期倒推指定天数后的日期对象 * + * @throws ParseException + */ + public static Date getDate(String dateString, int beforeDays) + throws ParseException { + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date inputDate = dateFormat.parse(dateString); + Calendar cal = Calendar.getInstance(); + cal.setTime(inputDate); + int inputDayOfYear = cal.get(Calendar.DAY_OF_YEAR); + cal.set(Calendar.DAY_OF_YEAR, inputDayOfYear - beforeDays); + return cal.getTime(); + } + + public static Date getDateStr(Date dateString, int beforeDays) + throws ParseException { + Calendar cal = Calendar.getInstance(); + cal.setTime(dateString); + int inputDayOfYear = cal.get(Calendar.DAY_OF_YEAR); + cal.set(Calendar.DAY_OF_YEAR, inputDayOfYear - beforeDays); + return cal.getTime(); + } + + /** + * + * @param dateString + * @return + * @throws ParseException + */ + public static List getLastWeek(String dateString) throws ParseException { + List datelist = new ArrayList<>(); + for(int i=0;i<7;i++){ + Date date = DateUtils.getDate(dateString,i); + datelist.add(DateUtils.date2String(date,DATE_FROMAT_CN)); + } + return datelist; + } + + /** + * 日期转换为字符串 + * + * @param date + * @return + */ + public static String date2String(Date date) { + return date2String(date, "yyyy-MM-dd"); + } + + /** + * 日期转换为字符串 + * + * @param date + * @return + */ + public static String date2String(Date date, String fromatStr) { + DateFormat df = new SimpleDateFormat(fromatStr); + return df.format(date); + } + + /** + * 字符串转为日期 + * + * @param dateStr + * @param fromatStr + * @return + * @throws ParseException + */ + public static Date String2Date(String dateStr, String fromatStr) { + SimpleDateFormat sdf = new SimpleDateFormat(fromatStr); + try { + return sdf.parse(dateStr); + } catch (ParseException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 字符串转为日期 + * + * @param dateStr + * @param + * @return + * @throws ParseException + */ + public static Date String2Date(String dateStr) { + return String2Date(dateStr, "yyyy-MM-dd"); + } + + /** + * 获得当前日期 + * + * @return + */ + public static String getCurDate() { + DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + return df.format(new Date()); + } + + /** + * 获取当前年 + */ + public static String getCurYear(){ + return date2String(new Date(), "yyyy"); + } + + public static int getCurYear(int addYear){ + return Integer.valueOf(getCurYear()) + addYear; + } + + /** + * 获得当前日期 + * + * @return + */ + public static String getCurTime() { + DateFormat df = new SimpleDateFormat(DATE_FROMAT_CN); + return df.format(new Date()); + } + + /** + * 获得当前日期 + * + * @return + */ + public static String getCurTime2Number() { + DateFormat df = new SimpleDateFormat(DATE_NUMBER_CN); + return df.format(new Date()); + } + + /** + * 获得当前日期 + * + * @return + */ + public static String getCurDate(String fromatStr) { + DateFormat df = new SimpleDateFormat(fromatStr); + return df.format(new Date()); + } + + /** + * 格式化时间 + * + * @param dateStr + * @return + */ + public static String formatDate(String dateStr) { + return formatDate(dateStr, DateUtils.DATE_FROMAT_CN); + } + + /** + * 格式化时间 + * + * @param dateStr + * @return + */ + public static String formatDate(String dateStr, String formatStr) { + DateFormat df = new SimpleDateFormat(formatStr); + try { + Date date = df.parse(dateStr); + return date2String(date, formatStr); + } catch (ParseException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 将日期字符串转日期类型 + * + * @param date + * @return + */ + public static Date parseDate(String date,String pattern) { + DateFormat df = new SimpleDateFormat(pattern); + try { + return df.parse(date); + } catch (ParseException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 将日期字符串转日期类型 + * + * @param date + * @return + */ + public static Date parseDate(String date) { + return parseDate(date, DateUtils.DATE_FROMAT); + } + + public static boolean isInDate(Date nowDate, Date startDate, Date endDate){ + if(nowDate != null && startDate != null && endDate != null){ + Calendar date = Calendar.getInstance(); + date.setTime(nowDate); + + Calendar begin = Calendar.getInstance(); + begin.setTime(startDate); + + Calendar end = Calendar.getInstance(); + end.setTime(endDate); + + if ((date.after(begin) || date.equals(begin)) && (date.equals(end) ||date.before(end))) { + return true; + } else { + return false; + } + }else{ + return false; + } + } + + public static boolean isInDate(Date startDate, Date endDate){ + if(startDate != null && endDate != null){ + + Calendar begin = Calendar.getInstance(); + begin.setTime(startDate); + + Calendar end = Calendar.getInstance(); + end.setTime(endDate); + + if (end.after(begin) || end.equals(begin)) { + return true; + } else { + return false; + } + }else{ + return false; + } + } + + public static Long getSecondInDate(Date startDate, Date endDate){ + long second = endDate.getTime() - startDate.getTime(); + return second > 1000 ? second / 1000 : 0; + } + + /** + * @description 两个时间是否在规定的范围内 + * @param date1 + * @param date2 + * @param + * @return + */ + public static boolean IsInDate(Date date1, Date date2, int second){ + long s1 = (date1.getTime() - date2.getTime()) / 1000; + long s2 = (date2.getTime() - date1.getTime()) / 1000; + if(s1 <= 0 && s2 <= second){ + return true; + }else if(s2 <= 0 && s1 <=second){ + return true; + }else{ + return false; + } + } + + public static int getWeek(Date nowDate){ + Calendar c=Calendar.getInstance(); + c.setTime(nowDate); + return c.get(Calendar.DAY_OF_WEEK); + } + + public static boolean isValidDate(String dateStr, String formatStr){ + boolean f = true; + SimpleDateFormat dateFormat = new SimpleDateFormat(formatStr); + try { + dateFormat.setLenient(false); + dateFormat.parse(dateStr); + } catch (ParseException e) { + f = false; + } + return f; + } + + public static String avgDateTime(String time1, String time2, String formatStr) { + if(StringUtils.isNotEmpty(time1) && StringUtils.isNotEmpty(time2)){ + int hh = (Integer.valueOf(time1.substring(0, time1.indexOf(":"))) + Integer.valueOf(time2.substring(0, time2.indexOf(":")))) / 2; + int mm = (Integer.valueOf(time1.substring(time1.indexOf(":")+1)) + Integer.valueOf(time2.substring(time2.indexOf(":")+1))) / 2 ; + return formatDate(hh+":"+mm, formatStr); + }else if(StringUtils.isNotEmpty(time1) && StringUtils.isEmpty(time2)){ + return formatDate(time1, formatStr); + }else if(StringUtils.isEmpty(time1) && StringUtils.isNotEmpty(time2)){ + return formatDate(time2, formatStr); + } + return ""; + } + + public static int getIntervalDays(Date startDate, Date endDate) { + Calendar aCalendar = Calendar.getInstance(); + aCalendar.setTime(startDate); + int day1 = aCalendar.get(Calendar.DAY_OF_YEAR); + aCalendar.setTime(endDate); + int day2 = aCalendar.get(Calendar.DAY_OF_YEAR); + return day2 - day1; + } + +// public static void main(String[] args) { +// System.out.println(DateUtils.getCurTime()); +// try { +// System.out.println(DateUtils.getLastWeek("2020-03-01 22:11:22")); +// } catch (ParseException e) { +// e.printStackTrace(); +// } +// } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/DoubleUtils.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/DoubleUtils.java" new file mode 100644 index 00000000..5eb61228 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/DoubleUtils.java" @@ -0,0 +1,137 @@ +package com.aihome.utils; + +import java.math.BigDecimal; +import java.text.DecimalFormat; + +/** + * Double数据的操作 使用Java,double 进行运算时,经常出现精度丢失的问题,总是在一个正确的结果左右偏0.0000**1。 + * 特别在实际项目中,通过一个公式校验该值是否大于0,如果大于0我们会做一件事情,小于0我们又处理其他事情。 + * 这样的情况通过double计算出来的结果去和0比较大小,尤其是有小数点的时候,经常会因为精度丢失而导致程序处理流程出错。 + */ +public class DoubleUtils { + private static final int DEF_DIV_SCALE = 10; + + public static double scale2(double v) { + BigDecimal bd = new BigDecimal(v); + bd = bd.setScale(2, 4); + return bd.doubleValue(); + } + + public static int getIntNum(Double value) { + DecimalFormat df = new DecimalFormat("#"); + String str = df.format(value).replaceAll("-", ""); + return str.length(); + } + + public static void main(String[] args) { + Double double1 = Double.valueOf(-3.126D); + System.out.println(scale2(double1.doubleValue())); + System.out.println(changeDecimal(double1.doubleValue(), 2)); + System.out.println("0.1*0.1=" + mul(Double.valueOf(0.1D), Double.valueOf(0.1D))); + System.out.println("1.0-0.1=" + sub(Double.valueOf(1.0D), Double.valueOf(0.1D))); + System.out.println("0.1+0.1=" + add(Double.valueOf(0.1D), Double.valueOf(0.1D))); + System.out.println(getIntNum(double1)); + System.out.println(toDecimalString("4444564321.2135", 2)); + } + + public static double changeDecimal(double value, int num) { + BigDecimal b = new BigDecimal(value); + double v = b.setScale(num, 4).doubleValue(); + return v; + } + + public static String toDecimalString(String str, int decimal) { + if (StringUtils.isEmpty(str)) { + return ""; + } + return toDecimalString(Double.valueOf(str.trim()), decimal); + } + + public static String toDecimalString(Double num, int decimal) { + if (num == null) { + return ""; + } + String str = num.toString(); + String formatStr = "#."; + for (int i = 0; i < decimal; ++i) { + formatStr = formatStr + "0"; + } + DecimalFormat df = new DecimalFormat(formatStr); + try { + str = df.format(num); + } catch (Exception localException) { + } + return str; + } + + public static String toSplitDecimalString(Double num, int decimal) { + if (num == null) { + return ""; + } + String str = num.toString(); + String formatStr = "###,###."; + for (int i = 0; i < decimal; ++i) { + formatStr = formatStr + "0"; + } + DecimalFormat df = new DecimalFormat(formatStr); + try { + str = df.format(num); + } catch (Exception localException) { + } + return str; + } + + public static String toSplitDecimalString(String str, int decimal) { + if (StringUtils.isEmpty(str)) { + return ""; + } + return toSplitDecimalString(Double.valueOf(str.trim()), decimal); + } + + public static Double add(Double v1, Double v2) { + BigDecimal b1 = new BigDecimal(v1.toString()); + BigDecimal b2 = new BigDecimal(v2.toString()); + return Double.valueOf(b1.add(b2).doubleValue()); + } + + public static Double add(Double v1, Double v2, int num) { + return Double.valueOf(changeDecimal(add(v1, v2).doubleValue(), num)); + } + + public static Double sub(Double v1, Double v2) { + BigDecimal b1 = new BigDecimal(v1.toString()); + BigDecimal b2 = new BigDecimal(v2.toString()); + return Double.valueOf(b1.subtract(b2).doubleValue()); + } + + public static Double sub(Double v1, Double v2, int num) { + return Double.valueOf(changeDecimal(sub(v1, v2).doubleValue(), num)); + } + + public static Double mul(Double v1, Double v2) { + BigDecimal b1 = new BigDecimal(v1.toString()); + BigDecimal b2 = new BigDecimal(v2.toString()); + return Double.valueOf(b1.multiply(b2).doubleValue()); + } + + public static Double mul(Double v1, Double v2, int num) { + return Double.valueOf(changeDecimal(mul(v1, v2).doubleValue(), num)); + } + + public static Double div(Double v1, Double v2) { + BigDecimal b1 = new BigDecimal(v1.toString()); + BigDecimal b2 = new BigDecimal(v2.toString()); + return Double.valueOf(b1.divide(b2, 10, 4).doubleValue()); + } + + public static Double div(Double v1, Double v2, int scale) { + if (scale < 0) { + throw new IllegalArgumentException("The scale must be a positive integer or zero"); + } + BigDecimal b1 = new BigDecimal(v1.toString()); + BigDecimal b2 = new BigDecimal(v2.toString()); + return Double.valueOf(b1.divide(b2, scale, 4).doubleValue()); + } + +} + diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/GsonHelper.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/GsonHelper.java" new file mode 100644 index 00000000..be5f3cba --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/GsonHelper.java" @@ -0,0 +1,129 @@ +package com.aihome.utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; + +/** + * @title: GsonHelper.java + * @description: TODO + * @author: zhaopf + * @date: 2017年3月21日 上午11:40:29 + * @version v1.0 + */ +public class GsonHelper { + + private static Gson gson = null; + + static { + if (gson == null) { + gson = new Gson(); + } + } + + private GsonHelper() { + } + + /** + * 将object对象转成json字符串 + * + * @param object + * @return + */ + public static String GsonString(Object object) { + if(StringUtils.isEmpty(object.toString())){ + return ""; + } + String gsonString = null; + if (gson != null) { + gsonString = gson.toJson(object); + } + return gsonString; + } + + /** + * 将gsonString转成泛型bean + * + * @param gsonString + * @param cls + * @return + */ + public static T GsonToBean(String gsonString, Class cls) { + T t = null; + if (gson != null) { + t = gson.fromJson(gsonString, cls); + } + return t; + } + + /** + * 转成list 泛型在编译期类型被擦除导致报错 + * + * @param gsonString + * @param cls + * @return + */ + public static List GsonToList(String gsonString, Class cls) { + List list = null; + if (gson != null) { + list = gson.fromJson(gsonString, new TypeToken>() { + }.getType()); + } + return list; + } + + /** + * 转成list 解决泛型问题 + * + * @param json + * @param cls + * @param + * @return + */ + public static List jsonToList(String json, Class cls) { + Gson gson = new Gson(); + List list = new ArrayList(); + JsonArray array = new JsonParser().parse(json).getAsJsonArray(); + for (final JsonElement elem : array) { + list.add(gson.fromJson(elem, cls)); + } + return list; + } + + /** + * 转成list中有map的 + * + * @param gsonString + * @return + */ + public static List> GsonToListMaps(String gsonString) { + List> list = null; + if (gson != null) { + list = gson.fromJson(gsonString, new TypeToken>>() { + }.getType()); + } + return list; + } + + /** + * 转成map的 + * + * @param gsonString + * @return + */ + public static Map GsonToMaps(String gsonString) { + Map map = null; + if (gson != null) { + map = gson.fromJson(gsonString, new TypeToken>() { + }.getType()); + } + return map; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/ShaUtils.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/ShaUtils.java" new file mode 100644 index 00000000..ee18eaf2 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/ShaUtils.java" @@ -0,0 +1,23 @@ +package com.aihome.utils; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class ShaUtils { + public static String getSha1(String input) throws NoSuchAlgorithmException { + MessageDigest mDigest = MessageDigest.getInstance("SHA1"); + byte[] pass = input.getBytes(); + byte[] result = mDigest.digest(pass); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < result.length; i++) { + sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1)); + } + return sb.toString(); + } + + public static void main(String[] args) throws NoSuchAlgorithmException { + String pass = "Scd123"; + System.out.println(getSha1(pass)); + } + +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/StringUtils.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/StringUtils.java" new file mode 100644 index 00000000..a0dfb56a --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/aihome/utils/StringUtils.java" @@ -0,0 +1,206 @@ +package com.aihome.utils; + +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.text.NumberFormat; +import java.util.List; +import java.util.UUID; + +/** + * 字符串工具类 + * @author lijie + * @date 2018年6月21日 + */ +public class StringUtils { + + private static final String hexString = "0123456789ABCDEF"; + + private StringUtils(){} + + + /** + * @description 字符串不为空或空串 + * @param str + * @return + */ + public static boolean isNotEmpty(Object obj) { + return !isEmpty(obj); + } + + /** + * @description 给定字符串是否为空或空串 + * @param str + * @return + */ + public static boolean isEmpty(Object obj) { + return (obj == null || obj.equals("")); + } + + /** + * @description 转字符串 + * @param obj + * @return + */ + public static String objToStr(Object obj){ + if(isEmpty(obj)){ + return ""; + } + return obj.toString(); + } + + /** + * 16进制转换成字符串 + * @param bytes + * @return + * @throws UnsupportedEncodingException + */ + public static String para16ToStr(String bytes) throws UnsupportedEncodingException { + bytes = bytes.replaceAll("%", ""); + ByteArrayOutputStream baos = new ByteArrayOutputStream(bytes.length() / 2); + // 将每2位16进制整数组装成一个字节 + for (int i = 0; i < bytes.length(); i += 2) + baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString + .indexOf(bytes.charAt(i + 1)))); + return new String(baos.toByteArray()); + } + + /** + * 字符串转换成16进制 + * @description + * @param str + * @return + * @throws UnsupportedEncodingException + */ + public static String paraTo16(String str) throws UnsupportedEncodingException { + String hs = ""; + + byte[] byStr = str.getBytes("UTF-8"); + for(int i=0;i 0){ + uuidStr = uuidStr.substring(0, subIndex); + } + return uuidStr; + } + + public static String filterPercent2String(String percent){ + if(isNotEmpty(percent)){ + return percent.replaceAll("%", ""); + } + return "0"; + } + + public static float filterPercent2Number(String percent){ + return Float.valueOf(filterPercent2String(percent)); + } + + public static boolean isNotEmpty(List list){ + if(list != null && list.size() > 0){ + return true; + } + return false; + } + + public static boolean isEmpty(List list){ + return !isNotEmpty(list); + } + + public static NumberFormat getPercentInstance(int newValue){ + //设置百分比格式 + NumberFormat nt = NumberFormat.getPercentInstance(); + //需要保留几位小数点 + nt.setMinimumFractionDigits(newValue); + return nt; + } + + public static Long String2Long(String str){ + if(isNotEmpty(str)){ + try { + return Long.valueOf(str); + } catch (Exception e) { + return null; + } + } + return null; + } + + public static BigDecimal String2BigDecimal(String str) { + if(isNotEmpty(str)){ + try { + return new BigDecimal(str); + } catch (Exception e) { + return null; + } + } + return null; + } + + public static int String2Int(String str, int defaultInt){ + if(isNotEmpty(str)){ + try { + return Integer.valueOf(str); + } catch (Exception e) { + return 0; + } + } + return defaultInt; + } + + public static int String2Int(String str){ + if(isNotEmpty(str)){ + try { + return Integer.valueOf(str); + } catch (Exception e) { + return 0; + } + } + return 0; + } + + public static BigDecimal object2BigDecimal(Object obj) { + if(isNotEmpty(obj)){ + try { + return new BigDecimal(objToStr(obj)); + } catch (Exception e) { + return new BigDecimal("0"); + } + } + return new BigDecimal("0"); + } + + public static BigDecimal filterBigDecimal(BigDecimal bigDecimal) { + if(bigDecimal == null) { + return new BigDecimal("0"); + } + return bigDecimal; + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/config/WebMvcConfig.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/config/WebMvcConfig.java" new file mode 100644 index 00000000..1827db76 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/config/WebMvcConfig.java" @@ -0,0 +1,22 @@ +package com.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/images/**/**").addResourceLocations("file:E:/Program Files/Klivexer/src/main/resources/static/images/"); + } + + @Override + //通过此处加载拦截器 + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new signinHandlerIntercepter()) + .addPathPatterns("/**","/main/login-success") + .excludePathPatterns("/main", "/main/**", "/error/**","/components/**","/classVideo/**","/fonts/**","/images/**","webview/**"); + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/config/WebSecurityConfig.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/config/WebSecurityConfig.java" new file mode 100644 index 00000000..b28ab4cc --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/config/WebSecurityConfig.java" @@ -0,0 +1,14 @@ +package com.config; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { +// @Override +// public void configure(WebSecurity web) { +// web.ignoring().antMatchers("/main"); //无条件允许访问 +// } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/config/signinHandlerIntercepter.java" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/config/signinHandlerIntercepter.java" new file mode 100644 index 00000000..9eacf0bb --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/java/com/config/signinHandlerIntercepter.java" @@ -0,0 +1,22 @@ +package com.config; + +import com.aihome.utils.ConstantUtils; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class signinHandlerIntercepter implements HandlerInterceptor { + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + + Object user = request.getSession().getAttribute(ConstantUtils.USER_SESSION_KEY); + if(user == null){ + request.getRequestDispatcher("/main").forward(request, response); + return false; + } + else { + return true; + } + } +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/application.properties" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/application.properties" new file mode 100644 index 00000000..680c908d --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/application.properties" @@ -0,0 +1,22 @@ +server.port=8088 +server.servlet.context-path=/Klive + +spring.mvc.view.prefix=/WEB-INF/webview/ +spring.mvc.view.suffix=.jsp + +spring.datasource.url=jdbc:mysql://localhost:3306/aihome?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC +spring.datasource.username=root +spring.datasource.password=123456 + +mybatis.mapper-locations: classpath:mybatis/mapper/*.xml +mybatis.type-aliases-package: com.aihome.aihomesys + +#ļ +spring.servlet.multipart.enabled=true +spring.servlet.multipart.max-file-size=100MB +spring.servlet.multipart.max-request-size=100MB +#־ +#logging.level.com.aihome = trace + +#־· +logging.file.path= E:/Program Files/AiHomeLogger \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/ActionInfoDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/ActionInfoDao.xml" new file mode 100644 index 00000000..210843f5 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/ActionInfoDao.xml" @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/CircleContentDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/CircleContentDao.xml" new file mode 100644 index 00000000..7690c82b --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/CircleContentDao.xml" @@ -0,0 +1,80 @@ + + + + + userId,fkId,fkType,conTime,conImg,conCont + + + INSERT INTO CIRCLE_CONTENT() + VALUES(#{userId},#{fkId},#{fkType},#{conTime},#{conImg},#{conCont}) + + + + + + + + + + + + + + + + + + + + + + + update circle_content set + conContNum = conContNum+1 + where conId = #{fkId} + + + + update circle_content set + conGood = conGood+1 + where conId = #{conId} + + + + update circle_content set + conGood = conGood-1 + where conId = #{conId} + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/ClassInfoDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/ClassInfoDao.xml" new file mode 100644 index 00000000..62760ffb --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/ClassInfoDao.xml" @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + update CLASS_INFO set classTrainnumber = classTrainnumber+1 where classId = #{classId} + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/FitnessRecordDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/FitnessRecordDao.xml" new file mode 100644 index 00000000..c65625ce --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/FitnessRecordDao.xml" @@ -0,0 +1,99 @@ + + + + + + INSERT INTO FITNESS_RECORD(userId,recordTime,fitnessTime,cumFatB,fkId,fkType,score) + VALUES(#{userId},#{recordTime},#{fitnessTime},#{cumFatB},#{fkId},#{fkType},#{score}) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/FoodKuDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/FoodKuDao.xml" new file mode 100644 index 00000000..65cfd429 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/FoodKuDao.xml" @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/HotelInfoDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/HotelInfoDao.xml" new file mode 100644 index 00000000..af46aaf3 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/HotelInfoDao.xml" @@ -0,0 +1,19 @@ + + + + + + + + + + update HOTEL_INFO set + hotelNotice = #{hotelNotice} + where hotelId = #{hotelId} + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/LabelTypeDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/LabelTypeDao.xml" new file mode 100644 index 00000000..2dd44225 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/LabelTypeDao.xml" @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/MealInfoDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/MealInfoDao.xml" new file mode 100644 index 00000000..65cde8fc --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/MealInfoDao.xml" @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserEnrollDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserEnrollDao.xml" new file mode 100644 index 00000000..c1c81032 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserEnrollDao.xml" @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + userId,userName,password,userType,loginTime,enrollTime + + + + + INSERT INTO USER_ENROLL(,hotelId) + VALUES(#{userId},#{userName},#{password},#{userType},#{loginTime},#{enrollTime},#{hotelId}) + + + + + + + + + + update USER_ENROLL set loginTime = #{loginTime} where userId = #{userId} + + + + update USER_ENROLL set + userImg = #{userAva} + where userId = #{userId} + + + + update USER_ENROLL set + userName = #{userName} + where userId = #{userId} + + + + update USER_ENROLL set + passWord = #{passWord} + where userId = #{userId} + + + + update USER_ENROLL set + enableInfoco = 1 + where userId = #{userId} + + + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserFollowDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserFollowDao.xml" new file mode 100644 index 00000000..3d078d3a --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserFollowDao.xml" @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + DELETE FROM USER_FOLLOW WHERE fuserId = #{fuserId} AND fuseredId = #{fuseredId}; + + + + INSERT INTO USER_FOLLOW(fuserId,fuseredId,followTime) + VALUES(#{fuserId},#{fuseredId},#{followTime}) + + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserGoodDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserGoodDao.xml" new file mode 100644 index 00000000..2559bbeb --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserGoodDao.xml" @@ -0,0 +1,20 @@ + + + + + userId,conId,goodTime + + + + + INSERT INTO USER_GOOD() + VALUES(#{userId},#{conId},#{goodTime}); + + + + DELETE FROM USER_GOOD WHERE userId = #{userId} AND conId = #{conId}; + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserInfoDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserInfoDao.xml" new file mode 100644 index 00000000..6866d209 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserInfoDao.xml" @@ -0,0 +1,38 @@ + + + + + + INSERT INTO USER_INFO(userID,modifyTime) + VALUES(#{userId},#{modifyTime}) + + + update USER_INFO set modifyTime = #{modifyTime} where userId = #{userId} + + + + INSERT INTO USER_INFO(userId,sex,age,height,weight,bust,waist,hipline,BMI,RHR,MHR,modifyTime) + VALUES(#{userId},#{sex},#{age},#{height},#{weight},#{bust},#{waist},#{hipline},#{BMI},#{RHR},#{MHR},#{modifyTime}) + + + + update USER_INFO set sex=#{sex}, age=#{age},height=#{height},weight=#{weight},bust=#{bust},waist=#{waist},hipline=#{hipline},BMI=#{BMI},RHR=#{RHR},MHR=#{MHR},modifyTime = #{modifyTime} where userId = #{userId} + + + + + + + + + + update USER_INFO set trainDay=trainDay+1,todayIsTrain=1 where userId = #{userId} + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserLabelDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserLabelDao.xml" new file mode 100644 index 00000000..641dc2c8 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserLabelDao.xml" @@ -0,0 +1,19 @@ + + + + + + + + INSERT INTO USER_LABEL + (userId,typeId,typeName) + values + + (#{item.userId}, + #{item.typeId}, + #{item.typeName}) + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserPlanDao.xml" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserPlanDao.xml" new file mode 100644 index 00000000..606c2c8d --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/mybatis/mapper/UserPlanDao.xml" @@ -0,0 +1,46 @@ + + + + + + INSERT INTO USER_PLAN(userId,classId,subTime) + VALUES(#{userId},#{classId},#{subTime}) + + + + + + + + + + update USER_PLAN set comTime = comTime+1,todayComplete=1,todayTime=#{todayTime},totalFatB=totalFatB+#{totalFatB} where classId = #{classId} AND userId = #{userId} + + + + update USER_PLAN set isComplete = 1 where classId = #{classId} AND userId = #{userId} + + + + update USER_PLAN set totalFatB = totalFatB + #{totalFatB},todayTime = #{todayTime} where classId = #{classId} AND userId = #{userId} + + + + + + + + + \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/Sha/js/Sha1.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/Sha/js/Sha1.js" new file mode 100644 index 00000000..3df9e093 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/Sha/js/Sha1.js" @@ -0,0 +1,49 @@ +function encodeUTF8(s) { + var i, r = [], c, x; + for (i = 0; i < s.length; i++) + if ((c = s.charCodeAt(i)) < 0x80) r.push(c); + else if (c < 0x800) r.push(0xC0 + (c >> 6 & 0x1F), 0x80 + (c & 0x3F)); + else { + if ((x = c ^ 0xD800) >> 10 == 0) //对四字节UTF-16转换为Unicode + c = (x << 10) + (s.charCodeAt(++i) ^ 0xDC00) + 0x10000, + r.push(0xF0 + (c >> 18 & 0x7), 0x80 + (c >> 12 & 0x3F)); + else r.push(0xE0 + (c >> 12 & 0xF)); + r.push(0x80 + (c >> 6 & 0x3F), 0x80 + (c & 0x3F)); + }; + return r; +} + +// 字符串加密成 hex 字符串 +function sha1(s) { + var data = new Uint8Array(encodeUTF8(s)) + var i, j, t; + var l = ((data.length + 8) >>> 6 << 4) + 16, s = new Uint8Array(l << 2); + s.set(new Uint8Array(data.buffer)), s = new Uint32Array(s.buffer); + for (t = new DataView(s.buffer), i = 0; i < l; i++)s[i] = t.getUint32(i << 2); + s[data.length >> 2] |= 0x80 << (24 - (data.length & 3) * 8); + s[l - 1] = data.length << 3; + var w = [], f = [ + function () { return m[1] & m[2] | ~m[1] & m[3]; }, + function () { return m[1] ^ m[2] ^ m[3]; }, + function () { return m[1] & m[2] | m[1] & m[3] | m[2] & m[3]; }, + function () { return m[1] ^ m[2] ^ m[3]; } + ], rol = function (n, c) { return n << c | n >>> (32 - c); }, + k = [1518500249, 1859775393, -1894007588, -899497514], + m = [1732584193, -271733879, null, null, -1009589776]; + m[2] = ~m[0], m[3] = ~m[1]; + for (i = 0; i < s.length; i += 16) { + var o = m.slice(0); + for (j = 0; j < 80; j++) + w[j] = j < 16 ? s[i + j] : rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1), + t = rol(m[0], 5) + f[j / 20 | 0]() + m[4] + w[j] + k[j / 20 | 0] | 0, + m[1] = rol(m[1], 30), m.pop(), m.unshift(t); + for (j = 0; j < 5; j++)m[j] = m[j] + o[j] | 0; + }; + t = new DataView(new Uint32Array(m).buffer); + for (var i = 0; i < 5; i++)m[i] = t.getUint32(i << 2); + + var hex = Array.prototype.map.call(new Uint8Array(new Uint32Array(m).buffer), function (e) { + return (e < 16 ? "0" : "") + e.toString(16); + }).join(""); + return hex; +} diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/echarts/echarts.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/echarts/echarts.js" new file mode 100644 index 00000000..f646b49e --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/echarts/echarts.js" @@ -0,0 +1,48934 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (factory((global.echarts = {}))); +}(this, (function (exports) { 'use strict'; + +/* +* 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. +*/ +// (1) The code `if (__DEV__) ...` can be removed by build tool. +// (2) If intend to use `__DEV__`, this module should be imported. Use a global +// variable `__DEV__` may cause that miss the declaration (see #6535), or the +// declaration is behind of the using position (for example in `Model.extent`, +// And tools like rollup can not analysis the dependency if not import). + +/** + * zrender: 生成唯一id + * + * @author errorrik (errorrik@gmail.com) + */ +var idStart = 0x0907; +var guid = function () { + return idStart++; +}; + +/** + * echarts设备环境识别 + * + * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。 + * @author firede[firede@firede.us] + * @desc thanks zepto. + */ + +/* global wx */ +var env = {}; + +if (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') { + // In Weixin Application + env = { + browser: {}, + os: {}, + node: false, + wxa: true, + // Weixin Application + canvasSupported: true, + svgSupported: false, + touchEventsSupported: true, + domSupported: false + }; +} else if (typeof document === 'undefined' && typeof self !== 'undefined') { + // In worker + env = { + browser: {}, + os: {}, + node: false, + worker: true, + canvasSupported: true, + domSupported: false + }; +} else if (typeof navigator === 'undefined') { + // In node + env = { + browser: {}, + os: {}, + node: true, + worker: false, + // Assume canvas is supported + canvasSupported: true, + svgSupported: true, + domSupported: false + }; +} else { + env = detect(navigator.userAgent); +} + +var env$1 = env; // Zepto.js +// (c) 2010-2013 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +function detect(ua) { + var os = {}; + var browser = {}; // var webkit = ua.match(/Web[kK]it[\/]{0,1}([\d.]+)/); + // var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); + // var ipad = ua.match(/(iPad).*OS\s([\d_]+)/); + // var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/); + // var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/); + // var webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/); + // var touchpad = webos && ua.match(/TouchPad/); + // var kindle = ua.match(/Kindle\/([\d.]+)/); + // var silk = ua.match(/Silk\/([\d._]+)/); + // var blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/); + // var bb10 = ua.match(/(BB10).*Version\/([\d.]+)/); + // var rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/); + // var playbook = ua.match(/PlayBook/); + // var chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/); + + var firefox = ua.match(/Firefox\/([\d.]+)/); // var safari = webkit && ua.match(/Mobile\//) && !chrome; + // var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome; + + var ie = ua.match(/MSIE\s([\d.]+)/) // IE 11 Trident/7.0; rv:11.0 + || ua.match(/Trident\/.+?rv:(([\d.]+))/); + var edge = ua.match(/Edge\/([\d.]+)/); // IE 12 and 12+ + + var weChat = /micromessenger/i.test(ua); // Todo: clean this up with a better OS/browser seperation: + // - discern (more) between multiple browsers on android + // - decide if kindle fire in silk mode is android or not + // - Firefox on Android doesn't specify the Android version + // - possibly devide in os, device and browser hashes + // if (browser.webkit = !!webkit) browser.version = webkit[1]; + // if (android) os.android = true, os.version = android[2]; + // if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.'); + // if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.'); + // if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null; + // if (webos) os.webos = true, os.version = webos[2]; + // if (touchpad) os.touchpad = true; + // if (blackberry) os.blackberry = true, os.version = blackberry[2]; + // if (bb10) os.bb10 = true, os.version = bb10[2]; + // if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2]; + // if (playbook) browser.playbook = true; + // if (kindle) os.kindle = true, os.version = kindle[1]; + // if (silk) browser.silk = true, browser.version = silk[1]; + // if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true; + // if (chrome) browser.chrome = true, browser.version = chrome[1]; + + if (firefox) { + browser.firefox = true; + browser.version = firefox[1]; + } // if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true; + // if (webview) browser.webview = true; + + + if (ie) { + browser.ie = true; + browser.version = ie[1]; + } + + if (edge) { + browser.edge = true; + browser.version = edge[1]; + } // It is difficult to detect WeChat in Win Phone precisely, because ua can + // not be set on win phone. So we do not consider Win Phone. + + + if (weChat) { + browser.weChat = true; + } // os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) || + // (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/))); + // os.phone = !!(!os.tablet && !os.ipod && (android || iphone || webos || + // (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) || + // (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/)))); + + + return { + browser: browser, + os: os, + node: false, + // 原生canvas支持,改极端点了 + // canvasSupported : !(browser.ie && parseFloat(browser.version) < 9) + canvasSupported: !!document.createElement('canvas').getContext, + svgSupported: typeof SVGRect !== 'undefined', + // works on most browsers + // IE10/11 does not support touch event, and MS Edge supports them but not by + // default, so we dont check navigator.maxTouchPoints for them here. + touchEventsSupported: 'ontouchstart' in window && !browser.ie && !browser.edge, + // . + pointerEventsSupported: 'onpointerdown' in window // Firefox supports pointer but not by default, only MS browsers are reliable on pointer + // events currently. So we dont use that on other browsers unless tested sufficiently. + // Although IE 10 supports pointer event, it use old style and is different from the + // standard. So we exclude that. (IE 10 is hardly used on touch device) + && (browser.edge || browser.ie && browser.version >= 11), + // passiveSupported: detectPassiveSupport() + domSupported: typeof document !== 'undefined' + }; +} // See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection +// function detectPassiveSupport() { +// // Test via a getter in the options object to see if the passive property is accessed +// var supportsPassive = false; +// try { +// var opts = Object.defineProperty({}, 'passive', { +// get: function() { +// supportsPassive = true; +// } +// }); +// window.addEventListener('testPassive', function() {}, opts); +// } catch (e) { +// } +// return supportsPassive; +// } + +/** + * @module zrender/core/util + */ +// 用于处理merge时无法遍历Date等对象的问题 +var BUILTIN_OBJECT = { + '[object Function]': 1, + '[object RegExp]': 1, + '[object Date]': 1, + '[object Error]': 1, + '[object CanvasGradient]': 1, + '[object CanvasPattern]': 1, + // For node-canvas + '[object Image]': 1, + '[object Canvas]': 1 +}; +var TYPED_ARRAY = { + '[object Int8Array]': 1, + '[object Uint8Array]': 1, + '[object Uint8ClampedArray]': 1, + '[object Int16Array]': 1, + '[object Uint16Array]': 1, + '[object Int32Array]': 1, + '[object Uint32Array]': 1, + '[object Float32Array]': 1, + '[object Float64Array]': 1 +}; +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 nativeReduce = arrayProto.reduce; // Avoid assign to an exported variable, for transforming to cjs. + +var methods = {}; +function $override(name, fn) { + // Clear ctx instance for different environment + if (name === 'createCanvas') { + _ctx = null; + } + + methods[name] = fn; +} +/** + * Those data types can be cloned: + * Plain object, Array, TypedArray, number, string, null, undefined. + * Those data types will be assgined using the orginal data: + * BUILTIN_OBJECT + * Instance of user defined class will be cloned to a plain object, without + * properties in prototype. + * Other data types is not supported (not sure what will happen). + * + * Caution: do not support clone Date, for performance consideration. + * (There might be a large number of date in `series.data`). + * So date should not be modified in and out of echarts. + * + * @param {*} source + * @return {*} new + */ + +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 (source.constructor.from) { + result = Ctor.from(source); + } else { + result = new Ctor(source.length); + + for (var i = 0, len = source.length; i < len; i++) { + result[i] = clone(source[i]); + } + } + } + } else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) { + result = {}; + + for (var key in source) { + if (source.hasOwnProperty(key)) { + result[key] = clone(source[key]); + } + } + } + + return result; +} +/** + * @memberOf module:zrender/core/util + * @param {*} target + * @param {*} source + * @param {boolean} [overwrite=false] + */ + +function merge(target, source, overwrite) { + // We should escapse that source is string + // and enter for ... in ... + if (!isObject$1(source) || !isObject$1(target)) { + return overwrite ? clone(source) : target; + } + + for (var key in source) { + if (source.hasOwnProperty(key)) { + var targetProp = target[key]; + var sourceProp = source[key]; + + if (isObject$1(sourceProp) && isObject$1(targetProp) && !isArray(sourceProp) && !isArray(targetProp) && !isDom(sourceProp) && !isDom(targetProp) && !isBuiltInObject(sourceProp) && !isBuiltInObject(targetProp) && !isPrimitive(sourceProp) && !isPrimitive(targetProp)) { + // 如果需要递归覆盖,就递归调用merge + merge(targetProp, sourceProp, overwrite); + } else if (overwrite || !(key in target)) { + // 否则只处理overwrite为true,或者在目标对象中没有此属性的情况 + // NOTE,在 target[key] 不存在的时候也是直接覆盖 + target[key] = clone(source[key], true); + } + } + } + + return target; +} +/** + * @param {Array} targetAndSources The first item is target, and the rests are source. + * @param {boolean} [overwrite=false] + * @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; +} +/** + * @param {*} target + * @param {*} source + * @memberOf module:zrender/core/util + */ + +function extend(target, source) { + for (var key in source) { + if (source.hasOwnProperty(key)) { + target[key] = source[key]; + } + } + + return target; +} +/** + * @param {*} target + * @param {*} source + * @param {boolean} [overlay=false] + * @memberOf module:zrender/core/util + */ + +function defaults(target, source, overlay) { + for (var key in source) { + if (source.hasOwnProperty(key) && (overlay ? source[key] != null : target[key] == null)) { + target[key] = source[key]; + } + } + + return target; +} +var createCanvas = function () { + return methods.createCanvas(); +}; + +methods.createCanvas = function () { + return document.createElement('canvas'); +}; // FIXME + + +var _ctx; + +function getContext() { + if (!_ctx) { + // Use util.createCanvas instead of createCanvas + // because createCanvas may be overwritten in different environment + _ctx = createCanvas().getContext('2d'); + } + + return _ctx; +} +/** + * 查询数组中元素的index + * @memberOf module:zrender/core/util + */ + +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; +} +/** + * 构造类继承关系 + * + * @memberOf module:zrender/core/util + * @param {Function} clazz 源类 + * @param {Function} baseClazz 基类 + */ + +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; +} +/** + * @memberOf module:zrender/core/util + * @param {Object|Function} target + * @param {Object|Function} sorce + * @param {boolean} overlay + */ + +function mixin(target, source, overlay) { + target = 'prototype' in target ? target.prototype : target; + source = 'prototype' in source ? source.prototype : source; + defaults(target, source, overlay); +} +/** + * Consider typed array. + * @param {Array|TypedArray} data + */ + +function isArrayLike(data) { + if (!data) { + return; + } + + if (typeof data === 'string') { + return false; + } + + return typeof data.length === 'number'; +} +/** + * 数组或对象遍历 + * @memberOf module:zrender/core/util + * @param {Object|Array} obj + * @param {Function} cb + * @param {*} [context] + */ + +function each$1(obj, cb, context) { + if (!(obj && cb)) { + return; + } + + if (obj.forEach && obj.forEach === nativeForEach) { + obj.forEach(cb, context); + } else if (obj.length === +obj.length) { + for (var i = 0, len = obj.length; i < len; i++) { + cb.call(context, obj[i], i, obj); + } + } else { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + cb.call(context, obj[key], key, obj); + } + } + } +} +/** + * 数组映射 + * @memberOf module:zrender/core/util + * @param {Array} obj + * @param {Function} cb + * @param {*} [context] + * @return {Array} + */ + +function map(obj, cb, context) { + if (!(obj && cb)) { + return; + } + + if (obj.map && obj.map === nativeMap) { + return obj.map(cb, context); + } else { + var result = []; + + for (var i = 0, len = obj.length; i < len; i++) { + result.push(cb.call(context, obj[i], i, obj)); + } + + return result; + } +} +/** + * @memberOf module:zrender/core/util + * @param {Array} obj + * @param {Function} cb + * @param {Object} [memo] + * @param {*} [context] + * @return {Array} + */ + +function reduce(obj, cb, memo, context) { + if (!(obj && cb)) { + return; + } + + if (obj.reduce && obj.reduce === nativeReduce) { + return obj.reduce(cb, memo, context); + } else { + for (var i = 0, len = obj.length; i < len; i++) { + memo = cb.call(context, memo, obj[i], i, obj); + } + + return memo; + } +} +/** + * 数组过滤 + * @memberOf module:zrender/core/util + * @param {Array} obj + * @param {Function} cb + * @param {*} [context] + * @return {Array} + */ + +function filter(obj, cb, context) { + if (!(obj && cb)) { + return; + } + + if (obj.filter && obj.filter === nativeFilter) { + return obj.filter(cb, context); + } else { + var result = []; + + for (var i = 0, len = obj.length; i < len; i++) { + if (cb.call(context, obj[i], i, obj)) { + result.push(obj[i]); + } + } + + return result; + } +} +/** + * 数组项查找 + * @memberOf module:zrender/core/util + * @param {Array} obj + * @param {Function} cb + * @param {*} [context] + * @return {*} + */ + +function find(obj, cb, context) { + if (!(obj && cb)) { + return; + } + + for (var i = 0, len = obj.length; i < len; i++) { + if (cb.call(context, obj[i], i, obj)) { + return obj[i]; + } + } +} +/** + * @memberOf module:zrender/core/util + * @param {Function} func + * @param {*} context + * @return {Function} + */ + +function bind(func, context) { + var args = nativeSlice.call(arguments, 2); + return function () { + return func.apply(context, args.concat(nativeSlice.call(arguments))); + }; +} +/** + * @memberOf module:zrender/core/util + * @param {Function} func + * @return {Function} + */ + +function curry(func) { + var args = nativeSlice.call(arguments, 1); + return function () { + return func.apply(this, args.concat(nativeSlice.call(arguments))); + }; +} +/** + * @memberOf module:zrender/core/util + * @param {*} value + * @return {boolean} + */ + +function isArray(value) { + return objToString.call(value) === '[object Array]'; +} +/** + * @memberOf module:zrender/core/util + * @param {*} value + * @return {boolean} + */ + +function isFunction$1(value) { + return typeof value === 'function'; +} +/** + * @memberOf module:zrender/core/util + * @param {*} value + * @return {boolean} + */ + +function isString(value) { + return objToString.call(value) === '[object String]'; +} +/** + * @memberOf module:zrender/core/util + * @param {*} value + * @return {boolean} + */ + +function isObject$1(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return type === 'function' || !!value && type === 'object'; +} +/** + * @memberOf module:zrender/core/util + * @param {*} value + * @return {boolean} + */ + +function isBuiltInObject(value) { + return !!BUILTIN_OBJECT[objToString.call(value)]; +} +/** + * @memberOf module:zrender/core/util + * @param {*} value + * @return {boolean} + */ + +function isTypedArray(value) { + return !!TYPED_ARRAY[objToString.call(value)]; +} +/** + * @memberOf module:zrender/core/util + * @param {*} value + * @return {boolean} + */ + +function isDom(value) { + return typeof value === 'object' && typeof value.nodeType === 'number' && typeof value.ownerDocument === 'object'; +} +/** + * Whether is exactly NaN. Notice isNaN('a') returns true. + * @param {*} value + * @return {boolean} + */ + +function eqNaN(value) { + /* eslint-disable-next-line no-self-compare */ + return value !== value; +} +/** + * If value1 is not null, then return value1, otherwise judget rest of values. + * Low performance. + * @memberOf module:zrender/core/util + * @return {*} Final value + */ + +function retrieve(values) { + for (var i = 0, len = arguments.length; i < len; i++) { + if (arguments[i] != null) { + return arguments[i]; + } + } +} +function retrieve2(value0, value1) { + return value0 != null ? value0 : value1; +} +function retrieve3(value0, value1, value2) { + return value0 != null ? value0 : value1 != null ? value1 : value2; +} +/** + * @memberOf module:zrender/core/util + * @param {Array} arr + * @param {number} startIndex + * @param {number} endIndex + * @return {Array} + */ + +function slice() { + return Function.call.apply(nativeSlice, arguments); +} +/** + * Normalize css liked array configuration + * e.g. + * 3 => [3, 3, 3, 3] + * [4, 2] => [4, 2, 4, 2] + * [4, 3, 2] => [4, 3, 2, 3] + * @param {number|Array.} val + * @return {Array.} + */ + +function normalizeCssArray(val) { + if (typeof val === 'number') { + return [val, val, val, val]; + } + + var len = val.length; + + if (len === 2) { + // vertical | horizontal + return [val[0], val[1], val[0], val[1]]; + } else if (len === 3) { + // top | horizontal | bottom + return [val[0], val[1], val[2], val[1]]; + } + + return val; +} +/** + * @memberOf module:zrender/core/util + * @param {boolean} condition + * @param {string} message + */ + +function assert$1(condition, message) { + if (!condition) { + throw new Error(message); + } +} +/** + * @memberOf module:zrender/core/util + * @param {string} str string to be trimed + * @return {string} trimed string + */ + +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__'; +/** + * Set an object as primitive to be ignored traversing children in clone or merge + */ + +function setAsPrimitive(obj) { + obj[primitiveKey] = true; +} +function isPrimitive(obj) { + return obj[primitiveKey]; +} +/** + * @constructor + * @param {Object} obj Only apply `ownProperty`. + */ + +function HashMap(obj) { + var isArr = isArray(obj); // Key should not be set on this, otherwise + // methods get/set/... may be overrided. + + this.data = {}; + var thisMap = this; + obj instanceof HashMap ? obj.each(visit) : obj && each$1(obj, visit); + + function visit(value, key) { + isArr ? thisMap.set(value, key) : thisMap.set(key, value); + } +} + +HashMap.prototype = { + constructor: HashMap, + // Do not provide `has` method to avoid defining what is `has`. + // (We usually treat `null` and `undefined` as the same, different + // from ES6 Map). + get: function (key) { + return this.data.hasOwnProperty(key) ? this.data[key] : null; + }, + set: function (key, value) { + // Comparing with invocation chaining, `return value` is more commonly + // used in this case: `var someVal = map.set('a', genVal());` + return this.data[key] = value; + }, + // Although util.each can be performed on this hashMap directly, user + // should not use the exposed keys, who are prefixed. + each: function (cb, context) { + context !== void 0 && (cb = bind(cb, context)); + /* eslint-disable guard-for-in */ + + for (var key in this.data) { + this.data.hasOwnProperty(key) && cb(this.data[key], key); + } + /* eslint-enable guard-for-in */ + + }, + // Do not use this method if performance sensitive. + removeKey: function (key) { + delete this.data[key]; + } +}; +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 (i = 0; i < b.length; i++) { + newArray[i + offset] = b[i]; + } + + return newArray; +} +function noop() {} + +var zrUtil = (Object.freeze || Object)({ + $override: $override, + clone: clone, + merge: merge, + mergeAll: mergeAll, + extend: extend, + defaults: defaults, + createCanvas: createCanvas, + getContext: getContext, + indexOf: indexOf, + inherits: inherits, + mixin: mixin, + isArrayLike: isArrayLike, + each: each$1, + map: map, + reduce: reduce, + filter: filter, + find: find, + bind: bind, + curry: curry, + isArray: isArray, + isFunction: isFunction$1, + isString: isString, + isObject: isObject$1, + isBuiltInObject: isBuiltInObject, + isTypedArray: isTypedArray, + isDom: isDom, + eqNaN: eqNaN, + retrieve: retrieve, + retrieve2: retrieve2, + retrieve3: retrieve3, + slice: slice, + normalizeCssArray: normalizeCssArray, + assert: assert$1, + trim: trim, + setAsPrimitive: setAsPrimitive, + isPrimitive: isPrimitive, + createHashMap: createHashMap, + concatArray: concatArray, + noop: noop +}); + +/* global Float32Array */ +var ArrayCtor = typeof Float32Array === 'undefined' ? Array : Float32Array; +/** + * 创建一个向量 + * @param {number} [x=0] + * @param {number} [y=0] + * @return {Vector2} + */ + +function create(x, y) { + var out = new ArrayCtor(2); + + if (x == null) { + x = 0; + } + + if (y == null) { + y = 0; + } + + out[0] = x; + out[1] = y; + return out; +} +/** + * 复制向量数据 + * @param {Vector2} out + * @param {Vector2} v + * @return {Vector2} + */ + +function copy(out, v) { + out[0] = v[0]; + out[1] = v[1]; + return out; +} +/** + * 克隆一个向量 + * @param {Vector2} v + * @return {Vector2} + */ + +function clone$1(v) { + var out = new ArrayCtor(2); + out[0] = v[0]; + out[1] = v[1]; + return out; +} +/** + * 设置向量的两个项 + * @param {Vector2} out + * @param {number} a + * @param {number} b + * @return {Vector2} 结果 + */ + +function set(out, a, b) { + out[0] = a; + out[1] = b; + return out; +} +/** + * 向量相加 + * @param {Vector2} out + * @param {Vector2} v1 + * @param {Vector2} v2 + */ + +function add(out, v1, v2) { + out[0] = v1[0] + v2[0]; + out[1] = v1[1] + v2[1]; + return out; +} +/** + * 向量缩放后相加 + * @param {Vector2} out + * @param {Vector2} v1 + * @param {Vector2} v2 + * @param {number} a + */ + +function scaleAndAdd(out, v1, v2, a) { + out[0] = v1[0] + v2[0] * a; + out[1] = v1[1] + v2[1] * a; + return out; +} +/** + * 向量相减 + * @param {Vector2} out + * @param {Vector2} v1 + * @param {Vector2} v2 + */ + +function sub(out, v1, v2) { + out[0] = v1[0] - v2[0]; + out[1] = v1[1] - v2[1]; + return out; +} +/** + * 向量长度 + * @param {Vector2} v + * @return {number} + */ + +function len(v) { + return Math.sqrt(lenSquare(v)); +} +var length = len; // jshint ignore:line + +/** + * 向量长度平方 + * @param {Vector2} v + * @return {number} + */ + +function lenSquare(v) { + return v[0] * v[0] + v[1] * v[1]; +} +var lengthSquare = lenSquare; +/** + * 向量乘法 + * @param {Vector2} out + * @param {Vector2} v1 + * @param {Vector2} v2 + */ + +function mul(out, v1, v2) { + out[0] = v1[0] * v2[0]; + out[1] = v1[1] * v2[1]; + return out; +} +/** + * 向量除法 + * @param {Vector2} out + * @param {Vector2} v1 + * @param {Vector2} v2 + */ + +function div(out, v1, v2) { + out[0] = v1[0] / v2[0]; + out[1] = v1[1] / v2[1]; + return out; +} +/** + * 向量点乘 + * @param {Vector2} v1 + * @param {Vector2} v2 + * @return {number} + */ + +function dot(v1, v2) { + return v1[0] * v2[0] + v1[1] * v2[1]; +} +/** + * 向量缩放 + * @param {Vector2} out + * @param {Vector2} v + * @param {number} s + */ + +function scale(out, v, s) { + out[0] = v[0] * s; + out[1] = v[1] * s; + return out; +} +/** + * 向量归一化 + * @param {Vector2} out + * @param {Vector2} v + */ + +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; +} +/** + * 计算向量间距离 + * @param {Vector2} v1 + * @param {Vector2} v2 + * @return {number} + */ + +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; +/** + * 向量距离平方 + * @param {Vector2} v1 + * @param {Vector2} v2 + * @return {number} + */ + +function distanceSquare(v1, v2) { + return (v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1]); +} +var distSquare = distanceSquare; +/** + * 求负向量 + * @param {Vector2} out + * @param {Vector2} v + */ + +function negate(out, v) { + out[0] = -v[0]; + out[1] = -v[1]; + return out; +} +/** + * 插值两个点 + * @param {Vector2} out + * @param {Vector2} v1 + * @param {Vector2} v2 + * @param {number} t + */ + +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; +} +/** + * 矩阵左乘向量 + * @param {Vector2} out + * @param {Vector2} v + * @param {Vector2} m + */ + +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; +} +/** + * 求两个向量最小值 + * @param {Vector2} out + * @param {Vector2} v1 + * @param {Vector2} v2 + */ + +function min(out, v1, v2) { + out[0] = Math.min(v1[0], v2[0]); + out[1] = Math.min(v1[1], v2[1]); + return out; +} +/** + * 求两个向量最大值 + * @param {Vector2} out + * @param {Vector2} v1 + * @param {Vector2} v2 + */ + +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 = (Object.freeze || Object)({ + 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 +}); + +// TODO Draggable for group +// FIXME Draggable on element which has parent rotation or scale +function Draggable() { + this.on('mousedown', this._dragStart, this); + this.on('mousemove', this._drag, this); + this.on('mouseup', this._dragEnd, this); + this.on('globalout', this._dragEnd, this); // this._dropTarget = null; + // this._draggingTarget = null; + // this._x = 0; + // this._y = 0; +} + +Draggable.prototype = { + constructor: Draggable, + _dragStart: function (e) { + var draggingTarget = e.target; + + if (draggingTarget && draggingTarget.draggable) { + this._draggingTarget = draggingTarget; + draggingTarget.dragging = true; + this._x = e.offsetX; + this._y = e.offsetY; + this.dispatchToElement(param(draggingTarget, e), 'dragstart', e.event); + } + }, + _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.dispatchToElement(param(draggingTarget, e), 'drag', e.event); + var dropTarget = this.findHover(x, y, draggingTarget).target; + var lastDropTarget = this._dropTarget; + this._dropTarget = dropTarget; + + if (draggingTarget !== dropTarget) { + if (lastDropTarget && dropTarget !== lastDropTarget) { + this.dispatchToElement(param(lastDropTarget, e), 'dragleave', e.event); + } + + if (dropTarget && dropTarget !== lastDropTarget) { + this.dispatchToElement(param(dropTarget, e), 'dragenter', e.event); + } + } + } + }, + _dragEnd: function (e) { + var draggingTarget = this._draggingTarget; + + if (draggingTarget) { + draggingTarget.dragging = false; + } + + this.dispatchToElement(param(draggingTarget, e), 'dragend', e.event); + + if (this._dropTarget) { + this.dispatchToElement(param(this._dropTarget, e), 'drop', e.event); + } + + this._draggingTarget = null; + this._dropTarget = null; + } +}; + +function param(target, e) { + return { + target: target, + topTarget: e && e.topTarget + }; +} + +/** + * Event Mixin + * @module zrender/mixin/Eventful + * @author Kener (@Kener-林峰, kener.linfeng@gmail.com) + * pissang (https://www.github.com/pissang) + */ +var arrySlice = Array.prototype.slice; +/** + * Event dispatcher. + * + * @alias module:zrender/mixin/Eventful + * @constructor + * @param {Object} [eventProcessor] The object eventProcessor is the scope when + * `eventProcessor.xxx` called. + * @param {Function} [eventProcessor.normalizeQuery] + * param: {string|Object} Raw query. + * return: {string|Object} Normalized query. + * @param {Function} [eventProcessor.filter] Event will be dispatched only + * if it returns `true`. + * param: {string} eventType + * param: {string|Object} query + * return: {boolean} + * @param {Function} [eventProcessor.afterTrigger] Call after all handlers called. + * param: {string} eventType + */ + +var Eventful = function (eventProcessor) { + this._$handlers = {}; + this._$eventProcessor = eventProcessor; +}; + +Eventful.prototype = { + constructor: Eventful, + + /** + * The handler can only be triggered once, then removed. + * + * @param {string} event The event name. + * @param {string|Object} [query] Condition used on event filter. + * @param {Function} handler The event handler. + * @param {Object} context + */ + one: function (event, query, handler, context) { + return on(this, event, query, handler, context, true); + }, + + /** + * Bind a handler. + * + * @param {string} event The event name. + * @param {string|Object} [query] Condition used on event filter. + * @param {Function} handler The event handler. + * @param {Object} [context] + */ + on: function (event, query, handler, context) { + return on(this, event, query, handler, context, false); + }, + + /** + * Whether any handler has bound. + * + * @param {string} event + * @return {boolean} + */ + isSilent: function (event) { + var _h = this._$handlers; + return !_h[event] || !_h[event].length; + }, + + /** + * Unbind a event. + * + * @param {string} event The event name. + * @param {Function} [handler] The event handler. + */ + off: function (event, handler) { + var _h = this._$handlers; + + if (!event) { + this._$handlers = {}; + return this; + } + + if (handler) { + if (_h[event]) { + var newList = []; + + for (var i = 0, l = _h[event].length; i < l; i++) { + if (_h[event][i].h !== handler) { + newList.push(_h[event][i]); + } + } + + _h[event] = newList; + } + + if (_h[event] && _h[event].length === 0) { + delete _h[event]; + } + } else { + delete _h[event]; + } + + return this; + }, + + /** + * Dispatch a event. + * + * @param {string} type The event name. + */ + trigger: function (type) { + var _h = this._$handlers[type]; + var eventProcessor = this._$eventProcessor; + + if (_h) { + var args = arguments; + var argLen = args.length; + + if (argLen > 3) { + args = arrySlice.call(args, 1); + } + + var len = _h.length; + + for (var i = 0; i < len;) { + var hItem = _h[i]; + + if (eventProcessor && eventProcessor.filter && hItem.query != null && !eventProcessor.filter(type, hItem.query)) { + i++; + continue; + } // Optimize advise from backbone + + + switch (argLen) { + case 1: + hItem.h.call(hItem.ctx); + break; + + case 2: + hItem.h.call(hItem.ctx, args[1]); + break; + + case 3: + hItem.h.call(hItem.ctx, args[1], args[2]); + break; + + default: + // have more than 2 given arguments + hItem.h.apply(hItem.ctx, args); + break; + } + + if (hItem.one) { + _h.splice(i, 1); + + len--; + } else { + i++; + } + } + } + + eventProcessor && eventProcessor.afterTrigger && eventProcessor.afterTrigger(type); + return this; + }, + + /** + * Dispatch a event with context, which is specified at the last parameter. + * + * @param {string} type The event name. + */ + triggerWithContext: function (type) { + var _h = this._$handlers[type]; + var eventProcessor = this._$eventProcessor; + + if (_h) { + var args = arguments; + var argLen = args.length; + + if (argLen > 4) { + args = arrySlice.call(args, 1, args.length - 1); + } + + var ctx = args[args.length - 1]; + var len = _h.length; + + for (var i = 0; i < len;) { + var hItem = _h[i]; + + if (eventProcessor && eventProcessor.filter && hItem.query != null && !eventProcessor.filter(type, hItem.query)) { + i++; + continue; + } // Optimize advise from backbone + + + switch (argLen) { + case 1: + hItem.h.call(ctx); + break; + + case 2: + hItem.h.call(ctx, args[1]); + break; + + case 3: + hItem.h.call(ctx, args[1], args[2]); + break; + + default: + // have more than 2 given arguments + hItem.h.apply(ctx, args); + break; + } + + if (hItem.one) { + _h.splice(i, 1); + + len--; + } else { + i++; + } + } + } + + eventProcessor && eventProcessor.afterTrigger && eventProcessor.afterTrigger(type); + return this; + } +}; + +function normalizeQuery(host, query) { + var eventProcessor = host._$eventProcessor; + + if (query != null && eventProcessor && eventProcessor.normalizeQuery) { + query = eventProcessor.normalizeQuery(query); + } + + return query; +} + +function on(eventful, event, query, handler, context, isOnce) { + var _h = eventful._$handlers; + + if (typeof query === 'function') { + context = handler; + handler = query; + query = null; + } + + if (!handler || !event) { + return eventful; + } + + query = normalizeQuery(eventful, query); + + if (!_h[event]) { + _h[event] = []; + } + + for (var i = 0; i < _h[event].length; i++) { + if (_h[event][i].h === handler) { + return eventful; + } + } + + var wrap = { + h: handler, + one: isOnce, + query: query, + ctx: context || eventful, + // FIXME + // Do not publish this feature util it is proved that it makes sense. + 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 eventful; +} // ---------------------- + +/** + * The algoritm is learnt from + * https://franklinta.com/2014/09/08/computing-css-matrix3d-transforms/ + * And we made some optimization for matrix inversion. + * Other similar approaches: + * "cv::getPerspectiveTransform", "Direct Linear Transformation". + */ +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) { + // In this case the colMask must be like: `11101111`. We can find the place of `0`. + 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] // det(subMatrix(0, j)) + * determinant(rows, rank - 1, subRowStart, subRowMask, colMask | colTag, detCache); + colLocalIdx++; + } + } + + detCache[cacheKey] = sum; + return sum; +} +/** + * Usage: + * ```js + * var transformer = buildTransformer( + * [10, 44, 100, 44, 100, 300, 10, 300], + * [50, 54, 130, 14, 140, 330, 14, 220] + * ); + * var out = []; + * transformer && transformer([11, 33], out); + * ``` + * + * Notice: `buildTransformer` may take more than 10ms in some Android device. + * + * @param {Array.} src source four points, [x0, y0, x1, y1, x2, y2, x3, y3] + * @param {Array.} dest destination four points, [x0, y0, x1, y1, x2, y2, x3, y3] + * @return {Function} transformer If fail, return null/undefined. + */ + + +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; + } // `invert(mA) * dest`, that is, `adj(mA) / det * dest`. + + + 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) * // det(subMatrix(i, j)) + 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; + }; +} + +/** + * Utilities for mouse or touch events. + */ +var isDomLevel2 = typeof window !== 'undefined' && !!window.addEventListener; +var MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/; +var EVENT_SAVED_PROP = '___zrEVENTSAVED'; +var _calcOut = []; +/** + * Get the `zrX` and `zrY`, which are relative to the top-left of + * the input `el`. + * CSS transform (2D & 3D) is supported. + * + * The strategy to fetch the coords: + * + If `calculate` is not set as `true`, users of this method should + * ensure that `el` is the same or the same size & location as `e.target`. + * Otherwise the result coords are probably not expected. Because we + * firstly try to get coords from e.offsetX/e.offsetY. + * + If `calculate` is set as `true`, the input `el` can be any element + * and we force to calculate the coords based on `el`. + * + The input `el` should be positionable (not position:static). + * + * The force `calculate` can be used in case like: + * When mousemove event triggered on ec tooltip, `e.target` is not `el`(zr painter.dom). + * + * @param {HTMLElement} el DOM element. + * @param {Event} e Mouse event or touch event. + * @param {Object} out Get `out.zrX` and `out.zrY` as the result. + * @param {boolean} [calculate=false] Whether to force calculate + * the coordinates but not use ones provided by browser. + */ + +function clientToLocal(el, e, out, calculate) { + out = out || {}; // According to the W3C Working Draft, offsetX and offsetY should be relative + // to the padding edge of the target element. The only browser using this convention + // is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does + // not support the properties. + // (see http://www.jacklmoore.com/notes/mouse-position/) + // In zr painter.dom, padding edge equals to border edge. + + if (calculate || !env$1.canvasSupported) { + calculateZrXY(el, e, out); + } // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned + // ancestor element, so we should make sure el is positioned (e.g., not position:static). + // BTW1, Webkit don't return the same results as FF in non-simple cases (like add + // zoom-factor, overflow / opacity layers, transforms ...) + // BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d. + // + // BTW3, In ff, offsetX/offsetY is always 0. + else if (env$1.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) { + out.zrX = e.layerX; + out.zrY = e.layerY; + } // For IE6+, chrome, safari, opera. (When will ff support offsetX?) + else if (e.offsetX != null) { + out.zrX = e.offsetX; + out.zrY = e.offsetY; + } // For some other device, e.g., IOS safari. + else { + calculateZrXY(el, e, out); + } + + return out; +} + +function calculateZrXY(el, e, out) { + // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect. + if (el.getBoundingClientRect && env$1.domSupported) { + var ex = e.clientX; + var ey = e.clientY; + + if (el.nodeName.toUpperCase() === 'CANVAS') { + // Original approach, which do not support CSS transform. + // marker can not be locationed in a canvas container + // (getBoundingClientRect is always 0). We do not support + // that input a pre-created canvas to zr while using css + // transform in iOS. + var box = el.getBoundingClientRect(); + out.zrX = ex - box.left; + out.zrY = ey - box.top; + return; + } else { + var saved = el[EVENT_SAVED_PROP] || (el[EVENT_SAVED_PROP] = {}); + var transformer = preparePointerTransformer(prepareCoordMarkers(el, saved), saved); + + if (transformer) { + transformer(_calcOut, ex, ey); + out.zrX = _calcOut[0]; + out.zrY = _calcOut[1]; + return; + } + } + } + + out.zrX = out.zrY = 0; +} + +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', 'width:0', 'height:0', // 'width: 5px', + // 'height: 5px', + 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) { + var transformer = saved.transformer; + var oldSrcCoords = saved.srcCoords; + var useOld = true; + var srcCoords = []; + var destCoords = []; + + 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); + useOld &= oldSrcCoords && x === oldSrcCoords[ii] && y === oldSrcCoords[ii + 1]; + destCoords.push(markers[i].offsetLeft, markers[i].offsetTop); + } // Cache to avoid time consuming of `buildTransformer`. + + + return useOld ? transformer : (saved.srcCoords = srcCoords, saved.transformer = buildTransformer(srcCoords, destCoords)); +} +/** + * Normalize the coordinates of the input event. + * + * Get the `e.zrX` and `e.zrY`, which are relative to the top-left of + * the input `el`. + * Get `e.zrDelta` if using mouse wheel. + * Get `e.which`, see the comment inside this function. + * + * Do not calculate repeatly if `zrX` and `zrY` already exist. + * + * Notice: see comments in `clientToLocal`. check the relationship + * between the result coords and the parameters `el` and `calculate`. + * + * @param {HTMLElement} el DOM element. + * @param {Event} [e] Mouse event or touch event. For lagency IE, + * do not need to input it and `window.event` is used. + * @param {boolean} [calculate=false] Whether to force calculate + * the coordinates but not use ones provided by browser. + */ + + +function normalizeEvent(el, e, calculate) { + e = e || window.event; + + if (e.zrX != null) { + return e; + } + + var eventType = e.type; + var isTouch = eventType && eventType.indexOf('touch') >= 0; + + if (!isTouch) { + clientToLocal(el, e, e, calculate); + e.zrDelta = e.wheelDelta ? e.wheelDelta / 120 : -(e.detail || 0) / 3; + } else { + var touch = eventType !== 'touchend' ? e.targetTouches[0] : e.changedTouches[0]; + touch && clientToLocal(el, touch, e, calculate); + } // Add which for click: 1 === left; 2 === middle; 3 === right; otherwise: 0; + // See jQuery: https://github.com/jquery/jquery/blob/master/src/event.js + // If e.which has been defined, it may be readonly, + // see: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which + + + 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; + } // [Caution]: `e.which` from browser is not always reliable. For example, + // when press left button and `mousemove (pointermove)` in Edge, the `e.which` + // is 65536 and the `e.button` is -1. But the `mouseup (pointerup)` and + // `mousedown (pointerdown)` is the same as Chrome does. + + + return e; +} +/** + * @param {HTMLElement} el + * @param {string} name + * @param {Function} handler + */ + +function addEventListener(el, name, handler) { + if (isDomLevel2) { + // Reproduct the console warning: + // [Violation] Added non-passive event listener to a scroll-blocking event. + // Consider marking event handler as 'passive' to make the page more responsive. + // Just set console log level: verbose in chrome dev tool. + // then the warning log will be printed when addEventListener called. + // See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md + // We have not yet found a neat way to using passive. Because in zrender the dom event + // listener delegate all of the upper events of element. Some of those events need + // to prevent default. For example, the feature `preventDefaultMouseMove` of echarts. + // Before passive can be adopted, these issues should be considered: + // (1) Whether and how a zrender user specifies an event listener passive. And by default, + // passive or not. + // (2) How to tread that some zrender event listener is passive, and some is not. If + // we use other way but not preventDefault of mousewheel and touchmove, browser + // compatibility should be handled. + // var opts = (env.passiveSupported && name === 'mousewheel') + // ? {passive: true} + // // By default, the third param of el.addEventListener is `capture: false`. + // : void 0; + // el.addEventListener(name, handler /* , opts */); + el.addEventListener(name, handler); + } else { + el.attachEvent('on' + name, handler); + } +} +function removeEventListener(el, name, handler) { + if (isDomLevel2) { + el.removeEventListener(name, handler); + } else { + el.detachEvent('on' + name, handler); + } +} +/** + * preventDefault and stopPropagation. + * Notice: do not use this method in zrender. It can only be + * used by upper applications if necessary. + * + * @param {Event} e A mouse or touch event. + */ + +var stop = isDomLevel2 ? function (e) { + e.preventDefault(); + e.stopPropagation(); + e.cancelBubble = true; +} : function (e) { + e.returnValue = false; + e.cancelBubble = true; +}; +/** + * This method only works for mouseup and mousedown. The functionality is restricted + * for fault tolerance, See the `e.which` compatibility above. + * + * @param {MouseEvent} e + * @return {boolean} + */ + + +/** + * To be removed. + * @deprecated + */ + + // For backward compatibility + +/** + * Only implements needed gestures for mobile. + */ +var GestureMgr = function () { + /** + * @private + * @type {Array.} + */ + this._track = []; +}; + +GestureMgr.prototype = { + constructor: GestureMgr, + recognize: function (event, target, root) { + this._doTrack(event, target, root); + + return this._recognize(event); + }, + clear: function () { + this._track.length = 0; + return this; + }, + _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); + }, + _recognize: function (event) { + for (var eventName in recognizers) { + if (recognizers.hasOwnProperty(eventName)) { + var gestureInfo = recognizers[eventName](this._track, event); + + if (gestureInfo) { + return gestureInfo; + } + } + } + } +}; + +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 (track, event) { + var trackLen = track.length; + + if (!trackLen) { + return; + } + + var pinchEnd = (track[trackLen - 1] || {}).points; + var pinchPre = (track[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: track[0].target, + event: event + }; + } + } // Only pinch currently. + +}; + +var SILENT = 'silent'; + +function makeEventPacket(eveType, targetInfo, event) { + return { + type: eveType, + event: event, + // target can only be an element that is not silent. + target: targetInfo.target, + // topTarget can be a silent element. + 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(event) { + stop(this.event); +} + +function EmptyProxy() {} + +EmptyProxy.prototype.dispose = function () {}; + +var handlerNames = ['click', 'dblclick', 'mousewheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu']; +/** + * @alias module:zrender/Handler + * @constructor + * @extends module:zrender/mixin/Eventful + * @param {module:zrender/Storage} storage Storage instance. + * @param {module:zrender/Painter} painter Painter instance. + * @param {module:zrender/dom/HandlerProxy} proxy HandlerProxy instance. + * @param {HTMLElement} painterRoot painter.root (not painter.getViewportRoot()). + */ + +var Handler = function (storage, painter, proxy, painterRoot) { + Eventful.call(this); + this.storage = storage; + this.painter = painter; + this.painterRoot = painterRoot; + proxy = proxy || new EmptyProxy(); + /** + * Proxy of event. can be Dom, WebGLSurface, etc. + */ + + this.proxy = null; + /** + * {target, topTarget, x, y} + * @private + * @type {Object} + */ + + this._hovered = {}; + /** + * @private + * @type {Date} + */ + + this._lastTouchMoment; + /** + * @private + * @type {number} + */ + + this._lastX; + /** + * @private + * @type {number} + */ + + this._lastY; + /** + * @private + * @type {module:zrender/core/GestureMgr} + */ + + this._gestureMgr; + Draggable.call(this); + this.setHandlerProxy(proxy); +}; + +Handler.prototype = { + constructor: Handler, + setHandlerProxy: function (proxy) { + if (this.proxy) { + this.proxy.dispose(); + } + + if (proxy) { + each$1(handlerNames, function (name) { + proxy.on && proxy.on(name, this[name], this); + }, this); // Attach handler + + proxy.handler = this; + } + + this.proxy = proxy; + }, + mousemove: function (event) { + var x = event.zrX; + var y = event.zrY; + var lastHovered = this._hovered; + var lastHoveredTarget = lastHovered.target; // If lastHoveredTarget is removed from zr (detected by '__zr') by some API call + // (like 'setOption' or 'dispatchAction') in event handlers, we should find + // lastHovered again here. Otherwise 'mouseout' can not be triggered normally. + // See #6198. + + if (lastHoveredTarget && !lastHoveredTarget.__zr) { + lastHovered = this.findHover(lastHovered.x, lastHovered.y); + lastHoveredTarget = lastHovered.target; + } + + var hovered = this._hovered = this.findHover(x, y); + var hoveredTarget = hovered.target; + var proxy = this.proxy; + proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default'); // Mouse out on previous hovered element + + if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) { + this.dispatchToElement(lastHovered, 'mouseout', event); + } // Mouse moving on one element + + + this.dispatchToElement(hovered, 'mousemove', event); // Mouse over on a new element + + if (hoveredTarget && hoveredTarget !== lastHoveredTarget) { + this.dispatchToElement(hovered, 'mouseover', event); + } + }, + mouseout: function (event) { + this.dispatchToElement(this._hovered, 'mouseout', event); // There might be some doms created by upper layer application + // at the same level of painter.getViewportRoot() (e.g., tooltip + // dom created by echarts), where 'globalout' event should not + // be triggered when mouse enters these doms. (But 'mouseout' + // should be triggered at the original hovered element as usual). + + var element = event.toElement || event.relatedTarget; + var innerDom; + + do { + element = element && element.parentNode; + } while (element && element.nodeType !== 9 && !(innerDom = element === this.painterRoot)); + + !innerDom && this.trigger('globalout', { + event: event + }); + }, + + /** + * Resize + */ + resize: function (event) { + this._hovered = {}; + }, + + /** + * Dispatch event + * @param {string} eventName + * @param {event=} eventArgs + */ + dispatch: function (eventName, eventArgs) { + var handler = this[eventName]; + handler && handler.call(this, eventArgs); + }, + + /** + * Dispose + */ + dispose: function () { + this.proxy.dispose(); + this.storage = this.proxy = this.painter = null; + }, + + /** + * 设置默认的cursor style + * @param {string} [cursorStyle='default'] 例如 crosshair + */ + setCursorStyle: function (cursorStyle) { + var proxy = this.proxy; + proxy.setCursor && proxy.setCursor(cursorStyle); + }, + + /** + * 事件分发代理 + * + * @private + * @param {Object} targetInfo {target, topTarget} 目标图形元素 + * @param {string} eventName 事件名称 + * @param {Object} event 事件对象 + */ + dispatchToElement: function (targetInfo, eventName, event) { + targetInfo = targetInfo || {}; + var el = targetInfo.target; + + if (el && el.silent) { + return; + } + + var eventHandler = 'on' + eventName; + var eventPacket = makeEventPacket(eventName, targetInfo, event); + + while (el) { + el[eventHandler] && (eventPacket.cancelBubble = el[eventHandler].call(el, eventPacket)); + el.trigger(eventName, eventPacket); + el = el.parent; + + if (eventPacket.cancelBubble) { + break; + } + } + + if (!eventPacket.cancelBubble) { + // 冒泡到顶级 zrender 对象 + this.trigger(eventName, eventPacket); // 分发事件到用户自定义层 + // 用户有可能在全局 click 事件中 dispose,所以需要判断下 painter 是否存在 + + this.painter && this.painter.eachOtherLayer(function (layer) { + if (typeof layer[eventHandler] === 'function') { + layer[eventHandler].call(layer, eventPacket); + } + + if (layer.trigger) { + layer.trigger(eventName, eventPacket); + } + }); + } + }, + + /** + * @private + * @param {number} x + * @param {number} y + * @param {module:zrender/graphic/Displayable} exclude + * @return {model:zrender/Element} + * @method + */ + findHover: function (x, y, exclude) { + var list = this.storage.getDisplayList(); + var out = { + x: x, + y: y + }; + + for (var i = list.length - 1; i >= 0; i--) { + var hoverCheckResult; + + if (list[i] !== exclude // getDisplayList may include ignored item in VML mode + && !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; + }, + 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(); // Do not do any preventDefault here. Upper application do that if necessary. + + if (gestureInfo) { + var type = gestureInfo.type; + event.gestureEvent = type; + this.dispatchToElement({ + target: gestureInfo.target + }, type, gestureInfo.event); + } + } +}; // Common handlers + +each$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) { + Handler.prototype[name] = function (event) { + // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover + var hovered = this.findHover(event.zrX, event.zrY); + var hoveredTarget = hovered.target; + + if (name === 'mousedown') { + this._downEl = hoveredTarget; + this._downPoint = [event.zrX, event.zrY]; // In case click triggered before mouseup + + this._upEl = hoveredTarget; + } else if (name === 'mouseup') { + this._upEl = hoveredTarget; + } else if (name === 'click') { + if (this._downEl !== this._upEl // Original click event is triggered on the whole canvas element, + // including the case that `mousedown` - `mousemove` - `mouseup`, + // which should be filtered, otherwise it will bring trouble to + // pan and zoom. + || !this._downPoint // Arbitrary value + || 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; + + while (el) { + // If clipped by ancestor. + // FIXME: If clipPath has neither stroke nor fill, + // el.clipPath.contain(x, y) will always return false. + if (el.clipPath && !el.clipPath.contain(x, y)) { + return false; + } + + if (el.silent) { + isSilent = true; + } + + el = el.parent; + } + + return isSilent ? SILENT : true; + } + + return false; +} + +mixin(Handler, Eventful); +mixin(Handler, Draggable); + +/** + * 3x2矩阵操作类 + * @exports zrender/tool/matrix + */ + +/* global Float32Array */ +var ArrayCtor$1 = typeof Float32Array === 'undefined' ? Array : Float32Array; +/** + * Create a identity matrix. + * @return {Float32Array|Array.} + */ + +function create$1() { + var out = new ArrayCtor$1(6); + identity(out); + return out; +} +/** + * 设置矩阵为单位矩阵 + * @param {Float32Array|Array.} out + */ + +function identity(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; +} +/** + * 复制矩阵 + * @param {Float32Array|Array.} out + * @param {Float32Array|Array.} m + */ + +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; +} +/** + * 矩阵相乘 + * @param {Float32Array|Array.} out + * @param {Float32Array|Array.} m1 + * @param {Float32Array|Array.} m2 + */ + +function mul$1(out, m1, m2) { + // Consider matrix.mul(m, m2, m); + // where out is the same as m2. + // So use temp variable to escape error. + 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; +} +/** + * 平移变换 + * @param {Float32Array|Array.} out + * @param {Float32Array|Array.} a + * @param {Float32Array|Array.} v + */ + +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; +} +/** + * 旋转变换 + * @param {Float32Array|Array.} out + * @param {Float32Array|Array.} a + * @param {number} rad + */ + +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; +} +/** + * 缩放变换 + * @param {Float32Array|Array.} out + * @param {Float32Array|Array.} a + * @param {Float32Array|Array.} v + */ + +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; +} +/** + * 求逆矩阵 + * @param {Float32Array|Array.} out + * @param {Float32Array|Array.} a + */ + +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; +} +/** + * Clone a new matrix. + * @param {Float32Array|Array.} a + */ + +function clone$2(a) { + var b = create$1(); + copy$1(b, a); + return b; +} + +var matrix = (Object.freeze || Object)({ + create: create$1, + identity: identity, + copy: copy$1, + mul: mul$1, + translate: translate, + rotate: rotate, + scale: scale$1, + invert: invert, + clone: clone$2 +}); + +/** + * 提供变换扩展 + * @module zrender/mixin/Transformable + * @author pissang (https://www.github.com/pissang) + */ +var mIdentity = identity; +var EPSILON = 5e-5; + +function isNotAroundZero(val) { + return val > EPSILON || val < -EPSILON; +} +/** + * @alias module:zrender/mixin/Transformable + * @constructor + */ + + +var Transformable = function (opts) { + opts = opts || {}; // If there are no given position, rotation, scale + + if (!opts.position) { + /** + * 平移 + * @type {Array.} + * @default [0, 0] + */ + this.position = [0, 0]; + } + + if (opts.rotation == null) { + /** + * 旋转 + * @type {Array.} + * @default 0 + */ + this.rotation = 0; + } + + if (!opts.scale) { + /** + * 缩放 + * @type {Array.} + * @default [1, 1] + */ + this.scale = [1, 1]; + } + /** + * 旋转和缩放的原点 + * @type {Array.} + * @default null + */ + + + this.origin = this.origin || null; +}; + +var transformableProto = Transformable.prototype; +transformableProto.transform = null; +/** + * 判断是否需要有坐标变换 + * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵 + */ + +transformableProto.needLocalTransform = function () { + return isNotAroundZero(this.rotation) || isNotAroundZero(this.position[0]) || isNotAroundZero(this.position[1]) || isNotAroundZero(this.scale[0] - 1) || isNotAroundZero(this.scale[1] - 1); +}; + +var scaleTmp = []; + +transformableProto.updateTransform = function () { + var parent = this.parent; + var parentHasTransform = parent && parent.transform; + var needLocalTransform = this.needLocalTransform(); + var m = this.transform; + + if (!(needLocalTransform || parentHasTransform)) { + m && mIdentity(m); + return; + } + + m = m || create$1(); + + if (needLocalTransform) { + this.getLocalTransform(m); + } else { + mIdentity(m); + } // 应用父节点变换 + + + if (parentHasTransform) { + if (needLocalTransform) { + mul$1(m, parent.transform, m); + } else { + copy$1(m, parent.transform); + } + } // 保存这个变换矩阵 + + + this.transform = 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); +}; + +transformableProto.getLocalTransform = function (m) { + return Transformable.getLocalTransform(this, m); +}; +/** + * 将自己的transform应用到context上 + * @param {CanvasRenderingContext2D} ctx + */ + + +transformableProto.setTransform = function (ctx) { + var m = this.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); + } +}; + +transformableProto.restoreTransform = function (ctx) { + var dpr = ctx.dpr || 1; + ctx.setTransform(dpr, 0, 0, dpr, 0, 0); +}; + +var tmpTransform = []; +var originTransform = create$1(); + +transformableProto.setLocalTransform = function (m) { + if (!m) { + // TODO return or set identity? + return; + } + + var sx = m[0] * m[0] + m[1] * m[1]; + var sy = m[2] * m[2] + m[3] * m[3]; + var position = this.position; + var scale$$1 = this.scale; + + if (isNotAroundZero(sx - 1)) { + sx = Math.sqrt(sx); + } + + if (isNotAroundZero(sy - 1)) { + sy = Math.sqrt(sy); + } + + if (m[0] < 0) { + sx = -sx; + } + + if (m[3] < 0) { + sy = -sy; + } + + position[0] = m[4]; + position[1] = m[5]; + scale$$1[0] = sx; + scale$$1[1] = sy; + this.rotation = Math.atan2(-m[1] / sy, m[0] / sx); +}; +/** + * 分解`transform`矩阵到`position`, `rotation`, `scale` + */ + + +transformableProto.decomposeTransform = function () { + if (!this.transform) { + return; + } + + var parent = this.parent; + var m = this.transform; + + if (parent && parent.transform) { + // Get local transform and decompose them to position, scale, rotation + mul$1(tmpTransform, parent.invTransform, m); + m = tmpTransform; + } + + var origin = this.origin; + + if (origin && (origin[0] || origin[1])) { + originTransform[4] = origin[0]; + originTransform[5] = origin[1]; + mul$1(tmpTransform, m, originTransform); + tmpTransform[4] -= origin[0]; + tmpTransform[5] -= origin[1]; + m = tmpTransform; + } + + this.setLocalTransform(m); +}; +/** + * Get global scale + * @return {Array.} + */ + + +transformableProto.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; +}; +/** + * 变换坐标位置到 shape 的局部坐标空间 + * @method + * @param {number} x + * @param {number} y + * @return {Array.} + */ + + +transformableProto.transformCoordToLocal = function (x, y) { + var v2 = [x, y]; + var invTransform = this.invTransform; + + if (invTransform) { + applyTransform(v2, v2, invTransform); + } + + return v2; +}; +/** + * 变换局部坐标位置到全局坐标空间 + * @method + * @param {number} x + * @param {number} y + * @return {Array.} + */ + + +transformableProto.transformCoordToGlobal = function (x, y) { + var v2 = [x, y]; + var transform = this.transform; + + if (transform) { + applyTransform(v2, v2, transform); + } + + return v2; +}; +/** + * @static + * @param {Object} target + * @param {Array.} target.origin + * @param {number} target.rotation + * @param {Array.} target.position + * @param {Array.} [m] + */ + + +Transformable.getLocalTransform = function (target, m) { + m = m || []; + mIdentity(m); + var origin = target.origin; + var scale$$1 = target.scale || [1, 1]; + var rotation = target.rotation || 0; + var position = target.position || [0, 0]; + + if (origin) { + // Translate to origin + m[4] -= origin[0]; + m[5] -= origin[1]; + } + + scale$1(m, m, scale$$1); + + if (rotation) { + rotate(m, m, rotation); + } + + if (origin) { + // Translate back from origin + m[4] += origin[0]; + m[5] += origin[1]; + } + + m[4] += position[0]; + m[5] += position[1]; + return m; +}; + +/** + * 缓动代码来自 https://github.com/sole/tween.js/blob/master/src/Tween.js + * @see http://sole.github.io/tween.js/examples/03_graphs.html + * @exports zrender/animation/easing + */ +var easing = { + /** + * @param {number} k + * @return {number} + */ + linear: function (k) { + return k; + }, + + /** + * @param {number} k + * @return {number} + */ + quadraticIn: function (k) { + return k * k; + }, + + /** + * @param {number} k + * @return {number} + */ + quadraticOut: function (k) { + return k * (2 - k); + }, + + /** + * @param {number} k + * @return {number} + */ + quadraticInOut: function (k) { + if ((k *= 2) < 1) { + return 0.5 * k * k; + } + + return -0.5 * (--k * (k - 2) - 1); + }, + // 三次方的缓动(t^3) + + /** + * @param {number} k + * @return {number} + */ + cubicIn: function (k) { + return k * k * k; + }, + + /** + * @param {number} k + * @return {number} + */ + cubicOut: function (k) { + return --k * k * k + 1; + }, + + /** + * @param {number} k + * @return {number} + */ + cubicInOut: function (k) { + if ((k *= 2) < 1) { + return 0.5 * k * k * k; + } + + return 0.5 * ((k -= 2) * k * k + 2); + }, + // 四次方的缓动(t^4) + + /** + * @param {number} k + * @return {number} + */ + quarticIn: function (k) { + return k * k * k * k; + }, + + /** + * @param {number} k + * @return {number} + */ + quarticOut: function (k) { + return 1 - --k * k * k * k; + }, + + /** + * @param {number} k + * @return {number} + */ + quarticInOut: function (k) { + if ((k *= 2) < 1) { + return 0.5 * k * k * k * k; + } + + return -0.5 * ((k -= 2) * k * k * k - 2); + }, + // 五次方的缓动(t^5) + + /** + * @param {number} k + * @return {number} + */ + quinticIn: function (k) { + return k * k * k * k * k; + }, + + /** + * @param {number} k + * @return {number} + */ + quinticOut: function (k) { + return --k * k * k * k * k + 1; + }, + + /** + * @param {number} k + * @return {number} + */ + 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); + }, + // 正弦曲线的缓动(sin(t)) + + /** + * @param {number} k + * @return {number} + */ + sinusoidalIn: function (k) { + return 1 - Math.cos(k * Math.PI / 2); + }, + + /** + * @param {number} k + * @return {number} + */ + sinusoidalOut: function (k) { + return Math.sin(k * Math.PI / 2); + }, + + /** + * @param {number} k + * @return {number} + */ + sinusoidalInOut: function (k) { + return 0.5 * (1 - Math.cos(Math.PI * k)); + }, + // 指数曲线的缓动(2^t) + + /** + * @param {number} k + * @return {number} + */ + exponentialIn: function (k) { + return k === 0 ? 0 : Math.pow(1024, k - 1); + }, + + /** + * @param {number} k + * @return {number} + */ + exponentialOut: function (k) { + return k === 1 ? 1 : 1 - Math.pow(2, -10 * k); + }, + + /** + * @param {number} k + * @return {number} + */ + 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); + }, + // 圆形曲线的缓动(sqrt(1-t^2)) + + /** + * @param {number} k + * @return {number} + */ + circularIn: function (k) { + return 1 - Math.sqrt(1 - k * k); + }, + + /** + * @param {number} k + * @return {number} + */ + circularOut: function (k) { + return Math.sqrt(1 - --k * k); + }, + + /** + * @param {number} k + * @return {number} + */ + 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); + }, + // 创建类似于弹簧在停止前来回振荡的动画 + + /** + * @param {number} k + * @return {number} + */ + 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)); + }, + + /** + * @param {number} k + * @return {number} + */ + 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; + }, + + /** + * @param {number} k + * @return {number} + */ + 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; + }, + // 在某一动画开始沿指示的路径进行动画处理前稍稍收回该动画的移动 + + /** + * @param {number} k + * @return {number} + */ + backIn: function (k) { + var s = 1.70158; + return k * k * ((s + 1) * k - s); + }, + + /** + * @param {number} k + * @return {number} + */ + backOut: function (k) { + var s = 1.70158; + return --k * k * ((s + 1) * k + s) + 1; + }, + + /** + * @param {number} k + * @return {number} + */ + 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); + }, + // 创建弹跳效果 + + /** + * @param {number} k + * @return {number} + */ + bounceIn: function (k) { + return 1 - easing.bounceOut(1 - k); + }, + + /** + * @param {number} k + * @return {number} + */ + 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; + } + }, + + /** + * @param {number} k + * @return {number} + */ + bounceInOut: function (k) { + if (k < 0.5) { + return easing.bounceIn(k * 2) * 0.5; + } + + return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5; + } +}; + +/** + * 动画主控制器 + * @config target 动画对象,可以是数组,如果是数组的话会批量分发onframe等事件 + * @config life(1000) 动画时长 + * @config delay(0) 动画延迟时间 + * @config loop(true) + * @config gap(0) 循环的间隔时间 + * @config onframe + * @config easing(optional) + * @config ondestroy(optional) + * @config onrestart(optional) + * + * TODO pause + */ +function Clip(options) { + this._target = options.target; // 生命周期 + + this._life = options.life || 1000; // 延时 + + this._delay = options.delay || 0; // 开始时间 + // this._startTime = new Date().getTime() + this._delay;// 单位毫秒 + + this._initialized = false; // 是否循环 + + this.loop = options.loop == null ? false : options.loop; + this.gap = options.gap || 0; + this.easing = options.easing || 'Linear'; + this.onframe = options.onframe; + this.ondestroy = options.ondestroy; + this.onrestart = options.onrestart; + this._pausedTime = 0; + this._paused = false; +} + +Clip.prototype = { + constructor: Clip, + step: function (globalTime, deltaTime) { + // Set startTime on first step, or _startTime may has milleseconds different between clips + // PENDING + if (!this._initialized) { + this._startTime = globalTime + this._delay; + this._initialized = true; + } + + if (this._paused) { + this._pausedTime += deltaTime; + return; + } + + var percent = (globalTime - this._startTime - this._pausedTime) / this._life; // 还没开始 + + if (percent < 0) { + return; + } + + percent = Math.min(percent, 1); + var easing$$1 = this.easing; + var easingFunc = typeof easing$$1 === 'string' ? easing[easing$$1] : easing$$1; + var schedule = typeof easingFunc === 'function' ? easingFunc(percent) : percent; + this.fire('frame', schedule); // 结束 + + if (percent === 1) { + if (this.loop) { + this.restart(globalTime); // 重新开始周期 + // 抛出而不是直接调用事件直到 stage.update 后再统一调用这些事件 + + return 'restart'; + } // 动画完成将这个控制器标识为待删除 + // 在Animation.update中进行批量删除 + + + this._needsRemove = true; + return 'destroy'; + } + + return null; + }, + restart: function (globalTime) { + var remainder = (globalTime - this._startTime - this._pausedTime) % this._life; + this._startTime = globalTime - remainder + this.gap; + this._pausedTime = 0; + this._needsRemove = false; + }, + fire: function (eventType, arg) { + eventType = 'on' + eventType; + + if (this[eventType]) { + this[eventType](this._target, arg); + } + }, + pause: function () { + this._paused = true; + }, + resume: function () { + this._paused = false; + } +}; + +// Simple LRU cache use doubly linked list +// @module zrender/core/LRU + +/** + * Simple double linked list. Compared with array, it has O(1) remove operation. + * @constructor + */ +var LinkedList = function () { + /** + * @type {module:zrender/core/LRU~Entry} + */ + this.head = null; + /** + * @type {module:zrender/core/LRU~Entry} + */ + + this.tail = null; + this._len = 0; +}; + +var linkedListProto = LinkedList.prototype; +/** + * Insert a new value at the tail + * @param {} val + * @return {module:zrender/core/LRU~Entry} + */ + +linkedListProto.insert = function (val) { + var entry = new Entry(val); + this.insertEntry(entry); + return entry; +}; +/** + * Insert an entry at the tail + * @param {module:zrender/core/LRU~Entry} entry + */ + + +linkedListProto.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++; +}; +/** + * Remove entry. + * @param {module:zrender/core/LRU~Entry} entry + */ + + +linkedListProto.remove = function (entry) { + var prev = entry.prev; + var next = entry.next; + + if (prev) { + prev.next = next; + } else { + // Is head + this.head = next; + } + + if (next) { + next.prev = prev; + } else { + // Is tail + this.tail = prev; + } + + entry.next = entry.prev = null; + this._len--; +}; +/** + * @return {number} + */ + + +linkedListProto.len = function () { + return this._len; +}; +/** + * Clear list + */ + + +linkedListProto.clear = function () { + this.head = this.tail = null; + this._len = 0; +}; +/** + * @constructor + * @param {} val + */ + + +var Entry = function (val) { + /** + * @type {} + */ + this.value = val; + /** + * @type {module:zrender/core/LRU~Entry} + */ + + this.next; + /** + * @type {module:zrender/core/LRU~Entry} + */ + + this.prev; +}; +/** + * LRU Cache + * @constructor + * @alias module:zrender/core/LRU + */ + + +var LRU = function (maxSize) { + this._list = new LinkedList(); + this._map = {}; + this._maxSize = maxSize || 10; + this._lastRemovedEntry = null; +}; + +var LRUProto = LRU.prototype; +/** + * @param {string} key + * @param {} value + * @return {} Removed value + */ + +LRUProto.put = function (key, value) { + var list = this._list; + var map = this._map; + var removed = null; + + if (map[key] == null) { + var len = list.len(); // Reuse last removed entry + + var entry = this._lastRemovedEntry; + + if (len >= this._maxSize && len > 0) { + // Remove the least recently used + 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; +}; +/** + * @param {string} key + * @return {} + */ + + +LRUProto.get = function (key) { + var entry = this._map[key]; + var list = this._list; + + if (entry != null) { + // Put the latest used entry in the tail + if (entry !== list.tail) { + list.remove(entry); + list.insertEntry(entry); + } + + return entry.value; + } +}; +/** + * Clear the cache + */ + + +LRUProto.clear = function () { + this._list.clear(); + + this._map = {}; +}; + +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) { + // Clamp to integer 0 .. 255. + i = Math.round(i); // Seems to be what Chrome does (vs truncation). + + return i < 0 ? 0 : i > 255 ? 255 : i; +} + +function clampCssAngle(i) { + // Clamp to integer 0 .. 360. + i = Math.round(i); // Seems to be what Chrome does (vs truncation). + + return i < 0 ? 0 : i > 360 ? 360 : i; +} + +function clampCssFloat(f) { + // Clamp to float 0.0 .. 1.0. + return f < 0 ? 0 : f > 1 ? 1 : f; +} + +function parseCssInt(str) { + // int or percentage. + if (str.length && str.charAt(str.length - 1) === '%') { + return clampCssByte(parseFloat(str) / 100 * 255); + } + + return clampCssByte(parseInt(str, 10)); +} + +function parseCssFloat(str) { + // float or percentage. + 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) { + // Reuse removed array + if (lastRemovedArr) { + copyRgba(lastRemovedArr, rgbaArr); + } + + lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || rgbaArr.slice()); +} +/** + * @param {string} colorStr + * @param {Array.} out + * @return {Array.} + * @memberOf module:zrender/util/color + */ + + +function parse(colorStr, rgbaArr) { + if (!colorStr) { + return; + } + + rgbaArr = rgbaArr || []; + var cached = colorCache.get(colorStr); + + if (cached) { + return copyRgba(rgbaArr, cached); + } // colorStr may be not string + + + colorStr = colorStr + ''; // Remove all whitespace, not compliant, but should just be more accepting. + + var str = colorStr.replace(/ /g, '').toLowerCase(); // Color keywords (and transparent) lookup. + + if (str in kCSSColorTable) { + copyRgba(rgbaArr, kCSSColorTable[str]); + putToCache(colorStr, rgbaArr); + return rgbaArr; + } // #abc and #abc123 syntax. + + + if (str.charAt(0) === '#') { + if (str.length === 4) { + var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. + + if (!(iv >= 0 && iv <= 0xfff)) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; // Covers NaN. + } + + setRgba(rgbaArr, (iv & 0xf00) >> 4 | (iv & 0xf00) >> 8, iv & 0xf0 | (iv & 0xf0) >> 4, iv & 0xf | (iv & 0xf) << 4, 1); + putToCache(colorStr, rgbaArr); + return rgbaArr; + } else if (str.length === 7) { + var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. + + if (!(iv >= 0 && iv <= 0xffffff)) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; // Covers NaN. + } + + setRgba(rgbaArr, (iv & 0xff0000) >> 16, (iv & 0xff00) >> 8, iv & 0xff, 1); + putToCache(colorStr, rgbaArr); + return rgbaArr; + } + + return; + } + + var op = str.indexOf('('); + var ep = str.indexOf(')'); + + if (op !== -1 && ep + 1 === str.length) { + var fname = str.substr(0, op); + var params = str.substr(op + 1, ep - (op + 1)).split(','); + var alpha = 1; // To allow case fallthrough. + + switch (fname) { + case 'rgba': + if (params.length !== 4) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + + alpha = parseCssFloat(params.pop()); + // jshint ignore:line + // Fall through. + + 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; +} +/** + * @param {Array.} hsla + * @param {Array.} rgba + * @return {Array.} rgba + */ + +function hsla2rgba(hsla, rgba) { + var h = (parseFloat(hsla[0]) % 360 + 360) % 360 / 360; // 0 .. 1 + // NOTE(deanm): According to the CSS spec s/l should only be + // percentages, but we don't bother and let float or percentage. + + 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; +} +/** + * @param {Array.} rgba + * @return {Array.} hsla + */ + + +function rgba2hsla(rgba) { + if (!rgba) { + return; + } // RGB from 0 to 255 + + + var R = rgba[0] / 255; + var G = rgba[1] / 255; + var B = rgba[2] / 255; + var vMin = Math.min(R, G, B); // Min. value of RGB + + var vMax = Math.max(R, G, B); // Max. value of RGB + + var delta = vMax - vMin; // Delta RGB value + + var L = (vMax + vMin) / 2; + var H; + var S; // HSL results from 0 to 1 + + 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; +} +/** + * @param {string} color + * @param {number} level + * @return {string} + * @memberOf module:zrender/util/color + */ + + +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 (color[i] < 0) { + colorArr[i] = 0; + } + } + + return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb'); + } +} +/** + * @param {string} color + * @return {string} + * @memberOf module:zrender/util/color + */ + +function toHex(color) { + var colorArr = parse(color); + + if (colorArr) { + return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + +colorArr[2]).toString(16).slice(1); + } +} +/** + * Map value to color. Faster than lerp methods because color is represented by rgba array. + * @param {number} normalizedValue A float between 0 and 1. + * @param {Array.>} colors List of rgba color array + * @param {Array.} [out] Mapped gba color array + * @return {Array.} will be null/undefined if input illegal. + */ + +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; +} +/** + * @deprecated + */ + +var fastMapToColor = fastLerp; +/** + * @param {number} normalizedValue A float between 0 and 1. + * @param {Array.} colors Color list. + * @param {boolean=} fullOutput Default false. + * @return {(string|Object)} Result color. If fullOutput, + * return {color: ..., leftIndex: ..., rightIndex: ..., value: ...}, + * @memberOf module:zrender/util/color + */ + +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; +} +/** + * @deprecated + */ + +var mapToColor = lerp$1; +/** + * @param {string} color + * @param {number=} h 0 ~ 360, ignore when null. + * @param {number=} s 0 ~ 1, ignore when null. + * @param {number=} l 0 ~ 1, ignore when null. + * @return {string} Color string in rgba format. + * @memberOf module:zrender/util/color + */ + +function modifyHSL(color, h, s, l) { + color = parse(color); + + if (color) { + color = rgba2hsla(color); + h != null && (color[0] = clampCssAngle(h)); + s != null && (color[1] = parseCssFloat(s)); + l != null && (color[2] = parseCssFloat(l)); + return stringify(hsla2rgba(color), 'rgba'); + } +} +/** + * @param {string} color + * @param {number=} alpha 0 ~ 1 + * @return {string} Color string in rgba format. + * @memberOf module:zrender/util/color + */ + +function modifyAlpha(color, alpha) { + color = parse(color); + + if (color && alpha != null) { + color[3] = clampCssFloat(alpha); + return stringify(color, 'rgba'); + } +} +/** + * @param {Array.} arrColor like [12,33,44,0.4] + * @param {string} type 'rgba', 'hsva', ... + * @return {string} Result color. (If input illegal, return undefined). + */ + +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 + ')'; +} + +var color = (Object.freeze || Object)({ + parse: parse, + lift: lift, + toHex: toHex, + fastLerp: fastLerp, + fastMapToColor: fastMapToColor, + lerp: lerp$1, + mapToColor: mapToColor, + modifyHSL: modifyHSL, + modifyAlpha: modifyAlpha, + stringify: stringify +}); + +/** + * @module echarts/animation/Animator + */ +var arraySlice = Array.prototype.slice; + +function defaultGetter(target, key) { + return target[key]; +} + +function defaultSetter(target, key, value) { + target[key] = value; +} +/** + * @param {number} p0 + * @param {number} p1 + * @param {number} percent + * @return {number} + */ + + +function interpolateNumber(p0, p1, percent) { + return (p1 - p0) * percent + p0; +} +/** + * @param {string} p0 + * @param {string} p1 + * @param {number} percent + * @return {string} + */ + + +function interpolateString(p0, p1, percent) { + return percent > 0.5 ? p1 : p0; +} +/** + * @param {Array} p0 + * @param {Array} p1 + * @param {number} percent + * @param {Array} out + * @param {number} arrDim + */ + + +function interpolateArray(p0, p1, percent, out, arrDim) { + var len = p0.length; + + if (arrDim === 1) { + for (var i = 0; i < len; i++) { + out[i] = interpolateNumber(p0[i], p1[i], percent); + } + } else { + var len2 = len && p0[0].length; + + for (var i = 0; i < len; i++) { + for (var j = 0; j < len2; j++) { + out[i][j] = interpolateNumber(p0[i][j], p1[i][j], percent); + } + } + } +} // arr0 is source array, arr1 is target array. +// Do some preprocess to avoid error happened when interpolating from arr0 to arr1 + + +function fillArr(arr0, arr1, arrDim) { + var arr0Len = arr0.length; + var arr1Len = arr1.length; + + if (arr0Len !== arr1Len) { + // FIXME Not work for TypedArray + var isPreviousLarger = arr0Len > arr1Len; + + if (isPreviousLarger) { + // Cut the previous + arr0.length = arr1Len; + } else { + // Fill the previous + for (var i = arr0Len; i < arr1Len; i++) { + arr0.push(arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])); + } + } + } // Handling NaN value + + + 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]; + } + } + } + } +} +/** + * @param {Array} arr0 + * @param {Array} arr1 + * @param {number} arrDim + * @return {boolean} + */ + + +function isArraySame(arr0, arr1, arrDim) { + if (arr0 === arr1) { + return true; + } + + var len = arr0.length; + + if (len !== arr1.length) { + return false; + } + + if (arrDim === 1) { + for (var i = 0; i < len; i++) { + if (arr0[i] !== arr1[i]) { + return false; + } + } + } else { + var len2 = arr0[0].length; + + for (var i = 0; i < len; i++) { + for (var j = 0; j < len2; j++) { + if (arr0[i][j] !== arr1[i][j]) { + return false; + } + } + } + } + + return true; +} +/** + * Catmull Rom interpolate array + * @param {Array} p0 + * @param {Array} p1 + * @param {Array} p2 + * @param {Array} p3 + * @param {number} t + * @param {number} t2 + * @param {number} t3 + * @param {Array} out + * @param {number} arrDim + */ + + +function catmullRomInterpolateArray(p0, p1, p2, p3, t, t2, t3, out, arrDim) { + var len = p0.length; + + if (arrDim === 1) { + for (var i = 0; i < len; i++) { + out[i] = catmullRomInterpolate(p0[i], p1[i], p2[i], p3[i], t, t2, t3); + } + } else { + var len2 = p0[0].length; + + for (var i = 0; i < len; i++) { + for (var j = 0; j < len2; j++) { + out[i][j] = catmullRomInterpolate(p0[i][j], p1[i][j], p2[i][j], p3[i][j], t, t2, t3); + } + } + } +} +/** + * Catmull Rom interpolate number + * @param {number} p0 + * @param {number} p1 + * @param {number} p2 + * @param {number} p3 + * @param {number} t + * @param {number} t2 + * @param {number} t3 + * @return {number} + */ + + +function catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) { + var v0 = (p2 - p0) * 0.5; + var v1 = (p3 - p1) * 0.5; + return (2 * (p1 - p2) + v0 + v1) * t3 + (-3 * (p1 - p2) - 2 * v0 - v1) * t2 + v0 * t + p1; +} + +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]); + rgba[1] = Math.floor(rgba[1]); + rgba[2] = Math.floor(rgba[2]); + return 'rgba(' + rgba.join(',') + ')'; +} + +function getArrayDim(keyframes) { + var lastValue = keyframes[keyframes.length - 1].value; + return isArrayLike(lastValue && lastValue[0]) ? 2 : 1; +} + +function createTrackClip(animator, easing, oneTrackDone, keyframes, propName, forceAnimate) { + var getter = animator._getter; + var setter = animator._setter; + var useSpline = easing === 'spline'; + var trackLen = keyframes.length; + + if (!trackLen) { + return; + } // Guess data type + + + var firstVal = keyframes[0].value; + var isValueArray = isArrayLike(firstVal); + var isValueColor = false; + var isValueString = false; // For vertices morphing + + var arrDim = isValueArray ? getArrayDim(keyframes) : 0; + var trackMaxTime; // Sort keyframe as ascending + + keyframes.sort(function (a, b) { + return a.time - b.time; + }); + trackMaxTime = keyframes[trackLen - 1].time; // Percents of each keyframe + + var kfPercents = []; // Value of each keyframe + + var kfValues = []; + var prevValue = keyframes[0].value; + var isAllValueEqual = true; + + for (var i = 0; i < trackLen; i++) { + kfPercents.push(keyframes[i].time / trackMaxTime); // Assume value is a color when it is a string + + var value = keyframes[i].value; // Check if value is equal, deep check if value is array + + if (!(isValueArray && isArraySame(value, prevValue, arrDim) || !isValueArray && value === prevValue)) { + isAllValueEqual = false; + } + + prevValue = value; // Try converting a string to a color array + + if (typeof value === 'string') { + var colorArray = parse(value); + + if (colorArray) { + value = colorArray; + isValueColor = true; + } else { + isValueString = true; + } + } + + kfValues.push(value); + } + + if (!forceAnimate && isAllValueEqual) { + return; + } + + var lastValue = kfValues[trackLen - 1]; // Polyfill array and NaN value + + for (var i = 0; i < trackLen - 1; i++) { + if (isValueArray) { + fillArr(kfValues[i], lastValue, arrDim); + } else { + if (isNaN(kfValues[i]) && !isNaN(lastValue) && !isValueString && !isValueColor) { + kfValues[i] = lastValue; + } + } + } + + isValueArray && fillArr(getter(animator._target, propName), lastValue, arrDim); // Cache the key of last frame to speed up when + // animation playback is sequency + + var lastFrame = 0; + var lastFramePercent = 0; + var start; + var w; + var p0; + var p1; + var p2; + var p3; + + if (isValueColor) { + var rgba = [0, 0, 0, 0]; + } + + var onframe = function (target, percent) { + // Find the range keyframes + // kf1-----kf2---------current--------kf3 + // find kf2 and kf3 and do interpolation + var frame; // In the easing function like elasticOut, percent may less than 0 + + if (percent < 0) { + frame = 0; + } else if (percent < lastFramePercent) { + // Start from next key + // PENDING start from lastFrame ? + start = Math.min(lastFrame + 1, trackLen - 1); + + for (frame = start; frame >= 0; frame--) { + if (kfPercents[frame] <= percent) { + break; + } + } // PENDING really need to do this ? + + + frame = Math.min(frame, trackLen - 2); + } else { + for (frame = lastFrame; frame < trackLen; frame++) { + if (kfPercents[frame] > percent) { + break; + } + } + + frame = Math.min(frame - 1, trackLen - 2); + } + + lastFrame = frame; + lastFramePercent = percent; + var range = kfPercents[frame + 1] - kfPercents[frame]; + + if (range === 0) { + return; + } else { + w = (percent - kfPercents[frame]) / range; + } + + if (useSpline) { + p1 = kfValues[frame]; + p0 = kfValues[frame === 0 ? frame : frame - 1]; + p2 = kfValues[frame > trackLen - 2 ? trackLen - 1 : frame + 1]; + p3 = kfValues[frame > trackLen - 3 ? trackLen - 1 : frame + 2]; + + if (isValueArray) { + catmullRomInterpolateArray(p0, p1, p2, p3, w, w * w, w * w * w, getter(target, propName), arrDim); + } else { + var value; + + if (isValueColor) { + value = catmullRomInterpolateArray(p0, p1, p2, p3, w, w * w, w * w * w, rgba, 1); + value = rgba2String(rgba); + } else if (isValueString) { + // String is step(0.5) + return interpolateString(p1, p2, w); + } else { + value = catmullRomInterpolate(p0, p1, p2, p3, w, w * w, w * w * w); + } + + setter(target, propName, value); + } + } else { + if (isValueArray) { + interpolateArray(kfValues[frame], kfValues[frame + 1], w, getter(target, propName), arrDim); + } else { + var value; + + if (isValueColor) { + interpolateArray(kfValues[frame], kfValues[frame + 1], w, rgba, 1); + value = rgba2String(rgba); + } else if (isValueString) { + // String is step(0.5) + return interpolateString(kfValues[frame], kfValues[frame + 1], w); + } else { + value = interpolateNumber(kfValues[frame], kfValues[frame + 1], w); + } + + setter(target, propName, value); + } + } + }; + + var clip = new Clip({ + target: animator._target, + life: trackMaxTime, + loop: animator._loop, + delay: animator._delay, + onframe: onframe, + ondestroy: oneTrackDone + }); + + if (easing && easing !== 'spline') { + clip.easing = easing; + } + + return clip; +} +/** + * @alias module:zrender/animation/Animator + * @constructor + * @param {Object} target + * @param {boolean} loop + * @param {Function} getter + * @param {Function} setter + */ + + +var Animator = function (target, loop, getter, setter) { + this._tracks = {}; + this._target = target; + this._loop = loop || false; + this._getter = getter || defaultGetter; + this._setter = setter || defaultSetter; + this._clipCount = 0; + this._delay = 0; + this._doneList = []; + this._onframeList = []; + this._clipList = []; +}; + +Animator.prototype = { + /** + * 设置动画关键帧 + * @param {number} time 关键帧时间,单位是ms + * @param {Object} props 关键帧的属性值,key-value表示 + * @return {module:zrender/animation/Animator} + */ + when: function (time + /* ms */ + , props) { + var tracks = this._tracks; + + for (var propName in props) { + if (!props.hasOwnProperty(propName)) { + continue; + } + + if (!tracks[propName]) { + tracks[propName] = []; // Invalid value + + var value = this._getter(this._target, propName); + + if (value == null) { + // zrLog('Invalid property ' + propName); + continue; + } // If time is 0 + // Then props is given initialize value + // Else + // Initialize value from current prop value + + + if (time !== 0) { + tracks[propName].push({ + time: 0, + value: cloneValue(value) + }); + } + } + + tracks[propName].push({ + time: time, + value: props[propName] + }); + } + + return this; + }, + + /** + * 添加动画每一帧的回调函数 + * @param {Function} callback + * @return {module:zrender/animation/Animator} + */ + during: function (callback) { + this._onframeList.push(callback); + + return this; + }, + pause: function () { + for (var i = 0; i < this._clipList.length; i++) { + this._clipList[i].pause(); + } + + this._paused = true; + }, + resume: function () { + for (var i = 0; i < this._clipList.length; i++) { + this._clipList[i].resume(); + } + + this._paused = false; + }, + isPaused: function () { + return !!this._paused; + }, + _doneCallback: function () { + // Clear all tracks + this._tracks = {}; // Clear all clips + + this._clipList.length = 0; + var doneList = this._doneList; + var len = doneList.length; + + for (var i = 0; i < len; i++) { + doneList[i].call(this); + } + }, + + /** + * 开始执行动画 + * @param {string|Function} [easing] + * 动画缓动函数,详见{@link module:zrender/animation/easing} + * @param {boolean} forceAnimate + * @return {module:zrender/animation/Animator} + */ + start: function (easing, forceAnimate) { + var self = this; + var clipCount = 0; + + var oneTrackDone = function () { + clipCount--; + + if (!clipCount) { + self._doneCallback(); + } + }; + + var lastClip; + + for (var propName in this._tracks) { + if (!this._tracks.hasOwnProperty(propName)) { + continue; + } + + var clip = createTrackClip(this, easing, oneTrackDone, this._tracks[propName], propName, forceAnimate); + + if (clip) { + this._clipList.push(clip); + + clipCount++; // If start after added to animation + + if (this.animation) { + this.animation.addClip(clip); + } + + lastClip = clip; + } + } // Add during callback on the last clip + + + if (lastClip) { + var oldOnFrame = lastClip.onframe; + + lastClip.onframe = function (target, percent) { + oldOnFrame(target, percent); + + for (var i = 0; i < self._onframeList.length; i++) { + self._onframeList[i](target, percent); + } + }; + } // This optimization will help the case that in the upper application + // the view may be refreshed frequently, where animation will be + // called repeatly but nothing changed. + + + if (!clipCount) { + this._doneCallback(); + } + + return this; + }, + + /** + * 停止动画 + * @param {boolean} forwardToLast If move to last frame before stop + */ + stop: function (forwardToLast) { + var clipList = this._clipList; + var animation = this.animation; + + for (var i = 0; i < clipList.length; i++) { + var clip = clipList[i]; + + if (forwardToLast) { + // Move to last frame before stop + clip.onframe(this._target, 1); + } + + animation && animation.removeClip(clip); + } + + clipList.length = 0; + }, + + /** + * 设置动画延迟开始的时间 + * @param {number} time 单位ms + * @return {module:zrender/animation/Animator} + */ + delay: function (time) { + this._delay = time; + return this; + }, + + /** + * 添加动画结束的回调 + * @param {Function} cb + * @return {module:zrender/animation/Animator} + */ + done: function (cb) { + if (cb) { + this._doneList.push(cb); + } + + return this; + }, + + /** + * @return {Array.} + */ + getClips: function () { + return this._clipList; + } +}; + +var dpr = 1; // If in browser environment + +if (typeof window !== 'undefined') { + dpr = Math.max(window.devicePixelRatio || 1, 1); +} +/** + * config默认配置项 + * @exports zrender/config + * @author Kener (@Kener-林峰, kener.linfeng@gmail.com) + */ + +/** + * Debug log mode: + * 0: Do nothing, for release. + * 1: console.error, for debug. + */ + + +var debugMode = 0; // retina 屏幕优化 + +var devicePixelRatio = dpr; + +var logError = function () {}; + +if (debugMode === 1) { + logError = console.error; +} + +var logError$1 = logError; + +/** + * @alias modue:zrender/mixin/Animatable + * @constructor + */ + +var Animatable = function () { + /** + * @type {Array.} + * @readOnly + */ + this.animators = []; +}; + +Animatable.prototype = { + constructor: Animatable, + + /** + * 动画 + * + * @param {string} path The path to fetch value from object, like 'a.b.c'. + * @param {boolean} [loop] Whether to loop animation. + * @return {module:zrender/animation/Animator} + * @example: + * el.animate('style', false) + * .when(1000, {x: 10} ) + * .done(function(){ // Animation done }) + * .start() + */ + animate: function (path, loop) { + var target; + var animatingShape = false; + var el = this; + var zr = this.__zr; + + if (path) { + var pathSplitted = path.split('.'); + var prop = el; // If animating shape + + animatingShape = pathSplitted[0] === 'shape'; + + for (var i = 0, l = pathSplitted.length; i < l; i++) { + if (!prop) { + continue; + } + + prop = prop[pathSplitted[i]]; + } + + if (prop) { + target = prop; + } + } else { + target = el; + } + + if (!target) { + logError$1('Property "' + path + '" is not existed in element ' + el.id); + return; + } + + var animators = el.animators; + var animator = new Animator(target, loop); + animator.during(function (target) { + el.dirty(animatingShape); + }).done(function () { + // FIXME Animator will not be removed if use `Animator#stop` to stop animation + animators.splice(indexOf(animators, animator), 1); + }); + animators.push(animator); // If animate after added to the zrender + + if (zr) { + zr.animation.addAnimator(animator); + } + + return animator; + }, + + /** + * 停止动画 + * @param {boolean} forwardToLast If move to last frame before stop + */ + stopAnimation: function (forwardToLast) { + var animators = this.animators; + var len = animators.length; + + for (var i = 0; i < len; i++) { + animators[i].stop(forwardToLast); + } + + animators.length = 0; + return this; + }, + + /** + * 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. + * @param {Object} target + * @param {number} [time=500] Time in ms + * @param {string} [easing='linear'] + * @param {number} [delay=0] + * @param {Function} [callback] + * @param {Function} [forceAnimate] Prevent stop animation and callback + * immediently when target values are the same as current values. + * + * @example + * // Animate position + * el.animateTo({ + * position: [10, 10] + * }, function () { // done }) + * + * // Animate shape, style and position in 100ms, delayed 100ms, with cubicOut easing + * el.animateTo({ + * shape: { + * width: 500 + * }, + * style: { + * fill: 'red' + * } + * position: [10, 10] + * }, 100, 100, 'cubicOut', function () { // done }) + */ + // TODO Return animation key + animateTo: function (target, time, delay, easing, callback, forceAnimate) { + animateTo(this, target, time, delay, easing, callback, forceAnimate); + }, + + /** + * Animate from the target state to current state. + * The params and the return value are the same as `this.animateTo`. + */ + animateFrom: function (target, time, delay, easing, callback, forceAnimate) { + animateTo(this, target, time, delay, easing, callback, forceAnimate, true); + } +}; + +function animateTo(animatable, target, time, delay, easing, callback, forceAnimate, reverse) { + // animateTo(target, time, easing, callback); + if (isString(delay)) { + callback = easing; + easing = delay; + delay = 0; + } // animateTo(target, time, delay, callback); + else if (isFunction$1(easing)) { + callback = easing; + easing = 'linear'; + delay = 0; + } // animateTo(target, time, callback); + else if (isFunction$1(delay)) { + callback = delay; + delay = 0; + } // animateTo(target, callback) + else if (isFunction$1(time)) { + callback = time; + time = 500; + } // animateTo(target) + else if (!time) { + time = 500; + } // Stop all previous animations + + + animatable.stopAnimation(); + animateToShallow(animatable, '', animatable, target, time, delay, reverse); // Animators may be removed immediately after start + // if there is nothing to animate + + var animators = animatable.animators.slice(); + var count = animators.length; + + function done() { + count--; + + if (!count) { + callback && callback(); + } + } // No animators. This should be checked before animators[i].start(), + // because 'done' may be executed immediately if no need to animate. + + + if (!count) { + callback && callback(); + } // Start after all animators created + // Incase any animator is done immediately when all animation properties are not changed + + + for (var i = 0; i < animators.length; i++) { + animators[i].done(done).start(easing, forceAnimate); + } +} +/** + * @param {string} path='' + * @param {Object} source=animatable + * @param {Object} target + * @param {number} [time=500] + * @param {number} [delay=0] + * @param {boolean} [reverse] If `true`, animate + * from the `target` to current state. + * + * @example + * // Animate position + * el._animateToShallow({ + * position: [10, 10] + * }) + * + * // Animate shape, style and position in 100ms, delayed 100ms + * el._animateToShallow({ + * shape: { + * width: 500 + * }, + * style: { + * fill: 'red' + * } + * position: [10, 10] + * }, 100, 100) + */ + + +function animateToShallow(animatable, path, source, target, time, delay, reverse) { + var objShallow = {}; + var propertyCount = 0; + + for (var name in target) { + if (!target.hasOwnProperty(name)) { + continue; + } + + if (source[name] != null) { + if (isObject$1(target[name]) && !isArrayLike(target[name])) { + animateToShallow(animatable, path ? path + '.' + name : name, source[name], target[name], time, delay, reverse); + } else { + if (reverse) { + objShallow[name] = source[name]; + setAttrByPath(animatable, path, name, target[name]); + } else { + objShallow[name] = target[name]; + } + + propertyCount++; + } + } else if (target[name] != null && !reverse) { + setAttrByPath(animatable, path, name, target[name]); + } + } + + if (propertyCount > 0) { + animatable.animate(path, false).when(time == null ? 500 : time, objShallow).delay(delay || 0); + } +} + +function setAttrByPath(el, path, name, value) { + // Attr directly if not has property + // FIXME, if some property not needed for element ? + if (!path) { + el.attr(name, value); + } else { + // Only support set shape or style + var props = {}; + props[path] = {}; + props[path][name] = value; + el.attr(props); + } +} + +/** + * @alias module:zrender/Element + * @constructor + * @extends {module:zrender/mixin/Animatable} + * @extends {module:zrender/mixin/Transformable} + * @extends {module:zrender/mixin/Eventful} + */ + +var Element = function (opts) { + // jshint ignore:line + Transformable.call(this, opts); + Eventful.call(this, opts); + Animatable.call(this, opts); + /** + * 画布元素ID + * @type {string} + */ + + this.id = opts.id || guid(); +}; + +Element.prototype = { + /** + * 元素类型 + * Element type + * @type {string} + */ + type: 'element', + + /** + * 元素名字 + * Element name + * @type {string} + */ + name: '', + + /** + * ZRender 实例对象,会在 element 添加到 zrender 实例中后自动赋值 + * ZRender instance will be assigned when element is associated with zrender + * @name module:/zrender/Element#__zr + * @type {module:zrender/ZRender} + */ + __zr: null, + + /** + * 图形是否忽略,为true时忽略图形的绘制以及事件触发 + * If ignore drawing and events of the element object + * @name module:/zrender/Element#ignore + * @type {boolean} + * @default false + */ + ignore: false, + + /** + * 用于裁剪的路径(shape),所有 Group 内的路径在绘制时都会被这个路径裁剪 + * 该路径会继承被裁减对象的变换 + * @type {module:zrender/graphic/Path} + * @see http://www.w3.org/TR/2dcontext/#clipping-region + * @readOnly + */ + clipPath: null, + + /** + * 是否是 Group + * @type {boolean} + */ + isGroup: false, + + /** + * Drift element + * @param {number} dx dx on the global space + * @param {number} dy dy on the global space + */ + drift: function (dx, dy) { + 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.dirty(false); + }, + + /** + * Hook before update + */ + beforeUpdate: function () {}, + + /** + * Hook after update + */ + afterUpdate: function () {}, + + /** + * Update each frame + */ + update: function () { + this.updateTransform(); + }, + + /** + * @param {Function} cb + * @param {} context + */ + traverse: function (cb, context) {}, + + /** + * @protected + */ + attrKV: function (key, value) { + if (key === 'position' || key === 'scale' || key === 'origin') { + // Copy the array + if (value) { + var target = this[key]; + + if (!target) { + target = this[key] = []; + } + + target[0] = value[0]; + target[1] = value[1]; + } + } else { + this[key] = value; + } + }, + + /** + * Hide the element + */ + hide: function () { + this.ignore = true; + this.__zr && this.__zr.refresh(); + }, + + /** + * Show the element + */ + show: function () { + this.ignore = false; + this.__zr && this.__zr.refresh(); + }, + + /** + * @param {string|Object} key + * @param {*} value + */ + attr: function (key, value) { + if (typeof key === 'string') { + this.attrKV(key, value); + } else if (isObject$1(key)) { + for (var name in key) { + if (key.hasOwnProperty(name)) { + this.attrKV(name, key[name]); + } + } + } + + this.dirty(false); + return this; + }, + + /** + * @param {module:zrender/graphic/Path} clipPath + */ + setClipPath: function (clipPath) { + var zr = this.__zr; + + if (zr) { + clipPath.addSelfToZr(zr); + } // Remove previous clip path + + + if (this.clipPath && this.clipPath !== clipPath) { + this.removeClipPath(); + } + + this.clipPath = clipPath; + clipPath.__zr = zr; + clipPath.__clipTarget = this; + this.dirty(false); + }, + + /** + */ + removeClipPath: function () { + var clipPath = this.clipPath; + + if (clipPath) { + if (clipPath.__zr) { + clipPath.removeSelfFromZr(clipPath.__zr); + } + + clipPath.__zr = null; + clipPath.__clipTarget = null; + this.clipPath = null; + this.dirty(false); + } + }, + + /** + * Add self from zrender instance. + * Not recursively because it will be invoked when element added to storage. + * @param {module:zrender/ZRender} zr + */ + addSelfToZr: function (zr) { + 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); + } + }, + + /** + * Remove self from zrender instance. + * Not recursively because it will be invoked when element added to storage. + * @param {module:zrender/ZRender} zr + */ + removeSelfFromZr: function (zr) { + 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); + } + } +}; +mixin(Element, Animatable); +mixin(Element, Transformable); +mixin(Element, Eventful); + +/** + * @module echarts/core/BoundingRect + */ +var v2ApplyTransform = applyTransform; +var mathMin = Math.min; +var mathMax = Math.max; +/** + * @alias module:echarts/core/BoundingRect + */ + +function BoundingRect(x, y, width, height) { + if (width < 0) { + x = x + width; + width = -width; + } + + if (height < 0) { + y = y + height; + height = -height; + } + /** + * @type {number} + */ + + + this.x = x; + /** + * @type {number} + */ + + this.y = y; + /** + * @type {number} + */ + + this.width = width; + /** + * @type {number} + */ + + this.height = height; +} + +BoundingRect.prototype = { + constructor: BoundingRect, + + /** + * @param {module:echarts/core/BoundingRect} other + */ + union: function (other) { + var x = mathMin(other.x, this.x); + var y = mathMin(other.y, this.y); + this.width = mathMax(other.x + other.width, this.x + this.width) - x; + this.height = mathMax(other.y + other.height, this.y + this.height) - y; + this.x = x; + this.y = y; + }, + + /** + * @param {Array.} m + * @methods + */ + applyTransform: function () { + var lt = []; + var rb = []; + var lb = []; + var rt = []; + return function (m) { + // In case usage like this + // el.getBoundingRect().applyTransform(el.transform) + // And element has no transform + if (!m) { + return; + } + + lt[0] = lb[0] = this.x; + lt[1] = rt[1] = this.y; + rb[0] = rt[0] = this.x + this.width; + rb[1] = lb[1] = this.y + this.height; + v2ApplyTransform(lt, lt, m); + v2ApplyTransform(rb, rb, m); + v2ApplyTransform(lb, lb, m); + v2ApplyTransform(rt, rt, m); + this.x = mathMin(lt[0], rb[0], lb[0], rt[0]); + this.y = mathMin(lt[1], rb[1], lb[1], rt[1]); + var maxX = mathMax(lt[0], rb[0], lb[0], rt[0]); + var maxY = mathMax(lt[1], rb[1], lb[1], rt[1]); + this.width = maxX - this.x; + this.height = maxY - this.y; + }; + }(), + + /** + * Calculate matrix of transforming from self to target rect + * @param {module:zrender/core/BoundingRect} b + * @return {Array.} + */ + 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; + }, + + /** + * @param {(module:echarts/core/BoundingRect|Object)} b + * @return {boolean} + */ + intersect: function (b) { + if (!b) { + return false; + } + + if (!(b instanceof BoundingRect)) { + // Normalize negative width/height. + 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; + return !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0); + }, + contain: function (x, y) { + var rect = this; + return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height; + }, + + /** + * @return {module:echarts/core/BoundingRect} + */ + clone: function () { + return new BoundingRect(this.x, this.y, this.width, this.height); + }, + + /** + * Copy from another rect + */ + copy: function (other) { + this.x = other.x; + this.y = other.y; + this.width = other.width; + this.height = other.height; + }, + plain: function () { + return { + x: this.x, + y: this.y, + width: this.width, + height: this.height + }; + } +}; +/** + * @param {Object|module:zrender/core/BoundingRect} rect + * @param {number} rect.x + * @param {number} rect.y + * @param {number} rect.width + * @param {number} rect.height + * @return {module:zrender/core/BoundingRect} + */ + +BoundingRect.create = function (rect) { + return new BoundingRect(rect.x, rect.y, rect.width, rect.height); +}; + +/** + * Group是一个容器,可以插入子节点,Group的变换也会被应用到子节点上 + * @module zrender/graphic/Group + * @example + * var Group = require('zrender/container/Group'); + * var Circle = require('zrender/graphic/shape/Circle'); + * var g = new Group(); + * g.position[0] = 100; + * g.position[1] = 100; + * g.add(new Circle({ + * style: { + * x: 100, + * y: 100, + * r: 20, + * } + * })); + * zr.add(g); + */ +/** + * @alias module:zrender/graphic/Group + * @constructor + * @extends module:zrender/mixin/Transformable + * @extends module:zrender/mixin/Eventful + */ + +var Group = function (opts) { + opts = opts || {}; + Element.call(this, opts); + + for (var key in opts) { + if (opts.hasOwnProperty(key)) { + this[key] = opts[key]; + } + } + + this._children = []; + this.__storage = null; + this.__dirty = true; +}; + +Group.prototype = { + constructor: Group, + isGroup: true, + + /** + * @type {string} + */ + type: 'group', + + /** + * 所有子孙元素是否响应鼠标事件 + * @name module:/zrender/container/Group#silent + * @type {boolean} + * @default false + */ + silent: false, + + /** + * @return {Array.} + */ + children: function () { + return this._children.slice(); + }, + + /** + * 获取指定 index 的儿子节点 + * @param {number} idx + * @return {module:zrender/Element} + */ + childAt: function (idx) { + return this._children[idx]; + }, + + /** + * 获取指定名字的儿子节点 + * @param {string} name + * @return {module:zrender/Element} + */ + childOfName: function (name) { + var children = this._children; + + for (var i = 0; i < children.length; i++) { + if (children[i].name === name) { + return children[i]; + } + } + }, + + /** + * @return {number} + */ + childCount: function () { + return this._children.length; + }, + + /** + * 添加子节点到最后 + * @param {module:zrender/Element} child + */ + add: function (child) { + if (child && child !== this && child.parent !== this) { + this._children.push(child); + + this._doAdd(child); + } + + return this; + }, + + /** + * 添加子节点在 nextSibling 之前 + * @param {module:zrender/Element} child + * @param {module:zrender/Element} nextSibling + */ + 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; + }, + _doAdd: function (child) { + if (child.parent) { + child.parent.remove(child); + } + + child.parent = this; + var storage = this.__storage; + var zr = this.__zr; + + if (storage && storage !== child.__storage) { + storage.addToStorage(child); + + if (child instanceof Group) { + child.addChildrenToStorage(storage); + } + } + + zr && zr.refresh(); + }, + + /** + * 移除子节点 + * @param {module:zrender/Element} child + */ + remove: function (child) { + var zr = this.__zr; + var storage = this.__storage; + var children = this._children; + var idx = indexOf(children, child); + + if (idx < 0) { + return this; + } + + children.splice(idx, 1); + child.parent = null; + + if (storage) { + storage.delFromStorage(child); + + if (child instanceof Group) { + child.delChildrenFromStorage(storage); + } + } + + zr && zr.refresh(); + return this; + }, + + /** + * 移除所有子节点 + */ + removeAll: function () { + var children = this._children; + var storage = this.__storage; + var child; + var i; + + for (i = 0; i < children.length; i++) { + child = children[i]; + + if (storage) { + storage.delFromStorage(child); + + if (child instanceof Group) { + child.delChildrenFromStorage(storage); + } + } + + child.parent = null; + } + + children.length = 0; + return this; + }, + + /** + * 遍历所有子节点 + * @param {Function} cb + * @param {} context + */ + 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; + }, + + /** + * 深度优先遍历所有子孙节点 + * @param {Function} cb + * @param {} context + */ + traverse: function (cb, context) { + for (var i = 0; i < this._children.length; i++) { + var child = this._children[i]; + cb.call(context, child); + + if (child.type === 'group') { + child.traverse(cb, context); + } + } + + return this; + }, + addChildrenToStorage: function (storage) { + for (var i = 0; i < this._children.length; i++) { + var child = this._children[i]; + storage.addToStorage(child); + + if (child instanceof Group) { + child.addChildrenToStorage(storage); + } + } + }, + delChildrenFromStorage: function (storage) { + for (var i = 0; i < this._children.length; i++) { + var child = this._children[i]; + storage.delFromStorage(child); + + if (child instanceof Group) { + child.delChildrenFromStorage(storage); + } + } + }, + dirty: function () { + this.__dirty = true; + this.__zr && this.__zr.refresh(); + return this; + }, + + /** + * @return {module:zrender/core/BoundingRect} + */ + getBoundingRect: function (includeChildren) { + // TODO Caching + var rect = null; + var tmpRect = new BoundingRect(0, 0, 0, 0); + var children = includeChildren || this._children; + var tmpMat = []; + + 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); // TODO + // The boundingRect cacluated by transforming original + // rect may be bigger than the actual bundingRect when rotation + // is used. (Consider a circle rotated aginst its center, where + // the actual boundingRect should be the same as that not be + // rotated.) But we can not find better approach to calculate + // actual boundingRect yet, considering performance. + + if (transform) { + tmpRect.copy(childRect); + tmpRect.applyTransform(transform); + rect = rect || tmpRect.clone(); + rect.union(tmpRect); + } else { + rect = rect || childRect.clone(); + rect.union(childRect); + } + } + + return rect || tmpRect; + } +}; +inherits(Group, Element); + +// https://github.com/mziccard/node-timsort +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 runStart; + var runLength; + var stackSize = 0; + 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(); // throw new Error('mergeLow preconditions were not respected'); + } 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(); // throw new Error('mergeHigh preconditions were not respected'); + } else { + customCursor = dest - (length2 - 1); + + for (i = 0; i < length2; i++) { + array[customCursor + i] = tmp[i]; + } + } + } + + this.mergeRuns = mergeRuns; + this.forceMergeRuns = forceMergeRuns; + this.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 = new 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(); +} + +// https://jsfiddle.net/pissang/jr4x7mdm/8/ + +function shapeCompareFunc(a, b) { + if (a.zlevel === b.zlevel) { + if (a.z === b.z) { + // if (a.z2 === b.z2) { + // // FIXME Slow has renderidx compare + // // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement + // // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012 + // return a.__renderidx - b.__renderidx; + // } + return a.z2 - b.z2; + } + + return a.z - b.z; + } + + return a.zlevel - b.zlevel; +} +/** + * 内容仓库 (M) + * @alias module:zrender/Storage + * @constructor + */ + + +var Storage = function () { + // jshint ignore:line + this._roots = []; + this._displayList = []; + this._displayListLen = 0; +}; + +Storage.prototype = { + constructor: Storage, + + /** + * @param {Function} cb + * + */ + traverse: function (cb, context) { + for (var i = 0; i < this._roots.length; i++) { + this._roots[i].traverse(cb, context); + } + }, + + /** + * 返回所有图形的绘制队列 + * @param {boolean} [update=false] 是否在返回前更新该数组 + * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效 + * + * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList} + * @return {Array.} + */ + getDisplayList: function (update, includeIgnore) { + includeIgnore = includeIgnore || false; + + if (update) { + this.updateDisplayList(includeIgnore); + } + + return this._displayList; + }, + + /** + * 更新图形的绘制队列。 + * 每次绘制前都会调用,该方法会先深度优先遍历整个树,更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中, + * 最后根据绘制的优先级(zlevel > z > 插入顺序)排序得到绘制队列 + * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组 + */ + 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; + env$1.canvasSupported && sort(displayList, shapeCompareFunc); + }, + _updateAndAddDisplayable: function (el, clipPaths, includeIgnore) { + if (el.ignore && !includeIgnore) { + return; + } + + el.beforeUpdate(); + + if (el.__dirty) { + el.update(); + } + + el.afterUpdate(); + var userSetClipPath = el.clipPath; + + if (userSetClipPath) { + // FIXME 效率影响 + if (clipPaths) { + clipPaths = clipPaths.slice(); + } else { + clipPaths = []; + } + + var currentClipPath = userSetClipPath; + var parentClipPath = el; // Recursively add clip path + + while (currentClipPath) { + // clipPath 的变换是基于使用这个 clipPath 的元素 + currentClipPath.parent = parentClipPath; + currentClipPath.updateTransform(); + clipPaths.push(currentClipPath); + parentClipPath = currentClipPath; + currentClipPath = currentClipPath.clipPath; + } + } + + if (el.isGroup) { + var children = el._children; + + for (var i = 0; i < children.length; i++) { + var child = children[i]; // Force to mark as dirty if group is dirty + // FIXME __dirtyPath ? + + if (el.__dirty) { + child.__dirty = true; + } + + this._updateAndAddDisplayable(child, clipPaths, includeIgnore); + } // Mark group clean here + + + el.__dirty = false; + } else { + el.__clipPaths = clipPaths; + this._displayList[this._displayListLen++] = el; + } + }, + + /** + * 添加图形(Shape)或者组(Group)到根节点 + * @param {module:zrender/Element} el + */ + addRoot: function (el) { + if (el.__storage === this) { + return; + } + + if (el instanceof Group) { + el.addChildrenToStorage(this); + } + + this.addToStorage(el); + + this._roots.push(el); + }, + + /** + * 删除指定的图形(Shape)或者组(Group) + * @param {string|Array.} [el] 如果为空清空整个Storage + */ + delRoot: function (el) { + if (el == null) { + // 不指定el清空 + for (var i = 0; i < this._roots.length; i++) { + var root = this._roots[i]; + + if (root instanceof Group) { + root.delChildrenFromStorage(this); + } + } + + this._roots = []; + this._displayList = []; + this._displayListLen = 0; + return; + } + + 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.delFromStorage(el); + + this._roots.splice(idx, 1); + + if (el instanceof Group) { + el.delChildrenFromStorage(this); + } + } + }, + addToStorage: function (el) { + if (el) { + el.__storage = this; + el.dirty(false); + } + + return this; + }, + delFromStorage: function (el) { + if (el) { + el.__storage = null; + } + + return this; + }, + + /** + * 清空并且释放Storage + */ + dispose: function () { + this._renderList = this._roots = null; + }, + displayableSortFunc: shapeCompareFunc +}; + +var SHADOW_PROPS = { + 'shadowBlur': 1, + 'shadowOffsetX': 1, + 'shadowOffsetY': 1, + 'textShadowBlur': 1, + 'textShadowOffsetX': 1, + 'textShadowOffsetY': 1, + 'textBoxShadowBlur': 1, + 'textBoxShadowOffsetX': 1, + 'textBoxShadowOffsetY': 1 +}; +var fixShadow = function (ctx, propName, value) { + if (SHADOW_PROPS.hasOwnProperty(propName)) { + return value *= ctx.dpr; + } + + return value; +}; + +var ContextCachedBy = { + NONE: 0, + STYLE_BIND: 1, + PLAIN_TEXT: 2 +}; // Avoid confused with 0/false. + +var WILL_BE_RESTORED = 9; + +var STYLE_COMMON_PROPS = [['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'], ['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]]; // var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4); +// var LINE_PROPS = STYLE_COMMON_PROPS.slice(4); + +var Style = function (opts) { + this.extendFrom(opts, false); +}; + +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; + } // Fix NaN when rect is Infinity + + + 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; +} + +Style.prototype = { + constructor: Style, + + /** + * @type {string} + */ + fill: '#000', + + /** + * @type {string} + */ + stroke: null, + + /** + * @type {number} + */ + opacity: 1, + + /** + * @type {number} + */ + fillOpacity: null, + + /** + * @type {number} + */ + strokeOpacity: null, + + /** + * `true` is not supported. + * `false`/`null`/`undefined` are the same. + * `false` is used to remove lineDash in some + * case that `null`/`undefined` can not be set. + * (e.g., emphasis.lineStyle in echarts) + * @type {Array.|boolean} + */ + lineDash: null, + + /** + * @type {number} + */ + lineDashOffset: 0, + + /** + * @type {number} + */ + shadowBlur: 0, + + /** + * @type {number} + */ + shadowOffsetX: 0, + + /** + * @type {number} + */ + shadowOffsetY: 0, + + /** + * @type {number} + */ + lineWidth: 1, + + /** + * If stroke ignore scale + * @type {Boolean} + */ + strokeNoScale: false, + // Bounding rect text configuration + // Not affected by element transform + + /** + * @type {string} + */ + text: null, + + /** + * If `fontSize` or `fontFamily` exists, `font` will be reset by + * `fontSize`, `fontStyle`, `fontWeight`, `fontFamily`. + * So do not visit it directly in upper application (like echarts), + * but use `contain/text#makeFont` instead. + * @type {string} + */ + font: null, + + /** + * The same as font. Use font please. + * @deprecated + * @type {string} + */ + textFont: null, + + /** + * It helps merging respectively, rather than parsing an entire font string. + * @type {string} + */ + fontStyle: null, + + /** + * It helps merging respectively, rather than parsing an entire font string. + * @type {string} + */ + fontWeight: null, + + /** + * It helps merging respectively, rather than parsing an entire font string. + * Should be 12 but not '12px'. + * @type {number} + */ + fontSize: null, + + /** + * It helps merging respectively, rather than parsing an entire font string. + * @type {string} + */ + fontFamily: null, + + /** + * Reserved for special functinality, like 'hr'. + * @type {string} + */ + textTag: null, + + /** + * @type {string} + */ + textFill: '#000', + + /** + * @type {string} + */ + textStroke: null, + + /** + * @type {number} + */ + textWidth: null, + + /** + * Only for textBackground. + * @type {number} + */ + textHeight: null, + + /** + * textStroke may be set as some color as a default + * value in upper applicaion, where the default value + * of textStrokeWidth should be 0 to make sure that + * user can choose to do not use text stroke. + * @type {number} + */ + textStrokeWidth: 0, + + /** + * @type {number} + */ + textLineHeight: null, + + /** + * 'inside', 'left', 'right', 'top', 'bottom' + * [x, y] + * Based on x, y of rect. + * @type {string|Array.} + * @default 'inside' + */ + textPosition: 'inside', + + /** + * If not specified, use the boundingRect of a `displayable`. + * @type {Object} + */ + textRect: null, + + /** + * [x, y] + * @type {Array.} + */ + textOffset: null, + + /** + * @type {string} + */ + textAlign: null, + + /** + * @type {string} + */ + textVerticalAlign: null, + + /** + * @type {number} + */ + textDistance: 5, + + /** + * @type {string} + */ + textShadowColor: 'transparent', + + /** + * @type {number} + */ + textShadowBlur: 0, + + /** + * @type {number} + */ + textShadowOffsetX: 0, + + /** + * @type {number} + */ + textShadowOffsetY: 0, + + /** + * @type {string} + */ + textBoxShadowColor: 'transparent', + + /** + * @type {number} + */ + textBoxShadowBlur: 0, + + /** + * @type {number} + */ + textBoxShadowOffsetX: 0, + + /** + * @type {number} + */ + textBoxShadowOffsetY: 0, + + /** + * Whether transform text. + * Only available in Path and Image element, + * where the text is called as `RectText`. + * @type {boolean} + */ + transformText: false, + + /** + * Text rotate around position of Path or Image. + * The origin of the rotation can be specified by `textOrigin`. + * Only available in Path and Image element, + * where the text is called as `RectText`. + */ + textRotation: 0, + + /** + * Text origin of text rotation. + * Useful in the case like label rotation of circular symbol. + * Only available in Path and Image element, where the text is called + * as `RectText` and the element is called as "host element". + * The value can be: + * + If specified as a coordinate like `[10, 40]`, it is the `[x, y]` + * base on the left-top corner of the rect of its host element. + * + If specified as a string `center`, it is the center of the rect of + * its host element. + * + By default, this origin is the `textPosition`. + * @type {string|Array.} + */ + textOrigin: null, + + /** + * @type {string} + */ + textBackgroundColor: null, + + /** + * @type {string} + */ + textBorderColor: null, + + /** + * @type {number} + */ + textBorderWidth: 0, + + /** + * @type {number} + */ + textBorderRadius: 0, + + /** + * Can be `2` or `[2, 4]` or `[2, 3, 4, 5]` + * @type {number|Array.} + */ + textPadding: null, + + /** + * Text styles for rich text. + * @type {Object} + */ + rich: null, + + /** + * {outerWidth, outerHeight, ellipsis, placeholder} + * @type {Object} + */ + truncate: null, + + /** + * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation + * @type {string} + */ + blend: null, + + /** + * @param {CanvasRenderingContext2D} ctx + */ + bind: function (ctx, el, prevEl) { + var style = this; + var prevStyle = prevEl && prevEl.style; // If no prevStyle, it means first draw. + // Only apply cache if the last time cachced by this function. + + var notCheckCache = !prevStyle || ctx.__attrCachedBy !== ContextCachedBy.STYLE_BIND; + ctx.__attrCachedBy = ContextCachedBy.STYLE_BIND; + + for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) { + var prop = STYLE_COMMON_PROPS[i]; + var styleName = prop[0]; + + if (notCheckCache || style[styleName] !== prevStyle[styleName]) { + // FIXME Invalid property value will cause style leak from previous element. + ctx[styleName] = fixShadow(ctx, styleName, style[styleName] || prop[1]); + } + } + + if (notCheckCache || style.fill !== prevStyle.fill) { + ctx.fillStyle = style.fill; + } + + if (notCheckCache || style.stroke !== prevStyle.stroke) { + ctx.strokeStyle = style.stroke; + } + + if (notCheckCache || style.opacity !== prevStyle.opacity) { + ctx.globalAlpha = style.opacity == null ? 1 : style.opacity; + } + + if (notCheckCache || style.blend !== prevStyle.blend) { + ctx.globalCompositeOperation = style.blend || 'source-over'; + } + + if (this.hasStroke()) { + var lineWidth = style.lineWidth; + ctx.lineWidth = lineWidth / (this.strokeNoScale && el && el.getLineScale ? el.getLineScale() : 1); + } + }, + hasFill: function () { + var fill = this.fill; + return fill != null && fill !== 'none'; + }, + hasStroke: function () { + var stroke = this.stroke; + return stroke != null && stroke !== 'none' && this.lineWidth > 0; + }, + + /** + * Extend from other style + * @param {zrender/graphic/Style} otherStyle + * @param {boolean} overwrite true: overwrirte any way. + * false: overwrite only when !target.hasOwnProperty + * others: overwrite when property is not null/undefined. + */ + extendFrom: function (otherStyle, overwrite) { + if (otherStyle) { + for (var name in otherStyle) { + if (otherStyle.hasOwnProperty(name) && (overwrite === true || (overwrite === false ? !this.hasOwnProperty(name) : otherStyle[name] != null))) { + this[name] = otherStyle[name]; + } + } + } + }, + + /** + * Batch setting style with a given object + * @param {Object|string} obj + * @param {*} [obj] + */ + set: function (obj, value) { + if (typeof obj === 'string') { + this[obj] = value; + } else { + this.extendFrom(obj, true); + } + }, + + /** + * Clone + * @return {zrender/graphic/Style} [description] + */ + clone: function () { + var newStyle = new this.constructor(); + newStyle.extendFrom(this, true); + return newStyle; + }, + getGradient: function (ctx, obj, rect) { + var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient; + var canvasGradient = method(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; + } +}; +var styleProto = Style.prototype; + +for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) { + var prop = STYLE_COMMON_PROPS[i]; + + if (!(prop[0] in styleProto)) { + styleProto[prop[0]] = prop[1]; + } +} // Provide for others + + +Style.getGradient = styleProto.getGradient; + +var Pattern = function (image, repeat) { + // Should do nothing more in this constructor. Because gradient can be + // declard by `color: {image: ...}`, where this constructor will not be called. + this.image = image; + this.repeat = repeat; // Can be cloned + + this.type = 'pattern'; +}; + +Pattern.prototype.getCanvasPattern = function (ctx) { + return ctx.createPattern(this.image, this.repeat || 'repeat'); +}; + +/** + * @module zrender/Layer + * @author pissang(https://www.github.com/pissang) + */ +function returnFalse() { + return false; +} +/** + * 创建dom + * + * @inner + * @param {string} id dom id 待用 + * @param {Painter} painter painter instance + * @param {number} number + */ + + +function createDom(id, painter, dpr) { + var newDom = createCanvas(); + var width = painter.getWidth(); + var height = painter.getHeight(); + var newDomStyle = newDom.style; + + if (newDomStyle) { + // In node or some other non-browser environment + 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; +} +/** + * @alias module:zrender/Layer + * @constructor + * @extends module:zrender/mixin/Transformable + * @param {string} id + * @param {module:zrender/Painter} painter + * @param {number} [dpr] + */ + + +var Layer = function (id, painter, dpr) { + var dom; + dpr = dpr || devicePixelRatio; + + if (typeof id === 'string') { + dom = createDom(id, painter, dpr); + } // Not using isDom because in node it will return false + else if (isObject$1(id)) { + dom = id; + id = dom.id; + } + + this.id = id; + this.dom = dom; + var domStyle = dom.style; + + if (domStyle) { + // Not in node + dom.onselectstart = returnFalse; // 避免页面选中的尴尬 + + domStyle['-webkit-user-select'] = 'none'; + domStyle['user-select'] = 'none'; + domStyle['-webkit-touch-callout'] = 'none'; + domStyle['-webkit-tap-highlight-color'] = 'rgba(0,0,0,0)'; + domStyle['padding'] = 0; // eslint-disable-line dot-notation + + domStyle['margin'] = 0; // eslint-disable-line dot-notation + + domStyle['border-width'] = 0; + } + + this.domBack = null; + this.ctxBack = null; + this.painter = painter; + this.config = null; // Configs + + /** + * 每次清空画布的颜色 + * @type {string} + * @default 0 + */ + + this.clearColor = 0; + /** + * 是否开启动态模糊 + * @type {boolean} + * @default false + */ + + this.motionBlur = false; + /** + * 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显 + * @type {number} + * @default 0.7 + */ + + this.lastFrameAlpha = 0.7; + /** + * Layer dpr + * @type {number} + */ + + this.dpr = dpr; +}; + +Layer.prototype = { + constructor: Layer, + __dirty: true, + __used: false, + __drawIndex: 0, + __startIndex: 0, + __endIndex: 0, + incremental: false, + getElementCount: function () { + return this.__endIndex - this.__startIndex; + }, + initContext: function () { + this.ctx = this.dom.getContext('2d'); + this.ctx.dpr = this.dpr; + }, + 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); + } + }, + + /** + * @param {number} width + * @param {number} height + */ + 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); + } + } + }, + + /** + * 清空该层画布 + * @param {boolean} [clearAll]=false Clear all with out motion blur + * @param {Color} [clearColor] + */ + clear: function (clearAll, clearColor) { + var dom = this.dom; + var ctx = this.ctx; + var width = dom.width; + var height = dom.height; + var clearColor = clearColor || this.clearColor; + var haveMotionBLur = this.motionBlur && !clearAll; + var lastFrameAlpha = this.lastFrameAlpha; + var dpr = this.dpr; + + if (haveMotionBLur) { + if (!this.domBack) { + this.createBackBuffer(); + } + + this.ctxBack.globalCompositeOperation = 'copy'; + this.ctxBack.drawImage(dom, 0, 0, width / dpr, height / dpr); + } + + ctx.clearRect(0, 0, width, height); + + if (clearColor && clearColor !== 'transparent') { + var clearColorGradientOrPattern; // Gradient + + if (clearColor.colorStops) { + // Cache canvas gradient + clearColorGradientOrPattern = clearColor.__canvasGradient || Style.getGradient(ctx, clearColor, { + x: 0, + y: 0, + width: width, + height: height + }); + clearColor.__canvasGradient = clearColorGradientOrPattern; + } // Pattern + else if (clearColor.image) { + clearColorGradientOrPattern = Pattern.prototype.getCanvasPattern.call(clearColor, ctx); + } + + ctx.save(); + ctx.fillStyle = clearColorGradientOrPattern || clearColor; + ctx.fillRect(0, 0, width, height); + ctx.restore(); + } + + if (haveMotionBLur) { + var domBack = this.domBack; + ctx.save(); + ctx.globalAlpha = lastFrameAlpha; + ctx.drawImage(domBack, 0, 0, width, height); + ctx.restore(); + } + } +}; + +var requestAnimationFrame = typeof window !== 'undefined' && (window.requestAnimationFrame && window.requestAnimationFrame.bind(window) || // https://github.com/ecomfe/zrender/issues/189#issuecomment-224919809 +window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window) || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame) || function (func) { + setTimeout(func, 16); +}; + +var globalImageCache = new LRU(50); +/** + * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc + * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image + */ + +function findExistImage(newImageOrSrc) { + if (typeof newImageOrSrc === 'string') { + var cachedImgObj = globalImageCache.get(newImageOrSrc); + return cachedImgObj && cachedImgObj.image; + } else { + return newImageOrSrc; + } +} +/** + * Caution: User should cache loaded images, but not just count on LRU. + * Consider if required images more than LRU size, will dead loop occur? + * + * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc + * @param {HTMLImageElement|HTMLCanvasElement|Canvas} image Existent image. + * @param {module:zrender/Element} [hostEl] For calling `dirty`. + * @param {Function} [cb] params: (image, cbPayload) + * @param {Object} [cbPayload] Payload on cb calling. + * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image + */ + +function createOrUpdateImage(newImageOrSrc, image, hostEl, cb, cbPayload) { + if (!newImageOrSrc) { + return image; + } else if (typeof newImageOrSrc === 'string') { + // Image should not be loaded repeatly. + if (image && image.__zrImageSrc === newImageOrSrc || !hostEl) { + return image; + } // Only when there is no existent image or existent image src + // is different, this method is responsible for load. + + + var cachedImgObj = globalImageCache.get(newImageOrSrc); + var pendingWrap = { + hostEl: hostEl, + cb: cb, + cbPayload: cbPayload + }; + + if (cachedImgObj) { + image = cachedImgObj.image; + !isImageReady(image) && cachedImgObj.pending.push(pendingWrap); + } else { + image = new Image(); + image.onload = image.onerror = imageOnLoad; + globalImageCache.put(newImageOrSrc, image.__cachedImgObj = { + image: image, + pending: [pendingWrap] + }); + image.src = image.__zrImageSrc = newImageOrSrc; + } + + return image; + } // newImageOrSrc is an HTMLImageElement or HTMLCanvasElement or Canvas + 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 textWidthCache = {}; +var textWidthCacheCounter = 0; +var TEXT_CACHE_MAX = 5000; +var STYLE_REG = /\{([a-zA-Z0-9_]+)\|([^}]*)\}/g; +var DEFAULT_FONT$1 = '12px sans-serif'; // Avoid assign to an exported variable, for transforming to cjs. + +var methods$1 = {}; +function $override$1(name, fn) { + methods$1[name] = fn; +} +/** + * @public + * @param {string} text + * @param {string} font + * @return {number} width + */ + +function getWidth(text, font) { + font = font || DEFAULT_FONT$1; + var key = text + ':' + font; + + if (textWidthCache[key]) { + return textWidthCache[key]; + } + + var textLines = (text + '').split('\n'); + var width = 0; + + for (var i = 0, l = textLines.length; i < l; i++) { + // textContain.measureText may be overrided in SVG or VML + width = Math.max(measureText(textLines[i], font).width, width); + } + + if (textWidthCacheCounter > TEXT_CACHE_MAX) { + textWidthCacheCounter = 0; + textWidthCache = {}; + } + + textWidthCacheCounter++; + textWidthCache[key] = width; + return width; +} +/** + * @public + * @param {string} text + * @param {string} font + * @param {string} [textAlign='left'] + * @param {string} [textVerticalAlign='top'] + * @param {Array.} [textPadding] + * @param {Object} [rich] + * @param {Object} [truncate] + * @return {Object} {x, y, width, height, lineHeight} + */ + +function getBoundingRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) { + return rich ? getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) : getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate); +} + +function getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate) { + var contentBlock = parsePlainText(text, font, textPadding, textLineHeight, truncate); + var outerWidth = getWidth(text, font); + + if (textPadding) { + outerWidth += textPadding[1] + textPadding[3]; + } + + var outerHeight = contentBlock.outerHeight; + var x = adjustTextX(0, outerWidth, textAlign); + var y = adjustTextY(0, outerHeight, textVerticalAlign); + var rect = new BoundingRect(x, y, outerWidth, outerHeight); + rect.lineHeight = contentBlock.lineHeight; + return rect; +} + +function getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) { + var contentBlock = parseRichText(text, { + rich: rich, + truncate: truncate, + font: font, + textAlign: textAlign, + textPadding: textPadding, + textLineHeight: textLineHeight + }); + var outerWidth = contentBlock.outerWidth; + var outerHeight = contentBlock.outerHeight; + var x = adjustTextX(0, outerWidth, textAlign); + var y = adjustTextY(0, outerHeight, textVerticalAlign); + return new BoundingRect(x, y, outerWidth, outerHeight); +} +/** + * @public + * @param {number} x + * @param {number} width + * @param {string} [textAlign='left'] + * @return {number} Adjusted x. + */ + + +function adjustTextX(x, width, textAlign) { + // FIXME Right to left language + if (textAlign === 'right') { + x -= width; + } else if (textAlign === 'center') { + x -= width / 2; + } + + return x; +} +/** + * @public + * @param {number} y + * @param {number} height + * @param {string} [textVerticalAlign='top'] + * @return {number} Adjusted y. + */ + +function adjustTextY(y, height, textVerticalAlign) { + if (textVerticalAlign === 'middle') { + y -= height / 2; + } else if (textVerticalAlign === 'bottom') { + y -= height; + } + + return y; +} +/** + * Follow same interface to `Displayable.prototype.calculateTextPosition`. + * @public + * @param {Obejct} [out] Prepared out object. If not input, auto created in the method. + * @param {module:zrender/graphic/Style} style where `textPosition` and `textDistance` are visited. + * @param {Object} rect {x, y, width, height} Rect of the host elment, according to which the text positioned. + * @return {Object} The input `out`. Set: {x, y, textAlign, textVerticalAlign} + */ + +function calculateTextPosition(out, style, rect) { + var textPosition = style.textPosition; + var distance = style.textDistance; + var x = rect.x; + var y = rect.y; + distance = distance || 0; + var height = rect.height; + var width = rect.width; + var halfHeight = height / 2; + var textAlign = 'left'; + var textVerticalAlign = 'top'; + + 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.textAlign = textAlign; + out.textVerticalAlign = textVerticalAlign; + return out; +} +/** + * To be removed. But still do not remove in case that some one has imported it. + * @deprecated + * @public + * @param {stirng} textPosition + * @param {Object} rect {x, y, width, height} + * @param {number} distance + * @return {Object} {x, y, textAlign, textVerticalAlign} + */ + + +/** + * Show ellipsis if overflow. + * + * @public + * @param {string} text + * @param {string} containerWidth + * @param {string} font + * @param {number} [ellipsis='...'] + * @param {Object} [options] + * @param {number} [options.maxIterations=3] + * @param {number} [options.minChar=0] If truncate result are less + * then minChar, ellipsis will not show, which is + * better for user hint in some cases. + * @param {number} [options.placeholder=''] When all truncated, use the placeholder. + * @return {string} + */ + +function truncateText(text, containerWidth, font, ellipsis, options) { + if (!containerWidth) { + return ''; + } + + var textLines = (text + '').split('\n'); + options = prepareTruncateOptions(containerWidth, font, ellipsis, options); // FIXME + // It is not appropriate that every line has '...' when truncate multiple lines. + + 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 = extend({}, options); + options.font = font; + var ellipsis = retrieve2(ellipsis, '...'); + options.maxIterations = retrieve2(options.maxIterations, 2); + var minChar = options.minChar = retrieve2(options.minChar, 0); // FIXME + // Other languages? + + options.cnCharWidth = getWidth('国', font); // FIXME + // Consider proportional font? + + var ascCharWidth = options.ascCharWidth = getWidth('a', font); + options.placeholder = retrieve2(options.placeholder, ''); // Example 1: minChar: 3, text: 'asdfzxcv', truncate result: 'asdf', but not: 'a...'. + // Example 2: minChar: 3, text: '维度', truncate result: '维', but not: '...'. + + var contentWidth = containerWidth = Math.max(0, containerWidth - 1); // Reserve some gap. + + 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; + options.ellipsis = ellipsis; + options.ellipsisWidth = ellipsisWidth; + options.contentWidth = contentWidth; + options.containerWidth = containerWidth; + return options; +} + +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; +} +/** + * @public + * @param {string} font + * @return {number} line height + */ + + +function getLineHeight(font) { + // FIXME A rough approach. + return getWidth('国', font); +} +/** + * @public + * @param {string} text + * @param {string} font + * @return {Object} width + */ + +function measureText(text, font) { + return methods$1.measureText(text, font); +} // Avoid assign to an exported variable, for transforming to cjs. + +methods$1.measureText = function (text, font) { + var ctx = getContext(); + ctx.font = font || DEFAULT_FONT$1; + return ctx.measureText(text); +}; +/** + * @public + * @param {string} text + * @param {string} font + * @param {Object} [truncate] + * @return {Object} block: {lineHeight, lines, height, outerHeight, canCacheByTextString} + * Notice: for performance, do not calculate outerWidth util needed. + * `canCacheByTextString` means the result `lines` is only determined by the input `text`. + * Thus we can simply comparing the `input` text to determin whether the result changed, + * without travel the result `lines`. + */ + + +function parsePlainText(text, font, padding, textLineHeight, truncate) { + text != null && (text += ''); + var lineHeight = retrieve2(textLineHeight, getLineHeight(font)); + var lines = text ? text.split('\n') : []; + var height = lines.length * lineHeight; + var outerHeight = height; + var canCacheByTextString = true; + + if (padding) { + outerHeight += padding[0] + padding[2]; + } + + if (text && truncate) { + canCacheByTextString = false; + var truncOuterHeight = truncate.outerHeight; + var truncOuterWidth = truncate.outerWidth; + + if (truncOuterHeight != null && outerHeight > truncOuterHeight) { + text = ''; + lines = []; + } else if (truncOuterWidth != null) { + var options = prepareTruncateOptions(truncOuterWidth - (padding ? padding[1] + padding[3] : 0), font, truncate.ellipsis, { + minChar: truncate.minChar, + placeholder: truncate.placeholder + }); // FIXME + // It is not appropriate that every line has '...' when truncate multiple lines. + + for (var i = 0, len = lines.length; i < len; i++) { + lines[i] = truncateSingleLine(lines[i], options); + } + } + } + + return { + lines: lines, + height: height, + outerHeight: outerHeight, + lineHeight: lineHeight, + canCacheByTextString: canCacheByTextString + }; +} +/** + * For example: 'some text {a|some text}other text{b|some text}xxx{c|}xxx' + * Also consider 'bbbb{a|xxx\nzzz}xxxx\naaaa'. + * + * @public + * @param {string} text + * @param {Object} style + * @return {Object} block + * { + * width, + * height, + * lines: [{ + * lineHeight, + * width, + * tokens: [[{ + * styleName, + * text, + * width, // include textPadding + * height, // include textPadding + * textWidth, // pure text width + * textHeight, // pure text height + * lineHeihgt, + * font, + * textAlign, + * textVerticalAlign + * }], [...], ...] + * }, ...] + * } + * If styleName is undefined, it is plain text. + */ + +function parseRichText(text, style) { + var contentBlock = { + lines: [], + width: 0, + height: 0 + }; + text != null && (text += ''); + + if (!text) { + return contentBlock; + } + + 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)); + } + + pushTokens(contentBlock, result[2], result[1]); + lastIndex = STYLE_REG.lastIndex; + } + + if (lastIndex < text.length) { + pushTokens(contentBlock, text.substring(lastIndex, text.length)); + } + + var lines = contentBlock.lines; + var contentHeight = 0; + var contentWidth = 0; // For `textWidth: 100%` + + var pendingList = []; + var stlPadding = style.textPadding; + var truncate = style.truncate; + var truncateWidth = truncate && truncate.outerWidth; + var truncateHeight = truncate && truncate.outerHeight; + + if (stlPadding) { + truncateWidth != null && (truncateWidth -= stlPadding[1] + stlPadding[3]); + truncateHeight != null && (truncateHeight -= stlPadding[0] + stlPadding[2]); + } // Calculate layout info of tokens. + + + for (var i = 0; i < lines.length; i++) { + var line = 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] || {}; // textPadding should not inherit from style. + + var textPadding = token.textPadding = tokenStyle.textPadding; // textFont has been asigned to font by `normalizeStyle`. + + var font = token.font = tokenStyle.font || style.font; // textHeight can be used when textVerticalAlign is specified in token. + + var tokenHeight = token.textHeight = retrieve2( // textHeight should not be inherited, consider it can be specified + // as box height of the block. + tokenStyle.textHeight, getLineHeight(font)); + textPadding && (tokenHeight += textPadding[0] + textPadding[2]); + token.height = tokenHeight; + token.lineHeight = retrieve3(tokenStyle.textLineHeight, style.textLineHeight, tokenHeight); + token.textAlign = tokenStyle && tokenStyle.textAlign || style.textAlign; + token.textVerticalAlign = tokenStyle && tokenStyle.textVerticalAlign || 'middle'; + + if (truncateHeight != null && contentHeight + token.lineHeight > truncateHeight) { + return { + lines: [], + width: 0, + height: 0 + }; + } + + token.textWidth = getWidth(token.text, font); + var tokenWidth = tokenStyle.textWidth; + var tokenWidthNotSpecified = tokenWidth == null || tokenWidth === 'auto'; // Percent width, can be `100%`, can be used in drawing separate + // line when box width is needed to be auto. + + if (typeof tokenWidth === 'string' && tokenWidth.charAt(tokenWidth.length - 1) === '%') { + token.percentWidth = tokenWidth; + pendingList.push(token); + tokenWidth = 0; // Do not truncate in this case, because there is no user case + // and it is too complicated. + } else { + if (tokenWidthNotSpecified) { + tokenWidth = token.textWidth; // FIXME: If image is not loaded and textWidth is not specified, calling + // `getBoundingRect()` will not get correct result. + + var textBackgroundColor = tokenStyle.textBackgroundColor; + var bgImg = textBackgroundColor && textBackgroundColor.image; // Use cases: + // (1) If image is not loaded, it will be loaded at render phase and call + // `dirty()` and `textBackgroundColor.image` will be replaced with the loaded + // image, and then the right size will be calculated here at the next tick. + // See `graphic/helper/text.js`. + // (2) If image loaded, and `textBackgroundColor.image` is image src string, + // use `imageHelper.findExistImage` to find cached image. + // `imageHelper.findExistImage` will always be called here before + // `imageHelper.createOrUpdateImage` in `graphic/helper/text.js#renderRichText` + // which ensures that image will not be rendered before correct size calcualted. + + if (bgImg) { + bgImg = findExistImage(bgImg); + + if (isImageReady(bgImg)) { + tokenWidth = Math.max(tokenWidth, bgImg.width * tokenHeight / bgImg.height); + } + } + } + + var paddingW = textPadding ? textPadding[1] + textPadding[3] : 0; + tokenWidth += paddingW; + var remianTruncWidth = truncateWidth != null ? truncateWidth - lineWidth : null; + + if (remianTruncWidth != null && remianTruncWidth < tokenWidth) { + if (!tokenWidthNotSpecified || remianTruncWidth < paddingW) { + token.text = ''; + token.textWidth = tokenWidth = 0; + } else { + token.text = truncateText(token.text, remianTruncWidth - paddingW, font, truncate.ellipsis, { + minChar: truncate.minChar + }); + token.textWidth = getWidth(token.text, font); + tokenWidth = token.textWidth + paddingW; + } + } + } + + lineWidth += token.width = tokenWidth; + tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight)); + } + + line.width = lineWidth; + line.lineHeight = lineHeight; + contentHeight += lineHeight; + contentWidth = Math.max(contentWidth, lineWidth); + } + + contentBlock.outerWidth = contentBlock.width = retrieve2(style.textWidth, contentWidth); + contentBlock.outerHeight = contentBlock.height = retrieve2(style.textHeight, contentHeight); + + 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; // Should not base on outerWidth, because token can not be placed out of padding. + + token.width = parseInt(percentWidth, 10) / 100 * contentWidth; + } + + return contentBlock; +} + +function pushTokens(block, str, styleName) { + var isEmptyStr = str === ''; + var strs = str.split('\n'); + var lines = block.lines; + + for (var i = 0; i < strs.length; i++) { + var text = strs[i]; + var token = { + styleName: styleName, + text: text, + isLineHolder: !text && !isEmptyStr + }; // The first token should be appended to the last line. + + if (!i) { + var tokens = (lines[lines.length - 1] || (lines[0] = { + tokens: [] + })).tokens; // Consider cases: + // (1) ''.split('\n') => ['', '\n', ''], the '' at the first item + // (which is a placeholder) should be replaced by new token. + // (2) A image backage, where token likes {a|}. + // (3) A redundant '' will affect textAlign in line. + // (4) tokens with the same tplName should not be merged, because + // they should be displayed in different box (with border and padding). + + var tokensLen = tokens.length; + tokensLen === 1 && tokens[0].isLineHolder ? tokens[0] = token : // Consider text is '', only insert when it is the "lineHolder" or + // "emptyStr". Otherwise a redundant '' will affect textAlign in line. + (text || !tokensLen || isEmptyStr) && tokens.push(token); + } // Other tokens always start a new line. + else { + // If there is '', insert it as a placeholder. + lines.push({ + tokens: [token] + }); + } + } +} + +function makeFont(style) { + // FIXME in node-canvas fontWeight is before fontStyle + // Use `fontSize` `fontFamily` to check whether font properties are defined. + var font = (style.fontSize || style.fontFamily) && [style.fontStyle, style.fontWeight, (style.fontSize || 12) + 'px', // If font properties are defined, `fontFamily` should not be ignored. + style.fontFamily || 'sans-serif'].join(' '); + return font && trim(font) || style.textFont || style.font; +} + +/** + * @param {Object} ctx + * @param {Object} shape + * @param {number} shape.x + * @param {number} shape.y + * @param {number} shape.width + * @param {number} shape.height + * @param {number} shape.r + */ +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; // Convert width and height to positive for better borderRadius + + 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 DEFAULT_FONT = DEFAULT_FONT$1; // TODO: Have not support 'start', 'end' yet. + +var VALID_TEXT_ALIGN = { + left: 1, + right: 1, + center: 1 +}; +var VALID_TEXT_VERTICAL_ALIGN = { + top: 1, + bottom: 1, + middle: 1 +}; // Different from `STYLE_COMMON_PROPS` of `graphic/Style`, +// the default value of shadowColor is `'transparent'`. + +var SHADOW_STYLE_COMMON_PROPS = [['textShadowBlur', 'shadowBlur', 0], ['textShadowOffsetX', 'shadowOffsetX', 0], ['textShadowOffsetY', 'shadowOffsetY', 0], ['textShadowColor', 'shadowColor', 'transparent']]; +var _tmpTextPositionResult = {}; +var _tmpBoxPositionResult = {}; +/** + * @param {module:zrender/graphic/Style} style + * @return {module:zrender/graphic/Style} The input style. + */ + +function normalizeTextStyle(style) { + normalizeStyle(style); + each$1(style.rich, normalizeStyle); + return style; +} + +function normalizeStyle(style) { + if (style) { + style.font = makeFont(style); + var textAlign = style.textAlign; + textAlign === 'middle' && (textAlign = 'center'); + style.textAlign = textAlign == null || VALID_TEXT_ALIGN[textAlign] ? textAlign : 'left'; // Compatible with textBaseline. + + var textVerticalAlign = style.textVerticalAlign || style.textBaseline; + textVerticalAlign === 'center' && (textVerticalAlign = 'middle'); + style.textVerticalAlign = textVerticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[textVerticalAlign] ? textVerticalAlign : 'top'; + var textPadding = style.textPadding; + + if (textPadding) { + style.textPadding = normalizeCssArray(style.textPadding); + } + } +} +/** + * @param {CanvasRenderingContext2D} ctx + * @param {string} text + * @param {module:zrender/graphic/Style} style + * @param {Object|boolean} [rect] {x, y, width, height} + * If set false, rect text is not used. + * @param {Element|module:zrender/graphic/helper/constant.WILL_BE_RESTORED} [prevEl] For ctx prop cache. + */ + + +function renderText(hostEl, ctx, text, style, rect, prevEl) { + style.rich ? renderRichText(hostEl, ctx, text, style, rect, prevEl) : renderPlainText(hostEl, ctx, text, style, rect, prevEl); +} // Avoid setting to ctx according to prevEl if possible for +// performance in scenarios of large amount text. + +function renderPlainText(hostEl, ctx, text, style, rect, prevEl) { + 'use strict'; + + var needDrawBg = needDrawBackground(style); + var prevStyle; + var checkCache = false; + var cachedByMe = ctx.__attrCachedBy === ContextCachedBy.PLAIN_TEXT; // Only take and check cache for `Text` el, but not RectText. + + if (prevEl !== WILL_BE_RESTORED) { + if (prevEl) { + prevStyle = prevEl.style; + checkCache = !needDrawBg && cachedByMe && prevStyle; + } // Prevent from using cache in `Style::bind`, because of the case: + // ctx property is modified by other properties than `Style::bind` + // used, and Style::bind is called next. + + + ctx.__attrCachedBy = needDrawBg ? ContextCachedBy.NONE : ContextCachedBy.PLAIN_TEXT; + } // Since this will be restored, prevent from using these props to check cache in the next + // entering of this method. But do not need to clear other cache like `Style::bind`. + else if (cachedByMe) { + ctx.__attrCachedBy = ContextCachedBy.NONE; + } + + var styleFont = style.font || DEFAULT_FONT; // PENDING + // Only `Text` el set `font` and keep it (`RectText` will restore). So theoretically + // we can make font cache on ctx, which can cache for text el that are discontinuous. + // But layer save/restore needed to be considered. + // if (styleFont !== ctx.__fontCache) { + // ctx.font = styleFont; + // if (prevEl !== WILL_BE_RESTORED) { + // ctx.__fontCache = styleFont; + // } + // } + + if (!checkCache || styleFont !== (prevStyle.font || DEFAULT_FONT)) { + ctx.font = styleFont; + } // Use the final font from context-2d, because the final + // font might not be the style.font when it is illegal. + // But get `ctx.font` might be time consuming. + + + var computedFont = hostEl.__computedFont; + + if (hostEl.__styleFont !== styleFont) { + hostEl.__styleFont = styleFont; + computedFont = hostEl.__computedFont = ctx.font; + } + + var textPadding = style.textPadding; + var textLineHeight = style.textLineHeight; + var contentBlock = hostEl.__textCotentBlock; + + if (!contentBlock || hostEl.__dirtyText) { + contentBlock = hostEl.__textCotentBlock = parsePlainText(text, computedFont, textPadding, textLineHeight, style.truncate); + } + + var outerHeight = contentBlock.outerHeight; + var textLines = contentBlock.lines; + var lineHeight = contentBlock.lineHeight; + var boxPos = getBoxPosition(_tmpBoxPositionResult, hostEl, style, rect); + var baseX = boxPos.baseX; + var baseY = boxPos.baseY; + var textAlign = boxPos.textAlign || 'left'; + var textVerticalAlign = boxPos.textVerticalAlign; // Origin of textRotation should be the base point of text drawing. + + applyTextRotation(ctx, style, rect, baseX, baseY); + var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign); + var textX = baseX; + var textY = boxY; + + if (needDrawBg || textPadding) { + // Consider performance, do not call getTextWidth util necessary. + var textWidth = getWidth(text, computedFont); + var outerWidth = textWidth; + textPadding && (outerWidth += textPadding[1] + textPadding[3]); + var boxX = adjustTextX(baseX, outerWidth, textAlign); + needDrawBg && drawBackground(hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight); + + if (textPadding) { + textX = getTextXForPadding(baseX, textAlign, textPadding); + textY += textPadding[0]; + } + } // Always set textAlign and textBase line, because it is difficute to calculate + // textAlign from prevEl, and we dont sure whether textAlign will be reset if + // font set happened. + + + ctx.textAlign = textAlign; // Force baseline to be "middle". Otherwise, if using "top", the + // text will offset downward a little bit in font "Microsoft YaHei". + + ctx.textBaseline = 'middle'; // Set text opacity + + ctx.globalAlpha = style.opacity || 1; // Always set shadowBlur and shadowOffset to avoid leak from displayable. + + for (var i = 0; i < SHADOW_STYLE_COMMON_PROPS.length; i++) { + var propItem = SHADOW_STYLE_COMMON_PROPS[i]; + var styleProp = propItem[0]; + var ctxProp = propItem[1]; + var val = style[styleProp]; + + if (!checkCache || val !== prevStyle[styleProp]) { + ctx[ctxProp] = fixShadow(ctx, ctxProp, val || propItem[2]); + } + } // `textBaseline` is set as 'middle'. + + + textY += lineHeight / 2; + var textStrokeWidth = style.textStrokeWidth; + var textStrokeWidthPrev = checkCache ? prevStyle.textStrokeWidth : null; + var strokeWidthChanged = !checkCache || textStrokeWidth !== textStrokeWidthPrev; + var strokeChanged = !checkCache || strokeWidthChanged || style.textStroke !== prevStyle.textStroke; + var textStroke = getStroke(style.textStroke, textStrokeWidth); + var textFill = getFill(style.textFill); + + if (textStroke) { + if (strokeWidthChanged) { + ctx.lineWidth = textStrokeWidth; + } + + if (strokeChanged) { + ctx.strokeStyle = textStroke; + } + } + + if (textFill) { + if (!checkCache || style.textFill !== prevStyle.textFill) { + ctx.fillStyle = textFill; + } + } // Optimize simply, in most cases only one line exists. + + + if (textLines.length === 1) { + // Fill after stroke so the outline will not cover the main part. + textStroke && ctx.strokeText(textLines[0], textX, textY); + textFill && ctx.fillText(textLines[0], textX, textY); + } else { + for (var i = 0; i < textLines.length; i++) { + // Fill after stroke so the outline will not cover the main part. + textStroke && ctx.strokeText(textLines[i], textX, textY); + textFill && ctx.fillText(textLines[i], textX, textY); + textY += lineHeight; + } + } +} + +function renderRichText(hostEl, ctx, text, style, rect, prevEl) { + // Do not do cache for rich text because of the complexity. + // But `RectText` this will be restored, do not need to clear other cache like `Style::bind`. + if (prevEl !== WILL_BE_RESTORED) { + ctx.__attrCachedBy = ContextCachedBy.NONE; + } + + var contentBlock = hostEl.__textCotentBlock; + + if (!contentBlock || hostEl.__dirtyText) { + contentBlock = hostEl.__textCotentBlock = parseRichText(text, style); + } + + drawRichText(hostEl, ctx, contentBlock, style, rect); +} + +function drawRichText(hostEl, ctx, contentBlock, style, rect) { + var contentWidth = contentBlock.width; + var outerWidth = contentBlock.outerWidth; + var outerHeight = contentBlock.outerHeight; + var textPadding = style.textPadding; + var boxPos = getBoxPosition(_tmpBoxPositionResult, hostEl, style, rect); + var baseX = boxPos.baseX; + var baseY = boxPos.baseY; + var textAlign = boxPos.textAlign; + var textVerticalAlign = boxPos.textVerticalAlign; // Origin of textRotation should be the base point of text drawing. + + applyTextRotation(ctx, style, rect, baseX, baseY); + var boxX = adjustTextX(baseX, outerWidth, textAlign); + var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign); + var xLeft = boxX; + var lineTop = boxY; + + if (textPadding) { + xLeft += textPadding[3]; + lineTop += textPadding[0]; + } + + var xRight = xLeft + contentWidth; + needDrawBackground(style) && drawBackground(hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight); + + 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 usedWidth = line.width; + var leftIndex = 0; + var lineXLeft = xLeft; + var lineXRight = xRight; + var rightIndex = tokenCount - 1; + var token; + + while (leftIndex < tokenCount && (token = tokens[leftIndex], !token.textAlign || token.textAlign === 'left')) { + placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft, 'left'); + usedWidth -= token.width; + lineXLeft += token.width; + leftIndex++; + } + + while (rightIndex >= 0 && (token = tokens[rightIndex], token.textAlign === 'right')) { + placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXRight, 'right'); + usedWidth -= token.width; + lineXRight -= token.width; + rightIndex--; + } // The other tokens are placed as textAlign 'center' if there is enough space. + + + lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - usedWidth) / 2; + + while (leftIndex <= rightIndex) { + token = tokens[leftIndex]; // Consider width specified by user, use 'center' rather than 'left'. + + placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center'); + lineXLeft += token.width; + leftIndex++; + } + + lineTop += lineHeight; + } +} + +function applyTextRotation(ctx, style, rect, x, y) { + // textRotation only apply in RectText. + if (rect && style.textRotation) { + var origin = style.textOrigin; + + if (origin === 'center') { + x = rect.width / 2 + rect.x; + y = rect.height / 2 + rect.y; + } else if (origin) { + x = origin[0] + rect.x; + y = origin[1] + rect.y; + } + + ctx.translate(x, y); // Positive: anticlockwise + + ctx.rotate(-style.textRotation); + ctx.translate(-x, -y); + } +} + +function placeToken(hostEl, ctx, token, style, lineHeight, lineTop, x, textAlign) { + var tokenStyle = style.rich[token.styleName] || {}; + tokenStyle.text = token.text; // 'ctx.textBaseline' is always set as 'middle', for sake of + // the bias of "Microsoft YaHei". + + var textVerticalAlign = token.textVerticalAlign; + var y = lineTop + lineHeight / 2; + + if (textVerticalAlign === 'top') { + y = lineTop + token.height / 2; + } else if (textVerticalAlign === 'bottom') { + y = lineTop + lineHeight - token.height / 2; + } + + !token.isLineHolder && needDrawBackground(tokenStyle) && drawBackground(hostEl, ctx, tokenStyle, textAlign === 'right' ? x - token.width : textAlign === 'center' ? x - token.width / 2 : x, y - token.height / 2, token.width, token.height); + var textPadding = token.textPadding; + + if (textPadding) { + x = getTextXForPadding(x, textAlign, textPadding); + y -= token.height / 2 - textPadding[2] - token.textHeight / 2; + } + + setCtx(ctx, 'shadowBlur', retrieve3(tokenStyle.textShadowBlur, style.textShadowBlur, 0)); + setCtx(ctx, 'shadowColor', tokenStyle.textShadowColor || style.textShadowColor || 'transparent'); + setCtx(ctx, 'shadowOffsetX', retrieve3(tokenStyle.textShadowOffsetX, style.textShadowOffsetX, 0)); + setCtx(ctx, 'shadowOffsetY', retrieve3(tokenStyle.textShadowOffsetY, style.textShadowOffsetY, 0)); + setCtx(ctx, 'textAlign', textAlign); // Force baseline to be "middle". Otherwise, if using "top", the + // text will offset downward a little bit in font "Microsoft YaHei". + + setCtx(ctx, 'textBaseline', 'middle'); + setCtx(ctx, 'font', token.font || DEFAULT_FONT); + var textStroke = getStroke(tokenStyle.textStroke || style.textStroke, textStrokeWidth); + var textFill = getFill(tokenStyle.textFill || style.textFill); + var textStrokeWidth = retrieve2(tokenStyle.textStrokeWidth, style.textStrokeWidth); // Fill after stroke so the outline will not cover the main part. + + if (textStroke) { + setCtx(ctx, 'lineWidth', textStrokeWidth); + setCtx(ctx, 'strokeStyle', textStroke); + ctx.strokeText(token.text, x, y); + } + + if (textFill) { + setCtx(ctx, 'fillStyle', textFill); + ctx.fillText(token.text, x, y); + } +} + +function needDrawBackground(style) { + return !!(style.textBackgroundColor || style.textBorderWidth && style.textBorderColor); +} // style: {textBackgroundColor, textBorderWidth, textBorderColor, textBorderRadius, text} +// shape: {x, y, width, height} + + +function drawBackground(hostEl, ctx, style, x, y, width, height) { + var textBackgroundColor = style.textBackgroundColor; + var textBorderWidth = style.textBorderWidth; + var textBorderColor = style.textBorderColor; + var isPlainBg = isString(textBackgroundColor); + setCtx(ctx, 'shadowBlur', style.textBoxShadowBlur || 0); + setCtx(ctx, 'shadowColor', style.textBoxShadowColor || 'transparent'); + setCtx(ctx, 'shadowOffsetX', style.textBoxShadowOffsetX || 0); + setCtx(ctx, 'shadowOffsetY', style.textBoxShadowOffsetY || 0); + + if (isPlainBg || textBorderWidth && textBorderColor) { + ctx.beginPath(); + var textBorderRadius = style.textBorderRadius; + + if (!textBorderRadius) { + ctx.rect(x, y, width, height); + } else { + buildPath(ctx, { + x: x, + y: y, + width: width, + height: height, + r: textBorderRadius + }); + } + + ctx.closePath(); + } + + if (isPlainBg) { + setCtx(ctx, 'fillStyle', textBackgroundColor); + + if (style.fillOpacity != null) { + var originalGlobalAlpha = ctx.globalAlpha; + ctx.globalAlpha = style.fillOpacity * style.opacity; + ctx.fill(); + ctx.globalAlpha = originalGlobalAlpha; + } else { + ctx.fill(); + } + } else if (isObject$1(textBackgroundColor)) { + var image = textBackgroundColor.image; + image = createOrUpdateImage(image, null, hostEl, onBgImageLoaded, textBackgroundColor); + + if (image && isImageReady(image)) { + ctx.drawImage(image, x, y, width, height); + } + } + + if (textBorderWidth && textBorderColor) { + setCtx(ctx, 'lineWidth', textBorderWidth); + setCtx(ctx, 'strokeStyle', textBorderColor); + + if (style.strokeOpacity != null) { + var originalGlobalAlpha = ctx.globalAlpha; + ctx.globalAlpha = style.strokeOpacity * style.opacity; + ctx.stroke(); + ctx.globalAlpha = originalGlobalAlpha; + } else { + ctx.stroke(); + } + } +} + +function onBgImageLoaded(image, textBackgroundColor) { + // Replace image, so that `contain/text.js#parseRichText` + // will get correct result in next tick. + textBackgroundColor.image = image; +} + +function getBoxPosition(out, hostEl, style, rect) { + var baseX = style.x || 0; + var baseY = style.y || 0; + var textAlign = style.textAlign; + var textVerticalAlign = style.textVerticalAlign; // Text position represented by coord + + if (rect) { + var textPosition = style.textPosition; + + if (textPosition instanceof Array) { + // Percent + baseX = rect.x + parsePercent(textPosition[0], rect.width); + baseY = rect.y + parsePercent(textPosition[1], rect.height); + } else { + var res = hostEl && hostEl.calculateTextPosition ? hostEl.calculateTextPosition(_tmpTextPositionResult, style, rect) : calculateTextPosition(_tmpTextPositionResult, style, rect); + baseX = res.x; + baseY = res.y; // Default align and baseline when has textPosition + + textAlign = textAlign || res.textAlign; + textVerticalAlign = textVerticalAlign || res.textVerticalAlign; + } // textOffset is only support in RectText, otherwise + // we have to adjust boundingRect for textOffset. + + + var textOffset = style.textOffset; + + if (textOffset) { + baseX += textOffset[0]; + baseY += textOffset[1]; + } + } + + out = out || {}; + out.baseX = baseX; + out.baseY = baseY; + out.textAlign = textAlign; + out.textVerticalAlign = textVerticalAlign; + return out; +} + +function setCtx(ctx, prop, value) { + ctx[prop] = fixShadow(ctx, prop, value); + return ctx[prop]; +} +/** + * @param {string} [stroke] If specified, do not check style.textStroke. + * @param {string} [lineWidth] If specified, do not check style.textStroke. + * @param {number} style + */ + + +function getStroke(stroke, lineWidth) { + return stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none' ? null // TODO pattern and gradient? + : stroke.image || stroke.colorStops ? '#000' : stroke; +} +function getFill(fill) { + return fill == null || fill === 'none' ? null // TODO pattern and gradient? + : fill.image || fill.colorStops ? '#000' : fill; +} +function parsePercent(value, maxValue) { + if (typeof value === 'string') { + if (value.lastIndexOf('%') >= 0) { + return parseFloat(value) / 100 * maxValue; + } + + return parseFloat(value); + } + + return value; +} + +function getTextXForPadding(x, textAlign, textPadding) { + return textAlign === 'right' ? x - textPadding[1] : textAlign === 'center' ? x + textPadding[3] / 2 - textPadding[1] / 2 : x + textPadding[3]; +} +/** + * @param {string} text + * @param {module:zrender/Style} style + * @return {boolean} + */ + + +function needDrawText(text, style) { + return text != null && (text || style.textBackgroundColor || style.textBorderWidth && style.textBorderColor || style.textPadding); +} + +/** + * Mixin for drawing text in a element bounding rect + * @module zrender/mixin/RectText + */ +var tmpRect$1 = new BoundingRect(); + +var RectText = function () {}; + +RectText.prototype = { + constructor: RectText, + + /** + * Draw text in a rect with specified position. + * @param {CanvasRenderingContext2D} ctx + * @param {Object} rect Displayable rect + */ + drawRectText: function (ctx, rect) { + var style = this.style; + rect = style.textRect || rect; // Optimize, avoid normalize every time. + + this.__dirty && normalizeTextStyle(style, true); + var text = style.text; // Convert to string + + text != null && (text += ''); + + if (!needDrawText(text, style)) { + return; + } // FIXME + // Do not provide prevEl to `textHelper.renderText` for ctx prop cache, + // but use `ctx.save()` and `ctx.restore()`. Because the cache for rect + // text propably break the cache for its host elements. + + + ctx.save(); // Transform rect to view space + + var transform = this.transform; + + if (!style.transformText) { + if (transform) { + tmpRect$1.copy(rect); + tmpRect$1.applyTransform(transform); + rect = tmpRect$1; + } + } else { + this.setTransform(ctx); + } // transformText and textRotation can not be used at the same time. + + + renderText(this, ctx, text, style, rect, WILL_BE_RESTORED); + ctx.restore(); + } +}; + +/** + * Base class of all displayable graphic objects + * @module zrender/graphic/Displayable + */ +/** + * @alias module:zrender/graphic/Displayable + * @extends module:zrender/Element + * @extends module:zrender/graphic/mixin/RectText + */ + +function Displayable(opts) { + opts = opts || {}; + Element.call(this, opts); // Extend properties + + for (var name in opts) { + if (opts.hasOwnProperty(name) && name !== 'style') { + this[name] = opts[name]; + } + } + /** + * @type {module:zrender/graphic/Style} + */ + + + this.style = new Style(opts.style, this); + this._rect = null; // Shapes for cascade clipping. + // Can only be `null`/`undefined` or an non-empty array, MUST NOT be an empty array. + // because it is easy to only using null to check whether clipPaths changed. + + this.__clipPaths = null; // FIXME Stateful must be mixined after style is setted + // Stateful.call(this, opts); +} + +Displayable.prototype = { + constructor: Displayable, + type: 'displayable', + + /** + * Dirty flag. From which painter will determine if this displayable object needs brush. + * @name module:zrender/graphic/Displayable#__dirty + * @type {boolean} + */ + __dirty: true, + + /** + * Whether the displayable object is visible. when it is true, the displayable object + * is not drawn, but the mouse event can still trigger the object. + * @name module:/zrender/graphic/Displayable#invisible + * @type {boolean} + * @default false + */ + invisible: false, + + /** + * @name module:/zrender/graphic/Displayable#z + * @type {number} + * @default 0 + */ + z: 0, + + /** + * @name module:/zrender/graphic/Displayable#z + * @type {number} + * @default 0 + */ + z2: 0, + + /** + * The z level determines the displayable object can be drawn in which layer canvas. + * @name module:/zrender/graphic/Displayable#zlevel + * @type {number} + * @default 0 + */ + zlevel: 0, + + /** + * Whether it can be dragged. + * @name module:/zrender/graphic/Displayable#draggable + * @type {boolean} + * @default false + */ + draggable: false, + + /** + * Whether is it dragging. + * @name module:/zrender/graphic/Displayable#draggable + * @type {boolean} + * @default false + */ + dragging: false, + + /** + * Whether to respond to mouse events. + * @name module:/zrender/graphic/Displayable#silent + * @type {boolean} + * @default false + */ + silent: false, + + /** + * If enable culling + * @type {boolean} + * @default false + */ + culling: false, + + /** + * Mouse cursor when hovered + * @name module:/zrender/graphic/Displayable#cursor + * @type {string} + */ + cursor: 'pointer', + + /** + * If hover area is bounding rect + * @name module:/zrender/graphic/Displayable#rectHover + * @type {string} + */ + rectHover: false, + + /** + * Render the element progressively when the value >= 0, + * usefull for large data. + * @type {boolean} + */ + progressive: false, + + /** + * @type {boolean} + */ + incremental: false, + + /** + * Scale ratio for global scale. + * @type {boolean} + */ + globalScaleRatio: 1, + beforeBrush: function (ctx) {}, + afterBrush: function (ctx) {}, + + /** + * Graphic drawing method. + * @param {CanvasRenderingContext2D} ctx + */ + // Interface + brush: function (ctx, prevEl) {}, + + /** + * Get the minimum bounding box. + * @return {module:zrender/core/BoundingRect} + */ + // Interface + getBoundingRect: function () {}, + + /** + * If displayable element contain coord x, y + * @param {number} x + * @param {number} y + * @return {boolean} + */ + contain: function (x, y) { + return this.rectContain(x, y); + }, + + /** + * @param {Function} cb + * @param {} context + */ + traverse: function (cb, context) { + cb.call(context, this); + }, + + /** + * If bounding rect of element contain coord x, y + * @param {number} x + * @param {number} y + * @return {boolean} + */ + rectContain: function (x, y) { + var coord = this.transformCoordToLocal(x, y); + var rect = this.getBoundingRect(); + return rect.contain(coord[0], coord[1]); + }, + + /** + * Mark displayable element dirty and refresh next frame + */ + dirty: function () { + this.__dirty = this.__dirtyText = true; + this._rect = null; + this.__zr && this.__zr.refresh(); + }, + + /** + * If displayable object binded any event + * @return {boolean} + */ + // TODO, events bound by bind + // isSilent: function () { + // return !( + // this.hoverable || this.draggable + // || this.onmousemove || this.onmouseover || this.onmouseout + // || this.onmousedown || this.onmouseup || this.onclick + // || this.ondragenter || this.ondragover || this.ondragleave + // || this.ondrop + // ); + // }, + + /** + * Alias for animate('style') + * @param {boolean} loop + */ + animateStyle: function (loop) { + return this.animate('style', loop); + }, + attrKV: function (key, value) { + if (key !== 'style') { + Element.prototype.attrKV.call(this, key, value); + } else { + this.style.set(value); + } + }, + + /** + * @param {Object|string} key + * @param {*} value + */ + setStyle: function (key, value) { + this.style.set(key, value); + this.dirty(false); + return this; + }, + + /** + * Use given style object + * @param {Object} obj + */ + useStyle: function (obj) { + this.style = new Style(obj, this); + this.dirty(false); + return this; + }, + + /** + * The string value of `textPosition` needs to be calculated to a real postion. + * For example, `'inside'` is calculated to `[rect.width/2, rect.height/2]` + * by default. See `contain/text.js#calculateTextPosition` for more details. + * But some coutom shapes like "pin", "flag" have center that is not exactly + * `[width/2, height/2]`. So we provide this hook to customize the calculation + * for those shapes. It will be called if the `style.textPosition` is a string. + * @param {Obejct} [out] Prepared out object. If not provided, this method should + * be responsible for creating one. + * @param {module:zrender/graphic/Style} style + * @param {Object} rect {x, y, width, height} + * @return {Obejct} out The same as the input out. + * { + * x: number. mandatory. + * y: number. mandatory. + * textAlign: string. optional. use style.textAlign by default. + * textVerticalAlign: string. optional. use style.textVerticalAlign by default. + * } + */ + calculateTextPosition: null +}; +inherits(Displayable, Element); +mixin(Displayable, RectText); // zrUtil.mixin(Displayable, Stateful); + +/** + * @alias zrender/graphic/Image + * @extends module:zrender/graphic/Displayable + * @constructor + * @param {Object} opts + */ + +function ZImage(opts) { + Displayable.call(this, opts); +} + +ZImage.prototype = { + constructor: ZImage, + type: 'image', + brush: function (ctx, prevEl) { + var style = this.style; + var src = style.image; // Must bind each time + + style.bind(ctx, this, prevEl); + var image = this._image = createOrUpdateImage(src, this._image, this, this.onload); + + if (!image || !isImageReady(image)) { + return; + } // 图片已经加载完成 + // if (image.nodeName.toUpperCase() == 'IMG') { + // if (!image.complete) { + // return; + // } + // } + // Else is canvas + + + var x = style.x || 0; + var y = style.y || 0; + var width = style.width; + var height = style.height; + var aspect = image.width / image.height; + + if (width == null && height != null) { + // Keep image/height ratio + width = height * aspect; + } else if (height == null && width != null) { + height = width / aspect; + } else if (width == null && height == null) { + width = image.width; + height = image.height; + } // 设置transform + + + this.setTransform(ctx); + + 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); + } // Draw rect text + + + if (style.text != null) { + // Only restore transform when needs draw text. + this.restoreTransform(ctx); + this.drawRectText(ctx, this.getBoundingRect()); + } + }, + getBoundingRect: function () { + var style = this.style; + + if (!this._rect) { + this._rect = new BoundingRect(style.x || 0, style.y || 0, style.width || 0, style.height || 0); + } + + return this._rect; + } +}; +inherits(ZImage, Displayable); + +var HOVER_LAYER_ZLEVEL = 1e5; +var CANVAS_ZLEVEL = 314159; +var EL_AFTER_INCREMENTAL_INC = 0.01; +var INCREMENTAL_INC = 0.001; + +function parseInt10(val) { + return parseInt(val, 10); +} + +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; +} + +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); +} + +function isClipPathChanged(clipPaths, prevClipPaths) { + // displayable.__clipPaths can only be `null`/`undefined` or an non-empty array. + if (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 doClip(clipPaths, ctx) { + for (var i = 0; i < clipPaths.length; i++) { + var clipPath = clipPaths[i]; + clipPath.setTransform(ctx); + ctx.beginPath(); + clipPath.buildPath(ctx, clipPath.shape); + ctx.clip(); // Transform back + + clipPath.restoreTransform(ctx); + } +} + +function createRoot(width, height) { + var domRoot = document.createElement('div'); // domRoot.onselectstart = returnFalse; // Avoid page selected + + domRoot.style.cssText = ['position:relative', // IOS13 safari probably has a compositing bug (z order of the canvas and the consequent + // dom does not act as expected) when some of the parent dom has + // `-webkit-overflow-scrolling: touch;` and the webpage is longer than one screen and + // the canvas is not at the top part of the page. + // Check `https://bugs.webkit.org/show_bug.cgi?id=203681` for more details. We remove + // this `overflow:hidden` to avoid the bug. + // 'overflow:hidden', + 'width:' + width + 'px', 'height:' + height + 'px', 'padding:0', 'margin:0', 'border-width:0'].join(';') + ';'; + return domRoot; +} +/** + * @alias module:zrender/Painter + * @constructor + * @param {HTMLElement} root 绘图容器 + * @param {module:zrender/Storage} storage + * @param {Object} opts + */ + + +var Painter = function (root, storage, opts) { + this.type = 'canvas'; // In node environment using node-canvas + + var singleCanvas = !root.nodeName // In node ? + || root.nodeName.toUpperCase() === 'CANVAS'; + this._opts = opts = extend({}, opts || {}); + /** + * @type {number} + */ + + this.dpr = opts.devicePixelRatio || devicePixelRatio; + /** + * @type {boolean} + * @private + */ + + this._singleCanvas = singleCanvas; + /** + * 绘图容器 + * @type {HTMLElement} + */ + + this.root = root; + var rootStyle = root.style; + + if (rootStyle) { + rootStyle['-webkit-tap-highlight-color'] = 'transparent'; + rootStyle['-webkit-user-select'] = rootStyle['user-select'] = rootStyle['-webkit-touch-callout'] = 'none'; + root.innerHTML = ''; + } + /** + * @type {module:zrender/Storage} + */ + + + this.storage = storage; + /** + * @type {Array.} + * @private + */ + + var zlevelList = this._zlevelList = []; + /** + * @type {Object.} + * @private + */ + + var layers = this._layers = {}; + /** + * @type {Object.} + * @private + */ + + this._layerConfig = {}; + /** + * zrender will do compositing when root is a canvas and have multiple zlevels. + */ + + this._needsManuallyCompositing = false; + + if (!singleCanvas) { + this._width = this._getSize(0); + this._height = this._getSize(1); + var domRoot = this._domRoot = createRoot(this._width, this._height); + root.appendChild(domRoot); + } else { + var width = root.width; + var height = root.height; + + if (opts.width != null) { + width = opts.width; + } + + if (opts.height != null) { + height = opts.height; + } + + this.dpr = opts.devicePixelRatio || 1; // Use canvas width and height directly + + root.width = width * this.dpr; + root.height = height * this.dpr; + this._width = width; + this._height = height; // Create layer if only one given canvas + // Device can be specified to create a high dpi image. + + var mainLayer = new Layer(root, this, this.dpr); + mainLayer.__builtin__ = true; + mainLayer.initContext(); // FIXME Use canvas width and height + // mainLayer.resize(width, height); + + layers[CANVAS_ZLEVEL] = mainLayer; + mainLayer.zlevel = CANVAS_ZLEVEL; // Not use common zlevel. + + zlevelList.push(CANVAS_ZLEVEL); + this._domRoot = root; + } + /** + * @type {module:zrender/Layer} + * @private + */ + + + this._hoverlayer = null; + this._hoverElements = []; +}; + +Painter.prototype = { + constructor: Painter, + getType: function () { + return 'canvas'; + }, + + /** + * If painter use a single canvas + * @return {boolean} + */ + isSingleCanvas: function () { + return this._singleCanvas; + }, + + /** + * @return {HTMLDivElement} + */ + getViewportRoot: function () { + return this._domRoot; + }, + getViewportRootOffset: function () { + var viewportRoot = this.getViewportRoot(); + + if (viewportRoot) { + return { + offsetLeft: viewportRoot.offsetLeft || 0, + offsetTop: viewportRoot.offsetTop || 0 + }; + } + }, + + /** + * 刷新 + * @param {boolean} [paintAll=false] 强制绘制所有displayable + */ + refresh: function (paintAll) { + var list = this.storage.getDisplayList(true); + var zlevelList = this._zlevelList; + this._redrawId = Math.random(); + + this._paintList(list, paintAll, this._redrawId); // Paint custum layers + + + 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); + } + } + + this.refreshHover(); + return this; + }, + addHover: function (el, hoverStyle) { + if (el.__hoverMir) { + return; + } + + var elMirror = new el.constructor({ + style: el.style, + shape: el.shape, + z: el.z, + z2: el.z2, + silent: el.silent + }); + elMirror.__from = el; + el.__hoverMir = elMirror; + hoverStyle && elMirror.setStyle(hoverStyle); + + this._hoverElements.push(elMirror); + + return elMirror; + }, + removeHover: function (el) { + var elMirror = el.__hoverMir; + var hoverElements = this._hoverElements; + var idx = indexOf(hoverElements, elMirror); + + if (idx >= 0) { + hoverElements.splice(idx, 1); + } + + el.__hoverMir = null; + }, + clearHover: function (el) { + var hoverElements = this._hoverElements; + + for (var i = 0; i < hoverElements.length; i++) { + var from = hoverElements[i].__from; + + if (from) { + from.__hoverMir = null; + } + } + + hoverElements.length = 0; + }, + refreshHover: function () { + var hoverElements = this._hoverElements; + var len = hoverElements.length; + var hoverLayer = this._hoverlayer; + hoverLayer && hoverLayer.clear(); + + if (!len) { + return; + } + + sort(hoverElements, this.storage.displayableSortFunc); // Use a extream large zlevel + // FIXME? + + if (!hoverLayer) { + hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL); + } + + var scope = {}; + hoverLayer.ctx.save(); + + for (var i = 0; i < len;) { + var el = hoverElements[i]; + var originalEl = el.__from; // Original el is removed + // PENDING + + if (!(originalEl && originalEl.__zr)) { + hoverElements.splice(i, 1); + originalEl.__hoverMir = null; + len--; + continue; + } + + i++; // Use transform + // FIXME style and shape ? + + if (!originalEl.invisible) { + el.transform = originalEl.transform; + el.invTransform = originalEl.invTransform; + el.__clipPaths = originalEl.__clipPaths; // el. + + this._doPaintEl(el, hoverLayer, true, scope); + } + } + + hoverLayer.ctx.restore(); + }, + getHoverLayer: function () { + return this.getLayer(HOVER_LAYER_ZLEVEL); + }, + _paintList: function (list, paintAll, redrawId) { + if (this._redrawId !== redrawId) { + return; + } + + paintAll = paintAll || false; + + this._updateLayerStatus(list); + + var finished = this._doPaintList(list, paintAll); + + if (this._needsManuallyCompositing) { + this._compositeManually(); + } + + if (!finished) { + var self = this; + requestAnimationFrame(function () { + self._paintList(list, paintAll, redrawId); + }); + } + }, + _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); // PENDING, If only builtin layer? + + this.eachBuiltinLayer(function (layer) { + if (layer.virtual) { + ctx.drawImage(layer.dom, 0, 0, width, height); + } + }); + }, + _doPaintList: function (list, paintAll) { + var layerList = []; + + 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; + + for (var k = 0; k < layerList.length; k++) { + var layer = layerList[k]; + var ctx = layer.ctx; + var scope = {}; + ctx.save(); + var start = paintAll ? layer.__startIndex : layer.__drawIndex; + var useTimer = !paintAll && layer.incremental && Date.now; + var startTime = useTimer && Date.now(); + var clearColor = layer.zlevel === this._zlevelList[0] ? this._backgroundColor : null; // All elements in this layer are cleared. + + if (layer.__startIndex === layer.__endIndex) { + layer.clear(false, clearColor); + } else if (start === layer.__startIndex) { + var firstEl = list[start]; + + if (!firstEl.incremental || !firstEl.notClear || paintAll) { + layer.clear(false, clearColor); + } + } + + if (start === -1) { + console.error('For some unknown reason. drawIndex is -1'); + start = layer.__startIndex; + } + + for (var i = start; i < layer.__endIndex; i++) { + var el = list[i]; + + this._doPaintEl(el, layer, paintAll, scope); + + el.__dirty = el.__dirtyText = false; + + if (useTimer) { + // Date.now can be executed in 13,025,305 ops/second. + var dTime = Date.now() - startTime; // Give 15 millisecond to draw. + // The rest elements will be drawn in the next frame. + + if (dTime > 15) { + break; + } + } + } + + layer.__drawIndex = i; + + if (layer.__drawIndex < layer.__endIndex) { + finished = false; + } + + if (scope.prevElClipPaths) { + // Needs restore the state. If last drawn element is in the clipping area. + ctx.restore(); + } + + ctx.restore(); + } + + if (env$1.wxa) { + // Flush for weixin application + each$1(this._layers, function (layer) { + if (layer && layer.ctx && layer.ctx.draw) { + layer.ctx.draw(); + } + }); + } + + return finished; + }, + _doPaintEl: function (el, currentLayer, forcePaint, scope) { + var ctx = currentLayer.ctx; + var m = el.transform; + + if ((currentLayer.__dirty || forcePaint) && // Ignore invisible element + !el.invisible // Ignore transparent element + && el.style.opacity !== 0 // Ignore scale 0 element, in some environment like node-canvas + // Draw a scale 0 element can cause all following draw wrong + // And setTransform with scale 0 will cause set back transform failed. + && !(m && !m[0] && !m[3]) // Ignore culled element + && !(el.culling && isDisplayableCulled(el, this._width, this._height))) { + var clipPaths = el.__clipPaths; + var prevElClipPaths = scope.prevElClipPaths; // Optimize when clipping on group with several elements + + if (!prevElClipPaths || isClipPathChanged(clipPaths, prevElClipPaths)) { + // If has previous clipping state, restore from it + if (prevElClipPaths) { + ctx.restore(); + scope.prevElClipPaths = null; // Reset prevEl since context has been restored + + scope.prevEl = null; + } // New clipping state + + + if (clipPaths) { + ctx.save(); + doClip(clipPaths, ctx); + scope.prevElClipPaths = clipPaths; + } + } + + el.beforeBrush && el.beforeBrush(ctx); + el.brush(ctx, scope.prevEl || null); + scope.prevEl = el; + el.afterBrush && el.afterBrush(ctx); + } + }, + + /** + * 获取 zlevel 所在层,如果不存在则会创建一个新的层 + * @param {number} zlevel + * @param {boolean} virtual Virtual layer will not be inserted into dom. + * @return {module:zrender/Layer} + */ + getLayer: function (zlevel, virtual) { + if (this._singleCanvas && !this._needsManuallyCompositing) { + zlevel = CANVAS_ZLEVEL; + } + + var layer = this._layers[zlevel]; + + if (!layer) { + // Create a new 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); + } + + if (virtual) { + layer.virtual = virtual; + } + + this.insertLayer(zlevel, layer); // Context is created after dom inserted to document + // Or excanvas will get 0px clientWidth and clientHeight + + layer.initContext(); + } + + return layer; + }, + insertLayer: function (zlevel, layer) { + var layersMap = this._layers; + var zlevelList = this._zlevelList; + var len = zlevelList.length; + var prevLayer = null; + var i = -1; + var domRoot = this._domRoot; + + if (layersMap[zlevel]) { + logError$1('ZLevel ' + zlevel + ' has been used already'); + return; + } // Check if is a valid layer + + + if (!isLayerValid(layer)) { + logError$1('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; // Vitual layer will not directly show on the screen. + // (It can be a WebGL layer and assigned to a ZImage element) + // But it still under management of zrender. + + 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); + } + } + } + }, + // Iterate each layer + eachLayer: function (cb, context) { + var zlevelList = this._zlevelList; + var z; + var i; + + for (i = 0; i < zlevelList.length; i++) { + z = zlevelList[i]; + cb.call(context, this._layers[z], z); + } + }, + // Iterate each buildin layer + eachBuiltinLayer: function (cb, context) { + var zlevelList = this._zlevelList; + var layer; + var z; + var i; + + for (i = 0; i < zlevelList.length; i++) { + z = zlevelList[i]; + layer = this._layers[z]; + + if (layer.__builtin__) { + cb.call(context, layer, z); + } + } + }, + // Iterate each other layer except buildin layer + eachOtherLayer: function (cb, context) { + var zlevelList = this._zlevelList; + var layer; + var z; + var i; + + for (i = 0; i < zlevelList.length; i++) { + z = zlevelList[i]; + layer = this._layers[z]; + + if (!layer.__builtin__) { + cb.call(context, layer, z); + } + } + }, + + /** + * 获取所有已创建的层 + * @param {Array.} [prevLayer] + */ + getLayers: function () { + return this._layers; + }, + _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; i < list.length; i++) { + var el = list[i]; + + if (el.zlevel !== list[i - 1].zlevel || el.incremental) { + this._needsManuallyCompositing = true; + break; + } + } + } + + var prevLayer = null; + var incrementalLayerCount = 0; + + for (var i = 0; i < list.length; i++) { + var el = list[i]; + var zlevel = el.zlevel; + var layer; // PENDING If change one incremental element style ? + // TODO Where there are non-incremental elements between incremental elements. + + 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$1('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 { + // Mark layer draw index needs to update. + layer.__drawIndex = -1; + } + + updatePrevLayer(i); + prevLayer = layer; + } + + if (el.__dirty) { + layer.__dirty = true; + + if (layer.incremental && layer.__drawIndex < 0) { + // Start draw from the first dirty element. + layer.__drawIndex = i; + } + } + } + + updatePrevLayer(i); + this.eachBuiltinLayer(function (layer, z) { + // Used in last frame but not in this frame. Needs clear + if (!layer.__used && layer.getElementCount() > 0) { + layer.__dirty = true; + layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0; + } // For incremental layer. In case start index changed and no elements are dirty. + + + if (layer.__dirty && layer.__drawIndex < 0) { + layer.__drawIndex = layer.__startIndex; + } + }); + }, + + /** + * 清除hover层外所有内容 + */ + clear: function () { + this.eachBuiltinLayer(this._clearLayer); + return this; + }, + _clearLayer: function (layer) { + layer.clear(); + }, + setBackgroundColor: function (backgroundColor) { + this._backgroundColor = backgroundColor; + }, + + /** + * 修改指定zlevel的绘制参数 + * + * @param {string} zlevel + * @param {Object} config 配置对象 + * @param {string} [config.clearColor=0] 每次清空画布的颜色 + * @param {string} [config.motionBlur=false] 是否开启动态模糊 + * @param {number} [config.lastFrameAlpha=0.7] + * 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显 + */ + 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); + } + } + } + }, + + /** + * 删除指定层 + * @param {number} zlevel 层所在的zlevel + */ + 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); + }, + + /** + * 区域大小变化后重绘 + */ + resize: function (width, height) { + if (!this._domRoot.style) { + // Maybe in node or worker + if (width == null || height == null) { + return; + } + + this._width = width; + this._height = height; + this.getLayer(CANVAS_ZLEVEL).resize(width, height); + } else { + var domRoot = this._domRoot; // FIXME Why ? + + domRoot.style.display = 'none'; // Save input w/h + + var opts = this._opts; + width != null && (opts.width = width); + height != null && (opts.height = height); + width = this._getSize(0); + height = this._getSize(1); + domRoot.style.display = ''; // 优化没有实际改变的resize + + 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); + } + } + + each$1(this._progressiveLayers, function (layer) { + layer.resize(width, height); + }); + this.refresh(true); + } + + this._width = width; + this._height = height; + } + + return this; + }, + + /** + * 清除单独的一个层 + * @param {number} zlevel + */ + clearLayer: function (zlevel) { + var layer = this._layers[zlevel]; + + if (layer) { + layer.clear(); + } + }, + + /** + * 释放 + */ + dispose: function () { + this.root.innerHTML = ''; + this.root = this.storage = this._domRoot = this._layers = null; + }, + + /** + * Get canvas which has all thing rendered + * @param {Object} opts + * @param {string} [opts.backgroundColor] + * @param {number} [opts.pixelRatio] + */ + 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); + + if (opts.pixelRatio <= this.dpr) { + this.refresh(); + var width = imageLayer.dom.width; + var height = imageLayer.dom.height; + var ctx = imageLayer.ctx; + this.eachLayer(function (layer) { + if (layer.__builtin__) { + ctx.drawImage(layer.dom, 0, 0, width, height); + } else if (layer.renderToCanvas) { + imageLayer.ctx.save(); + layer.renderToCanvas(imageLayer.ctx); + imageLayer.ctx.restore(); + } + }); + } else { + // PENDING, echarts-gl and incremental rendering. + var scope = {}; + var displayList = this.storage.getDisplayList(true); + + for (var i = 0; i < displayList.length; i++) { + var el = displayList[i]; + + this._doPaintEl(el, imageLayer, true, scope); + } + } + + return imageLayer.dom; + }, + + /** + * 获取绘图区域宽度 + */ + getWidth: function () { + return this._width; + }, + + /** + * 获取绘图区域高度 + */ + getHeight: function () { + return this._height; + }, + _getSize: function (whIdx) { + var opts = this._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 root = this.root; // IE8 does not support getComputedStyle, but it use VML. + + 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; + }, + pathToImage: function (path, dpr) { + dpr = dpr || this.dpr; + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); + var rect = path.getBoundingRect(); + var style = path.style; + var shadowBlurSize = style.shadowBlur * dpr; + var shadowOffsetX = style.shadowOffsetX * dpr; + var shadowOffsetY = style.shadowOffsetY * dpr; + var lineWidth = style.hasStroke() ? style.lineWidth : 0; + var leftMargin = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize); + var rightMargin = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize); + var topMargin = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize); + var bottomMargin = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize); + var width = rect.width + leftMargin + rightMargin; + var height = rect.height + topMargin + bottomMargin; + canvas.width = width * dpr; + canvas.height = height * dpr; + ctx.scale(dpr, dpr); + ctx.clearRect(0, 0, width, height); + ctx.dpr = dpr; + var pathTransform = { + position: path.position, + rotation: path.rotation, + scale: path.scale + }; + path.position = [leftMargin - rect.x, topMargin - rect.y]; + path.rotation = 0; + path.scale = [1, 1]; + path.updateTransform(); + + if (path) { + path.brush(ctx); + } + + var ImageShape = ZImage; + var imgShape = new ImageShape({ + style: { + x: 0, + y: 0, + image: canvas + } + }); + + if (pathTransform.position != null) { + imgShape.position = path.position = pathTransform.position; + } + + if (pathTransform.rotation != null) { + imgShape.rotation = path.rotation = pathTransform.rotation; + } + + if (pathTransform.scale != null) { + imgShape.scale = path.scale = pathTransform.scale; + } + + return imgShape; + } +}; + +/** + * 动画主类, 调度和管理所有动画控制器 + * + * @module zrender/animation/Animation + * @author pissang(https://github.com/pissang) + */ +// TODO Additive animation +// http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/ +// https://developer.apple.com/videos/wwdc2014/#236 +/** + * @typedef {Object} IZRenderStage + * @property {Function} update + */ + +/** + * @alias module:zrender/animation/Animation + * @constructor + * @param {Object} [options] + * @param {Function} [options.onframe] + * @param {IZRenderStage} [options.stage] + * @example + * var animation = new Animation(); + * var obj = { + * x: 100, + * y: 100 + * }; + * animation.animate(node.position) + * .when(1000, { + * x: 500, + * y: 500 + * }) + * .when(2000, { + * x: 100, + * y: 100 + * }) + * .start('spline'); + */ + +var Animation = function (options) { + options = options || {}; + this.stage = options.stage || {}; + + this.onframe = options.onframe || function () {}; // private properties + + + this._clips = []; + this._running = false; + this._time; + this._pausedTime; + this._pauseStart; + this._paused = false; + Eventful.call(this); +}; + +Animation.prototype = { + constructor: Animation, + + /** + * 添加 clip + * @param {module:zrender/animation/Clip} clip + */ + addClip: function (clip) { + this._clips.push(clip); + }, + + /** + * 添加 animator + * @param {module:zrender/animation/Animator} animator + */ + addAnimator: function (animator) { + animator.animation = this; + var clips = animator.getClips(); + + for (var i = 0; i < clips.length; i++) { + this.addClip(clips[i]); + } + }, + + /** + * 删除动画片段 + * @param {module:zrender/animation/Clip} clip + */ + removeClip: function (clip) { + var idx = indexOf(this._clips, clip); + + if (idx >= 0) { + this._clips.splice(idx, 1); + } + }, + + /** + * 删除动画片段 + * @param {module:zrender/animation/Animator} animator + */ + removeAnimator: function (animator) { + var clips = animator.getClips(); + + for (var i = 0; i < clips.length; i++) { + this.removeClip(clips[i]); + } + + animator.animation = null; + }, + _update: function () { + var time = new Date().getTime() - this._pausedTime; + + var delta = time - this._time; + var clips = this._clips; + var len = clips.length; + var deferredEvents = []; + var deferredClips = []; + + for (var i = 0; i < len; i++) { + var clip = clips[i]; + var e = clip.step(time, delta); // Throw out the events need to be called after + // stage.update, like destroy + + if (e) { + deferredEvents.push(e); + deferredClips.push(clip); + } + } // Remove the finished clip + + + for (var i = 0; i < len;) { + if (clips[i]._needsRemove) { + clips[i] = clips[len - 1]; + clips.pop(); + len--; + } else { + i++; + } + } + + len = deferredEvents.length; + + for (var i = 0; i < len; i++) { + deferredClips[i].fire(deferredEvents[i]); + } + + this._time = time; + this.onframe(delta); // 'frame' should be triggered before stage, because upper application + // depends on the sequence (e.g., echarts-stream and finish + // event judge) + + this.trigger('frame', delta); + + if (this.stage.update) { + this.stage.update(); + } + }, + _startLoop: function () { + var self = this; + this._running = true; + + function step() { + if (self._running) { + requestAnimationFrame(step); + !self._paused && self._update(); + } + } + + requestAnimationFrame(step); + }, + + /** + * Start animation. + */ + start: function () { + this._time = new Date().getTime(); + this._pausedTime = 0; + + this._startLoop(); + }, + + /** + * Stop animation. + */ + stop: function () { + this._running = false; + }, + + /** + * Pause animation. + */ + pause: function () { + if (!this._paused) { + this._pauseStart = new Date().getTime(); + this._paused = true; + } + }, + + /** + * Resume animation. + */ + resume: function () { + if (this._paused) { + this._pausedTime += new Date().getTime() - this._pauseStart; + this._paused = false; + } + }, + + /** + * Clear animation. + */ + clear: function () { + this._clips = []; + }, + + /** + * Whether animation finished. + */ + isFinished: function () { + return !this._clips.length; + }, + + /** + * Creat animator for a target, whose props can be animated. + * + * @param {Object} target + * @param {Object} options + * @param {boolean} [options.loop=false] Whether loop animation. + * @param {Function} [options.getter=null] Get value from target. + * @param {Function} [options.setter=null] Set value to target. + * @return {module:zrender/animation/Animation~Animator} + */ + // TODO Gap + animate: function (target, options) { + options = options || {}; + var animator = new Animator(target, options.loop, options.getter, options.setter); + this.addAnimator(animator); + return animator; + } +}; +mixin(Animation, Eventful); + +var TOUCH_CLICK_DELAY = 300; +var mouseHandlerNames = ['click', 'dblclick', 'mousewheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu']; +var touchHandlerNames = ['touchstart', 'touchend', 'touchmove']; +var pointerEventNames = { + pointerdown: 1, + pointerup: 1, + pointermove: 1, + pointerout: 1 +}; +var pointerHandlerNames = map(mouseHandlerNames, function (name) { + var nm = name.replace('mouse', 'pointer'); + return pointerEventNames[nm] ? nm : name; +}); + +function eventNameFix(name) { + return name === 'mousewheel' && env$1.browser.firefox ? 'DOMMouseScroll' : name; +} // function onMSGestureChange(proxy, event) { +// if (event.translationX || event.translationY) { +// // mousemove is carried by MSGesture to reduce the sensitivity. +// proxy.handler.dispatchToElement(event.target, 'mousemove', event); +// } +// if (event.scale !== 1) { +// event.pinchX = event.offsetX; +// event.pinchY = event.offsetY; +// event.pinchScale = event.scale; +// proxy.handler.dispatchToElement(event.target, 'pinch', event); +// } +// } + +/** + * Prevent mouse event from being dispatched after Touch Events action + * @see + * 1. Mobile browsers dispatch mouse events 300ms after touchend. + * 2. Chrome for Android dispatch mousedown for long-touch about 650ms + * Result: Blocking Mouse Events for 700ms. + */ + + +function setTouchTimer(instance) { + instance._touching = true; + clearTimeout(instance._touchTimer); + instance._touchTimer = setTimeout(function () { + instance._touching = false; + }, 700); +} + +var domHandlers = { + /** + * Mouse move handler + * @inner + * @param {Event} event + */ + mousemove: function (event) { + event = normalizeEvent(this.dom, event); + this.trigger('mousemove', event); + }, + + /** + * Mouse out handler + * @inner + * @param {Event} event + */ + mouseout: function (event) { + event = normalizeEvent(this.dom, event); + var element = event.toElement || event.relatedTarget; + + if (element !== this.dom) { + while (element && element.nodeType !== 9) { + // 忽略包含在root中的dom引起的mouseOut + if (element === this.dom) { + return; + } + + element = element.parentNode; + } + } + + this.trigger('mouseout', event); + }, + + /** + * Touch开始响应函数 + * @inner + * @param {Event} event + */ + touchstart: function (event) { + // Default mouse behaviour should not be disabled here. + // For example, page may needs to be slided. + event = normalizeEvent(this.dom, event); // Mark touch, which is useful in distinguish touch and + // mouse event in upper applicatoin. + + event.zrByTouch = true; + this._lastTouchMoment = new Date(); + this.handler.processGesture(event, 'start'); // In touch device, trigger `mousemove`(`mouseover`) should + // be triggered, and must before `mousedown` triggered. + + domHandlers.mousemove.call(this, event); + domHandlers.mousedown.call(this, event); + setTouchTimer(this); + }, + + /** + * Touch移动响应函数 + * @inner + * @param {Event} event + */ + touchmove: function (event) { + event = normalizeEvent(this.dom, event); // Mark touch, which is useful in distinguish touch and + // mouse event in upper applicatoin. + + event.zrByTouch = true; + this.handler.processGesture(event, 'change'); // Mouse move should always be triggered no matter whether + // there is gestrue event, because mouse move and pinch may + // be used at the same time. + + domHandlers.mousemove.call(this, event); + setTouchTimer(this); + }, + + /** + * Touch结束响应函数 + * @inner + * @param {Event} event + */ + touchend: function (event) { + event = normalizeEvent(this.dom, event); // Mark touch, which is useful in distinguish touch and + // mouse event in upper applicatoin. + + event.zrByTouch = true; + this.handler.processGesture(event, 'end'); + domHandlers.mouseup.call(this, event); // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is + // triggered in `touchstart`. This seems to be illogical, but by this mechanism, + // we can conveniently implement "hover style" in both PC and touch device just + // by listening to `mouseover` to add "hover style" and listening to `mouseout` + // to remove "hover style" on an element, without any additional code for + // compatibility. (`mouseout` will not be triggered in `touchend`, so "hover + // style" will remain for user view) + // click event should always be triggered no matter whether + // there is gestrue event. System click can not be prevented. + + if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) { + domHandlers.click.call(this, event); + } + + setTouchTimer(this); + }, + pointerdown: function (event) { + domHandlers.mousedown.call(this, event); // if (useMSGuesture(this, event)) { + // this._msGesture.addPointer(event.pointerId); + // } + }, + pointermove: function (event) { + // FIXME + // pointermove is so sensitive that it always triggered when + // tap(click) on touch screen, which affect some judgement in + // upper application. So, we dont support mousemove on MS touch + // device yet. + if (!isPointerFromTouch(event)) { + domHandlers.mousemove.call(this, event); + } + }, + pointerup: function (event) { + domHandlers.mouseup.call(this, event); + }, + pointerout: function (event) { + // pointerout will be triggered when tap on touch screen + // (IE11+/Edge on MS Surface) after click event triggered, + // which is inconsistent with the mousout behavior we defined + // in touchend. So we unify them. + // (check domHandlers.touchend for detailed explanation) + if (!isPointerFromTouch(event)) { + domHandlers.mouseout.call(this, event); + } + } +}; + +function isPointerFromTouch(event) { + var pointerType = event.pointerType; + return pointerType === 'pen' || pointerType === 'touch'; +} // function useMSGuesture(handlerProxy, event) { +// return isPointerFromTouch(event) && !!handlerProxy._msGesture; +// } +// Common handlers + + +each$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) { + domHandlers[name] = function (event) { + event = normalizeEvent(this.dom, event); + this.trigger(name, event); + }; +}); +/** + * 为控制类实例初始化dom 事件处理函数 + * + * @inner + * @param {module:zrender/Handler} instance 控制类实例 + */ + +function initDomHandler(instance) { + each$1(touchHandlerNames, function (name) { + instance._handlers[name] = bind(domHandlers[name], instance); + }); + each$1(pointerHandlerNames, function (name) { + instance._handlers[name] = bind(domHandlers[name], instance); + }); + each$1(mouseHandlerNames, function (name) { + instance._handlers[name] = makeMouseHandler(domHandlers[name], instance); + }); + + function makeMouseHandler(fn, instance) { + return function () { + if (instance._touching) { + return; + } + + return fn.apply(instance, arguments); + }; + } +} + +function HandlerDomProxy(dom) { + Eventful.call(this); + this.dom = dom; + /** + * @private + * @type {boolean} + */ + + this._touching = false; + /** + * @private + * @type {number} + */ + + this._touchTimer; + this._handlers = {}; + initDomHandler(this); + + if (env$1.pointerEventsSupported) { + // Only IE11+/Edge + // 1. On devices that both enable touch and mouse (e.g., MS Surface and lenovo X240), + // IE11+/Edge do not trigger touch event, but trigger pointer event and mouse event + // at the same time. + // 2. On MS Surface, it probablely only trigger mousedown but no mouseup when tap on + // screen, which do not occurs in pointer event. + // So we use pointer event to both detect touch gesture and mouse behavior. + mountHandlers(pointerHandlerNames, this); // FIXME + // Note: MS Gesture require CSS touch-action set. But touch-action is not reliable, + // which does not prevent defuault behavior occasionally (which may cause view port + // zoomed in but use can not zoom it back). And event.preventDefault() does not work. + // So we have to not to use MSGesture and not to support touchmove and pinch on MS + // touch screen. And we only support click behavior on MS touch screen now. + // MS Gesture Event is only supported on IE11+/Edge and on Windows 8+. + // We dont support touch on IE on win7. + // See + // if (typeof MSGesture === 'function') { + // (this._msGesture = new MSGesture()).target = dom; // jshint ignore:line + // dom.addEventListener('MSGestureChange', onMSGestureChange); + // } + } else { + if (env$1.touchEventsSupported) { + mountHandlers(touchHandlerNames, this); // Handler of 'mouseout' event is needed in touch mode, which will be mounted below. + // addEventListener(root, 'mouseout', this._mouseoutHandler); + } // 1. Considering some devices that both enable touch and mouse event (like on MS Surface + // and lenovo X240, @see #2350), we make mouse event be always listened, otherwise + // mouse event can not be handle in those devices. + // 2. On MS Surface, Chrome will trigger both touch event and mouse event. How to prevent + // mouseevent after touch event triggered, see `setTouchTimer`. + + + mountHandlers(mouseHandlerNames, this); + } + + function mountHandlers(handlerNames, instance) { + each$1(handlerNames, function (name) { + addEventListener(dom, eventNameFix(name), instance._handlers[name]); + }, instance); + } +} + +var handlerDomProxyProto = HandlerDomProxy.prototype; + +handlerDomProxyProto.dispose = function () { + var handlerNames = mouseHandlerNames.concat(touchHandlerNames); + + for (var i = 0; i < handlerNames.length; i++) { + var name = handlerNames[i]; + removeEventListener(this.dom, eventNameFix(name), this._handlers[name]); + } +}; + +handlerDomProxyProto.setCursor = function (cursorStyle) { + this.dom.style && (this.dom.style.cursor = cursorStyle || 'default'); +}; + +mixin(HandlerDomProxy, Eventful); + +/*! +* 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 useVML = !env$1.canvasSupported; +var painterCtors = { + canvas: Painter +}; +var instances$1 = {}; // ZRender实例map索引 + +/** + * @type {string} + */ + +var version$1 = '4.1.2'; +/** + * Initializing a zrender instance + * @param {HTMLElement} dom + * @param {Object} [opts] + * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg' + * @param {number} [opts.devicePixelRatio] + * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined) + * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined) + * @return {module:zrender/ZRender} + */ + +function init$1(dom, opts) { + var zr = new ZRender(guid(), dom, opts); + instances$1[zr.id] = zr; + return zr; +} +/** + * Dispose zrender instance + * @param {module:zrender/ZRender} zr + */ + +function dispose$1(zr) { + if (zr) { + zr.dispose(); + } else { + for (var key in instances$1) { + if (instances$1.hasOwnProperty(key)) { + instances$1[key].dispose(); + } + } + + instances$1 = {}; + } + + return this; +} +/** + * Get zrender instance by id + * @param {string} id zrender instance id + * @return {module:zrender/ZRender} + */ + +function getInstance(id) { + return instances$1[id]; +} +function registerPainter(name, Ctor) { + painterCtors[name] = Ctor; +} + +function delInstance(id) { + delete instances$1[id]; +} +/** + * @module zrender/ZRender + */ + +/** + * @constructor + * @alias module:zrender/ZRender + * @param {string} id + * @param {HTMLElement} dom + * @param {Object} opts + * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg' + * @param {number} [opts.devicePixelRatio] + * @param {number} [opts.width] Can be 'auto' (the same as null/undefined) + * @param {number} [opts.height] Can be 'auto' (the same as null/undefined) + */ + + +var ZRender = function (id, dom, opts) { + opts = opts || {}; + /** + * @type {HTMLDomElement} + */ + + this.dom = dom; + /** + * @type {string} + */ + + this.id = id; + var self = this; + var storage = new Storage(); + var rendererType = opts.renderer; // TODO WebGL + + if (useVML) { + if (!painterCtors.vml) { + throw new Error('You need to require \'zrender/vml/vml\' to support IE8'); + } + + rendererType = 'vml'; + } else if (!rendererType || !painterCtors[rendererType]) { + rendererType = 'canvas'; + } + + var painter = new painterCtors[rendererType](dom, storage, opts, id); + this.storage = storage; + this.painter = painter; + var handerProxy = !env$1.node && !env$1.worker ? new HandlerDomProxy(painter.getViewportRoot()) : null; + this.handler = new Handler(storage, painter, handerProxy, painter.root); + /** + * @type {module:zrender/animation/Animation} + */ + + this.animation = new Animation({ + stage: { + update: bind(this.flush, this) + } + }); + this.animation.start(); + /** + * @type {boolean} + * @private + */ + + this._needsRefresh; // 修改 storage.delFromStorage, 每次删除元素之前删除动画 + // FIXME 有点ugly + + var oldDelFromStorage = storage.delFromStorage; + var oldAddToStorage = storage.addToStorage; + + storage.delFromStorage = function (el) { + oldDelFromStorage.call(storage, el); + el && el.removeSelfFromZr(self); + }; + + storage.addToStorage = function (el) { + oldAddToStorage.call(storage, el); + el.addSelfToZr(self); + }; +}; + +ZRender.prototype = { + constructor: ZRender, + + /** + * 获取实例唯一标识 + * @return {string} + */ + getId: function () { + return this.id; + }, + + /** + * 添加元素 + * @param {module:zrender/Element} el + */ + add: function (el) { + this.storage.addRoot(el); + this._needsRefresh = true; + }, + + /** + * 删除元素 + * @param {module:zrender/Element} el + */ + remove: function (el) { + this.storage.delRoot(el); + this._needsRefresh = true; + }, + + /** + * Change configuration of layer + * @param {string} zLevel + * @param {Object} config + * @param {string} [config.clearColor=0] Clear color + * @param {string} [config.motionBlur=false] If enable motion blur + * @param {number} [config.lastFrameAlpha=0.7] Motion blur factor. Larger value cause longer trailer + */ + configLayer: function (zLevel, config) { + if (this.painter.configLayer) { + this.painter.configLayer(zLevel, config); + } + + this._needsRefresh = true; + }, + + /** + * Set background color + * @param {string} backgroundColor + */ + setBackgroundColor: function (backgroundColor) { + if (this.painter.setBackgroundColor) { + this.painter.setBackgroundColor(backgroundColor); + } + + this._needsRefresh = true; + }, + + /** + * Repaint the canvas immediately + */ + refreshImmediately: function () { + // var start = new Date(); + // Clear needsRefresh ahead to avoid something wrong happens in refresh + // Or it will cause zrender refreshes again and again. + this._needsRefresh = this._needsRefreshHover = false; + this.painter.refresh(); // Avoid trigger zr.refresh in Element#beforeUpdate hook + + this._needsRefresh = this._needsRefreshHover = false; // var end = new Date(); + // var log = document.getElementById('log'); + // if (log) { + // log.innerHTML = log.innerHTML + '
' + (end - start); + // } + }, + + /** + * Mark and repaint the canvas in the next frame of browser + */ + refresh: function () { + this._needsRefresh = true; + }, + + /** + * Perform all refresh + */ + flush: function () { + var triggerRendered; + + if (this._needsRefresh) { + triggerRendered = true; + this.refreshImmediately(); + } + + if (this._needsRefreshHover) { + triggerRendered = true; + this.refreshHoverImmediately(); + } + + triggerRendered && this.trigger('rendered'); + }, + + /** + * Add element to hover layer + * @param {module:zrender/Element} el + * @param {Object} style + */ + addHover: function (el, style) { + if (this.painter.addHover) { + var elMirror = this.painter.addHover(el, style); + this.refreshHover(); + return elMirror; + } + }, + + /** + * Add element from hover layer + * @param {module:zrender/Element} el + */ + removeHover: function (el) { + if (this.painter.removeHover) { + this.painter.removeHover(el); + this.refreshHover(); + } + }, + + /** + * Clear all hover elements in hover layer + * @param {module:zrender/Element} el + */ + clearHover: function () { + if (this.painter.clearHover) { + this.painter.clearHover(); + this.refreshHover(); + } + }, + + /** + * Refresh hover in next frame + */ + refreshHover: function () { + this._needsRefreshHover = true; + }, + + /** + * Refresh hover immediately + */ + refreshHoverImmediately: function () { + this._needsRefreshHover = false; + this.painter.refreshHover && this.painter.refreshHover(); + }, + + /** + * Resize the canvas. + * Should be invoked when container size is changed + * @param {Object} [opts] + * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined) + * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined) + */ + resize: function (opts) { + opts = opts || {}; + this.painter.resize(opts.width, opts.height); + this.handler.resize(); + }, + + /** + * Stop and clear all animation immediately + */ + clearAnimation: function () { + this.animation.clear(); + }, + + /** + * Get container width + */ + getWidth: function () { + return this.painter.getWidth(); + }, + + /** + * Get container height + */ + getHeight: function () { + return this.painter.getHeight(); + }, + + /** + * Export the canvas as Base64 URL + * @param {string} type + * @param {string} [backgroundColor='#fff'] + * @return {string} Base64 URL + */ + // toDataURL: function(type, backgroundColor) { + // return this.painter.getRenderedCanvas({ + // backgroundColor: backgroundColor + // }).toDataURL(type); + // }, + + /** + * Converting a path to image. + * It has much better performance of drawing image rather than drawing a vector path. + * @param {module:zrender/graphic/Path} e + * @param {number} width + * @param {number} height + */ + pathToImage: function (e, dpr) { + return this.painter.pathToImage(e, dpr); + }, + + /** + * Set default cursor + * @param {string} [cursorStyle='default'] 例如 crosshair + */ + setCursorStyle: function (cursorStyle) { + this.handler.setCursorStyle(cursorStyle); + }, + + /** + * Find hovered element + * @param {number} x + * @param {number} y + * @return {Object} {target, topTarget} + */ + findHover: function (x, y) { + return this.handler.findHover(x, y); + }, + + /** + * Bind event + * + * @param {string} eventName Event name + * @param {Function} eventHandler Handler function + * @param {Object} [context] Context object + */ + on: function (eventName, eventHandler, context) { + this.handler.on(eventName, eventHandler, context); + }, + + /** + * Unbind event + * @param {string} eventName Event name + * @param {Function} [eventHandler] Handler function + */ + off: function (eventName, eventHandler) { + this.handler.off(eventName, eventHandler); + }, + + /** + * Trigger event manually + * + * @param {string} eventName Event name + * @param {event=} event Event object + */ + trigger: function (eventName, event) { + this.handler.trigger(eventName, event); + }, + + /** + * Clear all objects and the canvas. + */ + clear: function () { + this.storage.delRoot(); + this.painter.clear(); + }, + + /** + * Dispose self. + */ + 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); + } +}; + +var zrender = (Object.freeze || Object)({ + version: version$1, + init: init$1, + dispose: dispose$1, + getInstance: getInstance, + registerPainter: registerPainter +}); + +/* +* 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 each$2 = each$1; +var isObject$2 = isObject$1; +var isArray$1 = isArray; +/** + * 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'; +/** + * 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 } + * } + * @param {Object} opt + * @param {string} key + * @param {Array.} subOpts + */ + +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. + * @param {string|number|Date|Array|Object} dataItem + * @return {number|string|Date|Array.} + */ + +function getDataItemValue(dataItem) { + return isObject$2(dataItem) && !isArray$1(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 + * @param {string|number|Date|Array|Object} dataItem + */ + +function isDataItemOption(dataItem) { + return isObject$2(dataItem) && !(dataItem instanceof Array); // // markLine data can be array + // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array)); +} +/** + * Mapping to exists for merge. + * + * @public + * @param {Array.|Array.} exists + * @param {Object|Array.} newCptOptions + * @return {Array.} Result, like [{exist: ..., option: ...}, {}], + * index of which is the same as exists. + */ + +function mappingToExists(exists, newCptOptions) { + // Mapping by the order by original option (but not order of + // new option) in merge mode. Because we should ensure + // some specified index (like xAxisIndex) is consistent with + // original option, which is easy to understand, espatially in + // media query. And in most case, merge option is used to + // update partial option but not be expected to change order. + newCptOptions = (newCptOptions || []).slice(); + var result = map(exists || [], function (obj, index) { + return { + exist: obj + }; + }); // Mapping by id or name if specified. + + each$2(newCptOptions, function (cptOption, index) { + if (!isObject$2(cptOption)) { + return; + } // id has highest priority. + + + for (var i = 0; i < result.length; i++) { + if (!result[i].option // Consider name: two map to one. + && cptOption.id != null && result[i].exist.id === cptOption.id + '') { + result[i].option = cptOption; + newCptOptions[index] = null; + return; + } + } + + for (var i = 0; i < result.length; i++) { + var exist = result[i].exist; + + if (!result[i].option // Consider name: two map to one. + // Can not match when both ids exist but different. + && (exist.id == null || cptOption.id == null) && cptOption.name != null && !isIdInner(cptOption) && !isIdInner(exist) && exist.name === cptOption.name + '') { + result[i].option = cptOption; + newCptOptions[index] = null; + return; + } + } + }); // Otherwise mapping by index. + + each$2(newCptOptions, function (cptOption, index) { + if (!isObject$2(cptOption)) { + return; + } + + var i = 0; + + for (; i < result.length; i++) { + var exist = result[i].exist; + + if (!result[i].option // Existing model that already has id should be able to + // mapped to (because after mapping performed model may + // be assigned with a id, whish should not affect next + // mapping), except those has inner id. + && !isIdInner(exist) // Caution: + // Do not overwrite id. But name can be overwritten, + // because axis use name as 'show label text'. + // 'exist' always has id and name and we dont + // need to check it. + && cptOption.id == null) { + result[i].option = cptOption; + break; + } + } + + if (i >= result.length) { + result.push({ + option: cptOption + }); + } + }); + return result; +} +/** + * Make id and name for mapping result (result of mappingToExists) + * into `keyInfo` field. + * + * @public + * @param {Array.} Result, like [{exist: ..., option: ...}, {}], + * which order is the same as exists. + * @return {Array.} The input. + */ + +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$2(mapResult, function (item, index) { + var existCpt = item.exist; + existCpt && idMap.set(existCpt.id, item); + }); + each$2(mapResult, function (item, index) { + var opt = item.option; + assert$1(!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$2(mapResult, function (item, index) { + var existCpt = item.exist; + var opt = item.option; + var keyInfo = item.keyInfo; + + if (!isObject$2(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 ? opt.name + '' : existCpt ? existCpt.name // Avoid diffferent series has the same name, + // because name may be used like in color pallet. + : DUMMY_COMPONENT_NAME_PREFIX + index; + + if (existCpt) { + keyInfo.id = existCpt.id; + } else if (opt.id != null) { + keyInfo.id = 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 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} cptOption + * @return {boolean} + */ + +function isIdInner(cptOption) { + return isObject$2(cptOption) && cptOption.id && (cptOption.id + '').indexOf('\0_ec_\0') === 0; +} +/** + * A helper for removing duplicate items between batchA and batchB, + * and in themselves, and categorize by series. + * + * @param {Array.} batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...] + * @param {Array.} batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...] + * @return {Array., Array.>} result: [resultBatchA, resultBatchB] + */ + + +/** + * @param {module:echarts/data/List} data + * @param {Object} payload Contains dataIndex (means rawIndex) / dataIndexInside / name + * each of which can be Array or primary type. + * @return {number|Array.} 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: + * var inner = zrUitl.makeInner(); + * + * function some1(hostObj) { + * inner(hostObj).someProperty = 1212; + * ... + * } + * function some2() { + * var fields = inner(this); + * fields.someProperty1 = 1212; + * fields.someProperty2 = 'xx'; + * ... + * } + * + * @return {Function} + */ + +function makeInner() { + // Consider different scope by es module import. + var key = '__\0ec_inner_' + innerUniqueIndex++ + '_' + Math.random().toFixed(5); + return function (hostObj) { + return hostObj[key] || (hostObj[key] = {}); + }; +} +var innerUniqueIndex = 0; +/** + * @param {module:echarts/model/Global} ecModel + * @param {string|Object} finder + * If string, e.g., 'geo', means {geoIndex: 0}. + * If Object, could contain some of these properties below: + * { + * seriesIndex, seriesId, seriesName, + * geoIndex, geoId, geoName, + * bmapIndex, bmapId, bmapName, + * xAxisIndex, xAxisId, xAxisName, + * yAxisIndex, yAxisId, yAxisName, + * gridIndex, gridId, gridName, + * ... (can be extended) + * } + * Each properties can be number|string|Array.|Array. + * For example, a finder could be + * { + * seriesIndex: 3, + * geoId: ['aa', 'cc'], + * gridName: ['xx', 'rr'] + * } + * xxxIndex can be set as 'all' (means all xxx) or 'none' (means not specify) + * If nothing or null/undefined specified, return nothing. + * @param {Object} [opt] + * @param {string} [opt.defaultMainType] + * @param {Array.} [opt.includeMainTypes] + * @return {Object} result like: + * { + * seriesModels: [seriesModel1, seriesModel2], + * seriesModel: seriesModel1, // The first model + * geoModels: [geoModel1, geoModel2], + * geoModel: geoModel1, // The first model + * ... + * } + */ + +function parseFinder(ecModel, finder, opt) { + if (isString(finder)) { + var obj = {}; + obj[finder + 'Index'] = 0; + finder = obj; + } + + var defaultMainType = opt && opt.defaultMainType; + + if (defaultMainType && !has(finder, defaultMainType + 'Index') && !has(finder, defaultMainType + 'Id') && !has(finder, defaultMainType + 'Name')) { + finder[defaultMainType + 'Index'] = 0; + } + + var result = {}; + each$2(finder, function (value, key) { + var value = finder[key]; // Exclude 'dataIndex' and other illgal keys. + + if (key === 'dataIndex' || key === 'dataIndexInside') { + result[key] = value; + return; + } + + var parsedKey = key.match(/^(\w+)(Index|Id|Name)$/) || []; + var mainType = parsedKey[1]; + var queryType = (parsedKey[2] || '').toLowerCase(); + + if (!mainType || !queryType || value == null || queryType === 'index' && value === 'none' || opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0) { + return; + } + + var queryParam = { + mainType: mainType + }; + + if (queryType !== 'index' || value !== 'all') { + queryParam[queryType] = value; + } + + var models = ecModel.queryComponents(queryParam); + result[mainType + 'Models'] = models; + result[mainType + 'Model'] = models[0]; + }); + return result; +} + +function has(obj, prop) { + return obj && obj.hasOwnProperty(prop); +} + +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$1.domSupported ? 'html' : 'richText'; + } else { + return renderModeOption || 'html'; + } +} +/** + * Group a list by key. + * + * @param {Array} array + * @param {Function} getKey + * param {*} Array item + * return {string} key + * @return {Object} Result + * {Array}: keys, + * {module:zrender/core/util/HashMap} buckets: {key -> Array} + */ + +/* +* 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 TYPE_DELIMITER = '.'; +var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___'; +/** + * Notice, parseClassType('') should returns {main: '', sub: ''} + * @public + */ + +function parseClassType$1(componentType) { + var ret = { + main: '', + sub: '' + }; + + if (componentType) { + componentType = componentType.split(TYPE_DELIMITER); + ret.main = componentType[0] || ''; + ret.sub = componentType[1] || ''; + } + + return ret; +} +/** + * @public + */ + +function checkClassType(componentType) { + assert$1(/^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType), 'componentType "' + componentType + '" illegal'); +} +/** + * @public + */ + + +function enableClassExtend(RootClass, mandatoryMethods) { + RootClass.$constructor = RootClass; + + RootClass.extend = function (proto) { + var superClass = this; + + var ExtendedClass = function () { + if (!proto.$constructor) { + superClass.apply(this, arguments); + } else { + proto.$constructor.apply(this, arguments); + } + }; + + extend(ExtendedClass.prototype, proto); + ExtendedClass.extend = this.extend; + ExtendedClass.superCall = superCall; + ExtendedClass.superApply = superApply; + inherits(ExtendedClass, this); + ExtendedClass.superClass = superClass; + return ExtendedClass; + }; +} +var classBase = 0; +/** + * Can not use instanceof, consider different scope by + * cross domain or es module import in ec extensions. + * Mount a method "isInstance()" to Clz. + */ + +function enableClassCheck(Clz) { + var classAttr = ['__\0is_clz', classBase++, Math.random().toFixed(3)].join('_'); + Clz.prototype[classAttr] = true; + + Clz.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 = slice(arguments, 2); + return this.superClass.prototype[methodName].apply(context, args); +} + +function superApply(context, methodName, args) { + return this.superClass.prototype[methodName].apply(context, args); +} +/** + * @param {Object} entity + * @param {Object} options + * @param {boolean} [options.registerWhenExtend] + * @public + */ + + +function enableClassManagement(entity, options) { + options = options || {}; + /** + * Component model classes + * key: componentType, + * value: + * componentClass, when componentType is 'xxx' + * or Object., when componentType is 'xxx.yy' + * @type {Object} + */ + + var storage = {}; + + entity.registerClass = function (Clazz, componentType) { + if (componentType) { + checkClassType(componentType); + componentType = parseClassType$1(componentType); + + if (!componentType.sub) { + storage[componentType.main] = Clazz; + } else if (componentType.sub !== IS_CONTAINER) { + var container = makeContainer(componentType); + container[componentType.sub] = Clazz; + } + } + + return Clazz; + }; + + entity.getClass = function (componentMainType, subType, throwWhenNotFound) { + var Clazz = storage[componentMainType]; + + if (Clazz && Clazz[IS_CONTAINER]) { + Clazz = subType ? Clazz[subType] : null; + } + + if (throwWhenNotFound && !Clazz) { + throw new Error(!subType ? componentMainType + '.' + 'type should be specified.' : 'Component ' + componentMainType + '.' + (subType || '') + ' not exists. Load it first.'); + } + + return Clazz; + }; + + entity.getClassesByMainType = function (componentType) { + componentType = parseClassType$1(componentType); + var result = []; + var obj = storage[componentType.main]; + + if (obj && obj[IS_CONTAINER]) { + each$1(obj, function (o, type) { + type !== IS_CONTAINER && result.push(o); + }); + } else { + result.push(obj); + } + + return result; + }; + + entity.hasClass = function (componentType) { + // Just consider componentType.main. + componentType = parseClassType$1(componentType); + return !!storage[componentType.main]; + }; + /** + * @return {Array.} Like ['aa', 'bb'], but can not be ['aa.xx'] + */ + + + entity.getAllClassMainTypes = function () { + var types = []; + each$1(storage, function (obj, type) { + types.push(type); + }); + return types; + }; + /** + * If a main type is container and has sub types + * @param {string} mainType + * @return {boolean} + */ + + + entity.hasSubTypes = function (componentType) { + componentType = parseClassType$1(componentType); + var obj = storage[componentType.main]; + return obj && obj[IS_CONTAINER]; + }; + + entity.parseClassType = parseClassType$1; + + function makeContainer(componentType) { + var container = storage[componentType.main]; + + if (!container || !container[IS_CONTAINER]) { + container = storage[componentType.main] = {}; + container[IS_CONTAINER] = true; + } + + return container; + } + + if (options.registerWhenExtend) { + var originalExtend = entity.extend; + + if (originalExtend) { + entity.extend = function (proto) { + var ExtendedClass = originalExtend.call(this, proto); + return entity.registerClass(ExtendedClass, proto.type); + }; + } + } + + return entity; +} +/** + * @param {string|Array.} properties + */ + +/* +* 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. +*/ +// TODO Parse shadow style +// TODO Only shallow path support +var makeStyleMapper = function (properties) { + // Normalize + for (var i = 0; i < properties.length; i++) { + if (!properties[i][1]) { + properties[i][1] = properties[i][0]; + } + } + + 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); + + if (val != null) { + style[properties[i][0]] = val; + } + } + + return style; + }; +}; + +/* +* 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 getLineStyle = makeStyleMapper([['lineWidth', 'width'], ['stroke', 'color'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor']]); +var lineStyleMixin = { + getLineStyle: function (excludes) { + var style = getLineStyle(this, excludes); // Always set lineDash whether dashed, otherwise we can not + // erase the previous style when assigning to el.style. + + style.lineDash = this.getLineDash(style.lineWidth); + return style; + }, + getLineDash: function (lineWidth) { + if (lineWidth == null) { + lineWidth = 1; + } + + var lineType = this.get('type'); + var dotSize = Math.max(lineWidth, 2); + var dashSize = lineWidth * 4; + return lineType === 'solid' || lineType == null ? // Use `false` but not `null` for the solid line here, because `null` might be + // ignored when assigning to `el.style`. e.g., when setting `lineStyle.type` as + // `'dashed'` and `emphasis.lineStyle.type` as `'solid'` in graph series, the + // `lineDash` gotten form the latter one is not able to erase that from the former + // one if using `null` here according to the emhpsis strategy in `util/graphic.js`. + false : lineType === 'dashed' ? [dashSize, dashSize] : [dotSize, dotSize]; + } +}; + +/* +* 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 getAreaStyle = makeStyleMapper([['fill', 'color'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['opacity'], ['shadowColor']]); +var areaStyleMixin = { + getAreaStyle: function (excludes, includes) { + return getAreaStyle(this, excludes, includes); + } +}; + +/** + * 曲线辅助模块 + * @module zrender/core/curve + * @author pissang(https://www.github.com/pissang) + */ +var mathPow = Math.pow; +var mathSqrt$2 = Math.sqrt; +var EPSILON$1 = 1e-8; +var EPSILON_NUMERIC = 1e-4; +var THREE_SQRT = mathSqrt$2(3); +var ONE_THIRD = 1 / 3; // 临时变量 + +var _v0 = create(); + +var _v1 = create(); + +var _v2 = create(); + +function isAroundZero(val) { + return val > -EPSILON$1 && val < EPSILON$1; +} + +function isNotAroundZero$1(val) { + return val > EPSILON$1 || val < -EPSILON$1; +} +/** + * 计算三次贝塞尔值 + * @memberOf module:zrender/core/curve + * @param {number} p0 + * @param {number} p1 + * @param {number} p2 + * @param {number} p3 + * @param {number} t + * @return {number} + */ + + +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); +} +/** + * 计算三次贝塞尔导数值 + * @memberOf module:zrender/core/curve + * @param {number} p0 + * @param {number} p1 + * @param {number} p2 + * @param {number} p3 + * @param {number} t + * @return {number} + */ + +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); +} +/** + * 计算三次贝塞尔方程根,使用盛金公式 + * @memberOf module:zrender/core/curve + * @param {number} p0 + * @param {number} p1 + * @param {number} p2 + * @param {number} p3 + * @param {number} val + * @param {Array.} roots + * @return {number} 有效根数目 + */ + +function cubicRootAt(p0, p1, p2, p3, val, roots) { + // Evaluate roots of cubic functions + 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; //t1, t2, t3, b is not zero + + 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; // t1, a is not zero + + var t2 = -K / 2; // t2, t3 + + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + + if (t2 >= 0 && t2 <= 1) { + roots[n++] = t2; + } + } else if (disc > 0) { + var discSqrt = mathSqrt$2(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$2(A * A * A)); + var theta = Math.acos(T) / 3; + var ASqrt = mathSqrt$2(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; +} +/** + * 计算三次贝塞尔方程极限值的位置 + * @memberOf module:zrender/core/curve + * @param {number} p0 + * @param {number} p1 + * @param {number} p2 + * @param {number} p3 + * @param {Array.} extrema + * @return {number} 有效数目 + */ + +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$1(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$2(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; +} +/** + * 细分三次贝塞尔曲线 + * @memberOf module:zrender/core/curve + * @param {number} p0 + * @param {number} p1 + * @param {number} p2 + * @param {number} p3 + * @param {number} t + * @param {Array.} out + */ + +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; // Seg0 + + out[0] = p0; + out[1] = p01; + out[2] = p012; + out[3] = p0123; // Seg1 + + out[4] = p0123; + out[5] = p123; + out[6] = p23; + out[7] = p3; +} +/** + * 投射点到三次贝塞尔曲线上,返回投射距离。 + * 投射点有可能会有一个或者多个,这里只返回其中距离最短的一个。 + * @param {number} x0 + * @param {number} y0 + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} x3 + * @param {number} y3 + * @param {number} x + * @param {number} y + * @param {Array.} [out] 投射点 + * @return {number} + */ + +function cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, out) { + // http://pomax.github.io/bezierinfo/#projections + var t; + var interval = 0.005; + var d = Infinity; + var prev; + var next; + var d1; + var d2; + _v0[0] = x; + _v0[1] = y; // 先粗略估计一下可能的最小距离的 t 值 + // PENDING + + 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; // At most 32 iteration + + for (var i = 0; i < 32; i++) { + if (interval < EPSILON_NUMERIC) { + break; + } + + prev = t - interval; + next = t + interval; // 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 { + // t + interval + _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; + } + } + } // t + + + if (out) { + out[0] = cubicAt(x0, x1, x2, x3, t); + out[1] = cubicAt(y0, y1, y2, y3, t); + } // console.log(interval, i); + + + return mathSqrt$2(d); +} +/** + * 计算二次方贝塞尔值 + * @param {number} p0 + * @param {number} p1 + * @param {number} p2 + * @param {number} t + * @return {number} + */ + +function quadraticAt(p0, p1, p2, t) { + var onet = 1 - t; + return onet * (onet * p0 + 2 * t * p1) + t * t * p2; +} +/** + * 计算二次方贝塞尔导数值 + * @param {number} p0 + * @param {number} p1 + * @param {number} p2 + * @param {number} t + * @return {number} + */ + +function quadraticDerivativeAt(p0, p1, p2, t) { + return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1)); +} +/** + * 计算二次方贝塞尔方程根 + * @param {number} p0 + * @param {number} p1 + * @param {number} p2 + * @param {number} t + * @param {Array.} roots + * @return {number} 有效根数目 + */ + +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$1(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$2(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; +} +/** + * 计算二次贝塞尔方程极限值 + * @memberOf module:zrender/core/curve + * @param {number} p0 + * @param {number} p1 + * @param {number} p2 + * @return {number} + */ + +function quadraticExtremum(p0, p1, p2) { + var divider = p0 + p2 - 2 * p1; + + if (divider === 0) { + // p1 is center of p0 and p2 + return 0.5; + } else { + return (p0 - p1) / divider; + } +} +/** + * 细分二次贝塞尔曲线 + * @memberOf module:zrender/core/curve + * @param {number} p0 + * @param {number} p1 + * @param {number} p2 + * @param {number} t + * @param {Array.} out + */ + +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; // Seg0 + + out[0] = p0; + out[1] = p01; + out[2] = p012; // Seg1 + + out[3] = p012; + out[4] = p12; + out[5] = p2; +} +/** + * 投射点到二次贝塞尔曲线上,返回投射距离。 + * 投射点有可能会有一个或者多个,这里只返回其中距离最短的一个。 + * @param {number} x0 + * @param {number} y0 + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} x + * @param {number} y + * @param {Array.} out 投射点 + * @return {number} + */ + +function quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, out) { + // http://pomax.github.io/bezierinfo/#projections + var t; + var interval = 0.005; + var d = Infinity; + _v0[0] = x; + _v0[1] = y; // 先粗略估计一下可能的最小距离的 t 值 + // PENDING + + 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; // At most 32 iteration + + for (var i = 0; i < 32; i++) { + if (interval < EPSILON_NUMERIC) { + break; + } + + var prev = t - interval; + var next = t + interval; // 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 { + // t + interval + _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; + } + } + } // t + + + if (out) { + out[0] = quadraticAt(x0, x1, x2, t); + out[1] = quadraticAt(y0, y1, y2, t); + } // console.log(interval, i); + + + return mathSqrt$2(d); +} + +/** + * @author Yi Shen(https://github.com/pissang) + */ +var mathMin$3 = Math.min; +var mathMax$3 = Math.max; +var mathSin$2 = Math.sin; +var mathCos$2 = Math.cos; +var PI2 = Math.PI * 2; +var start = create(); +var end = create(); +var extremity = create(); +/** + * 从顶点数组中计算出最小包围盒,写入`min`和`max`中 + * @module zrender/core/bbox + * @param {Array} points 顶点数组 + * @param {number} min + * @param {number} max + */ + +function fromPoints(points, min$$1, max$$1) { + 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]; + var i; + + for (i = 1; i < points.length; i++) { + p = points[i]; + left = mathMin$3(left, p[0]); + right = mathMax$3(right, p[0]); + top = mathMin$3(top, p[1]); + bottom = mathMax$3(bottom, p[1]); + } + + min$$1[0] = left; + min$$1[1] = top; + max$$1[0] = right; + max$$1[1] = bottom; +} +/** + * @memberOf module:zrender/core/bbox + * @param {number} x0 + * @param {number} y0 + * @param {number} x1 + * @param {number} y1 + * @param {Array.} min + * @param {Array.} max + */ + +function fromLine(x0, y0, x1, y1, min$$1, max$$1) { + min$$1[0] = mathMin$3(x0, x1); + min$$1[1] = mathMin$3(y0, y1); + max$$1[0] = mathMax$3(x0, x1); + max$$1[1] = mathMax$3(y0, y1); +} +var xDim = []; +var yDim = []; +/** + * 从三阶贝塞尔曲线(p0, p1, p2, p3)中计算出最小包围盒,写入`min`和`max`中 + * @memberOf module:zrender/core/bbox + * @param {number} x0 + * @param {number} y0 + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} x3 + * @param {number} y3 + * @param {Array.} min + * @param {Array.} max + */ + +function fromCubic(x0, y0, x1, y1, x2, y2, x3, y3, min$$1, max$$1) { + var cubicExtrema$$1 = cubicExtrema; + var cubicAt$$1 = cubicAt; + var i; + var n = cubicExtrema$$1(x0, x1, x2, x3, xDim); + min$$1[0] = Infinity; + min$$1[1] = Infinity; + max$$1[0] = -Infinity; + max$$1[1] = -Infinity; + + for (i = 0; i < n; i++) { + var x = cubicAt$$1(x0, x1, x2, x3, xDim[i]); + min$$1[0] = mathMin$3(x, min$$1[0]); + max$$1[0] = mathMax$3(x, max$$1[0]); + } + + n = cubicExtrema$$1(y0, y1, y2, y3, yDim); + + for (i = 0; i < n; i++) { + var y = cubicAt$$1(y0, y1, y2, y3, yDim[i]); + min$$1[1] = mathMin$3(y, min$$1[1]); + max$$1[1] = mathMax$3(y, max$$1[1]); + } + + min$$1[0] = mathMin$3(x0, min$$1[0]); + max$$1[0] = mathMax$3(x0, max$$1[0]); + min$$1[0] = mathMin$3(x3, min$$1[0]); + max$$1[0] = mathMax$3(x3, max$$1[0]); + min$$1[1] = mathMin$3(y0, min$$1[1]); + max$$1[1] = mathMax$3(y0, max$$1[1]); + min$$1[1] = mathMin$3(y3, min$$1[1]); + max$$1[1] = mathMax$3(y3, max$$1[1]); +} +/** + * 从二阶贝塞尔曲线(p0, p1, p2)中计算出最小包围盒,写入`min`和`max`中 + * @memberOf module:zrender/core/bbox + * @param {number} x0 + * @param {number} y0 + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {Array.} min + * @param {Array.} max + */ + +function fromQuadratic(x0, y0, x1, y1, x2, y2, min$$1, max$$1) { + var quadraticExtremum$$1 = quadraticExtremum; + var quadraticAt$$1 = quadraticAt; // Find extremities, where derivative in x dim or y dim is zero + + var tx = mathMax$3(mathMin$3(quadraticExtremum$$1(x0, x1, x2), 1), 0); + var ty = mathMax$3(mathMin$3(quadraticExtremum$$1(y0, y1, y2), 1), 0); + var x = quadraticAt$$1(x0, x1, x2, tx); + var y = quadraticAt$$1(y0, y1, y2, ty); + min$$1[0] = mathMin$3(x0, x2, x); + min$$1[1] = mathMin$3(y0, y2, y); + max$$1[0] = mathMax$3(x0, x2, x); + max$$1[1] = mathMax$3(y0, y2, y); +} +/** + * 从圆弧中计算出最小包围盒,写入`min`和`max`中 + * @method + * @memberOf module:zrender/core/bbox + * @param {number} x + * @param {number} y + * @param {number} rx + * @param {number} ry + * @param {number} startAngle + * @param {number} endAngle + * @param {number} anticlockwise + * @param {Array.} min + * @param {Array.} max + */ + +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) { + // Is a circle + min$$1[0] = x - rx; + min$$1[1] = y - ry; + max$$1[0] = x + rx; + max$$1[1] = y + ry; + return; + } + + start[0] = mathCos$2(startAngle) * rx + x; + start[1] = mathSin$2(startAngle) * ry + y; + end[0] = mathCos$2(endAngle) * rx + x; + end[1] = mathSin$2(endAngle) * ry + y; + vec2Min(min$$1, start, end); + vec2Max(max$$1, start, end); // Thresh to [0, Math.PI * 2] + + 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; + } // var number = 0; + // var step = (anticlockwise ? -Math.PI : Math.PI) / 2; + + + for (var angle = 0; angle < endAngle; angle += Math.PI / 2) { + if (angle > startAngle) { + extremity[0] = mathCos$2(angle) * rx + x; + extremity[1] = mathSin$2(angle) * ry + y; + vec2Min(min$$1, extremity, min$$1); + vec2Max(max$$1, extremity, max$$1); + } + } +} + +/** + * Path 代理,可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中 + * 可以用于 isInsidePath 判断以及获取boundingRect + * + * @module zrender/core/PathProxy + * @author Yi Shen (http://www.github.com/pissang) + */ +// TODO getTotalLength, getPointAtLength + +/* global Float32Array */ +var CMD = { + M: 1, + L: 2, + C: 3, + Q: 4, + A: 5, + Z: 6, + // Rect + R: 7 +}; // var CMD_MEM_SIZE = { +// M: 3, +// L: 3, +// C: 7, +// Q: 5, +// A: 9, +// R: 5, +// Z: 1 +// }; + +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 mathSqrt$1 = Math.sqrt; +var mathAbs = Math.abs; +var hasTypedArray = typeof Float32Array !== 'undefined'; +/** + * @alias module:zrender/core/PathProxy + * @constructor + */ + +var PathProxy = function (notSaveData) { + this._saveData = !(notSaveData || false); + + if (this._saveData) { + /** + * Path data. Stored as flat array + * @type {Array.} + */ + this.data = []; + } + + this._ctx = null; +}; +/** + * 快速计算Path包围盒(并不是最小包围盒) + * @return {Object} + */ + + +PathProxy.prototype = { + constructor: PathProxy, + _xi: 0, + _yi: 0, + _x0: 0, + _y0: 0, + // Unit x, Unit y. Provide for avoiding drawing that too short line segment + _ux: 0, + _uy: 0, + _len: 0, + _lineDash: null, + _dashOffset: 0, + _dashIdx: 0, + _dashSum: 0, + + /** + * @readOnly + */ + setScale: function (sx, sy, segmentIgnoreThreshold) { + // Compat. Previously there is no segmentIgnoreThreshold. + segmentIgnoreThreshold = segmentIgnoreThreshold || 0; + this._ux = mathAbs(segmentIgnoreThreshold / devicePixelRatio / sx) || 0; + this._uy = mathAbs(segmentIgnoreThreshold / devicePixelRatio / sy) || 0; + }, + getContext: function () { + return this._ctx; + }, + + /** + * @param {CanvasRenderingContext2D} ctx + * @return {module:zrender/core/PathProxy} + */ + beginPath: function (ctx) { + this._ctx = ctx; + ctx && ctx.beginPath(); + ctx && (this.dpr = ctx.dpr); // Reset + + if (this._saveData) { + this._len = 0; + } + + if (this._lineDash) { + this._lineDash = null; + this._dashOffset = 0; + } + + return this; + }, + + /** + * @param {number} x + * @param {number} y + * @return {module:zrender/core/PathProxy} + */ + moveTo: function (x, y) { + this.addData(CMD.M, x, y); + this._ctx && this._ctx.moveTo(x, y); // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用 + // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。 + // 有可能在 beginPath 之后直接调用 lineTo,这时候 x0, y0 需要 + // 在 lineTo 方法中记录,这里先不考虑这种情况,dashed line 也只在 IE10- 中不支持 + + this._x0 = x; + this._y0 = y; + this._xi = x; + this._yi = y; + return this; + }, + + /** + * @param {number} x + * @param {number} y + * @return {module:zrender/core/PathProxy} + */ + lineTo: function (x, y) { + var exceedUnit = mathAbs(x - this._xi) > this._ux || mathAbs(y - this._yi) > this._uy // Force draw the first segment + || this._len < 5; + this.addData(CMD.L, x, y); + + if (this._ctx && exceedUnit) { + this._needsDash() ? this._dashedLineTo(x, y) : this._ctx.lineTo(x, y); + } + + if (exceedUnit) { + this._xi = x; + this._yi = y; + } + + return this; + }, + + /** + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} x3 + * @param {number} y3 + * @return {module:zrender/core/PathProxy} + */ + bezierCurveTo: function (x1, y1, x2, y2, x3, y3) { + this.addData(CMD.C, x1, y1, x2, y2, x3, y3); + + if (this._ctx) { + this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3) : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3); + } + + this._xi = x3; + this._yi = y3; + return this; + }, + + /** + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @return {module:zrender/core/PathProxy} + */ + quadraticCurveTo: function (x1, y1, x2, y2) { + this.addData(CMD.Q, x1, y1, x2, y2); + + if (this._ctx) { + this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2) : this._ctx.quadraticCurveTo(x1, y1, x2, y2); + } + + this._xi = x2; + this._yi = y2; + return this; + }, + + /** + * @param {number} cx + * @param {number} cy + * @param {number} r + * @param {number} startAngle + * @param {number} endAngle + * @param {boolean} anticlockwise + * @return {module:zrender/core/PathProxy} + */ + arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) { + this.addData(CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 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; + }, + // TODO + arcTo: function (x1, y1, x2, y2, radius) { + if (this._ctx) { + this._ctx.arcTo(x1, y1, x2, y2, radius); + } + + return this; + }, + // TODO + rect: function (x, y, w, h) { + this._ctx && this._ctx.rect(x, y, w, h); + this.addData(CMD.R, x, y, w, h); + return this; + }, + + /** + * @return {module:zrender/core/PathProxy} + */ + closePath: function () { + this.addData(CMD.Z); + var ctx = this._ctx; + var x0 = this._x0; + var y0 = this._y0; + + if (ctx) { + this._needsDash() && this._dashedLineTo(x0, y0); + ctx.closePath(); + } + + this._xi = x0; + this._yi = y0; + return this; + }, + + /** + * Context 从外部传入,因为有可能是 rebuildPath 完之后再 fill。 + * stroke 同样 + * @param {CanvasRenderingContext2D} ctx + * @return {module:zrender/core/PathProxy} + */ + fill: function (ctx) { + ctx && ctx.fill(); + this.toStatic(); + }, + + /** + * @param {CanvasRenderingContext2D} ctx + * @return {module:zrender/core/PathProxy} + */ + stroke: function (ctx) { + ctx && ctx.stroke(); + this.toStatic(); + }, + + /** + * 必须在其它绘制命令前调用 + * Must be invoked before all other path drawing methods + * @return {module:zrender/core/PathProxy} + */ + setLineDash: function (lineDash) { + if (lineDash instanceof Array) { + this._lineDash = lineDash; + this._dashIdx = 0; + var lineDashSum = 0; + + for (var i = 0; i < lineDash.length; i++) { + lineDashSum += lineDash[i]; + } + + this._dashSum = lineDashSum; + } + + return this; + }, + + /** + * 必须在其它绘制命令前调用 + * Must be invoked before all other path drawing methods + * @return {module:zrender/core/PathProxy} + */ + setLineDashOffset: function (offset) { + this._dashOffset = offset; + return this; + }, + + /** + * + * @return {boolean} + */ + len: function () { + return this._len; + }, + + /** + * 直接设置 Path 数据 + */ + setData: function (data) { + var len$$1 = data.length; + + if (!(this.data && this.data.length === len$$1) && hasTypedArray) { + this.data = new Float32Array(len$$1); + } + + for (var i = 0; i < len$$1; i++) { + this.data[i] = data[i]; + } + + this._len = len$$1; + }, + + /** + * 添加子路径 + * @param {module:zrender/core/PathProxy|Array.} path + */ + appendPath: function (path) { + if (!(path instanceof Array)) { + path = [path]; + } + + var len$$1 = path.length; + var appendSize = 0; + var offset = this._len; + + for (var i = 0; i < len$$1; i++) { + appendSize += path[i].len(); + } + + if (hasTypedArray && this.data instanceof Float32Array) { + this.data = new Float32Array(offset + appendSize); + } + + for (var i = 0; i < len$$1; i++) { + var appendPathData = path[i].data; + + for (var k = 0; k < appendPathData.length; k++) { + this.data[offset++] = appendPathData[k]; + } + } + + this._len = offset; + }, + + /** + * 填充 Path 数据。 + * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。 + */ + addData: function (cmd) { + if (!this._saveData) { + return; + } + + var data = this.data; + + if (this._len + arguments.length > data.length) { + // 因为之前的数组已经转换成静态的 Float32Array + // 所以不够用时需要扩展一个新的动态数组 + this._expandData(); + + data = this.data; + } + + for (var i = 0; i < arguments.length; i++) { + data[this._len++] = arguments[i]; + } + + this._prevCmd = cmd; + }, + _expandData: function () { + // Only if data is Float32Array + if (!(this.data instanceof Array)) { + var newData = []; + + for (var i = 0; i < this._len; i++) { + newData[i] = this.data[i]; + } + + this.data = newData; + } + }, + + /** + * If needs js implemented dashed line + * @return {boolean} + * @private + */ + _needsDash: function () { + return this._lineDash; + }, + _dashedLineTo: function (x1, y1) { + var dashSum = this._dashSum; + var offset = this._dashOffset; + var lineDash = this._lineDash; + var ctx = this._ctx; + var x0 = this._xi; + var y0 = this._yi; + var dx = x1 - x0; + var dy = y1 - y0; + var dist$$1 = mathSqrt$1(dx * dx + dy * dy); + var x = x0; + var y = y0; + var dash; + var nDash = lineDash.length; + var idx; + dx /= dist$$1; + dy /= dist$$1; + + if (offset < 0) { + // Convert to positive offset + offset = dashSum + offset; + } + + offset %= dashSum; + x -= offset * dx; + y -= offset * dy; + + while (dx > 0 && x <= x1 || dx < 0 && x >= x1 || dx === 0 && (dy > 0 && y <= y1 || dy < 0 && y >= y1)) { + idx = this._dashIdx; + dash = lineDash[idx]; + x += dx * dash; + y += dy * dash; + this._dashIdx = (idx + 1) % nDash; // Skip positive offset + + if (dx > 0 && x < x0 || dx < 0 && x > x0 || dy > 0 && y < y0 || dy < 0 && y > y0) { + continue; + } + + ctx[idx % 2 ? 'moveTo' : 'lineTo'](dx >= 0 ? mathMin$2(x, x1) : mathMax$2(x, x1), dy >= 0 ? mathMin$2(y, y1) : mathMax$2(y, y1)); + } // Offset for next lineTo + + + dx = x - x1; + dy = y - y1; + this._dashOffset = -mathSqrt$1(dx * dx + dy * dy); + }, + // Not accurate dashed line to + _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) { + var dashSum = this._dashSum; + var offset = this._dashOffset; + var lineDash = this._lineDash; + var ctx = this._ctx; + var x0 = this._xi; + var y0 = this._yi; + var t; + var dx; + var dy; + var cubicAt$$1 = cubicAt; + var bezierLen = 0; + var idx = this._dashIdx; + var nDash = lineDash.length; + var x; + var y; + var tmpLen = 0; + + if (offset < 0) { + // Convert to positive offset + offset = dashSum + offset; + } + + offset %= dashSum; // Bezier approx length + + for (t = 0; t < 1; t += 0.1) { + dx = cubicAt$$1(x0, x1, x2, x3, t + 0.1) - cubicAt$$1(x0, x1, x2, x3, t); + dy = cubicAt$$1(y0, y1, y2, y3, t + 0.1) - cubicAt$$1(y0, y1, y2, y3, t); + bezierLen += mathSqrt$1(dx * dx + dy * dy); + } // Find idx after add offset + + + for (; idx < nDash; idx++) { + tmpLen += lineDash[idx]; + + if (tmpLen > offset) { + break; + } + } + + t = (tmpLen - offset) / bezierLen; + + while (t <= 1) { + x = cubicAt$$1(x0, x1, x2, x3, t); + y = cubicAt$$1(y0, y1, y2, y3, t); // Use line to approximate dashed bezier + // Bad result if dash is long + + idx % 2 ? ctx.moveTo(x, y) : ctx.lineTo(x, y); + t += lineDash[idx] / bezierLen; + idx = (idx + 1) % nDash; + } // Finish the last segment and calculate the new offset + + + idx % 2 !== 0 && ctx.lineTo(x3, y3); + dx = x3 - x; + dy = y3 - y; + this._dashOffset = -mathSqrt$1(dx * dx + dy * dy); + }, + _dashedQuadraticTo: function (x1, y1, x2, y2) { + // Convert quadratic to cubic using degree elevation + var x3 = x2; + var y3 = y2; + x2 = (x2 + 2 * x1) / 3; + y2 = (y2 + 2 * y1) / 3; + x1 = (this._xi + 2 * x1) / 3; + y1 = (this._yi + 2 * y1) / 3; + + this._dashedBezierTo(x1, y1, x2, y2, x3, y3); + }, + + /** + * 转成静态的 Float32Array 减少堆内存占用 + * Convert dynamic array to static Float32Array + */ + toStatic: function () { + var data = this.data; + + if (data instanceof Array) { + data.length = this._len; + + if (hasTypedArray) { + this.data = new Float32Array(data); + } + } + }, + + /** + * @return {module:zrender/core/BoundingRect} + */ + 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; + + for (var i = 0; i < data.length;) { + var cmd = data[i++]; + + if (i === 1) { + // 如果第一个命令是 L, C, Q + // 则 previous point 同绘制命令的第一个 point + // + // 第一个命令为 Arc 的情况下会在后面特殊处理 + xi = data[i]; + yi = data[i + 1]; + x0 = xi; + y0 = yi; + } + + switch (cmd) { + case CMD.M: + // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点 + // 在 closePath 的时候使用 + x0 = data[i++]; + y0 = data[i++]; + xi = x0; + yi = y0; + 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: + // TODO Arc 判断的开销比较大 + 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; // TODO Arc 旋转 + + i += 1; + var anticlockwise = 1 - data[i++]; + + if (i === 1) { + // 直接使用 arc 命令 + // 第一个命令起点还未定义 + 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++]; // Use fromLine + + fromLine(x0, y0, x0 + width, y0 + height, min2, max2); + break; + + case CMD.Z: + xi = x0; + yi = y0; + break; + } // Union + + + min(min$1, min$1, min2); + max(max$1, max$1, max2); + } // No data + + + 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]); + }, + + /** + * Rebuild path from current data + * Rebuild path will not consider javascript implemented line dash. + * @param {CanvasRenderingContext2D} ctx + */ + rebuildPath: function (ctx) { + var d = this.data; + var x0; + var y0; + var xi; + var yi; + var x; + var y; + var ux = this._ux; + var uy = this._uy; + var len$$1 = this._len; + + for (var i = 0; i < len$$1;) { + var cmd = d[i++]; + + if (i === 1) { + // 如果第一个命令是 L, C, Q + // 则 previous point 同绘制命令的第一个 point + // + // 第一个命令为 Arc 的情况下会在后面特殊处理 + xi = d[i]; + yi = d[i + 1]; + x0 = xi; + y0 = yi; + } + + 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++]; // Not draw too small seg between + + if (mathAbs(x - xi) > ux || mathAbs(y - yi) > uy || i === len$$1 - 1) { + ctx.lineTo(x, y); + xi = x; + yi = y; + } + + break; + + case CMD.C: + ctx.bezierCurveTo(d[i++], d[i++], d[i++], d[i++], d[i++], d[i++]); + xi = d[i - 2]; + yi = d[i - 1]; + break; + + case CMD.Q: + ctx.quadraticCurveTo(d[i++], d[i++], d[i++], d[i++]); + xi = d[i - 2]; + yi = d[i - 1]; + break; + + case CMD.A: + var cx = d[i++]; + var cy = d[i++]; + var rx = d[i++]; + var ry = d[i++]; + var theta = d[i++]; + var dTheta = d[i++]; + var psi = d[i++]; + var fs = d[i++]; + var r = rx > ry ? rx : ry; + var scaleX = rx > ry ? 1 : rx / ry; + var scaleY = rx > ry ? ry / rx : 1; + var isEllipse = Math.abs(rx - ry) > 1e-3; + var endAngle = theta + dTheta; + + if (isEllipse) { + ctx.translate(cx, cy); + ctx.rotate(psi); + ctx.scale(scaleX, scaleY); + ctx.arc(0, 0, r, theta, endAngle, 1 - fs); + ctx.scale(1 / scaleX, 1 / scaleY); + ctx.rotate(-psi); + ctx.translate(-cx, -cy); + } else { + ctx.arc(cx, cy, r, theta, endAngle, 1 - fs); + } + + if (i === 1) { + // 直接使用 arc 命令 + // 第一个命令起点还未定义 + x0 = mathCos$1(theta) * rx + cx; + y0 = mathSin$1(theta) * 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]; + ctx.rect(d[i++], d[i++], d[i++], d[i++]); + break; + + case CMD.Z: + ctx.closePath(); + xi = x0; + yi = y0; + } + } + } +}; +PathProxy.CMD = CMD; + +/** + * 线段包含判断 + * @param {number} x0 + * @param {number} y0 + * @param {number} x1 + * @param {number} y1 + * @param {number} lineWidth + * @param {number} x + * @param {number} y + * @return {boolean} + */ +function containStroke$1(x0, y0, x1, y1, lineWidth, x, y) { + if (lineWidth === 0) { + return false; + } + + var _l = lineWidth; + var _a = 0; + var _b = x0; // Quick reject + + 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; +} + +/** + * 三次贝塞尔曲线描边包含判断 + * @param {number} x0 + * @param {number} y0 + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} x3 + * @param {number} y3 + * @param {number} lineWidth + * @param {number} x + * @param {number} y + * @return {boolean} + */ + +function containStroke$2(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) { + if (lineWidth === 0) { + return false; + } + + var _l = lineWidth; // Quick reject + + 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; +} + +/** + * 二次贝塞尔曲线描边包含判断 + * @param {number} x0 + * @param {number} y0 + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} lineWidth + * @param {number} x + * @param {number} y + * @return {boolean} + */ + +function containStroke$3(x0, y0, x1, y1, x2, y2, lineWidth, x, y) { + if (lineWidth === 0) { + return false; + } + + var _l = lineWidth; // Quick reject + + 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$3 = Math.PI * 2; +function normalizeRadian(angle) { + angle %= PI2$3; + + if (angle < 0) { + angle += PI2$3; + } + + return angle; +} + +var PI2$2 = Math.PI * 2; +/** + * 圆弧描边包含判断 + * @param {number} cx + * @param {number} cy + * @param {number} r + * @param {number} startAngle + * @param {number} endAngle + * @param {boolean} anticlockwise + * @param {number} lineWidth + * @param {number} x + * @param {number} y + * @return {Boolean} + */ + +function containStroke$4(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$2 < 1e-4) { + // Is a circle + 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$2; + } + + var angle = Math.atan2(y, x); + + if (angle < 0) { + angle += PI2$2; + } + + return angle >= startAngle && angle <= endAngle || angle + PI2$2 >= startAngle && angle + PI2$2 <= endAngle; +} + +function windingLine(x0, y0, x1, y1, x, y) { + if (y > y0 && y > y1 || y < y0 && y < y1) { + return 0; + } // Ignore horizontal line + + + if (y1 === y0) { + return 0; + } + + var dir = y1 < y0 ? 1 : -1; + var t = (y - y0) / (y1 - y0); // Avoid winding error when intersection point is the connect point of two line of polygon + + if (t === 1 || t === 0) { + dir = y1 < y0 ? 0.5 : -0.5; + } + + var x_ = t * (x1 - x0) + x0; // If (x, y) on the line, considered as "contain". + + return x_ === x ? Infinity : x_ > x ? dir : 0; +} + +var CMD$1 = PathProxy.CMD; +var PI2$1 = Math.PI * 2; +var EPSILON$2 = 1e-4; + +function isAroundEqual(a, b) { + return Math.abs(a - b) < EPSILON$2; +} // 临时数组 + + +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) { + // Quick reject + 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_; + var y1_; + + for (var i = 0; i < nRoots; i++) { + var t = roots[i]; // Avoid winding error when intersection point is the connect point of two line of polygon + + var unit = t === 0 || t === 1 ? 0.5 : 1; + var x_ = cubicAt(x0, x1, x2, x3, t); + + if (x_ < x) { + // Quick reject + 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) { + // Quick reject + 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++) { + // Remove one endpoint. + var unit = roots[i] === 0 || roots[i] === 1 ? 0.5 : 1; + var x_ = quadraticAt(x0, x1, x2, roots[i]); + + if (x_ < x) { + // Quick reject + continue; + } + + if (roots[i] < t) { + w += y_ < y0 ? unit : -unit; + } else { + w += y2 < y_ ? unit : -unit; + } + } + + return w; + } else { + // Remove one endpoint. + var unit = roots[0] === 0 || roots[0] === 1 ? 0.5 : 1; + var x_ = quadraticAt(x0, x1, x2, roots[0]); + + if (x_ < x) { + // Quick reject + return 0; + } + + return y2 < y0 ? unit : -unit; + } + } +} // TODO +// Arc 旋转 + + +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 diff = Math.abs(startAngle - endAngle); + + if (diff < 1e-4) { + return 0; + } + + if (diff % PI2$1 < 1e-4) { + // Is a circle + startAngle = 0; + endAngle = PI2$1; + var dir = anticlockwise ? 1 : -1; + + if (x >= roots[0] + cx && x <= roots[1] + cx) { + return dir; + } else { + return 0; + } + } + + if (anticlockwise) { + var tmp = startAngle; + startAngle = normalizeRadian(endAngle); + endAngle = normalizeRadian(tmp); + } else { + startAngle = normalizeRadian(startAngle); + endAngle = normalizeRadian(endAngle); + } + + if (startAngle > endAngle) { + endAngle += PI2$1; + } + + 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$1 + angle; + } + + if (angle >= startAngle && angle <= endAngle || angle + PI2$1 >= startAngle && angle + PI2$1 <= endAngle) { + if (angle > Math.PI / 2 && angle < Math.PI * 1.5) { + dir = -dir; + } + + w += dir; + } + } + } + + return w; +} + +function containPath(data, lineWidth, isStroke, x, y) { + var w = 0; + var xi = 0; + var yi = 0; + var x0 = 0; + var y0 = 0; + + for (var i = 0; i < data.length;) { + var cmd = data[i++]; // Begin a new subpath + + if (cmd === CMD$1.M && i > 1) { + // Close previous subpath + if (!isStroke) { + w += windingLine(xi, yi, x0, y0, x, y); + } // 如果被任何一个 subpath 包含 + // if (w !== 0) { + // return true; + // } + + } + + if (i === 1) { + // 如果第一个命令是 L, C, Q + // 则 previous point 同绘制命令的第一个 point + // + // 第一个命令为 Arc 的情况下会在后面特殊处理 + xi = data[i]; + yi = data[i + 1]; + x0 = xi; + y0 = yi; + } + + switch (cmd) { + case CMD$1.M: + // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点 + // 在 closePath 的时候使用 + x0 = data[i++]; + y0 = data[i++]; + xi = x0; + yi = y0; + break; + + case CMD$1.L: + if (isStroke) { + if (containStroke$1(xi, yi, data[i], data[i + 1], lineWidth, x, y)) { + return true; + } + } else { + // NOTE 在第一个命令为 L, C, Q 的时候会计算出 NaN + 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$2(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$3(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: + // 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++]; + var x1 = Math.cos(theta) * rx + cx; + var y1 = Math.sin(theta) * ry + cy; // 不是直接使用 arc 命令 + + if (i > 1) { + w += windingLine(xi, yi, x1, y1, x, y); + } else { + // 第一个命令起点还未定义 + x0 = x1; + y0 = y1; + } // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放 + + + var _x = (x - cx) * ry / rx + cx; + + if (isStroke) { + if (containStroke$4(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++]; + var x1 = x0 + width; + var y1 = y0 + height; + + if (isStroke) { + if (containStroke$1(x0, y0, x1, y0, lineWidth, x, y) || containStroke$1(x1, y0, x1, y1, lineWidth, x, y) || containStroke$1(x1, y1, x0, y1, lineWidth, x, y) || containStroke$1(x0, y1, x0, y0, lineWidth, x, y)) { + return true; + } + } else { + // FIXME Clockwise ? + 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$1(xi, yi, x0, y0, lineWidth, x, y)) { + return true; + } + } else { + // Close a subpath + w += windingLine(xi, yi, x0, y0, x, y); // 如果被任何一个 subpath 包含 + // FIXME subpaths may overlap + // if (w !== 0) { + // return true; + // } + } + + xi = x0; + yi = y0; + break; + } + } + + if (!isStroke && !isAroundEqual(yi, y0)) { + w += windingLine(xi, yi, x0, y0, x, y) || 0; + } + + return w !== 0; +} + +function contain(pathData, x, y) { + return containPath(pathData, 0, false, x, y); +} +function containStroke(pathData, lineWidth, x, y) { + return containPath(pathData, lineWidth, true, x, y); +} + +var getCanvasPattern = Pattern.prototype.getCanvasPattern; +var abs = Math.abs; +var pathProxyForDraw = new PathProxy(true); +/** + * @alias module:zrender/graphic/Path + * @extends module:zrender/graphic/Displayable + * @constructor + * @param {Object} opts + */ + +function Path(opts) { + Displayable.call(this, opts); + /** + * @type {module:zrender/core/PathProxy} + * @readOnly + */ + + this.path = null; +} + +Path.prototype = { + constructor: Path, + type: 'path', + __dirtyPath: true, + strokeContainThreshold: 5, + // This item default to be false. But in map series in echarts, + // in order to improve performance, it should be set to true, + // so the shorty segment won't draw. + segmentIgnoreThreshold: 0, + + /** + * See `module:zrender/src/graphic/helper/subPixelOptimize`. + * @type {boolean} + */ + subPixelOptimize: false, + brush: function (ctx, prevEl) { + var style = this.style; + var path = this.path || pathProxyForDraw; + var hasStroke = style.hasStroke(); + var hasFill = style.hasFill(); + 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; + style.bind(ctx, this, prevEl); + this.setTransform(ctx); + + if (this.__dirty) { + var rect; // Update gradient because bounding rect may changed + + if (hasFillGradient) { + rect = rect || this.getBoundingRect(); + this._fillGradient = style.getGradient(ctx, fill, rect); + } + + if (hasStrokeGradient) { + rect = rect || this.getBoundingRect(); + this._strokeGradient = style.getGradient(ctx, stroke, rect); + } + } // Use the gradient or pattern + + + if (hasFillGradient) { + // PENDING If may have affect the state + ctx.fillStyle = this._fillGradient; + } else if (hasFillPattern) { + ctx.fillStyle = getCanvasPattern.call(fill, ctx); + } + + if (hasStrokeGradient) { + ctx.strokeStyle = this._strokeGradient; + } else if (hasStrokePattern) { + ctx.strokeStyle = getCanvasPattern.call(stroke, ctx); + } + + var lineDash = style.lineDash; + var lineDashOffset = style.lineDashOffset; + var ctxLineDash = !!ctx.setLineDash; // Update path sx, sy + + var scale = this.getGlobalScale(); + path.setScale(scale[0], scale[1], this.segmentIgnoreThreshold); // Proxy context + // Rebuild path in following 2 cases + // 1. Path is dirty + // 2. Path needs javascript implemented lineDash stroking. + // In this case, lineDash information will not be saved in PathProxy + + if (this.__dirtyPath || lineDash && !ctxLineDash && hasStroke) { + path.beginPath(ctx); // Setting line dash before build path + + if (lineDash && !ctxLineDash) { + path.setLineDash(lineDash); + path.setLineDashOffset(lineDashOffset); + } + + this.buildPath(path, this.shape, false); // Clear path dirty flag + + if (this.path) { + this.__dirtyPath = false; + } + } else { + // Replay path building + ctx.beginPath(); + this.path.rebuildPath(ctx); + } + + if (hasFill) { + if (style.fillOpacity != null) { + var originalGlobalAlpha = ctx.globalAlpha; + ctx.globalAlpha = style.fillOpacity * style.opacity; + path.fill(ctx); + ctx.globalAlpha = originalGlobalAlpha; + } else { + path.fill(ctx); + } + } + + if (lineDash && ctxLineDash) { + ctx.setLineDash(lineDash); + ctx.lineDashOffset = lineDashOffset; + } + + if (hasStroke) { + if (style.strokeOpacity != null) { + var originalGlobalAlpha = ctx.globalAlpha; + ctx.globalAlpha = style.strokeOpacity * style.opacity; + path.stroke(ctx); + ctx.globalAlpha = originalGlobalAlpha; + } else { + path.stroke(ctx); + } + } + + if (lineDash && ctxLineDash) { + // PENDING + // Remove lineDash + ctx.setLineDash([]); + } // Draw rect text + + + if (style.text != null) { + // Only restore transform when needs draw text. + this.restoreTransform(ctx); + this.drawRectText(ctx, this.getBoundingRect()); + } + }, + // When bundling path, some shape may decide if use moveTo to begin a new subpath or closePath + // Like in circle + buildPath: function (ctx, shapeCfg, inBundle) {}, + createPathProxy: function () { + this.path = new PathProxy(); + }, + getBoundingRect: function () { + var rect = this._rect; + var style = this.style; + var needsUpdateRect = !rect; + + if (needsUpdateRect) { + var path = this.path; + + if (!path) { + // Create path on demand. + path = this.path = new PathProxy(); + } + + if (this.__dirtyPath) { + path.beginPath(); + this.buildPath(path, this.shape, false); + } + + rect = path.getBoundingRect(); + } + + this._rect = rect; + + if (style.hasStroke()) { + // Needs update rect with stroke lineWidth when + // 1. Element changes scale or lineWidth + // 2. Shape is changed + var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone()); + + if (this.__dirty || needsUpdateRect) { + rectWithStroke.copy(rect); // FIXME Must after updateTransform + + var w = style.lineWidth; // PENDING, Min line width is needed when line is horizontal or vertical + + var lineScale = style.strokeNoScale ? this.getLineScale() : 1; // Only add extra hover lineWidth when there are no fill + + if (!style.hasFill()) { + w = Math.max(w, this.strokeContainThreshold || 4); + } // Consider line width + // Line scale can't be 0; + + + if (lineScale > 1e-10) { + rectWithStroke.width += w / lineScale; + rectWithStroke.height += w / lineScale; + rectWithStroke.x -= w / lineScale / 2; + rectWithStroke.y -= w / lineScale / 2; + } + } // Return rect with stroke + + + return rectWithStroke; + } + + return rect; + }, + 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 pathData = this.path.data; + + if (style.hasStroke()) { + var lineWidth = style.lineWidth; + var lineScale = style.strokeNoScale ? this.getLineScale() : 1; // Line scale can't be 0; + + if (lineScale > 1e-10) { + // Only add extra hover lineWidth when there are no fill + if (!style.hasFill()) { + lineWidth = Math.max(lineWidth, this.strokeContainThreshold); + } + + if (containStroke(pathData, lineWidth / lineScale, x, y)) { + return true; + } + } + } + + if (style.hasFill()) { + return contain(pathData, x, y); + } + } + + return false; + }, + + /** + * @param {boolean} dirtyPath + */ + dirty: function (dirtyPath) { + if (dirtyPath == null) { + dirtyPath = true; + } // Only mark dirty, not mark clean + + + if (dirtyPath) { + this.__dirtyPath = dirtyPath; + this._rect = null; + } + + this.__dirty = this.__dirtyText = true; + this.__zr && this.__zr.refresh(); // Used as a clipping path + + if (this.__clipTarget) { + this.__clipTarget.dirty(); + } + }, + + /** + * Alias for animate('shape') + * @param {boolean} loop + */ + animateShape: function (loop) { + return this.animate('shape', loop); + }, + // Overwrite attrKV + attrKV: function (key, value) { + // FIXME + if (key === 'shape') { + this.setShape(value); + this.__dirtyPath = true; + this._rect = null; + } else { + Displayable.prototype.attrKV.call(this, key, value); + } + }, + + /** + * @param {Object|string} key + * @param {*} value + */ + setShape: function (key, value) { + var shape = this.shape; // Path from string may not have shape + + if (shape) { + if (isObject$1(key)) { + for (var name in key) { + if (key.hasOwnProperty(name)) { + shape[name] = key[name]; + } + } + } else { + shape[key] = value; + } + + this.dirty(true); + } + + return this; + }, + getLineScale: function () { + var m = this.transform; // Get the line scale. + // Determinant of `m` means how much the area is enlarged by the + // transformation. So its square root can be used as a scale factor + // for width. + + 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; + } +}; +/** + * 扩展一个 Path element, 比如星形,圆等。 + * Extend a path element + * @param {Object} props + * @param {string} props.type Path type + * @param {Function} props.init Initialize + * @param {Function} props.buildPath Overwrite buildPath method + * @param {Object} [props.style] Extended default style config + * @param {Object} [props.shape] Extended default shape config + */ + +Path.extend = function (defaults$$1) { + var Sub = function (opts) { + Path.call(this, opts); + + if (defaults$$1.style) { + // Extend default style + this.style.extendFrom(defaults$$1.style, false); + } // Extend default shape + + + var defaultShape = defaults$$1.shape; + + if (defaultShape) { + this.shape = this.shape || {}; + var thisShape = this.shape; + + for (var name in defaultShape) { + if (!thisShape.hasOwnProperty(name) && defaultShape.hasOwnProperty(name)) { + thisShape[name] = defaultShape[name]; + } + } + } + + defaults$$1.init && defaults$$1.init.call(this, opts); + }; + + inherits(Sub, Path); // FIXME 不能 extend position, rotation 等引用对象 + + for (var name in defaults$$1) { + // Extending prototype values and methods + if (name !== 'style' && name !== 'shape') { + Sub.prototype[name] = defaults$$1[name]; + } + } + + return Sub; +}; + +inherits(Path, Displayable); + +var CMD$2 = PathProxy.CMD; +var points = [[], [], []]; +var mathSqrt$3 = Math.sqrt; +var mathAtan2 = Math.atan2; +var transformPath = function (path, m) { + var data = path.data; + 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 < data.length;) { + 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$3(m[0] * m[0] + m[1] * m[1]); + var sy = mathSqrt$3(m[2] * m[2] + m[3] * m[3]); + var angle = mathAtan2(-m[1] / sy, m[0] / sx); // cx + + data[i] *= sx; + data[i++] += x; // cy + + data[i] *= sy; + data[i++] += y; // Scale rx and ry + // FIXME Assume psi is 0 here + + data[i++] *= sx; + data[i++] *= sy; // Start angle + + data[i++] += angle; // end angle + + data[i++] += angle; // FIXME psi + + i += 2; + j = i; + break; + + case R: + // x0, y0 + p[0] = data[i++]; + p[1] = data[i++]; + applyTransform(p, p, m); + data[j++] = p[0]; + data[j++] = p[1]; // x1, y1 + + 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 = points[k]; + p[0] = data[i++]; + p[1] = data[i++]; + applyTransform(p, p, m); // Write back + + data[j++] = p[0]; + data[j++] = p[1]; + } + } +}; + +// var cc = [ +// 'm', 'M', 'l', 'L', 'v', 'V', 'h', 'H', 'z', 'Z', +// 'c', 'C', 'q', 'Q', 't', 'T', 's', 'S', 'a', 'A' +// ]; + +var mathSqrt = Math.sqrt; +var mathSin = Math.sin; +var mathCos = Math.cos; +var PI = Math.PI; + +var vMag = function (v) { + return Math.sqrt(v[0] * v[0] + v[1] * v[1]); +}; + +var vRatio = function (u, v) { + return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v)); +}; + +var vAngle = function (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 / 180.0); + var xp = mathCos(psi) * (x1 - x2) / 2.0 + mathSin(psi) * (y1 - y2) / 2.0; + var yp = -1 * mathSin(psi) * (x1 - x2) / 2.0 + mathCos(psi) * (y1 - y2) / 2.0; + var lambda = xp * xp / (rx * rx) + yp * yp / (ry * ry); + + if (lambda > 1) { + rx *= mathSqrt(lambda); + ry *= mathSqrt(lambda); + } + + var f = (fa === fs ? -1 : 1) * mathSqrt((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(psi) * cxp - mathSin(psi) * cyp; + var cy = (y1 + y2) / 2.0 + mathSin(psi) * cxp + mathCos(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; + } + + if (vRatio(u, v) >= 1) { + dTheta = 0; + } + + if (fs === 0 && dTheta > 0) { + dTheta = dTheta - 2 * PI; + } + + if (fs === 1 && dTheta < 0) { + dTheta = dTheta + 2 * PI; + } + + path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs); +} + +var commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig; // Consider case: +// (1) delimiter can be comma or space, where continuous commas +// or spaces should be seen as one comma. +// (2) value can be like: +// '2e-4', 'l.5.9' (ignore 0), 'M-10-10', 'l-2.43e-1,34.9983', +// 'l-.5E1,54', '121-23-44-11' (no delimiter) + +var numberReg = /-?([0-9]*\.)?[0-9]+([eE]-?[0-9]+)?/g; // var valueSplitReg = /[\s,]+/; + +function createPathProxyFromString(data) { + if (!data) { + return new PathProxy(); + } // var data = data.replace(/-/g, ' -') + // .replace(/ /g, ' ') + // .replace(/ /g, ',') + // .replace(/,,/g, ','); + // var n; + // create pipes so that we can split the data + // for (n = 0; n < cc.length; n++) { + // cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]); + // } + // data = data.replace(/-/g, ',-'); + // create array + // var arr = cs.split('|'); + // init context point + + + var cpx = 0; + var cpy = 0; + var subpathX = cpx; + var subpathY = cpy; + var prevCmd; + var path = new PathProxy(); + var CMD = PathProxy.CMD; // commandReg.lastIndex = 0; + // var cmdResult; + // while ((cmdResult = commandReg.exec(data)) != null) { + // var cmdStr = cmdResult[1]; + // var cmdContent = cmdResult[2]; + + var cmdList = data.match(commandReg); + + for (var l = 0; l < cmdList.length; l++) { + var cmdText = cmdList[l]; + var cmdStr = cmdText.charAt(0); + var cmd; // String#split is faster a little bit than String#replace or RegExp#exec. + // var p = cmdContent.split(valueSplitReg); + // var pLen = 0; + // for (var i = 0; i < p.length; i++) { + // // '' and other invalid str => NaN + // var val = parseFloat(p[i]); + // !isNaN(val) && (p[pLen++] = val); + // } + + 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; + var ctlPty; + var rx; + var ry; + var psi; + var fa; + var fs; + var x1 = cpx; + var y1 = cpy; // convert l, H, h, V, and v to L + + 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; + var len = path.len(); + var 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; + var len = path.len(); + var 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; + var len = path.len(); + var 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; + var len = path.len(); + var 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); // z may be in the middle of the path. + + cpx = subpathX; + cpy = subpathY; + } + + prevCmd = cmd; + } + + path.toStatic(); + return path; +} // TODO Optimize double memory cost problem + + +function createPathOptions(str, opts) { + var pathProxy = createPathProxyFromString(str); + opts = opts || {}; + + opts.buildPath = function (path) { + if (path.setData) { + path.setData(pathProxy.data); // Svg and vml renderer don't have context + + var ctx = path.getContext(); + + if (ctx) { + path.rebuildPath(ctx); + } + } else { + var ctx = path; + pathProxy.rebuildPath(ctx); + } + }; + + opts.applyTransform = function (m) { + transformPath(pathProxy, m); + this.dirty(true); + }; + + return opts; +} +/** + * Create a Path object from path string data + * http://www.w3.org/TR/SVG/paths.html#PathData + * @param {Object} opts Other options + */ + + +function createFromString(str, opts) { + return new Path(createPathOptions(str, opts)); +} +/** + * Create a Path class from path string data + * @param {string} str + * @param {Object} opts Other options + */ + +function extendFromString(str, opts) { + return Path.extend(createPathOptions(str, opts)); +} +/** + * Merge multiple paths + */ +// TODO Apply transform +// TODO stroke dash +// TODO Optimize double memory cost problem + +function mergePath$1(pathEls, opts) { + var pathList = []; + var len = pathEls.length; + + for (var i = 0; i < len; i++) { + var pathEl = pathEls[i]; + + if (!pathEl.path) { + pathEl.createPathProxy(); + } + + if (pathEl.__dirtyPath) { + pathEl.buildPath(pathEl.path, pathEl.shape, true); + } + + pathList.push(pathEl.path); + } + + var pathBundle = new Path(opts); // Need path proxy. + + pathBundle.createPathProxy(); + + pathBundle.buildPath = function (path) { + path.appendPath(pathList); // Svg and vml renderer don't have context + + var ctx = path.getContext(); + + if (ctx) { + path.rebuildPath(ctx); + } + }; + + return pathBundle; +} + +/** + * @alias zrender/graphic/Text + * @extends module:zrender/graphic/Displayable + * @constructor + * @param {Object} opts + */ + +var Text = function (opts) { + // jshint ignore:line + Displayable.call(this, opts); +}; + +Text.prototype = { + constructor: Text, + type: 'text', + brush: function (ctx, prevEl) { + var style = this.style; // Optimize, avoid normalize every time. + + this.__dirty && normalizeTextStyle(style, true); // Use props with prefix 'text'. + + style.fill = style.stroke = style.shadowBlur = style.shadowColor = style.shadowOffsetX = style.shadowOffsetY = null; + var text = style.text; // Convert to string + + text != null && (text += ''); // Do not apply style.bind in Text node. Because the real bind job + // is in textHelper.renderText, and performance of text render should + // be considered. + // style.bind(ctx, this, prevEl); + + if (!needDrawText(text, style)) { + // The current el.style is not applied + // and should not be used as cache. + ctx.__attrCachedBy = ContextCachedBy.NONE; + return; + } + + this.setTransform(ctx); + renderText(this, ctx, text, style, null, prevEl); + this.restoreTransform(ctx); + }, + getBoundingRect: function () { + var style = this.style; // Optimize, avoid normalize every time. + + this.__dirty && normalizeTextStyle(style, true); + + if (!this._rect) { + var text = style.text; + text != null ? text += '' : text = ''; + var rect = getBoundingRect(style.text + '', style.font, style.textAlign, style.textVerticalAlign, style.textPadding, style.textLineHeight, style.rich); + rect.x += style.x || 0; + rect.y += style.y || 0; + + if (getStroke(style.textStroke, style.textStrokeWidth)) { + var w = style.textStrokeWidth; + rect.x -= w / 2; + rect.y -= w / 2; + rect.width += w; + rect.height += w; + } + + this._rect = rect; + } + + return this._rect; + } +}; +inherits(Text, Displayable); + +/** + * 圆形 + * @module zrender/shape/Circle + */ +var Circle = Path.extend({ + type: 'circle', + shape: { + cx: 0, + cy: 0, + r: 0 + }, + buildPath: function (ctx, shape, inBundle) { + // Better stroking in ShapeBundle + // Always do it may have performence issue ( fill may be 2x more cost) + if (inBundle) { + ctx.moveTo(shape.cx + shape.r, shape.cy); + } // else { + // if (ctx.allocate && !ctx.data.length) { + // ctx.allocate(ctx.CMD_MEM_SIZE.A); + // } + // } + // Better stroking in ShapeBundle + // ctx.moveTo(shape.cx + shape.r, shape.cy); + + + ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true); + } +}); + +// where exception "unexpected call to method or property access" +// might be thrown when calling ctx.fill or ctx.stroke after a path +// whose area size is zero is drawn and ctx.clip() is called and +// shadowBlur is set. See #4572, #3112, #5777. +// (e.g., +// ctx.moveTo(10, 10); +// ctx.lineTo(20, 10); +// ctx.closePath(); +// ctx.clip(); +// ctx.shadowBlur = 10; +// ... +// ctx.fill(); +// ) + +var shadowTemp = [['shadowBlur', 0], ['shadowColor', '#000'], ['shadowOffsetX', 0], ['shadowOffsetY', 0]]; +var fixClipWithShadow = function (orignalBrush) { + // version string can be: '11.0' + return env$1.browser.ie && env$1.browser.version >= 11 ? function () { + var clipPaths = this.__clipPaths; + var style = this.style; + var modified; + + if (clipPaths) { + for (var i = 0; i < clipPaths.length; i++) { + var clipPath = clipPaths[i]; + var shape = clipPath && clipPath.shape; + var type = clipPath && clipPath.type; + + if (shape && (type === 'sector' && shape.startAngle === shape.endAngle || type === 'rect' && (!shape.width || !shape.height))) { + for (var j = 0; j < shadowTemp.length; j++) { + // It is save to put shadowTemp static, because shadowTemp + // will be all modified each item brush called. + shadowTemp[j][2] = style[shadowTemp[j][0]]; + style[shadowTemp[j][0]] = shadowTemp[j][1]; + } + + modified = true; + break; + } + } + } + + orignalBrush.apply(this, arguments); + + if (modified) { + for (var j = 0; j < shadowTemp.length; j++) { + style[shadowTemp[j][0]] = shadowTemp[j][2]; + } + } + } : orignalBrush; +}; + +/** + * 扇形 + * @module zrender/graphic/shape/Sector + */ +var Sector = Path.extend({ + type: 'sector', + shape: { + cx: 0, + cy: 0, + r0: 0, + r: 0, + startAngle: 0, + endAngle: Math.PI * 2, + clockwise: true + }, + brush: fixClipWithShadow(Path.prototype.brush), + buildPath: function (ctx, shape) { + var x = shape.cx; + var y = shape.cy; + var r0 = Math.max(shape.r0 || 0, 0); + 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 * r0 + x, unitY * r0 + y); + ctx.lineTo(unitX * r + x, unitY * r + y); + ctx.arc(x, y, r, startAngle, endAngle, !clockwise); + ctx.lineTo(Math.cos(endAngle) * r0 + x, Math.sin(endAngle) * r0 + y); + + if (r0 !== 0) { + ctx.arc(x, y, r0, endAngle, startAngle, clockwise); + } + + ctx.closePath(); + } +}); + +/** + * 圆环 + * @module zrender/graphic/shape/Ring + */ +var Ring = Path.extend({ + type: 'ring', + shape: { + cx: 0, + cy: 0, + r: 0, + r0: 0 + }, + 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); + } +}); + +/** + * Catmull-Rom spline 插值折线 + * @module zrender/shape/util/smoothSpline + * @author pissang (https://www.github.com/pissang) + * Kener (@Kener-林峰, kener.linfeng@gmail.com) + * errorrik (errorrik@gmail.com) + */ +/** + * @inner + */ + +function interpolate(p0, p1, p2, p3, t, t2, t3) { + var v0 = (p2 - p0) * 0.5; + var v1 = (p3 - p1) * 0.5; + return (2 * (p1 - p2) + v0 + v1) * t3 + (-3 * (p1 - p2) - 2 * v0 - v1) * t2 + v0 * t + p1; +} +/** + * @alias module:zrender/shape/util/smoothSpline + * @param {Array} points 线段顶点数组 + * @param {boolean} isLoop + * @return {Array} + */ + + +var smoothSpline = function (points, isLoop) { + var len$$1 = points.length; + var ret = []; + var distance$$1 = 0; + + for (var i = 1; i < len$$1; i++) { + distance$$1 += distance(points[i - 1], points[i]); + } + + var segs = distance$$1 / 2; + segs = segs < len$$1 ? len$$1 : segs; + + for (var i = 0; i < segs; i++) { + var pos = i / (segs - 1) * (isLoop ? len$$1 : len$$1 - 1); + var idx = Math.floor(pos); + var w = pos - idx; + var p0; + var p1 = points[idx % len$$1]; + var p2; + var p3; + + if (!isLoop) { + p0 = points[idx === 0 ? idx : idx - 1]; + p2 = points[idx > len$$1 - 2 ? len$$1 - 1 : idx + 1]; + p3 = points[idx > len$$1 - 3 ? len$$1 - 1 : idx + 2]; + } else { + p0 = points[(idx - 1 + len$$1) % len$$1]; + p2 = points[(idx + 1) % len$$1]; + p3 = points[(idx + 2) % len$$1]; + } + + var w2 = w * w; + var w3 = w * w2; + ret.push([interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3), interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)]); + } + + return ret; +}; + +/** + * 贝塞尔平滑曲线 + * @module zrender/shape/util/smoothBezier + * @author pissang (https://www.github.com/pissang) + * Kener (@Kener-林峰, kener.linfeng@gmail.com) + * errorrik (errorrik@gmail.com) + */ +/** + * 贝塞尔平滑曲线 + * @alias module:zrender/shape/util/smoothBezier + * @param {Array} points 线段顶点数组 + * @param {number} smooth 平滑等级, 0-1 + * @param {boolean} isLoop + * @param {Array} constraint 将计算出来的控制点约束在一个包围盒内 + * 比如 [[0, 0], [100, 100]], 这个包围盒会与 + * 整个折线的包围盒做一个并集用来约束控制点。 + * @param {Array} 计算出来的控制点数组 + */ + +var smoothBezier = function (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$$1 = points.length; i < len$$1; 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$$1 = points.length; i < len$$1; i++) { + var point = points[i]; + + if (isLoop) { + prevPoint = points[i ? i - 1 : len$$1 - 1]; + nextPoint = points[(i + 1) % len$$1]; + } else { + if (i === 0 || i === len$$1 - 1) { + cps.push(clone$1(points[i])); + continue; + } else { + prevPoint = points[i - 1]; + nextPoint = points[i + 1]; + } + } + + sub(v, nextPoint, prevPoint); // use degree to scale the handle length + + 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$1(ctx, shape, closePath) { + var points = shape.points; + var smooth = shape.smooth; + + if (points && points.length >= 2) { + if (smooth && smooth !== 'spline') { + 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 { + if (smooth === 'spline') { + points = smoothSpline(points, closePath); + } + + 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(); + } +} + +/** + * 多边形 + * @module zrender/shape/Polygon + */ +var Polygon = Path.extend({ + type: 'polygon', + shape: { + points: null, + smooth: false, + smoothConstraint: null + }, + buildPath: function (ctx, shape) { + buildPath$1(ctx, shape, true); + } +}); + +/** + * @module zrender/graphic/shape/Polyline + */ +var Polyline = Path.extend({ + type: 'polyline', + shape: { + points: null, + smooth: false, + smoothConstraint: null + }, + style: { + stroke: '#000', + fill: null + }, + buildPath: function (ctx, shape) { + buildPath$1(ctx, shape, false); + } +}); + +/** + * Sub-pixel optimize for canvas rendering, prevent from blur + * when rendering a thin vertical/horizontal line. + */ +var round = Math.round; +/** + * Sub pixel optimize line for canvas + * + * @param {Object} outputShape The modification will be performed on `outputShape`. + * `outputShape` and `inputShape` can be the same object. + * `outputShape` object can be used repeatly, because all of + * the `x1`, `x2`, `y1`, `y2` will be assigned in this method. + * @param {Object} [inputShape] + * @param {number} [inputShape.x1] + * @param {number} [inputShape.y1] + * @param {number} [inputShape.x2] + * @param {number} [inputShape.y2] + * @param {Object} [style] + * @param {number} [style.lineWidth] + */ + +function subPixelOptimizeLine$1(outputShape, inputShape, style) { + var lineWidth = style && style.lineWidth; + + if (!inputShape || !lineWidth) { + return; + } + + var x1 = inputShape.x1; + var x2 = inputShape.x2; + var y1 = inputShape.y1; + var y2 = inputShape.y2; + + if (round(x1 * 2) === round(x2 * 2)) { + outputShape.x1 = outputShape.x2 = subPixelOptimize$1(x1, lineWidth, true); + } else { + outputShape.x1 = x1; + outputShape.x2 = x2; + } + + if (round(y1 * 2) === round(y2 * 2)) { + outputShape.y1 = outputShape.y2 = subPixelOptimize$1(y1, lineWidth, true); + } else { + outputShape.y1 = y1; + outputShape.y2 = y2; + } +} +/** + * Sub pixel optimize rect for canvas + * + * @param {Object} outputShape The modification will be performed on `outputShape`. + * `outputShape` and `inputShape` can be the same object. + * `outputShape` object can be used repeatly, because all of + * the `x`, `y`, `width`, `height` will be assigned in this method. + * @param {Object} [inputShape] + * @param {number} [inputShape.x] + * @param {number} [inputShape.y] + * @param {number} [inputShape.width] + * @param {number} [inputShape.height] + * @param {Object} [style] + * @param {number} [style.lineWidth] + */ + +function subPixelOptimizeRect$1(outputShape, inputShape, style) { + var lineWidth = style && style.lineWidth; + + if (!inputShape || !lineWidth) { + return; + } + + var originX = inputShape.x; + var originY = inputShape.y; + var originWidth = inputShape.width; + var originHeight = inputShape.height; + outputShape.x = subPixelOptimize$1(originX, lineWidth, true); + outputShape.y = subPixelOptimize$1(originY, lineWidth, true); + outputShape.width = Math.max(subPixelOptimize$1(originX + originWidth, lineWidth, false) - outputShape.x, originWidth === 0 ? 0 : 1); + outputShape.height = Math.max(subPixelOptimize$1(originY + originHeight, lineWidth, false) - outputShape.y, originHeight === 0 ? 0 : 1); +} +/** + * Sub pixel optimize for canvas + * + * @param {number} position Coordinate, such as x, y + * @param {number} lineWidth Should be nonnegative integer. + * @param {boolean=} positiveOrNegative Default false (negative). + * @return {number} Optimized position. + */ + +function subPixelOptimize$1(position, lineWidth, positiveOrNegative) { + // Assure that (position + lineWidth / 2) is near integer edge, + // otherwise line will be fuzzy in canvas. + var doubledPosition = round(position * 2); + return (doubledPosition + round(lineWidth)) % 2 === 0 ? doubledPosition / 2 : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2; +} + +/** + * 矩形 + * @module zrender/graphic/shape/Rect + */ +var subPixelOptimizeOutputShape = {}; +var Rect = Path.extend({ + type: 'rect', + shape: { + // 左上、右上、右下、左下角的半径依次为r1、r2、r3、r4 + // r缩写为1 相当于 [1, 1, 1, 1] + // r缩写为[1] 相当于 [1, 1, 1, 1] + // r缩写为[1, 2] 相当于 [1, 2, 1, 2] + // r缩写为[1, 2, 3] 相当于 [1, 2, 3, 2] + r: 0, + x: 0, + y: 0, + width: 0, + height: 0 + }, + buildPath: function (ctx, shape) { + var x; + var y; + var width; + var height; + + if (this.subPixelOptimize) { + subPixelOptimizeRect$1(subPixelOptimizeOutputShape, shape, this.style); + x = subPixelOptimizeOutputShape.x; + y = subPixelOptimizeOutputShape.y; + width = subPixelOptimizeOutputShape.width; + height = subPixelOptimizeOutputShape.height; + subPixelOptimizeOutputShape.r = shape.r; + shape = subPixelOptimizeOutputShape; + } 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); + } + + ctx.closePath(); + return; + } +}); + +/** + * 直线 + * @module zrender/graphic/shape/Line + */ +var subPixelOptimizeOutputShape$1 = {}; +var Line = Path.extend({ + type: 'line', + shape: { + // Start point + x1: 0, + y1: 0, + // End point + x2: 0, + y2: 0, + percent: 1 + }, + style: { + stroke: '#000', + fill: null + }, + buildPath: function (ctx, shape) { + var x1; + var y1; + var x2; + var y2; + + if (this.subPixelOptimize) { + subPixelOptimizeLine$1(subPixelOptimizeOutputShape$1, shape, this.style); + x1 = subPixelOptimizeOutputShape$1.x1; + y1 = subPixelOptimizeOutputShape$1.y1; + x2 = subPixelOptimizeOutputShape$1.x2; + y2 = subPixelOptimizeOutputShape$1.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); + }, + + /** + * Get point at percent + * @param {number} percent + * @return {Array.} + */ + pointAt: function (p) { + var shape = this.shape; + return [shape.x1 * (1 - p) + shape.x2 * p, shape.y1 * (1 - p) + shape.y2 * p]; + } +}); + +/** + * 贝塞尔曲线 + * @module zrender/shape/BezierCurve + */ +var out = []; + +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 = Path.extend({ + type: 'bezier-curve', + shape: { + x1: 0, + y1: 0, + x2: 0, + y2: 0, + cpx1: 0, + cpy1: 0, + // cpx2: 0, + // cpy2: 0 + // Curve show percent, for animating + percent: 1 + }, + style: { + stroke: '#000', + fill: null + }, + 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); + } + }, + + /** + * Get point at percent + * @param {number} t + * @return {Array.} + */ + pointAt: function (t) { + return someVectorAt(this.shape, t, false); + }, + + /** + * Get tangent at percent + * @param {number} t + * @return {Array.} + */ + tangentAt: function (t) { + var p = someVectorAt(this.shape, t, true); + return normalize(p, p); + } +}); + +/** + * 圆弧 + * @module zrender/graphic/shape/Arc + */ +var Arc = Path.extend({ + type: 'arc', + shape: { + cx: 0, + cy: 0, + r: 0, + startAngle: 0, + endAngle: Math.PI * 2, + clockwise: true + }, + style: { + stroke: '#000', + fill: null + }, + 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); + } +}); + +// CompoundPath to improve performance +var CompoundPath = Path.extend({ + type: 'compound', + shape: { + paths: null + }, + _updatePathDirty: function () { + var dirtyPath = this.__dirtyPath; + var paths = this.shape.paths; + + for (var i = 0; i < paths.length; i++) { + // Mark as dirty if any subpath is dirty + dirtyPath = dirtyPath || paths[i].__dirtyPath; + } + + this.__dirtyPath = dirtyPath; + this.__dirty = this.__dirty || dirtyPath; + }, + beforeBrush: function () { + this._updatePathDirty(); + + var paths = this.shape.paths || []; + var scale = this.getGlobalScale(); // Update path scale + + 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); + } + }, + buildPath: function (ctx, shape) { + var paths = shape.paths || []; + + for (var i = 0; i < paths.length; i++) { + paths[i].buildPath(ctx, paths[i].shape, true); + } + }, + afterBrush: function () { + var paths = this.shape.paths || []; + + for (var i = 0; i < paths.length; i++) { + paths[i].__dirtyPath = false; + } + }, + getBoundingRect: function () { + this._updatePathDirty(); + + return Path.prototype.getBoundingRect.call(this); + } +}); + +/** + * @param {Array.} colorStops + */ +var Gradient = function (colorStops) { + this.colorStops = colorStops || []; +}; + +Gradient.prototype = { + constructor: Gradient, + addColorStop: function (offset, color) { + this.colorStops.push({ + offset: offset, + color: color + }); + } +}; + +/** + * x, y, x2, y2 are all percent from 0 to 1 + * @param {number} [x=0] + * @param {number} [y=0] + * @param {number} [x2=1] + * @param {number} [y2=0] + * @param {Array.} colorStops + * @param {boolean} [globalCoord=false] + */ + +var LinearGradient = function (x, y, x2, y2, colorStops, globalCoord) { + // Should do nothing more in this constructor. Because gradient can be + // declard by `color: {type: 'linear', colorStops: ...}`, where + // this constructor will not be called. + this.x = x == null ? 0 : x; + this.y = y == null ? 0 : y; + this.x2 = x2 == null ? 1 : x2; + this.y2 = y2 == null ? 0 : y2; // Can be cloned + + this.type = 'linear'; // If use global coord + + this.global = globalCoord || false; + Gradient.call(this, colorStops); +}; + +LinearGradient.prototype = { + constructor: LinearGradient +}; +inherits(LinearGradient, Gradient); + +/** + * x, y, r are all percent from 0 to 1 + * @param {number} [x=0.5] + * @param {number} [y=0.5] + * @param {number} [r=0.5] + * @param {Array.} [colorStops] + * @param {boolean} [globalCoord=false] + */ + +var RadialGradient = function (x, y, r, colorStops, globalCoord) { + // Should do nothing more in this constructor. Because gradient can be + // declard by `color: {type: 'radial', colorStops: ...}`, where + // this constructor will not be called. + this.x = x == null ? 0.5 : x; + this.y = y == null ? 0.5 : y; + this.r = r == null ? 0.5 : r; // Can be cloned + + this.type = 'radial'; // If use global coord + + this.global = globalCoord || false; + Gradient.call(this, colorStops); +}; + +RadialGradient.prototype = { + constructor: RadialGradient +}; +inherits(RadialGradient, Gradient); + +/** + * Displayable for incremental rendering. It will be rendered in a separate layer + * IncrementalDisplay have two main methods. `clearDisplayables` and `addDisplayables` + * addDisplayables will render the added displayables incremetally. + * + * It use a not clearFlag to tell the painter don't clear the layer if it's the first element. + */ +function IncrementalDisplayble(opts) { + Displayable.call(this, opts); + this._displayables = []; + this._temporaryDisplayables = []; + this._cursor = 0; + this.notClear = true; +} + +IncrementalDisplayble.prototype.incremental = true; + +IncrementalDisplayble.prototype.clearDisplaybles = function () { + this._displayables = []; + this._temporaryDisplayables = []; + this._cursor = 0; + this.dirty(); + this.notClear = false; +}; + +IncrementalDisplayble.prototype.addDisplayable = function (displayable, notPersistent) { + if (notPersistent) { + this._temporaryDisplayables.push(displayable); + } else { + this._displayables.push(displayable); + } + + this.dirty(); +}; + +IncrementalDisplayble.prototype.addDisplayables = function (displayables, notPersistent) { + notPersistent = notPersistent || false; + + for (var i = 0; i < displayables.length; i++) { + this.addDisplayable(displayables[i], notPersistent); + } +}; + +IncrementalDisplayble.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]); + } +}; + +IncrementalDisplayble.prototype.update = function () { + this.updateTransform(); + + for (var i = this._cursor; i < this._displayables.length; i++) { + var displayable = this._displayables[i]; // PENDING + + displayable.parent = this; + displayable.update(); + displayable.parent = null; + } + + for (var i = 0; i < this._temporaryDisplayables.length; i++) { + var displayable = this._temporaryDisplayables[i]; // PENDING + + displayable.parent = this; + displayable.update(); + displayable.parent = null; + } +}; + +IncrementalDisplayble.prototype.brush = function (ctx, prevEl) { + // Render persistant displayables. + for (var i = this._cursor; i < this._displayables.length; i++) { + var displayable = this._displayables[i]; + displayable.beforeBrush && displayable.beforeBrush(ctx); + displayable.brush(ctx, i === this._cursor ? null : this._displayables[i - 1]); + displayable.afterBrush && displayable.afterBrush(ctx); + } + + this._cursor = i; // Render temporary displayables. + + for (var i = 0; i < this._temporaryDisplayables.length; i++) { + var displayable = this._temporaryDisplayables[i]; + displayable.beforeBrush && displayable.beforeBrush(ctx); + displayable.brush(ctx, i === 0 ? null : this._temporaryDisplayables[i - 1]); + displayable.afterBrush && displayable.afterBrush(ctx); + } + + this._temporaryDisplayables = []; + this.notClear = true; +}; + +var m = []; + +IncrementalDisplayble.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; +}; + +IncrementalDisplayble.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; +}; + +inherits(IncrementalDisplayble, Displayable); + +/* +* 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 mathMax$1 = Math.max; +var mathMin$1 = Math.min; +var EMPTY_OBJ = {}; +var Z2_EMPHASIS_LIFT = 1; // key: label model property nane, value: style property name. + +var CACHED_LABEL_STYLE_PROPERTIES = { + color: 'textFill', + textBorderColor: 'textStroke', + textBorderWidth: 'textStrokeWidth' +}; +var EMPHASIS = 'emphasis'; +var NORMAL = 'normal'; // Reserve 0 as default. + +var _highlightNextDigit = 1; +var _highlightKeyMap = {}; +var _customShapeMap = {}; +/** + * Extend shape with parameters + */ + +function extendShape(opts) { + return Path.extend(opts); +} +/** + * Extend path + */ + +function extendPath(pathData, opts) { + return extendFromString(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 {string} name + * @param {Object} 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 {string} name + * @return {Object} 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 {string} pathData + * @param {Object} opts + * @param {module:zrender/core/BoundingRect} rect + * @param {string} [layout=cover] 'center' or '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 {string} imageUrl image url + * @param {Object} opts options + * @param {module:zrender/core/BoundingRect} rect constrain rect + * @param {string} [layout=cover] 'center' or 'cover' + */ + +function makeImage(imageUrl, rect, layout) { + var path = new ZImage({ + 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 + }; + path.setStyle(centerGraphic(rect, boundingRect)); + } + } + }); + return path; +} +/** + * Get position of centered element in bounding box. + * + * @param {Object} rect element local bounding box + * @param {Object} boundingRect constraint bounding box + * @return {Object} 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 = mergePath$1; +/** + * Resize a path to fit the rect + * @param {module:zrender/graphic/Path} path + * @param {Object} 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 + * + * @param {Object} param + * @param {Object} [param.shape] + * @param {number} [param.shape.x1] + * @param {number} [param.shape.y1] + * @param {number} [param.shape.x2] + * @param {number} [param.shape.y2] + * @param {Object} [param.style] + * @param {number} [param.style.lineWidth] + * @return {Object} Modified param + */ + +function subPixelOptimizeLine(param) { + subPixelOptimizeLine$1(param.shape, param.shape, param.style); + return param; +} +/** + * Sub pixel optimize rect for canvas + * + * @param {Object} param + * @param {Object} [param.shape] + * @param {number} [param.shape.x] + * @param {number} [param.shape.y] + * @param {number} [param.shape.width] + * @param {number} [param.shape.height] + * @param {Object} [param.style] + * @param {number} [param.style.lineWidth] + * @return {Object} Modified param + */ + +function subPixelOptimizeRect(param) { + subPixelOptimizeRect$1(param.shape, param.shape, param.style); + return param; +} +/** + * Sub pixel optimize for canvas + * + * @param {number} position Coordinate, such as x, y + * @param {number} lineWidth Should be nonnegative integer. + * @param {boolean=} positiveOrNegative Default false (negative). + * @return {number} Optimized position. + */ + +var subPixelOptimize = subPixelOptimize$1; + +function hasFillOrStroke(fillOrStroke) { + return fillOrStroke != null && fillOrStroke !== 'none'; +} // Most lifted color are duplicated. + + +var liftedColorMap = createHashMap(); +var liftedColorCount = 0; + +function liftColor(color) { + if (typeof color !== 'string') { + return color; + } + + var liftedColor = liftedColorMap.get(color); + + if (!liftedColor) { + liftedColor = lift(color, -0.1); + + if (liftedColorCount < 10000) { + liftedColorMap.set(color, liftedColor); + liftedColorCount++; + } + } + + return liftedColor; +} + +function cacheElementStl(el) { + if (!el.__hoverStlDirty) { + return; + } + + el.__hoverStlDirty = false; + var hoverStyle = el.__hoverStl; + + if (!hoverStyle) { + el.__cachedNormalStl = el.__cachedNormalZ2 = null; + return; + } + + var normalStyle = el.__cachedNormalStl = {}; + el.__cachedNormalZ2 = el.z2; + var elStyle = el.style; + + for (var name in hoverStyle) { + // See comment in `singleEnterEmphasis`. + if (hoverStyle[name] != null) { + normalStyle[name] = elStyle[name]; + } + } // Always cache fill and stroke to normalStyle for lifting color. + + + normalStyle.fill = elStyle.fill; + normalStyle.stroke = elStyle.stroke; +} + +function singleEnterEmphasis(el) { + var hoverStl = el.__hoverStl; + + if (!hoverStl || el.__highlighted) { + return; + } + + var zr = el.__zr; + var useHoverLayer = el.useHoverLayer && zr && zr.painter.type === 'canvas'; + el.__highlighted = useHoverLayer ? 'layer' : 'plain'; + + if (el.isGroup || !zr && el.useHoverLayer) { + return; + } + + var elTarget = el; + var targetStyle = el.style; + + if (useHoverLayer) { + elTarget = zr.addHover(el); + targetStyle = elTarget.style; + } + + rollbackDefaultTextStyle(targetStyle); + + if (!useHoverLayer) { + cacheElementStl(elTarget); + } // styles can be: + // { + // label: { + // show: false, + // position: 'outside', + // fontSize: 18 + // }, + // emphasis: { + // label: { + // show: true + // } + // } + // }, + // where properties of `emphasis` may not appear in `normal`. We previously use + // module:echarts/util/model#defaultEmphasis to merge `normal` to `emphasis`. + // But consider rich text and setOption in merge mode, it is impossible to cover + // all properties in merge. So we use merge mode when setting style here. + // But we choose the merge strategy that only properties that is not `null/undefined`. + // Because when making a textStyle (espacially rich text), it is not easy to distinguish + // `hasOwnProperty` and `null/undefined` in code, so we trade them as the same for simplicity. + // But this strategy brings a trouble that `null/undefined` can not be used to remove + // style any more in `emphasis`. Users can both set properties directly on normal and + // emphasis to avoid this issue, or we might support `'none'` for this case if required. + + + targetStyle.extendFrom(hoverStl); + setDefaultHoverFillStroke(targetStyle, hoverStl, 'fill'); + setDefaultHoverFillStroke(targetStyle, hoverStl, 'stroke'); + applyDefaultTextStyle(targetStyle); + + if (!useHoverLayer) { + el.dirty(false); + el.z2 += Z2_EMPHASIS_LIFT; + } +} + +function setDefaultHoverFillStroke(targetStyle, hoverStyle, prop) { + if (!hasFillOrStroke(hoverStyle[prop]) && hasFillOrStroke(targetStyle[prop])) { + targetStyle[prop] = liftColor(targetStyle[prop]); + } +} + +function singleEnterNormal(el) { + var highlighted = el.__highlighted; + + if (!highlighted) { + return; + } + + el.__highlighted = false; + + if (el.isGroup) { + return; + } + + if (highlighted === 'layer') { + el.__zr && el.__zr.removeHover(el); + } else { + var style = el.style; + var normalStl = el.__cachedNormalStl; + + if (normalStl) { + rollbackDefaultTextStyle(style); + el.setStyle(normalStl); + applyDefaultTextStyle(style); + } // `__cachedNormalZ2` will not be reset if calling `setElementHoverStyle` + // when `el` is on emphasis state. So here by comparing with 1, we try + // hard to make the bug case rare. + + + var normalZ2 = el.__cachedNormalZ2; + + if (normalZ2 != null && el.z2 - normalZ2 === Z2_EMPHASIS_LIFT) { + el.z2 = normalZ2; + } + } +} + +function traverseUpdate(el, updater, commonParam) { + // If root is group, also enter updater for `highDownOnUpdate`. + var fromState = NORMAL; + var toState = NORMAL; + var trigger; // See the rule of `highDownOnUpdate` on `graphic.setAsHighDownDispatcher`. + + el.__highlighted && (fromState = EMPHASIS, trigger = true); + updater(el, commonParam); + el.__highlighted && (toState = EMPHASIS, trigger = true); + el.isGroup && el.traverse(function (child) { + !child.isGroup && updater(child, commonParam); + }); + trigger && el.__highDownOnUpdate && el.__highDownOnUpdate(fromState, toState); +} +/** + * Set hover style (namely "emphasis style") of element, based on the current + * style of the given `el`. + * This method should be called after all of the normal styles have been adopted + * to the `el`. See the reason on `setHoverStyle`. + * + * @param {module:zrender/Element} el Should not be `zrender/container/Group`. + * @param {Object} [el.hoverStyle] Can be set on el or its descendants, + * e.g., `el.hoverStyle = ...; graphic.setHoverStyle(el); `. + * Often used when item group has a label element and it's hoverStyle is different. + * @param {Object|boolean} [hoverStl] The specified hover style. + * If set as `false`, disable the hover style. + * Similarly, The `el.hoverStyle` can alse be set + * as `false` to disable the hover style. + * Otherwise, use the default hover style if not provided. + */ + + +function setElementHoverStyle(el, hoverStl) { + // For performance consideration, it might be better to make the "hover style" only the + // difference properties from the "normal style", but not a entire copy of all styles. + hoverStl = el.__hoverStl = hoverStl !== false && (el.hoverStyle || hoverStl || {}); + el.__hoverStlDirty = true; // FIXME + // It is not completely right to save "normal"/"emphasis" flag on elements. + // It probably should be saved on `data` of series. Consider the cases: + // (1) A highlighted elements are moved out of the view port and re-enter + // again by dataZoom. + // (2) call `setOption` and replace elements totally when they are highlighted. + + if (el.__highlighted) { + // Consider the case: + // The styles of a highlighted `el` is being updated. The new "emphasis style" + // should be adapted to the `el`. Notice here new "normal styles" should have + // been set outside and the cached "normal style" is out of date. + el.__cachedNormalStl = null; // Do not clear `__cachedNormalZ2` here, because setting `z2` is not a constraint + // of this method. In most cases, `z2` is not set and hover style should be able + // to rollback. Of course, that would bring bug, but only in a rare case, see + // `doSingleLeaveHover` for details. + + singleEnterNormal(el); + singleEnterEmphasis(el); + } +} + +function onElementMouseOver(e) { + !shouldSilent(this, e) // "emphasis" event highlight has higher priority than mouse highlight. + && !this.__highByOuter && traverseUpdate(this, singleEnterEmphasis); +} + +function onElementMouseOut(e) { + !shouldSilent(this, e) // "emphasis" event highlight has higher priority than mouse highlight. + && !this.__highByOuter && traverseUpdate(this, singleEnterNormal); +} + +function onElementEmphasisEvent(highlightDigit) { + this.__highByOuter |= 1 << (highlightDigit || 0); + traverseUpdate(this, singleEnterEmphasis); +} + +function onElementNormalEvent(highlightDigit) { + !(this.__highByOuter &= ~(1 << (highlightDigit || 0))) && traverseUpdate(this, singleEnterNormal); +} + +function shouldSilent(el, e) { + return el.__highDownSilentOnTouch && e.zrByTouch; +} +/** + * Set hover style (namely "emphasis style") of element, + * based on the current style of the given `el`. + * + * (1) + * **CONSTRAINTS** for this method: + * This method MUST be called after all of the normal styles having been adopted + * to the `el`. + * The input `hoverStyle` (that is, "emphasis style") MUST be the subset of the + * "normal style" having been set to the el. + * `color` MUST be one of the "normal styles" (because color might be lifted as + * a default hover style). + * + * The reason: this method treat the current style of the `el` as the "normal style" + * and cache them when enter/update the "emphasis style". Consider the case: the `el` + * is in "emphasis" state and `setOption`/`dispatchAction` trigger the style updating + * logic, where the el should shift from the original emphasis style to the new + * "emphasis style" and should be able to "downplay" back to the new "normal style". + * + * Indeed, it is error-prone to make a interface has so many constraints, but I have + * not found a better solution yet to fit the backward compatibility, performance and + * the current programming style. + * + * (2) + * Call the method for a "root" element once. Do not call it for each descendants. + * If the descendants elemenets of a group has itself hover style different from the + * root group, we can simply mount the style on `el.hoverStyle` for them, but should + * not call this method for them. + * + * (3) These input parameters can be set directly on `el`: + * + * @param {module:zrender/Element} el + * @param {Object} [el.hoverStyle] See `graphic.setElementHoverStyle`. + * @param {boolean} [el.highDownSilentOnTouch=false] See `graphic.setAsHighDownDispatcher`. + * @param {Function} [el.highDownOnUpdate] See `graphic.setAsHighDownDispatcher`. + * @param {Object|boolean} [hoverStyle] See `graphic.setElementHoverStyle`. + */ + + +function setHoverStyle(el, hoverStyle) { + setAsHighDownDispatcher(el, true); + traverseUpdate(el, setElementHoverStyle, hoverStyle); +} +/** + * @param {module:zrender/Element} el + * @param {Function} [el.highDownOnUpdate] Called when state updated. + * Since `setHoverStyle` has the constraint that it must be called after + * all of the normal style updated, `highDownOnUpdate` is not needed to + * trigger if both `fromState` and `toState` is 'normal', and needed to + * trigger if both `fromState` and `toState` is 'emphasis', which enables + * to sync outside style settings to "emphasis" state. + * @this {string} This dispatcher `el`. + * @param {string} fromState Can be "normal" or "emphasis". + * `fromState` might equal to `toState`, + * for example, when this method is called when `el` is + * on "emphasis" state. + * @param {string} toState Can be "normal" or "emphasis". + * + * FIXME + * CAUTION: Do not expose `highDownOnUpdate` outside echarts. + * Because it is not a complete solution. The update + * listener should not have been mount in element, + * and the normal/emphasis state should not have + * mantained on elements. + * + * @param {boolean} [el.highDownSilentOnTouch=false] + * 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 {boolean} [asDispatcher=true] If `false`, do not set as "highDownDispatcher". + */ + +function setAsHighDownDispatcher(el, asDispatcher) { + var disable = asDispatcher === false; // Make `highDownSilentOnTouch` and `highDownOnUpdate` only work after + // `setAsHighDownDispatcher` called. Avoid it is modified by user unexpectedly. + + el.__highDownSilentOnTouch = el.highDownSilentOnTouch; + el.__highDownOnUpdate = el.highDownOnUpdate; // Simple optimize, since this method might be + // called for each elements of a group in some cases. + + if (!disable || el.__highDownDispatcher) { + var method = disable ? 'off' : 'on'; // Duplicated function will be auto-ignored, see Eventful.js. + + el[method]('mouseover', onElementMouseOver)[method]('mouseout', onElementMouseOut); // 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. + + el.__highByOuter = el.__highByOuter || 0; + el.__highDownDispatcher = !disable; + } +} +/** + * @param {module:zrender/src/Element} el + * @return {boolean} + */ + +function isHighDownDispatcher(el) { + return !!(el && el.__highDownDispatcher); +} +/** + * 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; +} +/** + * See more info in `setTextStyleCommon`. + * @param {Object|module:zrender/graphic/Style} normalStyle + * @param {Object} emphasisStyle + * @param {module:echarts/model/Model} normalModel + * @param {module:echarts/model/Model} emphasisModel + * @param {Object} opt Check `opt` of `setTextStyleCommon` to find other props. + * @param {string|Function} [opt.defaultText] + * @param {module:echarts/model/Model} [opt.labelFetcher] Fetch text by + * `opt.labelFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)` + * @param {module:echarts/model/Model} [opt.labelDataIndex] Fetch text by + * `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)` + * @param {module:echarts/model/Model} [opt.labelDimIndex] Fetch text by + * `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)` + * @param {Object} [normalSpecified] + * @param {Object} [emphasisSpecified] + */ + +function setLabelStyle(normalStyle, emphasisStyle, normalModel, emphasisModel, opt, normalSpecified, emphasisSpecified) { + opt = opt || EMPTY_OBJ; + var labelFetcher = opt.labelFetcher; + var labelDataIndex = opt.labelDataIndex; + var labelDimIndex = opt.labelDimIndex; // This scenario, `label.normal.show = true; label.emphasis.show = false`, + // is not supported util someone requests. + + var showNormal = normalModel.getShallow('show'); + var showEmphasis = emphasisModel.getShallow('show'); // Consider performance, only fetch label when necessary. + // If `normal.show` is `false` and `emphasis.show` is `true` and `emphasis.formatter` is not set, + // label should be displayed, where text is fetched by `normal.formatter` or `opt.defaultText`. + + var baseText; + + if (showNormal || showEmphasis) { + if (labelFetcher) { + baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex); + } + + if (baseText == null) { + baseText = isFunction$1(opt.defaultText) ? opt.defaultText(labelDataIndex, opt) : opt.defaultText; + } + } + + var normalStyleText = showNormal ? baseText : null; + var emphasisStyleText = showEmphasis ? retrieve2(labelFetcher ? labelFetcher.getFormattedLabel(labelDataIndex, 'emphasis', null, labelDimIndex) : null, baseText) : null; // Optimize: If style.text is null, text will not be drawn. + + if (normalStyleText != null || emphasisStyleText != null) { + // Always set `textStyle` even if `normalStyle.text` is null, because default + // values have to be set on `normalStyle`. + // If we set default values on `emphasisStyle`, consider case: + // Firstly, `setOption(... label: {normal: {text: null}, emphasis: {show: true}} ...);` + // Secondly, `setOption(... label: {noraml: {show: true, text: 'abc', color: 'red'} ...);` + // Then the 'red' will not work on emphasis. + setTextStyle(normalStyle, normalModel, normalSpecified, opt); + setTextStyle(emphasisStyle, emphasisModel, emphasisSpecified, opt, true); + } + + normalStyle.text = normalStyleText; + emphasisStyle.text = emphasisStyleText; +} +/** + * Modify label style manually. + * Only works after `setLabelStyle` and `setElementHoverStyle` called. + * + * @param {module:zrender/src/Element} el + * @param {Object} [normalStyleProps] optional + * @param {Object} [emphasisStyleProps] optional + */ + +function modifyLabelStyle(el, normalStyleProps, emphasisStyleProps) { + var elStyle = el.style; + + if (normalStyleProps) { + rollbackDefaultTextStyle(elStyle); + el.setStyle(normalStyleProps); + applyDefaultTextStyle(elStyle); + } + + elStyle = el.__hoverStl; + + if (emphasisStyleProps && elStyle) { + rollbackDefaultTextStyle(elStyle); + extend(elStyle, emphasisStyleProps); + applyDefaultTextStyle(elStyle); + } +} +/** + * Set basic textStyle properties. + * See more info in `setTextStyleCommon`. + * @param {Object|module:zrender/graphic/Style} textStyle + * @param {module:echarts/model/Model} model + * @param {Object} [specifiedTextStyle] Can be overrided by settings in model. + * @param {Object} [opt] See `opt` of `setTextStyleCommon`. + * @param {boolean} [isEmphasis] + */ + +function setTextStyle(textStyle, textStyleModel, specifiedTextStyle, opt, isEmphasis) { + setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis); + specifiedTextStyle && extend(textStyle, specifiedTextStyle); // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false); + + return textStyle; +} +/** + * Set text option in the style. + * See more info in `setTextStyleCommon`. + * @deprecated + * @param {Object} textStyle + * @param {module:echarts/model/Model} labelModel + * @param {string|boolean} defaultColor Default text color. + * If set as false, it will be processed as a emphasis style. + */ + +function setText(textStyle, labelModel, defaultColor) { + var opt = { + isRectText: true + }; + var isEmphasis; + + if (defaultColor === false) { + isEmphasis = true; + } else { + // Support setting color as 'auto' to get visual color. + opt.autoColor = defaultColor; + } + + setTextStyleCommon(textStyle, labelModel, opt, isEmphasis); // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false); +} +/** + * 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.) + * + * The `textStyle` object can either be a plain object or an instance of + * `zrender/src/graphic/Style`, and either be the style of normal or emphasis. + * After this mothod called, the `textStyle` object can then be used in + * `el.setStyle(textStyle)` or `el.hoverStyle = textStyle`. + * + * Default value will be adopted and `insideRollbackOpt` will be created. + * See `applyDefaultTextStyle` `rollbackDefaultTextStyle` for more details. + * + * opt: { + * disableBox: boolean, Whether diable drawing box of block (outer most). + * isRectText: boolean, + * autoColor: string, specify a color when color is 'auto', + * for textFill, textStroke, textBackgroundColor, and textBorderColor. + * If autoColor specified, it is used as default textFill. + * useInsideStyle: + * `true`: Use inside style (textFill, textStroke, textStrokeWidth) + * if `textFill` is not specified. + * `false`: Do not use inside style. + * `null/undefined`: use inside style if `isRectText` is true and + * `textFill` is not specified and textPosition contains `'inside'`. + * forceRich: boolean + * } + */ + +function setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis) { + // Consider there will be abnormal when merge hover style to normal style if given default value. + opt = opt || EMPTY_OBJ; + + if (opt.isRectText) { + var textPosition; + + if (opt.getTextPosition) { + textPosition = opt.getTextPosition(textStyleModel, isEmphasis); + } else { + textPosition = textStyleModel.getShallow('position') || (isEmphasis ? null : 'inside'); // 'outside' is not a valid zr textPostion value, but used + // in bar series, and magric type should be considered. + + textPosition === 'outside' && (textPosition = 'top'); + } + + textStyle.textPosition = textPosition; + textStyle.textOffset = textStyleModel.getShallow('offset'); + var labelRotate = textStyleModel.getShallow('rotate'); + labelRotate != null && (labelRotate *= Math.PI / 180); + textStyle.textRotation = labelRotate; + textStyle.textDistance = retrieve2(textStyleModel.getShallow('distance'), isEmphasis ? null : 5); + } + + 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 in richItemNames) { + if (richItemNames.hasOwnProperty(name)) { + // Cascade is supported in rich. + var richTextStyle = textStyleModel.getModel(['rich', name]); // 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] = {}, richTextStyle, globalTextStyle, opt, isEmphasis); + } + } + } + + textStyle.rich = richResult; + setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, true); + + if (opt.forceRich && !opt.textStyle) { + opt.textStyle = {}; + } + + return textStyle; +} // Consider case: +// { +// data: [{ +// value: 12, +// label: { +// rich: { +// // no 'a' here but using parent 'a'. +// } +// } +// }], +// rich: { +// a: { ... } +// } +// } + + +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 || {}; + + for (var name in rich) { + if (rich.hasOwnProperty(name)) { + richItemNameMap[name] = 1; + } + } + } + + textStyleModel = textStyleModel.parentModel; + } + + return richItemNameMap; +} + +function setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, isBlock) { + // In merge mode, default value should not be given. + globalTextStyle = !isEmphasis && globalTextStyle || EMPTY_OBJ; + textStyle.textFill = getAutoColor(textStyleModel.getShallow('color'), opt) || globalTextStyle.color; + textStyle.textStroke = getAutoColor(textStyleModel.getShallow('textBorderColor'), opt) || globalTextStyle.textBorderColor; + textStyle.textStrokeWidth = retrieve2(textStyleModel.getShallow('textBorderWidth'), globalTextStyle.textBorderWidth); + + if (!isEmphasis) { + if (isBlock) { + textStyle.insideRollbackOpt = opt; + applyDefaultTextStyle(textStyle); + } // Set default finally. + + + if (textStyle.textFill == null) { + textStyle.textFill = opt.autoColor; + } + } // 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. + + + textStyle.fontStyle = textStyleModel.getShallow('fontStyle') || globalTextStyle.fontStyle; + textStyle.fontWeight = textStyleModel.getShallow('fontWeight') || globalTextStyle.fontWeight; + textStyle.fontSize = textStyleModel.getShallow('fontSize') || globalTextStyle.fontSize; + textStyle.fontFamily = textStyleModel.getShallow('fontFamily') || globalTextStyle.fontFamily; + textStyle.textAlign = textStyleModel.getShallow('align'); + textStyle.textVerticalAlign = textStyleModel.getShallow('verticalAlign') || textStyleModel.getShallow('baseline'); + textStyle.textLineHeight = textStyleModel.getShallow('lineHeight'); + textStyle.textWidth = textStyleModel.getShallow('width'); + textStyle.textHeight = textStyleModel.getShallow('height'); + textStyle.textTag = textStyleModel.getShallow('tag'); + + if (!isBlock || !opt.disableBox) { + textStyle.textBackgroundColor = getAutoColor(textStyleModel.getShallow('backgroundColor'), opt); + textStyle.textPadding = textStyleModel.getShallow('padding'); + textStyle.textBorderColor = getAutoColor(textStyleModel.getShallow('borderColor'), opt); + textStyle.textBorderWidth = textStyleModel.getShallow('borderWidth'); + textStyle.textBorderRadius = textStyleModel.getShallow('borderRadius'); + textStyle.textBoxShadowColor = textStyleModel.getShallow('shadowColor'); + textStyle.textBoxShadowBlur = textStyleModel.getShallow('shadowBlur'); + textStyle.textBoxShadowOffsetX = textStyleModel.getShallow('shadowOffsetX'); + textStyle.textBoxShadowOffsetY = textStyleModel.getShallow('shadowOffsetY'); + } + + textStyle.textShadowColor = textStyleModel.getShallow('textShadowColor') || globalTextStyle.textShadowColor; + textStyle.textShadowBlur = textStyleModel.getShallow('textShadowBlur') || globalTextStyle.textShadowBlur; + textStyle.textShadowOffsetX = textStyleModel.getShallow('textShadowOffsetX') || globalTextStyle.textShadowOffsetX; + textStyle.textShadowOffsetY = textStyleModel.getShallow('textShadowOffsetY') || globalTextStyle.textShadowOffsetY; +} + +function getAutoColor(color, opt) { + return color !== 'auto' ? color : opt && opt.autoColor ? opt.autoColor : null; +} +/** + * Give some default value to the input `textStyle` object, based on the current settings + * in this `textStyle` object. + * + * The Scenario: + * when text position is `inside` and `textFill` is not specified, we show + * text border by default for better view. But it should be considered that text position + * might be changed when hovering or being emphasis, where the `insideRollback` is used to + * restore the style. + * + * Usage (& NOTICE): + * When a style object (eithor plain object or instance of `zrender/src/graphic/Style`) is + * about to be modified on its text related properties, `rollbackDefaultTextStyle` should + * be called before the modification and `applyDefaultTextStyle` should be called after that. + * (For the case that all of the text related properties is reset, like `setTextStyleCommon` + * does, `rollbackDefaultTextStyle` is not needed to be called). + */ + + +function applyDefaultTextStyle(textStyle) { + var textPosition = textStyle.textPosition; + var opt = textStyle.insideRollbackOpt; + var insideRollback; + + if (opt && textStyle.textFill == null) { + var autoColor = opt.autoColor; + var isRectText = opt.isRectText; + var useInsideStyle = opt.useInsideStyle; + var useInsideStyleCache = useInsideStyle !== false && (useInsideStyle === true || isRectText && textPosition // textPosition can be [10, 30] + && typeof textPosition === 'string' && textPosition.indexOf('inside') >= 0); + var useAutoColorCache = !useInsideStyleCache && autoColor != null; // All of the props declared in `CACHED_LABEL_STYLE_PROPERTIES` are to be cached. + + if (useInsideStyleCache || useAutoColorCache) { + insideRollback = { + textFill: textStyle.textFill, + textStroke: textStyle.textStroke, + textStrokeWidth: textStyle.textStrokeWidth + }; + } + + if (useInsideStyleCache) { + textStyle.textFill = '#fff'; // Consider text with #fff overflow its container. + + if (textStyle.textStroke == null) { + textStyle.textStroke = autoColor; + textStyle.textStrokeWidth == null && (textStyle.textStrokeWidth = 2); + } + } + + if (useAutoColorCache) { + textStyle.textFill = autoColor; + } + } // Always set `insideRollback`, so that the previous one can be cleared. + + + textStyle.insideRollback = insideRollback; +} +/** + * Consider the case: in a scatter, + * label: { + * normal: {position: 'inside'}, + * emphasis: {position: 'top'} + * } + * In the normal state, the `textFill` will be set as '#fff' for pretty view (see + * `applyDefaultTextStyle`), but when switching to emphasis state, the `textFill` + * should be retured to 'autoColor', but not keep '#fff'. + */ + + +function rollbackDefaultTextStyle(style) { + var insideRollback = style.insideRollback; + + if (insideRollback) { + // Reset all of the props in `CACHED_LABEL_STYLE_PROPERTIES`. + style.textFill = insideRollback.textFill; + style.textStroke = insideRollback.textStroke; + style.textStrokeWidth = insideRollback.textStrokeWidth; + style.insideRollback = null; + } +} + +function getFont(opt, ecModel) { + // ecModel or default text style model. + 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(' ')); +} + +function animateOrSetProps(isUpdate, el, props, animatableModel, dataIndex, cb) { + if (typeof dataIndex === 'function') { + cb = dataIndex; + dataIndex = null; + } // Do not check 'animation' property directly here. Consider this case: + // animation model is an `itemModel`, whose does not have `isAnimationEnabled` + // but its parent model (`seriesModel`) does. + + + var animationEnabled = animatableModel && animatableModel.isAnimationEnabled(); + + if (animationEnabled) { + var postfix = isUpdate ? 'Update' : ''; + var duration = animatableModel.getShallow('animationDuration' + postfix); + var animationEasing = animatableModel.getShallow('animationEasing' + postfix); + var animationDelay = animatableModel.getShallow('animationDelay' + postfix); + + if (typeof animationDelay === 'function') { + animationDelay = animationDelay(dataIndex, animatableModel.getAnimationDelayParams ? animatableModel.getAnimationDelayParams(el, dataIndex) : null); + } + + if (typeof duration === 'function') { + duration = duration(dataIndex); + } + + duration > 0 ? el.animateTo(props, duration, animationDelay || 0, animationEasing, cb, !!cb) : (el.stopAnimation(), el.attr(props), cb && cb()); + } else { + el.stopAnimation(); + el.attr(props); + cb && cb(); + } +} +/** + * Update graphic element properties with or without animation according to the + * configuration in series. + * + * Caution: this method will stop previous animation. + * So if do not use this method to one element twice before + * animation starts, unless you know what you are doing. + * + * @param {module:zrender/Element} el + * @param {Object} props + * @param {module:echarts/model/Model} [animatableModel] + * @param {number} [dataIndex] + * @param {Function} [cb] + * @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, animatableModel, dataIndex, cb) { + animateOrSetProps(true, el, props, animatableModel, dataIndex, cb); +} +/** + * Init graphic element properties with or without animation according to the + * configuration in series. + * + * Caution: this method will stop previous animation. + * So if do not use this method to one element twice before + * animation starts, unless you know what you are doing. + * + * @param {module:zrender/Element} el + * @param {Object} props + * @param {module:echarts/model/Model} [animatableModel] + * @param {number} [dataIndex] + * @param {Function} cb + */ + +function initProps(el, props, animatableModel, dataIndex, cb) { + animateOrSetProps(false, el, props, animatableModel, dataIndex, cb); +} +/** + * Get transform matrix of target (param target), + * in coordinate of its ancestor (param ancestor) + * + * @param {module:zrender/mixin/Transformable} target + * @param {module:zrender/mixin/Transformable} [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 {Array.} target [x, y] + * @param {Array.|TypedArray.|Object} transform Can be: + * + Transform matrix: like [1, 0, 0, 1, 0, 0] + * + {position, rotation, scale}, the same as `zrender/Transformable`. + * @param {boolean=} invert Whether use invert matrix. + * @return {Array.} [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 {string} direction 'left' 'right' 'top' 'bottom' + * @param {Array.} transform Transform matrix: like [1, 0, 0, 1, 0, 0] + * @param {boolean=} invert Whether use invert matrix. + * @return {string} Transformed direction. 'left' 'right' 'top' 'bottom' + */ + +function transformDirection(direction, transform, invert$$1) { + // 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$$1); + return Math.abs(vertex[0]) > Math.abs(vertex[1]) ? vertex[0] > 0 ? 'right' : 'left' : vertex[1] > 0 ? 'bottom' : 'top'; +} +/** + * Apply group transition animation from g1 to g2. + * If no animatableModel, no animation. + */ + +function groupTransition(g1, g2, animatableModel, cb) { + if (!g1 || !g2) { + return; + } + + function getElMap(g) { + var elMap = {}; + g.traverse(function (el) { + if (!el.isGroup && el.anid) { + elMap[el.anid] = el; + } + }); + return elMap; + } + + function getAnimatableProps(el) { + var obj = { + position: clone$1(el.position), + rotation: el.rotation + }; + + if (el.shape) { + obj.shape = extend({}, el.shape); + } + + return obj; + } + + var elMap1 = getElMap(g1); + g2.traverse(function (el) { + if (!el.isGroup && el.anid) { + var oldEl = elMap1[el.anid]; + + if (oldEl) { + var newProp = getAnimatableProps(el); + el.attr(getAnimatableProps(oldEl)); + updateProps(el, newProp, animatableModel, el.dataIndex); + } // else { + // if (el.previousProps) { + // graphic.updateProps + // } + // } + + } + }); +} +/** + * @param {Array.>} points Like: [[23, 44], [53, 66], ...] + * @param {Object} rect {x, y, width, height} + * @return {Array.>} A new clipped points. + */ + +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$1(x, rect.x); + x = mathMin$1(x, rect.x + rect.width); + var y = point[1]; + y = mathMax$1(y, rect.y); + y = mathMin$1(y, rect.y + rect.height); + return [x, y]; + }); +} +/** + * @param {Object} targetRect {x, y, width, height} + * @param {Object} rect {x, y, width, height} + * @return {Object} A new clipped rect. If rect size are negative, return undefined. + */ + +function clipRectByRect(targetRect, rect) { + var x = mathMax$1(targetRect.x, rect.x); + var x2 = mathMin$1(targetRect.x + targetRect.width, rect.x + rect.width); + var y = mathMax$1(targetRect.y, rect.y); + var y2 = mathMin$1(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 + }; + } +} +/** + * @param {string} iconStr Support 'image://' or 'path://' or direct svg path. + * @param {Object} [opt] Properties of `module:zrender/Element`, except `style`. + * @param {Object} [rect] {x, y, width, height} + * @return {module:zrender/Element} Icon path or image element. + */ + +function createIcon(iconStr, opt, rect) { + opt = extend({ + rectHover: true + }, opt); + var style = opt.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 ZImage(opt)) : makePath(iconStr.replace('path://', ''), opt, 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. + * + * @param {number} a1x + * @param {number} a1y + * @param {number} a2x + * @param {number} a2y + * @param {Array.>} points Points of the polygon. + * @return {boolean} + */ + +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. + * + * @param {number} a1x + * @param {number} a1y + * @param {number} a2x + * @param {number} a2y + * @param {number} b1x + * @param {number} b1y + * @param {number} b2x + * @param {number} b2y + * @return {boolean} + */ + +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; +} // Register built-in shapes. These shapes might be overwirtten +// by users, although we do not recommend that. + + +registerShape('circle', Circle); +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 = (Object.freeze || Object)({ + Z2_EMPHASIS_LIFT: Z2_EMPHASIS_LIFT, + CACHED_LABEL_STYLE_PROPERTIES: CACHED_LABEL_STYLE_PROPERTIES, + extendShape: extendShape, + extendPath: extendPath, + registerShape: registerShape, + getShapeClass: getShapeClass, + makePath: makePath, + makeImage: makeImage, + mergePath: mergePath, + resizePath: resizePath, + subPixelOptimizeLine: subPixelOptimizeLine, + subPixelOptimizeRect: subPixelOptimizeRect, + subPixelOptimize: subPixelOptimize, + setElementHoverStyle: setElementHoverStyle, + setHoverStyle: setHoverStyle, + setAsHighDownDispatcher: setAsHighDownDispatcher, + isHighDownDispatcher: isHighDownDispatcher, + getHighlightDigit: getHighlightDigit, + setLabelStyle: setLabelStyle, + modifyLabelStyle: modifyLabelStyle, + setTextStyle: setTextStyle, + setText: setText, + getFont: getFont, + updateProps: updateProps, + initProps: initProps, + getTransform: getTransform, + applyTransform: applyTransform$1, + transformDirection: transformDirection, + groupTransition: groupTransition, + clipPointsByRect: clipPointsByRect, + clipRectByRect: clipRectByRect, + createIcon: createIcon, + linePolygonIntersect: linePolygonIntersect, + lineLineIntersect: lineLineIntersect, + Group: Group, + Image: ZImage, + Text: Text, + Circle: Circle, + Sector: Sector, + Ring: Ring, + Polygon: Polygon, + Polyline: Polyline, + Rect: Rect, + Line: Line, + BezierCurve: BezierCurve, + Arc: Arc, + IncrementalDisplayable: IncrementalDisplayble, + CompoundPath: CompoundPath, + LinearGradient: LinearGradient, + RadialGradient: RadialGradient, + BoundingRect: BoundingRect +}); + +/* +* 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 PATH_COLOR = ['textStyle', 'color']; +var textStyleMixin = { + /** + * Get color property or get color from option.textStyle.color + * @param {boolean} [isEmphasis] + * @return {string} + */ + 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} + */ + getFont: function () { + return getFont({ + fontStyle: this.getShallow('fontStyle'), + fontWeight: this.getShallow('fontWeight'), + fontSize: this.getShallow('fontSize'), + fontFamily: this.getShallow('fontFamily') + }, this.ecModel); + }, + getTextRect: function (text) { + return getBoundingRect(text, this.getFont(), this.getShallow('align'), this.getShallow('verticalAlign') || this.getShallow('baseline'), this.getShallow('padding'), this.getShallow('lineHeight'), this.getShallow('rich'), this.getShallow('truncateText')); + } +}; + +/* +* 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 getItemStyle = makeStyleMapper([['fill', 'color'], ['stroke', 'borderColor'], ['lineWidth', 'borderWidth'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'], ['textPosition'], ['textAlign']]); +var itemStyleMixin = { + getItemStyle: function (excludes, includes) { + var style = getItemStyle(this, excludes, includes); + var lineDash = this.getBorderLineDash(); + lineDash && (style.lineDash = lineDash); + return style; + }, + getBorderLineDash: function () { + var lineType = this.get('borderType'); + return lineType === 'solid' || lineType == null ? null : lineType === 'dashed' ? [5, 5] : [1, 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. +*/ + +/** + * @module echarts/model/Model + */ +var mixin$1 = mixin; +var inner = makeInner(); +/** + * @alias module:echarts/model/Model + * @constructor + * @param {Object} [option] + * @param {module:echarts/model/Model} [parentModel] + * @param {module:echarts/model/Global} [ecModel] + */ + +function Model(option, parentModel, ecModel) { + /** + * @type {module:echarts/model/Model} + * @readOnly + */ + this.parentModel = parentModel; + /** + * @type {module:echarts/model/Global} + * @readOnly + */ + + this.ecModel = ecModel; + /** + * @type {Object} + * @protected + */ + + 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 = { + constructor: Model, + + /** + * Model 的初始化函数 + * @param {Object} option + */ + init: null, + + /** + * 从新的 Option merge + */ + mergeOption: function (option) { + merge(this.option, option, true); + }, + + /** + * @param {string|Array.} path + * @param {boolean} [ignoreParent=false] + * @return {*} + */ + get: function (path, ignoreParent) { + if (path == null) { + return this.option; + } + + return doGet(this.option, this.parsePath(path), !ignoreParent && getParent(this, path)); + }, + + /** + * @param {string} key + * @param {boolean} [ignoreParent=false] + * @return {*} + */ + getShallow: function (key, ignoreParent) { + var option = this.option; + var val = option == null ? option : option[key]; + var parentModel = !ignoreParent && getParent(this, key); + + if (val == null && parentModel) { + val = parentModel.getShallow(key); + } + + return val; + }, + + /** + * @param {string|Array.} [path] + * @param {module:echarts/model/Model} [parentModel] + * @return {module:echarts/model/Model} + */ + getModel: function (path, parentModel) { + var obj = path == null ? this.option : doGet(this.option, path = this.parsePath(path)); + var thisParentModel; + parentModel = parentModel || (thisParentModel = getParent(this, path)) && thisParentModel.getModel(path); + return new Model(obj, parentModel, this.ecModel); + }, + + /** + * If model has option + */ + isEmpty: function () { + return this.option == null; + }, + restoreData: function () {}, + // Pending + clone: function () { + var Ctor = this.constructor; + return new Ctor(clone(this.option)); + }, + setReadOnly: function (properties) {// clazzUtil.setReadOnly(this, properties); + }, + // If path is null/undefined, return null/undefined. + parsePath: function (path) { + if (typeof path === 'string') { + path = path.split('.'); + } + + return path; + }, + + /** + * @param {Function} getParentMethod + * param {Array.|string} path + * return {module:echarts/model/Model} + */ + customizeGetParent: function (getParentMethod) { + inner(this).getParent = getParentMethod; + }, + isAnimationEnabled: function () { + if (!env$1.node) { + if (this.option.animation != null) { + return !!this.option.animation; + } else if (this.parentModel) { + return this.parentModel.isAnimationEnabled(); + } + } + } +}; + +function doGet(obj, pathArr, parentModel) { + 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.get(pathArr); + } + + return obj; +} // `path` can be null/undefined + + +function getParent(model, path) { + var getParentMethod = inner(model).getParent; + return getParentMethod ? getParentMethod.call(model, path) : model.parentModel; +} // Enable Model.extend. + + +enableClassExtend(Model); +enableClassCheck(Model); +mixin$1(Model, lineStyleMixin); +mixin$1(Model, areaStyleMixin); +mixin$1(Model, textStyleMixin); +mixin$1(Model, itemStyleMixin); + +/* +* 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 base = 0; +/** + * @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++, Math.random().toFixed(5)].join('_'); +} +/** + * @inner + */ + +function enableSubTypeDefaulter(entity) { + var subTypeDefaulters = {}; + + entity.registerSubTypeDefaulter = function (componentType, defaulter) { + componentType = parseClassType$1(componentType); + subTypeDefaulters[componentType.main] = defaulter; + }; + + entity.determineSubType = function (componentType, option) { + var type = option.type; + + if (!type) { + var componentTypeMain = parseClassType$1(componentType).main; + + if (entity.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) { + type = subTypeDefaulters[componentTypeMain](option); + } + } + + return type; + }; + + return 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 circle dependencey, Error will be thrown. + * + */ + +function enableTopologicalTravel(entity, dependencyGetter) { + /** + * @public + * @param {Array.} targetNameList Target Component type list. + * Can be ['aa', 'bb', 'aa.xx'] + * @param {Array.} fullNameList By which we can build dependency graph. + * @param {Function} callback Params: componentType, dependencies. + * @param {Object} context Scope of callback. + */ + entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) { + if (!targetNameList.length) { + return; + } + + var result = makeDepndencyGraph(fullNameList); + var graph = result.graph; + var stack = result.noEntryList; + var targetNameSet = {}; + each$1(targetNameList, function (name) { + targetNameSet[name] = true; + }); + + while (stack.length) { + var currComponentType = stack.pop(); + var currVertex = graph[currComponentType]; + var isInTargetNameSet = !!targetNameSet[currComponentType]; + + if (isInTargetNameSet) { + callback.call(context, currComponentType, currVertex.originalDeps.slice()); + delete targetNameSet[currComponentType]; + } + + each$1(currVertex.successor, isInTargetNameSet ? removeEdgeAndAdd : removeEdge); + } + + each$1(targetNameSet, function () { + throw new Error('Circle dependency may exists'); + }); + + function removeEdge(succComponentType) { + graph[succComponentType].entryCount--; + + if (graph[succComponentType].entryCount === 0) { + stack.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); + } + }; + /** + * DepndencyGraph: {Object} + * key: conponentType, + * value: { + * successor: [conponentTypes...], + * originalDeps: [conponentTypes...], + * entryCount: {number} + * } + */ + + + function makeDepndencyGraph(fullNameList) { + var graph = {}; + var noEntryList = []; + each$1(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$1(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$1(originalDeps, function (dep) { + indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep); + }); + return availableDeps; + } +} + +/* +* 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. +*/ + +/* +* A third-party license is embeded for some of the code in this file: +* The method "quantile" was copied from "d3.js". +* (See more details in the comment of the method below.) +* The use of the source code of this file is also subject to the terms +* and consitions of the license of "d3.js" (BSD-3Clause, see +* ). +*/ +var RADIAN_EPSILON = 1e-4; + +function _trim(str) { + return str.replace(/^\s+|\s+$/g, ''); +} +/** + * Linear mapping a value from domain to range + * @memberOf module:echarts/util/number + * @param {(number|Array.)} val + * @param {Array.} domain Domain extent domain[0] can be bigger than domain[1] + * @param {Array.} range Range extent range[0] can be bigger than range[1] + * @param {boolean} clamp + * @return {(number|Array.} + */ + + +function linearMap(val, domain, range, clamp) { + var subDomain = domain[1] - domain[0]; + var subRange = range[1] - range[0]; + + if (subDomain === 0) { + return subRange === 0 ? range[0] : (range[0] + range[1]) / 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 <= domain[0]) { + return range[0]; + } else if (val >= domain[1]) { + return range[1]; + } + } else { + if (val >= domain[0]) { + return range[0]; + } else if (val <= domain[1]) { + return range[1]; + } + } + } else { + if (val === domain[0]) { + return range[0]; + } + + if (val === domain[1]) { + return range[1]; + } + } + + return (val - domain[0]) / subDomain * subRange + range[0]; +} +/** + * Convert a percent string to absolute number. + * Returns NaN if percent is not a valid string or number + * @memberOf module:echarts/util/number + * @param {string|number} percent + * @param {number} all + * @return {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 (typeof percent === 'string') { + if (_trim(percent).match(/%$/)) { + return parseFloat(percent) / 100 * all; + } + + return parseFloat(percent); + } + + return percent == null ? NaN : +percent; +} +/** + * (1) Fix rounding error of float numbers. + * (2) Support return string to avoid scientific notation like '3.5e-7'. + * + * @param {number} x + * @param {number} [precision] + * @param {boolean} [returnStr] + * @return {number|string} + */ + +function round$1(x, precision, returnStr) { + if (precision == null) { + precision = 10; + } // Avoid range error + + + precision = Math.min(Math.max(0, precision), 20); + x = (+x).toFixed(precision); + return returnStr ? x : +x; +} +/** + * asc sort arr. + * The input arr will be modified. + * + * @param {Array} arr + * @return {Array} The input arr. + */ + +function asc(arr) { + arr.sort(function (a, b) { + return a - b; + }); + return arr; +} +/** + * Get precision + * @param {number} val + */ + +function getPrecision(val) { + val = +val; + + if (isNaN(val)) { + return 0; + } // It is much faster than methods converting number to string as follows + // var tmp = val.toString(); + // return tmp.length - 1 - tmp.indexOf('.'); + // especially when precision is low + + + var e = 1; + var count = 0; + + while (Math.round(val * e) / e !== val) { + e *= 10; + count++; + } + + return count; +} +/** + * @param {string|number} val + * @return {number} + */ + +function getPrecisionSafe(val) { + var str = val.toString(); // Consider scientific notation: '3.4e-12' '3.4e+12' + + var eIndex = str.indexOf('e'); + + if (eIndex > 0) { + var precision = +str.slice(eIndex + 1); + return precision < 0 ? -precision : 0; + } else { + var dotIndex = str.indexOf('.'); + return dotIndex < 0 ? 0 : str.length - 1 - dotIndex; + } +} +/** + * Minimal dicernible data precisioin according to a single pixel. + * + * @param {Array.} dataExtent + * @param {Array.} pixelExtent + * @return {number} precision + */ + +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 {Array.} valueList a list of all data + * @param {number} idx index of the data to be processed in valueList + * @param {number} precision integer number showing digits of precision + * @return {number} 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; +} // Number.MAX_SAFE_INTEGER, ie do not support. + +var MAX_SAFE_INTEGER = 9007199254740991; +/** + * To 0 - 2 * PI, considering negative radian. + * @param {number} radian + * @return {number} + */ + +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 */ + +var TIME_REG = /^(?:(\d{4})(?:[-\/](\d{1,2})(?:[-\/](\d{1,2})(?:[T ](\d{1,2})(?::(\d\d)(?::(\d\d)(?:[.,](\d+))?)?)?(Z|[\+\-]\d\d:?\d\d)?)?)?)?)?$/; // jshint ignore:line + +/* eslint-enable */ + +/** + * @param {string|Date|number} value 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} date + */ + +function parseDate(value) { + if (value instanceof Date) { + return value; + } else if (typeof value === 'string') { + // 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] || 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] || 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 {number} val + * @return {number} + */ + +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 {number} val non-negative value + * @return {number} + */ + +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 {number} val Non-negative value. + * @param {boolean} round + * @return {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 {Array.} 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 {Array.} list, where `close` mean open or close + * of the interval, and Infinity can be used. + * @return {Array.} 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 = list[i].close; + + for (var lg = 0; lg < 2; lg++) { + if (interval[lg] <= curr) { + interval[lg] = curr; + close[lg] = !lg ? 1 - currClose : 1; + } + + curr = interval[lg]; + currClose = close[lg]; + } + + if (interval[0] === interval[1] && close[0] * close[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)); + } +} +/** + * parseFloat NaNs numeric-cast false positives (null|true|false|"") + * ...but misinterprets leading-number strings, particularly hex literals ("0x...") + * subtraction forces infinities to NaN + * + * @param {*} v + * @return {boolean} + */ + +function isNumeric(v) { + return v - parseFloat(v) >= 0; +} + +var number = (Object.freeze || Object)({ + linearMap: linearMap, + parsePercent: parsePercent$1, + round: round$1, + 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 +}); + +/* +* 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. +*/ +/** + * 每三位默认加,格式化 + * @param {string|number} x + * @return {string} + */ + +function addCommas(x) { + if (isNaN(x)) { + return '-'; + } + + x = (x + '').split('.'); + return x[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g, '$1,') + (x.length > 1 ? '.' + x[1] : ''); +} +/** + * @param {string} str + * @param {boolean} [upperCaseFirst=false] + * @return {string} str + */ + +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]; + }); +} +var TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; + +var wrapVar = function (varName, seriesIdx) { + return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}'; +}; +/** + * Template formatter + * @param {string} tpl + * @param {Array.|Object} paramsList + * @param {boolean} [encode=false] + * @return {string} + */ + + +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 + * + * @param {string} tpl + * @param {Object} param + * @param {boolean} [encode=false] + * @return {string} + */ + +function formatTplSimple(tpl, param, encode) { + each$1(param, function (value, key) { + tpl = tpl.replace('{' + key + '}', encode ? encodeHTML(value) : value); + }); + return tpl; +} +/** + * @param {Object|string} [opt] If string, means color. + * @param {string} [opt.color] + * @param {string} [opt.extraCssText] + * @param {string} [opt.type='item'] 'item' or 'subItem' + * @param {string} [opt.renderMode='html'] render mode of tooltip, 'html' or 'richText' + * @param {string} [opt.markerId='X'] id name for marker. If only one marker is in a rich text, this can be omitted. + * @return {string} + */ + +function getTooltipMarker(opt, extraCssText) { + opt = isString(opt) ? { + color: opt, + extraCssText: extraCssText + } : opt || {}; + var color = opt.color; + var type = opt.type; + var extraCssText = opt.extraCssText; + var renderMode = opt.renderMode || 'html'; + var markerId = opt.markerId || 'X'; + + if (!color) { + return ''; + } + + if (renderMode === 'html') { + return type === 'subItem' ? '' : ''; + } else { + // Space for rich element marker + return { + renderMode: renderMode, + content: '{marker' + markerId + '|} ', + style: { + color: color + } + }; + } +} + +function pad(str, len) { + str += ''; + return '0000'.substr(0, len - str.length) + str; +} +/** + * 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 (tpl === 'week' || tpl === 'month' || tpl === 'quarter' || tpl === 'half-year' || tpl === 'year') { + tpl = 'MM-dd\nyyyy'; + } + + var date = parseDate(value); + var utc = isUTC ? 'UTC' : ''; + var y = date['get' + utc + 'FullYear'](); + var M = date['get' + utc + 'Month']() + 1; + var d = date['get' + utc + 'Date'](); + var h = date['get' + utc + 'Hours'](); + var m = date['get' + utc + 'Minutes'](); + var s = date['get' + utc + 'Seconds'](); + var S = date['get' + utc + '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; +} +var truncateText$1 = truncateText; +/** + * @public + * @param {Object} opt + * @param {string} opt.text + * @param {string} opt.font + * @param {string} [opt.textAlign='left'] + * @param {string} [opt.textVerticalAlign='top'] + * @param {Array.} [opt.textPadding] + * @param {number} [opt.textLineHeight] + * @param {Object} [opt.rich] + * @param {Object} [opt.truncate] + * @return {Object} {x, y, width, height, lineHeight} + */ + +function getTextBoundingRect(opt) { + return getBoundingRect(opt.text, opt.font, opt.textAlign, opt.textVerticalAlign, opt.textPadding, opt.textLineHeight, opt.rich, opt.truncate); +} +/** + * @deprecated + * the `textLineHeight` was added later. + * For backward compatiblility, put it as the last parameter. + * But deprecated this interface. Please use `getTextBoundingRect` instead. + */ + +function getTextRect(text, font, textAlign, textVerticalAlign, textPadding, rich, truncate, textLineHeight) { + return getBoundingRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate); +} + +var format = (Object.freeze || Object)({ + addCommas: addCommas, + toCamelCase: toCamelCase, + normalizeCssArray: normalizeCssArray$1, + encodeHTML: encodeHTML, + formatTpl: formatTpl, + formatTplSimple: formatTplSimple, + getTooltipMarker: getTooltipMarker, + formatTime: formatTime, + capitalFirst: capitalFirst, + truncateText: truncateText$1, + getTextBoundingRect: getTextBoundingRect, + getTextRect: getTextRect +}); + +/* +* 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. +*/ +// Layout helpers for each component positioning +var each$3 = each$1; +/** + * @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 position = child.position; + 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; + } + + position[0] = x; + position[1] = y; + orient === 'horizontal' ? x = nextX + gap : y = nextY + gap; + }); +} +/** + * VBox or HBox layouting + * @param {string} orient + * @param {module:zrender/container/Group} group + * @param {number} gap + * @param {number} [width=Infinity] + * @param {number} [height=Infinity] + */ + + +var box = boxLayout; +/** + * VBox layouting + * @param {module:zrender/container/Group} group + * @param {number} gap + * @param {number} [width=Infinity] + * @param {number} [height=Infinity] + */ + +var vbox = curry(boxLayout, 'vertical'); +/** + * HBox layouting + * @param {module:zrender/container/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. + * + * @param {Object} positionInfo + * @param {number|string} [positionInfo.x] + * @param {number|string} [positionInfo.y] + * @param {number|string} [positionInfo.x2] + * @param {number|string} [positionInfo.y2] + * @param {Object} containerRect {width, height} + * @param {string|number} margin + * @return {Object} {width, height} + */ + + +/** + * Parse position info. + * + * @param {Object} positionInfo + * @param {number|string} [positionInfo.left] + * @param {number|string} [positionInfo.top] + * @param {number|string} [positionInfo.right] + * @param {number|string} [positionInfo.bottom] + * @param {number|string} [positionInfo.width] + * @param {number|string} [positionInfo.height] + * @param {number|string} [positionInfo.aspect] Aspect is width / height + * @param {Object} containerRect + * @param {string|number} [margin] + * + * @return {module:zrender/core/BoundingRect} + */ + +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. + * + * @param {module:zrender/Element} el Should have `getBoundingRect` method. + * @param {Object} positionInfo + * @param {number|string} [positionInfo.left] + * @param {number|string} [positionInfo.top] + * @param {number|string} [positionInfo.right] + * @param {number|string} [positionInfo.bottom] + * @param {number|string} [positionInfo.width] Only for opt.boundingModel: 'raw' + * @param {number|string} [positionInfo.height] Only for opt.boundingModel: 'raw' + * @param {Object} containerRect + * @param {string|number} margin + * @param {Object} [opt] + * @param {Array.} [opt.hv=[1,1]] Only horizontal or only vertical. + * @param {Array.} [opt.boundingMode='all'] + * 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. + */ + + +/** + * @param {Object} option Contains some of the properties in HV_NAMES. + * @param {number} hvIdx 0: horizontal; 1: vertical. + */ + + +/** + * Consider Case: + * When defulat 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 () { + * ... + * var inputPositionParams = layout.getLayoutParams(option); + * this.mergeOption(inputPositionParams); + * }, + * mergeOption: function (newOption) { + * newOption && zrUtil.merge(thisOption, newOption, true); + * layout.mergeLayoutParam(thisOption, newOption); + * } + * }); + * + * @param {Object} targetOption + * @param {Object} newOption + * @param {Object|string} [opt] + * @param {boolean|Array.} [opt.ignoreSize=false] Used for the components + * that width (or height) should not be calculated by left and right (or top and bottom). + */ + +function mergeLayoutParam(targetOption, newOption, opt) { + !isObject$1(opt) && (opt = {}); + var ignoreSize = opt.ignoreSize; + !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]); + var hResult = merge$$1(HV_NAMES[0], 0); + var vResult = merge$$1(HV_NAMES[1], 1); + copy(HV_NAMES[0], targetOption, hResult); + copy(HV_NAMES[1], targetOption, vResult); + + function merge$$1(names, hvIdx) { + var newParams = {}; + var newValueCount = 0; + var merged = {}; + var mergedValueCount = 0; + var enoughParamNumber = 2; + each$3(names, function (name) { + merged[name] = targetOption[name]; + }); + each$3(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 = names[i]; + + if (!hasProp(newParams, name) && hasProp(targetOption, name)) { + newParams[name] = targetOption[name]; + 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$3(names, function (name) { + target[name] = source[name]; + }); + } +} +/** + * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object. + * @param {Object} source + * @return {Object} Result contains those props. + */ + +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$3(LOCATION_PARAMS, function (name) { + source.hasOwnProperty(name) && (target[name] = source[name]); + }); + return target; +} + +/* +* 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 boxLayoutMixin = { + getBoxLayoutParams: function () { + return { + left: this.get('left'), + top: this.get('top'), + right: this.get('right'), + bottom: this.get('bottom'), + width: this.get('width'), + height: this.get('height') + }; + } +}; + +/* +* 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. +*/ + +/** + * Component model + * + * @module echarts/model/Component + */ +var inner$1 = makeInner(); +/** + * @alias module:echarts/model/Component + * @constructor + * @param {Object} option + * @param {module:echarts/model/Model} parentModel + * @param {module:echarts/model/Model} ecModel + */ + +var ComponentModel = Model.extend({ + type: 'component', + + /** + * @readOnly + * @type {string} + */ + id: '', + + /** + * Because simplified concept is probably better, series.name (or component.name) + * has been having too many resposibilities: + * (1) Generating id (which requires name in option should not be modified). + * (2) As an index to mapping series when merging option or calling API (a name + * can refer to more then one components, which is convinient is some case). + * (3) Display. + * @readOnly + */ + name: '', + + /** + * @readOnly + * @type {string} + */ + mainType: '', + + /** + * @readOnly + * @type {string} + */ + subType: '', + + /** + * @readOnly + * @type {number} + */ + componentIndex: 0, + + /** + * @type {Object} + * @protected + */ + defaultOption: null, + + /** + * @type {module:echarts/model/Global} + * @readOnly + */ + ecModel: null, + + /** + * key: componentType + * value: Component model list, can not be null. + * @type {Object.>} + * @readOnly + */ + dependentModels: [], + + /** + * @type {string} + * @readOnly + */ + uid: null, + + /** + * Support merge layout params. + * Only support 'box' now (left/right/top/bottom/width/height). + * @type {string|Object} Object can be {ignoreSize: true} + * @readOnly + */ + layoutMode: null, + $constructor: function (option, parentModel, ecModel, extraOpt) { + Model.call(this, option, parentModel, ecModel, extraOpt); + this.uid = getUID('ec_cpt_model'); + }, + init: function (option, parentModel, ecModel, extraOpt) { + this.mergeDefaultAndTheme(option, ecModel); + }, + mergeDefaultAndTheme: function (option, ecModel) { + var layoutMode = this.layoutMode; + 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); + } + }, + mergeOption: function (option, extraOpt) { + merge(this.option, option, true); + var layoutMode = this.layoutMode; + + if (layoutMode) { + mergeLayoutParam(this.option, option, layoutMode); + } + }, + // Hooker after init or mergeOption + optionUpdated: function (newCptOption, isInit) {}, + getDefaultOption: function () { + var fields = inner$1(this); + + if (!fields.defaultOption) { + var optList = []; + var Class = this.constructor; + + while (Class) { + var opt = Class.prototype.defaultOption; + opt && optList.push(opt); + Class = Class.superClass; + } + + var defaultOption = {}; + + for (var i = optList.length - 1; i >= 0; i--) { + defaultOption = merge(defaultOption, optList[i], true); + } + + fields.defaultOption = defaultOption; + } + + return fields.defaultOption; + }, + getReferringComponents: function (mainType) { + return this.ecModel.queryComponents({ + mainType: mainType, + index: this.get(mainType + 'Index', true), + id: this.get(mainType + 'Id', true) + }); + } +}); // Reset ComponentModel.extend, add preConstruct. +// clazzUtil.enableClassExtend( +// ComponentModel, +// function (option, parentModel, ecModel, extraOpt) { +// // Set dependentModels, componentIndex, name, id, mainType, subType. +// zrUtil.extend(this, extraOpt); +// this.uid = componentUtil.getUID('componentModel'); +// // this.setReadOnly([ +// // 'type', 'id', 'uid', 'name', 'mainType', 'subType', +// // 'dependentModels', 'componentIndex' +// // ]); +// } +// ); +// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on. + +enableClassManagement(ComponentModel, { + registerWhenExtend: true +}); +enableSubTypeDefaulter(ComponentModel); // Add capability of ComponentModel.topologicalTravel. + +enableTopologicalTravel(ComponentModel, getDependencies); + +function getDependencies(componentType) { + var deps = []; + each$1(ComponentModel.getClassesByMainType(componentType), function (Clazz) { + deps = deps.concat(Clazz.prototype.dependencies || []); + }); // Ensure main type. + + deps = map(deps, function (type) { + return parseClassType$1(type).main; + }); // Hack dataset for convenience. + + if (componentType !== 'dataset' && indexOf(deps, 'dataset') <= 0) { + deps.unshift('dataset'); + } + + return deps; +} + +mixin(ComponentModel, boxLayoutMixin); + +/* +* 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') { + platform = navigator.platform || ''; +} + +var globalDefault = { + // backgroundColor: 'rgba(0,0,0,0)', + // https://dribbble.com/shots/1065960-Infographic-Pie-chart-visualization + // color: ['#5793f3', '#d14a61', '#fd9c35', '#675bba', '#fec42c', '#dd4444', '#d4df5a', '#cd4870'], + // Light colors: + // color: ['#bcd3bb', '#e88f70', '#edc1a5', '#9dc5c8', '#e1e8c8', '#7b7c68', '#e5b5b5', '#f0b489', '#928ea8', '#bda29a'], + // color: ['#cc5664', '#9bd6ec', '#ea946e', '#8acaaa', '#f1ec64', '#ee8686', '#a48dc1', '#5da6bc', '#b9dcae'], + // Dark colors: + color: ['#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83', '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'], + gradientColor: ['#f6efa6', '#d88273', '#bf444c'], + // 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, + animation: 'auto', + animationDuration: 1000, + animationDurationUpdate: 300, + animationEasing: 'exponentialOut', + animationEasingUpdate: 'cubicOut', + 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 +}; + +/* +* 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 inner$2 = makeInner(); + +function getNearestColorPalette(colors, requestColorNum) { + var paletteNum = colors.length; // TODO colors must be in order + + for (var i = 0; i < paletteNum; i++) { + if (colors[i].length > requestColorNum) { + return colors[i]; + } + } + + return colors[paletteNum - 1]; +} + +var colorPaletteMixin = { + clearColorPalette: function () { + inner$2(this).colorIdx = 0; + inner$2(this).colorNameMap = {}; + }, + + /** + * @param {string} name MUST NOT be null/undefined. Otherwise call this function + * twise with the same parameters will get different result. + * @param {Object} [scope=this] + * @param {Object} [requestColorNum] + * @return {string} color string. + */ + getColorFromPalette: function (name, scope, requestColorNum) { + scope = scope || this; + var scopeFields = inner$2(scope); + var colorIdx = scopeFields.colorIdx || 0; + var colorNameMap = scopeFields.colorNameMap = scopeFields.colorNameMap || {}; // Use `hasOwnProperty` to avoid conflict with Object.prototype. + + if (colorNameMap.hasOwnProperty(name)) { + return colorNameMap[name]; + } + + var defaultColorPalette = normalizeToArray(this.get('color', true)); + var layeredColorPalette = this.get('colorLayer', true); + var colorPalette = requestColorNum == null || !layeredColorPalette ? defaultColorPalette : getNearestColorPalette(layeredColorPalette, requestColorNum); // In case can't find in layered color palette. + + colorPalette = colorPalette || defaultColorPalette; + + if (!colorPalette || !colorPalette.length) { + return; + } + + var color = colorPalette[colorIdx]; + + if (name) { + colorNameMap[name] = color; + } + + scopeFields.colorIdx = (colorIdx + 1) % colorPalette.length; + return color; + } +}; + +/* +* 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. +*/ + +/** + * Helper for model references. + * There are many manners to refer axis/coordSys. + */ +// TODO +// merge relevant logic to this file? +// check: "modelHelper" of tooltip and "BrushTargetManager". +/** + * @return {Object} For example: + * { + * coordSysName: 'cartesian2d', + * coordSysDims: ['x', 'y', ...], + * axisMap: HashMap({ + * x: xAxisModel, + * y: yAxisModel + * }), + * categoryAxisMap: HashMap({ + * x: xAxisModel, + * y: undefined + * }), + * // It also indicate that whether there is category axis. + * firstCategoryDimIndex: 1, + * // To replace user specified encode. + * } + */ + +function getCoordSysDefineBySeries(seriesModel) { + var coordSysName = seriesModel.get('coordinateSystem'); + var result = { + coordSysName: coordSysName, + coordSysDims: [], + axisMap: createHashMap(), + categoryAxisMap: createHashMap() + }; + 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')[0]; + var yAxisModel = seriesModel.getReferringComponents('yAxis')[0]; + 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 = 1; + } + }, + singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) { + var singleAxisModel = seriesModel.getReferringComponents('singleAxis')[0]; + 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')[0]; + var radiusAxisModel = polarModel.findAxisModel('radiusAxis'); + var angleAxisModel = polarModel.findAxisModel('angleAxis'); + 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 = 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$1(parallelModel.parallelAxisIndex, function (axisIndex, index) { + var axisModel = ecModel.getComponent('parallelAxis', axisIndex); + var axisDim = coordSysDims[index]; + axisMap.set(axisDim, axisModel); + + if (isCategory(axisModel) && result.firstCategoryDimIndex == null) { + categoryAxisMap.set(axisDim, axisModel); + result.firstCategoryDimIndex = index; + } + }); + } +}; + +function isCategory(axisModel) { + return axisModel.get('type') === 'category'; +} + +/* +* 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. +*/ +// Avoid typo. +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_UNKNOWN = 'unknown'; // ??? CHANGE A NAME + +var SOURCE_FORMAT_TYPED_ARRAY = 'typedArray'; +var SERIES_LAYOUT_BY_COLUMN = 'column'; +var SERIES_LAYOUT_BY_ROW = 'row'; + +/* +* 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. +*/ +/** + * [sourceFormat] + * + * + "original": + * This format is only used in series.data, where + * itemStyle can be specified in data item. + * + * + "arrayRows": + * [ + * ['product', 'score', 'amount'], + * ['Matcha Latte', 89.3, 95.8], + * ['Milk Tea', 92.1, 89.4], + * ['Cheese Cocoa', 94.4, 91.2], + * ['Walnut Brownie', 85.4, 76.9] + * ] + * + * + "objectRows": + * [ + * {product: 'Matcha Latte', score: 89.3, amount: 95.8}, + * {product: 'Milk Tea', score: 92.1, amount: 89.4}, + * {product: 'Cheese Cocoa', score: 94.4, amount: 91.2}, + * {product: 'Walnut Brownie', score: 85.4, amount: 76.9} + * ] + * + * + "keyedColumns": + * { + * 'product': ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie'], + * 'count': [823, 235, 1042, 988], + * 'score': [95.8, 81.4, 91.2, 76.9] + * } + * + * + "typedArray" + * + * + "unknown" + */ + +/** + * @constructor + * @param {Object} fields + * @param {string} fields.sourceFormat + * @param {Array|Object} fields.fromDataset + * @param {Array|Object} [fields.data] + * @param {string} [seriesLayoutBy='column'] + * @param {Array.} [dimensionsDefine] + * @param {Objet|HashMap} [encodeDefine] + * @param {number} [startIndex=0] + * @param {number} [dimensionsDetectCount] + */ + +function Source(fields) { + /** + * @type {boolean} + */ + this.fromDataset = fields.fromDataset; + /** + * Not null/undefined. + * @type {Array|Object} + */ + + this.data = fields.data || (fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []); + /** + * See also "detectSourceFormat". + * Not null/undefined. + * @type {string} + */ + + this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN; + /** + * 'row' or 'column' + * Not null/undefined. + * @type {string} seriesLayoutBy + */ + + this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN; + /** + * dimensions definition in option. + * can be null/undefined. + * @type {Array.} + */ + + this.dimensionsDefine = fields.dimensionsDefine; + /** + * encode definition in option. + * can be null/undefined. + * @type {Objet|HashMap} + */ + + this.encodeDefine = fields.encodeDefine && createHashMap(fields.encodeDefine); + /** + * Not null/undefined, uint. + * @type {number} + */ + + this.startIndex = fields.startIndex || 0; + /** + * Can be null/undefined (when unknown), uint. + * @type {number} + */ + + this.dimensionsDetectCount = fields.dimensionsDetectCount; +} +/** + * Wrap original series data for some compatibility cases. + */ + + +Source.seriesDataToSource = function (data) { + return new Source({ + data: data, + sourceFormat: isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL, + fromDataset: false + }); +}; + +enableClassCheck(Source); + +/* +* 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 inner$3 = makeInner(); +/** + * @see {module:echarts/data/Source} + * @param {module:echarts/component/dataset/DatasetModel} datasetModel + * @return {string} sourceFormat + */ + +function detectSourceFormat(datasetModel) { + var data = datasetModel.option.source; + 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$1(item)) { + sourceFormat = SOURCE_FORMAT_OBJECT_ROWS; + break; + } + } + } else if (isObject$1(data)) { + for (var key in data) { + if (data.hasOwnProperty(key) && isArrayLike(data[key])) { + sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS; + break; + } + } + } else if (data != null) { + throw new Error('Invalid data'); + } + + inner$3(datasetModel).sourceFormat = sourceFormat; +} +/** + * [Scenarios]: + * (1) Provide source data directly: + * series: { + * encode: {...}, + * dimensions: [...] + * seriesLayoutBy: 'row', + * data: [[...]] + * } + * (2) Refer to datasetModel. + * series: [{ + * encode: {...} + * // Ignore datasetIndex means `datasetIndex: 0` + * // and the dimensions defination in dataset is used + * }, { + * encode: {...}, + * seriesLayoutBy: 'column', + * datasetIndex: 1 + * }] + * + * Get data from series itself or datset. + * @return {module:echarts/data/Source} source + */ + +function getSource(seriesModel) { + return inner$3(seriesModel).source; +} +/** + * MUST be called before mergeOption of all series. + * @param {module:echarts/model/Global} ecModel + */ + +function resetSourceDefaulter(ecModel) { + // `datasetMap` is used to make default encode. + inner$3(ecModel).datasetMap = createHashMap(); +} +/** + * [Caution]: + * MUST be called after series option merged and + * before "series.getInitailData()" called. + * + * [The rule of making default encode]: + * Category axis (if exists) alway map to the first dimension. + * Each other axis occupies a subsequent dimension. + * + * [Why make default encode]: + * Simplify the typing of encode in option, avoiding the case like that: + * series: [{encode: {x: 0, y: 1}}, {encode: {x: 0, y: 2}}, {encode: {x: 0, y: 3}}], + * where the "y" have to be manually typed as "1, 2, 3, ...". + * + * @param {module:echarts/model/Series} seriesModel + */ + +function prepareSource(seriesModel) { + var seriesOption = seriesModel.option; + var data = seriesOption.data; + var sourceFormat = isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL; + var fromDataset = false; + var seriesLayoutBy = seriesOption.seriesLayoutBy; + var sourceHeader = seriesOption.sourceHeader; + var dimensionsDefine = seriesOption.dimensions; + var datasetModel = getDatasetModel(seriesModel); + + if (datasetModel) { + var datasetOption = datasetModel.option; + data = datasetOption.source; + sourceFormat = inner$3(datasetModel).sourceFormat; + fromDataset = true; // These settings from series has higher priority. + + seriesLayoutBy = seriesLayoutBy || datasetOption.seriesLayoutBy; + sourceHeader == null && (sourceHeader = datasetOption.sourceHeader); + dimensionsDefine = dimensionsDefine || datasetOption.dimensions; + } + + var completeResult = completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine); // Note: dataset option does not have `encode`. + + var encodeDefine = seriesOption.encode; + + if (!encodeDefine && datasetModel) { + encodeDefine = makeDefaultEncode(seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult); + } + + inner$3(seriesModel).source = new Source({ + data: data, + fromDataset: fromDataset, + seriesLayoutBy: seriesLayoutBy, + sourceFormat: sourceFormat, + dimensionsDefine: completeResult.dimensionsDefine, + startIndex: completeResult.startIndex, + dimensionsDetectCount: completeResult.dimensionsDetectCount, + encodeDefine: encodeDefine + }); +} // return {startIndex, dimensionsDefine, dimensionsCount} + +function completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine) { + if (!data) { + return { + dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine) + }; + } + + var dimensionsDetectCount; + var startIndex; + var findPotentialName; + + if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) { + // 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, data, 10); + } else { + startIndex = sourceHeader ? 1 : 0; + } + + if (!dimensionsDefine && startIndex === 1) { + dimensionsDefine = []; + arrayRowsTravelFirst(function (val, index) { + dimensionsDefine[index] = val != null ? val : ''; + }, seriesLayoutBy, data); + } + + dimensionsDetectCount = dimensionsDefine ? dimensionsDefine.length : seriesLayoutBy === SERIES_LAYOUT_BY_ROW ? data.length : data[0] ? data[0].length : null; + } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) { + if (!dimensionsDefine) { + dimensionsDefine = objectRowsCollectDimensions(data); + findPotentialName = true; + } + } else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) { + if (!dimensionsDefine) { + dimensionsDefine = []; + findPotentialName = true; + each$1(data, function (colArr, key) { + dimensionsDefine.push(key); + }); + } + } else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) { + var value0 = getDataItemValue(data[0]); + dimensionsDetectCount = isArray(value0) && value0.length || 1; + } else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {} + + var potentialNameDimIndex; + + if (findPotentialName) { + each$1(dimensionsDefine, function (dim, idx) { + if ((isObject$1(dim) ? dim.name : dim) === 'name') { + potentialNameDimIndex = idx; + } + }); + } + + return { + startIndex: startIndex, + dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine), + dimensionsDetectCount: dimensionsDetectCount, + potentialNameDimIndex: potentialNameDimIndex // TODO: potentialIdDimIdx + + }; +} // 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 normalizeDimensionsDefine(dimensionsDefine) { + if (!dimensionsDefine) { + // The meaning of null/undefined is different from empty array. + return; + } + + var nameMap = createHashMap(); + return map(dimensionsDefine, function (item, index) { + item = extend({}, isObject$1(item) ? item : { + name: item + }); // 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) { + maxLoop == null && (maxLoop = Infinity); + + 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 objectRowsCollectDimensions(data) { + var firstIndex = 0; + var obj; + + while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line + + + if (obj) { + var dimensions = []; + each$1(obj, function (value, key) { + dimensions.push(key); + }); + return dimensions; + } +} // ??? TODO merge to completedimensions, where also has +// default encode making logic. And the default rule +// should depends on series? consider 'map'. + + +function makeDefaultEncode(seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult) { + var coordSysDefine = getCoordSysDefineBySeries(seriesModel); + var encode = {}; // var encodeTooltip = []; + // var encodeLabel = []; + + var encodeItemName = []; + var encodeSeriesName = []; + var seriesType = seriesModel.subType; // ??? TODO refactor: provide by series itself. + // Consider the case: 'map' series is based on geo coordSys, + // 'graph', 'heatmap' can be based on cartesian. But can not + // give default rule simply here. + + var nSeriesMap = createHashMap(['pie', 'map', 'funnel']); + var cSeriesMap = createHashMap(['line', 'bar', 'pictorialBar', 'scatter', 'effectScatter', 'candlestick', 'boxplot']); // Usually in this case series will use the first data + // dimension as the "value" dimension, or other default + // processes respectively. + + if (coordSysDefine && cSeriesMap.get(seriesType) != null) { + var ecModel = seriesModel.ecModel; + var datasetMap = inner$3(ecModel).datasetMap; + var key = datasetModel.uid + '_' + seriesLayoutBy; + var datasetRecord = datasetMap.get(key) || datasetMap.set(key, { + categoryWayDim: 1, + valueWayDim: 0 + }); // TODO + // Auto detect first time axis and do arrangement. + + each$1(coordSysDefine.coordSysDims, function (coordDim) { + // In value way. + if (coordSysDefine.firstCategoryDimIndex == null) { + var dataDim = datasetRecord.valueWayDim++; + encode[coordDim] = dataDim; // ??? 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. + + encodeSeriesName.push(dataDim); // encodeTooltip.push(dataDim); + // encodeLabel.push(dataDim); + } // In category way, category axis. + else if (coordSysDefine.categoryAxisMap.get(coordDim)) { + encode[coordDim] = 0; + encodeItemName.push(0); + } // In category way, non-category axis. + else { + var dataDim = datasetRecord.categoryWayDim++; + encode[coordDim] = dataDim; // encodeTooltip.push(dataDim); + // encodeLabel.push(dataDim); + + encodeSeriesName.push(dataDim); + } + }); + } // Do not make a complex rule! Hard to code maintain and not necessary. + // ??? TODO refactor: provide by series itself. + // [{name: ..., value: ...}, ...] like: + else if (nSeriesMap.get(seriesType) != null) { + // Find the first not ordinal. (5 is an experience value) + var firstNotOrdinal; + + for (var i = 0; i < 5 && firstNotOrdinal == null; i++) { + if (!doGuessOrdinal(data, sourceFormat, seriesLayoutBy, completeResult.dimensionsDefine, completeResult.startIndex, i)) { + firstNotOrdinal = i; + } + } + + if (firstNotOrdinal != null) { + encode.value = firstNotOrdinal; + var nameDimIndex = completeResult.potentialNameDimIndex || Math.max(firstNotOrdinal - 1, 0); // By default, label use itemName in charts. + // So we dont set encodeLabel here. + + encodeSeriesName.push(nameDimIndex); + encodeItemName.push(nameDimIndex); // encodeTooltip.push(firstNotOrdinal); + } + } // encodeTooltip.length && (encode.tooltip = encodeTooltip); + // encodeLabel.length && (encode.label = encodeLabel); + + + encodeItemName.length && (encode.itemName = encodeItemName); + encodeSeriesName.length && (encode.seriesName = encodeSeriesName); + return encode; +} +/** + * If return null/undefined, indicate that should not use datasetModel. + */ + + +function getDatasetModel(seriesModel) { + var option = seriesModel.option; // 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 = option.data; + + if (!thisData) { + return seriesModel.ecModel.getComponent('dataset', option.datasetIndex || 0); + } +} +/** + * 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? + * + * @param {module:echars/data/Source} source + * @param {number} dimIndex + * @return {boolean} Whether ordinal. + */ + + +function guessOrdinal(source, dimIndex) { + return doGuessOrdinal(source.data, source.sourceFormat, source.seriesLayoutBy, source.dimensionsDefine, source.startIndex, dimIndex); +} // dimIndex may be overflow source data. + +function doGuessOrdinal(data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex) { + var result; // Experience value. + + var maxLoop = 5; + + if (isTypedArray(data)) { + return false; + } // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine + // always exists in source. + + + var dimName; + + if (dimensionsDefine) { + dimName = dimensionsDefine[dimIndex]; + dimName = isObject$1(dimName) ? dimName.name : dimName; + } + + if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) { + if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) { + var sample = data[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 < data.length && i < maxLoop; i++) { + var row = data[startIndex + i]; + + if (row && (result = detectValue(row[dimIndex])) != null) { + return result; + } + } + } + } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) { + if (!dimName) { + return; + } + + for (var i = 0; i < data.length && i < maxLoop; i++) { + var item = data[i]; + + if (item && (result = detectValue(item[dimName])) != null) { + return result; + } + } + } else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) { + if (!dimName) { + return; + } + + var sample = data[dimName]; + + if (!sample || isTypedArray(sample)) { + return false; + } + + for (var i = 0; i < sample.length && i < maxLoop; i++) { + if ((result = detectValue(sample[i])) != null) { + return result; + } + } + } else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) { + for (var i = 0; i < data.length && i < maxLoop; i++) { + var item = data[i]; + var val = getDataItemValue(item); + + if (!isArray(val)) { + return false; + } + + if ((result = detectValue(val[dimIndex])) != null) { + return result; + } + } + } + + function detectValue(val) { + // Consider usage convenience, '1', '2' will be treated as "number". + // `isFinit('')` get `true`. + if (val != null && isFinite(val) && val !== '') { + return false; + } else if (isString(val) && val !== '-') { + return true; + } + } + + return false; +} + +/* +* 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. +*/ + +/** + * ECharts global model + * + * @module {echarts/model/Global} + */ + +/** + * Caution: If the mechanism should be changed some day, these cases + * should be considered: + * + * (1) In `merge option` mode, if using the same option to call `setOption` + * many times, the result should be the same (try our best to ensure that). + * (2) In `merge option` mode, if a component has no id/name specified, it + * will be merged by index, and the result sequence of the components is + * consistent to the original sequence. + * (3) `reset` feature (in toolbox). Find detailed info in comments about + * `mergeOption` in module:echarts/model/OptionManager. + */ +var OPTION_INNER_KEY = '\0_ec_inner'; +/** + * @alias module:echarts/model/Global + * + * @param {Object} option + * @param {module:echarts/model/Model} parentModel + * @param {Object} theme + */ + +var GlobalModel = Model.extend({ + init: function (option, parentModel, theme, optionManager) { + theme = theme || {}; + this.option = null; // Mark as not initialized. + + /** + * @type {module:echarts/model/Model} + * @private + */ + + this._theme = new Model(theme); + /** + * @type {module:echarts/model/OptionManager} + */ + + this._optionManager = optionManager; + }, + setOption: function (option, optionPreprocessorFuncs) { + assert$1(!(OPTION_INNER_KEY in option), 'please use chart.getOption()'); + + this._optionManager.setOption(option, optionPreprocessorFuncs); + + this.resetOption(null); + }, + + /** + * @param {string} type null/undefined: reset all. + * 'recreate': force recreate all. + * 'timeline': only reset timeline option + * 'media': only reset media query option + * @return {boolean} Whether option changed. + */ + resetOption: function (type) { + var optionChanged = false; + var optionManager = this._optionManager; + + if (!type || type === 'recreate') { + var baseOption = optionManager.mountOption(type === 'recreate'); + + if (!this.option || type === 'recreate') { + initBase.call(this, baseOption); + } else { + this.restoreData(); + this.mergeOption(baseOption); + } + + optionChanged = true; + } + + if (type === 'timeline' || type === 'media') { + this.restoreData(); + } + + if (!type || type === 'recreate' || type === 'timeline') { + var timelineOption = optionManager.getTimelineOption(this); + timelineOption && (this.mergeOption(timelineOption), optionChanged = true); + } + + if (!type || type === 'recreate' || type === 'media') { + var mediaOptions = optionManager.getMediaOption(this, this._api); + + if (mediaOptions.length) { + each$1(mediaOptions, function (mediaOption) { + this.mergeOption(mediaOption, optionChanged = true); + }, this); + } + } + + return optionChanged; + }, + + /** + * @protected + */ + mergeOption: function (newOption) { + var option = this.option; + var componentsMap = this._componentsMap; + var newCptTypes = []; + resetSourceDefaulter(this); // If no component class, merge directly. + // For example: color, animaiton options, etc. + + each$1(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) { + newCptTypes.push(mainType); + } + }); + ComponentModel.topologicalTravel(newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this); + + function visitComponent(mainType, dependencies) { + var newCptOptionList = normalizeToArray(newOption[mainType]); + var mapResult = mappingToExists(componentsMap.get(mainType), newCptOptionList); + makeIdAndName(mapResult); // Set mainType and complete subType. + + each$1(mapResult, function (item, index) { + var opt = item.option; + + if (isObject$1(opt)) { + item.keyInfo.mainType = mainType; + item.keyInfo.subType = determineSubType(mainType, opt, item.exist); + } + }); + var dependentModels = getComponentsByTypes(componentsMap, dependencies); + option[mainType] = []; + componentsMap.set(mainType, []); + each$1(mapResult, function (resultItem, index) { + var componentModel = resultItem.exist; + var newCptOption = resultItem.option; + assert$1(isObject$1(newCptOption) || componentModel, 'Empty component definition'); // Consider where is no new option and should be merged using {}, + // see removeEdgeAndAdd in topologicalTravel and + // ComponentModel.getAllClassMainTypes. + + if (!newCptOption) { + componentModel.mergeOption({}, this); + componentModel.optionUpdated({}, false); + } else { + var ComponentModelClass = ComponentModel.getClass(mainType, resultItem.keyInfo.subType, true); + + if (componentModel && componentModel.constructor === ComponentModelClass) { + componentModel.name = resultItem.keyInfo.name; // componentModel.settingTask && componentModel.settingTask.dirty(); + + componentModel.mergeOption(newCptOption, this); + componentModel.optionUpdated(newCptOption, false); + } else { + // PENDING Global as parent ? + var extraOpt = extend({ + dependentModels: dependentModels, + componentIndex: index + }, resultItem.keyInfo); + componentModel = new ComponentModelClass(newCptOption, this, this, extraOpt); + extend(componentModel, extraOpt); + componentModel.init(newCptOption, this, this, extraOpt); // Call optionUpdated after init. + // newCptOption has been used as componentModel.option + // and may be merged with theme and default, so pass null + // to avoid confusion. + + componentModel.optionUpdated(null, true); + } + } + + componentsMap.get(mainType)[index] = componentModel; + option[mainType][index] = componentModel.option; + }, this); // Backup series for filtering. + + if (mainType === 'series') { + createSeriesIndices(this, componentsMap.get('series')); + } + } + + this._seriesIndicesMap = createHashMap(this._seriesIndices = this._seriesIndices || []); + }, + + /** + * Get option for output (cloned option and inner info removed) + * @public + * @return {Object} + */ + getOption: function () { + var option = clone(this.option); + each$1(option, function (opts, mainType) { + if (ComponentModel.hasClass(mainType)) { + var opts = normalizeToArray(opts); + + for (var i = opts.length - 1; i >= 0; i--) { + // Remove options with inner id. + if (isIdInner(opts[i])) { + opts.splice(i, 1); + } + } + + option[mainType] = opts; + } + }); + delete option[OPTION_INNER_KEY]; + return option; + }, + + /** + * @return {module:echarts/model/Model} + */ + getTheme: function () { + return this._theme; + }, + + /** + * @param {string} mainType + * @param {number} [idx=0] + * @return {module:echarts/model/Component} + */ + getComponent: function (mainType, idx) { + var list = this._componentsMap.get(mainType); + + if (list) { + return list[idx || 0]; + } + }, + + /** + * If none of index and id and name used, return all components with mainType. + * @param {Object} condition + * @param {string} condition.mainType + * @param {string} [condition.subType] If ignore, only query by mainType + * @param {number|Array.} [condition.index] Either input index or id or name. + * @param {string|Array.} [condition.id] Either input index or id or name. + * @param {string|Array.} [condition.name] Either input index or id or name. + * @return {Array.} + */ + queryComponents: function (condition) { + var mainType = condition.mainType; + + if (!mainType) { + return []; + } + + var index = condition.index; + var id = condition.id; + var name = condition.name; + + var cpts = this._componentsMap.get(mainType); + + if (!cpts || !cpts.length) { + return []; + } + + var result; + + if (index != null) { + if (!isArray(index)) { + index = [index]; + } + + result = filter(map(index, function (idx) { + return cpts[idx]; + }), function (val) { + return !!val; + }); + } else if (id != null) { + var isIdArray = isArray(id); + result = filter(cpts, function (cpt) { + return isIdArray && indexOf(id, cpt.id) >= 0 || !isIdArray && cpt.id === id; + }); + } else if (name != null) { + var isNameArray = isArray(name); + result = filter(cpts, function (cpt) { + return isNameArray && indexOf(name, cpt.name) >= 0 || !isNameArray && cpt.name === name; + }); + } else { + // Return all components with mainType + result = cpts.slice(); + } + + return filterBySubType(result, condition); + }, + + /** + * The interface is different from queryComponents, + * which is convenient for inner usage. + * + * @usage + * var result = findComponents( + * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}} + * ); + * var result = findComponents( + * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}} + * ); + * var result = findComponents( + * {mainType: 'series', + * filter: function (model, index) {...}} + * ); + * // result like [component0, componnet1, ...] + * + * @param {Object} condition + * @param {string} condition.mainType Mandatory. + * @param {string} [condition.subType] Optional. + * @param {Object} [condition.query] like {xxxIndex, xxxId, xxxName}, + * where xxx is mainType. + * If query attribute is null/undefined or has no index/id/name, + * do not filtering by query conditions, which is convenient for + * no-payload situations or when target of action is global. + * @param {Function} [condition.filter] parameter: component, return boolean. + * @return {Array.} + */ + findComponents: function (condition) { + var query = condition.query; + var mainType = condition.mainType; + var queryCond = getQueryCond(query); + var result = queryCond ? this.queryComponents(queryCond) : this._componentsMap.get(mainType); + 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; + } + }, + + /** + * @usage + * eachComponent('legend', function (legendModel, index) { + * ... + * }); + * eachComponent(function (componentType, model, index) { + * // componentType does not include subType + * // (componentType is 'xxx' but not 'xxx.aa') + * }); + * eachComponent( + * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}, + * function (model, index) {...} + * ); + * eachComponent( + * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}, + * function (model, index) {...} + * ); + * + * @param {string|Object=} mainType When mainType is object, the definition + * is the same as the method 'findComponents'. + * @param {Function} cb + * @param {*} context + */ + eachComponent: function (mainType, cb, context) { + var componentsMap = this._componentsMap; + + if (typeof mainType === 'function') { + context = cb; + cb = mainType; + componentsMap.each(function (components, componentType) { + each$1(components, function (component, index) { + cb.call(context, componentType, component, index); + }); + }); + } else if (isString(mainType)) { + each$1(componentsMap.get(mainType), cb, context); + } else if (isObject$1(mainType)) { + var queryResult = this.findComponents(mainType); + each$1(queryResult, cb, context); + } + }, + + /** + * @param {string} name + * @return {Array.} + */ + getSeriesByName: function (name) { + var series = this._componentsMap.get('series'); + + return filter(series, function (oneSeries) { + return oneSeries.name === name; + }); + }, + + /** + * @param {number} seriesIndex + * @return {module:echarts/model/Series} + */ + getSeriesByIndex: function (seriesIndex) { + return this._componentsMap.get('series')[seriesIndex]; + }, + + /** + * Get series list before filtered by type. + * FIXME: rename to getRawSeriesByType? + * + * @param {string} subType + * @return {Array.} + */ + getSeriesByType: function (subType) { + var series = this._componentsMap.get('series'); + + return filter(series, function (oneSeries) { + return oneSeries.subType === subType; + }); + }, + + /** + * @return {Array.} + */ + getSeries: function () { + return this._componentsMap.get('series').slice(); + }, + + /** + * @return {number} + */ + getSeriesCount: function () { + return this._componentsMap.get('series').length; + }, + + /** + * After filtering, series may be different + * frome raw series. + * + * @param {Function} cb + * @param {*} context + */ + eachSeries: function (cb, context) { + each$1(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 + */ + eachRawSeries: function (cb, context) { + each$1(this._componentsMap.get('series'), cb, context); + }, + + /** + * After filtering, series may be different. + * frome raw series. + * + * @param {string} subType. + * @param {Function} cb + * @param {*} context + */ + eachSeriesByType: function (subType, cb, context) { + each$1(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. + * + * @parma {string} subType + * @param {Function} cb + * @param {*} context + */ + eachRawSeriesByType: function (subType, cb, context) { + return each$1(this.getSeriesByType(subType), cb, context); + }, + + /** + * @param {module:echarts/model/Series} seriesModel + */ + isSeriesFiltered: function (seriesModel) { + return this._seriesIndicesMap.get(seriesModel.componentIndex) == null; + }, + + /** + * @return {Array.} + */ + getCurrentSeriesIndices: function () { + return (this._seriesIndices || []).slice(); + }, + + /** + * @param {Function} cb + * @param {*} context + */ + filterSeries: function (cb, context) { + var filteredSeries = filter(this._componentsMap.get('series'), cb, context); + createSeriesIndices(this, filteredSeries); + }, + restoreData: function (payload) { + var componentsMap = this._componentsMap; + createSeriesIndices(this, componentsMap.get('series')); + var componentTypes = []; + componentsMap.each(function (components, componentType) { + componentTypes.push(componentType); + }); + ComponentModel.topologicalTravel(componentTypes, ComponentModel.getAllClassMainTypes(), function (componentType, dependencies) { + each$1(componentsMap.get(componentType), function (component) { + (componentType !== 'series' || !isNotTargetSeries(component, payload)) && component.restoreData(); + }); + }); + } +}); + +function isNotTargetSeries(seriesModel, payload) { + if (payload) { + var index = payload.seiresIndex; + var id = payload.seriesId; + var name = payload.seriesName; + return index != null && seriesModel.componentIndex !== index || id != null && seriesModel.id !== id || name != null && seriesModel.name !== name; + } +} +/** + * @inner + */ + + +function mergeTheme(option, theme) { + // PENDING + // NOT use `colorLayer` in theme if option has `color` + var notMergeColorLayer = option.color && !option.colorLayer; + each$1(theme, function (themeItem, name) { + if (name === 'colorLayer' && notMergeColorLayer) { + return; + } // 如果有 component model 则把具体的 merge 逻辑交给该 model 处理 + + + 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 initBase(baseOption) { + baseOption = baseOption; // Using OPTION_INNER_KEY to mark that this option can not be used outside, + // i.e. `chart.setOption(chart.getModel().option);` is forbiden. + + this.option = {}; + this.option[OPTION_INNER_KEY] = 1; + /** + * Init with series: [], in case of calling findSeries method + * before series initialized. + * @type {Object.>} + * @private + */ + + this._componentsMap = createHashMap({ + series: [] + }); + /** + * Mapping between filtered series list and raw series list. + * key: filtered series indices, value: raw series indices. + * @type {Array.} + * @private + */ + + this._seriesIndices; + this._seriesIndicesMap; + mergeTheme(baseOption, this._theme.option); // TODO Needs clone when merging to the unexisted property + + merge(baseOption, globalDefault, false); + this.mergeOption(baseOption); +} +/** + * @inner + * @param {Array.|string} types model types + * @return {Object} key: {string} type, value: {Array.} models + */ + + +function getComponentsByTypes(componentsMap, types) { + if (!isArray(types)) { + types = types ? [types] : []; + } + + var ret = {}; + each$1(types, function (type) { + ret[type] = (componentsMap.get(type) || []).slice(); + }); + return ret; +} +/** + * @inner + */ + + +function determineSubType(mainType, newCptOption, existComponent) { + var subType = newCptOption.type ? newCptOption.type : existComponent ? existComponent.subType // Use determineSubType only when there is no existComponent. + : ComponentModel.determineSubType(mainType, newCptOption); // tooltip, markline, markpoint may always has no subType + + return subType; +} +/** + * @inner + */ + + +function createSeriesIndices(ecModel, seriesModels) { + ecModel._seriesIndicesMap = createHashMap(ecModel._seriesIndices = map(seriesModels, function (series) { + return series.componentIndex; + }) || []); +} +/** + * @inner + */ + + +function filterBySubType(components, condition) { + // Using hasOwnProperty for restrict. Consider + // subType is undefined in user payload. + return condition.hasOwnProperty('subType') ? filter(components, function (cpt) { + return cpt.subType === condition.subType; + }) : components; +} +mixin(GlobalModel, colorPaletteMixin); + +/* +* 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 echartsAPIList = ['getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isDisposed', 'on', 'off', 'getDataURL', 'getConnectedDataURL', 'getModel', 'getOption', 'getViewOfComponentModel', 'getViewOfSeriesModel']; // And `getCoordinateSystems` and `getComponentByElement` will be injected in echarts.js + +function ExtensionAPI(chartInstance) { + each$1(echartsAPIList, function (name) { + this[name] = bind(chartInstance[name], chartInstance); + }, this); +} + +/* +* 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 coordinateSystemCreators = {}; + +function CoordinateSystemManager() { + this._coordinateSystems = []; +} + +CoordinateSystemManager.prototype = { + constructor: CoordinateSystemManager, + create: function (ecModel, api) { + var coordinateSystems = []; + each$1(coordinateSystemCreators, function (creater, type) { + var list = creater.create(ecModel, api); + coordinateSystems = coordinateSystems.concat(list || []); + }); + this._coordinateSystems = coordinateSystems; + }, + update: function (ecModel, api) { + each$1(this._coordinateSystems, function (coordSys) { + coordSys.update && coordSys.update(ecModel, api); + }); + }, + getCoordinateSystems: function () { + return this._coordinateSystems.slice(); + } +}; + +CoordinateSystemManager.register = function (type, coordinateSystemCreator) { + coordinateSystemCreators[type] = coordinateSystemCreator; +}; + +CoordinateSystemManager.get = function (type) { + return coordinateSystemCreators[type]; +}; + +/* +* 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. +*/ + +/** + * ECharts option manager + * + * @module {echarts/model/OptionManager} + */ +var each$4 = each$1; +var clone$3 = clone; +var map$1 = map; +var merge$1 = merge; +var QUERY_REG = /^(min|max)?(.+)$/; +/** + * TERM EXPLANATIONS: + * + * [option]: + * + * An object that contains definitions of components. For example: + * var option = { + * title: {...}, + * legend: {...}, + * visualMap: {...}, + * series: [ + * {data: [...]}, + * {data: [...]}, + * ... + * ] + * }; + * + * [rawOption]: + * + * An object input to echarts.setOption. 'rawOption' may be an + * 'option', or may be an object contains multi-options. For example: + * var option = { + * baseOption: { + * title: {...}, + * legend: {...}, + * series: [ + * {data: [...]}, + * {data: [...]}, + * ... + * ] + * }, + * timeline: {...}, + * options: [ + * {title: {...}, series: {data: [...]}}, + * {title: {...}, series: {data: [...]}}, + * ... + * ], + * media: [ + * { + * query: {maxWidth: 320}, + * option: {series: {x: 20}, visualMap: {show: false}} + * }, + * { + * query: {minWidth: 320, maxWidth: 720}, + * option: {series: {x: 500}, visualMap: {show: true}} + * }, + * { + * option: {series: {x: 1200}, visualMap: {show: true}} + * } + * ] + * }; + * + * @alias module:echarts/model/OptionManager + * @param {module:echarts/ExtensionAPI} api + */ + +function OptionManager(api) { + /** + * @private + * @type {module:echarts/ExtensionAPI} + */ + this._api = api; + /** + * @private + * @type {Array.} + */ + + this._timelineOptions = []; + /** + * @private + * @type {Array.} + */ + + this._mediaList = []; + /** + * @private + * @type {Object} + */ + + this._mediaDefault; + /** + * -1, means default. + * empty means no media. + * @private + * @type {Array.} + */ + + this._currentMediaIndices = []; + /** + * @private + * @type {Object} + */ + + this._optionBackup; + /** + * @private + * @type {Object} + */ + + this._newBaseOption; +} // 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); + + +OptionManager.prototype = { + constructor: OptionManager, + + /** + * @public + * @param {Object} rawOption Raw option. + * @param {module:echarts/model/Global} ecModel + * @param {Array.} optionPreprocessorFuncs + * @return {Object} Init option + */ + setOption: function (rawOption, optionPreprocessorFuncs) { + if (rawOption) { + // That set dat primitive is dangerous if user reuse the data when setOption again. + each$1(normalizeToArray(rawOption.series), function (series) { + series && series.data && isTypedArray(series.data) && setAsPrimitive(series.data); + }); + } // 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$3(rawOption); // FIXME + // 如果 timeline options 或者 media 中设置了某个属性,而baseOption中没有设置,则进行警告。 + + var oldOptionBackup = this._optionBackup; + var newParsedOption = parseRawOption.call(this, rawOption, optionPreprocessorFuncs, !oldOptionBackup); + this._newBaseOption = newParsedOption.baseOption; // For setOption at second time (using merge mode); + + if (oldOptionBackup) { + // Only baseOption can be merged. + mergeOption(oldOptionBackup.baseOption, newParsedOption.baseOption); // 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) { + oldOptionBackup.timelineOptions = newParsedOption.timelineOptions; + } + + if (newParsedOption.mediaList.length) { + oldOptionBackup.mediaList = newParsedOption.mediaList; + } + + if (newParsedOption.mediaDefault) { + oldOptionBackup.mediaDefault = newParsedOption.mediaDefault; + } + } else { + this._optionBackup = newParsedOption; + } + }, + + /** + * @param {boolean} isRecreate + * @return {Object} + */ + mountOption: function (isRecreate) { + var optionBackup = this._optionBackup; // TODO + // 如果没有reset功能则不clone。 + + this._timelineOptions = map$1(optionBackup.timelineOptions, clone$3); + this._mediaList = map$1(optionBackup.mediaList, clone$3); + this._mediaDefault = clone$3(optionBackup.mediaDefault); + this._currentMediaIndices = []; + return clone$3(isRecreate // this._optionBackup.baseOption, which is created at the first `setOption` + // called, and is merged into every new option by inner method `mergeOption` + // 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); + }, + + /** + * @param {module:echarts/model/Global} ecModel + * @return {Object} + */ + 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$3(timelineOptions[timelineModel.getCurrentIndex()], true); + } + } + + return option; + }, + + /** + * @param {module:echarts/model/Global} ecModel + * @return {Array.} + */ + 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 + // 是否mediaDefault应该强制用户设置,否则可能修改不能回归。 + + + if (!indices.length && mediaDefault) { + indices = [-1]; + } + + if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) { + result = map$1(indices, function (index) { + return clone$3(index === -1 ? mediaDefault.option : mediaList[index].option); + }); + } // Otherwise return nothing. + + + this._currentMediaIndices = indices; + return result; + } +}; + +function parseRawOption(rawOption, optionPreprocessorFuncs, isNew) { + var timelineOptions = []; + var mediaList = []; + var mediaDefault; + var baseOption; // Compatible with ec2. + + var timelineOpt = rawOption.timeline; + + if (rawOption.baseOption) { + baseOption = rawOption.baseOption; + } // For timeline + + + if (timelineOpt || rawOption.options) { + baseOption = baseOption || {}; + timelineOptions = (rawOption.options || []).slice(); + } // For media query + + + if (rawOption.media) { + baseOption = baseOption || {}; + var media = rawOption.media; + each$4(media, function (singleMedia) { + if (singleMedia && singleMedia.option) { + if (singleMedia.query) { + mediaList.push(singleMedia); + } else if (!mediaDefault) { + // Use the first media default. + mediaDefault = singleMedia; + } + } + }); + } // For normal option + + + if (!baseOption) { + baseOption = rawOption; + } // Set timelineOpt to baseOption in ec3, + // which is convenient for merge option. + + + if (!baseOption.timeline) { + baseOption.timeline = timelineOpt; + } // Preprocess. + + + each$4([baseOption].concat(timelineOptions).concat(map(mediaList, function (media) { + return media.option; + })), function (option) { + each$4(optionPreprocessorFuncs, function (preProcess) { + preProcess(option, isNew); + }); + }); + return { + baseOption: baseOption, + timelineOptions: timelineOptions, + 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$1(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(','); +} +/** + * Consider case: + * `chart.setOption(opt1);` + * Then user do some interaction like dataZoom, dataView changing. + * `chart.setOption(opt2);` + * Then user press 'reset button' in toolbox. + * + * After doing that all of the interaction effects should be reset, the + * chart should be the same as the result of invoke + * `chart.setOption(opt1); chart.setOption(opt2);`. + * + * Although it is not able ensure that + * `chart.setOption(opt1); chart.setOption(opt2);` is equivalents to + * `chart.setOption(merge(opt1, opt2));` exactly, + * this might be the only simple way to implement that feature. + * + * MEMO: We've considered some other approaches: + * 1. Each model handle its self restoration but not uniform treatment. + * (Too complex in logic and error-prone) + * 2. Use a shadow ecModel. (Performace expensive) + */ + + +function mergeOption(oldOption, newOption) { + newOption = newOption || {}; + each$4(newOption, function (newCptOpt, mainType) { + if (newCptOpt == null) { + return; + } + + var oldCptOpt = oldOption[mainType]; + + if (!ComponentModel.hasClass(mainType)) { + oldOption[mainType] = merge$1(oldCptOpt, newCptOpt, true); + } else { + newCptOpt = normalizeToArray(newCptOpt); + oldCptOpt = normalizeToArray(oldCptOpt); + var mapResult = mappingToExists(oldCptOpt, newCptOpt); + oldOption[mainType] = map$1(mapResult, function (item) { + return item.option && item.exist ? merge$1(item.exist, item.option, true) : item.exist || item.option; + }); + } + }); +} + +/* +* 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 each$5 = each$1; +var isObject$3 = isObject$1; +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]) { + 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]) { + 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) { + // 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) { + opt.emphasis = opt.emphasis || {}; + opt.emphasis[optType] = emphasisOpt; + } + } +} + +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$3(opt) && opt[propName]; + var textStyle = isObject$3(labelOptSingle) && labelOptSingle.textStyle; + + if (textStyle) { + for (var i = 0, len = TEXT_STYLE_OPTIONS.length; i < len; i++) { + var propName = TEXT_STYLE_OPTIONS[i]; + + if (textStyle.hasOwnProperty(propName)) { + labelOptSingle[propName] = textStyle[propName]; + } + } + } +} + +function compatEC3CommonStyles(opt) { + if (opt) { + removeEC3NormalStatus(opt); + compatTextStyle(opt, 'label'); + opt.emphasis && compatTextStyle(opt.emphasis, 'label'); + } +} + +function processSeries(seriesOpt) { + if (!isObject$3(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$1(seriesOpt.categories, function (opt) { + removeEC3NormalStatus(opt); + }); + } + + if (data && !isTypedArray(data)) { + for (var i = 0; i < data.length; i++) { + compatEC3CommonStyles(data[i]); + } + } // mark point data + + + var 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 + + + var 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$1(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) || {}; +} + +var compatStyle = function (option, isTheme) { + each$5(toArr(option.series), function (seriesOpt) { + isObject$3(seriesOpt) && processSeries(seriesOpt); + }); + var axes = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'parallelAxis', 'radar']; + isTheme && axes.push('valueAxis', 'categoryAxis', 'logAxis', 'timeAxis'); + each$5(axes, function (axisName) { + each$5(toArr(option[axisName]), function (axisOpt) { + if (axisOpt) { + compatTextStyle(axisOpt, 'axisLabel'); + compatTextStyle(axisOpt.axisPointer, 'label'); + } + }); + }); + each$5(toArr(option.parallel), function (parallelOpt) { + var parallelAxisDefault = parallelOpt && parallelOpt.parallelAxisDefault; + compatTextStyle(parallelAxisDefault, 'axisLabel'); + compatTextStyle(parallelAxisDefault && parallelAxisDefault.axisPointer, 'label'); + }); + each$5(toArr(option.calendar), function (calendarOpt) { + convertNormalEmphasis(calendarOpt, 'itemStyle'); + compatTextStyle(calendarOpt, 'dayLabel'); + compatTextStyle(calendarOpt, 'monthLabel'); + compatTextStyle(calendarOpt, 'yearLabel'); + }); // radar.name.textStyle + + each$5(toArr(option.radar), function (radarOpt) { + compatTextStyle(radarOpt, 'name'); + }); + each$5(toArr(option.geo), function (geoOpt) { + if (isObject$3(geoOpt)) { + compatEC3CommonStyles(geoOpt); + each$5(toArr(geoOpt.regions), function (regionObj) { + compatEC3CommonStyles(regionObj); + }); + } + }); + each$5(toArr(option.timeline), function (timelineOpt) { + compatEC3CommonStyles(timelineOpt); + convertNormalEmphasis(timelineOpt, 'label'); + convertNormalEmphasis(timelineOpt, 'itemStyle'); + convertNormalEmphasis(timelineOpt, 'controlStyle', true); + var data = timelineOpt.data; + isArray(data) && each$1(data, function (item) { + if (isObject$1(item)) { + convertNormalEmphasis(item, 'label'); + convertNormalEmphasis(item, 'itemStyle'); + } + }); + }); + each$5(toArr(option.toolbox), function (toolboxOpt) { + convertNormalEmphasis(toolboxOpt, 'iconStyle'); + each$5(toolboxOpt.feature, function (featureOpt) { + convertNormalEmphasis(featureOpt, 'iconStyle'); + }); + }); + compatTextStyle(toObj(option.axisPointer), 'label'); + compatTextStyle(toObj(option.tooltip).axisPointer, 'label'); +}; + +/* +* 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. +*/ +// Compatitable with 2.0 +function get(opt, path) { + path = path.split(','); + var obj = opt; + + for (var i = 0; i < path.length; i++) { + obj = obj && obj[path[i]]; + + if (obj == null) { + break; + } + } + + return obj; +} + +function set$1(opt, path, val, overwrite) { + path = path.split(','); + var obj = opt; + var key; + + for (var i = 0; i < path.length - 1; i++) { + key = path[i]; + + if (obj[key] == null) { + obj[key] = {}; + } + + obj = obj[key]; + } + + if (overwrite || obj[path[i]] == null) { + obj[path[i]] = val; + } +} + +function compatLayoutProperties(option) { + each$1(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 backwardCompat = function (option, isTheme) { + compatStyle(option, isTheme); // Make sure series array for model initialization. + + option.series = normalizeToArray(option.series); + each$1(option.series, function (seriesOpt) { + if (!isObject$1(seriesOpt)) { + return; + } + + var seriesType = seriesOpt.type; + + if (seriesType === 'line') { + if (seriesOpt.clipOverflow != null) { + seriesOpt.clip = seriesOpt.clipOverflow; + } + } else if (seriesType === 'pie' || seriesType === 'gauge') { + if (seriesOpt.clockWise != null) { + seriesOpt.clockwise = seriesOpt.clockWise; + } + } else if (seriesType === 'gauge') { + var pointerColor = get(seriesOpt, 'pointer.color'); + pointerColor != null && set$1(seriesOpt, 'itemStyle.color', pointerColor); + } + + compatLayoutProperties(seriesOpt); + }); // dataRange has changed to visualMap + + if (option.dataRange) { + option.visualMap = option.dataRange; + } + + each$1(COMPATITABLE_COMPONENTS, function (componentName) { + var options = option[componentName]; + + if (options) { + if (!isArray(options)) { + options = [options]; + } + + each$1(options, function (option) { + compatLayoutProperties(option); + }); + } + }); +}; + +/* +* 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. +*/ +// 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. + +var dataStack = function (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. + 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$1(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. + + var newData = targetData.map(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 + ) { + sum += val; + stackedOver = val; + break; + } + } + } + + resultVal[0] = sum; + resultVal[1] = stackedOver; + return resultVal; + }); + targetData.hostModel.setData(newData); // Update for consequent calculation + + targetStackInfo.data = newData; + }); +} + +/* +* 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. +*/ +// TODO +// ??? refactor? check the outer usage of data provider. +// merge with defaultDimValueGetter? +/** + * If normal array used, mutable chunk size is supported. + * If typed array used, chunk size must be fixed. + */ + +function DefaultDataProvider(source, dimSize) { + if (!Source.isInstance(source)) { + source = Source.seriesDataToSource(source); + } + + this._source = source; + var data = this._data = source.data; + var sourceFormat = source.sourceFormat; // Typed array. TODO IE10+? + + if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) { + this._offset = 0; + this._dimSize = dimSize; + this._data = data; + } + + var methods = providerMethods[sourceFormat === SOURCE_FORMAT_ARRAY_ROWS ? sourceFormat + '_' + source.seriesLayoutBy : sourceFormat]; + extend(this, methods); +} +var providerProto = DefaultDataProvider.prototype; // If data is pure without style configuration + +providerProto.pure = false; // If data is persistent and will not be released after use. + +providerProto.persistent = true; // ???! FIXME legacy data provider do not has method getSource + +providerProto.getSource = function () { + return this._source; +}; + +var providerMethods = { + 'arrayRows_column': { + pure: true, + count: function () { + return Math.max(0, this._data.length - this._source.startIndex); + }, + getItem: function (idx) { + return this._data[idx + this._source.startIndex]; + }, + appendData: appendDataSimply + }, + 'arrayRows_row': { + pure: true, + count: function () { + var row = this._data[0]; + return row ? Math.max(0, row.length - this._source.startIndex) : 0; + }, + getItem: function (idx) { + idx += this._source.startIndex; + var item = []; + var data = this._data; + + for (var i = 0; i < data.length; i++) { + var row = data[i]; + item.push(row ? row[idx] : null); + } + + return item; + }, + appendData: function () { + throw new Error('Do not support appendData when set seriesLayoutBy: "row".'); + } + }, + 'objectRows': { + pure: true, + count: countSimply, + getItem: getItemSimply, + appendData: appendDataSimply + }, + 'keyedColumns': { + pure: true, + count: function () { + var dimName = this._source.dimensionsDefine[0].name; + var col = this._data[dimName]; + return col ? col.length : 0; + }, + getItem: function (idx) { + var item = []; + var dims = this._source.dimensionsDefine; + + for (var i = 0; i < dims.length; i++) { + var col = this._data[dims[i].name]; + item.push(col ? col[idx] : null); + } + + return item; + }, + appendData: function (newData) { + var data = this._data; + each$1(newData, function (newCol, key) { + var oldCol = data[key] || (data[key] = []); + + for (var i = 0; i < (newCol || []).length; i++) { + oldCol.push(newCol[i]); + } + }); + } + }, + 'original': { + count: countSimply, + getItem: getItemSimply, + appendData: appendDataSimply + }, + 'typedArray': { + persistent: false, + pure: true, + count: function () { + return this._data ? this._data.length / this._dimSize : 0; + }, + getItem: function (idx, out) { + idx = idx - this._offset; + out = out || []; + var offset = this._dimSize * idx; + + for (var i = 0; i < this._dimSize; i++) { + out[i] = this._data[offset + i]; + } + + return out; + }, + appendData: function (newData) { + this._data = newData; + }, + // Clean self if data is already used. + clean: function () { + // PENDING + this._offset += this.count(); + this._data = null; + } + } +}; + +function countSimply() { + return this._data.length; +} + +function getItemSimply(idx) { + return this._data[idx]; +} + +function appendDataSimply(newData) { + for (var i = 0; i < newData.length; i++) { + this._data.push(newData[i]); + } +} + +var rawValueGetters = { + arrayRows: getRawValueSimply, + objectRows: function (dataItem, dataIndex, dimIndex, dimName) { + return dimIndex != null ? dataItem[dimName] : dataItem; + }, + keyedColumns: getRawValueSimply, + original: function (dataItem, dataIndex, dimIndex, dimName) { + // FIXME + // In some case (markpoint in geo (geo-map.html)), dataItem + // is {coord: [...]} + var value = getDataItemValue(dataItem); + return dimIndex == null || !(value instanceof Array) ? value : value[dimIndex]; + }, + typedArray: getRawValueSimply +}; + +function getRawValueSimply(dataItem, dataIndex, dimIndex, dimName) { + return dimIndex != null ? dataItem[dimIndex] : dataItem; +} + +var defaultDimValueGetters = { + arrayRows: getDimValueSimply, + objectRows: function (dataItem, dimName, dataIndex, dimIndex) { + return converDataValue(dataItem[dimName], this._dimensionInfos[dimName]); + }, + keyedColumns: getDimValueSimply, + original: function (dataItem, dimName, dataIndex, dimIndex) { + // Performance sensitive, do not use modelUtil.getDataItemValue. + // If dataItem is an plain object with no value field, the var `value` + // will be assigned with the object, but it will be tread correctly + // in the `convertDataValue`. + var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value); // If any dataItem is like { value: 10 } + + if (!this._rawData.pure && isDataItemOption(dataItem)) { + this.hasItemOption = true; + } + + return converDataValue(value instanceof Array ? value[dimIndex] // If value is a single number or something else not array. + : value, this._dimensionInfos[dimName]); + }, + typedArray: function (dataItem, dimName, dataIndex, dimIndex) { + return dataItem[dimIndex]; + } +}; + +function getDimValueSimply(dataItem, dimName, dataIndex, dimIndex) { + return converDataValue(dataItem[dimIndex], this._dimensionInfos[dimName]); +} +/** + * This helper method convert value in data. + * @param {string|number|Date} value + * @param {Object|string} [dimInfo] If string (like 'x'), dimType defaults 'number'. + * If "dimInfo.ordinalParseAndSave", ordinal value can be parsed. + */ + + +function converDataValue(value, dimInfo) { + // Performance sensitive. + var dimType = dimInfo && dimInfo.type; + + if (dimType === 'ordinal') { + // If given value is a category string + var ordinalMeta = dimInfo && dimInfo.ordinalMeta; + return ordinalMeta ? ordinalMeta.parseAndCollect(value) : value; + } + + if (dimType === 'time' // spead up when using timestamp + && typeof value !== 'number' && 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. + + + return value == null || value === '' ? NaN // If string (like '-'), using '+' parse to NaN + // If object, also parse to NaN + : +value; +} // ??? 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? + +/** + * @param {module:echarts/data/List} data + * @param {number} dataIndex + * @param {string|number} [dim] dimName or dimIndex + * @return {Array.|string|number} can be null/undefined. + */ + + +function retrieveRawValue(data, dataIndex, dim) { + if (!data) { + return; + } // Consider data may be not persistent. + + + var dataItem = data.getRawDataItem(dataIndex); + + if (dataItem == null) { + return; + } + + var sourceFormat = data.getProvider().getSource().sourceFormat; + var dimName; + var dimIndex; + var dimInfo = data.getDimensionInfo(dim); + + if (dimInfo) { + dimName = dimInfo.name; + dimIndex = dimInfo.index; + } + + return rawValueGetters[sourceFormat](dataItem, dataIndex, dimIndex, dimName); +} +/** + * Compatible with some cases (in pie, map) like: + * data: [{name: 'xx', value: 5, selected: true}, ...] + * where only sourceFormat is 'original' and 'objectRows' supported. + * + * ??? TODO + * Supported detail options in data item when using 'arrayRows'. + * + * @param {module:echarts/data/List} data + * @param {number} dataIndex + * @param {string} attr like 'selected' + */ + +function retrieveRawAttr(data, dataIndex, attr) { + if (!data) { + return; + } + + var sourceFormat = data.getProvider().getSource().sourceFormat; + + if (sourceFormat !== SOURCE_FORMAT_ORIGINAL && sourceFormat !== SOURCE_FORMAT_OBJECT_ROWS) { + return; + } + + var dataItem = data.getRawDataItem(dataIndex); + + if (sourceFormat === SOURCE_FORMAT_ORIGINAL && !isObject$1(dataItem)) { + dataItem = null; + } + + if (dataItem) { + return dataItem[attr]; + } +} + +/* +* 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 DIMENSION_LABEL_REG = /\{@(.+?)\}/g; // PENDING A little ugly + +var dataFormatMixin = { + /** + * Get params for formatter + * @param {number} dataIndex + * @param {string} [dataType] + * @return {Object} + */ + 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 color = data.getItemVisual(dataIndex, 'color'); + var borderColor = data.getItemVisual(dataIndex, 'borderColor'); + var tooltipModel = this.ecModel.getComponent('tooltip'); + var renderModeOption = tooltipModel && tooltipModel.get('renderMode'); + var renderMode = getTooltipRenderMode(renderModeOption); + var mainType = this.mainType; + var isSeries = mainType === 'series'; + var userOutput = data.userOutput; + 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.dimensionNames : null, + encode: userOutput ? userOutput.encode : null, + marker: getTooltipMarker({ + color: color, + renderMode: renderMode + }), + // Param name list for mapping `a`, `b`, `c`, `d`, `e` + $vars: ['seriesName', 'name', 'value'] + }; + }, + + /** + * Format label + * @param {number} dataIndex + * @param {string} [status='normal'] 'normal' or 'emphasis' + * @param {string} [dataType] + * @param {number} [dimIndex] Only used in some chart that + * use formatter in different dimensions, like radar. + * @param {string} [labelProp='label'] + * @return {string} If not formatter, return null/undefined + */ + getFormattedLabel: function (dataIndex, status, dataType, dimIndex, labelProp) { + status = status || 'normal'; + var data = this.getData(dataType); + var itemModel = data.getItemModel(dataIndex); + var params = this.getDataParams(dataIndex, dataType); + + if (dimIndex != null && params.value instanceof Array) { + params.value = params.value[dimIndex]; + } + + var formatter = itemModel.get(status === 'normal' ? [labelProp || 'label', 'formatter'] : [status, labelProp || 'label', 'formatter']); + + if (typeof formatter === 'function') { + params.status = status; + params.dimensionIndex = dimIndex; + return formatter(params); + } else if (typeof formatter === 'string') { + 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, dim) { + var len = dim.length; + + if (dim.charAt(0) === '[' && dim.charAt(len - 1) === ']') { + dim = +dim.slice(1, len - 1); // Also: '[]' => 0 + } + + return retrieveRawValue(data, dataIndex, dim); + }); + } + }, + + /** + * Get raw value in option + * @param {number} idx + * @param {string} [dataType] + * @return {Array|number|string} + */ + getRawValue: function (idx, dataType) { + return retrieveRawValue(this.getData(dataType), idx); + }, + + /** + * Should be implemented. + * @param {number} dataIndex + * @param {boolean} [multipleSeries=false] + * @param {number} [dataType] + * @return {string} tooltip string + */ + formatTooltip: function () {// Empty function + } +}; + +/* +* 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. +*/ +/** + * @param {Object} define + * @return See the return of `createTask`. + */ + +function createTask(define) { + return new Task(define); +} +/** + * @constructor + * @param {Object} define + * @param {Function} define.reset Custom reset + * @param {Function} [define.plan] Returns 'reset' indicate reset immediately. + * @param {Function} [define.count] count is used to determin data task. + * @param {Function} [define.onDirty] count is used to determin data task. + */ + +function Task(define) { + define = define || {}; + this._reset = define.reset; + this._plan = define.plan; + this._count = define.count; + this._onDirty = define.onDirty; + this._dirty = true; // Context must be specified implicitly, to + // avoid miss update context when model changed. + + this.context; +} + +var taskProto = Task.prototype; +/** + * @param {Object} performArgs + * @param {number} [performArgs.step] Specified step. + * @param {number} [performArgs.skip] Skip customer perform call. + * @param {number} [performArgs.modBy] Sampling window size. + * @param {number} [performArgs.modDataCount] Sampling count. + */ + +taskProto.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 = reset(this, skip); + } + + this._modBy = modBy; + this._modDataCount = modDataCount; + var step = performArgs && performArgs.step; + + if (upTask) { + this._dueEnd = upTask._outputDueEnd; + } // DataTask or overallTask + else { + 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++) { + doProgress(this, progress[i], start, end, modBy, modDataCount); + } + } else { + doProgress(this, 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; + 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(); +}; + +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; + } +}(); + +taskProto.dirty = function () { + this._dirty = true; + this._onDirty && this._onDirty(this.context); +}; + +function doProgress(taskIns, progress, start, end, modBy, modDataCount) { + iterator.reset(start, end, modBy, modDataCount); + taskIns._callingProgress = progress; + + taskIns._callingProgress({ + start: start, + end: end, + count: end - start, + next: iterator.next + }, taskIns.context); +} + +function reset(taskIns, skip) { + taskIns._dueIndex = taskIns._outputDueEnd = taskIns._dueEnd = 0; + taskIns._settedOutputEnd = null; + var progress; + var forceFirstProgress; + + if (!skip && taskIns._reset) { + progress = taskIns._reset(taskIns.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; + } + } + + taskIns._progress = progress; + taskIns._modBy = taskIns._modDataCount = null; + var downstream = taskIns._downstream; + downstream && downstream.dirty(); + return forceFirstProgress; +} +/** + * @return {boolean} + */ + + +taskProto.unfinished = function () { + return this._progress && this._dueIndex < this._dueEnd; +}; +/** + * @param {Object} downTask The downstream task. + * @return {Object} The downstream task. + */ + + +taskProto.pipe = function (downTask) { + // If already downstream, do not dirty downTask. + if (this._downstream !== downTask || this._dirty) { + this._downstream = downTask; + downTask._upstream = this; + downTask.dirty(); + } +}; + +taskProto.dispose = function () { + if (this._disposed) { + return; + } + + this._upstream && (this._upstream._downstream = null); + this._downstream && (this._downstream._upstream = null); + this._dirty = false; + this._disposed = true; +}; + +taskProto.getUpstream = function () { + return this._upstream; +}; + +taskProto.getDownstream = function () { + return this._downstream; +}; + +taskProto.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; +}; /////////////////////////////////////////////////////////// +// For stream debug (Should be commented out after used!) +// Usage: printTask(this, 'begin'); +// Usage: printTask(this, null, {someExtraProp}); +// function printTask(task, prefix, extra) { +// 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++}`); +// var props = []; +// if (task.__pipeline) { +// var val = `${task.__idxInPipeline}/${task.__pipeline.tail.__idxInPipeline} ${task.agent ? '(stub)' : ''}`; +// props.push({text: 'idx', value: val}); +// } else { +// var 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: 'pid', 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]}); +// }); +// } +// var args = ['color: blue']; +// var msg = `%c[${prefix || 'T'}] %c` + props.map(item => ( +// args.push('color: black', 'color: red'), +// `${item.text}: %c${item.value}` +// )).join('%c, '); +// console.log.apply(console, [msg].concat(args)); +// // console.log(this); +// } + +/* +* 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 inner$4 = makeInner(); +var SeriesModel = ComponentModel.extend({ + type: 'series.__base__', + + /** + * @readOnly + */ + seriesIndex: 0, + // coodinateSystem will be injected in the echarts/CoordinateSystem + coordinateSystem: null, + + /** + * @type {Object} + * @protected + */ + defaultOption: null, + + /** + * Data provided for legend + * @type {Function} + */ + // PENDING + legendDataProvider: null, + + /** + * Access path of color for visual + */ + visualColorAccessPath: 'itemStyle.color', + + /** + * Access path of borderColor for visual + */ + visualBorderColorAccessPath: 'itemStyle.borderColor', + + /** + * Support merge layout params. + * Only support 'box' now (left/right/top/bottom/width/height). + * @type {string|Object} Object can be {ignoreSize: true} + * @readOnly + */ + layoutMode: null, + init: function (option, parentModel, ecModel, extraOpt) { + /** + * @type {number} + * @readOnly + */ + this.seriesIndex = this.componentIndex; + this.dataTask = createTask({ + count: dataTaskCount, + reset: dataTaskReset + }); + this.dataTask.context = { + model: this + }; + this.mergeDefaultAndTheme(option, ecModel); + prepareSource(this); + var data = this.getInitialData(option, ecModel); + wrapData(data, this); + this.dataTask.context.data = data; + + /** + * @type {module:echarts/data/List|module:echarts/data/Tree|module:echarts/data/Graph} + * @private + */ + inner$4(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/linkList + // 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); + }, + + /** + * Util for merge default and theme to option + * @param {Object} option + * @param {module:echarts/model/Global} ecModel + */ + mergeDefaultAndTheme: function (option, ecModel) { + var layoutMode = this.layoutMode; + 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); + } + }, + mergeOption: function (newSeriesOption, ecModel) { + // this.settingTask.dirty(); + newSeriesOption = merge(this.option, newSeriesOption, true); + this.fillDataTextStyle(newSeriesOption.data); + var layoutMode = this.layoutMode; + + if (layoutMode) { + mergeLayoutParam(this.option, newSeriesOption, layoutMode); + } + + prepareSource(this); + var data = this.getInitialData(newSeriesOption, ecModel); + wrapData(data, this); + this.dataTask.dirty(); + this.dataTask.context.data = data; + inner$4(this).dataBeforeProcessed = data; + autoSeriesName(this); + }, + 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 overwritten + */ + getInitialData: function () {}, + + /** + * Append data to list + * @param {Object} params + * @param {Array|TypedArray} params.data + */ + 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. + * @param {string} [dataType] + * @return {module:echarts/data/List} + */ + 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$4(this).data; + } + }, + + /** + * @param {module:echarts/data/List} data + */ + setData: function (data) { + var task = getCurrentTask(this); + + if (task) { + var context = task.context; // Consider case: filter, data sample. + + 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$4(this).data = data; + }, + + /** + * @see {module:echarts/data/helper/sourceHelper#getSource} + * @return {module:echarts/data/Source} source + */ + getSource: function () { + return getSource(this); + }, + + /** + * Get data before processed + * @return {module:echarts/data/List} + */ + getRawData: function () { + return inner$4(this).dataBeforeProcessed; + }, + + /** + * Get base axis if has coordinate system and has axis. + * By default use coordSys.getBaseAxis(); + * Can be overrided for some chart. + * @return {type} description + */ + getBaseAxis: function () { + var coordSys = this.coordinateSystem; + return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis(); + }, + // FIXME + + /** + * Default tooltip formatter + * + * @param {number} dataIndex + * @param {boolean} [multipleSeries=false] + * @param {number} [dataType] + * @param {string} [renderMode='html'] valid values: 'html' 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 {Object} formatted tooltip with `html` and `markers` + */ + formatTooltip: function (dataIndex, multipleSeries, dataType, renderMode) { + var series = this; + renderMode = renderMode || 'html'; + var newLine = renderMode === 'html' ? '
' : '\n'; + var isRichText = renderMode === 'richText'; + var markers = {}; + var markerId = 0; + + function formatArrayValue(value) { + // ??? TODO refactor these logic. + // check: category-no-encode-has-axis-data in dataset.html + var vertially = reduce(value, function (vertially, val, idx) { + var dimItem = data.getDimensionInfo(idx); + return vertially |= dimItem && dimItem.tooltip !== false && dimItem.displayName != null; + }, 0); + var result = []; + tooltipDims.length ? each$1(tooltipDims, function (dim) { + setEachItem(retrieveRawValue(data, dataIndex, dim), dim); + }) // By default, all dims is used on tooltip. + : each$1(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; + } + + var dimType = dimInfo.type; + var markName = 'sub' + series.seriesIndex + 'at' + markerId; + var dimHead = getTooltipMarker({ + color: color, + type: 'subItem', + renderMode: renderMode, + markerId: markName + }); + var dimHeadStr = typeof dimHead === 'string' ? dimHead : dimHead.content; + var valStr = (vertially ? dimHeadStr + encodeHTML(dimInfo.displayName || '-') + ': ' : '') + // FIXME should not format time for raw data? + encodeHTML(dimType === 'ordinal' ? val + '' : dimType === 'time' ? multipleSeries ? '' : formatTime('yyyy/MM/dd hh:mm:ss', val) : addCommas(val)); + valStr && result.push(valStr); + + if (isRichText) { + markers[markName] = color; + ++markerId; + } + } + + var newLine = vertially ? isRichText ? '\n' : '
' : ''; + var content = newLine + result.join(newLine || ', '); + return { + renderMode: renderMode, + content: content, + style: markers + }; + } + + function formatSingleValue(val) { + // return encodeHTML(addCommas(val)); + return { + renderMode: renderMode, + content: encodeHTML(addCommas(val)), + style: markers + }; + } + + var data = this.getData(); + var tooltipDims = data.mapDimension('defaultedTooltip', true); + var tooltipDimLen = tooltipDims.length; + var value = this.getRawValue(dataIndex); + var isValueArr = isArray(value); + var color = data.getItemVisual(dataIndex, 'color'); + + if (isObject$1(color) && color.colorStops) { + color = (color.colorStops[0] || {}).color; + } + + color = color || 'transparent'; // Complicated rule for pretty tooltip. + + var formattedValue = tooltipDimLen > 1 || isValueArr && !tooltipDimLen ? formatArrayValue(value) : tooltipDimLen ? formatSingleValue(retrieveRawValue(data, dataIndex, tooltipDims[0])) : formatSingleValue(isValueArr ? value[0] : value); + var content = formattedValue.content; + var markName = series.seriesIndex + 'at' + markerId; + var colorEl = getTooltipMarker({ + color: color, + type: 'item', + renderMode: renderMode, + markerId: markName + }); + markers[markName] = color; + ++markerId; + var name = data.getName(dataIndex); + var seriesName = this.name; + + if (!isNameSpecified(this)) { + seriesName = ''; + } + + seriesName = seriesName ? encodeHTML(seriesName) + (!multipleSeries ? newLine : ': ') : ''; + var colorStr = typeof colorEl === 'string' ? colorEl : colorEl.content; + var html = !multipleSeries ? seriesName + colorStr + (name ? encodeHTML(name) + ': ' + content : content) : colorStr + seriesName + content; + return { + html: html, + markers: markers + }; + }, + + /** + * @return {boolean} + */ + isAnimationEnabled: function () { + if (env$1.node) { + return false; + } + + var animationEnabled = this.getShallow('animation'); + + if (animationEnabled) { + if (this.getData().count() > this.getShallow('animationThreshold')) { + animationEnabled = false; + } + } + + return animationEnabled; + }, + restoreData: function () { + this.dataTask.dirty(); + }, + getColorFromPalette: function (name, scope, requestColorNum) { + var ecModel = this.ecModel; // PENDING + + var color = colorPaletteMixin.getColorFromPalette.call(this, name, scope, requestColorNum); + + if (!color) { + color = ecModel.getColorFromPalette(name, scope, requestColorNum); + } + + return color; + }, + + /** + * Use `data.mapDimension(coordDim, true)` instead. + * @deprecated + */ + coordDimToDataDim: function (coordDim) { + return this.getRawData().mapDimension(coordDim, true); + }, + + /** + * Get progressive rendering count each step + * @return {number} + */ + getProgressive: function () { + return this.get('progressive'); + }, + + /** + * Get progressive rendering count each step + * @return {number} + */ + getProgressiveThreshold: function () { + return this.get('progressiveThreshold'); + }, + + /** + * Get data indices for show tooltip content. See tooltip. + * @abstract + * @param {Array.|string} dim + * @param {Array.} value + * @param {module:echarts/coord/single/SingleAxis} baseAxis + * @return {Object} {dataIndices, nestestValue}. + */ + getAxisTooltipData: null, + + /** + * See tooltip. + * @abstract + * @param {number} dataIndex + * @return {Array.} Point of tooltip. null/undefined can be returned. + */ + getTooltipPosition: null, + + /** + * @see {module:echarts/stream/Scheduler} + */ + pipeTask: null, + + /** + * Convinient for override in extended class. + * @protected + * @type {Function} + */ + preventIncremental: null, + + /** + * @public + * @readOnly + * @type {Object} + */ + pipelineContext: null +}); +mixin(SeriesModel, dataFormatMixin); +mixin(SeriesModel, colorPaletteMixin); +/** + * 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.mapDimension('seriesName', true); + var nameArr = []; + each$1(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 (param.end > context.outputData.count()) { + context.model.getRawData().cloneShallow(context.outputData); + } +} // TODO refactor + + +function wrapData(data, seriesModel) { + each$1(data.CHANGABLE_METHODS, function (methodName) { + data.wrapMethod(methodName, curry(onDataSelfChange, seriesModel)); + }); +} + +function onDataSelfChange(seriesModel) { + var task = getCurrentTask(seriesModel); + + if (task) { + // Consider case: filter, selectRange + task.setOutputEnd(this.count()); + } +} + +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; + } +} + +/* +* 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 Component$1 = function () { + /** + * @type {module:zrender/container/Group} + * @readOnly + */ + this.group = new Group(); + /** + * @type {string} + * @readOnly + */ + + this.uid = getUID('viewComponent'); +}; + +Component$1.prototype = { + constructor: Component$1, + init: function (ecModel, api) {}, + render: function (componentModel, ecModel, api, payload) {}, + dispose: function () {}, + + /** + * @param {string} eventType + * @param {Object} query + * @param {module:zrender/Element} targetEl + * @param {Object} packedEvent + * @return {boolen} Pass only when return `true`. + */ + filterForExposedEvent: null +}; +var componentProto = Component$1.prototype; + +componentProto.updateView = componentProto.updateLayout = componentProto.updateVisual = function (seriesModel, ecModel, api, payload) {// Do nothing; +}; // Enable Component.extend. + + +enableClassExtend(Component$1); // Enable capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on. + +enableClassManagement(Component$1, { + registerWhenExtend: 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. +*/ +/** + * @return {string} If large mode changed, return string 'reset'; + */ + +var createRenderPlanner = function () { + var inner = makeInner(); + return function (seriesModel) { + var fields = inner(seriesModel); + var pipelineContext = seriesModel.pipelineContext; + var originalLarge = fields.large; + var originalProgressive = fields.progressiveRender; + var large = fields.large = pipelineContext.large; + var progressive = fields.progressiveRender = pipelineContext.progressiveRender; + return !!(originalLarge ^ large || originalProgressive ^ progressive) && 'reset'; + }; +}; + +/* +* 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 inner$5 = makeInner(); +var renderPlanner = createRenderPlanner(); + +function Chart() { + /** + * @type {module:zrender/container/Group} + * @readOnly + */ + this.group = new Group(); + /** + * @type {string} + * @readOnly + */ + + this.uid = getUID('viewChart'); + this.renderTask = createTask({ + plan: renderTaskPlan, + reset: renderTaskReset + }); + this.renderTask.context = { + view: this + }; +} + +Chart.prototype = { + type: 'chart', + + /** + * Init the chart. + * @param {module:echarts/model/Global} ecModel + * @param {module:echarts/ExtensionAPI} api + */ + init: function (ecModel, api) {}, + + /** + * Render the chart. + * @param {module:echarts/model/Series} seriesModel + * @param {module:echarts/model/Global} ecModel + * @param {module:echarts/ExtensionAPI} api + * @param {Object} payload + */ + render: function (seriesModel, ecModel, api, payload) {}, + + /** + * Highlight series or specified data item. + * @param {module:echarts/model/Series} seriesModel + * @param {module:echarts/model/Global} ecModel + * @param {module:echarts/ExtensionAPI} api + * @param {Object} payload + */ + highlight: function (seriesModel, ecModel, api, payload) { + toggleHighlight(seriesModel.getData(), payload, 'emphasis'); + }, + + /** + * Downplay series or specified data item. + * @param {module:echarts/model/Series} seriesModel + * @param {module:echarts/model/Global} ecModel + * @param {module:echarts/ExtensionAPI} api + * @param {Object} payload + */ + downplay: function (seriesModel, ecModel, api, payload) { + toggleHighlight(seriesModel.getData(), payload, 'normal'); + }, + + /** + * Remove self. + * @param {module:echarts/model/Global} ecModel + * @param {module:echarts/ExtensionAPI} api + */ + remove: function (ecModel, api) { + this.group.removeAll(); + }, + + /** + * Dispose self. + * @param {module:echarts/model/Global} ecModel + * @param {module:echarts/ExtensionAPI} api + */ + dispose: function () {}, + + /** + * Rendering preparation in progressive mode. + * @param {module:echarts/model/Series} seriesModel + * @param {module:echarts/model/Global} ecModel + * @param {module:echarts/ExtensionAPI} api + * @param {Object} payload + */ + incrementalPrepareRender: null, + + /** + * Render in progressive mode. + * @param {Object} params See taskParams in `stream/task.js` + * @param {module:echarts/model/Series} seriesModel + * @param {module:echarts/model/Global} ecModel + * @param {module:echarts/ExtensionAPI} api + * @param {Object} payload + */ + incrementalRender: null, + + /** + * Update transform directly. + * @param {module:echarts/model/Series} seriesModel + * @param {module:echarts/model/Global} ecModel + * @param {module:echarts/ExtensionAPI} api + * @param {Object} payload + * @return {Object} {update: true} + */ + updateTransform: null, + + /** + * The view contains the given point. + * @interface + * @param {Array.} point + * @return {boolean} + */ + // containPoint: function () {} + + /** + * @param {string} eventType + * @param {Object} query + * @param {module:zrender/Element} targetEl + * @param {Object} packedEvent + * @return {boolen} Pass only when return `true`. + */ + filterForExposedEvent: null +}; +var chartProto = Chart.prototype; + +chartProto.updateView = chartProto.updateLayout = chartProto.updateVisual = function (seriesModel, ecModel, api, payload) { + this.render(seriesModel, ecModel, api, payload); +}; +/** + * Set state of single element + * @param {module:zrender/Element} el + * @param {string} state 'normal'|'emphasis' + * @param {number} highlightDigit + */ + + +function elSetState(el, state, highlightDigit) { + if (el) { + el.trigger(state, highlightDigit); + + if (el.isGroup // Simple optimize. + && !isHighDownDispatcher(el)) { + for (var i = 0, len = el.childCount(); i < len; i++) { + elSetState(el.childAt(i), state, highlightDigit); + } + } + } +} +/** + * @param {module:echarts/data/List} data + * @param {Object} payload + * @param {string} state 'normal'|'emphasis' + */ + + +function toggleHighlight(data, payload, state) { + var dataIndex = queryDataIndex(data, payload); + var highlightDigit = payload && payload.highlightKey != null ? getHighlightDigit(payload.highlightKey) : null; + + if (dataIndex != null) { + each$1(normalizeToArray(dataIndex), function (dataIdx) { + elSetState(data.getItemGraphicEl(dataIdx), state, highlightDigit); + }); + } else { + data.eachItemGraphicEl(function (el) { + elSetState(el, state, highlightDigit); + }); + } +} // Enable Chart.extend. + + +enableClassExtend(Chart, ['dispose']); // Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on. + +enableClassManagement(Chart, { + registerWhenExtend: true +}); + +Chart.markUpdateMethod = function (payload, methodName) { + inner$5(payload).updateMethod = methodName; +}; + +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; // ???! remove updateView updateVisual + + var progressiveRender = seriesModel.pipelineContext.progressiveRender; + var view = context.view; + var updateMethod = payload && inner$5(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. +*/ +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 () { + currCall = new Date().getTime(); + scope = this; + args = arguments; + 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'); + * }; + * + * @public + * @param {Object} obj + * @param {string} fnAttr + * @param {number} [rate] + * @param {string} [throttleType='fixRate'] 'fixRate' or 'debounce' + * @return {Function} throttled function. + */ + +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. + * + * @public + * @param {Object} obj + * @param {string} fnAttr + */ + +/* +* 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 seriesColor = { + createOnAllSeries: true, + performRawSeries: true, + reset: function (seriesModel, ecModel) { + var data = seriesModel.getData(); + var colorAccessPath = (seriesModel.visualColorAccessPath || 'itemStyle.color').split('.'); + var color = seriesModel.get(colorAccessPath) // Set in itemStyle + || seriesModel.getColorFromPalette( // TODO series count changed. + seriesModel.name, null, ecModel.getSeriesCount()); // Default color + // FIXME Set color function or use the platte color + + data.setVisual('color', color); + var borderColorAccessPath = (seriesModel.visualBorderColorAccessPath || 'itemStyle.borderColor').split('.'); + var borderColor = seriesModel.get(borderColorAccessPath); + data.setVisual('borderColor', borderColor); // Only visible series has each data be visual encoded + + if (!ecModel.isSeriesFiltered(seriesModel)) { + if (typeof color === 'function' && !(color instanceof Gradient)) { + data.each(function (idx) { + data.setItemVisual(idx, 'color', color(seriesModel.getDataParams(idx))); + }); + } // itemStyle in each data item + + + var dataEach = function (data, idx) { + var itemModel = data.getItemModel(idx); + var color = itemModel.get(colorAccessPath, true); + var borderColor = itemModel.get(borderColorAccessPath, true); + + if (color != null) { + data.setItemVisual(idx, 'color', color); + } + + if (borderColor != null) { + data.setItemVisual(idx, 'borderColor', borderColor); + } + }; + + 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. +*/ + +/** + * Language: (Simplified) Chinese. + */ +var lang = { + 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: '' + } + } + } +}; + +/* +* 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 aria = function (dom, ecModel) { + var ariaModel = ecModel.getModel('aria'); + + if (!ariaModel.get('show')) { + return; + } else if (ariaModel.get('description')) { + dom.setAttribute('aria-label', ariaModel.get('description')); + return; + } + + var seriesCnt = 0; + ecModel.eachSeries(function (seriesModel, idx) { + ++seriesCnt; + }, this); + var maxDataCnt = ariaModel.get('data.maxCount') || 10; + var maxSeriesCnt = ariaModel.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) { + ariaLabel = replace(getConfig('general.withTitle'), { + title: title + }); + } else { + ariaLabel = getConfig('general.withoutTitle'); + } + + var seriesLabels = []; + var prefix = seriesCnt > 1 ? 'series.multiple.prefix' : 'series.single.prefix'; + ariaLabel += replace(getConfig(prefix), { + seriesCount: seriesCnt + }); + ecModel.eachSeries(function (seriesModel, idx) { + if (idx < displaySeriesCnt) { + var seriesLabel; + var seriesName = seriesModel.get('name'); + var seriesTpl = 'series.' + (seriesCnt > 1 ? 'multiple' : 'single') + '.'; + seriesLabel = getConfig(seriesName ? seriesTpl + 'withName' : seriesTpl + 'withoutName'); + seriesLabel = replace(seriesLabel, { + seriesId: seriesModel.seriesIndex, + seriesName: seriesModel.get('name'), + seriesType: getSeriesTypeName(seriesModel.subType) + }); + var data = seriesModel.getData(); + window.data = data; + + if (data.count() > maxDataCnt) { + // Show part of data + seriesLabel += replace(getConfig('data.partialData'), { + displayCnt: maxDataCnt + }); + } else { + seriesLabel += getConfig('data.allData'); + } + + var dataLabels = []; + + for (var i = 0; i < data.count(); i++) { + if (i < maxDataCnt) { + var name = data.getName(i); + var value = retrieveRawValue(data, i); + dataLabels.push(replace(name ? getConfig('data.withName') : getConfig('data.withoutName'), { + name: name, + value: value + })); + } + } + + seriesLabel += dataLabels.join(getConfig('data.separator.middle')) + getConfig('data.separator.end'); + seriesLabels.push(seriesLabel); + } + }); + ariaLabel += seriesLabels.join(getConfig('series.multiple.separator.middle')) + getConfig('series.multiple.separator.end'); + dom.setAttribute('aria-label', ariaLabel); + } + + function replace(str, keyValues) { + if (typeof str !== 'string') { + return str; + } + + var result = str; + each$1(keyValues, function (value, key) { + result = result.replace(new RegExp('\\{\\s*' + key + '\\s*\\}', 'g'), value); + }); + return result; + } + + function getConfig(path) { + var userConfig = ariaModel.get(path); + + if (userConfig == null) { + var pathArr = path.split('.'); + var result = lang.aria; + + for (var i = 0; i < pathArr.length; ++i) { + result = result[pathArr[i]]; + } + + return result; + } else { + return userConfig; + } + } + + function getTitle() { + var title = ecModel.getModel('title').option; + + if (title && title.length) { + title = title[0]; + } + + return title && title.text; + } + + function getSeriesTypeName(type) { + return lang.series.typeNames[type] || '自定义图'; + } +}; + +/* +* 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 PI$1 = 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} + */ + +var loadingDefault = function (api, opts) { + opts = opts || {}; + defaults(opts, { + text: 'loading', + color: '#c23531', + textColor: '#000', + maskColor: 'rgba(255, 255, 255, 0.8)', + zlevel: 0 + }); + var mask = new Rect({ + style: { + fill: opts.maskColor + }, + zlevel: opts.zlevel, + z: 10000 + }); + var arc = new Arc({ + shape: { + startAngle: -PI$1 / 2, + endAngle: -PI$1 / 2 + 0.1, + r: 10 + }, + style: { + stroke: opts.color, + lineCap: 'round', + lineWidth: 5 + }, + zlevel: opts.zlevel, + z: 10001 + }); + var labelRect = new Rect({ + style: { + fill: 'none', + text: opts.text, + textPosition: 'right', + textDistance: 10, + textFill: opts.textColor + }, + zlevel: opts.zlevel, + z: 10001 + }); + arc.animateShape(true).when(1000, { + endAngle: PI$1 * 3 / 2 + }).start('circularInOut'); + arc.animateShape(true).when(1000, { + startAngle: PI$1 * 3 / 2 + }).delay(300).start('circularInOut'); + var group = new Group(); + group.add(arc); + group.add(labelRect); + group.add(mask); // Inject resize + + group.resize = function () { + var cx = api.getWidth() / 2; + var cy = api.getHeight() / 2; + arc.setShape({ + cx: cx, + cy: cy + }); + var r = arc.shape.r; + 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; +}; + +/* +* 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. +*/ + +/** + * @module echarts/stream/Scheduler + */ +/** + * @constructor + */ + +function Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) { + this.ecInstance = ecInstance; + this.api = api; + this.unfinished; // 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. + + var dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice(); + var visualHandlers = this._visualHandlers = visualHandlers.slice(); + this._allHandlers = dataProcessorHandlers.concat(visualHandlers); + /** + * @private + * @type { + * [handlerUID: string]: { + * seriesTaskMap?: { + * [seriesUID: string]: Task + * }, + * overallTask?: Task + * } + * } + */ + + this._stageTaskMap = createHashMap(); +} + +var proto = Scheduler.prototype; +/** + * @param {module:echarts/model/Global} ecModel + * @param {Object} payload + */ + +proto.restoreData = function (ecModel, payload) { + // TODO: Only restroe 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. + + +proto.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 + }; +}; + +proto.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()`. + */ + + +proto.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 + }; +}; + +proto.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 + }); + pipe(scheduler, seriesModel, seriesModel.dataTask); + }); +}; + +proto.prepareStageTasks = function () { + var stageTaskMap = this._stageTaskMap; + var ecModel = this.ecInstance.getModel(); + var api = this.api; + each$1(this._allHandlers, function (handler) { + var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, []); + handler.reset && createSeriesStageTask(this, handler, record, ecModel, api); + handler.overallReset && createOverallStageTask(this, handler, record, ecModel, api); + }, this); +}; + +proto.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; + pipe(this, model, renderTask); +}; + +proto.performDataProcessorTasks = function (ecModel, payload) { + // If we do not use `block` here, it should be considered when to update modes. + performStageTasks(this, this._dataProcessorHandlers, ecModel, payload, { + block: true + }); +}; // opt +// opt.visualType: 'visual' or 'layout' +// opt.setDirty + + +proto.performVisualTasks = function (ecModel, payload, opt) { + performStageTasks(this, this._visualHandlers, ecModel, payload, opt); +}; + +function performStageTasks(scheduler, stageHandlers, ecModel, payload, opt) { + opt = opt || {}; + var unfinished; + each$1(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; + var agentStubMap = overallTask.agentStubMap; + agentStubMap.each(function (stub) { + if (needSetDirty(opt, stub)) { + stub.dirty(); + overallNeedDirty = true; + } + }); + overallNeedDirty && overallTask.dirty(); + updatePayload(overallTask, payload); + var performArgs = 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); + }); + unfinished |= overallTask.perform(performArgs); + } else if (seriesTaskMap) { + seriesTaskMap.each(function (task, pipelineId) { + if (needSetDirty(opt, task)) { + task.dirty(); + } + + var performArgs = scheduler.getPerformArgs(task, opt.block); + performArgs.skip = !stageHandler.performRawSeries && ecModel.isSeriesFiltered(task.context.model); + updatePayload(task, payload); + unfinished |= task.perform(performArgs); + }); + } + }); + + function needSetDirty(opt, task) { + return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id)); + } + + scheduler.unfinished |= unfinished; +} + +proto.performSeriesTasks = function (ecModel) { + var unfinished; + ecModel.eachSeries(function (seriesModel) { + // Progress to the end for dataInit and dataRestore. + unfinished |= seriesModel.dataTask.perform(); + }); + this.unfinished |= unfinished; +}; + +proto.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); + }); +}; + +var updatePayload = proto.updatePayload = function (task, payload) { + payload !== 'remain' && (task.context.payload = payload); +}; + +function createSeriesStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) { + var seriesTaskMap = stageHandlerRecord.seriesTaskMap || (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 = seriesTaskMap.get(pipelineId) || seriesTaskMap.set(pipelineId, createTask({ + plan: seriesTaskPlan, + reset: seriesTaskReset, + count: seriesTaskCount + })); + task.context = { + model: seriesModel, + ecModel: ecModel, + api: api, + useClearVisual: stageHandler.isVisual && !stageHandler.isLayout, + plan: stageHandler.plan, + reset: stageHandler.reset, + scheduler: scheduler + }; + pipe(scheduler, seriesModel, task); + } // Clear unused series tasks. + + + var pipelineMap = scheduler._pipelineMap; + seriesTaskMap.each(function (task, pipelineId) { + if (!pipelineMap.get(pipelineId)) { + task.dispose(); + seriesTaskMap.removeKey(pipelineId); + } + }); +} + +function createOverallStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) { + 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 + }; // Reuse orignal stubs. + + var agentStubMap = overallTask.agentStubMap = overallTask.agentStubMap || createHashMap(); + var seriesType = stageHandler.seriesType; + var getTargetSeries = stageHandler.getTargetSeries; + var overallProgress = true; + var 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. + + 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$1(ecModel.getSeries(), createStub); + } + + function createStub(seriesModel) { + var pipelineId = seriesModel.uid; + var stub = agentStubMap.get(pipelineId); + + if (!stub) { + stub = agentStubMap.set(pipelineId, createTask({ + reset: stubReset, + onDirty: stubOnDirty + })); // When the result of `getTargetSeries` changed, the overallTask + // should be set as dirty and re-performed. + + overallTask.dirty(); + } + + stub.context = { + model: seriesModel, + overallProgress: overallProgress, + modifyOutputEnd: modifyOutputEnd + }; + stub.agent = overallTask; + stub.__block = overallProgress; + pipe(scheduler, seriesModel, stub); + } // Clear unused stubs. + + + var pipelineMap = scheduler._pipelineMap; + agentStubMap.each(function (stub, pipelineId) { + if (!pipelineMap.get(pipelineId)) { + stub.dispose(); // When the result of `getTargetSeries` changed, the overallTask + // should be set as dirty and re-performed. + + overallTask.dirty(); + agentStubMap.removeKey(pipelineId); + } + }); +} + +function overallTaskReset(context) { + context.overallReset(context.ecModel, context.api, context.payload); +} + +function stubReset(context, upstreamContext) { + 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); +} + +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(); +} + +function pipe(scheduler, seriesModel, task) { + var pipelineId = seriesModel.uid; + + var pipeline = scheduler._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$1(stageHandler)) { + stageHandler = { + overallReset: stageHandler, + seriesType: detectSeriseType(stageHandler) + }; + } + + stageHandler.uid = getUID('stageHandler'); + visualType && (stageHandler.visualType = visualType); + return stageHandler; +}; +/** + * 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 in Clz.prototype) { + // Do not use hasOwnProperty + target[name] = 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. +*/ +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. +*/ +var contrastColor = '#eee'; + +var axisCommon = function () { + return { + axisLine: { + lineStyle: { + color: contrastColor + } + }, + axisTick: { + lineStyle: { + color: contrastColor + } + }, + axisLabel: { + textStyle: { + color: contrastColor + } + }, + splitLine: { + lineStyle: { + type: 'dashed', + color: '#aaa' + } + }, + splitArea: { + areaStyle: { + color: contrastColor + } + } + }; +}; + +var colorPalette = ['#dd6b66', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53', '#eedd78', '#73a373', '#73b9bc', '#7289ab', '#91ca8c', '#f49f42']; +var theme = { + color: colorPalette, + backgroundColor: '#333', + tooltip: { + axisPointer: { + lineStyle: { + color: contrastColor + }, + crossStyle: { + color: contrastColor + } + } + }, + legend: { + textStyle: { + color: contrastColor + } + }, + textStyle: { + color: contrastColor + }, + title: { + textStyle: { + color: contrastColor + } + }, + toolbox: { + iconStyle: { + normal: { + borderColor: contrastColor + } + } + }, + dataZoom: { + textStyle: { + color: contrastColor + } + }, + visualMap: { + textStyle: { + color: contrastColor + } + }, + timeline: { + lineStyle: { + color: contrastColor + }, + itemStyle: { + normal: { + color: colorPalette[1] + } + }, + label: { + normal: { + textStyle: { + color: contrastColor + } + } + }, + controlStyle: { + normal: { + color: contrastColor, + borderColor: contrastColor + } + } + }, + timeAxis: axisCommon(), + logAxis: axisCommon(), + valueAxis: axisCommon(), + categoryAxis: axisCommon(), + line: { + symbol: 'circle' + }, + graph: { + color: colorPalette + }, + gauge: { + title: { + textStyle: { + color: contrastColor + } + } + }, + candlestick: { + itemStyle: { + normal: { + color: '#FD1050', + color0: '#0CF49B', + borderColor: '#FD1050', + borderColor0: '#0CF49B' + } + } + } +}; +theme.categoryAxis.splitLine.show = false; + +/* +* 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. +*/ + +/** + * This module is imported by echarts directly. + * + * Notice: + * Always keep this file exists for backward compatibility. + * Because before 4.1.0, dataset is an optional component, + * some users may import this module manually. + */ +ComponentModel.extend({ + type: 'dataset', + + /** + * @protected + */ + defaultOption: { + // 'row', 'column' + seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN, + // null/'auto': auto detect header, see "module:echarts/data/helper/sourceHelper" + sourceHeader: null, + dimensions: null, + source: null + }, + optionUpdated: function () { + detectSourceFormat(this); + } +}); +Component$1.extend({ + type: 'dataset' +}); + +/** + * 椭圆形状 + * @module zrender/graphic/shape/Ellipse + */ +var Ellipse = Path.extend({ + type: 'ellipse', + shape: { + cx: 0, + cy: 0, + rx: 0, + ry: 0 + }, + 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(); + } +}); + +// import Pattern from '../graphic/Pattern'; + +var DILIMITER_REG = /[\s,]+/; +/** + * For big svg string, this method might be time consuming. + * + * @param {string} svg xml string + * @return {Object} xml root. + */ + +function parseXML(svg) { + if (isString(svg)) { + var parser = new DOMParser(); + svg = parser.parseFromString(svg, 'text/xml'); + } // Document node. If using $.get, doc node may be input. + + + if (svg.nodeType === 9) { + svg = svg.firstChild; + } // nodeName of is also 'svg'. + + + while (svg.nodeName.toLowerCase() !== 'svg' || svg.nodeType !== 1) { + svg = svg.nextSibling; + } + + return svg; +} + +function SVGParser() { + this._defs = {}; + this._root = null; + this._isDefine = false; + this._isText = false; +} + +SVGParser.prototype.parse = function (xml, opt) { + opt = opt || {}; + var svg = parseXML(xml); + + if (!svg) { + throw new Error('Illegal svg'); + } + + var root = new Group(); + this._root = root; // parse view port + + var viewBox = svg.getAttribute('viewBox') || ''; // If width/height not specified, means "100%" of `opt.width/height`. + // TODO: Other percent value not supported yet. + + var width = parseFloat(svg.getAttribute('width') || opt.width); + var height = parseFloat(svg.getAttribute('height') || opt.height); // If width/height not specified, set as null for output. + + isNaN(width) && (width = null); + isNaN(height) && (height = null); // Apply inline style on svg element. + + parseAttributes(svg, root, null, true); + var child = svg.firstChild; + + while (child) { + this._parseNode(child, root); + + child = child.nextSibling; + } + + var viewBoxRect; + var viewBoxTransform; + + if (viewBox) { + var viewBoxArr = trim(viewBox).split(DILIMITER_REG); // Some invalid case like viewBox: 'none'. + + 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, width, height); + + if (!opt.ignoreViewBox) { + // If set transform on the output group, it probably bring trouble when + // some users only intend to show the clipped content inside the viewBox, + // but not intend to transform the output group. So we keep the output + // group no transform. If the user intend to use the viewBox as a + // camera, just set `opt.ignoreViewBox` as `true` and set transfrom + // manually according to the viewBox info in the output of this method. + var elRoot = root; + root = new Group(); + root.add(elRoot); + elRoot.scale = viewBoxTransform.scale.slice(); + elRoot.position = viewBoxTransform.position.slice(); + } + } // Some shapes might be overflow the viewport, which should be + // clipped despite whether the viewBox is used, as the SVG does. + + + if (!opt.ignoreRootClip && width != null && height != null) { + root.setClipPath(new Rect({ + shape: { + x: 0, + y: 0, + width: width, + height: height + } + })); + } // Set width/height on group just for output the viewport size. + + + return { + root: root, + width: width, + height: height, + viewBoxRect: viewBoxRect, + viewBoxTransform: viewBoxTransform + }; +}; + +SVGParser.prototype._parseNode = function (xmlNode, parentGroup) { + var nodeName = xmlNode.nodeName.toLowerCase(); // TODO + // support in svg, where nodeName is 'style', + // CSS classes is defined globally wherever the style tags are declared. + + if (nodeName === 'defs') { + // define flag + this._isDefine = true; + } else if (nodeName === 'text') { + this._isText = true; + } + + var el; + + if (this._isDefine) { + var parser = defineParsers[nodeName]; + + if (parser) { + var def = parser.call(this, xmlNode); + var id = xmlNode.getAttribute('id'); + + if (id) { + this._defs[id] = def; + } + } + } else { + var parser = nodeParsers[nodeName]; + + if (parser) { + el = parser.call(this, xmlNode, parentGroup); + parentGroup.add(el); + } + } + + var child = xmlNode.firstChild; + + while (child) { + if (child.nodeType === 1) { + this._parseNode(child, el); + } // Is text + + + if (child.nodeType === 3 && this._isText) { + this._parseText(child, el); + } + + child = child.nextSibling; + } // Quit define + + + if (nodeName === 'defs') { + this._isDefine = false; + } else if (nodeName === 'text') { + this._isText = false; + } +}; + +SVGParser.prototype._parseText = function (xmlNode, parentGroup) { + if (xmlNode.nodeType === 1) { + var dx = xmlNode.getAttribute('dx') || 0; + var dy = xmlNode.getAttribute('dy') || 0; + this._textX += parseFloat(dx); + this._textY += parseFloat(dy); + } + + var text = new Text({ + style: { + text: xmlNode.textContent, + transformText: true + }, + position: [this._textX || 0, this._textY || 0] + }); + inheritStyle(parentGroup, text); + parseAttributes(xmlNode, text, this._defs); + var fontSize = text.style.fontSize; + + if (fontSize && fontSize < 9) { + // PENDING + text.style.fontSize = 9; + text.scale = text.scale || [1, 1]; + text.scale[0] *= fontSize / 9; + text.scale[1] *= fontSize / 9; + } + + var rect = text.getBoundingRect(); + this._textX += rect.width; + parentGroup.add(text); + return text; +}; + +var nodeParsers = { + 'g': function (xmlNode, parentGroup) { + var g = new Group(); + inheritStyle(parentGroup, g); + parseAttributes(xmlNode, g, this._defs); + return g; + }, + 'rect': function (xmlNode, parentGroup) { + var rect = new Rect(); + inheritStyle(parentGroup, rect); + parseAttributes(xmlNode, rect, this._defs); + 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) + }); // console.log(xmlNode.getAttribute('transform')); + // console.log(rect.transform); + + return rect; + }, + 'circle': function (xmlNode, parentGroup) { + var circle = new Circle(); + inheritStyle(parentGroup, circle); + parseAttributes(xmlNode, circle, this._defs); + circle.setShape({ + cx: parseFloat(xmlNode.getAttribute('cx') || 0), + cy: parseFloat(xmlNode.getAttribute('cy') || 0), + r: parseFloat(xmlNode.getAttribute('r') || 0) + }); + return circle; + }, + 'line': function (xmlNode, parentGroup) { + var line = new Line(); + inheritStyle(parentGroup, line); + parseAttributes(xmlNode, line, this._defs); + 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) + }); + return line; + }, + 'ellipse': function (xmlNode, parentGroup) { + var ellipse = new Ellipse(); + inheritStyle(parentGroup, ellipse); + parseAttributes(xmlNode, ellipse, this._defs); + 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) + }); + return ellipse; + }, + 'polygon': function (xmlNode, parentGroup) { + var points = xmlNode.getAttribute('points'); + + if (points) { + points = parsePoints(points); + } + + var polygon = new Polygon({ + shape: { + points: points || [] + } + }); + inheritStyle(parentGroup, polygon); + parseAttributes(xmlNode, polygon, this._defs); + return polygon; + }, + 'polyline': function (xmlNode, parentGroup) { + var path = new Path(); + inheritStyle(parentGroup, path); + parseAttributes(xmlNode, path, this._defs); + var points = xmlNode.getAttribute('points'); + + if (points) { + points = parsePoints(points); + } + + var polyline = new Polyline({ + shape: { + points: points || [] + } + }); + return polyline; + }, + 'image': function (xmlNode, parentGroup) { + var img = new ZImage(); + inheritStyle(parentGroup, img); + parseAttributes(xmlNode, img, this._defs); + img.setStyle({ + image: xmlNode.getAttribute('xlink:href'), + x: xmlNode.getAttribute('x'), + y: xmlNode.getAttribute('y'), + width: xmlNode.getAttribute('width'), + height: xmlNode.getAttribute('height') + }); + 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._defs); + return g; + }, + 'tspan': function (xmlNode, parentGroup) { + var x = xmlNode.getAttribute('x'); + var y = xmlNode.getAttribute('y'); + + if (x != null) { + // new offset x + this._textX = parseFloat(x); + } + + if (y != null) { + // new offset y + 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._defs); + this._textX += dx; + this._textY += dy; + return g; + }, + 'path': function (xmlNode, parentGroup) { + // TODO svg fill rule + // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule + // path.style.globalCompositeOperation = 'xor'; + var d = xmlNode.getAttribute('d') || ''; // Performance sensitive. + + var path = createFromString(d); + inheritStyle(parentGroup, path); + parseAttributes(xmlNode, path, this._defs); + return path; + } +}; +var defineParsers = { + '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); + + _parseGradientColorStops(xmlNode, gradient); + + return gradient; + }, + 'radialgradient': function (xmlNode) {} +}; + +function _parseGradientColorStops(xmlNode, gradient) { + var stop = xmlNode.firstChild; + + while (stop) { + if (stop.nodeType === 1) { + var offset = stop.getAttribute('offset'); + + if (offset.indexOf('%') > 0) { + // percentage + offset = parseInt(offset, 10) / 100; + } else if (offset) { + // number from 0 to 1 + offset = parseFloat(offset); + } else { + offset = 0; + } + + var stopColor = stop.getAttribute('stop-color') || '#000000'; + gradient.addColorStop(offset, 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 = trim(pointsString).split(DILIMITER_REG); + 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; +} + +var attributesMap = { + '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-align': 'textAlign', + 'alignment-baseline': 'textBaseline' +}; + +function parseAttributes(xmlNode, el, defs, onlyInlineStyle) { + var zrStyle = el.__inheritedStyle || {}; + var isTextEl = el.type === 'text'; // TODO Shadow + + if (xmlNode.nodeType === 1) { + parseTransformAttribute(xmlNode, el); + extend(zrStyle, parseStyleAttribute(xmlNode)); + + if (!onlyInlineStyle) { + for (var svgAttrName in attributesMap) { + if (attributesMap.hasOwnProperty(svgAttrName)) { + var attrValue = xmlNode.getAttribute(svgAttrName); + + if (attrValue != null) { + zrStyle[attributesMap[svgAttrName]] = attrValue; + } + } + } + } + } + + var elFillProp = isTextEl ? 'textFill' : 'fill'; + var elStrokeProp = isTextEl ? 'textStroke' : 'stroke'; + el.style = el.style || new Style(); + var elStyle = el.style; + zrStyle.fill != null && elStyle.set(elFillProp, getPaint(zrStyle.fill, defs)); + zrStyle.stroke != null && elStyle.set(elStrokeProp, getPaint(zrStyle.stroke, defs)); + each$1(['lineWidth', 'opacity', 'fillOpacity', 'strokeOpacity', 'miterLimit', 'fontSize'], function (propName) { + var elPropName = propName === 'lineWidth' && isTextEl ? 'textStrokeWidth' : propName; + zrStyle[propName] != null && elStyle.set(elPropName, parseFloat(zrStyle[propName])); + }); + + if (!zrStyle.textBaseline || zrStyle.textBaseline === 'auto') { + zrStyle.textBaseline = 'alphabetic'; + } + + if (zrStyle.textBaseline === 'alphabetic') { + zrStyle.textBaseline = 'bottom'; + } + + if (zrStyle.textAlign === 'start') { + zrStyle.textAlign = 'left'; + } + + if (zrStyle.textAlign === 'end') { + zrStyle.textAlign = 'right'; + } + + each$1(['lineDashOffset', 'lineCap', 'lineJoin', 'fontWeight', 'fontFamily', 'fontStyle', 'textAlign', 'textBaseline'], function (propName) { + zrStyle[propName] != null && elStyle.set(propName, zrStyle[propName]); + }); + + if (zrStyle.lineDash) { + el.style.lineDash = trim(zrStyle.lineDash).split(DILIMITER_REG); + } + + if (elStyle[elStrokeProp] && elStyle[elStrokeProp] !== 'none') { + // enable stroke + el[elStrokeProp] = true; + } + + el.__inheritedStyle = zrStyle; +} + +var urlRegex = /url\(\s*#(.*?)\)/; + +function getPaint(str, defs) { + // if (str === 'none') { + // return; + // } + var urlMatch = defs && str && str.match(urlRegex); + + if (urlMatch) { + var url = trim(urlMatch[1]); + var def = defs[url]; + return def; + } + + return str; +} + +var transformRegex = /(translate|scale|rotate|skewX|skewY|matrix)\(([\-\s0-9\.e,]*)\)/g; + +function parseTransformAttribute(xmlNode, node) { + var transform = xmlNode.getAttribute('transform'); + + if (transform) { + transform = transform.replace(/,/g, ' '); + var m = null; + var transformOps = []; + transform.replace(transformRegex, function (str, type, value) { + transformOps.push(type, value); + }); + + for (var i = transformOps.length - 1; i > 0; i -= 2) { + var value = transformOps[i]; + var type = transformOps[i - 1]; + m = m || create$1(); + + switch (type) { + case 'translate': + value = trim(value).split(DILIMITER_REG); + translate(m, m, [parseFloat(value[0]), parseFloat(value[1] || 0)]); + break; + + case 'scale': + value = trim(value).split(DILIMITER_REG); + scale$1(m, m, [parseFloat(value[0]), parseFloat(value[1] || value[0])]); + break; + + case 'rotate': + value = trim(value).split(DILIMITER_REG); + rotate(m, m, parseFloat(value[0])); + break; + + case 'skew': + value = trim(value).split(DILIMITER_REG); + console.warn('Skew transform is not supported yet'); + break; + + case 'matrix': + var value = trim(value).split(DILIMITER_REG); + m[0] = parseFloat(value[0]); + m[1] = parseFloat(value[1]); + m[2] = parseFloat(value[2]); + m[3] = parseFloat(value[3]); + m[4] = parseFloat(value[4]); + m[5] = parseFloat(value[5]); + break; + } + } + + node.setLocalTransform(m); + } +} // Value may contain space. + + +var styleRegex = /([^\s:;]+)\s*:\s*([^:;]+)/g; + +function parseStyleAttribute(xmlNode) { + var style = xmlNode.getAttribute('style'); + var result = {}; + + if (!style) { + return result; + } + + var styleList = {}; + styleRegex.lastIndex = 0; + var styleRegResult; + + while ((styleRegResult = styleRegex.exec(style)) != null) { + styleList[styleRegResult[1]] = styleRegResult[2]; + } + + for (var svgAttrName in attributesMap) { + if (attributesMap.hasOwnProperty(svgAttrName) && styleList[svgAttrName] != null) { + result[attributesMap[svgAttrName]] = styleList[svgAttrName]; + } + } + + return result; +} +/** + * @param {Array.} viewBoxRect + * @param {number} width + * @param {number} height + * @return {Object} {scale, position} + */ + + +function makeViewBoxTransform(viewBoxRect, width, height) { + var scaleX = width / viewBoxRect.width; + var scaleY = height / viewBoxRect.height; + var scale = Math.min(scaleX, scaleY); // preserveAspectRatio 'xMidYMid' + + var viewBoxScale = [scale, scale]; + var viewBoxPosition = [-(viewBoxRect.x + viewBoxRect.width / 2) * scale + width / 2, -(viewBoxRect.y + viewBoxRect.height / 2) * scale + height / 2]; + return { + scale: viewBoxScale, + position: viewBoxPosition + }; +} +/** + * @param {string|XMLElement} xml + * @param {Object} [opt] + * @param {number} [opt.width] Default width if svg width not specified or is a percent value. + * @param {number} [opt.height] Default height if svg height not specified or is a percent value. + * @param {boolean} [opt.ignoreViewBox] + * @param {boolean} [opt.ignoreRootClip] + * @return {Object} result: + * { + * root: Group, The root of the the result tree of zrender shapes, + * width: number, the viewport width of the SVG, + * height: number, the viewport height of the SVG, + * viewBoxRect: {x, y, width, height}, the declared viewBox rect of the SVG, if exists, + * viewBoxTransform: the {scale, position} calculated by viewBox and viewport, is exists. + * } + */ + +/* +* 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 storage = createHashMap(); // For minimize the code size of common echarts package, +// do not put too much logic in this module. + +var mapDataStorage = { + // The format of record: see `echarts.registerMap`. + // Compatible with previous `echarts.registerMap`. + registerMap: function (mapName, rawGeoJson, rawSpecialAreas) { + var records; + + if (isArray(rawGeoJson)) { + records = rawGeoJson; + } else if (rawGeoJson.svg) { + records = [{ + type: 'svg', + source: rawGeoJson.svg, + specialAreas: rawGeoJson.specialAreas + }]; + } else { + // Backward compatibility. + if (rawGeoJson.geoJson && !rawGeoJson.features) { + rawSpecialAreas = rawGeoJson.specialAreas; + rawGeoJson = rawGeoJson.geoJson; + } + + records = [{ + type: 'geoJSON', + source: rawGeoJson, + specialAreas: rawSpecialAreas + }]; + } + + each$1(records, function (record) { + var type = record.type; + type === 'geoJson' && (type = record.type = 'geoJSON'); + var parse = parsers[type]; + parse(record); + }); + return storage.set(mapName, records); + }, + retrieveMap: function (mapName) { + return storage.get(mapName); + } +}; +var parsers = { + geoJSON: function (record) { + var source = record.source; + record.geoJSON = !isString(source) ? source : typeof JSON !== 'undefined' && JSON.parse ? JSON.parse(source) : new Function('return (' + source + ');')(); + }, + // 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. + svg: function (record) { + record.svgXML = parseXML(record.source); + } +}; + +/* +* 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 assert = assert$1; +var each = each$1; +var isFunction = isFunction$1; +var isObject = isObject$1; +var parseClassType = ComponentModel.parseClassType; +var version = '4.5.0'; +var dependencies = { + zrender: '4.1.2' +}; +var TEST_FRAME_REMAIN_TIME = 1; +var PRIORITY_PROCESSOR_FILTER = 1000; +var PRIORITY_PROCESSOR_SERIES_FILTER = 800; +var PRIORITY_PROCESSOR_DATASTACK = 900; +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_POST_CHART_LAYOUT = 3500; +var PRIORITY_VISUAL_COMPONENT = 4000; // FIXME +// necessary? + +var PRIORITY_VISUAL_BRUSH = 5000; +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 + } +}; // 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 = '__flagInMainProcess'; +var OPTION_UPDATED = '__optionUpdated'; +var ACTION_REG = /^[a-zA-Z0-9_]+$/; + +function createRegisterEventWithLowercaseName(method, ignoreDisposed) { + return function (eventName, handler, context) { + if (!ignoreDisposed && this._disposed) { + return; + } // Event name is all lowercase + + + eventName = eventName && eventName.toLowerCase(); + Eventful.prototype[method].call(this, eventName, handler, context); + }; +} +/** + * @module echarts~MessageCenter + */ + + +function MessageCenter() { + Eventful.call(this); +} + +MessageCenter.prototype.on = createRegisterEventWithLowercaseName('on', true); +MessageCenter.prototype.off = createRegisterEventWithLowercaseName('off', true); +MessageCenter.prototype.one = createRegisterEventWithLowercaseName('one', true); +mixin(MessageCenter, Eventful); +/** + * @module echarts~ECharts + */ + +function ECharts(dom, theme$$1, opts) { + opts = opts || {}; // Get theme by name + + if (typeof theme$$1 === 'string') { + theme$$1 = themeStorage[theme$$1]; + } + /** + * @type {string} + */ + + + this.id; + /** + * Group id + * @type {string} + */ + + this.group; + /** + * @type {HTMLElement} + * @private + */ + + this._dom = dom; + var defaultRenderer = 'canvas'; + + /** + * @type {module:zrender/ZRender} + * @private + */ + var zr = this._zr = init$1(dom, { + renderer: opts.renderer || defaultRenderer, + devicePixelRatio: opts.devicePixelRatio, + width: opts.width, + height: opts.height + }); + /** + * Expect 60 fps. + * @type {Function} + * @private + */ + + this._throttledZrFlush = throttle(bind(zr.flush, zr), 17); + var theme$$1 = clone(theme$$1); + theme$$1 && backwardCompat(theme$$1, true); + /** + * @type {Object} + * @private + */ + + this._theme = theme$$1; + /** + * @type {Array.} + * @private + */ + + this._chartsViews = []; + /** + * @type {Object.} + * @private + */ + + this._chartsMap = {}; + /** + * @type {Array.} + * @private + */ + + this._componentsViews = []; + /** + * @type {Object.} + * @private + */ + + this._componentsMap = {}; + /** + * @type {module:echarts/CoordinateSystem} + * @private + */ + + this._coordSysMgr = new CoordinateSystemManager(); + /** + * @type {module:echarts/ExtensionAPI} + * @private + */ + + var api = this._api = createExtensionAPI(this); // Sort on demand + + function prioritySortFunc(a, b) { + return a.__prio - b.__prio; + } + + sort(visualFuncs, prioritySortFunc); + sort(dataProcessorFuncs, prioritySortFunc); + /** + * @type {module:echarts/stream/Scheduler} + */ + + this._scheduler = new Scheduler(this, api, dataProcessorFuncs, visualFuncs); + Eventful.call(this, this._ecEventProcessor = new EventProcessor()); + /** + * @type {module:echarts~MessageCenter} + * @private + */ + + this._messageCenter = new MessageCenter(); // Init mouse events + + this._initEvents(); // In case some people write `window.onresize = chart.resize` + + + this.resize = bind(this.resize, this); // Can't dispatch action during rendering procedure + + this._pendingActions = []; + zr.animation.on('frame', this._onframe, this); + bindRenderedEvent(zr, this); // ECharts instance can be used as value. + + setAsPrimitive(this); +} + +var echartsProto = ECharts.prototype; + +echartsProto._onframe = function () { + if (this._disposed) { + return; + } + + var scheduler = this._scheduler; // Lazy update + + if (this[OPTION_UPDATED]) { + var silent = this[OPTION_UPDATED].silent; + this[IN_MAIN_PROCESS] = true; + prepare(this); + updateMethods.update.call(this); + this[IN_MAIN_PROCESS] = false; + this[OPTION_UPDATED] = false; + 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. + + } +}; +/** + * @return {HTMLElement} + */ + + +echartsProto.getDom = function () { + return this._dom; +}; +/** + * @return {module:zrender~ZRender} + */ + + +echartsProto.getZr = function () { + return this._zr; +}; +/** + * Usage: + * chart.setOption(option, notMerge, lazyUpdate); + * chart.setOption(option, { + * notMerge: ..., + * lazyUpdate: ..., + * silent: ... + * }); + * + * @param {Object} option + * @param {Object|boolean} [opts] opts or notMerge. + * @param {boolean} [opts.notMerge=false] + * @param {boolean} [opts.lazyUpdate=false] Useful when setOption frequently. + */ + + +echartsProto.setOption = function (option, notMerge, lazyUpdate) { + if (this._disposed) { + return; + } + + var silent; + + if (isObject(notMerge)) { + lazyUpdate = notMerge.lazyUpdate; + silent = notMerge.silent; + notMerge = notMerge.notMerge; + } + + this[IN_MAIN_PROCESS] = true; + + if (!this._model || notMerge) { + var optionManager = new OptionManager(this._api); + var theme$$1 = this._theme; + var ecModel = this._model = new GlobalModel(); + ecModel.scheduler = this._scheduler; + ecModel.init(null, null, theme$$1, optionManager); + } + + this._model.setOption(option, optionPreprocessorFuncs); + + if (lazyUpdate) { + this[OPTION_UPDATED] = { + silent: silent + }; + this[IN_MAIN_PROCESS] = false; + } else { + prepare(this); + updateMethods.update.call(this); // Ensure zr refresh sychronously, and then pixel in canvas can be + // fetched after `setOption`. + + this._zr.flush(); + + this[OPTION_UPDATED] = false; + this[IN_MAIN_PROCESS] = false; + flushPendingActions.call(this, silent); + triggerUpdatedEvent.call(this, silent); + } +}; +/** + * @DEPRECATED + */ + + +echartsProto.setTheme = function () { + console.error('ECharts#setTheme() is DEPRECATED in ECharts 3.0'); +}; +/** + * @return {module:echarts/model/Global} + */ + + +echartsProto.getModel = function () { + return this._model; +}; +/** + * @return {Object} + */ + + +echartsProto.getOption = function () { + return this._model && this._model.getOption(); +}; +/** + * @return {number} + */ + + +echartsProto.getWidth = function () { + return this._zr.getWidth(); +}; +/** + * @return {number} + */ + + +echartsProto.getHeight = function () { + return this._zr.getHeight(); +}; +/** + * @return {number} + */ + + +echartsProto.getDevicePixelRatio = function () { + return this._zr.painter.dpr || window.devicePixelRatio || 1; +}; +/** + * Get canvas which has all thing rendered + * @param {Object} opts + * @param {string} [opts.backgroundColor] + * @return {string} + */ + + +echartsProto.getRenderedCanvas = function (opts) { + if (!env$1.canvasSupported) { + return; + } + + opts = opts || {}; + opts.pixelRatio = opts.pixelRatio || 1; + opts.backgroundColor = opts.backgroundColor || this._model.get('backgroundColor'); + var zr = this._zr; // var list = zr.storage.getDisplayList(); + // Stop animations + // Never works before in init animation, so remove it. + // zrUtil.each(list, function (el) { + // el.stopAnimation(true); + // }); + + return zr.painter.getRenderedCanvas(opts); +}; +/** + * Get svg data url + * @return {string} + */ + + +echartsProto.getSvgDataUrl = function () { + if (!env$1.svgSupported) { + return; + } + + var zr = this._zr; + var list = zr.storage.getDisplayList(); // Stop animations + + each$1(list, function (el) { + el.stopAnimation(true); + }); + return zr.painter.pathToDataUrl(); +}; +/** + * @return {string} + * @param {Object} opts + * @param {string} [opts.type='png'] + * @param {string} [opts.pixelRatio=1] + * @param {string} [opts.backgroundColor] + * @param {string} [opts.excludeComponents] + */ + + +echartsProto.getDataURL = function (opts) { + if (this._disposed) { + 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.getRenderedCanvas(opts).toDataURL('image/' + (opts && opts.type || 'png')); + each(excludesComponentViews, function (view) { + view.group.ignore = false; + }); + return url; +}; +/** + * @return {string} + * @param {Object} opts + * @param {string} [opts.type='png'] + * @param {string} [opts.pixelRatio=1] + * @param {string} [opts.backgroundColor] + */ + + +echartsProto.getConnectedDataURL = function (opts) { + if (this._disposed) { + return; + } + + if (!env$1.canvasSupported) { + return; + } + + var groupId = this.group; + var mathMin = Math.min; + var mathMax = Math.max; + var MAX_NUMBER = Infinity; + + if (connectedGroups[groupId]) { + var left = MAX_NUMBER; + var top = MAX_NUMBER; + var right = -MAX_NUMBER; + var bottom = -MAX_NUMBER; + var canvasList = []; + var dpr = opts && opts.pixelRatio || 1; + each$1(instances, function (chart, id) { + if (chart.group === groupId) { + var canvas = chart.getRenderedCanvas(clone(opts)); + var boundingRect = chart.getDom().getBoundingClientRect(); + left = mathMin(boundingRect.left, left); + top = mathMin(boundingRect.top, top); + right = mathMax(boundingRect.right, right); + bottom = mathMax(boundingRect.bottom, bottom); + canvasList.push({ + dom: canvas, + left: boundingRect.left, + top: boundingRect.top + }); + } + }); + left *= dpr; + top *= dpr; + right *= dpr; + bottom *= dpr; + var width = right - left; + var height = bottom - top; + var targetCanvas = createCanvas(); + targetCanvas.width = width; + targetCanvas.height = height; + var zr = init$1(targetCanvas); // Background between the charts + + if (opts.connectedBackgroundColor) { + zr.add(new Rect({ + shape: { + x: 0, + y: 0, + width: width, + height: height + }, + style: { + fill: opts.connectedBackgroundColor + } + })); + } + + each(canvasList, function (item) { + var img = new ZImage({ + style: { + x: item.left * dpr - left, + y: item.top * dpr - top, + image: item.dom + } + }); + zr.add(img); + }); + zr.refreshImmediately(); + return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png')); + } else { + return this.getDataURL(opts); + } +}; +/** + * Convert from logical coordinate system to pixel coordinate system. + * See CoordinateSystem#convertToPixel. + * @param {string|Object} finder + * If string, e.g., 'geo', means {geoIndex: 0}. + * If Object, could contain some of these properties below: + * { + * seriesIndex / seriesId / seriesName, + * geoIndex / geoId, geoName, + * bmapIndex / bmapId / bmapName, + * xAxisIndex / xAxisId / xAxisName, + * yAxisIndex / yAxisId / yAxisName, + * gridIndex / gridId / gridName, + * ... (can be extended) + * } + * @param {Array|number} value + * @return {Array|number} result + */ + + +echartsProto.convertToPixel = curry(doConvertPixel, 'convertToPixel'); +/** + * Convert from pixel coordinate system to logical coordinate system. + * See CoordinateSystem#convertFromPixel. + * @param {string|Object} finder + * If string, e.g., 'geo', means {geoIndex: 0}. + * If Object, could contain some of these properties below: + * { + * seriesIndex / seriesId / seriesName, + * geoIndex / geoId / geoName, + * bmapIndex / bmapId / bmapName, + * xAxisIndex / xAxisId / xAxisName, + * yAxisIndex / yAxisId / yAxisName + * gridIndex / gridId / gridName, + * ... (can be extended) + * } + * @param {Array|number} value + * @return {Array|number} result + */ + +echartsProto.convertFromPixel = curry(doConvertPixel, 'convertFromPixel'); + +function doConvertPixel(methodName, finder, value) { + if (this._disposed) { + return; + } + + var ecModel = this._model; + + var coordSysList = this._coordSysMgr.getCoordinateSystems(); + + var result; + finder = parseFinder(ecModel, finder); + + for (var i = 0; i < coordSysList.length; i++) { + var coordSys = coordSysList[i]; + + if (coordSys[methodName] && (result = coordSys[methodName](ecModel, finder, value)) != null) { + return result; + } + } +} +/** + * Is the specified coordinate systems or components contain the given pixel point. + * @param {string|Object} finder + * If string, e.g., 'geo', means {geoIndex: 0}. + * If Object, could contain some of these properties below: + * { + * seriesIndex / seriesId / seriesName, + * geoIndex / geoId / geoName, + * bmapIndex / bmapId / bmapName, + * xAxisIndex / xAxisId / xAxisName, + * yAxisIndex / yAxisId / yAxisName, + * gridIndex / gridId / gridName, + * ... (can be extended) + * } + * @param {Array|number} value + * @return {boolean} result + */ + + +echartsProto.containPixel = function (finder, value) { + if (this._disposed) { + return; + } + + var ecModel = this._model; + var result; + finder = parseFinder(ecModel, finder); + each$1(finder, function (models, key) { + key.indexOf('Models') >= 0 && each$1(models, function (model) { + var coordSys = model.coordinateSystem; + + if (coordSys && coordSys.containPoint) { + result |= !!coordSys.containPoint(value); + } else if (key === 'seriesModels') { + var view = this._chartsMap[model.__viewId]; + + if (view && view.containPoint) { + result |= view.containPoint(value, model); + } else {} + } else {} + }, this); + }, this); + return !!result; +}; +/** + * Get visual from series or data. + * @param {string|Object} 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 {string} visualType 'color', 'symbol', 'symbolSize' + */ + + +echartsProto.getVisual = function (finder, visualType) { + var ecModel = this._model; + finder = parseFinder(ecModel, finder, { + defaultMainType: 'series' + }); + var seriesModel = finder.seriesModel; + var data = seriesModel.getData(); + var dataIndexInside = finder.hasOwnProperty('dataIndexInside') ? finder.dataIndexInside : finder.hasOwnProperty('dataIndex') ? data.indexOfRawIndex(finder.dataIndex) : null; + return dataIndexInside != null ? data.getItemVisual(dataIndexInside, visualType) : data.getVisual(visualType); +}; +/** + * Get view of corresponding component model + * @param {module:echarts/model/Component} componentModel + * @return {module:echarts/view/Component} + */ + + +echartsProto.getViewOfComponentModel = function (componentModel) { + return this._componentsMap[componentModel.__viewId]; +}; +/** + * Get view of corresponding series model + * @param {module:echarts/model/Series} seriesModel + * @return {module:echarts/view/Chart} + */ + + +echartsProto.getViewOfSeriesModel = function (seriesModel) { + return this._chartsMap[seriesModel.__viewId]; +}; + +var updateMethods = { + prepareAndUpdate: function (payload) { + prepare(this); + updateMethods.update.call(this, payload); + }, + + /** + * @param {Object} payload + * @private + */ + update: function (payload) { + // console.profile && console.profile('update'); + 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; + } + + 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); // Set background + + var backgroundColor = ecModel.get('backgroundColor') || 'transparent'; // In IE8 + + if (!env$1.canvasSupported) { + var colorArr = parse(backgroundColor); + backgroundColor = stringify(colorArr, 'rgb'); + + if (colorArr[3] === 0) { + backgroundColor = 'transparent'; + } + } else { + zr.setBackgroundColor(backgroundColor); + } + + performPostUpdateFuncs(ecModel, api); // console.profile && console.profileEnd('update'); + }, + + /** + * @param {Object} payload + * @private + */ + updateTransform: function (payload) { + var ecModel = this._model; + var ecIns = this; + var api = this._api; // update before setOption + + if (!ecModel) { + return; + } // ChartView.markUpdateMethod(payload, 'updateTransform'); + + + var componentDirtyList = []; + ecModel.eachComponent(function (componentType, componentModel) { + var componentView = ecIns.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 = ecIns._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(ecIns, ecModel, api, payload, seriesDirtyMap); + performPostUpdateFuncs(ecModel, this._api); + }, + + /** + * @param {Object} payload + * @private + */ + updateView: function (payload) { + var ecModel = this._model; // update before setOption + + if (!ecModel) { + return; + } + + Chart.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, this._model, this._api, payload); + performPostUpdateFuncs(ecModel, this._api); + }, + + /** + * @param {Object} payload + * @private + */ + updateVisual: function (payload) { + updateMethods.update.call(this, payload); // var ecModel = this._model; + // // update before setOption + // if (!ecModel) { + // return; + // } + // 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}); + // render(this, this._model, this._api, payload); + // performPostUpdateFuncs(ecModel, this._api); + }, + + /** + * @param {Object} payload + * @private + */ + updateLayout: function (payload) { + updateMethods.update.call(this, payload); // var ecModel = this._model; + // // update before setOption + // if (!ecModel) { + // return; + // } + // ChartView.markUpdateMethod(payload, 'updateLayout'); + // // 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}); + // render(this, this._model, this._api, payload); + // performPostUpdateFuncs(ecModel, this._api); + } +}; + +function prepare(ecIns) { + var ecModel = ecIns._model; + var scheduler = ecIns._scheduler; + scheduler.restorePipelines(ecModel); + scheduler.prepareStageTasks(); + prepareView(ecIns, 'component', ecModel, scheduler); + prepareView(ecIns, 'chart', ecModel, scheduler); + scheduler.plan(); +} +/** + * @private + */ + + +function updateDirectly(ecIns, method, payload, mainType, subType) { + var ecModel = ecIns._model; // broadcast + + if (!mainType) { + // FIXME + // Chart will not be update directly here, except set dirty. + // But there is no such scenario now. + each(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; + + if (excludeSeriesId != null) { + excludeSeriesId = createHashMap(normalizeToArray(excludeSeriesId)); + } // If dispatchAction before setOption, do nothing. + + + ecModel && ecModel.eachComponent(condition, function (model) { + if (!excludeSeriesId || excludeSeriesId.get(model.id) == null) { + 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); + } +} +/** + * Resize the chart + * @param {Object} opts + * @param {number} [opts.width] Can be 'auto' (the same as null/undefined) + * @param {number} [opts.height] Can be 'auto' (the same as null/undefined) + * @param {boolean} [opts.silent=false] + */ + + +echartsProto.resize = function (opts) { + if (this._disposed) { + return; + } + + this._zr.resize(opts); + + var ecModel = this._model; // Resize loading effect + + this._loadingFX && this._loadingFX.resize(); + + if (!ecModel) { + return; + } + + var optionChanged = ecModel.resetOption('media'); + var silent = opts && opts.silent; + this[IN_MAIN_PROCESS] = true; + optionChanged && prepare(this); + updateMethods.update.call(this); + this[IN_MAIN_PROCESS] = false; + flushPendingActions.call(this, silent); + triggerUpdatedEvent.call(this, silent); +}; + +function updateStreamModes(ecIns, ecModel) { + var chartsMap = ecIns._chartsMap; + var scheduler = ecIns._scheduler; + ecModel.eachSeries(function (seriesModel) { + scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]); + }); +} +/** + * Show loading effect + * @param {string} [name='default'] + * @param {Object} [cfg] + */ + + +echartsProto.showLoading = function (name, cfg) { + if (this._disposed) { + return; + } + + if (isObject(name)) { + cfg = name; + name = ''; + } + + name = name || 'default'; + this.hideLoading(); + + if (!loadingEffects[name]) { + return; + } + + var el = loadingEffects[name](this._api, cfg); + var zr = this._zr; + this._loadingFX = el; + zr.add(el); +}; +/** + * Hide loading effect + */ + + +echartsProto.hideLoading = function () { + if (this._disposed) { + return; + } + + this._loadingFX && this._zr.remove(this._loadingFX); + this._loadingFX = null; +}; +/** + * @param {Object} eventObj + * @return {Object} + */ + + +echartsProto.makeActionFromEvent = function (eventObj) { + var payload = extend({}, eventObj); + payload.type = eventActionMap[eventObj.type]; + return payload; +}; +/** + * @pubilc + * @param {Object} payload + * @param {string} [payload.type] Action type + * @param {Object|boolean} [opt] If pass boolean, means opt.silent + * @param {boolean} [opt.silent=false] Whether trigger events. + * @param {boolean} [opt.flush=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. + */ + + +echartsProto.dispatchAction = function (payload, opt) { + if (this._disposed) { + 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]) { + this._pendingActions.push(payload); + + return; + } + + doDispatchAction.call(this, payload, opt.silent); + + if (opt.flush) { + this._zr.flush(true); + } else if (opt.flush !== false && env$1.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, opt.silent); + triggerUpdatedEvent.call(this, opt.silent); +}; + +function doDispatchAction(payload, silent) { + var payloadType = payload.type; + var escapeConnect = payload.escapeConnect; + var actionWrap = actions[payloadType]; + var actionInfo = actionWrap.actionInfo; + var cptType = (actionInfo.update || 'update').split(':'); + var updateMethod = cptType.pop(); + cptType = cptType[0] != null && parseClassType(cptType[0]); + this[IN_MAIN_PROCESS] = 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 isHighDown = payloadType === 'highlight' || payloadType === 'downplay'; + 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) { + // method, payload, mainType, subType + updateDirectly(this, updateMethod, batchItem, 'series'); + } else if (cptType) { + updateDirectly(this, updateMethod, batchItem, cptType.main, cptType.sub); + } + }, this); + + if (updateMethod !== 'none' && !isHighDown && !cptType) { + // Still dirty + if (this[OPTION_UPDATED]) { + // FIXME Pass payload ? + prepare(this); + updateMethods.update.call(this, payload); + this[OPTION_UPDATED] = false; + } else { + updateMethods[updateMethod].call(this, payload); + } + } // 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] = false; + !silent && this._messageCenter.trigger(eventObj.type, eventObj); +} + +function flushPendingActions(silent) { + var pendingActions = this._pendingActions; + + while (pendingActions.length) { + var payload = pendingActions.shift(); + doDispatchAction.call(this, payload, silent); + } +} + +function triggerUpdatedEvent(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. + */ + + +function bindRenderedEvent(zr, ecIns) { + zr.on('rendered', function () { + ecIns.trigger('rendered'); // 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[OPTION_UPDATED] && !ecIns._scheduler.unfinished && !ecIns._pendingActions.length) { + ecIns.trigger('finished'); + } + }); +} +/** + * @param {Object} params + * @param {number} params.seriesIndex + * @param {Array|TypedArray} params.data + */ + + +echartsProto.appendData = function (params) { + if (this._disposed) { + return; + } + + var seriesIndex = params.seriesIndex; + var ecModel = this.getModel(); + var seriesModel = ecModel.getSeriesByIndex(seriesIndex); + 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; +}; +/** + * Register event + * @method + */ + + +echartsProto.on = createRegisterEventWithLowercaseName('on', false); +echartsProto.off = createRegisterEventWithLowercaseName('off', false); +echartsProto.one = createRegisterEventWithLowercaseName('one', false); +/** + * Prepare view instances of charts and components + * @param {module:echarts/model/Global} ecModel + * @private + */ + +function prepareView(ecIns, type, ecModel, scheduler) { + var isComponent = type === 'component'; + 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) { + // Consider: id same and type changed. + var viewId = '_ec_' + model.id + '_' + model.type; + var view = viewMap[viewId]; + + if (!view) { + var classType = parseClassType(model.type); + var Clazz = isComponent ? Component$1.getClass(classType.main, classType.sub) : Chart.getClass(classType.sub); + 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); + delete viewMap[view.__id]; + view.__id = view.group.__ecComponentInfo = null; + } else { + i++; + } + } +} // /** +// * Encode visual infomation from data after data processing +// * +// * @param {module:echarts/model/Global} ecModel +// * @param {object} layout +// * @param {boolean} [layoutFilter] `true`: only layout, +// * `false`: only not layout, +// * `null`/`undefined`: all. +// * @param {string} taskBaseTag +// * @private +// */ +// function startVisualEncoding(ecIns, ecModel, api, payload, layoutFilter) { +// each(visualFuncs, function (visual, index) { +// var isLayout = visual.isLayout; +// if (layoutFilter == null +// || (layoutFilter === false && !isLayout) +// || (layoutFilter === true && isLayout) +// ) { +// visual.func(ecModel, api, payload); +// } +// }); +// } + + +function clearColorPalette(ecModel) { + ecModel.clearColorPalette(); + ecModel.eachSeries(function (seriesModel) { + seriesModel.clearColorPalette(); + }); +} + +function render(ecIns, ecModel, api, payload) { + renderComponents(ecIns, ecModel, api, payload); + each(ecIns._chartsViews, function (chart) { + chart.__alive = false; + }); + renderSeries(ecIns, ecModel, api, payload); // Remove groups of unrendered charts + + each(ecIns._chartsViews, function (chart) { + if (!chart.__alive) { + chart.remove(ecModel, api); + } + }); +} + +function renderComponents(ecIns, ecModel, api, payload, dirtyList) { + each(dirtyList || ecIns._componentsViews, function (componentView) { + var componentModel = componentView.__model; + componentView.render(componentModel, ecModel, api, payload); + updateZ(componentModel, componentView); + }); +} +/** + * Render each chart and component + * @private + */ + + +function renderSeries(ecIns, ecModel, api, payload, dirtyMap) { + // Render all charts + var scheduler = ecIns._scheduler; + var unfinished; + ecModel.eachSeries(function (seriesModel) { + var chartView = ecIns._chartsMap[seriesModel.__viewId]; + chartView.__alive = true; + var renderTask = chartView.renderTask; + scheduler.updatePayload(renderTask, payload); + + if (dirtyMap && dirtyMap.get(seriesModel.uid)) { + renderTask.dirty(); + } + + unfinished |= renderTask.perform(scheduler.getPerformArgs(renderTask)); + chartView.group.silent = !!seriesModel.get('silent'); + updateZ(seriesModel, chartView); + updateBlend(seriesModel, chartView); + }); + scheduler.unfinished |= unfinished; // If use hover layer + + updateHoverLayerStatus(ecIns, ecModel); // Add aria + + aria(ecIns._zr.dom, ecModel); +} + +function performPostUpdateFuncs(ecModel, api) { + each(postUpdateFuncs, function (func) { + func(ecModel, api); + }); +} + +var MOUSE_EVENT_NAMES = ['click', 'dblclick', 'mouseover', 'mouseout', 'mousemove', 'mousedown', 'mouseup', 'globalout', 'contextmenu']; +/** + * @private + */ + +echartsProto._initEvents = function () { + 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 if (el && el.dataIndex != null) { + var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex); + params = dataModel && dataModel.getDataParams(el.dataIndex, el.dataType, el) || {}; + } // If element has custom eventData of components + else if (el && el.eventData) { + params = extend({}, el.eventData); + } // 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]; + params.event = e; + params.type = eveName; + this._ecEventProcessor.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); + }, this); + each(eventActionMap, function (actionType, eventType) { + this._messageCenter.on(eventType, function (event) { + this.trigger(eventType, event); + }, this); + }, this); +}; +/** + * @return {boolean} + */ + + +echartsProto.isDisposed = function () { + return this._disposed; +}; +/** + * Clear + */ + + +echartsProto.clear = function () { + if (this._disposed) { + return; + } + + this.setOption({ + series: [] + }, true); +}; +/** + * Dispose instance + */ + + +echartsProto.dispose = function () { + if (this._disposed) { + return; + } + + this._disposed = true; + setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, ''); + var api = this._api; + var ecModel = this._model; + each(this._componentsViews, function (component) { + component.dispose(ecModel, api); + }); + each(this._chartsViews, function (chart) { + chart.dispose(ecModel, api); + }); // Dispose after all views disposed + + this._zr.dispose(); + + delete instances[this.id]; +}; + +mixin(ECharts, Eventful); + +function updateHoverLayerStatus(ecIns, ecModel) { + var zr = ecIns._zr; + var storage = zr.storage; + var elCount = 0; + storage.traverse(function (el) { + elCount++; + }); + + if (elCount > ecModel.get('hoverLayerThreshold') && !env$1.node) { + ecModel.eachSeries(function (seriesModel) { + if (seriesModel.preventUsingHoverLayer) { + return; + } + + var chartView = ecIns._chartsMap[seriesModel.__viewId]; + + if (chartView.__alive) { + chartView.group.traverse(function (el) { + // Don't switch back. + el.useHoverLayer = true; + }); + } + }); + } +} +/** + * Update chart progressive and blend. + * @param {module:echarts/model/Series|module:echarts/model/Component} model + * @param {module:echarts/view/Component|module:echarts/view/Chart} view + */ + + +function updateBlend(seriesModel, chartView) { + var blendMode = seriesModel.get('blendMode') || null; + chartView.group.traverse(function (el) { + // FIXME marker and other components + if (!el.isGroup) { + // Only set if blendMode is changed. In case element is incremental and don't wan't to rerender. + if (el.style.blend !== blendMode) { + el.setStyle('blend', blendMode); + } + } + + if (el.eachPendingDisplayable) { + el.eachPendingDisplayable(function (displayable) { + displayable.setStyle('blend', blendMode); + }); + } + }); +} +/** + * @param {module:echarts/model/Series|module:echarts/model/Component} model + * @param {module:echarts/view/Component|module:echarts/view/Chart} view + */ + + +function updateZ(model, view) { + var z = model.get('z'); + var zlevel = model.get('zlevel'); // Set z and zlevel + + view.group.traverse(function (el) { + if (el.type !== 'group') { + z != null && (el.z = z); + zlevel != null && (el.zlevel = zlevel); + } + }); +} + +function createExtensionAPI(ecInstance) { + var coordSysMgr = ecInstance._coordSysMgr; + return extend(new ExtensionAPI(ecInstance), { + // Inject methods + getCoordinateSystems: bind(coordSysMgr.getCoordinateSystems, coordSysMgr), + getComponentByElement: function (el) { + while (el) { + var modelInfo = el.__ecComponentInfo; + + if (modelInfo != null) { + return ecInstance._model.getComponent(modelInfo.mainType, modelInfo.index); + } + + el = el.parent; + } + } + }); +} +/** + * @class + * 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. + */ + + +function EventProcessor() { + // These info required: targetEl, packedEvent, model, view + this.eventInfo; +} + +EventProcessor.prototype = { + constructor: EventProcessor, + 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 = ['Index', 'Name', 'Id']; + var dataKeys = { + name: 1, + dataIndex: 1, + dataType: 1 + }; + each$1(query, function (val, key) { + var reserved = false; + + for (var i = 0; i < suffixes.length; i++) { + var propSuffix = suffixes[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.hasOwnProperty(key)) { + dataQuery[key] = val; + reserved = true; + } + + if (!reserved) { + otherQuery[key] = val; + } + }); + } + + return { + cptQuery: cptQuery, + dataQuery: dataQuery, + otherQuery: otherQuery + }; + }, + filter: function (eventType, query, args) { + // 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]; + } + }, + afterTrigger: function () { + // Make sure the eventInfo wont be used in next trigger. + this.eventInfo = null; + } +}; +/** + * @type {Object} key: actionType. + * @inner + */ + +var actions = {}; +/** + * Map eventType to actionType + * @type {Object} + */ + +var eventActionMap = {}; +/** + * Data processor functions of each stage + * @type {Array.>} + * @inner + */ + +var dataProcessorFuncs = []; +/** + * @type {Array.} + * @inner + */ + +var optionPreprocessorFuncs = []; +/** + * @type {Array.} + * @inner + */ + +var postUpdateFuncs = []; +/** + * Visual encoding functions of each stage + * @type {Array.>} + */ + +var visualFuncs = []; +/** + * Theme storage + * @type {Object.} + */ + +var themeStorage = {}; +/** + * Loading effects + */ + +var loadingEffects = {}; +var instances = {}; +var connectedGroups = {}; +var idBase = new Date() - 0; +var groupIdBase = new Date() - 0; +var DOM_ATTRIBUTE_KEY = '_echarts_instance_'; + +function enableConnect(chart) { + var STATUS_PENDING = 0; + var STATUS_UPDATING = 1; + var STATUS_UPDATED = 2; + var STATUS_KEY = '__connectUpdateStatus'; + + function updateConnectedChartsStatus(charts, status) { + for (var i = 0; i < charts.length; i++) { + var otherChart = charts[i]; + otherChart[STATUS_KEY] = status; + } + } + + each(eventActionMap, function (actionType, eventType) { + chart._messageCenter.on(eventType, function (event) { + if (connectedGroups[chart.group] && chart[STATUS_KEY] !== STATUS_PENDING) { + if (event && event.escapeConnect) { + return; + } + + var action = chart.makeActionFromEvent(event); + var otherCharts = []; + each(instances, function (otherChart) { + if (otherChart !== chart && otherChart.group === chart.group) { + otherCharts.push(otherChart); + } + }); + updateConnectedChartsStatus(otherCharts, STATUS_PENDING); + each(otherCharts, function (otherChart) { + if (otherChart[STATUS_KEY] !== STATUS_UPDATING) { + otherChart.dispatchAction(action); + } + }); + updateConnectedChartsStatus(otherCharts, STATUS_UPDATED); + } + }); + }); +} +/** + * @param {HTMLElement} dom + * @param {Object} [theme] + * @param {Object} opts + * @param {number} [opts.devicePixelRatio] Use window.devicePixelRatio by default + * @param {string} [opts.renderer] Can choose 'canvas' or 'svg' to render the chart. + * @param {number} [opts.width] Use clientWidth of the input `dom` by default. + * Can be 'auto' (the same as null/undefined) + * @param {number} [opts.height] Use clientHeight of the input `dom` by default. + * Can be 'auto' (the same as null/undefined) + */ + + +function init(dom, theme$$1, opts) { + var existInstance = getInstanceByDom(dom); + + if (existInstance) { + return existInstance; + } + + var chart = new ECharts(dom, theme$$1, opts); + chart.id = 'ec_' + idBase++; + instances[chart.id] = chart; + setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id); + enableConnect(chart); + return chart; +} +/** + * @return {string|Array.} groupId + */ + +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 + * @return {string} groupId + */ + +function disConnect(groupId) { + connectedGroups[groupId] = false; +} +/** + * @return {string} groupId + */ + +var disconnect = disConnect; +/** + * Dispose a chart instance + * @param {module:echarts~ECharts|HTMLDomElement|string} chart + */ + +function dispose(chart) { + if (typeof chart === 'string') { + chart = instances[chart]; + } else if (!(chart instanceof ECharts)) { + // Try to treat as dom + chart = getInstanceByDom(chart); + } + + if (chart instanceof ECharts && !chart.isDisposed()) { + chart.dispose(); + } +} +/** + * @param {HTMLElement} dom + * @return {echarts~ECharts} + */ + +function getInstanceByDom(dom) { + return instances[getAttribute(dom, DOM_ATTRIBUTE_KEY)]; +} +/** + * @param {string} key + * @return {echarts~ECharts} + */ + +function getInstanceById(key) { + return instances[key]; +} +/** + * Register theme + */ + +function registerTheme(name, theme$$1) { + themeStorage[name] = theme$$1; +} +/** + * Register option preprocessor + * @param {Function} preprocessorFunc + */ + +function registerPreprocessor(preprocessorFunc) { + optionPreprocessorFuncs.push(preprocessorFunc); +} +/** + * @param {number} [priority=1000] + * @param {Object|Function} processor + */ + +function registerProcessor(priority, processor) { + normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_FILTER); +} +/** + * Register postUpdater + * @param {Function} postUpdateFunc + */ + +function registerPostUpdate(postUpdateFunc) { + postUpdateFuncs.push(postUpdateFunc); +} +/** + * Usage: + * registerAction('someAction', 'someEvent', function () { ... }); + * registerAction('someAction', function () { ... }); + * registerAction( + * {type: 'someAction', event: 'someEvent', update: 'updateView'}, + * function () { ... } + * ); + * + * @param {(string|Object)} actionInfo + * @param {string} actionInfo.type + * @param {string} [actionInfo.event] + * @param {string} [actionInfo.update] + * @param {string} [eventName] + * @param {Function} action + */ + +function registerAction(actionInfo, eventName, action) { + if (typeof eventName === 'function') { + 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; // 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; +} +/** + * @param {string} type + * @param {*} CoordinateSystem + */ + +function registerCoordinateSystem(type, CoordinateSystem$$1) { + CoordinateSystemManager.register(type, CoordinateSystem$$1); +} +/** + * 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(); + } +} +/** + * Layout is a special stage of visual encoding + * Most visual encoding like color are common for different chart + * But each chart has it's own layout algorithm + * + * @param {number} [priority=1000] + * @param {Function} layoutTask + */ + +function registerLayout(priority, layoutTask) { + normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout'); +} +/** + * @param {number} [priority=3000] + * @param {module:echarts/stream/Task} visualTask + */ + +function registerVisual(priority, visualTask) { + normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual'); +} +/** + * @param {Object|Function} fn: {seriesType, createOnAllSeries, performRawSeries, reset} + */ + +function normalizeRegister(targetList, priority, fn, defaultPriority, visualType) { + if (isFunction(priority) || isObject(priority)) { + fn = priority; + priority = defaultPriority; + } + + var stageHandler = Scheduler.wrapStageHandler(fn, visualType); + stageHandler.__prio = priority; + stageHandler.__raw = fn; + targetList.push(stageHandler); + return stageHandler; +} +/** + * @param {string} name + */ + + +function registerLoading(name, loadingFx) { + loadingEffects[name] = loadingFx; +} +/** + * @param {Object} opts + * @param {string} [superClass] + */ + +function extendComponentModel(opts +/*, superClass*/ +) { + // var Clazz = ComponentModel; + // if (superClass) { + // var classType = parseClassType(superClass); + // Clazz = ComponentModel.getClass(classType.main, classType.sub, true); + // } + return ComponentModel.extend(opts); +} +/** + * @param {Object} opts + * @param {string} [superClass] + */ + +function extendComponentView(opts +/*, superClass*/ +) { + // var Clazz = ComponentView; + // if (superClass) { + // var classType = parseClassType(superClass); + // Clazz = ComponentView.getClass(classType.main, classType.sub, true); + // } + return Component$1.extend(opts); +} +/** + * @param {Object} opts + * @param {string} [superClass] + */ + +function extendSeriesModel(opts +/*, superClass*/ +) { + // var Clazz = SeriesModel; + // if (superClass) { + // superClass = 'series.' + superClass.replace('series.', ''); + // var classType = parseClassType(superClass); + // Clazz = ComponentModel.getClass(classType.main, classType.sub, true); + // } + return SeriesModel.extend(opts); +} +/** + * @param {Object} opts + * @param {string} [superClass] + */ + +function extendChartView(opts +/*, superClass*/ +) { + // var Clazz = ChartView; + // if (superClass) { + // superClass = superClass.replace('series.', ''); + // var classType = parseClassType(superClass); + // Clazz = ChartView.getClass(classType.main, true); + // } + return Chart.extend(opts); +} +/** + * 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') + * + * Be careful of using it in the browser. + * + * @param {Function} creator + * @example + * var Canvas = require('canvas'); + * var echarts = require('echarts'); + * echarts.setCanvasCreator(function () { + * // Small size is enough. + * return new Canvas(32, 32); + * }); + */ + +function setCanvasCreator(creator) { + $override('createCanvas', creator); +} +/** + * @param {string} mapName + * @param {Array.|Object|string} geoJson + * @param {Object} [specialAreas] + * + * @example GeoJSON + * $.get('USA.json', function (geoJson) { + * echarts.registerMap('USA', geoJson); + * // Or + * echarts.registerMap('USA', { + * geoJson: geoJson, + * specialAreas: {} + * }) + * }); + * + * $.get('airport.svg', function (svg) { + * echarts.registerMap('airport', { + * svg: svg + * } + * }); + * + * echarts.registerMap('eu', [ + * {svg: eu-topographic.svg}, + * {geoJSON: eu.json} + * ]) + */ + +function registerMap(mapName, geoJson, specialAreas) { + mapDataStorage.registerMap(mapName, geoJson, specialAreas); +} +/** + * @param {string} mapName + * @return {Object} + */ + +function getMap(mapName) { + // For backward compatibility, only return the first one. + var records = mapDataStorage.retrieveMap(mapName); + return records && records[0] && { + geoJson: records[0].geoJSON, + specialAreas: records[0].specialAreas + }; +} +registerVisual(PRIORITY_VISUAL_GLOBAL, seriesColor); +registerPreprocessor(backwardCompat); +registerProcessor(PRIORITY_PROCESSOR_DATASTACK, dataStack); +registerLoading('default', loadingDefault); // Default actions + +registerAction({ + type: 'highlight', + event: 'highlight', + update: 'highlight' +}, noop); +registerAction({ + type: 'downplay', + event: 'downplay', + update: 'downplay' +}, 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 = {}; + +/* +* 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 defaultKeyGetter(item) { + return item; +} +/** + * @param {Array} oldArr + * @param {Array} newArr + * @param {Function} oldKeyGetter + * @param {Function} newKeyGetter + * @param {Object} [context] Can be visited by this.context in callback. + */ + + +function DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter, context) { + this._old = oldArr; + this._new = newArr; + this._oldKeyGetter = oldKeyGetter || defaultKeyGetter; + this._newKeyGetter = newKeyGetter || defaultKeyGetter; + this.context = context; +} + +DataDiffer.prototype = { + constructor: DataDiffer, + + /** + * Callback function when add a data + */ + add: function (func) { + this._add = func; + return this; + }, + + /** + * Callback function when update a data + */ + update: function (func) { + this._update = func; + return this; + }, + + /** + * Callback function when remove a data + */ + remove: function (func) { + this._remove = func; + return this; + }, + execute: function () { + var oldArr = this._old; + var newArr = this._new; + var oldDataIndexMap = {}; + var newDataIndexMap = {}; + var oldDataKeyArr = []; + var newDataKeyArr = []; + var i; + initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter', this); + initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter', this); + + for (i = 0; i < oldArr.length; i++) { + var key = oldDataKeyArr[i]; + var idx = newDataIndexMap[key]; // idx can never be empty array here. see 'set null' logic below. + + if (idx != null) { + // 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 len = idx.length; + + if (len) { + len === 1 && (newDataIndexMap[key] = null); + idx = idx.shift(); + } else { + newDataIndexMap[key] = null; + } + + this._update && this._update(idx, i); + } else { + this._remove && this._remove(i); + } + } + + for (var i = 0; i < newDataKeyArr.length; i++) { + var key = newDataKeyArr[i]; + + if (newDataIndexMap.hasOwnProperty(key)) { + var idx = newDataIndexMap[key]; + + if (idx == null) { + continue; + } // idx can never be empty array here. see 'set null' logic above. + + + if (!idx.length) { + this._add && this._add(idx); + } else { + for (var j = 0, len = idx.length; j < len; j++) { + this._add && this._add(idx[j]); + } + } + } + } + } +}; + +function initIndexMap(arr, map, keyArr, keyGetterName, dataDiffer) { + for (var i = 0; i < arr.length; i++) { + // Add prefix to avoid conflict with Object.prototype. + var key = '_ec_' + dataDiffer[keyGetterName](arr[i], i); + var existence = map[key]; + + if (existence == null) { + keyArr.push(key); + map[key] = i; + } else { + if (!existence.length) { + map[key] = existence = [existence]; + } + + existence.push(i); + } + } +} + +/* +* 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 OTHER_DIMENSIONS = createHashMap(['tooltip', 'label', 'itemName', 'itemId', 'seriesName']); +function summarizeDimensions(data) { + var summary = {}; + var encode = summary.encode = {}; + var notExtraCoordDimMap = createHashMap(); + var defaultedLabel = []; + var defaultedTooltip = []; // See the comment of `List.js#userOutput`. + + var userOutput = summary.userOutput = { + dimensionNames: data.dimensions.slice(), + encode: {} + }; + each$1(data.dimensions, function (dimName) { + var dimItem = data.getDimensionInfo(dimName); + var coordDim = dimItem.coordDim; + + if (coordDim) { + 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(userOutput.encode, coordDim)[coordDimIndex] = dimItem.index; + } + + if (dimItem.defaultTooltip) { + defaultedTooltip.push(dimName); + } + } + + OTHER_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]; // ??? FIXME extra coord should not be set in dataDimsOnCoord. + // But should fix the case that radar axes: simplify the logic + // of `completeDimension`, remove `extraPrefix`. + + 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.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; + return summary; +} + +function getOrCreateEncodeArr(encode, dim) { + if (!encode.hasOwnProperty(dim)) { + encode[dim] = []; + } + + return encode[dim]; +} + +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 +// var dimensions = data.dimensions.slice(); +// var valueType; +// var valueDim; +// while (dimensions.length && ( +// valueDim = dimensions.pop(), +// valueType = data.getDimensionInfo(valueDim).type, +// valueType === 'ordinal' || valueType === 'time' +// )) {} // jshint ignore:line +// return valueDim; +// } + +/* +* 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. +*/ + +/* global Float64Array, Int32Array, Uint32Array, Uint16Array */ + +/** + * List for data storage + * @module echarts/data/List + */ +var isObject$4 = isObject$1; +var UNDEFINED = 'undefined'; +var INDEX_NOT_FOUND = -1; // 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 dataCtors = { + 'float': typeof Float64Array === UNDEFINED ? Array : Float64Array, + 'int': typeof Int32Array === UNDEFINED ? Array : Int32Array, + // Ordinal data type can be string or int + 'ordinal': Array, + 'number': Array, + 'time': Array +}; // 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 CtorInt32Array = typeof Int32Array === UNDEFINED ? Array : Int32Array; +var CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array; + +function getIndicesCtor(list) { + // The possible max value in this._indicies is always this._rawCount despite of filtering. + return list._rawCount > 65535 ? CtorUint32Array : CtorUint16Array; +} + +function cloneChunk(originalChunk) { + var Ctor = originalChunk.constructor; // Only shallow clone is enough when Array. + + return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk); +} + +var TRANSFERABLE_PROPERTIES = ['hasItemOption', '_nameList', '_idList', '_invertedIndicesMap', '_rawData', '_chunkSize', '_chunkCount', '_dimValueGetter', '_count', '_rawCount', '_nameDimIdx', '_idDimIdx']; +var CLONE_PROPERTIES = ['_extent', '_approximateExtent', '_rawExtent']; + +function transferProperties(target, source) { + each$1(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) { + if (source.hasOwnProperty(propName)) { + target[propName] = source[propName]; + } + }); + target.__wrappedMethods = source.__wrappedMethods; + each$1(CLONE_PROPERTIES, function (propName) { + target[propName] = clone(source[propName]); + }); + target._calculationInfo = extend(source._calculationInfo); +} +/** + * @constructor + * @alias module:echarts/data/List + * + * @param {Array.} dimensions + * For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...]. + * Dimensions should be concrete names like x, y, z, lng, lat, angle, radius + * Spetial fields: { + * ordinalMeta: + * createInvertedIndices: + * } + * @param {module:echarts/model/Model} hostModel + */ + + +var List = function (dimensions, hostModel) { + dimensions = dimensions || ['x', 'y']; + var dimensionInfos = {}; + var dimensionNames = []; + var invertedIndicesMap = {}; + + for (var i = 0; i < dimensions.length; i++) { + // Use the original dimensions[i], where other flag props may exists. + var dimensionInfo = dimensions[i]; + + if (isString(dimensionInfo)) { + dimensionInfo = { + name: dimensionInfo + }; + } + + var dimensionName = dimensionInfo.name; + dimensionInfo.type = dimensionInfo.type || 'float'; + + if (!dimensionInfo.coordDim) { + dimensionInfo.coordDim = dimensionName; + dimensionInfo.coordDimIndex = 0; + } + + dimensionInfo.otherDims = dimensionInfo.otherDims || {}; + dimensionNames.push(dimensionName); + dimensionInfos[dimensionName] = dimensionInfo; + dimensionInfo.index = i; + + if (dimensionInfo.createInvertedIndices) { + invertedIndicesMap[dimensionName] = []; + } + } + /** + * @readOnly + * @type {Array.} + */ + + + this.dimensions = dimensionNames; + /** + * Infomation of each data dimension, like data type. + * @type {Object} + */ + + this._dimensionInfos = dimensionInfos; + /** + * @type {module:echarts/model/Model} + */ + + this.hostModel = hostModel; + /** + * @type {module:echarts/model/Model} + */ + + this.dataType; + /** + * Indices stores the indices of data subset after filtered. + * This data subset will be used in chart. + * @type {Array.} + * @readOnly + */ + + this._indices = null; + this._count = 0; + this._rawCount = 0; + /** + * Data storage + * @type {Object.>} + * @private + */ + + this._storage = {}; + /** + * @type {Array.} + */ + + this._nameList = []; + /** + * @type {Array.} + */ + + this._idList = []; + /** + * Models of data option is stored sparse for optimizing memory cost + * @type {Array.} + * @private + */ + + this._optionModels = []; + /** + * Global visual properties after visual coding + * @type {Object} + * @private + */ + + this._visual = {}; + /** + * Globel layout properties. + * @type {Object} + * @private + */ + + this._layout = {}; + /** + * Item visual properties after visual coding + * @type {Array.} + * @private + */ + + this._itemVisuals = []; + /** + * Key: visual type, Value: boolean + * @type {Object} + * @readOnly + */ + + this.hasItemVisual = {}; + /** + * Item layout properties after layout + * @type {Array.} + * @private + */ + + this._itemLayouts = []; + /** + * Graphic elemnents + * @type {Array.} + * @private + */ + + this._graphicEls = []; + /** + * Max size of each chunk. + * @type {number} + * @private + */ + + this._chunkSize = 1e5; + /** + * @type {number} + * @private + */ + + this._chunkCount = 0; + /** + * @type {Array.} + * @private + */ + + this._rawData; + /** + * Raw extent will not be cloned, but only transfered. + * It will not be calculated util needed. + * key: dim, + * value: {end: number, extent: Array.} + * @type {Object} + * @private + */ + + this._rawExtent = {}; + /** + * @type {Object} + * @private + */ + + this._extent = {}; + /** + * key: dim + * value: extent + * @type {Object} + * @private + */ + + this._approximateExtent = {}; + /** + * Cache summary info for fast visit. See "dimensionHelper". + * @type {Object} + * @private + */ + + this._dimensionsSummary = summarizeDimensions(this); + /** + * @type {Object.} + * @private + */ + + this._invertedIndicesMap = invertedIndicesMap; + /** + * @type {Object} + * @private + */ + + this._calculationInfo = {}; + /** + * User output info of this data. + * DO NOT use it in other places! + * + * When preparing user params for user callbacks, we have + * to clone these inner data structures to prevent users + * from modifying them to effect built-in logic. And for + * performance consideration we make this `userOutput` to + * avoid clone them too many times. + * + * @type {Object} + * @readOnly + */ + + this.userOutput = this._dimensionsSummary.userOutput; +}; + +var listProto = List.prototype; +listProto.type = 'list'; +/** + * If each data item has it's own option + * @type {boolean} + */ + +listProto.hasItemOption = true; +/** + * 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 `this.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"`. + * + * Get dimension name + * @param {string|number} dim See above. + * @return {string} Concrete dim name. + */ + +listProto.getDimension = function (dim) { + if (typeof dim === 'number' // If being a number-like string but not being defined a dimension name. + || !isNaN(dim) && !this._dimensionInfos.hasOwnProperty(dim)) { + dim = this.dimensions[dim]; + } + + return dim; +}; +/** + * Get type and calculation info of particular dimension + * @param {string|number} 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' + */ + + +listProto.getDimensionInfo = function (dim) { + // Do not clone, because there may be categories in dimInfo. + return this._dimensionInfos[this.getDimension(dim)]; +}; +/** + * @return {Array.} concrete dimension name list on coord. + */ + + +listProto.getDimensionsOnCoord = function () { + return this._dimensionsSummary.dataDimsOnCoord.slice(); +}; +/** + * @param {string} coordDim + * @param {number} [idx] A coordDim may map to more than one data dim. + * If idx is `true`, return a array of all mapped dims. + * If idx is not specified, return the first dim not extra. + * @return {string|Array.} concrete data dim. + * If idx is number, and not found, return null/undefined. + * If idx is `true`, and not found, return empty array (always return array). + */ + + +listProto.mapDimension = function (coordDim, idx) { + var dimensionsSummary = this._dimensionsSummary; + + if (idx == null) { + return dimensionsSummary.encodeFirstDimNotExtra[coordDim]; + } + + var dims = dimensionsSummary.encode[coordDim]; + return idx === true // always return array if idx is `true` + ? (dims || []).slice() : dims && dims[idx]; +}; +/** + * Initialize from data + * @param {Array.} data source or data or data provider. + * @param {Array.} [nameLIst] The name of a datum is used on data diff and + * defualt label/tooltip. + * A name can be specified in encode.itemName, + * or dataItem.name (only for series option data), + * or provided in nameList from outside. + * @param {Function} [dimValueGetter] (dataItem, dimName, dataIndex, dimIndex) => number + */ + + +listProto.initData = function (data, nameList, dimValueGetter) { + var notProvider = Source.isInstance(data) || isArrayLike(data); + + if (notProvider) { + data = new DefaultDataProvider(data, this.dimensions.length); + } + + this._rawData = data; // Clear + + this._storage = {}; + this._indices = null; + this._nameList = nameList || []; + this._idList = []; + this._nameRepeatCount = {}; + + if (!dimValueGetter) { + this.hasItemOption = false; + } + /** + * @readOnly + */ + + + this.defaultDimValueGetter = defaultDimValueGetters[this._rawData.getSource().sourceFormat]; // Default dim value getter + + this._dimValueGetter = dimValueGetter = dimValueGetter || this.defaultDimValueGetter; + this._dimValueGetterArrayRows = defaultDimValueGetters.arrayRows; // Reset raw extent. + + this._rawExtent = {}; + + this._initDataFromProvider(0, data.count()); // If data has no item option. + + + if (data.pure) { + this.hasItemOption = false; + } +}; + +listProto.getProvider = function () { + return this._rawData; +}; +/** + * Caution: Can be only called on raw data (before `this._indices` created). + */ + + +listProto.appendData = function (data) { + var rawData = this._rawData; + var start = this.count(); + rawData.appendData(data); + var end = rawData.count(); + + if (!rawData.persistent) { + end += start; + } + + this._initDataFromProvider(start, end); +}; +/** + * Caution: Can be only called on raw data (before `this._indices` created). + * This method does not modify `rawData` (`dataProvider`), but only + * add values to storage. + * + * The final count will be increased by `Math.max(values.length, names.length)`. + * + * @param {Array.>} values That is the SourceType: 'arrayRows', like + * [ + * [12, 33, 44], + * [NaN, 43, 1], + * ['-', 'asdf', 0] + * ] + * Each item is exaclty cooresponding to a dimension. + * @param {Array.} [names] + */ + + +listProto.appendValues = function (values, names) { + var chunkSize = this._chunkSize; + var storage = this._storage; + var dimensions = this.dimensions; + var dimLen = dimensions.length; + var rawExtent = this._rawExtent; + var start = this.count(); + var end = start + Math.max(values.length, names ? names.length : 0); + var originalChunkCount = this._chunkCount; + + for (var i = 0; i < dimLen; i++) { + var dim = dimensions[i]; + + if (!rawExtent[dim]) { + rawExtent[dim] = getInitialExtent(); + } + + if (!storage[dim]) { + storage[dim] = []; + } + + prepareChunks(storage, this._dimensionInfos[dim], chunkSize, originalChunkCount, end); + this._chunkCount = storage[dim].length; + } + + var emptyDataItem = new Array(dimLen); + + for (var idx = start; idx < end; idx++) { + var sourceIdx = idx - start; + var chunkIndex = Math.floor(idx / chunkSize); + var chunkOffset = idx % chunkSize; // Store the data by dimensions + + for (var k = 0; k < dimLen; k++) { + var dim = dimensions[k]; + + var val = this._dimValueGetterArrayRows(values[sourceIdx] || emptyDataItem, dim, sourceIdx, k); + + storage[dim][chunkIndex][chunkOffset] = val; + var dimRawExtent = rawExtent[dim]; + val < dimRawExtent[0] && (dimRawExtent[0] = val); + val > dimRawExtent[1] && (dimRawExtent[1] = val); + } + + if (names) { + this._nameList[idx] = names[sourceIdx]; + } + } + + this._rawCount = this._count = end; // Reset data extent + + this._extent = {}; + prepareInvertedIndex(this); +}; + +listProto._initDataFromProvider = function (start, end) { + // Optimize. + if (start >= end) { + return; + } + + var chunkSize = this._chunkSize; + var rawData = this._rawData; + var storage = this._storage; + var dimensions = this.dimensions; + var dimLen = dimensions.length; + var dimensionInfoMap = this._dimensionInfos; + var nameList = this._nameList; + var idList = this._idList; + var rawExtent = this._rawExtent; + var nameRepeatCount = this._nameRepeatCount = {}; + var nameDimIdx; + var originalChunkCount = this._chunkCount; + + for (var i = 0; i < dimLen; i++) { + var dim = dimensions[i]; + + if (!rawExtent[dim]) { + rawExtent[dim] = getInitialExtent(); + } + + var dimInfo = dimensionInfoMap[dim]; + + if (dimInfo.otherDims.itemName === 0) { + nameDimIdx = this._nameDimIdx = i; + } + + if (dimInfo.otherDims.itemId === 0) { + this._idDimIdx = i; + } + + if (!storage[dim]) { + storage[dim] = []; + } + + prepareChunks(storage, dimInfo, chunkSize, originalChunkCount, end); + this._chunkCount = storage[dim].length; + } + + var dataItem = new Array(dimLen); + + for (var idx = start; idx < end; idx++) { + // NOTICE: Try not to write things into dataItem + dataItem = rawData.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 + + var chunkIndex = Math.floor(idx / chunkSize); + var chunkOffset = idx % chunkSize; // Store the data by dimensions + + for (var k = 0; k < dimLen; k++) { + var dim = dimensions[k]; + var dimStorage = storage[dim][chunkIndex]; // PENDING NULL is empty or zero + + var val = this._dimValueGetter(dataItem, dim, idx, k); + + dimStorage[chunkOffset] = val; + var dimRawExtent = rawExtent[dim]; + val < dimRawExtent[0] && (dimRawExtent[0] = val); + val > dimRawExtent[1] && (dimRawExtent[1] = val); + } // ??? FIXME not check by pure but sourceFormat? + // TODO refactor these logic. + + + if (!rawData.pure) { + var name = nameList[idx]; + + if (dataItem && name == null) { + // If dataItem is {name: ...}, it has highest priority. + // That is appropriate for many common cases. + if (dataItem.name != null) { + // There is no other place to persistent dataItem.name, + // so save it to nameList. + nameList[idx] = name = dataItem.name; + } else if (nameDimIdx != null) { + var nameDim = dimensions[nameDimIdx]; + var nameDimChunk = storage[nameDim][chunkIndex]; + + if (nameDimChunk) { + name = nameDimChunk[chunkOffset]; + var ordinalMeta = dimensionInfoMap[nameDim].ordinalMeta; + + if (ordinalMeta && ordinalMeta.categories.length) { + name = ordinalMeta.categories[name]; + } + } + } + } // Try using the id in option + // id or name is used on dynamical data, mapping old and new items. + + + var id = dataItem == null ? null : dataItem.id; + + if (id == null && name != null) { + // Use name as id and add counter to avoid same name + nameRepeatCount[name] = nameRepeatCount[name] || 0; + id = name; + + if (nameRepeatCount[name] > 0) { + id += '__ec__' + nameRepeatCount[name]; + } + + nameRepeatCount[name]++; + } + + id != null && (idList[idx] = id); + } + } + + if (!rawData.persistent && rawData.clean) { + // Clean unused data if data source is typed array. + rawData.clean(); + } + + this._rawCount = this._count = end; // Reset data extent + + this._extent = {}; + prepareInvertedIndex(this); +}; + +function prepareChunks(storage, dimInfo, chunkSize, chunkCount, end) { + var DataCtor = dataCtors[dimInfo.type]; + var lastChunkIndex = chunkCount - 1; + var dim = dimInfo.name; + var resizeChunkArray = storage[dim][lastChunkIndex]; + + if (resizeChunkArray && resizeChunkArray.length < chunkSize) { + var newStore = new DataCtor(Math.min(end - lastChunkIndex * chunkSize, chunkSize)); // The cost of the copy is probably inconsiderable + // within the initial chunkSize. + + for (var j = 0; j < resizeChunkArray.length; j++) { + newStore[j] = resizeChunkArray[j]; + } + + storage[dim][lastChunkIndex] = newStore; + } // Create new chunks. + + + for (var k = chunkCount * chunkSize; k < end; k += chunkSize) { + storage[dim].push(new DataCtor(Math.min(end - k, chunkSize))); + } +} + +function prepareInvertedIndex(list) { + var invertedIndicesMap = list._invertedIndicesMap; + each$1(invertedIndicesMap, function (invertedIndices, dim) { + var dimInfo = list._dimensionInfos[dim]; // Currently, only dimensions that has ordinalMeta can create inverted indices. + + var ordinalMeta = dimInfo.ordinalMeta; + + if (ordinalMeta) { + invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array(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 < list._count; i++) { + // Only support the case that all values are distinct. + invertedIndices[list.get(dim, i)] = i; + } + } + }); +} + +function getRawValueFromStore(list, dimIndex, rawIndex) { + var val; + + if (dimIndex != null) { + var chunkSize = list._chunkSize; + var chunkIndex = Math.floor(rawIndex / chunkSize); + var chunkOffset = rawIndex % chunkSize; + var dim = list.dimensions[dimIndex]; + var chunk = list._storage[dim][chunkIndex]; + + if (chunk) { + val = chunk[chunkOffset]; + var ordinalMeta = list._dimensionInfos[dim].ordinalMeta; + + if (ordinalMeta && ordinalMeta.categories.length) { + val = ordinalMeta.categories[val]; + } + } + } + + return val; +} +/** + * @return {number} + */ + + +listProto.count = function () { + return this._count; +}; + +listProto.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); + var newIndices = new Ctor(this.count()); + + for (var i = 0; i < newIndices.length; i++) { + newIndices[i] = i; + } + } + + return newIndices; +}; +/** + * Get value. Return NaN if idx is out of range. + * @param {string} dim Dim must be concrete name. + * @param {number} idx + * @param {boolean} stack + * @return {number} + */ + + +listProto.get = function (dim, idx +/*, stack */ +) { + if (!(idx >= 0 && idx < this._count)) { + return NaN; + } + + var storage = this._storage; + + if (!storage[dim]) { + // TODO Warn ? + return NaN; + } + + idx = this.getRawIndex(idx); + var chunkIndex = Math.floor(idx / this._chunkSize); + var chunkOffset = idx % this._chunkSize; + var chunkStore = storage[dim][chunkIndex]; + var value = chunkStore[chunkOffset]; // FIXME ordinal data type is not stackable + // if (stack) { + // var dimensionInfo = this._dimensionInfos[dim]; + // if (dimensionInfo && dimensionInfo.stackable) { + // var stackedOn = this.stackedOn; + // while (stackedOn) { + // // Get no stacked data of stacked on + // var stackedValue = stackedOn.get(dim, idx); + // // Considering positive stack, negative stack and empty data + // if ((value >= 0 && stackedValue > 0) // Positive stack + // || (value <= 0 && stackedValue < 0) // Negative stack + // ) { + // value += stackedValue; + // } + // stackedOn = stackedOn.stackedOn; + // } + // } + // } + + return value; +}; +/** + * @param {string} dim concrete dim + * @param {number} rawIndex + * @return {number|string} + */ + + +listProto.getByRawIndex = function (dim, rawIdx) { + if (!(rawIdx >= 0 && rawIdx < this._rawCount)) { + return NaN; + } + + var dimStore = this._storage[dim]; + + if (!dimStore) { + // TODO Warn ? + return NaN; + } + + var chunkIndex = Math.floor(rawIdx / this._chunkSize); + var chunkOffset = rawIdx % this._chunkSize; + var chunkStore = dimStore[chunkIndex]; + return chunkStore[chunkOffset]; +}; +/** + * FIXME Use `get` on chrome maybe slow(in filterSelf and selectRange). + * Hack a much simpler _getFast + * @private + */ + + +listProto._getFast = function (dim, rawIdx) { + var chunkIndex = Math.floor(rawIdx / this._chunkSize); + var chunkOffset = rawIdx % this._chunkSize; + var chunkStore = this._storage[dim][chunkIndex]; + return chunkStore[chunkOffset]; +}; +/** + * Get value for multi dimensions. + * @param {Array.} [dimensions] If ignored, using all dimensions. + * @param {number} idx + * @return {number} + */ + + +listProto.getValues = function (dimensions, idx +/*, stack */ +) { + var values = []; + + if (!isArray(dimensions)) { + // stack = idx; + idx = dimensions; + dimensions = this.dimensions; + } + + for (var i = 0, len = dimensions.length; i < len; i++) { + values.push(this.get(dimensions[i], idx + /*, stack */ + )); + } + + return values; +}; +/** + * If value is NaN. Inlcuding '-' + * Only check the coord dimensions. + * @param {string} dim + * @param {number} idx + * @return {number} + */ + + +listProto.hasValue = function (idx) { + var dataDimsOnCoord = this._dimensionsSummary.dataDimsOnCoord; + + for (var i = 0, len = dataDimsOnCoord.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.get(dataDimsOnCoord[i], idx))) { + return false; + } + } + + return true; +}; +/** + * Get extent of data in one dimension + * @param {string} dim + * @param {boolean} stack + */ + + +listProto.getDataExtent = function (dim +/*, stack */ +) { + // Make sure use concrete dim as cache name. + dim = this.getDimension(dim); + var dimData = this._storage[dim]; + var initialExtent = getInitialExtent(); // stack = !!((stack || false) && this.getCalculationInfo(dim)); + + if (!dimData) { + return initialExtent; + } // Make more strict checkings to ensure hitting cache. + + + var currEnd = this.count(); // var cacheName = [dim, !!stack].join('_'); + // var cacheName = dim; + // 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; // && !stack; + + 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 value = stack ? this.get(dim, i, true) : this._getFast(dim, this.getRawIndex(i)); + var value = this._getFast(dim, this.getRawIndex(i)); + + value < min && (min = value); + value > max && (max = value); + } + + dimExtent = [min, max]; + this._extent[dim] = dimExtent; + return dimExtent; +}; +/** + * 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. + */ + + +listProto.getApproximateExtent = function (dim +/*, stack */ +) { + dim = this.getDimension(dim); + return this._approximateExtent[dim] || this.getDataExtent(dim + /*, stack */ + ); +}; + +listProto.setApproximateExtent = function (extent, dim +/*, stack */ +) { + dim = this.getDimension(dim); + this._approximateExtent[dim] = extent.slice(); +}; +/** + * @param {string} key + * @return {*} + */ + + +listProto.getCalculationInfo = function (key) { + return this._calculationInfo[key]; +}; +/** + * @param {string|Object} key or k-v object + * @param {*} [value] + */ + + +listProto.setCalculationInfo = function (key, value) { + isObject$4(key) ? extend(this._calculationInfo, key) : this._calculationInfo[key] = value; +}; +/** + * Get sum of data in one dimension + * @param {string} dim + */ + + +listProto.getSum = function (dim +/*, stack */ +) { + var dimData = this._storage[dim]; + var sum = 0; + + if (dimData) { + for (var i = 0, len = this.count(); i < len; i++) { + var value = this.get(dim, i + /*, stack */ + ); + + if (!isNaN(value)) { + sum += value; + } + } + } + + return sum; +}; +/** + * Get median of data in one dimension + * @param {string} dim + */ + + +listProto.getMedian = function (dim +/*, stack */ +) { + var dimDataArray = []; // map all data of one dimension + + this.each(dim, function (val, idx) { + if (!isNaN(val)) { + dimDataArray.push(val); + } + }); // TODO + // Use quick select? + // immutability & sort + + var sortedDimDataArray = [].concat(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 value +// * @param {string} dim Concrete dimension. +// * @param {number} value +// * @return {number} +// */ +// Currently incorrect: should return dataIndex but not rawIndex. +// Do not fix it until this method is to be used somewhere. +// FIXME Precision of float value +// listProto.indexOf = function (dim, value) { +// var storage = this._storage; +// var dimData = storage[dim]; +// var chunkSize = this._chunkSize; +// if (dimData) { +// for (var i = 0, len = this.count(); i < len; i++) { +// var chunkIndex = Math.floor(i / chunkSize); +// var chunkOffset = i % chunkSize; +// if (dimData[chunkIndex][chunkOffset] === value) { +// return i; +// } +// } +// } +// return -1; +// }; + +/** + * Only support the dimension which inverted index created. + * Do not support other cases until required. + * @param {string} concrete dim + * @param {number|string} value + * @return {number} rawIndex + */ + + +listProto.rawIndexOf = function (dim, value) { + var invertedIndices = dim && this._invertedIndicesMap[dim]; + var rawIndex = invertedIndices[value]; + + if (rawIndex == null || isNaN(rawIndex)) { + return INDEX_NOT_FOUND; + } + + return rawIndex; +}; +/** + * Retreive the index with given name + * @param {number} idx + * @param {number} name + * @return {number} + */ + + +listProto.indexOfName = function (name) { + for (var i = 0, len = this.count(); i < len; i++) { + if (this.getName(i) === name) { + return i; + } + } + + return -1; +}; +/** + * Retreive the index with given raw data index + * @param {number} idx + * @param {number} name + * @return {number} + */ + + +listProto.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 {string} dim + * @param {number} value + * @param {number} [maxDistance=Infinity] + * @return {Array.} Considere multiple points has the same value. + */ + + +listProto.indicesOfNearest = function (dim, value, maxDistance) { + var storage = this._storage; + var dimData = storage[dim]; + var nearestIndices = []; + + if (!dimData) { + return nearestIndices; + } + + if (maxDistance == null) { + maxDistance = Infinity; + } + + var minDist = Number.MAX_VALUE; + var minDiff = -1; + + for (var i = 0, len = this.count(); i < len; i++) { + var diff = value - this.get(dim, i + /*, stack */ + ); + var dist = Math.abs(diff); + + if (diff <= maxDistance && dist <= minDist) { + // For the case of two data are same on xAxis, which has sequence data. + // Show the nearest index + // https://github.com/ecomfe/echarts/issues/2869 + if (dist < minDist || diff >= 0 && minDiff < 0) { + minDist = dist; + minDiff = diff; + nearestIndices.length = 0; + } + + nearestIndices.push(i); + } + } + + return nearestIndices; +}; +/** + * Get raw data index + * @param {number} idx + * @return {number} + */ + + +listProto.getRawIndex = getRawIndexWithoutIndices; + +function getRawIndexWithoutIndices(idx) { + return idx; +} + +function getRawIndexWithIndices(idx) { + if (idx < this._count && idx >= 0) { + return this._indices[idx]; + } + + return -1; +} +/** + * Get raw data item + * @param {number} idx + * @return {number} + */ + + +listProto.getRawDataItem = function (idx) { + if (!this._rawData.persistent) { + var val = []; + + for (var i = 0; i < this.dimensions.length; i++) { + var dim = this.dimensions[i]; + val.push(this.get(dim, idx)); + } + + return val; + } else { + return this._rawData.getItem(this.getRawIndex(idx)); + } +}; +/** + * @param {number} idx + * @param {boolean} [notDefaultIdx=false] + * @return {string} + */ + + +listProto.getName = function (idx) { + var rawIndex = this.getRawIndex(idx); + return this._nameList[rawIndex] || getRawValueFromStore(this, this._nameDimIdx, rawIndex) || ''; +}; +/** + * @param {number} idx + * @param {boolean} [notDefaultIdx=false] + * @return {string} + */ + + +listProto.getId = function (idx) { + return getId(this, this.getRawIndex(idx)); +}; + +function getId(list, rawIndex) { + var id = list._idList[rawIndex]; + + if (id == null) { + id = getRawValueFromStore(list, list._idDimIdx, rawIndex); + } + + if (id == null) { + // FIXME Check the usage in graph, should not use prefix. + id = ID_PREFIX + rawIndex; + } + + return id; +} + +function normalizeDimensions(dimensions) { + if (!isArray(dimensions)) { + dimensions = [dimensions]; + } + + return dimensions; +} + +/** + * Data iteration + * @param {string|Array.} + * @param {Function} cb + * @param {*} [context=this] + * + * @example + * list.each('x', function (x, idx) {}); + * list.each(['x', 'y'], function (x, y, idx) {}); + * list.each(function (idx) {}) + */ + + +listProto.each = function (dims, cb, context, contextCompat) { + 'use strict'; + + if (!this._count) { + return; + } + + if (typeof dims === 'function') { + contextCompat = context; + context = cb; + cb = dims; + dims = []; + } // contextCompat just for compat echarts3 + + + context = context || contextCompat || this; + dims = map(normalizeDimensions(dims), this.getDimension, this); + var dimSize = dims.length; + + for (var i = 0; i < this.count(); i++) { + // Simple optimization + switch (dimSize) { + case 0: + cb.call(context, i); + break; + + case 1: + cb.call(context, this.get(dims[0], i), i); + break; + + case 2: + cb.call(context, this.get(dims[0], i), this.get(dims[1], i), i); + break; + + default: + var k = 0; + var value = []; + + for (; k < dimSize; k++) { + value[k] = this.get(dims[k], i); + } // Index + + + value[k] = i; + cb.apply(context, value); + } + } +}; +/** + * Data filter + * @param {string|Array.} + * @param {Function} cb + * @param {*} [context=this] + */ + + +listProto.filterSelf = function (dimensions, cb, context, contextCompat) { + 'use strict'; + + if (!this._count) { + return; + } + + if (typeof dimensions === 'function') { + contextCompat = context; + context = cb; + cb = dimensions; + dimensions = []; + } // contextCompat just for compat echarts3 + + + context = context || contextCompat || this; + dimensions = map(normalizeDimensions(dimensions), this.getDimension, this); + var count = this.count(); + var Ctor = getIndicesCtor(this); + var newIndices = new Ctor(count); + var value = []; + var dimSize = dimensions.length; + var offset = 0; + var dim0 = dimensions[0]; + + for (var i = 0; i < count; i++) { + var keep; + var rawIdx = this.getRawIndex(i); // Simple optimization + + if (dimSize === 0) { + keep = cb.call(context, i); + } else if (dimSize === 1) { + var val = this._getFast(dim0, rawIdx); + + keep = cb.call(context, val, i); + } else { + for (var k = 0; k < dimSize; k++) { + value[k] = this._getFast(dim0, rawIdx); + } + + value[k] = i; + keep = cb.apply(context, value); + } + + if (keep) { + newIndices[offset++] = rawIdx; + } + } // Set indices after filtered. + + + if (offset < count) { + this._indices = newIndices; + } + + this._count = offset; // Reset data extent + + this._extent = {}; + this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices; + return this; +}; +/** + * Select data in range. (For optimization of filter) + * (Manually inline code, support 5 million data filtering in data zoom.) + */ + + +listProto.selectRange = function (range) { + 'use strict'; + + if (!this._count) { + return; + } + + var dimensions = []; + + for (var dim in range) { + if (range.hasOwnProperty(dim)) { + dimensions.push(dim); + } + } + + var dimSize = dimensions.length; + + if (!dimSize) { + return; + } + + var originalCount = this.count(); + var Ctor = getIndicesCtor(this); + var newIndices = new Ctor(originalCount); + var offset = 0; + var dim0 = dimensions[0]; + var min = range[dim0][0]; + var max = range[dim0][1]; + var quickFinished = false; + + if (!this._indices) { + // Extreme optimization for common case. About 2x faster in chrome. + var idx = 0; + + if (dimSize === 1) { + var dimStorage = this._storage[dimensions[0]]; + + for (var k = 0; k < this._chunkCount; k++) { + var chunkStorage = dimStorage[k]; + var len = Math.min(this._count - k * this._chunkSize, this._chunkSize); + + for (var i = 0; i < len; i++) { + var val = chunkStorage[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 = this._storage[dim0]; + var dimStorage2 = this._storage[dimensions[1]]; + var min2 = range[dimensions[1]][0]; + var max2 = range[dimensions[1]][1]; + + for (var k = 0; k < this._chunkCount; k++) { + var chunkStorage = dimStorage[k]; + var chunkStorage2 = dimStorage2[k]; + var len = Math.min(this._count - k * this._chunkSize, this._chunkSize); + + for (var i = 0; i < len; i++) { + var val = chunkStorage[i]; + var val2 = chunkStorage2[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 = this.getRawIndex(i); + + var val = this._getFast(dim0, 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 = this.getRawIndex(i); + + for (var k = 0; k < dimSize; k++) { + var dimk = dimensions[k]; + + var val = this._getFast(dim, rawIndex); // Do not filter NaN, see comment above. + + + if (val < range[dimk][0] || val > range[dimk][1]) { + keep = false; + } + } + + if (keep) { + newIndices[offset++] = this.getRawIndex(i); + } + } + } + } // Set indices after filtered. + + + if (offset < originalCount) { + this._indices = newIndices; + } + + this._count = offset; // Reset data extent + + this._extent = {}; + this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices; + return this; +}; +/** + * Data mapping to a plain array + * @param {string|Array.} [dimensions] + * @param {Function} cb + * @param {*} [context=this] + * @return {Array} + */ + + +listProto.mapArray = function (dimensions, cb, context, contextCompat) { + 'use strict'; + + if (typeof dimensions === 'function') { + contextCompat = context; + context = cb; + cb = dimensions; + dimensions = []; + } // contextCompat just for compat echarts3 + + + context = context || contextCompat || this; + var result = []; + this.each(dimensions, function () { + result.push(cb && cb.apply(this, arguments)); + }, context); + return result; +}; // Data in excludeDimensions is copied, otherwise transfered. + + +function cloneListForMapAndSample(original, excludeDimensions) { + var allDimensions = original.dimensions; + var list = new List(map(allDimensions, original.getDimensionInfo, original), original.hostModel); // FIXME If needs stackedOn, value may already been stacked + + transferProperties(list, original); + var storage = list._storage = {}; + var originalStorage = original._storage; // Init storage + + for (var i = 0; i < allDimensions.length; i++) { + var dim = allDimensions[i]; + + if (originalStorage[dim]) { + // Notice that we do not reset invertedIndicesMap here, becuase + // there is no scenario of mapping or sampling ordinal dimension. + if (indexOf(excludeDimensions, dim) >= 0) { + storage[dim] = cloneDimStore(originalStorage[dim]); + list._rawExtent[dim] = getInitialExtent(); + list._extent[dim] = null; + } else { + // Direct reference for other dimensions + storage[dim] = originalStorage[dim]; + } + } + } + + return list; +} + +function cloneDimStore(originalDimStore) { + var newDimStore = new Array(originalDimStore.length); + + for (var j = 0; j < originalDimStore.length; j++) { + newDimStore[j] = cloneChunk(originalDimStore[j]); + } + + return newDimStore; +} + +function getInitialExtent() { + return [Infinity, -Infinity]; +} +/** + * Data mapping to a new List with given dimensions + * @param {string|Array.} dimensions + * @param {Function} cb + * @param {*} [context=this] + * @return {Array} + */ + + +listProto.map = function (dimensions, cb, context, contextCompat) { + 'use strict'; // contextCompat just for compat echarts3 + + context = context || contextCompat || this; + dimensions = map(normalizeDimensions(dimensions), this.getDimension, this); + var list = cloneListForMapAndSample(this, dimensions); // Following properties are all immutable. + // So we can reference to the same value + + list._indices = this._indices; + list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices; + var storage = list._storage; + var tmpRetValue = []; + var chunkSize = this._chunkSize; + var dimSize = dimensions.length; + var dataCount = this.count(); + var values = []; + var rawExtent = list._rawExtent; + + for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) { + for (var dimIndex = 0; dimIndex < dimSize; dimIndex++) { + values[dimIndex] = this.get(dimensions[dimIndex], dataIndex + /*, stack */ + ); + } + + values[dimSize] = dataIndex; + var retValue = cb && cb.apply(context, values); + + if (retValue != null) { + // a number or string (in oridinal dimension)? + if (typeof retValue !== 'object') { + tmpRetValue[0] = retValue; + retValue = tmpRetValue; + } + + var rawIndex = this.getRawIndex(dataIndex); + var chunkIndex = Math.floor(rawIndex / chunkSize); + var chunkOffset = rawIndex % chunkSize; + + for (var i = 0; i < retValue.length; i++) { + var dim = dimensions[i]; + var val = retValue[i]; + var rawExtentOnDim = rawExtent[dim]; + var dimStore = storage[dim]; + + if (dimStore) { + dimStore[chunkIndex][chunkOffset] = val; + } + + if (val < rawExtentOnDim[0]) { + rawExtentOnDim[0] = val; + } + + if (val > rawExtentOnDim[1]) { + rawExtentOnDim[1] = val; + } + } + } + } + + return list; +}; +/** + * Large data down sampling on given dimension + * @param {string} dimension + * @param {number} rate + * @param {Function} sampleValue + * @param {Function} sampleIndex Sample index for name and id + */ + + +listProto.downSample = function (dimension, rate, sampleValue, sampleIndex) { + var list = cloneListForMapAndSample(this, [dimension]); + var targetStorage = list._storage; + var frameValues = []; + var frameSize = Math.floor(1 / rate); + var dimStore = targetStorage[dimension]; + var len = this.count(); + var chunkSize = this._chunkSize; + var rawExtentOnDim = list._rawExtent[dimension]; + var newIndices = new (getIndicesCtor(this))(len); + 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); + var originalChunkIndex = Math.floor(dataIdx / chunkSize); + var originalChunkOffset = dataIdx % chunkSize; + frameValues[k] = dimStore[originalChunkIndex][originalChunkOffset]; + } + + var value = sampleValue(frameValues); + var sampleFrameIdx = this.getRawIndex(Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)); + var sampleChunkIndex = Math.floor(sampleFrameIdx / chunkSize); + var sampleChunkOffset = sampleFrameIdx % chunkSize; // Only write value on the filtered data + + dimStore[sampleChunkIndex][sampleChunkOffset] = value; + + if (value < rawExtentOnDim[0]) { + rawExtentOnDim[0] = value; + } + + if (value > rawExtentOnDim[1]) { + rawExtentOnDim[1] = value; + } + + newIndices[offset++] = sampleFrameIdx; + } + + list._count = offset; + list._indices = newIndices; + list.getRawIndex = getRawIndexWithIndices; + return list; +}; +/** + * Get model of one data item. + * + * @param {number} idx + */ +// FIXME Model proxy ? + + +listProto.getItemModel = function (idx) { + var hostModel = this.hostModel; + return new Model(this.getRawDataItem(idx), hostModel, hostModel && hostModel.ecModel); +}; +/** + * Create a data differ + * @param {module:echarts/data/List} otherList + * @return {module:echarts/data/DataDiffer} + */ + + +listProto.diff = function (otherList) { + var thisList = this; + return new DataDiffer(otherList ? otherList.getIndices() : [], this.getIndices(), function (idx) { + return getId(otherList, idx); + }, function (idx) { + return getId(thisList, idx); + }); +}; +/** + * Get visual property. + * @param {string} key + */ + + +listProto.getVisual = function (key) { + var visual = this._visual; + return visual && visual[key]; +}; +/** + * Set visual property + * @param {string|Object} key + * @param {*} [value] + * + * @example + * setVisual('color', color); + * setVisual({ + * 'color': color + * }); + */ + + +listProto.setVisual = function (key, val) { + if (isObject$4(key)) { + for (var name in key) { + if (key.hasOwnProperty(name)) { + this.setVisual(name, key[name]); + } + } + + return; + } + + this._visual = this._visual || {}; + this._visual[key] = val; +}; +/** + * Set layout property. + * @param {string|Object} key + * @param {*} [val] + */ + + +listProto.setLayout = function (key, val) { + if (isObject$4(key)) { + for (var name in key) { + if (key.hasOwnProperty(name)) { + this.setLayout(name, key[name]); + } + } + + return; + } + + this._layout[key] = val; +}; +/** + * Get layout property. + * @param {string} key. + * @return {*} + */ + + +listProto.getLayout = function (key) { + return this._layout[key]; +}; +/** + * Get layout of single data item + * @param {number} idx + */ + + +listProto.getItemLayout = function (idx) { + return this._itemLayouts[idx]; +}; +/** + * Set layout of single data item + * @param {number} idx + * @param {Object} layout + * @param {boolean=} [merge=false] + */ + + +listProto.setItemLayout = function (idx, layout, merge$$1) { + this._itemLayouts[idx] = merge$$1 ? extend(this._itemLayouts[idx] || {}, layout) : layout; +}; +/** + * Clear all layout of single data item + */ + + +listProto.clearItemLayouts = function () { + this._itemLayouts.length = 0; +}; +/** + * Get visual property of single data item + * @param {number} idx + * @param {string} key + * @param {boolean} [ignoreParent=false] + */ + + +listProto.getItemVisual = function (idx, key, ignoreParent) { + var itemVisual = this._itemVisuals[idx]; + var val = itemVisual && itemVisual[key]; + + if (val == null && !ignoreParent) { + // Use global visual property + return this.getVisual(key); + } + + return val; +}; +/** + * Set visual property of single data item + * + * @param {number} idx + * @param {string|Object} key + * @param {*} [value] + * + * @example + * setItemVisual(0, 'color', color); + * setItemVisual(0, { + * 'color': color + * }); + */ + + +listProto.setItemVisual = function (idx, key, value) { + var itemVisual = this._itemVisuals[idx] || {}; + var hasItemVisual = this.hasItemVisual; + this._itemVisuals[idx] = itemVisual; + + if (isObject$4(key)) { + for (var name in key) { + if (key.hasOwnProperty(name)) { + itemVisual[name] = key[name]; + hasItemVisual[name] = true; + } + } + + return; + } + + itemVisual[key] = value; + hasItemVisual[key] = true; +}; +/** + * Clear itemVisuals and list visual. + */ + + +listProto.clearAllVisual = function () { + this._visual = {}; + this._itemVisuals = []; + this.hasItemVisual = {}; +}; + +var setItemDataAndSeriesIndex = function (child) { + child.seriesIndex = this.seriesIndex; + child.dataIndex = this.dataIndex; + child.dataType = this.dataType; +}; +/** + * Set graphic element relative to data. It can be set as null + * @param {number} idx + * @param {module:zrender/Element} [el] + */ + + +listProto.setItemGraphicEl = function (idx, el) { + var hostModel = this.hostModel; + + if (el) { + // Add data index and series index for indexing the data by element + // Useful in tooltip + el.dataIndex = idx; + el.dataType = this.dataType; + el.seriesIndex = hostModel && hostModel.seriesIndex; + + if (el.type === 'group') { + el.traverse(setItemDataAndSeriesIndex, el); + } + } + + this._graphicEls[idx] = el; +}; +/** + * @param {number} idx + * @return {module:zrender/Element} + */ + + +listProto.getItemGraphicEl = function (idx) { + return this._graphicEls[idx]; +}; +/** + * @param {Function} cb + * @param {*} context + */ + + +listProto.eachItemGraphicEl = function (cb, context) { + each$1(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. + */ + + +listProto.cloneShallow = function (list) { + if (!list) { + var dimensionInfoList = map(this.dimensions, this.getDimensionInfo, this); + list = new List(dimensionInfoList, this.hostModel); + } // FIXME + + + list._storage = this._storage; + transferProperties(list, this); // Clone will not change the data extent and indices + + if (this._indices) { + var Ctor = this._indices.constructor; + list._indices = new Ctor(this._indices); + } else { + list._indices = null; + } + + list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices; + return list; +}; +/** + * Wrap some method to add more feature + * @param {string} methodName + * @param {Function} injectFunction + */ + + +listProto.wrapMethod = function (methodName, injectFunction) { + var originalMethod = this[methodName]; + + if (typeof originalMethod !== 'function') { + 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))); + }; +}; // Methods that create a new list based on this list should be listed here. +// Notice that those method should `RETURN` the new list. + + +listProto.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'map']; // Methods that change indices of this list should be listed here. + +listProto.CHANGABLE_METHODS = ['filterSelf', 'selectRange']; + +/* +* 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. +*/ + +/** + * @deprecated + * Use `echarts/data/helper/createDimensions` instead. + */ +/** + * @see {module:echarts/test/ut/spec/data/completeDimensions} + * + * Complete the dimensions array, by user defined `dimension` and `encode`, + * and guessing from the data structure. + * If no 'value' dimension specified, the first no-named dimension will be + * named as 'value'. + * + * @param {Array.} sysDims Necessary dimensions, like ['x', 'y'], which + * provides not only dim template, but also default order. + * properties: 'name', 'type', 'displayName'. + * `name` of each item provides default coord name. + * [{dimsDef: [string|Object, ...]}, ...] dimsDef of sysDim item provides default dim name, and + * provide dims count that the sysDim required. + * [{ordinalMeta}] can be specified. + * @param {module:echarts/data/Source|Array|Object} source or data (for compatibal with pervious) + * @param {Object} [opt] + * @param {Array.} [opt.dimsDef] option.series.dimensions User defined dimensions + * For example: ['asdf', {name, type}, ...]. + * @param {Object|HashMap} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3} + * @param {string} [opt.generateCoord] Generate coord dim with the given name. + * If not specified, extra dim names will be: + * 'value', 'value0', 'value1', ... + * @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`. + * If `generateCoordCount` specified, the generated dim names will be: + * `generateCoord` + 0, `generateCoord` + 1, ... + * can be Infinity, indicate that use all of the remain columns. + * @param {number} [opt.dimCount] If not specified, guess by the first data item. + * @param {number} [opt.encodeDefaulter] If not specified, auto find the next available data dim. + * @return {Array.} [{ + * name: string mandatory, + * displayName: string, the origin name in dimsDef, see source helper. + * If displayName given, the tooltip will displayed vertically. + * coordDim: string mandatory, + * coordDimIndex: number mandatory, + * type: string optional, + * otherDims: { never null/undefined + * tooltip: number optional, + * label: number optional, + * itemName: number optional, + * seriesName: number optional, + * }, + * isExtraCoord: boolean true if coord is generated + * (not specified in encode and not series specified) + * other props ... + * }] + */ + +function completeDimensions(sysDims, source, opt) { + if (!Source.isInstance(source)) { + source = Source.seriesDataToSource(source); + } + + opt = opt || {}; + sysDims = (sysDims || []).slice(); + var dimsDef = (opt.dimsDef || []).slice(); + var encodeDef = createHashMap(opt.encodeDef); + var dataDimNameMap = createHashMap(); + var coordDimNameMap = createHashMap(); // var valueCandidate; + + var result = []; + var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimCount); // Apply user defined dims (`name` and `type`) and init result. + + for (var i = 0; i < dimCount; i++) { + var dimDefItem = dimsDef[i] = extend({}, isObject$1(dimsDef[i]) ? dimsDef[i] : { + name: dimsDef[i] + }); + var userDimName = dimDefItem.name; + var resultItem = result[i] = { + otherDims: {} + }; // Name will be applied later for avoiding duplication. + + 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; + dataDimNameMap.set(userDimName, i); + } + + dimDefItem.type != null && (resultItem.type = dimDefItem.type); + dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName); + } // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`. + + + encodeDef.each(function (dataDims, coordDim) { + dataDims = normalizeToArray(dataDims).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) { + encodeDef.set(coordDim, false); + return; + } + + var validDataDims = encodeDef.set(coordDim, []); + each$1(dataDims, function (resultDimIdx, idx) { + // The input resultDimIdx can be dim name or index. + isString(resultDimIdx) && (resultDimIdx = dataDimNameMap.get(resultDimIdx)); + + if (resultDimIdx != null && resultDimIdx < dimCount) { + validDataDims[idx] = resultDimIdx; + applyDim(result[resultDimIdx], coordDim, idx); + } + }); + }); // Apply templetes and default order from `sysDims`. + + var availDimIdx = 0; + each$1(sysDims, function (sysDimItem, sysDimIndex) { + var coordDim; + var sysDimItem; + var sysDimItemDimsDef; + var sysDimItemOtherDims; + + if (isString(sysDimItem)) { + coordDim = sysDimItem; + sysDimItem = {}; + } else { + coordDim = sysDimItem.name; + var ordinalMeta = sysDimItem.ordinalMeta; + sysDimItem.ordinalMeta = null; + sysDimItem = clone(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 = encodeDef.get(coordDim); // negative resultDimIdx means no need to mapping. + + if (dataDims === false) { + return; + } + + var dataDims = normalizeToArray(dataDims); // dimensions provides default dim sequences. + + if (!dataDims.length) { + for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) { + while (availDimIdx < result.length && result[availDimIdx].coordDim != null) { + availDimIdx++; + } + + availDimIdx < result.length && dataDims.push(availDimIdx++); + } + } // Apply templates. + + + each$1(dataDims, function (resultDimIdx, coordDimIndex) { + var resultItem = result[resultDimIdx]; + applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex); + + if (resultItem.name == null && sysDimItemDimsDef) { + var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex]; + !isObject$1(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 (OTHER_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'; // Set dim `name` and other `coordDim` and other props. + + for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) { + var resultItem = result[resultDimIdx] = result[resultDimIdx] || {}; + var coordDim = resultItem.coordDim; + + if (coordDim == null) { + resultItem.coordDim = genName(extra, coordDimNameMap, fromZero); + resultItem.coordDimIndex = 0; + + if (!generateCoord || generateCoordCount <= 0) { + resultItem.isExtraCoord = true; + } + + generateCoordCount--; + } + + resultItem.name == null && (resultItem.name = genName(resultItem.coordDim, dataDimNameMap)); + + if (resultItem.type == null && guessOrdinal(source, resultDimIdx, resultItem.name)) { + resultItem.type = 'ordinal'; + } + } + + return result; +} // ??? 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 storage? + + +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.dimensionsDetectCount || 1, sysDims.length, dimsDef.length, optDimCount || 0); + each$1(sysDims, function (sysDimItem) { + var sysDimItemDimsDef = sysDimItem.dimsDef; + sysDimItemDimsDef && (dimCount = Math.max(dimCount, sysDimItemDimsDef.length)); + }); + return dimCount; +} + +function genName(name, map$$1, fromZero) { + if (fromZero || map$$1.get(name) != null) { + var i = 0; + + while (map$$1.get(name + i) != null) { + i++; + } + + name += i; + } + + map$$1.set(name, true); + return name; +} + +/* +* 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. +*/ + +/** + * Substitute `completeDimensions`. + * `completeDimensions` is to be deprecated. + */ +/** + * @param {module:echarts/data/Source|module:echarts/data/List} source or data. + * @param {Object|Array} [opt] + * @param {Array.} [opt.coordDimensions=[]] + * @param {number} [opt.dimensionsCount] + * @param {string} [opt.generateCoord] + * @param {string} [opt.generateCoordCount] + * @param {Array.} [opt.dimensionsDefine=source.dimensionsDefine] Overwrite source define. + * @param {Object|HashMap} [opt.encodeDefine=source.encodeDefine] Overwrite source define. + * @return {Array.} dimensionsInfo + */ + +var createDimensions = function (source, opt) { + opt = opt || {}; + return completeDimensions(opt.coordDimensions || [], source, { + dimsDef: opt.dimensionsDefine || source.dimensionsDefine, + encodeDef: opt.encodeDefine || source.encodeDefine, + dimCount: opt.dimensionsCount, + generateCoord: opt.generateCoord, + generateCoordCount: opt.generateCoordCount + }); +}; + +/* +* 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. +*/ +/** + * 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 {module:echarts/model/Series} seriesModel + * @param {Array.} dimensionInfoList The same as the input of . + * The input dimensionInfoList will be modified. + * @param {Object} [opt] + * @param {boolean} [opt.stackedCoordDimension=''] Specify a coord dimension if needed. + * @param {boolean} [opt.byIndex=false] + * @return {Object} calculationInfo + * { + * stackedDimension: string + * stackedByDimension: string + * isStackedByIndex: boolean + * stackedOverDimension: string + * stackResultDimension: string + * } + */ + +function enableDataStack(seriesModel, dimensionInfoList, opt) { + opt = opt || {}; + var byIndex = opt.byIndex; + var stackedCoordDimension = opt.stackedCoordDimension; // Compatibal: when `stack` is set as '', do not stack. + + var mayStack = !!(seriesModel && seriesModel.get('stack')); + var stackedByDimInfo; + var stackedDimInfo; + var stackResultDimension; + var stackedOverDimension; + each$1(dimensionInfoList, function (dimensionInfo, index) { + if (isString(dimensionInfo)) { + dimensionInfoList[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. + stackResultDimension = '__\0ecstackresult'; + stackedOverDimension = '__\0ecstackedover'; // Create inverted index to fast query index by value. + + if (stackedByDimInfo) { + stackedByDimInfo.createInvertedIndices = true; + } + + var stackedDimCoordDim = stackedDimInfo.coordDim; + var stackedDimType = stackedDimInfo.type; + var stackedDimCoordIndex = 0; + each$1(dimensionInfoList, function (dimensionInfo) { + if (dimensionInfo.coordDim === stackedDimCoordDim) { + stackedDimCoordIndex++; + } + }); + dimensionInfoList.push({ + name: stackResultDimension, + coordDim: stackedDimCoordDim, + coordDimIndex: stackedDimCoordIndex, + type: stackedDimType, + isExtraCoord: true, + isCalculationCoord: true + }); + stackedDimCoordIndex++; + dimensionInfoList.push({ + 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, + type: stackedDimType, + isExtraCoord: true, + isCalculationCoord: true + }); + } + + return { + stackedDimension: stackedDimInfo && stackedDimInfo.name, + stackedByDimension: stackedByDimInfo && stackedByDimInfo.name, + isStackedByIndex: byIndex, + stackedOverDimension: stackedOverDimension, + stackResultDimension: stackResultDimension + }; +} +/** + * @param {module:echarts/data/List} data + * @param {string} stackedDim + */ + +function isDimensionStacked(data, stackedDim +/*, stackedByDim*/ +) { + // 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'); // && ( + // stackedByDim != null + // ? stackedByDim === data.getCalculationInfo('stackedByDimension') + // : data.getCalculationInfo('isStackedByIndex') + // ); +} +/** + * @param {module:echarts/data/List} data + * @param {string} targetDim + * @param {string} [stackedByDim] If not input this parameter, check whether + * stacked by index. + * @return {string} dimension + */ + +function getStackedDimension(data, targetDim) { + return isDimensionStacked(data, targetDim) ? data.getCalculationInfo('stackResultDimension') : targetDim; +} + +/* +* 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. +*/ +/** + * @param {module:echarts/data/Source|Array} source Or raw data. + * @param {module:echarts/model/Series} seriesModel + * @param {Object} [opt] + * @param {string} [opt.generateCoord] + */ + +function createListFromArray(source, seriesModel, opt) { + opt = opt || {}; + + if (!Source.isInstance(source)) { + source = Source.seriesDataToSource(source); + } + + var coordSysName = seriesModel.get('coordinateSystem'); + var registeredCoordSys = CoordinateSystemManager.get(coordSysName); + var coordSysDefine = getCoordSysDefineBySeries(seriesModel); + var coordSysDimDefs; + + if (coordSysDefine) { + coordSysDimDefs = map(coordSysDefine.coordSysDims, function (dim) { + var dimInfo = { + name: dim + }; + var axisModel = coordSysDefine.axisMap.get(dim); + + if (axisModel) { + var axisType = axisModel.get('type'); + dimInfo.type = getDimensionTypeByAxis(axisType); // dimInfo.stackable = isStackable(axisType); + } + + return dimInfo; + }); + } + + if (!coordSysDimDefs) { + // Get dimensions from registered coordinate system + coordSysDimDefs = registeredCoordSys && (registeredCoordSys.getDimensionsInfo ? registeredCoordSys.getDimensionsInfo() : registeredCoordSys.dimensions.slice()) || ['x', 'y']; + } + + var dimInfoList = createDimensions(source, { + coordDimensions: coordSysDimDefs, + generateCoord: opt.generateCoord + }); + var firstCategoryDimIndex; + var hasNameEncode; + coordSysDefine && each$1(dimInfoList, function (dimInfo, dimIndex) { + var coordDim = dimInfo.coordDim; + var categoryAxisModel = coordSysDefine.categoryAxisMap.get(coordDim); + + if (categoryAxisModel) { + if (firstCategoryDimIndex == null) { + firstCategoryDimIndex = dimIndex; + } + + dimInfo.ordinalMeta = categoryAxisModel.getOrdinalMeta(); + } + + if (dimInfo.otherDims.itemName != null) { + hasNameEncode = true; + } + }); + + if (!hasNameEncode && firstCategoryDimIndex != null) { + dimInfoList[firstCategoryDimIndex].otherDims.itemName = 0; + } + + var stackCalculationInfo = enableDataStack(seriesModel, dimInfoList); + var list = new List(dimInfoList, seriesModel); + list.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; + list.hasItemOption = false; + list.initData(source, null, dimValueGetter); + return list; +} + +function isNeedCompleteOrdinalData(source) { + if (source.sourceFormat === SOURCE_FORMAT_ORIGINAL) { + var sampleItem = firstDataNotNull(source.data || []); + return sampleItem != null && !isArray(getDataItemValue(sampleItem)); + } +} + +function firstDataNotNull(data) { + var i = 0; + + while (i < data.length && data[i] == null) { + i++; + } + + return data[i]; +} + +/* +* 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. +*/ + +/** + * // Scale class management + * @module echarts/scale/Scale + */ +/** + * @param {Object} [setting] + */ + +function Scale(setting) { + this._setting = setting || {}; + /** + * Extent + * @type {Array.} + * @protected + */ + + this._extent = [Infinity, -Infinity]; + /** + * Step is calculated in adjustExtent + * @type {Array.} + * @protected + */ + + this._interval = 0; + this.init && this.init.apply(this, arguments); +} +/** + * Parse input val to valid inner number. + * @param {*} val + * @return {number} + */ + + +Scale.prototype.parse = function (val) { + // Notice: This would be a trap here, If the implementation + // of this method depends on extent, and this method is used + // before extent set (like in dataZoom), it would be wrong. + // Nevertheless, parse does not depend on extent generally. + return val; +}; + +Scale.prototype.getSetting = function (name) { + return this._setting[name]; +}; + +Scale.prototype.contain = function (val) { + var extent = this._extent; + return val >= extent[0] && val <= extent[1]; +}; +/** + * Normalize value to linear [0, 1], return 0.5 if extent span is 0 + * @param {number} val + * @return {number} + */ + + +Scale.prototype.normalize = function (val) { + var extent = this._extent; + + if (extent[1] === extent[0]) { + return 0.5; + } + + return (val - extent[0]) / (extent[1] - extent[0]); +}; +/** + * Scale normalized value + * @param {number} val + * @return {number} + */ + + +Scale.prototype.scale = function (val) { + var extent = this._extent; + return val * (extent[1] - extent[0]) + extent[0]; +}; +/** + * Set extent from data + * @param {Array.} other + */ + + +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 + * @param {module:echarts/data/List} data + * @param {string} dim + */ + + +Scale.prototype.unionExtentFromData = function (data, dim) { + this.unionExtent(data.getApproximateExtent(dim)); +}; +/** + * Get extent + * @return {Array.} + */ + + +Scale.prototype.getExtent = function () { + return this._extent.slice(); +}; +/** + * Set extent + * @param {number} start + * @param {number} end + */ + + +Scale.prototype.setExtent = function (start, end) { + var thisExtent = this._extent; + + if (!isNaN(start)) { + thisExtent[0] = start; + } + + if (!isNaN(end)) { + thisExtent[1] = end; + } +}; +/** + * 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; +}; +/** + * @abstract + * @param {*} tick + * @return {string} label of the tick. + */ + +Scale.prototype.getLabel = null; +enableClassExtend(Scale); +enableClassManagement(Scale, { + registerWhenExtend: 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. +*/ +/** + * @constructor + * @param {Object} [opt] + * @param {Object} [opt.categories=[]] + * @param {Object} [opt.needCollect=false] + * @param {Object} [opt.deduplication=false] + */ + +function OrdinalMeta(opt) { + /** + * @readOnly + * @type {Array.} + */ + this.categories = opt.categories || []; + /** + * @private + * @type {boolean} + */ + + this._needCollect = opt.needCollect; + /** + * @private + * @type {boolean} + */ + + this._deduplication = opt.deduplication; + /** + * @private + * @type {boolean} + */ + + this._map; +} +/** + * @param {module:echarts/model/Model} axisModel + * @return {module:echarts/data/OrdinalMeta} + */ + + +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 + }); +}; + +var proto$1 = OrdinalMeta.prototype; +/** + * @param {string} category + * @return {number} ordinal + */ + +proto$1.getOrdinal = function (category) { + return getOrCreateMap(this).get(category); +}; +/** + * @param {*} category + * @return {number} The ordinal. If not found, return NaN. + */ + + +proto$1.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 (typeof category !== 'string' && !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$$1 = getOrCreateMap(this); + index = map$$1.get(category); + + if (index == null) { + if (needCollect) { + index = this.categories.length; + this.categories[index] = category; + map$$1.set(category, index); + } else { + index = NaN; + } + } + + return index; +}; // Consider big data, do not create map until needed. + + +function getOrCreateMap(ordinalMeta) { + return ordinalMeta._map || (ordinalMeta._map = createHashMap(ordinalMeta.categories)); +} + +function getName(obj) { + if (isObject$1(obj) && obj.value != null) { + return obj.value; + } else { + return obj + ''; + } +} + +/* +* 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. +*/ + +/** + * Linear continuous scale + * @module echarts/coord/scale/Ordinal + * + * http://en.wikipedia.org/wiki/Level_of_measurement + */ +// FIXME only one data +var scaleProto = Scale.prototype; +var OrdinalScale = Scale.extend({ + type: 'ordinal', + + /** + * @param {module:echarts/data/OrdianlMeta|Array.} ordinalMeta + */ + init: function (ordinalMeta, extent) { + // Caution: Should not use instanceof, consider ec-extensions using + // import approach to get OrdinalMeta class. + if (!ordinalMeta || isArray(ordinalMeta)) { + ordinalMeta = new OrdinalMeta({ + categories: ordinalMeta + }); + } + + this._ordinalMeta = ordinalMeta; + this._extent = extent || [0, ordinalMeta.categories.length - 1]; + }, + parse: function (val) { + return typeof val === 'string' ? this._ordinalMeta.getOrdinal(val) // val might be float. + : Math.round(val); + }, + contain: function (rank) { + rank = this.parse(rank); + return scaleProto.contain.call(this, rank) && this._ordinalMeta.categories[rank] != null; + }, + + /** + * Normalize given rank or name to linear [0, 1] + * @param {number|string} [val] + * @return {number} + */ + normalize: function (val) { + return scaleProto.normalize.call(this, this.parse(val)); + }, + scale: function (val) { + return Math.round(scaleProto.scale.call(this, val)); + }, + + /** + * @return {Array} + */ + getTicks: function () { + var ticks = []; + var extent = this._extent; + var rank = extent[0]; + + while (rank <= extent[1]) { + ticks.push(rank); + rank++; + } + + return ticks; + }, + + /** + * Get item on rank n + * @param {number} n + * @return {string} + */ + getLabel: function (n) { + if (!this.isBlank()) { + // Note that if no data, ordinalMeta.categories is an empty array. + return this._ordinalMeta.categories[n]; + } + }, + + /** + * @return {number} + */ + count: function () { + return this._extent[1] - this._extent[0] + 1; + }, + + /** + * @override + */ + unionExtentFromData: function (data, dim) { + this.unionExtent(data.getApproximateExtent(dim)); + }, + getOrdinalMeta: function () { + return this._ordinalMeta; + }, + niceTicks: noop, + niceExtent: noop +}); +/** + * @return {module:echarts/scale/Time} + */ + +OrdinalScale.create = function () { + return new OrdinalScale(); +}; + +/* +* 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 testable. + */ +var roundNumber$1 = round$1; +/** + * @param {Array.} extent Both extent[0] and extent[1] should be valid number. + * Should be extent[0] < extent[1]. + * @param {number} splitNumber splitNumber should be >= 1. + * @param {number} [minInterval] + * @param {number} [maxInterval] + * @return {Object} {interval, intervalPrecision, niceTickExtent} + */ + +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 = [roundNumber$1(Math.ceil(extent[0] / interval) * interval, precision), roundNumber$1(Math.floor(extent[1] / interval) * interval, precision)]; + fixExtent(niceTickExtent, extent); + return result; +} +/** + * @param {number} interval + * @return {number} interval precision + */ + +function getIntervalPrecision(interval) { + // Tow more digital for tick. + return getPrecisionSafe(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 intervalScaleGetTicks(interval, extent, niceTickExtent, 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]) { + ticks.push(extent[0]); + } + + var tick = niceTickExtent[0]; + + while (tick <= niceTickExtent[1]) { + ticks.push(tick); // Avoid rounding error + + tick = roundNumber$1(tick + interval, intervalPrecision); + + if (tick === ticks[ticks.length - 1]) { + // 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]. + + + if (extent[1] > (ticks.length ? ticks[ticks.length - 1] : niceTickExtent[1])) { + ticks.push(extent[1]); + } + + return ticks; +} + +/* +* 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. +*/ + +/** + * Interval scale + * @module echarts/scale/Interval + */ +var roundNumber = round$1; +/** + * @alias module:echarts/coord/scale/Interval + * @constructor + */ + +var IntervalScale = Scale.extend({ + type: 'interval', + _interval: 0, + _intervalPrecision: 2, + 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); + } + }, + 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 + + IntervalScale.prototype.setExtent.call(this, extent[0], extent[1]); + }, + + /** + * Get interval + */ + getInterval: function () { + return this._interval; + }, + + /** + * Set interval + */ + 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); + }, + + /** + * @return {Array.} + */ + getTicks: function () { + return intervalScaleGetTicks(this._interval, this._extent, this._niceExtent, this._intervalPrecision); + }, + + /** + * @param {number} data + * @param {Object} [opt] + * @param {number|string} [opt.precision] If 'auto', use nice presision. + * @param {boolean} [opt.pad] returns 1.50 but not 1.5 if precision is 2. + * @return {string} + */ + getLabel: function (data, opt) { + if (data == null) { + return ''; + } + + var precision = opt && opt.precision; + + if (precision == null) { + precision = getPrecisionSafe(data) || 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'. + + + data = roundNumber(data, precision, true); + return addCommas(data); + }, + + /** + * Update interval and extent of intervals for nice ticks + * + * @param {number} [splitNumber = 5] Desired number of ticks + * @param {number} [minInterval] + * @param {number} [maxInterval] + */ + niceTicks: 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; + }, + + /** + * Nice extent. + * @param {Object} opt + * @param {number} [opt.splitNumber = 5] Given approx tick number + * @param {boolean} [opt.fixMin=false] + * @param {boolean} [opt.fixMax=false] + * @param {boolean} [opt.minInterval] + * @param {boolean} [opt.maxInterval] + */ + niceExtent: 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.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval); // var 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); + } + } +}); +/** + * @return {module:echarts/scale/Time} + */ + +IntervalScale.create = function () { + return new IntervalScale(); +}; + +/* +* 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. +*/ + +/* global Float32Array */ +var STACK_PREFIX = '__ec_stack_'; +var LARGE_BAR_MIN_WIDTH = 0.5; +var LargeArr = typeof Float32Array !== 'undefined' ? Float32Array : Array; + +function getSeriesStackId(seriesModel) { + return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex; +} + +function getAxisKey(axis) { + return axis.dim + axis.index; +} +/** + * @param {Object} opt + * @param {module:echarts/coord/Axis} opt.axis Only support category axis currently. + * @param {number} opt.count Positive interger. + * @param {number} [opt.barWidth] + * @param {number} [opt.barMaxWidth] + * @param {number} [opt.barMinWidth] + * @param {number} [opt.barGap] + * @param {number} [opt.barCategoryGap] + * @return {Object} {width, offset, offsetCenter} If axis.type is not 'category', return undefined. + */ + + + +function prepareLayoutBarSeries(seriesType, ecModel) { + var seriesModels = []; + ecModel.eachSeriesByType(seriesType, function (seriesModel) { + // Check series coordinate, do layout for cartesian2d only + if (isOnCartesian(seriesModel) && !isInLargeMode(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$1(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 dim = data.mapDimension(baseAxis.dim); + + for (var i = 0, cnt = data.count(); i < cnt; ++i) { + var value = data.get(dim, 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$1(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 1 in cartesian. Because in value axis, + // the auto-calculated bar width might be less than 1. + seriesModel.get('barMinWidth') || 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$1(seriesInfoList, function (seriesInfo, idx) { + var axisKey = seriesInfo.axisKey; + var bandWidth = seriesInfo.bandWidth; + var columnsOnAxis = columnsMap[axisKey] || { + bandWidth: bandWidth, + remainedWidth: bandWidth, + autoWidthCount: 0, + categoryGap: '20%', + gap: '30%', + 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. + // TODO + + 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$1(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$1(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; + 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; + autoWidthCount--; + } + }); // Recalculate width again + + autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent); + autoWidth = Math.max(autoWidth, 0); + var widthSum = 0; + var lastColumn; + each$1(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$1(stacks, function (column, stackId) { + result[coordSysName][stackId] = result[coordSysName][stackId] || { + bandWidth: bandWidth, + offset: offset, + width: column.width + }; + offset += column.width * (1 + barGapPercent); + }); + }); + return result; +} +/** + * @param {Object} barWidthAndOffset The result of makeColumnLayout + * @param {module:echarts/coord/Axis} axis + * @param {module:echarts/model/Series} [seriesModel] If not provided, return all. + * @return {Object} {stackId: {offset, width}} or {offset, width} if seriesModel provided. + */ + + +function retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) { + if (barWidthAndOffset && axis) { + var result = barWidthAndOffset[getAxisKey(axis)]; + + if (result != null && seriesModel != null) { + result = result[getSeriesStackId(seriesModel)]; + } + + return result; + } +} +/** + * @param {string} seriesType + * @param {module:echarts/model/Global} ecModel + */ + +function layout(seriesType, ecModel) { + var seriesModels = prepareLayoutBarSeries(seriesType, ecModel); + var barWidthAndOffset = makeColumnLayout(seriesModels); + var lastStackCoords = {}; + each$1(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; + var valueAxis = cartesian.getOtherAxis(baseAxis); + var barMinHeight = seriesModel.get('barMinHeight') || 0; + lastStackCoords[stackId] = lastStackCoords[stackId] || []; + data.setLayout({ + bandWidth: columnLayoutInfo.bandWidth, + offset: columnOffset, + size: columnWidth + }); + var valueDim = data.mapDimension(valueAxis.dim); + var baseDim = data.mapDimension(baseAxis.dim); + var stacked = isDimensionStacked(data, valueDim + /*, baseDim*/ + ); + var isValueAxisH = valueAxis.isHorizontal(); + var valueAxisStart = getValueAxisStart(baseAxis, valueAxis, stacked); + + for (var idx = 0, len = data.count(); idx < len; idx++) { + var value = data.get(valueDim, idx); + var baseValue = data.get(baseDim, idx); // If dataZoom in filteMode: 'empty', the baseValue can be set as NaN in "axisProxy". + + if (isNaN(value) || isNaN(baseValue)) { + continue; + } + + var sign = value >= 0 ? 'p' : 'n'; + var baseCoord = valueAxisStart; // Because of the barMinHeight, we can not use the value in + // stackResultDimension directly. + + if (stacked) { + // Only ordinal axis can be stacked. + if (!lastStackCoords[stackId][baseValue]) { + lastStackCoords[stackId][baseValue] = { + p: valueAxisStart, + // Positive stack + n: valueAxisStart // Negative stack + + }; + } // Should also consider #4243 + + + baseCoord = lastStackCoords[stackId][baseValue][sign]; + } + + var x; + var y; + var width; + var height; + + if (isValueAxisH) { + var coord = cartesian.dataToPoint([value, baseValue]); + x = baseCoord; + y = coord[1] + columnOffset; + width = coord[0] - valueAxisStart; + height = columnWidth; + + if (Math.abs(width) < barMinHeight) { + width = (width < 0 ? -1 : 1) * barMinHeight; + } + + stacked && (lastStackCoords[stackId][baseValue][sign] += width); + } else { + var coord = cartesian.dataToPoint([baseValue, value]); + x = coord[0] + columnOffset; + y = baseCoord; + width = columnWidth; + height = coord[1] - valueAxisStart; + + if (Math.abs(height) < barMinHeight) { + // Include zero to has a positive bar + height = (height <= 0 ? -1 : 1) * barMinHeight; + } + + stacked && (lastStackCoords[stackId][baseValue][sign] += height); + } + + data.setItemLayout(idx, { + x: x, + y: y, + width: width, + height: height + }); + } + }, this); +} // TODO: Do not support stack in large mode yet. + +var largeLayout = { + seriesType: 'bar', + plan: createRenderPlanner(), + reset: function (seriesModel) { + if (!isOnCartesian(seriesModel) || !isInLargeMode(seriesModel)) { + return; + } + + var data = seriesModel.getData(); + var cartesian = seriesModel.coordinateSystem; + var baseAxis = cartesian.getBaseAxis(); + var valueAxis = cartesian.getOtherAxis(baseAxis); + var valueDim = data.mapDimension(valueAxis.dim); + var baseDim = data.mapDimension(baseAxis.dim); + var valueAxisHorizontal = valueAxis.isHorizontal(); + var valueDimIdx = valueAxisHorizontal ? 0 : 1; + var barWidth = retrieveColumnLayout(makeColumnLayout([seriesModel]), baseAxis, seriesModel).width; + + if (!(barWidth > LARGE_BAR_MIN_WIDTH)) { + // jshint ignore:line + barWidth = LARGE_BAR_MIN_WIDTH; + } + + return { + progress: progress + }; + + function progress(params, data) { + var count = params.count; + var largePoints = new LargeArr(count * 2); + var largeDataIndices = new LargeArr(count); + var dataIndex; + var coord = []; + var valuePair = []; + var pointsOffset = 0; + var idxOffset = 0; + + while ((dataIndex = params.next()) != null) { + valuePair[valueDimIdx] = data.get(valueDim, dataIndex); + valuePair[1 - valueDimIdx] = data.get(baseDim, dataIndex); + coord = cartesian.dataToPoint(valuePair, null, coord); // Data index might not be in order, depends on `progressiveChunkMode`. + + largePoints[pointsOffset++] = coord[0]; + largePoints[pointsOffset++] = coord[1]; + largeDataIndices[idxOffset++] = dataIndex; + } + + data.setLayout({ + largePoints: largePoints, + largeDataIndices: largeDataIndices, + barWidth: barWidth, + valueAxisStart: getValueAxisStart(baseAxis, valueAxis, false), + valueAxisHorizontal: valueAxisHorizontal + }); + } + } +}; + +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, stacked) { + return valueAxis.toGlobalCoord(valueAxis.dataToCoord(valueAxis.type === 'log' ? 1 : 0)); +} + +/* +* 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. +*/ + +/* +* A third-party license is embeded for some of the code in this file: +* The "scaleLevels" was originally copied from "d3.js" with some +* modifications made for this project. +* (See more details in the comment on the definition of "scaleLevels" below.) +* The use of the source code of this file is also subject to the terms +* and consitions of the license of "d3.js" (BSD-3Clause, see +* ). +*/ +// [About UTC and local time zone]: +// In most cases, `number.parseDate` will treat input data string as local time +// (except time zone is specified in time string). And `format.formateTime` returns +// local time by default. option.useUTC is false by default. This design have +// concidered these common case: +// (1) Time that is persistent in server is in UTC, but it is needed to be diplayed +// in local time by default. +// (2) By default, the input data string (e.g., '2011-01-02') should be displayed +// as its original time, without any time difference. +var intervalScaleProto = IntervalScale.prototype; +var mathCeil = Math.ceil; +var mathFloor = Math.floor; +var ONE_SECOND = 1000; +var ONE_MINUTE = ONE_SECOND * 60; +var ONE_HOUR = ONE_MINUTE * 60; +var ONE_DAY = ONE_HOUR * 24; // FIXME 公用? + +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; +}; +/** + * @alias module:echarts/coord/scale/Time + * @constructor + */ + + +var TimeScale = IntervalScale.extend({ + type: 'time', + + /** + * @override + */ + getLabel: function (val) { + var stepLvl = this._stepLvl; + var date = new Date(val); + return formatTime(stepLvl[0], date, this.getSetting('useUTC')); + }, + + /** + * @override + */ + niceExtent: 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.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval); // var extent = this._extent; + + var interval = this._interval; + + if (!opt.fixMin) { + extent[0] = round$1(mathFloor(extent[0] / interval) * interval); + } + + if (!opt.fixMax) { + extent[1] = round$1(mathCeil(extent[1] / interval) * interval); + } + }, + + /** + * @override + */ + niceTicks: function (approxTickNum, minInterval, maxInterval) { + approxTickNum = approxTickNum || 10; + var extent = this._extent; + var span = extent[1] - extent[0]; + var approxInterval = span / approxTickNum; + + if (minInterval != null && approxInterval < minInterval) { + approxInterval = minInterval; + } + + if (maxInterval != null && approxInterval > maxInterval) { + approxInterval = maxInterval; + } + + var scaleLevelsLen = scaleLevels.length; + var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen); + var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)]; + var interval = level[1]; // Same with interval scale if span is much larger than 1 year + + if (level[0] === 'year') { + var yearSpan = span / interval; // From "Nice Numbers for Graph Labels" of Graphic Gems + // var niceYearSpan = numberUtil.nice(yearSpan, false); + + var yearStep = nice(yearSpan / approxTickNum, true); + interval *= yearStep; + } + + var timezoneOffset = this.getSetting('useUTC') ? 0 : new Date(+extent[0] || +extent[1]).getTimezoneOffset() * 60 * 1000; + var niceExtent = [Math.round(mathCeil((extent[0] - timezoneOffset) / interval) * interval + timezoneOffset), Math.round(mathFloor((extent[1] - timezoneOffset) / interval) * interval + timezoneOffset)]; + fixExtent(niceExtent, extent); + this._stepLvl = level; // Interval will be used in getTicks + + this._interval = interval; + this._niceExtent = niceExtent; + }, + parse: function (val) { + // val might be float. + return +parseDate(val); + } +}); +each$1(['contain', 'normalize'], function (methodName) { + TimeScale.prototype[methodName] = function (val) { + return intervalScaleProto[methodName].call(this, this.parse(val)); + }; +}); +/** + * 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 scaleLevels = [// Format interval +['hh:mm:ss', ONE_SECOND], // 1s +['hh:mm:ss', ONE_SECOND * 5], // 5s +['hh:mm:ss', ONE_SECOND * 10], // 10s +['hh:mm:ss', ONE_SECOND * 15], // 15s +['hh:mm:ss', ONE_SECOND * 30], // 30s +['hh:mm\nMM-dd', ONE_MINUTE], // 1m +['hh:mm\nMM-dd', ONE_MINUTE * 5], // 5m +['hh:mm\nMM-dd', ONE_MINUTE * 10], // 10m +['hh:mm\nMM-dd', ONE_MINUTE * 15], // 15m +['hh:mm\nMM-dd', ONE_MINUTE * 30], // 30m +['hh:mm\nMM-dd', ONE_HOUR], // 1h +['hh:mm\nMM-dd', ONE_HOUR * 2], // 2h +['hh:mm\nMM-dd', ONE_HOUR * 6], // 6h +['hh:mm\nMM-dd', ONE_HOUR * 12], // 12h +['MM-dd\nyyyy', ONE_DAY], // 1d +['MM-dd\nyyyy', ONE_DAY * 2], // 2d +['MM-dd\nyyyy', ONE_DAY * 3], // 3d +['MM-dd\nyyyy', ONE_DAY * 4], // 4d +['MM-dd\nyyyy', ONE_DAY * 5], // 5d +['MM-dd\nyyyy', ONE_DAY * 6], // 6d +['week', ONE_DAY * 7], // 7d +['MM-dd\nyyyy', ONE_DAY * 10], // 10d +['week', ONE_DAY * 14], // 2w +['week', ONE_DAY * 21], // 3w +['month', ONE_DAY * 31], // 1M +['week', ONE_DAY * 42], // 6w +['month', ONE_DAY * 62], // 2M +['week', ONE_DAY * 70], // 10w +['quarter', ONE_DAY * 95], // 3M +['month', ONE_DAY * 31 * 4], // 4M +['month', ONE_DAY * 31 * 5], // 5M +['half-year', ONE_DAY * 380 / 2], // 6M +['month', ONE_DAY * 31 * 8], // 8M +['month', ONE_DAY * 31 * 10], // 10M +['year', ONE_DAY * 380] // 1Y +]; +/** + * @param {module:echarts/model/Model} + * @return {module:echarts/scale/Time} + */ + +TimeScale.create = function (model) { + return new TimeScale({ + useUTC: model.ecModel.get('useUTC') + }); +}; + +/* +* 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. +*/ + +/** + * Log scale + * @module echarts/scale/Log + */ +var scaleProto$1 = Scale.prototype; +var intervalScaleProto$1 = IntervalScale.prototype; +var getPrecisionSafe$1 = getPrecisionSafe; +var roundingErrorFix = round$1; +var mathFloor$1 = Math.floor; +var mathCeil$1 = Math.ceil; +var mathPow$1 = Math.pow; +var mathLog = Math.log; +var LogScale = Scale.extend({ + type: 'log', + base: 10, + $constructor: function () { + Scale.apply(this, arguments); + this._originalScale = new IntervalScale(); + }, + + /** + * @return {Array.} + */ + getTicks: function () { + var originalScale = this._originalScale; + var extent = this._extent; + var originalExtent = originalScale.getExtent(); + return map(intervalScaleProto$1.getTicks.call(this), function (val) { + var powVal = round$1(mathPow$1(this.base, val)); // Fix #4158 + + powVal = val === extent[0] && originalScale.__fixMin ? fixRoundingError(powVal, originalExtent[0]) : powVal; + powVal = val === extent[1] && originalScale.__fixMax ? fixRoundingError(powVal, originalExtent[1]) : powVal; + return powVal; + }, this); + }, + + /** + * @param {number} val + * @return {string} + */ + getLabel: intervalScaleProto$1.getLabel, + + /** + * @param {number} val + * @return {number} + */ + scale: function (val) { + val = scaleProto$1.scale.call(this, val); + return mathPow$1(this.base, val); + }, + + /** + * @param {number} start + * @param {number} end + */ + setExtent: function (start, end) { + var base = this.base; + start = mathLog(start) / mathLog(base); + end = mathLog(end) / mathLog(base); + intervalScaleProto$1.setExtent.call(this, start, end); + }, + + /** + * @return {number} end + */ + getExtent: function () { + var base = this.base; + var extent = scaleProto$1.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(); + originalScale.__fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0])); + originalScale.__fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1])); + return extent; + }, + + /** + * @param {Array.} extent + */ + 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$1.unionExtent.call(this, extent); + }, + + /** + * @override + */ + unionExtentFromData: function (data, dim) { + // TODO + // filter value that <= 0 + this.unionExtent(data.getApproximateExtent(dim)); + }, + + /** + * Update interval and extent of intervals for nice ticks + * @param {number} [approxTickNum = 10] Given approx tick number + */ + niceTicks: 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$1(mathCeil$1(extent[0] / interval) * interval), round$1(mathFloor$1(extent[1] / interval) * interval)]; + this._interval = interval; + this._niceExtent = niceExtent; + }, + + /** + * Nice extent. + * @override + */ + niceExtent: function (opt) { + intervalScaleProto$1.niceExtent.call(this, opt); + var originalScale = this._originalScale; + originalScale.__fixMin = opt.fixMin; + originalScale.__fixMax = opt.fixMax; + } +}); +each$1(['contain', 'normalize'], function (methodName) { + LogScale.prototype[methodName] = function (val) { + val = mathLog(val) / mathLog(this.base); + return scaleProto$1[methodName].call(this, val); + }; +}); + +LogScale.create = function () { + return new LogScale(); +}; + +function fixRoundingError(val, originalVal) { + return roundingErrorFix(val, getPrecisionSafe$1(originalVal)); +} + +/* +* 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. +*/ +/** + * Get axis scale extent before niced. + * Item of returned array can only be number (including Infinity and NaN). + */ + +function getScaleExtent(scale, model) { + var scaleType = scale.type; + var min = model.getMin(); + var max = model.getMax(); + var fixMin = min != null; + var fixMax = max != null; + var originalExtent = scale.getExtent(); + var axisDataLen; + var boundaryGap; + var span; + + if (scaleType === 'ordinal') { + axisDataLen = model.getCategories().length; + } else { + boundaryGap = model.get('boundaryGap'); + + if (!isArray(boundaryGap)) { + boundaryGap = [boundaryGap || 0, boundaryGap || 0]; + } + + if (typeof boundaryGap[0] === 'boolean') { + boundaryGap = [0, 0]; + } + + boundaryGap[0] = parsePercent$1(boundaryGap[0], 1); + boundaryGap[1] = parsePercent$1(boundaryGap[1], 1); + span = originalExtent[1] - originalExtent[0] || Math.abs(originalExtent[0]); + } // 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. + // FIXME + // (1) When min/max is 'dataMin' or 'dataMax', should boundaryGap be able to used? + // (2) When `needCrossZero` and all data is positive/negative, should it be ensured + // that the results processed by boundaryGap are positive/negative? + + + if (min == null) { + min = scaleType === 'ordinal' ? axisDataLen ? 0 : NaN : originalExtent[0] - boundaryGap[0] * span; + } + + if (max == null) { + max = scaleType === 'ordinal' ? axisDataLen ? axisDataLen - 1 : NaN : originalExtent[1] + boundaryGap[1] * span; + } + + if (min === 'dataMin') { + min = originalExtent[0]; + } else if (typeof min === 'function') { + min = min({ + min: originalExtent[0], + max: originalExtent[1] + }); + } + + if (max === 'dataMax') { + max = originalExtent[1]; + } else if (typeof max === 'function') { + max = max({ + min: originalExtent[0], + max: originalExtent[1] + }); + } + + (min == null || !isFinite(min)) && (min = NaN); + (max == null || !isFinite(max)) && (max = NaN); + scale.setBlank(eqNaN(min) || eqNaN(max) || scaleType === 'ordinal' && !scale.getOrdinalMeta().categories.length); // Evaluate if axis needs cross zero + + if (model.getNeedCrossZero()) { + // Axis is over zero and min is not set + if (min > 0 && max > 0 && !fixMin) { + min = 0; + } // Axis is under zero and max is not set + + + if (min < 0 && max < 0 && !fixMax) { + max = 0; + } + } // 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; + each$1(barSeriesModels, function (seriesModel) { + isBaseAxisAndHasBarSeries |= seriesModel.getBaseAxis() === model.axis; + }); + + if (isBaseAxisAndHasBarSeries) { + // Calculate placement of bars on axis + 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 [min, max]; +} + +function adjustScaleForOverflow(min, max, model, 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$1(barsOnCurrentAxis, function (item) { + minOverflow = Math.min(item.offset, minOverflow); + }); + var maxOverflow = -Infinity; + each$1(barsOnCurrentAxis, function (item) { + maxOverflow = Math.max(item.offset + item.width, maxOverflow); + }); + minOverflow = Math.abs(minOverflow); + maxOverflow = Math.abs(maxOverflow); + var totalOverFlow = minOverflow + maxOverflow; // Calulate 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 + }; +} + +function niceScaleExtent(scale, model) { + var extent = getScaleExtent(scale, model); + var fixMin = model.getMin() != null; + var fixMax = model.getMax() != null; + var splitNumber = model.get('splitNumber'); + + if (scale.type === 'log') { + scale.base = model.get('logBase'); + } + + var scaleType = scale.type; + scale.setExtent(extent[0], extent[1]); + scale.niceExtent({ + splitNumber: splitNumber, + fixMin: fixMin, + fixMax: fixMax, + minInterval: scaleType === 'interval' || scaleType === 'time' ? model.get('minInterval') : null, + maxInterval: scaleType === 'interval' || scaleType === 'time' ? 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 + + var interval = model.get('interval'); + + if (interval != null) { + scale.setInterval && scale.setInterval(interval); + } +} +/** + * @param {module:echarts/model/Model} model + * @param {string} [axisType] Default retrieve from model.type + * @return {module:echarts/scale/*} + */ + +function createScaleByModel(model, axisType) { + axisType = axisType || model.get('type'); + + if (axisType) { + switch (axisType) { + // Buildin scale + case 'category': + return new OrdinalScale(model.getOrdinalMeta ? model.getOrdinalMeta() : model.getCategories(), [Infinity, -Infinity]); + + case 'value': + return new IntervalScale(); + // Extended scale, like time and log + + default: + return (Scale.getClass(axisType) || IntervalScale).create(model); + } + } +} +/** + * Check if the axis corss 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 {module:echarts/coord/Axis} axis + * @return {Function} Label formatter function. + * param: {number} tickValue, + * param: {number} idx, the index in all ticks. + * If category axis, this param is not requied. + * return: {string} label string. + */ + +function makeLabelFormatter(axis) { + var labelFormatter = axis.getLabelModel().get('formatter'); + var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null; + + if (typeof labelFormatter === 'string') { + labelFormatter = function (tpl) { + return function (val) { + // For category axis, get raw value; for numeric axis, + // get foramtted label like '1,333,444'. + val = axis.scale.getLabel(val); + return tpl.replace('{value}', val != null ? val : ''); + }; + }(labelFormatter); // Consider empty array + + + return labelFormatter; + } else if (typeof labelFormatter === 'function') { + return function (tickValue, 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 = tickValue - categoryTickStart; + } + + return labelFormatter(getAxisRawValue(axis, tickValue), idx); + }; + } else { + return function (tick) { + return axis.scale.getLabel(tick); + }; + } +} +function getAxisRawValue(axis, value) { + // 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(value) : value; +} +/** + * @param {module:echarts/coord/Axis} axis + * @return {module:zrender/core/BoundingRect} 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 isCategory = axis.type === 'category'; + var realNumberScaleTicks; + var tickCount; + var categoryScaleExtent = scale.getExtent(); // Optimize for large category data, avoid call `getTicks()`. + + if (isCategory) { + 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 tickValue = realNumberScaleTicks ? realNumberScaleTicks[i] : categoryScaleExtent[0] + i; + var label = labelFormatter(tickValue); + 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 boundingBox = textRect.plain(); + var beforeWidth = boundingBox.width; + var beforeHeight = boundingBox.height; + var afterWidth = beforeWidth * Math.cos(rotateRadians) + beforeHeight * Math.sin(rotateRadians); + var afterHeight = beforeWidth * Math.sin(rotateRadians) + beforeHeight * Math.cos(rotateRadians); + var rotatedRect = new BoundingRect(boundingBox.x, boundingBox.y, afterWidth, afterHeight); + return rotatedRect; +} +/** + * @param {module:echarts/src/model/Model} 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 + * @return {boolean} + */ + +function shouldShowAllLabels(axis) { + return axis.type === 'category' && getOptionCategoryInterval(axis.getLabelModel()) === 0; +} + +/* +* 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 axisModelCommonMixin = { + /** + * @param {boolean} origin + * @return {number|string} min value or 'dataMin' or null/undefined (means auto) or NaN + */ + getMin: function (origin) { + var option = this.option; + var min = !origin && option.rangeStart != null ? option.rangeStart : option.min; + + if (this.axis && min != null && min !== 'dataMin' && typeof min !== 'function' && !eqNaN(min)) { + min = this.axis.scale.parse(min); + } + + return min; + }, + + /** + * @param {boolean} origin + * @return {number|string} max value or 'dataMax' or null/undefined (means auto) or NaN + */ + getMax: function (origin) { + var option = this.option; + var max = !origin && option.rangeEnd != null ? option.rangeEnd : option.max; + + if (this.axis && max != null && max !== 'dataMax' && typeof max !== 'function' && !eqNaN(max)) { + max = this.axis.scale.parse(max); + } + + return max; + }, + + /** + * @return {boolean} + */ + getNeedCrossZero: function () { + var option = this.option; + return option.rangeStart != null || option.rangeEnd != null ? false : !option.scale; + }, + + /** + * Should be implemented by each axis model if necessary. + * @return {module:echarts/model/Component} coordinate system model + */ + getCoordSysModel: noop, + + /** + * @param {number} rangeStart Can only be finite number or null/undefined or NaN. + * @param {number} rangeEnd Can only be finite number or null/undefined or NaN. + */ + setRange: function (rangeStart, rangeEnd) { + this.option.rangeStart = rangeStart; + this.option.rangeEnd = rangeEnd; + }, + + /** + * Reset range + */ + resetRange: function () { + // rangeStart and rangeEnd is readonly. + this.option.rangeStart = this.option.rangeEnd = 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. +*/ +// Symbol factory +/** + * Triangle shape + * @inner + */ + +var Triangle = extendShape({ + 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 = extendShape({ + 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 = extendShape({ + 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 = extendShape({ + 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 + * @type {Object.} + */ + +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) { + // FIXME + 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$1(symbolCtors, function (Ctor, name) { + symbolBuildProxies[name] = new Ctor(); +}); +var SymbolClz = extendShape({ + type: 'symbol', + shape: { + symbolType: '', + x: 0, + y: 0, + width: 0, + height: 0 + }, + calculateTextPosition: function (out, style, rect) { + var res = calculateTextPosition(out, style, rect); + var shape = this.shape; + + if (shape && shape.symbolType === 'pin' && style.textPosition === '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; + var symbolShape = this.shape; + + if (symbolShape && symbolShape.symbolType === 'line') { + symbolStyle.stroke = color; + } else if (this.__isEmptyBrush) { + symbolStyle.stroke = color; + symbolStyle.fill = innerColor || '#fff'; + } else { + // FIXME 判断图形默认是填充还是描边,使用 onlyStroke ? + symbolStyle.fill && (symbolStyle.fill = color); + symbolStyle.stroke && (symbolStyle.stroke = color); + } + + this.dirty(false); + } +} +/** + * Create a symbol element with given symbol configuration: shape, x, y, width, height, color + * @param {string} symbolType + * @param {number} x + * @param {number} y + * @param {number} w + * @param {number} h + * @param {string} color + * @param {boolean} [keepAspect=false] whether to keep the ratio of w/h, + * for path and image only. + */ + + +function createSymbol(symbolType, x, y, w, h, color, 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; + symbolPath.setColor = symbolPathSetColor; + symbolPath.setColor(color); + return symbolPath; +} + +/* +* 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. +*/ +/** + * Create a muti dimension List structure from seriesModel. + * @param {module:echarts/model/Model} seriesModel + * @return {module:echarts/data/List} list + */ + +function createList(seriesModel) { + return createListFromArray(seriesModel.getSource(), 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 + */ + +function createScale(dataExtent, option) { + var axisModel = option; + + if (!Model.isInstance(option)) { + axisModel = new Model(option); + 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` + * `setRange(start: number, end: number)` + * `resetRange()` + */ + +function mixinAxisModelCommonMethods(Model$$1) { + mixin(Model$$1, axisModelCommonMixin); +} + +var helper = (Object.freeze || Object)({ + createList: createList, + getLayoutRect: getLayoutRect, + dataStack: dataStack$1, + createScale: createScale, + mixinAxisModelCommonMethods: mixinAxisModelCommonMethods, + completeDimensions: completeDimensions, + createDimensions: createDimensions, + createSymbol: createSymbol +}); + +var EPSILON$3 = 1e-8; + +function isAroundEqual$1(a, b) { + return Math.abs(a - b) < EPSILON$3; +} + +function contain$1(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; + } // Close polygon + + + 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; +} + +/* +* 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. +*/ + +/** + * @module echarts/coord/geo/Region + */ +/** + * @param {string|Region} name + * @param {Array} geometries + * @param {Array.} cp + */ + +function Region(name, geometries, cp) { + /** + * @type {string} + * @readOnly + */ + this.name = name; + /** + * @type {Array.} + * @readOnly + */ + + this.geometries = geometries; + + if (!cp) { + var rect = this.getBoundingRect(); + cp = [rect.x + rect.width / 2, rect.y + rect.height / 2]; + } else { + cp = [cp[0], cp[1]]; + } + /** + * @type {Array.} + */ + + + this.center = cp; +} + +Region.prototype = { + constructor: Region, + properties: null, + + /** + * @return {module:zrender/core/BoundingRect} + */ + getBoundingRect: function () { + var rect = this._rect; + + if (rect) { + return rect; + } + + var MAX_NUMBER = Number.MAX_VALUE; + var min$$1 = [MAX_NUMBER, MAX_NUMBER]; + var max$$1 = [-MAX_NUMBER, -MAX_NUMBER]; + var min2 = []; + var max2 = []; + var geometries = this.geometries; + + for (var i = 0; i < geometries.length; i++) { + // Only support polygon + if (geometries[i].type !== 'polygon') { + continue; + } // Doesn't consider hole + + + var exterior = geometries[i].exterior; + fromPoints(exterior, min2, max2); + min(min$$1, min$$1, min2); + max(max$$1, max$$1, max2); + } // No data + + + if (i === 0) { + min$$1[0] = min$$1[1] = max$$1[0] = max$$1[1] = 0; + } + + return this._rect = new BoundingRect(min$$1[0], min$$1[1], max$$1[0] - min$$1[0], max$$1[1] - min$$1[1]); + }, + + /** + * @param {} coord + * @return {boolean} + */ + 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$$1 = geometries.length; i < len$$1; i++) { + // Only support polygon. + if (geometries[i].type !== 'polygon') { + continue; + } + + var exterior = geometries[i].exterior; + var interiors = geometries[i].interiors; + + if (contain$1(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$1(interiors[k])) { + continue loopGeo; + } + } + + return true; + } + } + + return false; + }, + 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++) { + // Only support polygon. + if (geometries[i].type !== 'polygon') { + continue; + } + + var exterior = geometries[i].exterior; + var interiors = geometries[i].interiors; + + for (var p = 0; p < exterior.length; p++) { + applyTransform(exterior[p], exterior[p], transform); + } + + for (var h = 0; h < (interiors ? interiors.length : 0); h++) { + for (var p = 0; p < interiors[h].length; p++) { + applyTransform(interiors[h][p], interiors[h][p], transform); + } + } + } + + rect = this._rect; + rect.copy(target); // Update center + + this.center = [rect.x + rect.width / 2, rect.y + rect.height / 2]; + }, + cloneShallow: function (name) { + name == null && (name = this.name); + var newRegion = new Region(name, this.geometries, this.center); + newRegion._rect = this._rect; + newRegion.transformTo = null; // Simply avoid to be called. + + return newRegion; + } +}; + +/* +* 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. +*/ + +/** + * Parse and decode geo json + * @module echarts/coord/geo/parseGeoJson + */ +function decode(json) { + if (!json.UTF8Encoding) { + return json; + } + + var encodeScale = json.UTF8Scale; + + if (encodeScale == null) { + encodeScale = 1024; + } + + var features = json.features; + + for (var f = 0; f < features.length; f++) { + var feature = features[f]; + var geometry = feature.geometry; + var coordinates = geometry.coordinates; + var encodeOffsets = geometry.encodeOffsets; + + for (var c = 0; c < coordinates.length; c++) { + var coordinate = coordinates[c]; + + if (geometry.type === 'Polygon') { + coordinates[c] = decodePolygon(coordinate, encodeOffsets[c], encodeScale); + } else if (geometry.type === 'MultiPolygon') { + for (var c2 = 0; c2 < coordinate.length; c2++) { + var polygon = coordinate[c2]; + coordinate[c2] = decodePolygon(polygon, encodeOffsets[c][c2], encodeScale); + } + } + } + } // Has been decoded + + + json.UTF8Encoding = false; + return json; +} + +function decodePolygon(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; +} +/** + * @alias module:echarts/coord/geo/parseGeoJson + * @param {Object} geoJson + * @return {module:zrender/container/Group} + */ + + +var parseGeoJSON = function (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 coordinates = geo.coordinates; + var geometries = []; + + if (geo.type === 'Polygon') { + geometries.push({ + type: 'polygon', + // According to the GeoJSON specification. + // First must be exterior, and the rest are all interior(holes). + exterior: coordinates[0], + interiors: coordinates.slice(1) + }); + } + + if (geo.type === 'MultiPolygon') { + each$1(coordinates, function (item) { + if (item[0]) { + geometries.push({ + type: 'polygon', + exterior: item[0], + interiors: item.slice(1) + }); + } + }); + } + + var region = new Region(properties.name, geometries, properties.cp); + region.properties = properties; + return region; + }); +}; + +/* +* 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 inner$6 = makeInner(); +/** + * @param {module:echats/coord/Axis} axis + * @return {Object} { + * labels: [{ + * formattedLabel: string, + * rawLabel: string, + * tickValue: number + * }, ...], + * labelCategoryInterval: number + * } + */ + +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: axis.scale.getTicks() + }; +} + +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$1(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$1(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 (tickValue, idx) { + return { + formattedLabel: labelFormatter(tickValue, idx), + rawLabel: axis.scale.getLabel(tickValue), + tickValue: tickValue + }; + }) + }; +} // Large category data calculation is performence sensitive, and ticks and label +// probably be fetched by multiple times. So we cache the result. +// axis is created each time during a ec process, so we do not need to clear cache. + + +function getListCache(axis, prop) { + // Because key can be funciton, and cache size always be small, we use array cache. + return inner$6(axis)[prop] || (inner$6(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$6(axis).autoInterval; + return result != null ? result : inner$6(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(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$6(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.axisExtend0 === axisExtent[0] && cache.axisExtend1 === 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.axisExtend0 = axisExtent[0]; + cache.axisExtend1 = 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(tVal) { + result.push(onlyTick ? tVal : { + formattedLabel: labelFormatter(tVal), + rawLabel: ordinalScale.getLabel(tVal), + tickValue: tVal + }); + } + + return result; +} // When interval is function, the result `false` means ignore the tick. +// It is time consuming for large category data. + + +function makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) { + var ordinalScale = axis.scale; + var labelFormatter = makeLabelFormatter(axis); + var result = []; + each$1(ordinalScale.getTicks(), function (tickValue) { + var rawLabel = ordinalScale.getLabel(tickValue); + + if (categoryInterval(tickValue, rawLabel)) { + result.push(onlyTick ? tickValue : { + formattedLabel: labelFormatter(tickValue), + rawLabel: rawLabel, + tickValue: tickValue + }); + } + }); + return result; +} + +/* +* 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 NORMALIZED_EXTENT = [0, 1]; +/** + * Base class of Axis. + * @constructor + */ + +var Axis = function (dim, scale, extent) { + /** + * Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius'. + * @type {string} + */ + this.dim = dim; + /** + * Axis scale + * @type {module:echarts/coord/scale/*} + */ + + this.scale = scale; + /** + * @type {Array.} + * @private + */ + + this._extent = extent || [0, 0]; + /** + * @type {boolean} + */ + + this.inverse = false; + /** + * Usually true when axis has a ordinal scale + * @type {boolean} + */ + + this.onBand = false; +}; + +Axis.prototype = { + constructor: Axis, + + /** + * If axis extent contain given coord + * @param {number} coord + * @return {boolean} + */ + 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 + * @param {number} data + * @return {boolean} + */ + containData: function (data) { + return this.contain(this.dataToCoord(data)); + }, + + /** + * Get coord extent. + * @return {Array.} + */ + getExtent: function () { + return this._extent.slice(); + }, + + /** + * Get precision used for formatting + * @param {Array.} [dataExtent] + * @return {number} + */ + getPixelPrecision: function (dataExtent) { + return getPixelPrecision(dataExtent || this.scale.getExtent(), this._extent); + }, + + /** + * Set coord extent + * @param {number} start + * @param {number} end + */ + 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 + * @param {number} data + * @param {boolean} clamp + * @return {number} + */ + 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 + * @param {number} coord + * @param {boolean} clamp + * @return {number} + */ + 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 + * @param {Array.} point + * @param {boolean} clamp + * @return {number} data + */ + pointToData: function (point, clamp) {// Should be implemented in derived class if necessary. + }, + + /** + * 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 {Object} [opt] + * @param {number} [opt.tickModel=axis.model.getModel('axisTick')] + * @param {boolean} [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. + * @return {Array.} [{ + * coord: ..., + * tickValue: ... + * }, ...] + */ + 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 (tickValue) { + return { + coord: this.dataToCoord(tickValue), + tickValue: tickValue + }; + }, this); + var alignWithLabel = tickModel.get('alignWithLabel'); + fixOnBandTicksCoords(this, ticksCoords, alignWithLabel, opt.clamp); + return ticksCoords; + }, + + /** + * @return {Array.} [{ + * formattedLabel: string, + * rawLabel: axis.scale.getLabel(tickValue) + * tickValue: number + * }, ...] + */ + getViewLabels: function () { + return createAxisLabels(this).labels; + }, + + /** + * @return {module:echarts/coord/model/Model} + */ + 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'));` + * @return {module:echarts/coord/model/Model} + */ + getTickModel: function () { + return this.model.getModel('axisTick'); + }, + + /** + * Get width of band + * @return {number} + */ + 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; + }, + + /** + * @abstract + * @return {boolean} Is horizontal + */ + isHorizontal: null, + + /** + * @abstract + * @return {number} Get axis rotate, by degree. + */ + getRotate: null, + + /** + * Only be called in category axis. + * Can be overrided, consider other axes like in 3D. + * @return {number} Auto interval for cateogry axis tick and label + */ + calculateCategoryInterval: function () { + return calculateCategoryInterval(this); + } +}; + +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 = (ticksCoords[ticksLen - 1].coord - ticksCoords[0].coord) / crossLen; + each$1(ticksCoords, function (ticksItem) { + ticksItem.coord -= shift / 2; + }); + var dataExtent = axis.scale.getExtent(); + diffSize = 1 + dataExtent[1] - ticksCoords[ticksLen - 1].tickValue; + last = { + coord: ticksCoords[ticksLen - 1].coord + shift * 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$1(a); + b = round$1(b); + return inverse ? a > b : a < b; + } +} + +/* +* 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. +*/ + +/** + * Do not mount those modules on 'src/echarts' for better tree shaking. + */ +var parseGeoJson = parseGeoJSON; +var ecUtil = {}; +each$1(['map', 'each', 'filter', 'indexOf', 'inherits', 'reduce', 'filter', 'bind', 'curry', 'isArray', 'isString', 'isObject', 'isFunction', 'extend', 'defaults', 'clone', 'merge'], function (name) { + ecUtil[name] = zrUtil[name]; +}); +var graphic$1 = {}; +each$1(['extendShape', 'extendPath', 'makePath', 'makeImage', 'mergePath', 'resizePath', 'createIcon', 'setHoverStyle', 'setLabelStyle', 'setTextStyle', 'setText', 'getFont', 'updateProps', 'initProps', 'getTransform', 'clipPointsByRect', 'clipRectByRect', 'registerShape', 'getShapeClass', 'Group', 'Image', 'Text', 'Circle', 'Sector', 'Ring', 'Polygon', 'Polyline', 'Rect', 'Line', 'BezierCurve', 'Arc', 'IncrementalDisplayable', 'CompoundPath', 'LinearGradient', 'RadialGradient', 'BoundingRect'], function (name) { + graphic$1[name] = graphic[name]; +}); + +/* +* 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. +*/ + +/** + * Cartesian coordinate system + * @module echarts/coord/Cartesian + * + */ +function dimAxisMapper(dim) { + return this._axes[dim]; +} +/** + * @alias module:echarts/coord/Cartesian + * @constructor + */ + + +var Cartesian = function (name) { + this._axes = {}; + this._dimList = []; + /** + * @type {string} + */ + + this.name = name || ''; +}; + +Cartesian.prototype = { + constructor: Cartesian, + type: 'cartesian', + + /** + * Get axis + * @param {number|string} dim + * @return {module:echarts/coord/Cartesian~Axis} + */ + getAxis: function (dim) { + return this._axes[dim]; + }, + + /** + * Get axes list + * @return {Array.} + */ + getAxes: function () { + return map(this._dimList, dimAxisMapper, this); + }, + + /** + * Get axes list by given scale type + */ + getAxesByScale: function (scaleType) { + scaleType = scaleType.toLowerCase(); + return filter(this.getAxes(), function (axis) { + return axis.scale.type === scaleType; + }); + }, + + /** + * Add axis + * @param {module:echarts/coord/Cartesian.Axis} + */ + addAxis: function (axis) { + var dim = axis.dim; + this._axes[dim] = axis; + + this._dimList.push(dim); + }, + + /** + * Convert data to coord in nd space + * @param {Array.|Object.} val + * @return {Array.|Object.} + */ + dataToCoord: function (val) { + return this._dataCoordConvert(val, 'dataToCoord'); + }, + + /** + * Convert coord in nd space to data + * @param {Array.|Object.} val + * @return {Array.|Object.} + */ + coordToData: function (val) { + return this._dataCoordConvert(val, 'coordToData'); + }, + _dataCoordConvert: function (input, method) { + var dimList = this._dimList; + var output = input instanceof Array ? [] : {}; + + for (var i = 0; i < dimList.length; i++) { + var dim = dimList[i]; + var axis = this._axes[dim]; + output[dim] = axis[method](input[dim]); + } + + return output; + } +}; + +/* +* 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 Cartesian2D(name) { + Cartesian.call(this, name); +} + +Cartesian2D.prototype = { + constructor: Cartesian2D, + type: 'cartesian2d', + + /** + * @type {Array.} + * @readOnly + */ + dimensions: ['x', 'y'], + + /** + * Base axis will be used on stacking. + * + * @return {module:echarts/coord/cartesian/Axis2D} + */ + getBaseAxis: function () { + return this.getAxesByScale('ordinal')[0] || this.getAxesByScale('time')[0] || this.getAxis('x'); + }, + + /** + * If contain point + * @param {Array.} point + * @return {boolean} + */ + 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])); + }, + + /** + * If contain data + * @param {Array.} data + * @return {boolean} + */ + containData: function (data) { + return this.getAxis('x').containData(data[0]) && this.getAxis('y').containData(data[1]); + }, + + /** + * @param {Array.} data + * @param {Array.} out + * @return {Array.} + */ + dataToPoint: function (data, reserved, out) { + var xAxis = this.getAxis('x'); + var yAxis = this.getAxis('y'); + out = out || []; + out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(data[0])); + out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(data[1])); + return out; + }, + + /** + * @param {Array.} data + * @param {Array.} out + * @return {Array.} + */ + 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; + }, + + /** + * @param {Array.} point + * @param {Array.} out + * @return {Array.} + */ + pointToData: function (point, out) { + var xAxis = this.getAxis('x'); + var yAxis = this.getAxis('y'); + out = out || []; + out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0])); + out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1])); + return out; + }, + + /** + * Get other axis + * @param {module:echarts/coord/cartesian/Axis2D} axis + */ + 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. + * @return {BoundingRect} + */ + 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; + var rect = new BoundingRect(x, y, width, height); + return rect; + } +}; +inherits(Cartesian2D, Cartesian); + +/* +* 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. +*/ +/** + * Extend axis 2d + * @constructor module:echarts/coord/cartesian/Axis2D + * @extends {module:echarts/coord/cartesian/Axis} + * @param {string} dim + * @param {*} scale + * @param {Array.} coordExtent + * @param {string} axisType + * @param {string} position + */ + +var Axis2D = function (dim, scale, coordExtent, axisType, position) { + Axis.call(this, dim, scale, coordExtent); + /** + * Axis type + * - 'category' + * - 'value' + * - 'time' + * - 'log' + * @type {string} + */ + + this.type = axisType || 'value'; + /** + * Axis position + * - 'top' + * - 'bottom' + * - 'left' + * - 'right' + */ + + this.position = position || 'bottom'; +}; + +Axis2D.prototype = { + constructor: Axis2D, + + /** + * Index of axis, can be used as key + */ + index: 0, + + /** + * Implemented in . + * @return {Array.} + * If not on zero of other axis, return null/undefined. + * If no axes, return an empty array. + */ + getAxesOnZeroOf: null, + + /** + * Axis model + * @param {module:echarts/coord/cartesian/AxisModel} + */ + model: null, + 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.} + */ + 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; + }, + getOtherAxis: function () { + this.grid.getOtherAxis(); + }, + + /** + * @override + */ + pointToData: function (point, clamp) { + return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp); + }, + + /** + * Transform global coord to local coord, + * i.e. var localCoord = axis.toLocalCoord(80); + * designate by module:echarts/coord/cartesian/Grid. + * @type {Function} + */ + toLocalCoord: null, + + /** + * Transform global coord to local coord, + * i.e. var globalCoord = axis.toLocalCoord(40); + * designate by module:echarts/coord/cartesian/Grid. + * @type {Function} + */ + toGlobalCoord: null +}; +inherits(Axis2D, 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. +*/ +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 defualt 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: '#333', + 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: ['#ccc'], + width: 1, + type: 'solid' + } + }, + splitArea: { + show: false, + areaStyle: { + color: ['rgba(250,250,250,0.3)', 'rgba(200,200,200,0.3)'] + } + } +}; +var axisDefault = {}; +axisDefault.categoryAxis = merge({ + // The gap at both ends of the axis. For categoryAxis, boolean. + boundaryGap: true, + // Set false to faster category collection. + // Only usefull in the case like: category is + // ['2012-01-01', '2012-01-02', ...], where the input + // data has been ensured not duplicate and is large data. + // null means "auto": + // if axis.data provided, do not deduplication, + // else do deduplication. + 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); +axisDefault.valueAxis = merge({ + // The gap at both ends of the axis. For value axis, [GAP, GAP], where + // `GAP` can be an absolute pixel number (like `35`), or percent (like `'30%'`) + boundaryGap: [0, 0], + // TODO + // min/max: [30, datamin, 60] or [20, datamin] or [datamin, 60] + // Min value of the axis. can be: + // + a number + // + 'dataMin': use the min value in data. + // + null/undefined: auto decide min value (consider pretty look and boundaryGap). + // min: null, + // Max value of the axis. can be: + // + a number + // + 'dataMax': use the max value in data. + // + null/undefined: auto decide max value (consider pretty look and boundaryGap). + // max: null, + // Readonly prop, specifies start value of the range when using data zoom. + // rangeStart: null + // Readonly prop, specifies end value of the range when using data zoom. + // rangeEnd: null + // Optional value can be: + // + `false`: always include value 0. + // + `true`: the extent do not consider value 0. + // scale: false, + // AxisTick and axisLabel and splitLine are caculated based on splitNumber. + splitNumber: 5 // Interval specifies the span of the ticks is mandatorily. + // interval: null + // Specify min interval when auto calculate tick interval. + // minInterval: null + // Specify max interval when auto calculate tick interval. + // maxInterval: null + +}, defaultOption); +axisDefault.timeAxis = defaults({ + scale: true, + min: 'dataMin', + max: 'dataMax' +}, axisDefault.valueAxis); +axisDefault.logAxis = defaults({ + scale: true, + logBase: 10 +}, axisDefault.valueAxis); + +/* +* 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', 'category', 'time', 'log']; +/** + * Generate sub axis model class + * @param {string} axisName 'x' 'y' 'radius' 'angle' 'parallel' + * @param {module:echarts/model/Component} BaseAxisModelClass + * @param {Function} axisTypeDefaulter + * @param {Object} [extraDefaultOption] + */ + +var axisModelCreator = function (axisName, BaseAxisModelClass, axisTypeDefaulter, extraDefaultOption) { + each$1(AXIS_TYPES, function (axisType) { + BaseAxisModelClass.extend({ + /** + * @readOnly + */ + type: axisName + 'Axis.' + axisType, + mergeDefaultAndTheme: function (option, ecModel) { + var layoutMode = this.layoutMode; + var inputPositionParams = layoutMode ? getLayoutParams(option) : {}; + var themeModel = ecModel.getTheme(); + merge(option, themeModel.get(axisType + 'Axis')); + merge(option, this.getDefaultOption()); + option.type = axisTypeDefaulter(axisName, option); + + if (layoutMode) { + mergeLayoutParam(option, inputPositionParams, layoutMode); + } + }, + + /** + * @override + */ + 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. + */ + 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; + } + }, + getOrdinalMeta: function () { + return this.__ordinalMeta; + }, + defaultOption: mergeAll([{}, axisDefault[axisType + 'Axis'], extraDefaultOption], true) + }); + }); + ComponentModel.registerSubTypeDefaulter(axisName + 'Axis', curry(axisTypeDefaulter, axisName)); +}; + +/* +* 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 AxisModel = ComponentModel.extend({ + type: 'cartesian2dAxis', + + /** + * @type {module:echarts/coord/cartesian/Axis2D} + */ + axis: null, + + /** + * @override + */ + init: function () { + AxisModel.superApply(this, 'init', arguments); + this.resetRange(); + }, + + /** + * @override + */ + mergeOption: function () { + AxisModel.superApply(this, 'mergeOption', arguments); + this.resetRange(); + }, + + /** + * @override + */ + restoreData: function () { + AxisModel.superApply(this, 'restoreData', arguments); + this.resetRange(); + }, + + /** + * @override + * @return {module:echarts/model/Component} + */ + getCoordSysModel: function () { + return this.ecModel.queryComponents({ + mainType: 'grid', + index: this.option.gridIndex, + id: this.option.gridId + })[0]; + } +}); + +function getAxisType(axisDim, option) { + // Default axis with data is category axis + return option.type || (option.data ? 'category' : 'value'); +} + +merge(AxisModel.prototype, axisModelCommonMixin); +var extraOption = { + // gridIndex: 0, + // gridId: '', + // Offset is for multiple axis on the same position + offset: 0 +}; +axisModelCreator('x', AxisModel, getAxisType, extraOption); +axisModelCreator('y', AxisModel, getAxisType, extraOption); + +/* +* 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. +*/ +// Grid 是在有直角坐标系的时候必须要存在的 +// 所以这里也要被 Cartesian2D 依赖 +ComponentModel.extend({ + type: 'grid', + dependencies: ['xAxis', 'yAxis'], + layoutMode: 'box', + + /** + * @type {module:echarts/coord/cartesian/Grid} + */ + coordinateSystem: null, + defaultOption: { + show: false, + zlevel: 0, + z: 0, + left: '10%', + top: 60, + right: '10%', + bottom: 60, + // 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' + } +}); + +/* +* 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. +*/ + +/** + * Grid is a region which contains at most 4 cartesian systems + * + * TODO Default cartesian + */ +/** + * Check if the axis is used in the specified grid + * @inner + */ + +function isAxisUsedInTheGrid(axisModel, gridModel, ecModel) { + return axisModel.getCoordSysModel() === gridModel; +} + +function Grid(gridModel, ecModel, api) { + /** + * @type {Object.} + * @private + */ + this._coordsMap = {}; + /** + * @type {Array.} + * @private + */ + + this._coordsList = []; + /** + * @type {Object.>} + * @private + */ + + this._axesMap = {}; + /** + * @type {Array.} + * @private + */ + + this._axesList = []; + + this._initCartesian(gridModel, ecModel, api); + + this.model = gridModel; +} + +var gridProto = Grid.prototype; +gridProto.type = 'grid'; +gridProto.axisPointerEnabled = true; + +gridProto.getRect = function () { + return this._rect; +}; + +gridProto.update = function (ecModel, api) { + var axesMap = this._axesMap; + + this._updateScale(ecModel, this.model); + + each$1(axesMap.x, function (xAxis) { + niceScaleExtent(xAxis.scale, xAxis.model); + }); + each$1(axesMap.y, function (yAxis) { + niceScaleExtent(yAxis.scale, yAxis.model); + }); // Key: axisDim_axisIndex, value: boolean, whether onZero target. + + var onZeroRecords = {}; + each$1(axesMap.x, function (xAxis) { + fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords); + }); + each$1(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); +}; + +function fixAxisOnZero(axesMap, otherAxisDim, axis, 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); +} +/** + * Resize the grid + * @param {module:echarts/coord/cartesian/GridModel} gridModel + * @param {module:echarts/ExtensionAPI} api + */ + + +gridProto.resize = function (gridModel, api, ignoreContainLabel) { + var gridRect = getLayoutRect(gridModel.getBoxLayoutParams(), { + width: api.getWidth(), + height: api.getHeight() + }); + this._rect = gridRect; + var axesList = this._axesList; + adjustAxes(); // Minus label size + + if (!ignoreContainLabel && gridModel.get('containLabel')) { + each$1(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(); + } + + function adjustAxes() { + each$1(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); + }); + } +}; +/** + * @param {string} axisType + * @param {number} [axisIndex] + */ + + +gridProto.getAxis = function (axisType, axisIndex) { + var axesMapOnDim = this._axesMap[axisType]; + + if (axesMapOnDim != null) { + if (axisIndex == null) { + // Find first axis + for (var name in axesMapOnDim) { + if (axesMapOnDim.hasOwnProperty(name)) { + return axesMapOnDim[name]; + } + } + } + + return axesMapOnDim[axisIndex]; + } +}; +/** + * @return {Array.} + */ + + +gridProto.getAxes = function () { + return this._axesList.slice(); +}; +/** + * Usage: + * grid.getCartesian(xAxisIndex, yAxisIndex); + * grid.getCartesian(xAxisIndex); + * grid.getCartesian(null, yAxisIndex); + * grid.getCartesian({xAxisIndex: ..., yAxisIndex: ...}); + * + * @param {number|Object} [xAxisIndex] + * @param {number} [yAxisIndex] + */ + + +gridProto.getCartesian = function (xAxisIndex, yAxisIndex) { + if (xAxisIndex != null && yAxisIndex != null) { + var key = 'x' + xAxisIndex + 'y' + yAxisIndex; + return this._coordsMap[key]; + } + + if (isObject$1(xAxisIndex)) { + yAxisIndex = xAxisIndex.yAxisIndex; + xAxisIndex = xAxisIndex.xAxisIndex; + } // When only xAxisIndex or yAxisIndex given, find its first cartesian. + + + 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]; + } + } +}; + +gridProto.getCartesians = function () { + return this._coordsList.slice(); +}; +/** + * @implements + * see {module:echarts/CoodinateSystem} + */ + + +gridProto.convertToPixel = function (ecModel, finder, value) { + var target = this._findConvertTarget(ecModel, finder); + + return target.cartesian ? target.cartesian.dataToPoint(value) : target.axis ? target.axis.toGlobalCoord(target.axis.dataToCoord(value)) : null; +}; +/** + * @implements + * see {module:echarts/CoodinateSystem} + */ + + +gridProto.convertFromPixel = function (ecModel, finder, value) { + var target = this._findConvertTarget(ecModel, finder); + + return target.cartesian ? target.cartesian.pointToData(value) : target.axis ? target.axis.coordToData(target.axis.toLocalCoord(value)) : null; +}; +/** + * @inner + */ + + +gridProto._findConvertTarget = function (ecModel, finder) { + var seriesModel = finder.seriesModel; + var xAxisModel = finder.xAxisModel || seriesModel && seriesModel.getReferringComponents('xAxis')[0]; + var yAxisModel = finder.yAxisModel || seriesModel && seriesModel.getReferringComponents('yAxis')[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 + * see {module:echarts/CoodinateSystem} + */ + + +gridProto.containPoint = function (point) { + var coord = this._coordsList[0]; + + if (coord) { + return coord.containPoint(point); + } +}; +/** + * Initialize cartesian coordinate systems + * @private + */ + + +gridProto._initCartesian = function (gridModel, ecModel, api) { + 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$1(axesMap.x, function (xAxis, xAxisIndex) { + each$1(axesMap.y, function (yAxis, yAxisIndex) { + var key = 'x' + xAxisIndex + 'y' + yAxisIndex; + var cartesian = new Cartesian2D(key); + cartesian.grid = this; + cartesian.model = gridModel; + this._coordsMap[key] = cartesian; + + this._coordsList.push(cartesian); + + cartesian.addAxis(xAxis); + cartesian.addAxis(yAxis); + }, this); + }, this); + + function createAxisCreator(axisType) { + return function (axisModel, idx) { + if (!isAxisUsedInTheGrid(axisModel, gridModel, ecModel)) { + return; + } + + var axisPosition = axisModel.get('position'); + + if (axisType === '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(axisType, 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 = this; // Index of axis, can be used as key + + axis.index = idx; + + this._axesList.push(axis); + + axesMap[axisType][idx] = axis; + axesCount[axisType]++; + }; + } +}; +/** + * Update cartesian properties from series + * @param {module:echarts/model/Option} option + * @private + */ + + +gridProto._updateScale = function (ecModel, gridModel) { + // Reset scale + each$1(this._axesList, function (axis) { + axis.scale.setExtent(Infinity, -Infinity); + }); + ecModel.eachSeries(function (seriesModel) { + if (isCartesian2D(seriesModel)) { + var axesModels = findAxesModels(seriesModel, ecModel); + var xAxisModel = axesModels[0]; + var yAxisModel = axesModels[1]; + + if (!isAxisUsedInTheGrid(xAxisModel, gridModel, ecModel) || !isAxisUsedInTheGrid(yAxisModel, gridModel, ecModel)) { + return; + } + + var cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex); + var data = seriesModel.getData(); + var xAxis = cartesian.getAxis('x'); + var yAxis = cartesian.getAxis('y'); + + if (data.type === 'list') { + unionExtent(data, xAxis, seriesModel); + unionExtent(data, yAxis, seriesModel); + } + } + }, this); + + function unionExtent(data, axis, seriesModel) { + each$1(data.mapDimension(axis.dim, true), function (dim) { + axis.scale.unionExtentFromData( // For example, the extent of the orginal dimension + // is [0.1, 0.5], the extent of the `stackResultDimension` + // is [7, 9], the final extent should not include [0.1, 0.5]. + data, getStackedDimension(data, dim)); + }); + } +}; +/** + * @param {string} [dim] 'x' or 'y' or 'auto' or null/undefined + * @return {Object} {baseAxes: [], otherAxes: []} + */ + + +gridProto.getTooltipAxes = function (dim) { + var baseAxes = []; + var otherAxes = []; + each$1(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 + }; +}; +/** + * @inner + */ + + +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 axesTypes = ['xAxis', 'yAxis']; +/** + * @inner + */ + +function findAxesModels(seriesModel, ecModel) { + return map(axesTypes, function (axisType) { + var axisModel = seriesModel.getReferringComponents(axisType)[0]; + return axisModel; + }); +} +/** + * @inner + */ + + +function isCartesian2D(seriesModel) { + return seriesModel.get('coordinateSystem') === 'cartesian2d'; +} + +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 (!isCartesian2D(seriesModel)) { + return; + } + + var axesModels = findAxesModels(seriesModel, ecModel); + var xAxisModel = axesModels[0]; + var yAxisModel = axesModels[1]; + var gridModel = xAxisModel.getCoordSysModel(); + 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 = Grid.prototype.dimensions = Cartesian2D.prototype.dimensions; +CoordinateSystemManager.register('cartesian2d', Grid); + +/* +* 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 BaseBarSeries = SeriesModel.extend({ + type: 'series.__base_bar__', + getInitialData: function (option, ecModel) { + return createListFromArray(this.getSource(), this); + }, + getMarkerPosition: function (value) { + var coordSys = this.coordinateSystem; + + if (coordSys) { + // 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]; + }, + defaultOption: { + zlevel: 0, + // 一级层叠 + z: 2, + // 二级层叠 + coordinateSystem: 'cartesian2d', + legendHoverLink: true, + // stack: null + // Cartesian coordinate system + // xAxisIndex: 0, + // yAxisIndex: 0, + // 最小高度改为0 + barMinHeight: 0, + // 最小角度为0,仅对极坐标系下的柱状图有效 + barMinAngle: 0, + // cursor: null, + large: false, + largeThreshold: 400, + progressive: 3e3, + progressiveChunkMode: 'mod', + // barMaxWidth: null, + // In cartesian, the default value is 1. Otherwise null. + // barMinWidth: null, + // 默认自适应 + // barWidth: null, + // 柱间距离,默认为柱形宽度的30%,可设固定值 + // barGap: '30%', + // 类目间柱形距离,默认为类目间距的20%,可设固定值 + // barCategoryGap: '20%', + // label: { + // show: false + // }, + itemStyle: {}, + emphasis: {} + } +}); + +/* +* 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. +*/ +BaseBarSeries.extend({ + type: 'series.bar', + dependencies: ['grid', 'polar'], + brushSelector: 'rect', + + /** + * @override + */ + getProgressive: function () { + // Do not support progressive in normal mode. + return this.get('large') ? this.get('progressive') : false; + }, + + /** + * @override + */ + 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; + }, + defaultOption: { + // If clipped + // Only available on cartesian2d + clip: true, + // If use caps on two sides of bars + // Only available on tangential polar bar + roundCap: false + } +}); + +/* +* 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. +*/ +/** + * @param {module:echarts/data/List} data + * @param {number} dataIndex + * @return {string} label string. Not null/undefined + */ + +function getDefaultLabel(data, dataIndex) { + var labelDims = data.mapDimension('defaultedLabel', true); + var len = labelDims.length; // Simple optimization (in lots of cases, label dims length is 1) + + if (len === 1) { + return retrieveRawValue(data, dataIndex, labelDims[0]); + } else if (len) { + var vals = []; + + for (var i = 0; i < labelDims.length; i++) { + var val = retrieveRawValue(data, dataIndex, labelDims[i]); + vals.push(val); + } + + return vals.join(' '); + } +} + +/* +* 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 setLabel(normalStyle, hoverStyle, itemModel, color, seriesModel, dataIndex, labelPositionOutside) { + var labelModel = itemModel.getModel('label'); + var hoverLabelModel = itemModel.getModel('emphasis.label'); + setLabelStyle(normalStyle, hoverStyle, labelModel, hoverLabelModel, { + labelFetcher: seriesModel, + labelDataIndex: dataIndex, + defaultText: getDefaultLabel(seriesModel.getData(), dataIndex), + isRectText: true, + autoColor: color + }); + fixPosition(normalStyle); + fixPosition(hoverStyle); +} + +function fixPosition(style, labelPositionOutside) { + if (style.textPosition === 'outside') { + style.textPosition = labelPositionOutside; + } +} + +/* +* 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 getBarItemStyle = makeStyleMapper([['fill', 'color'], ['stroke', 'borderColor'], ['lineWidth', 'borderWidth'], // Compatitable with 2 +['stroke', 'barBorderColor'], ['lineWidth', 'barBorderWidth'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor']]); +var barItemStyle = { + getBarItemStyle: function (excludes) { + var style = getBarItemStyle(this, excludes); + + if (this.getBorderLineDash) { + var lineDash = this.getBorderLineDash(); + lineDash && (style.lineDash = lineDash); + } + + return style; + } +}; + +/* +* 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 createGridClipPath(cartesian, hasAnimation, seriesModel) { + var rect = cartesian.getArea(); + var isHorizontal = cartesian.getBaseAxis().isHorizontal(); + 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; + var clipPath = new Rect({ + shape: { + x: x, + y: y, + width: width, + height: height + } + }); + + if (hasAnimation) { + clipPath.shape[isHorizontal ? 'width' : 'height'] = 0; + initProps(clipPath, { + shape: { + width: width, + height: height + } + }, seriesModel); + } + + 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 clipPath = new Sector({ + shape: { + cx: round$1(polar.cx, 1), + cy: round$1(polar.cy, 1), + r0: round$1(sectorArea.r0, 1), + r: round$1(sectorArea.r, 1), + startAngle: sectorArea.startAngle, + endAngle: sectorArea.endAngle, + clockwise: sectorArea.clockwise + } + }); + + if (hasAnimation) { + clipPath.shape.endAngle = sectorArea.startAngle; + initProps(clipPath, { + shape: { + endAngle: sectorArea.endAngle + } + }, seriesModel); + } + + return clipPath; +} + +function createClipPath(coordSys, hasAnimation, seriesModel) { + if (!coordSys) { + return null; + } else if (coordSys.type === 'polar') { + return createPolarClipPath(coordSys, hasAnimation, seriesModel); + } else if (coordSys.type === 'cartesian2d') { + return createGridClipPath(coordSys, hasAnimation, seriesModel); + } + + 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. +*/ +/** + * Sausage: similar to sector, but have half circle on both sides + * @public + */ + +var Sausage = extendShape({ + type: 'sausage', + shape: { + cx: 0, + cy: 0, + r0: 0, + r: 0, + startAngle: 0, + endAngle: Math.PI * 2, + clockwise: true + }, + buildPath: function (ctx, shape) { + var x = shape.cx; + var y = 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 unitStartX = Math.cos(startAngle); + var unitStartY = Math.sin(startAngle); + var unitEndX = Math.cos(endAngle); + var unitEndY = Math.sin(endAngle); + var lessThanCircle = clockwise ? endAngle - startAngle < Math.PI * 2 : startAngle - endAngle < Math.PI * 2; + + if (lessThanCircle) { + ctx.moveTo(unitStartX * r0 + x, unitStartY * r0 + y); + ctx.arc(unitStartX * rCenter + x, unitStartY * rCenter + y, dr, -Math.PI + startAngle, startAngle, !clockwise); + } + + ctx.arc(x, y, r, startAngle, endAngle, !clockwise); + ctx.moveTo(unitEndX * r + x, unitEndY * r + y); + ctx.arc(unitEndX * rCenter + x, unitEndY * rCenter + y, dr, endAngle - Math.PI * 2, endAngle - Math.PI, !clockwise); + + if (r0 !== 0) { + ctx.arc(x, y, r0, endAngle, startAngle, clockwise); + ctx.moveTo(unitStartX * r0 + x, unitEndY * r0 + y); + } + + ctx.closePath(); + } +}); + +/* +* 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 BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'barBorderWidth']; +var _eventPos = [0, 0]; // FIXME +// Just for compatible with ec2. + +extend(Model.prototype, barItemStyle); + +function getClipArea(coord, data) { + var coordSysClipArea = coord.getArea && coord.getArea(); + + if (coord.type === '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; +} + +extendChartView({ + type: 'bar', + render: function (seriesModel, ecModel, api) { + this._updateDrawMode(seriesModel); + + var coordinateSystemType = seriesModel.get('coordinateSystem'); + + if (coordinateSystemType === 'cartesian2d' || coordinateSystemType === 'polar') { + this._isLargeDraw ? this._renderLarge(seriesModel, ecModel, api) : this._renderNormal(seriesModel, ecModel, api); + } else {} + + return this.group; + }, + incrementalPrepareRender: function (seriesModel, ecModel, api) { + this._clear(); + + this._updateDrawMode(seriesModel); + }, + incrementalRender: function (params, seriesModel, ecModel, api) { + // Do not support progressive in normal mode. + this._incrementalRenderLarge(params, seriesModel); + }, + _updateDrawMode: function (seriesModel) { + var isLargeDraw = seriesModel.pipelineContext.large; + + if (this._isLargeDraw == null || isLargeDraw ^ this._isLargeDraw) { + this._isLargeDraw = isLargeDraw; + + this._clear(); + } + }, + _renderNormal: function (seriesModel, ecModel, api) { + 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 needsClip = seriesModel.get('clip', true); + 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); + data.diff(oldData).add(function (dataIndex) { + if (!data.hasValue(dataIndex)) { + return; + } + + var itemModel = data.getItemModel(dataIndex); + var layout = getLayout[coord.type](data, dataIndex, itemModel); + + if (needsClip) { + // Clip will modify the layout params. + // And return a boolean to determine if the shape are fully clipped. + var isClipped = clip[coord.type](coordSysClipArea, layout); + + if (isClipped) { + group.remove(el); + return; + } + } + + var el = elementCreator[coord.type](dataIndex, layout, isHorizontalOrRadial, animationModel, false, roundCap); + data.setItemGraphicEl(dataIndex, el); + group.add(el); + updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar'); + }).update(function (newIndex, oldIndex) { + var el = oldData.getItemGraphicEl(oldIndex); + + if (!data.hasValue(newIndex)) { + group.remove(el); + return; + } + + var itemModel = data.getItemModel(newIndex); + var layout = getLayout[coord.type](data, newIndex, itemModel); + + if (needsClip) { + var isClipped = clip[coord.type](coordSysClipArea, layout); + + if (isClipped) { + group.remove(el); + return; + } + } + + if (el) { + updateProps(el, { + shape: layout + }, animationModel, newIndex); + } else { + el = elementCreator[coord.type](newIndex, layout, isHorizontalOrRadial, animationModel, true, roundCap); + } + + data.setItemGraphicEl(newIndex, el); // Add back + + group.add(el); + updateStyle(el, data, newIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar'); + }).remove(function (dataIndex) { + var el = oldData.getItemGraphicEl(dataIndex); + + if (coord.type === 'cartesian2d') { + el && removeRect(dataIndex, animationModel, el); + } else { + el && removeSector(dataIndex, animationModel, el); + } + }).execute(); + this._data = data; + }, + _renderLarge: function (seriesModel, ecModel, api) { + this._clear(); + + createLarge(seriesModel, this.group); // Use clipPath in large mode. + + var clipPath = seriesModel.get('clip', true) ? createClipPath(seriesModel.coordinateSystem, false, seriesModel) : null; + + if (clipPath) { + this.group.setClipPath(clipPath); + } else { + this.group.removeClipPath(); + } + }, + _incrementalRenderLarge: function (params, seriesModel) { + createLarge(seriesModel, this.group, true); + }, + dispose: noop, + remove: function (ecModel) { + this._clear(ecModel); + }, + _clear: function (ecModel) { + var group = this.group; + var data = this._data; + + if (ecModel && ecModel.get('animation') && data && !this._isLargeDraw) { + data.eachItemGraphicEl(function (el) { + if (el.type === 'sector') { + removeSector(el.dataIndex, ecModel, el); + } else { + removeRect(el.dataIndex, ecModel, el); + } + }); + } else { + group.removeAll(); + } + + this._data = null; + } +}); +var mathMax$4 = Math.max; +var mathMin$4 = Math.min; +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 x = mathMax$4(layout.x, coordSysBoundingRect.x); + var x2 = mathMin$4(layout.x + layout.width, coordSysBoundingRect.x + coordSysBoundingRect.width); + var y = mathMax$4(layout.y, coordSysBoundingRect.y); + var y2 = mathMin$4(layout.y + layout.height, coordSysBoundingRect.y + coordSysBoundingRect.height); + layout.x = x; + layout.y = y; + layout.width = x2 - x; + layout.height = y2 - y; + var clipped = layout.width < 0 || layout.height < 0; // 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 clipped; + }, + polar: function (coordSysClipArea) { + return false; + } +}; +var elementCreator = { + cartesian2d: function (dataIndex, layout, isHorizontal, animationModel, isUpdate) { + var rect = new Rect({ + shape: extend({}, layout) + }); // Animation + + if (animationModel) { + var rectShape = rect.shape; + var animateProperty = isHorizontal ? 'height' : 'width'; + var animateTarget = {}; + rectShape[animateProperty] = 0; + animateTarget[animateProperty] = layout[animateProperty]; + graphic[isUpdate ? 'updateProps' : 'initProps'](rect, { + shape: animateTarget + }, animationModel, dataIndex); + } + + return rect; + }, + polar: function (dataIndex, layout, isRadial, animationModel, isUpdate, roundCap) { + // 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. + var clockwise = layout.startAngle < layout.endAngle; + var ShapeClass = !isRadial && roundCap ? Sausage : Sector; + var sector = new ShapeClass({ + shape: defaults({ + clockwise: clockwise + }, layout) + }); // Animation + + if (animationModel) { + var sectorShape = sector.shape; + var animateProperty = isRadial ? 'r' : 'endAngle'; + var animateTarget = {}; + sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle; + animateTarget[animateProperty] = layout[animateProperty]; + graphic[isUpdate ? 'updateProps' : 'initProps'](sector, { + shape: animateTarget + }, animationModel, dataIndex); + } + + return sector; + } +}; + +function removeRect(dataIndex, animationModel, el) { + // Not show text when animating + el.style.text = null; + updateProps(el, { + shape: { + width: 0 + } + }, animationModel, dataIndex, function () { + el.parent && el.parent.remove(el); + }); +} + +function removeSector(dataIndex, animationModel, el) { + // Not show text when animating + el.style.text = null; + updateProps(el, { + shape: { + r: el.shape.r0 + } + }, animationModel, dataIndex, function () { + el.parent && el.parent.remove(el); + }); +} + +var getLayout = { + cartesian2d: function (data, dataIndex, itemModel) { + var layout = data.getItemLayout(dataIndex); + var fixedLineWidth = getLineWidth(itemModel, layout); // 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 + }; + } +}; + +function updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal, isPolar) { + var color = data.getItemVisual(dataIndex, 'color'); + var opacity = data.getItemVisual(dataIndex, 'opacity'); + var itemStyleModel = itemModel.getModel('itemStyle'); + var hoverStyle = itemModel.getModel('emphasis.itemStyle').getBarItemStyle(); + + if (!isPolar) { + el.setShape('r', itemStyleModel.get('barBorderRadius') || 0); + } + + el.useStyle(defaults({ + fill: color, + opacity: opacity + }, itemStyleModel.getBarItemStyle())); + var cursorStyle = itemModel.getShallow('cursor'); + cursorStyle && el.attr('cursor', cursorStyle); + var labelPositionOutside = isHorizontal ? layout.height > 0 ? 'bottom' : 'top' : layout.width > 0 ? 'left' : 'right'; + + if (!isPolar) { + setLabel(el.style, hoverStyle, itemModel, color, seriesModel, dataIndex, labelPositionOutside); + } + + setHoverStyle(el, hoverStyle); +} // In case width or height are too small. + + +function getLineWidth(itemModel, rawLayout) { + var lineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY) || 0; + return Math.min(lineWidth, Math.abs(rawLayout.width), Math.abs(rawLayout.height)); +} + +var LargePath = Path.extend({ + type: 'largeBar', + shape: { + points: [] + }, + buildPath: function (ctx, shape) { + // Drawing lines is more efficient than drawing + // a whole line or drawing rects. + var points = shape.points; + var startPoint = this.__startPoint; + var baseDimIdx = this.__baseDimIdx; + + for (var i = 0; i < points.length; i += 2) { + startPoint[baseDimIdx] = points[i + baseDimIdx]; + ctx.moveTo(startPoint[0], startPoint[1]); + ctx.lineTo(points[i], points[i + 1]); + } + } +}); + +function createLarge(seriesModel, group, incremental) { + // TODO support polar + var data = seriesModel.getData(); + var startPoint = []; + var baseDimIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0; + startPoint[1 - baseDimIdx] = data.getLayout('valueAxisStart'); + var el = new LargePath({ + shape: { + points: data.getLayout('largePoints') + }, + incremental: !!incremental, + __startPoint: startPoint, + __baseDimIdx: baseDimIdx, + __largeDataIndices: data.getLayout('largeDataIndices'), + __barWidth: data.getLayout('barWidth') + }); + group.add(el); + setLargeStyle(el, seriesModel, data); // Enable tooltip and user mouse/touch event handlers. + + el.seriesIndex = seriesModel.seriesIndex; + + if (!seriesModel.get('silent')) { + el.on('mousedown', largePathUpdateDataIndex); + el.on('mousemove', largePathUpdateDataIndex); + } +} // 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); + 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 barWidthHalf = Math.abs(largePath.__barWidth / 2); + var startValueVal = largePath.__startPoint[valueDimIdx]; + _eventPos[0] = x; + _eventPos[1] = y; + var pointerBaseVal = _eventPos[baseDimIdx]; + var pointerValueVal = _eventPos[1 - baseDimIdx]; + var baseLowerBound = pointerBaseVal - barWidthHalf; + var baseUpperBound = pointerBaseVal + barWidthHalf; + + for (var i = 0, len = points.length / 2; i < len; i++) { + var ii = i * 2; + var barBaseVal = points[ii + baseDimIdx]; + var barValueVal = points[ii + valueDimIdx]; + + if (barBaseVal >= baseLowerBound && barBaseVal <= baseUpperBound && (startValueVal <= barValueVal ? pointerValueVal >= startValueVal && pointerValueVal <= barValueVal : pointerValueVal >= barValueVal && pointerValueVal <= startValueVal)) { + return largeDataIndices[i]; + } + } + + return -1; +} + +function setLargeStyle(el, seriesModel, data) { + var borderColor = data.getVisual('borderColor') || data.getVisual('color'); + var itemStyle = seriesModel.getModel('itemStyle').getItemStyle(['color', 'borderColor']); + el.useStyle(itemStyle); + el.style.fill = null; + el.style.stroke = borderColor; + el.style.lineWidth = data.getLayout('barWidth'); +} + +/* +* 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 PI$2 = 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. + * + * @param {module:zrender/container/Group} group + * @param {Object} axisModel + * @param {Object} opt Standard axis parameters. + * @param {Array.} opt.position [x, y] + * @param {number} opt.rotation by radian + * @param {number} [opt.nameDirection=1] 1 or -1 Used when nameLocation is 'middle' or 'center'. + * @param {number} [opt.tickDirection=1] 1 or -1 + * @param {number} [opt.labelDirection=1] 1 or -1 + * @param {number} [opt.labelOffset=0] Usefull when onZero. + * @param {string} [opt.axisLabelShow] default get from axisModel. + * @param {string} [opt.axisName] default get from axisModel. + * @param {number} [opt.axisNameAvailableWidth] + * @param {number} [opt.labelRotate] by degree, default get from axisModel. + * @param {number} [opt.strokeContainThreshold] Default label interval when label + * @param {number} [opt.nameTruncateMaxWidth] + */ + +var AxisBuilder = function (axisModel, opt) { + /** + * @readOnly + */ + this.opt = opt; + /** + * @readOnly + */ + + this.axisModel = axisModel; // Default value + + defaults(opt, { + labelOffset: 0, + nameDirection: 1, + tickDirection: 1, + labelDirection: 1, + silent: true + }); + /** + * @readOnly + */ + + this.group = new Group(); // FIXME Not use a seperate text group? + + var dumbGroup = new Group({ + position: opt.position.slice(), + rotation: opt.rotation + }); // this.group.add(dumbGroup); + // this._dumbGroup = dumbGroup; + + dumbGroup.updateTransform(); + this._transform = dumbGroup.transform; + this._dumbGroup = dumbGroup; +}; + +AxisBuilder.prototype = { + constructor: AxisBuilder, + hasBuilder: function (name) { + return !!builders[name]; + }, + add: function (name) { + builders[name].call(this); + }, + getGroup: function () { + return this.group; + } +}; +var builders = { + /** + * @private + */ + axisLine: function () { + var opt = this.opt; + var axisModel = this.axisModel; + + if (!axisModel.get('axisLine.show')) { + return; + } + + var extent = this.axisModel.axis.getExtent(); + var matrix = this._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()); + this.group.add(new Line({ + // Id for animation + anid: 'line', + 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 + })); + var arrows = axisModel.get('axisLine.symbol'); + var arrowSize = axisModel.get('axisLine.symbolSize'); + var arrowOffset = axisModel.get('axisLine.symbolOffset') || 0; + + if (typeof arrowOffset === 'number') { + arrowOffset = [arrowOffset, arrowOffset]; + } + + if (arrows != null) { + if (typeof arrows === 'string') { + // Use the same arrow for start and end point + arrows = [arrows, arrows]; + } + + if (typeof arrowSize === 'string' || typeof arrowSize === 'number') { + // Use the same size for width and height + arrowSize = [arrowSize, arrowSize]; + } + + var symbolWidth = arrowSize[0]; + var symbolHeight = arrowSize[1]; + each$1([{ + 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 / 2, -symbolHeight / 2, symbolWidth, symbolHeight, lineStyle.stroke, true); // Calculate arrow position with offset + + var r = point.r + point.offset; + var pos = [pt1[0] + r * Math.cos(opt.rotation), pt1[1] - r * Math.sin(opt.rotation)]; + symbol.attr({ + rotation: point.rotate, + position: pos, + silent: true, + z2: 11 + }); + this.group.add(symbol); + } + }, this); + } + }, + + /** + * @private + */ + axisTickLabel: function () { + var axisModel = this.axisModel; + var opt = this.opt; + var tickEls = buildAxisTick(this, axisModel, opt); + var labelEls = buildAxisLabel(this, axisModel, opt); + fixMinMaxLabelShow(axisModel, labelEls, tickEls); + }, + + /** + * @private + */ + axisName: function () { + var opt = this.opt; + var axisModel = this.axisModel; + 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 = this.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, // 'middle' + // Reuse labelOffset. + isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * gap : 0]; + var labelLayout; + var nameRotation = axisModel.get('nameRotate'); + + if (nameRotation != null) { + nameRotation = nameRotation * PI$2 / 180; // To radian. + } + + var axisNameAvailableWidth; + + if (isNameLocationCenter(nameLocation)) { + labelLayout = innerTextLayout(opt.rotation, nameRotation != null ? nameRotation : opt.rotation, // Adapt to axis. + nameDirection); + } else { + labelLayout = endTextLayout(opt, 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); // FIXME + // truncate rich text? (consider performance) + + var truncatedText = ellipsis != null && maxWidth != null ? truncateText$1(name, maxWidth, textFont, ellipsis, { + minChar: 2, + placeholder: truncateOpt.placeholder + }) : name; + var tooltipOpt = axisModel.get('tooltip', true); + var mainType = axisModel.mainType; + var formatterParams = { + componentType: mainType, + name: name, + $vars: ['name'] + }; + formatterParams[mainType + 'Index'] = axisModel.componentIndex; + var textEl = new Text({ + // Id for animation + anid: 'name', + __fullText: name, + __truncatedText: truncatedText, + position: pos, + rotation: labelLayout.rotation, + silent: isLabelSilent(axisModel), + z2: 1, + tooltip: tooltipOpt && tooltipOpt.show ? extend({ + content: name, + formatter: function () { + return name; + }, + formatterParams: formatterParams + }, tooltipOpt) : null + }); + setTextStyle(textEl.style, textStyleModel, { + text: truncatedText, + textFont: textFont, + textFill: textStyleModel.getTextColor() || axisModel.get('axisLine.lineStyle.color'), + textAlign: textStyleModel.get('align') || labelLayout.textAlign, + textVerticalAlign: textStyleModel.get('verticalAlign') || labelLayout.textVerticalAlign + }); + + if (axisModel.get('triggerEvent')) { + textEl.eventData = makeAxisEventDataBase(axisModel); + textEl.eventData.targetType = 'axisName'; + textEl.eventData.name = name; + } // FIXME + + + this._dumbGroup.add(textEl); + + textEl.updateTransform(); + this.group.add(textEl); + textEl.decomposeTransform(); + } +}; + +var makeAxisEventDataBase = AxisBuilder.makeAxisEventDataBase = function (axisModel) { + var eventData = { + componentType: axisModel.mainType, + componentIndex: axisModel.componentIndex + }; + eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex; + return eventData; +}; +/** + * @public + * @static + * @param {Object} opt + * @param {number} axisRotation in radian + * @param {number} textRotation in radian + * @param {number} direction + * @return {Object} { + * rotation, // according to axis + * textAlign, + * textVerticalAlign + * } + */ + + +var innerTextLayout = 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$2)) { + // Label is inverse parallel with axis line. + textVerticalAlign = direction > 0 ? 'bottom' : 'top'; + textAlign = 'center'; + } else { + textVerticalAlign = 'middle'; + + if (rotationDiff > 0 && rotationDiff < PI$2) { + textAlign = direction > 0 ? 'right' : 'left'; + } else { + textAlign = direction > 0 ? 'left' : 'right'; + } + } + + return { + rotation: rotationDiff, + textAlign: textAlign, + textVerticalAlign: textVerticalAlign + }; +}; + +function endTextLayout(opt, textPosition, textRotate, extent) { + var rotationDiff = remRadian(textRotate - opt.rotation); + var textAlign; + var textVerticalAlign; + var inverse = extent[0] > extent[1]; + var onLeft = textPosition === 'start' && !inverse || textPosition !== 'start' && inverse; + + if (isRadianAroundZero(rotationDiff - PI$2 / 2)) { + textVerticalAlign = onLeft ? 'bottom' : 'top'; + textAlign = 'center'; + } else if (isRadianAroundZero(rotationDiff - PI$2 * 1.5)) { + textVerticalAlign = onLeft ? 'top' : 'bottom'; + textAlign = 'center'; + } else { + textVerticalAlign = 'middle'; + + if (rotationDiff < PI$2 * 1.5 && rotationDiff > PI$2 / 2) { + textAlign = onLeft ? 'left' : 'right'; + } else { + textAlign = onLeft ? 'right' : 'left'; + } + } + + return { + rotation: rotationDiff, + textAlign: textAlign, + textVerticalAlign: textVerticalAlign + }; +} + +var isLabelSilent = 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); +}; + +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, labelLayout) { + // 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 buildAxisTick(axisBuilder, axisModel, opt) { + var axis = axisModel.axis; + + if (!axisModel.get('axisTick.show') || axis.scale.isBlank()) { + return; + } + + var tickModel = axisModel.getModel('axisTick'); + var lineStyleModel = tickModel.getModel('lineStyle'); + var tickLen = tickModel.get('length'); + var ticksCoords = axis.getTicksCoords(); + var pt1 = []; + var pt2 = []; + var matrix = axisBuilder._transform; + var tickEls = []; + + for (var i = 0; i < ticksCoords.length; i++) { + var tickCoord = ticksCoords[i].coord; + pt1[0] = tickCoord; + pt1[1] = 0; + pt2[0] = tickCoord; + pt2[1] = opt.tickDirection * tickLen; + + if (matrix) { + applyTransform(pt1, pt1, matrix); + applyTransform(pt2, pt2, matrix); + } // Tick line, Not use group transform to have better line draw + + + var tickEl = new Line({ + // Id for animation + anid: 'tick_' + ticksCoords[i].tickValue, + subPixelOptimize: true, + shape: { + x1: pt1[0], + y1: pt1[1], + x2: pt2[0], + y2: pt2[1] + }, + style: defaults(lineStyleModel.getLineStyle(), { + stroke: axisModel.get('axisLine.lineStyle.color') + }), + z2: 2, + silent: true + }); + axisBuilder.group.add(tickEl); + tickEls.push(tickEl); + } + + return tickEls; +} + +function buildAxisLabel(axisBuilder, 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$2 / 180; + var labelLayout = innerTextLayout(opt.rotation, labelRotation, opt.labelDirection); + var rawCategoryData = axisModel.getCategories && axisModel.getCategories(true); + var labelEls = []; + var silent = isLabelSilent(axisModel); + var triggerEvent = axisModel.get('triggerEvent'); + each$1(labels, function (labelItem, index) { + var tickValue = labelItem.tickValue; + var formattedLabel = labelItem.formattedLabel; + var rawLabel = labelItem.rawLabel; + var itemLabelModel = labelModel; + + if (rawCategoryData && rawCategoryData[tickValue] && rawCategoryData[tickValue].textStyle) { + itemLabelModel = new Model(rawCategoryData[tickValue].textStyle, labelModel, axisModel.ecModel); + } + + var textColor = itemLabelModel.getTextColor() || axisModel.get('axisLine.lineStyle.color'); + var tickCoord = axis.dataToCoord(tickValue); + var pos = [tickCoord, opt.labelOffset + opt.labelDirection * labelMargin]; + var textEl = new Text({ + // Id for animation + anid: 'label_' + tickValue, + position: pos, + rotation: labelLayout.rotation, + silent: silent, + z2: 10 + }); + setTextStyle(textEl.style, itemLabelModel, { + text: formattedLabel, + textAlign: itemLabelModel.getShallow('align', true) || labelLayout.textAlign, + textVerticalAlign: itemLabelModel.getShallow('verticalAlign', true) || itemLabelModel.getShallow('baseline', true) || labelLayout.textVerticalAlign, + textFill: typeof textColor === 'function' ? 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 + }); // Pack data for mouse event + + if (triggerEvent) { + textEl.eventData = makeAxisEventDataBase(axisModel); + textEl.eventData.targetType = 'axisLabel'; + textEl.eventData.value = rawLabel; + } // FIXME + + + axisBuilder._dumbGroup.add(textEl); + + textEl.updateTransform(); + labelEls.push(textEl); + axisBuilder.group.add(textEl); + textEl.decomposeTransform(); + }); + return labelEls; +} + +/* +* 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 each$6 = each$1; +var curry$1 = curry; // Build axisPointerModel, mergin tooltip.axisPointer model for each axis. +// 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$6(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$6(coordSys.getAxes(), curry$1(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$6(tooltipAxes.baseAxes, curry$1(saveTooltipAxisInfo, cross ? 'cross' : true, triggerAxis)); + } + + if (cross) { + each$6(tooltipAxes.otherAxes, curry$1(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 key = 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[key] = { + key: key, + axis: axis, + coordSys: coordSys, + axisPointerModel: axisPointerModel, + triggerTooltip: triggerTooltip, + involveSeries: involveSeries, + snap: snap, + useHandle: isHandleTrigger(axisPointerModel), + seriesModels: [] + }; + axesInfoInCoordSys[key] = axisInfo; + result.seriesInvolved |= involveSeries; + var groupIndex = getLinkGroupIndex(linksOption, axis); + + if (groupIndex != null) { + var linkGroup = linkGroups[groupIndex] || (linkGroups[groupIndex] = { + axesInfo: {} + }); + linkGroup.axesInfo[key] = axisInfo; + linkGroup.mapper = linksOption[groupIndex].mapper; + axisInfo.linkGroup = linkGroup; + } + } + }); +} + +function makeAxisPointerModel(axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip) { + var tooltipAxisPointerModel = baseTooltipModel.getModel('axisPointer'); + var volatileOption = {}; + each$6(['type', 'snap', 'lineStyle', 'shadowStyle', 'label', 'animation', 'animationDurationUpdate', 'animationEasingUpdate', 'z'], 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$6(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(); + } + }); + }, this); +} +/** + * 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; +} + +/* +* 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. +*/ +/** + * Base class of AxisView. + */ + +var AxisView = extendComponentView({ + type: 'axis', + + /** + * @private + */ + _axisPointer: null, + + /** + * @protected + * @type {string} + */ + axisPointerClass: null, + + /** + * @override + */ + 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); + AxisView.superApply(this, 'render', arguments); + updateAxisPointer(this, axisModel, ecModel, api, payload, true); + }, + + /** + * Action handler. + * @public + * @param {module:echarts/coord/cartesian/AxisModel} axisModel + * @param {module:echarts/model/Global} ecModel + * @param {module:echarts/ExtensionAPI} api + * @param {Object} payload + */ + updateAxisPointer: function (axisModel, ecModel, api, payload, force) { + updateAxisPointer(this, axisModel, ecModel, api, payload, false); + }, + + /** + * @override + */ + remove: function (ecModel, api) { + var axisPointer = this._axisPointer; + axisPointer && axisPointer.remove(api); + AxisView.superApply(this, 'remove', arguments); + }, + + /** + * @override + */ + dispose: function (ecModel, api) { + disposeAxisPointer(this, api); + AxisView.superApply(this, 'dispose', arguments); + } +}); + +function updateAxisPointer(axisView, axisModel, ecModel, api, payload, forceRender) { + var Clazz = AxisView.getAxisPointerClass(axisView.axisPointerClass); + + if (!Clazz) { + return; + } + + var axisPointerModel = getAxisPointerModel(axisModel); + axisPointerModel ? (axisView._axisPointer || (axisView._axisPointer = new Clazz())).render(axisModel, axisPointerModel, api, forceRender) : disposeAxisPointer(axisView, api); +} + +function disposeAxisPointer(axisView, ecModel, api) { + var axisPointer = axisView._axisPointer; + axisPointer && axisPointer.dispose(ecModel, api); + axisView._axisPointer = null; +} + +var axisPointerClazz = []; + +AxisView.registerAxisPointerClass = function (type, clazz) { + axisPointerClazz[type] = clazz; +}; + +AxisView.getAxisPointerClass = function (type) { + return type && axisPointerClazz[type]; +}; + +/* +* 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. +*/ +/** + * Can only be called after coordinate system creation stage. + * (Can be called before coordinate system update stage). + * + * @param {Object} opt {labelInside} + * @return {Object} { + * position, rotation, labelDirection, labelOffset, + * tickDirection, labelRotate, z2 + * } + */ + +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; +} + +/* +* 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 axisBuilderAttrs = ['axisLine', 'axisTickLabel', 'axisName']; +var selfBuilderAttrs = ['splitArea', 'splitLine']; // function getAlignWithLabel(model, axisModel) { +// var alignWithLabel = model.get('alignWithLabel'); +// if (alignWithLabel === 'auto') { +// alignWithLabel = axisModel.get('axisTick.alignWithLabel'); +// } +// return alignWithLabel; +// } + +var CartesianAxisView = AxisView.extend({ + type: 'cartesianAxis', + axisPointerClass: 'CartesianAxisPointer', + + /** + * @override + */ + 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, layout); + each$1(axisBuilderAttrs, axisBuilder.add, axisBuilder); + + this._axisGroup.add(axisBuilder.getGroup()); + + each$1(selfBuilderAttrs, function (name) { + if (axisModel.get(name + '.show')) { + this['_' + name](axisModel, gridModel); + } + }, this); + groupTransition(oldAxisGroup, this._axisGroup, axisModel); + CartesianAxisView.superCall(this, 'render', axisModel, ecModel, api, payload); + }, + remove: function () { + this._splitAreaColors = null; + }, + + /** + * @param {module:echarts/coord/cartesian/AxisModel} axisModel + * @param {module:echarts/coord/cartesian/GridModel} gridModel + * @private + */ + _splitLine: function (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 = []; // Simple optimization + // Batching the lines if color are the same + + 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; + + this._axisGroup.add(new Line({ + anid: tickValue != null ? 'line_' + ticksCoords[i].tickValue : null, + subPixelOptimize: true, + shape: { + x1: p1[0], + y1: p1[1], + x2: p2[0], + y2: p2[1] + }, + style: defaults({ + stroke: lineColors[colorIndex] + }, lineStyle), + silent: true + })); + } + }, + + /** + * @param {module:echarts/coord/cartesian/AxisModel} axisModel + * @param {module:echarts/coord/cartesian/GridModel} gridModel + * @private + */ + _splitArea: function (axisModel, gridModel) { + var axis = axisModel.axis; + + if (axis.scale.isBlank()) { + return; + } + + 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 = this._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; + var y; + var width; + var height; + + 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); + + this._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), + silent: true + })); + + colorIndex = (colorIndex + 1) % areaColorsLen; + } + + this._splitAreaColors = newSplitAreaColors; + } +}); +CartesianAxisView.extend({ + type: 'xAxis' +}); +CartesianAxisView.extend({ + type: 'yAxis' +}); + +/* +* 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. +*/ + +/* +* 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. +*/ +extendComponentView({ + type: 'grid', + 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 + })); + } + } +}); +registerPreprocessor(function (option) { + // Only create grid when need + if (option.xAxis && option.yAxis && !option.grid) { + option.grid = {}; + } +}); + +/* +* 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. +*/ +registerLayout(PRIORITY.VISUAL.LAYOUT, curry(layout, 'bar')); // Use higher prority to avoid to be blocked by other overall layout, which do not +// only exist in this module, but probably also exist in other modules, like `barPolar`. + +registerLayout(PRIORITY.VISUAL.PROGRESSIVE_LAYOUT, largeLayout); +registerVisual({ + seriesType: 'bar', + reset: function (seriesModel) { + // Visual coding for legend + seriesModel.getData().setVisual('legendSymbol', 'roundRect'); + } +}); + +/* +* 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. +*/ +SeriesModel.extend({ + type: 'series.line', + dependencies: ['grid', 'polar'], + getInitialData: function (option, ecModel) { + return createListFromArray(this.getSource(), this); + }, + defaultOption: { + zlevel: 0, + z: 2, + coordinateSystem: 'cartesian2d', + legendHoverLink: true, + hoverAnimation: true, + // stack: null + // xAxisIndex: 0, + // yAxisIndex: 0, + // polarIndex: 0, + // If clip the overflow value + clip: true, + // cursor: null, + label: { + position: 'top' + }, + // itemStyle: { + // }, + lineStyle: { + width: 2, + type: 'solid' + }, + // 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'. + sampling: 'none', + animationEasing: 'linear', + // Disable progressive + progressive: 0, + hoverLayerThreshold: Infinity + } +}); + +/* +* 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. +*/ + +/** + * @module echarts/chart/helper/Symbol + */ +/** + * @constructor + * @alias {module:echarts/chart/helper/Symbol} + * @param {module:echarts/data/List} data + * @param {number} idx + * @extends {module:zrender/graphic/Group} + */ + +function SymbolClz$1(data, idx, seriesScope) { + Group.call(this); + this.updateData(data, idx, seriesScope); +} + +var symbolProto = SymbolClz$1.prototype; +/** + * @public + * @static + * @param {module:echarts/data/List} data + * @param {number} dataIndex + * @return {Array.} [width, height] + */ + +var getSymbolSize = SymbolClz$1.getSymbolSize = function (data, idx) { + var symbolSize = data.getItemVisual(idx, 'symbolSize'); + return symbolSize instanceof Array ? symbolSize.slice() : [+symbolSize, +symbolSize]; +}; + +function getScale(symbolSize) { + return [symbolSize[0] / 2, symbolSize[1] / 2]; +} + +function driftSymbol(dx, dy) { + this.parent.drift(dx, dy); +} + +symbolProto._createSymbol = function (symbolType, data, idx, symbolSize, keepAspect) { + // Remove paths created before + this.removeAll(); + var color = data.getItemVisual(idx, 'color'); // var 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, color, keepAspect); + symbolPath.attr({ + z2: 100, + culling: true, + scale: getScale(symbolSize) + }); // Rewrite drift method + + symbolPath.drift = driftSymbol; + this._symbolType = symbolType; + this.add(symbolPath); +}; +/** + * Stop animation + * @param {boolean} toLastFrame + */ + + +symbolProto.stopSymbolAnimation = function (toLastFrame) { + this.childAt(0).stopAnimation(toLastFrame); +}; +/** + * 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. + */ + + +symbolProto.getSymbolPath = function () { + return this.childAt(0); +}; +/** + * Get scale(aka, current symbol size). + * Including the change caused by animation + */ + + +symbolProto.getScale = function () { + return this.childAt(0).scale; +}; +/** + * Highlight symbol + */ + + +symbolProto.highlight = function () { + this.childAt(0).trigger('emphasis'); +}; +/** + * Downplay symbol + */ + + +symbolProto.downplay = function () { + this.childAt(0).trigger('normal'); +}; +/** + * @param {number} zlevel + * @param {number} z + */ + + +symbolProto.setZ = function (zlevel, z) { + var symbolPath = this.childAt(0); + symbolPath.zlevel = zlevel; + symbolPath.z = z; +}; + +symbolProto.setDraggable = function (draggable) { + var symbolPath = this.childAt(0); + symbolPath.draggable = draggable; + symbolPath.cursor = draggable ? 'move' : symbolPath.cursor; +}; +/** + * Update symbol properties + * @param {module:echarts/data/List} data + * @param {number} idx + * @param {Object} [seriesScope] + * @param {Object} [seriesScope.itemStyle] + * @param {Object} [seriesScope.hoverItemStyle] + * @param {Object} [seriesScope.symbolRotate] + * @param {Object} [seriesScope.symbolOffset] + * @param {module:echarts/model/Model} [seriesScope.labelModel] + * @param {module:echarts/model/Model} [seriesScope.hoverLabelModel] + * @param {boolean} [seriesScope.hoverAnimation] + * @param {Object} [seriesScope.cursorStyle] + * @param {module:echarts/model/Model} [seriesScope.itemModel] + * @param {string} [seriesScope.symbolInnerColor] + * @param {Object} [seriesScope.fadeIn=false] + */ + + +symbolProto.updateData = function (data, idx, seriesScope) { + this.silent = false; + var symbolType = data.getItemVisual(idx, 'symbol') || 'circle'; + var seriesModel = data.hostModel; + var symbolSize = getSymbolSize(data, idx); + var isInit = symbolType !== this._symbolType; + + if (isInit) { + var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect'); + + this._createSymbol(symbolType, data, idx, symbolSize, keepAspect); + } else { + var symbolPath = this.childAt(0); + symbolPath.silent = false; + updateProps(symbolPath, { + scale: getScale(symbolSize) + }, seriesModel, idx); + } + + this._updateCommon(data, idx, symbolSize, seriesScope); + + if (isInit) { + var symbolPath = this.childAt(0); + var fadeIn = seriesScope && seriesScope.fadeIn; + var target = { + scale: symbolPath.scale.slice() + }; + fadeIn && (target.style = { + opacity: symbolPath.style.opacity + }); + symbolPath.scale = [0, 0]; + fadeIn && (symbolPath.style.opacity = 0); + initProps(symbolPath, target, seriesModel, idx); + } + + this._seriesModel = seriesModel; +}; // Update common properties + + +var normalStyleAccessPath = ['itemStyle']; +var emphasisStyleAccessPath = ['emphasis', 'itemStyle']; +var normalLabelAccessPath = ['label']; +var emphasisLabelAccessPath = ['emphasis', 'label']; +/** + * @param {module:echarts/data/List} data + * @param {number} idx + * @param {Array.} symbolSize + * @param {Object} [seriesScope] + */ + +symbolProto._updateCommon = function (data, idx, symbolSize, seriesScope) { + var symbolPath = this.childAt(0); + var seriesModel = data.hostModel; + var color = data.getItemVisual(idx, 'color'); // Reset style + + if (symbolPath.type !== 'image') { + symbolPath.useStyle({ + strokeNoScale: true + }); + } else { + symbolPath.setStyle({ + opacity: null, + shadowBlur: null, + shadowOffsetX: null, + shadowOffsetY: null, + shadowColor: null + }); + } + + var itemStyle = seriesScope && seriesScope.itemStyle; + var hoverItemStyle = seriesScope && seriesScope.hoverItemStyle; + var symbolRotate = seriesScope && seriesScope.symbolRotate; + var symbolOffset = seriesScope && seriesScope.symbolOffset; + var labelModel = seriesScope && seriesScope.labelModel; + var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel; + var hoverAnimation = seriesScope && seriesScope.hoverAnimation; + var cursorStyle = seriesScope && seriesScope.cursorStyle; + + if (!seriesScope || data.hasItemOption) { + var itemModel = seriesScope && seriesScope.itemModel ? seriesScope.itemModel : data.getItemModel(idx); // Color must be excluded. + // Because symbol provide setColor individually to set fill and stroke + + itemStyle = itemModel.getModel(normalStyleAccessPath).getItemStyle(['color']); + hoverItemStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle(); + symbolRotate = itemModel.getShallow('symbolRotate'); + symbolOffset = itemModel.getShallow('symbolOffset'); + labelModel = itemModel.getModel(normalLabelAccessPath); + hoverLabelModel = itemModel.getModel(emphasisLabelAccessPath); + hoverAnimation = itemModel.getShallow('hoverAnimation'); + cursorStyle = itemModel.getShallow('cursor'); + } else { + hoverItemStyle = extend({}, hoverItemStyle); + } + + var elStyle = symbolPath.style; + symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0); + + if (symbolOffset) { + symbolPath.attr('position', [parsePercent$1(symbolOffset[0], symbolSize[0]), parsePercent$1(symbolOffset[1], symbolSize[1])]); + } + + cursorStyle && symbolPath.attr('cursor', cursorStyle); // PENDING setColor before setStyle!!! + + symbolPath.setColor(color, seriesScope && seriesScope.symbolInnerColor); + symbolPath.setStyle(itemStyle); + var opacity = data.getItemVisual(idx, 'opacity'); + + if (opacity != null) { + elStyle.opacity = opacity; + } + + var liftZ = data.getItemVisual(idx, 'liftZ'); + var z2Origin = symbolPath.__z2Origin; + + if (liftZ != null) { + if (z2Origin == null) { + symbolPath.__z2Origin = symbolPath.z2; + symbolPath.z2 += liftZ; + } + } else if (z2Origin != null) { + symbolPath.z2 = z2Origin; + symbolPath.__z2Origin = null; + } + + var useNameLabel = seriesScope && seriesScope.useNameLabel; + setLabelStyle(elStyle, hoverItemStyle, labelModel, hoverLabelModel, { + labelFetcher: seriesModel, + labelDataIndex: idx, + defaultText: getLabelDefaultText, + isRectText: true, + autoColor: color + }); // Do not execute util needed. + + function getLabelDefaultText(idx, opt) { + return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx); + } + + symbolPath.__symbolOriginalScale = getScale(symbolSize); + symbolPath.hoverStyle = hoverItemStyle; + symbolPath.highDownOnUpdate = hoverAnimation && seriesModel.isAnimationEnabled() ? highDownOnUpdate : null; + setHoverStyle(symbolPath); +}; + +function highDownOnUpdate(fromState, toState) { + // Do not support this hover animation util some scenario required. + // Animation can only be supported in hover layer when using `el.incremetal`. + if (this.incremental || this.useHoverLayer) { + return; + } + + if (toState === 'emphasis') { + var scale = this.__symbolOriginalScale; + var ratio = scale[1] / scale[0]; + var emphasisOpt = { + scale: [Math.max(scale[0] * 1.1, scale[0] + 3), Math.max(scale[1] * 1.1, scale[1] + 3 * ratio)] + }; // FIXME + // modify it after support stop specified animation. + // toState === fromState + // ? (this.stopAnimation(), this.attr(emphasisOpt)) + + this.animateTo(emphasisOpt, 400, 'elasticOut'); + } else if (toState === 'normal') { + this.animateTo({ + scale: this.__symbolOriginalScale + }, 400, 'elasticOut'); + } +} +/** + * @param {Function} cb + * @param {Object} [opt] + * @param {Object} [opt.keepLabel=true] + */ + + +symbolProto.fadeOut = function (cb, opt) { + var symbolPath = this.childAt(0); // Avoid mistaken hover when fading out + + this.silent = symbolPath.silent = true; // Not show text when animating + + !(opt && opt.keepLabel) && (symbolPath.style.text = null); + updateProps(symbolPath, { + style: { + opacity: 0 + }, + scale: [0, 0] + }, this._seriesModel, this.dataIndex, cb); +}; + +inherits(SymbolClz$1, Group); + +/* +* 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. +*/ + +/** + * @module echarts/chart/helper/SymbolDraw + */ +/** + * @constructor + * @alias module:echarts/chart/helper/SymbolDraw + * @param {module:zrender/graphic/Group} [symbolCtor] + */ + +function SymbolDraw(symbolCtor) { + this.group = new Group(); + this._symbolCtor = symbolCtor || SymbolClz$1; +} + +var symbolDrawProto = SymbolDraw.prototype; + +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'; +} +/** + * Update symbols draw by new data + * @param {module:echarts/data/List} data + * @param {Object} [opt] Or isIgnore + * @param {Function} [opt.isIgnore] + * @param {Object} [opt.clipShape] + */ + + +symbolDrawProto.updateData = function (data, opt) { + opt = normalizeUpdateOpt(opt); + var group = this.group; + var seriesModel = data.hostModel; + var oldData = this._data; + var SymbolCtor = this._symbolCtor; + var seriesScope = makeSeriesScope(data); // 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 = data.getItemLayout(newIdx); + + if (symbolNeedsDraw(data, point, newIdx, opt)) { + var symbolEl = new SymbolCtor(data, newIdx, seriesScope); + symbolEl.attr('position', point); + data.setItemGraphicEl(newIdx, symbolEl); + group.add(symbolEl); + } + }).update(function (newIdx, oldIdx) { + var symbolEl = oldData.getItemGraphicEl(oldIdx); + var point = data.getItemLayout(newIdx); + + if (!symbolNeedsDraw(data, point, newIdx, opt)) { + group.remove(symbolEl); + return; + } + + if (!symbolEl) { + symbolEl = new SymbolCtor(data, newIdx); + symbolEl.attr('position', point); + } else { + symbolEl.updateData(data, newIdx, seriesScope); + updateProps(symbolEl, { + position: point + }, 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); + }); + }).execute(); + this._data = data; +}; + +symbolDrawProto.isPersistent = function () { + return true; +}; + +symbolDrawProto.updateLayout = function () { + var data = this._data; + + if (data) { + // Not use animation + data.eachItemGraphicEl(function (el, idx) { + var point = data.getItemLayout(idx); + el.attr('position', point); + }); + } +}; + +symbolDrawProto.incrementalPrepareUpdate = function (data) { + this._seriesScope = makeSeriesScope(data); + this._data = null; + this.group.removeAll(); +}; +/** + * Update symbols draw by new data + * @param {module:echarts/data/List} data + * @param {Object} [opt] Or isIgnore + * @param {Function} [opt.isIgnore] + * @param {Object} [opt.clipShape] + */ + + +symbolDrawProto.incrementalUpdate = function (taskParams, data, opt) { + opt = normalizeUpdateOpt(opt); + + function updateIncrementalAndHover(el) { + if (!el.isGroup) { + el.incremental = el.useHoverLayer = 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.attr('position', point); + this.group.add(el); + data.setItemGraphicEl(idx, el); + } + } +}; + +function normalizeUpdateOpt(opt) { + if (opt != null && !isObject$1(opt)) { + opt = { + isIgnore: opt + }; + } + + return opt || {}; +} + +symbolDrawProto.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); + }); + }); + } else { + group.removeAll(); + } +}; + +function makeSeriesScope(data) { + var seriesModel = data.hostModel; + return { + itemStyle: seriesModel.getModel('itemStyle').getItemStyle(['color']), + hoverItemStyle: seriesModel.getModel('emphasis.itemStyle').getItemStyle(), + symbolRotate: seriesModel.get('symbolRotate'), + symbolOffset: seriesModel.get('symbolOffset'), + hoverAnimation: seriesModel.get('hoverAnimation'), + labelModel: seriesModel.getModel('label'), + hoverLabelModel: seriesModel.getModel('emphasis.label'), + cursorStyle: seriesModel.get('cursor') + }; +} + +/* +* 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. +*/ +/** + * @param {Object} coordSys + * @param {module:echarts/data/List} data + * @param {string} valueOrigin lineSeries.option.areaStyle.origin + */ + +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; + var stackResultDim = data.getCalculationInfo('stackResultDimension'); + + if (stacked |= isDimensionStacked(data, dims[0] + /*, dims[1]*/ + )) { + // jshint ignore:line + dims[0] = stackResultDim; + } + + if (stacked |= isDimensionStacked(data, dims[1] + /*, dims[0]*/ + )) { + // jshint ignore:line + 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]; + } // 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); +} + +/* +* 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. +*/ +// 'zrender/src/core/arrayDiff' has been used before, but it did +// not do well in performance when roam with fixed dataZoom window. +// function convertToIntId(newIdList, oldIdList) { +// // Generate int id instead of string id. +// // Compare string maybe slow in score function of arrDiff +// // Assume id in idList are all unique +// var idIndicesMap = {}; +// var idx = 0; +// for (var i = 0; i < newIdList.length; i++) { +// idIndicesMap[newIdList[i]] = idx; +// newIdList[i] = idx++; +// } +// for (var i = 0; i < oldIdList.length; i++) { +// var oldId = oldIdList[i]; +// // Same with newIdList +// if (idIndicesMap[oldId]) { +// oldIdList[i] = idIndicesMap[oldId]; +// } +// else { +// oldIdList[i] = idx++; +// } +// } +// } + +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; +} + +var lineAnimationDiff = function (oldData, newData, oldStackedOnPoints, newStackedOnPoints, oldCoordSys, newCoordSys, oldValueOrigin, newValueOrigin) { + var diff = diffData(oldData, newData); // var newIdList = newData.mapArray(newData.getId); + // var 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); + var oldDataNewCoordInfo = prepareDataCoordInfo(newCoordSys, oldData, newValueOrigin); + + for (var i = 0; i < diff.length; i++) { + var diffItem = diff[i]; + var pointAdded = true; // 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 '=': + var currentPt = oldData.getItemLayout(diffItem.idx); + var nextPt = newData.getItemLayout(diffItem.idx1); // If previous data is NaN, use next point directly + + if (isNaN(currentPt[0]) || isNaN(currentPt[1])) { + currentPt = nextPt.slice(); + } + + currPoints.push(currentPt); + nextPoints.push(nextPt); + currStackedPoints.push(oldStackedOnPoints[diffItem.idx]); + nextStackedPoints.push(newStackedOnPoints[diffItem.idx1]); + rawIndices.push(newData.getRawIndex(diffItem.idx1)); + break; + + case '+': + var idx = diffItem.idx; + currPoints.push(oldCoordSys.dataToPoint([newData.get(newDataOldCoordInfo.dataDimsForPoint[0], idx), newData.get(newDataOldCoordInfo.dataDimsForPoint[1], idx)])); + nextPoints.push(newData.getItemLayout(idx).slice()); + currStackedPoints.push(getStackedOnPoint(newDataOldCoordInfo, oldCoordSys, newData, idx)); + nextStackedPoints.push(newStackedOnPoints[idx]); + rawIndices.push(newData.getRawIndex(idx)); + break; + + case '-': + var idx = diffItem.idx; + var rawIndex = oldData.getRawIndex(idx); // Data is replaced. In the case of dynamic data queue + // FIXME FIXME FIXME + + if (rawIndex !== idx) { + currPoints.push(oldData.getItemLayout(idx)); + nextPoints.push(newCoordSys.dataToPoint([oldData.get(oldDataNewCoordInfo.dataDimsForPoint[0], idx), oldData.get(oldDataNewCoordInfo.dataDimsForPoint[1], idx)])); + currStackedPoints.push(oldStackedOnPoints[idx]); + nextStackedPoints.push(getStackedOnPoint(oldDataNewCoordInfo, newCoordSys, oldData, idx)); + rawIndices.push(rawIndex); + } else { + 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 sortedCurrPoints = []; + var sortedNextPoints = []; + var sortedCurrStackedPoints = []; + var sortedNextStackedPoints = []; + var sortedStatus = []; + + for (var i = 0; i < sortedIndices.length; i++) { + var idx = sortedIndices[i]; + sortedCurrPoints[i] = currPoints[idx]; + sortedNextPoints[i] = nextPoints[idx]; + sortedCurrStackedPoints[i] = currStackedPoints[idx]; + sortedNextStackedPoints[i] = nextStackedPoints[idx]; + sortedStatus[i] = status[idx]; + } + + return { + current: sortedCurrPoints, + next: sortedNextPoints, + stackedOnCurrent: sortedCurrStackedPoints, + stackedOnNext: sortedNextStackedPoints, + status: sortedStatus + }; +}; + +/* +* 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. +*/ +// Poly path support NaN point +var vec2Min = min; +var vec2Max = max; +var scaleAndAdd$1 = scaleAndAdd; +var v2Copy = copy; // Temporary variable + +var v = []; +var cp0 = []; +var cp1 = []; + +function isPointNull(p) { + return isNaN(p[0]) || isNaN(p[1]); +} + +function drawSegment(ctx, points, start, segLen, allLen, dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls) { + // if (smoothMonotone == null) { + // if (isMono(points, 'x')) { + // return drawMono(ctx, points, start, segLen, allLen, + // dir, smoothMin, smoothMax, smooth, 'x', connectNulls); + // } + // else if (isMono(points, 'y')) { + // return drawMono(ctx, points, start, segLen, allLen, + // dir, smoothMin, smoothMax, smooth, 'y', connectNulls); + // } + // else { + // return drawNonMono.apply(this, arguments); + // } + // } + // else if (smoothMonotone !== 'none' && isMono(points, smoothMonotone)) { + // return drawMono.apply(this, arguments); + // } + // else { + // return drawNonMono.apply(this, arguments); + // } + if (smoothMonotone === 'none' || !smoothMonotone) { + return drawNonMono.apply(this, arguments); + } else { + return drawMono.apply(this, arguments); + } +} +/** + * Check if points is in monotone. + * + * @param {number[][]} points Array of points which is in [x, y] form + * @param {string} smoothMonotone 'x', 'y', or 'none', stating for which + * dimension that is checking. + * If is 'none', `drawNonMono` should be + * called. + * If is undefined, either being monotone + * in 'x' or 'y' will call `drawMono`. + */ +// function isMono(points, smoothMonotone) { +// if (points.length <= 1) { +// return true; +// } +// var dim = smoothMonotone === 'x' ? 0 : 1; +// var last = points[0][dim]; +// var lastDiff = 0; +// for (var i = 1; i < points.length; ++i) { +// var diff = points[i][dim] - last; +// if (!isNaN(diff) && !isNaN(lastDiff) +// && diff !== 0 && lastDiff !== 0 +// && ((diff >= 0) !== (lastDiff >= 0)) +// ) { +// return false; +// } +// if (!isNaN(diff) && diff !== 0) { +// lastDiff = diff; +// last = points[i][dim]; +// } +// } +// return true; +// } + +/** + * Draw smoothed line in monotone, in which only vertical or horizontal bezier + * control points will be used. This should be used when points are monotone + * either in x or y dimension. + */ + + +function drawMono(ctx, points, start, segLen, allLen, dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls) { + var prevIdx = 0; + var idx = start; + + for (var k = 0; k < segLen; k++) { + var p = points[idx]; + + if (idx >= allLen || idx < 0) { + break; + } + + if (isPointNull(p)) { + if (connectNulls) { + idx += dir; + continue; + } + + break; + } + + if (idx === start) { + ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]); + } else { + if (smooth > 0) { + var prevP = points[prevIdx]; + var dim = smoothMonotone === 'y' ? 1 : 0; // Length of control point to p, either in x or y, but not both + + var ctrlLen = (p[dim] - prevP[dim]) * smooth; + v2Copy(cp0, prevP); + cp0[dim] = prevP[dim] + ctrlLen; + v2Copy(cp1, p); + cp1[dim] = p[dim] - ctrlLen; + ctx.bezierCurveTo(cp0[0], cp0[1], cp1[0], cp1[1], p[0], p[1]); + } else { + ctx.lineTo(p[0], p[1]); + } + } + + prevIdx = idx; + idx += dir; + } + + return k; +} +/** + * 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 drawNonMono(ctx, points, start, segLen, allLen, dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls) { + var prevIdx = 0; + var idx = start; + + for (var k = 0; k < segLen; k++) { + var p = points[idx]; + + if (idx >= allLen || idx < 0) { + break; + } + + if (isPointNull(p)) { + if (connectNulls) { + idx += dir; + continue; + } + + break; + } + + if (idx === start) { + ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]); + v2Copy(cp0, p); + } else { + if (smooth > 0) { + var nextIdx = idx + dir; + var nextP = points[nextIdx]; + + if (connectNulls) { + // Find next point not null + while (nextP && isPointNull(points[nextIdx])) { + nextIdx += dir; + nextP = points[nextIdx]; + } + } + + var ratioNextSeg = 0.5; + var prevP = points[prevIdx]; + var nextP = points[nextIdx]; // Last point + + if (!nextP || isPointNull(nextP)) { + v2Copy(cp1, p); + } else { + // If next data is null in not connect case + if (isPointNull(nextP) && !connectNulls) { + nextP = p; + } + + sub(v, nextP, prevP); + var lenPrevSeg; + var lenNextSeg; + + if (smoothMonotone === 'x' || smoothMonotone === 'y') { + var dim = smoothMonotone === 'x' ? 0 : 1; + lenPrevSeg = Math.abs(p[dim] - prevP[dim]); + lenNextSeg = Math.abs(p[dim] - nextP[dim]); + } else { + lenPrevSeg = dist(p, prevP); + lenNextSeg = dist(p, nextP); + } // Use ratio of seg length + + + ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg); + scaleAndAdd$1(cp1, p, v, -smooth * (1 - ratioNextSeg)); + } // Smooth constraint + + + vec2Min(cp0, cp0, smoothMax); + vec2Max(cp0, cp0, smoothMin); + vec2Min(cp1, cp1, smoothMax); + vec2Max(cp1, cp1, smoothMin); + ctx.bezierCurveTo(cp0[0], cp0[1], cp1[0], cp1[1], p[0], p[1]); // cp0 of next segment + + scaleAndAdd$1(cp0, p, v, smooth * ratioNextSeg); + } else { + ctx.lineTo(p[0], p[1]); + } + } + + prevIdx = idx; + idx += dir; + } + + return k; +} + +function getBoundingBox(points, smoothConstraint) { + var ptMin = [Infinity, Infinity]; + var ptMax = [-Infinity, -Infinity]; + + if (smoothConstraint) { + for (var i = 0; i < points.length; i++) { + var pt = points[i]; + + if (pt[0] < ptMin[0]) { + ptMin[0] = pt[0]; + } + + if (pt[1] < ptMin[1]) { + ptMin[1] = pt[1]; + } + + if (pt[0] > ptMax[0]) { + ptMax[0] = pt[0]; + } + + if (pt[1] > ptMax[1]) { + ptMax[1] = pt[1]; + } + } + } + + return { + min: smoothConstraint ? ptMin : ptMax, + max: smoothConstraint ? ptMax : ptMin + }; +} + +var Polyline$1 = Path.extend({ + type: 'ec-polyline', + shape: { + points: [], + smooth: 0, + smoothConstraint: true, + smoothMonotone: null, + connectNulls: false + }, + style: { + fill: null, + stroke: '#000' + }, + brush: fixClipWithShadow(Path.prototype.brush), + buildPath: function (ctx, shape) { + var points = shape.points; + var i = 0; + var len$$1 = points.length; + var result = getBoundingBox(points, shape.smoothConstraint); + + if (shape.connectNulls) { + // Must remove first and last null values avoid draw error in polygon + for (; len$$1 > 0; len$$1--) { + if (!isPointNull(points[len$$1 - 1])) { + break; + } + } + + for (; i < len$$1; i++) { + if (!isPointNull(points[i])) { + break; + } + } + } + + while (i < len$$1) { + i += drawSegment(ctx, points, i, len$$1, len$$1, 1, result.min, result.max, shape.smooth, shape.smoothMonotone, shape.connectNulls) + 1; + } + } +}); +var Polygon$1 = Path.extend({ + type: 'ec-polygon', + shape: { + points: [], + // Offset between stacked base points and points + stackedOnPoints: [], + smooth: 0, + stackedOnSmooth: 0, + smoothConstraint: true, + smoothMonotone: null, + connectNulls: false + }, + brush: fixClipWithShadow(Path.prototype.brush), + buildPath: function (ctx, shape) { + var points = shape.points; + var stackedOnPoints = shape.stackedOnPoints; + var i = 0; + var len$$1 = points.length; + var smoothMonotone = shape.smoothMonotone; + var bbox = getBoundingBox(points, shape.smoothConstraint); + var stackedOnBBox = getBoundingBox(stackedOnPoints, shape.smoothConstraint); + + if (shape.connectNulls) { + // Must remove first and last null values avoid draw error in polygon + for (; len$$1 > 0; len$$1--) { + if (!isPointNull(points[len$$1 - 1])) { + break; + } + } + + for (; i < len$$1; i++) { + if (!isPointNull(points[i])) { + break; + } + } + } + + while (i < len$$1) { + var k = drawSegment(ctx, points, i, len$$1, len$$1, 1, bbox.min, bbox.max, shape.smooth, smoothMonotone, shape.connectNulls); + drawSegment(ctx, stackedOnPoints, i + k - 1, k, len$$1, -1, stackedOnBBox.min, stackedOnBBox.max, shape.stackedOnSmooth, smoothMonotone, shape.connectNulls); + i += k + 1; + ctx.closePath(); + } + } +}); + +/* +* 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. +*/ +// FIXME step not support polar +function isPointsSame(points1, points2) { + if (points1.length !== points2.length) { + return; + } + + for (var i = 0; i < points1.length; i++) { + var p1 = points1[i]; + var p2 = points2[i]; + + if (p1[0] !== p2[0] || p1[1] !== p2[1]) { + return; + } + } + + return true; +} + +function getSmooth(smooth) { + return typeof smooth === 'number' ? smooth : smooth ? 0.5 : 0; +} +/** + * @param {module:echarts/coord/cartesian/Cartesian2D|module:echarts/coord/polar/Polar} coordSys + * @param {module:echarts/data/List} data + * @param {Object} dataCoordInfo + * @param {Array.>} points + */ + + +function getStackedOnPoints(coordSys, data, dataCoordInfo) { + if (!dataCoordInfo.valueDim) { + return []; + } + + var points = []; + + for (var idx = 0, len = data.count(); idx < len; idx++) { + points.push(getStackedOnPoint(dataCoordInfo, coordSys, data, idx)); + } + + return points; +} + +function turnPointsIntoStep(points, coordSys, stepTurnAt) { + var baseAxis = coordSys.getBaseAxis(); + var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1; + var stepPoints = []; + + for (var i = 0; i < points.length - 1; i++) { + var nextPt = points[i + 1]; + var pt = points[i]; + stepPoints.push(pt); + var stepPt = []; + + switch (stepTurnAt) { + case 'end': + stepPt[baseIndex] = nextPt[baseIndex]; + stepPt[1 - baseIndex] = pt[1 - baseIndex]; // default is start + + stepPoints.push(stepPt); + break; + + case 'middle': + // default is start + 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); + stepPoints.push(stepPt2); + break; + + default: + stepPt[baseIndex] = pt[baseIndex]; + stepPt[1 - baseIndex] = nextPt[1 - baseIndex]; // default is start + + stepPoints.push(stepPt); + } + } // Last points + + + points[i] && stepPoints.push(points[i]); + return stepPoints; +} + +function getVisualGradient(data, coordSys) { + 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') { + return; + } + + var coordDim; + var visualMeta; + + for (var i = visualMetaList.length - 1; i >= 0; i--) { + var dimIndex = visualMetaList[i].dimension; + var dimName = data.dimensions[dimIndex]; + var dimInfo = data.getDimensionInfo(dimName); + coordDim = dimInfo && dimInfo.coordDim; // Can only be x or y + + if (coordDim === 'x' || coordDim === 'y') { + visualMeta = visualMetaList[i]; + break; + } + } + + if (!visualMeta) { + 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); // dataToCoor mapping may not be linear, but must be monotonic. + + var colorStops = map(visualMeta.stops, function (stop) { + 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 tinyExtent = 10; // Arbitrary value: 10px + + var minCoord = colorStops[0].coord - tinyExtent; + var maxCoord = colorStops[stopLen - 1].coord + tinyExtent; + var coordSpan = maxCoord - minCoord; + + if (coordSpan < 1e-3) { + return 'transparent'; + } + + each$1(colorStops, function (stop) { + stop.offset = (stop.coord - minCoord) / coordSpan; + }); + colorStops.push({ + offset: stopLen ? colorStops[stopLen - 1].offset : 0.5, + color: outerColors[1] || 'transparent' + }); + colorStops.unshift({ + // notice colorStops.length have been changed. + offset: stopLen ? colorStops[0].offset : 0.5, + color: outerColors[0] || 'transparent' + }); // zrUtil.each(colorStops, function (colorStop) { + // // Make sure each offset has rounded px to avoid not sharp edge + // colorStop.offset = (Math.round(colorStop.offset * (end - start) + start) - start) / (end - start); + // }); + + var gradient = new LinearGradient(0, 0, 0, 0, colorStops, 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$1(categoryAxis.getViewLabels(), function (labelItem) { + labelMap[labelItem.tickValue] = 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 (SymbolClz$1.getSymbolSize(data, dataIndex // Only for cartesian, where `isHorizontal` exists. + )[categoryAxis.isHorizontal() ? 1 : 0] // Empirical number + * 1.5 > availSize) { + return false; + } + } + + return true; +} + +function createLineClipPath(coordSys, hasAnimation, seriesModel) { + if (coordSys.type === 'cartesian2d') { + var isHorizontal = coordSys.getBaseAxis().isHorizontal(); + var clipPath = createGridClipPath(coordSys, hasAnimation, seriesModel); // 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; + } + } + + return clipPath; + } else { + return createPolarClipPath(coordSys, hasAnimation, seriesModel); + } +} + +Chart.extend({ + type: 'line', + init: function () { + var lineGroup = new Group(); + var symbolDraw = new SymbolDraw(); + this.group.add(symbolDraw.group); + this._symbolDraw = symbolDraw; + this._lineGroup = lineGroup; + }, + render: function (seriesModel, ecModel, api) { + 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.mapArray(data.getItemLayout); + 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 = getStackedOnPoints(coordSys, data, dataCoordInfo); + var showSymbol = seriesModel.get('showSymbol'); + 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'); + var clipShapeForSymbol; + + if (coordSys && coordSys.getArea) { + 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.r1 += 0.5; + } + } // Initialization animation or coordinate system changed + + + if (!(polyline && prevCoordSys.type === coordSys.type && step === this._step)) { + showSymbol && symbolDraw.updateData(data, { + isIgnore: isIgnoreFunc, + clipShape: clipShapeForSymbol + }); + + if (step) { + // TODO If stacked series is not step + points = turnPointsIntoStep(points, coordSys, step); + stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step); + } + + polyline = this._newPolyline(points, coordSys, hasAnimation); + + if (isAreaChart) { + polygon = this._newPolygon(points, stackedOnPoints, coordSys, hasAnimation); + } + + lineGroup.setClipPath(createLineClipPath(coordSys, true, seriesModel)); + } else { + if (isAreaChart && !polygon) { + // If areaStyle is added + polygon = this._newPolygon(points, stackedOnPoints, coordSys, hasAnimation); + } else if (polygon && !isAreaChart) { + // If areaStyle is removed + lineGroup.remove(polygon); + polygon = this._polygon = null; + } // Update clipPath + + + lineGroup.setClipPath(createLineClipPath(coordSys, false, 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 + }); // Stop symbol animation and sync with line points + // FIXME performance? + + data.eachItemGraphicEl(function (el) { + el.stopAnimation(true); + }); // 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._updateAnimation(data, stackedOnPoints, coordSys, api, step, valueOrigin); + } else { + // Not do it in update with animation + if (step) { + // TODO If stacked series is not step + points = turnPointsIntoStep(points, coordSys, step); + stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step); + } + + polyline.setShape({ + points: points + }); + polygon && polygon.setShape({ + points: points, + stackedOnPoints: stackedOnPoints + }); + } + } + } + + var visualColor = getVisualGradient(data, coordSys) || data.getVisual('color'); + polyline.useStyle(defaults( // Use color in lineStyle first + lineStyleModel.getLineStyle(), { + fill: 'none', + stroke: visualColor, + lineJoin: 'bevel' + })); + var smooth = seriesModel.get('smooth'); + smooth = getSmooth(seriesModel.get('smooth')); + polyline.setShape({ + smooth: smooth, + smoothMonotone: seriesModel.get('smoothMonotone'), + connectNulls: seriesModel.get('connectNulls') + }); + + if (polygon) { + var stackedOnSeries = data.getCalculationInfo('stackedOnSeries'); + var stackedOnSmooth = 0; + polygon.useStyle(defaults(areaStyleModel.getAreaStyle(), { + fill: visualColor, + opacity: 0.7, + lineJoin: 'bevel' + })); + + if (stackedOnSeries) { + stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth')); + } + + polygon.setShape({ + smooth: smooth, + stackedOnSmooth: stackedOnSmooth, + smoothMonotone: seriesModel.get('smoothMonotone'), + connectNulls: seriesModel.get('connectNulls') + }); + } + + 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; + }, + dispose: function () {}, + highlight: function (seriesModel, ecModel, api, payload) { + var data = seriesModel.getData(); + var dataIndex = queryDataIndex(data, payload); + + if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) { + var symbol = data.getItemGraphicEl(dataIndex); + + if (!symbol) { + // Create a temporary symbol if it is not exists + var pt = data.getItemLayout(dataIndex); + + if (!pt) { + // Null data + return; + } + + symbol = new SymbolClz$1(data, dataIndex); + symbol.position = pt; + symbol.setZ(seriesModel.get('zlevel'), seriesModel.get('z')); + symbol.ignore = isNaN(pt[0]) || isNaN(pt[1]); + symbol.__temp = true; + data.setItemGraphicEl(dataIndex, symbol); // Stop scale animation + + symbol.stopSymbolAnimation(true); + this.group.add(symbol); + } + + symbol.highlight(); + } else { + // Highlight whole series + Chart.prototype.highlight.call(this, seriesModel, ecModel, api, payload); + } + }, + downplay: function (seriesModel, ecModel, api, payload) { + var data = seriesModel.getData(); + var dataIndex = queryDataIndex(data, payload); + + 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 + Chart.prototype.downplay.call(this, seriesModel, ecModel, api, payload); + } + }, + + /** + * @param {module:zrender/container/Group} group + * @param {Array.>} points + * @private + */ + _newPolyline: function (points) { + var polyline = this._polyline; // Remove previous created polyline + + if (polyline) { + this._lineGroup.remove(polyline); + } + + polyline = new Polyline$1({ + shape: { + points: points + }, + silent: true, + z2: 10 + }); + + this._lineGroup.add(polyline); + + this._polyline = polyline; + return polyline; + }, + + /** + * @param {module:zrender/container/Group} group + * @param {Array.>} stackedOnPoints + * @param {Array.>} points + * @private + */ + _newPolygon: function (points, stackedOnPoints) { + var polygon = this._polygon; // Remove previous created polygon + + if (polygon) { + this._lineGroup.remove(polygon); + } + + polygon = new Polygon$1({ + shape: { + points: points, + stackedOnPoints: stackedOnPoints + }, + silent: true + }); + + this._lineGroup.add(polygon); + + this._polygon = polygon; + return polygon; + }, + + /** + * @private + */ + // FIXME Two value axis + _updateAnimation: function (data, stackedOnPoints, coordSys, api, step, valueOrigin) { + 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, 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); + stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step); + next = turnPointsIntoStep(diff.next, coordSys, step); + stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step); + } // `diff.current` is subset of `current` (which should be ensured by + // turnPointsIntoStep), so points in `__points` can be updated when + // points in `current` are update during animation. + + + polyline.shape.__points = diff.current; + polyline.shape.points = current; + updateProps(polyline, { + shape: { + points: next + } + }, seriesModel); + + if (polygon) { + polygon.setShape({ + points: current, + stackedOnPoints: stackedOnCurrent + }); + updateProps(polygon, { + shape: { + points: next, + stackedOnPoints: stackedOnNext + } + }, seriesModel); + } + + 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 () { + for (var i = 0; i < updatedDataInfo.length; i++) { + var el = updatedDataInfo[i].el; + el.attr('position', polyline.shape.__points[updatedDataInfo[i].ptIdx]); + } + }); + } + }, + 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._data = 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. +*/ +var visualSymbol = function (seriesType, defaultSymbolType, legendSymbol) { + // Encoding visual for all series include which is filtered for legend drawing + return { + seriesType: seriesType, + // For legend. + performRawSeries: true, + reset: function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + var symbolType = seriesModel.get('symbol'); + var symbolSize = seriesModel.get('symbolSize'); + var keepAspect = seriesModel.get('symbolKeepAspect'); + var hasSymbolTypeCallback = isFunction$1(symbolType); + var hasSymbolSizeCallback = isFunction$1(symbolSize); + var hasCallback = hasSymbolTypeCallback || hasSymbolSizeCallback; + var seriesSymbol = !hasSymbolTypeCallback && symbolType ? symbolType : defaultSymbolType; + var seriesSymbolSize = !hasSymbolSizeCallback ? symbolSize : null; + data.setVisual({ + legendSymbol: legendSymbol || seriesSymbol, + // If seting callback functions on `symbol` or `symbolSize`, for simplicity and avoiding + // to bring trouble, we do not pick a reuslt from one of its calling on data item here, + // but just use the default value. Callback on `symbol` or `symbolSize` is convenient in + // some cases but generally it is not recommanded. + symbol: seriesSymbol, + symbolSize: seriesSymbolSize, + symbolKeepAspect: keepAspect + }); // Only visible series has each data be visual encoded + + if (ecModel.isSeriesFiltered(seriesModel)) { + return; + } + + function dataEach(data, idx) { + if (hasCallback) { + var rawValue = seriesModel.getRawValue(idx); + var params = seriesModel.getDataParams(idx); + hasSymbolTypeCallback && data.setItemVisual(idx, 'symbol', symbolType(rawValue, params)); + hasSymbolSizeCallback && data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params)); + } + + if (data.hasItemOption) { + var itemModel = data.getItemModel(idx); + var itemSymbolType = itemModel.getShallow('symbol', true); + var itemSymbolSize = itemModel.getShallow('symbolSize', true); + var itemSymbolKeepAspect = itemModel.getShallow('symbolKeepAspect', true); // If has item symbol + + if (itemSymbolType != null) { + data.setItemVisual(idx, 'symbol', itemSymbolType); + } + + if (itemSymbolSize != null) { + // PENDING Transform symbolSize ? + data.setItemVisual(idx, 'symbolSize', itemSymbolSize); + } + + if (itemSymbolKeepAspect != null) { + data.setItemVisual(idx, 'symbolKeepAspect', itemSymbolKeepAspect); + } + } + } + + return { + dataEach: data.hasItemOption || hasCallback ? 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. +*/ + +/* global Float32Array */ +var layoutPoints = function (seriesType) { + return { + seriesType: seriesType, + plan: createRenderPlanner(), + reset: function (seriesModel) { + var data = seriesModel.getData(); + var coordSys = seriesModel.coordinateSystem; + var pipelineContext = seriesModel.pipelineContext; + var isLargeRender = 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[1]*/ + )) { + dims[0] = stackResultDim; + } + + if (isDimensionStacked(data, dims[1] + /*, dims[0]*/ + )) { + dims[1] = stackResultDim; + } + + function progress(params, data) { + var segCount = params.end - params.start; + var points = isLargeRender && new Float32Array(segCount * dimLen); + + for (var i = params.start, offset = 0, tmpIn = [], tmpOut = []; i < params.end; i++) { + var point; + + if (dimLen === 1) { + var x = data.get(dims[0], i); + point = !isNaN(x) && coordSys.dataToPoint(x, null, tmpOut); + } else { + var x = tmpIn[0] = data.get(dims[0], i); + var y = tmpIn[1] = data.get(dims[1], i); // Also {Array.}, not undefined to avoid if...else... statement + + point = !isNaN(x) && !isNaN(y) && coordSys.dataToPoint(tmpIn, null, tmpOut); + } + + if (isLargeRender) { + points[offset++] = point ? point[0] : NaN; + points[offset++] = point ? point[1] : NaN; + } else { + data.setItemLayout(i, point && point.slice() || [NaN, NaN]); + } + } + + isLargeRender && data.setLayout('symbolPoints', points); + } + + return dimLen && { + progress: progress + }; + } + }; +}; + +/* +* 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 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, value) { + return Math.round(frame.length / 2); +}; + +var dataSample = function (seriesType) { + return { + seriesType: seriesType, + modifyOutputEnd: true, + reset: function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + var sampling = seriesModel.get('sampling'); + var coordSys = seriesModel.coordinateSystem; // Only cartesian2d support down sampling + + if (coordSys.type === 'cartesian2d' && sampling) { + var baseAxis = coordSys.getBaseAxis(); + var valueAxis = coordSys.getOtherAxis(baseAxis); + var extent = baseAxis.getExtent(); // Coordinste system has been resized + + var size = extent[1] - extent[0]; + var rate = Math.round(data.count() / size); + + if (rate > 1) { + var sampler; + + if (typeof sampling === 'string') { + sampler = samplers[sampling]; + } else if (typeof sampling === 'function') { + 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)); + } + } + } + } + }; +}; + +/* +* 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. +*/ +registerVisual(visualSymbol('line', 'circle', 'line')); +registerLayout(layoutPoints('line')); // Down sample after filter + +registerProcessor(PRIORITY.PROCESSOR.STATISTIC, dataSample('line')); + +/* +* 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. +*/ +/** + * [Usage]: + * (1) + * createListSimply(seriesModel, ['value']); + * (2) + * createListSimply(seriesModel, { + * coordDimensions: ['value'], + * dimensionsCount: 5 + * }); + * + * @param {module:echarts/model/Series} seriesModel + * @param {Object|Array.} opt opt or coordDimensions + * The options in opt, see `echarts/data/helper/createDimensions` + * @param {Array.} [nameList] + * @return {module:echarts/data/List} + */ + +var createListSimply = function (seriesModel, opt, nameList) { + opt = isArray(opt) && { + coordDimensions: opt + } || extend({}, opt); + var source = seriesModel.getSource(); + var dimensionsInfo = createDimensions(source, opt); + var list = new List(dimensionsInfo, 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. +*/ + +/** + * Data selectable mixin for chart series. + * To eanble data select, option of series must have `selectedMode`. + * And each data item will use `selected` to toggle itself selected status + */ +var dataSelectableMixin = { + /** + * @param {Array.} targetList [{name, value, selected}, ...] + * If targetList is an array, it should like [{name: ..., value: ...}, ...]. + * If targetList is a "List", it must have coordDim: 'value' dimension and name. + */ + updateSelectedMap: function (targetList) { + this._targetList = isArray(targetList) ? targetList.slice() : []; + this._selectTargetMap = reduce(targetList || [], function (targetMap, target) { + targetMap.set(target.name, target); + return targetMap; + }, createHashMap()); + }, + + /** + * Either name or id should be passed as input here. + * If both of them are defined, id is used. + * + * @param {string|undefined} name name of data + * @param {number|undefined} id dataIndex of data + */ + // PENGING If selectedMode is null ? + select: function (name, id) { + var target = id != null ? this._targetList[id] : this._selectTargetMap.get(name); + var selectedMode = this.get('selectedMode'); + + if (selectedMode === 'single') { + this._selectTargetMap.each(function (target) { + target.selected = false; + }); + } + + target && (target.selected = true); + }, + + /** + * Either name or id should be passed as input here. + * If both of them are defined, id is used. + * + * @param {string|undefined} name name of data + * @param {number|undefined} id dataIndex of data + */ + unSelect: function (name, id) { + var target = id != null ? this._targetList[id] : this._selectTargetMap.get(name); // var selectedMode = this.get('selectedMode'); + // selectedMode !== 'single' && target && (target.selected = false); + + target && (target.selected = false); + }, + + /** + * Either name or id should be passed as input here. + * If both of them are defined, id is used. + * + * @param {string|undefined} name name of data + * @param {number|undefined} id dataIndex of data + */ + toggleSelected: function (name, id) { + var target = id != null ? this._targetList[id] : this._selectTargetMap.get(name); + + if (target != null) { + this[target.selected ? 'unSelect' : 'select'](name, id); + return target.selected; + } + }, + + /** + * Either name or id should be passed as input here. + * If both of them are defined, id is used. + * + * @param {string|undefined} name name of data + * @param {number|undefined} id dataIndex of data + */ + isSelected: function (name, id) { + var target = id != null ? this._targetList[id] : this._selectTargetMap.get(name); + return target && target.selected; + } +}; + +/* +* 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 PieSeries = extendSeriesModel({ + type: 'series.pie', + // Overwrite + init: function (option) { + PieSeries.superApply(this, 'init', arguments); // Enable legend selection for each data item + // Use a function instead of direct access because data reference may changed + + this.legendDataProvider = function () { + return this.getRawData(); + }; + + this.updateSelectedMap(this._createSelectableList()); + + this._defaultLabelLine(option); + }, + // Overwrite + mergeOption: function (newOption) { + PieSeries.superCall(this, 'mergeOption', newOption); + this.updateSelectedMap(this._createSelectableList()); + }, + getInitialData: function (option, ecModel) { + return createListSimply(this, ['value']); + }, + _createSelectableList: function () { + var data = this.getRawData(); + var valueDim = data.mapDimension('value'); + var targetList = []; + + for (var i = 0, len = data.count(); i < len; i++) { + targetList.push({ + name: data.getName(i), + value: data.get(valueDim, i), + selected: retrieveRawAttr(data, i, 'selected') + }); + } + + return targetList; + }, + // Overwrite + getDataParams: function (dataIndex) { + var data = this.getData(); + var params = PieSeries.superCall(this, 'getDataParams', 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; + }, + _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; + }, + defaultOption: { + zlevel: 0, + z: 2, + legendHoverLink: true, + hoverAnimation: true, + // 默认全局居中 + 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, + // 高亮扇区偏移量 + hoverOffset: 10, + // If use strategy to avoid label overlapping + avoidLabelOverlap: true, + // 选择模式,默认关闭,可选single,multiple + // selectedMode: false, + // 南丁格尔玫瑰图模式,'radius'(半径) | 'area'(面积) + // roseType: null, + percentPrecision: 2, + // If still show when all data zero. + stillShowZeroSum: true, + // cursor: null, + label: { + // If rotate around circle + rotate: false, + show: true, + // 'outer', 'inside', 'center' + position: 'outer' // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调 + // 默认使用全局文本样式,详见TEXTSTYLE + // distance: 当position为inner时有效,为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数 + + }, + // Enabled when label.normal.position is 'outer' + labelLine: { + show: true, + // 引导线两段中的第一段长度 + length: 15, + // 引导线两段中的第二段长度 + length2: 15, + smooth: false, + lineStyle: { + // color: 各异, + width: 1, + type: 'solid' + } + }, + itemStyle: { + borderWidth: 1 + }, + // Animation type. Valid values: expansion, scale + animationType: 'expansion', + // Animation type when update. Valid values: transition, expansion + animationTypeUpdate: 'transition', + animationEasing: 'cubicOut' + } +}); +mixin(PieSeries, dataSelectableMixin); + +/* +* 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. +*/ +/** + * @param {module:echarts/model/Series} seriesModel + * @param {boolean} hasAnimation + * @inner + */ + +function updateDataSelected(uid, seriesModel, hasAnimation, api) { + var data = seriesModel.getData(); + var dataIndex = this.dataIndex; + var name = data.getName(dataIndex); + var selectedOffset = seriesModel.get('selectedOffset'); + api.dispatchAction({ + type: 'pieToggleSelect', + from: uid, + name: name, + seriesId: seriesModel.id + }); + data.each(function (idx) { + toggleItemSelected(data.getItemGraphicEl(idx), data.getItemLayout(idx), seriesModel.isSelected(data.getName(idx)), selectedOffset, hasAnimation); + }); +} +/** + * @param {module:zrender/graphic/Sector} el + * @param {Object} layout + * @param {boolean} isSelected + * @param {number} selectedOffset + * @param {boolean} hasAnimation + * @inner + */ + + +function toggleItemSelected(el, layout, isSelected, selectedOffset, hasAnimation) { + var midAngle = (layout.startAngle + layout.endAngle) / 2; + var dx = Math.cos(midAngle); + var dy = Math.sin(midAngle); + var offset = isSelected ? selectedOffset : 0; + var position = [dx * offset, dy * offset]; + hasAnimation // animateTo will stop revious animation like update transition + ? el.animate().when(200, { + position: position + }).start('bounceOut') : el.attr('position', position); +} +/** + * Piece of pie including Sector, Label, LabelLine + * @constructor + * @extends {module:zrender/graphic/Group} + */ + + +function PiePiece(data, idx) { + Group.call(this); + var sector = new Sector({ + z2: 2 + }); + var polyline = new Polyline(); + var text = new Text(); + this.add(sector); + this.add(polyline); + this.add(text); + this.updateData(data, idx, true); +} + +var piePieceProto = PiePiece.prototype; + +piePieceProto.updateData = function (data, idx, firstCreate) { + var sector = this.childAt(0); + var labelLine = this.childAt(1); + var labelText = this.childAt(2); + var seriesModel = data.hostModel; + var itemModel = data.getItemModel(idx); + var layout = data.getItemLayout(idx); + var sectorShape = extend({}, layout); + sectorShape.label = null; + var animationTypeUpdate = seriesModel.getShallow('animationTypeUpdate'); + + if (firstCreate) { + sector.setShape(sectorShape); + var animationType = seriesModel.getShallow('animationType'); + + if (animationType === 'scale') { + sector.shape.r = layout.r0; + initProps(sector, { + shape: { + r: layout.r + } + }, seriesModel, idx); + } // Expansion + else { + sector.shape.endAngle = layout.startAngle; + updateProps(sector, { + shape: { + endAngle: layout.endAngle + } + }, seriesModel, idx); + } + } else { + if (animationTypeUpdate === 'expansion') { + // Sectors are set to be target shape and an overlaying clipPath is used for animation + sector.setShape(sectorShape); + } else { + // Transition animation from the old shape + updateProps(sector, { + shape: sectorShape + }, seriesModel, idx); + } + } // Update common style + + + var visualColor = data.getItemVisual(idx, 'color'); + sector.useStyle(defaults({ + lineJoin: 'bevel', + fill: visualColor + }, itemModel.getModel('itemStyle').getItemStyle())); + sector.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle(); + var cursorStyle = itemModel.getShallow('cursor'); + cursorStyle && sector.attr('cursor', cursorStyle); // Toggle selected + + toggleItemSelected(this, data.getItemLayout(idx), seriesModel.isSelected(null, idx), seriesModel.get('selectedOffset'), seriesModel.get('animation')); // Label and text animation should be applied only for transition type animation when update + + var withAnimation = !firstCreate && animationTypeUpdate === 'transition'; + + this._updateLabel(data, idx, withAnimation); + + this.highDownOnUpdate = itemModel.get('hoverAnimation') && seriesModel.isAnimationEnabled() ? function (fromState, toState) { + if (toState === 'emphasis') { + labelLine.ignore = labelLine.hoverIgnore; + labelText.ignore = labelText.hoverIgnore; // Sector may has animation of updating data. Force to move to the last frame + // Or it may stopped on the wrong shape + + sector.stopAnimation(true); + sector.animateTo({ + shape: { + r: layout.r + seriesModel.get('hoverOffset') + } + }, 300, 'elasticOut'); + } else { + labelLine.ignore = labelLine.normalIgnore; + labelText.ignore = labelText.normalIgnore; + sector.stopAnimation(true); + sector.animateTo({ + shape: { + r: layout.r + } + }, 300, 'elasticOut'); + } + } : null; + setHoverStyle(this); +}; + +piePieceProto._updateLabel = function (data, idx, withAnimation) { + var labelLine = this.childAt(1); + var labelText = this.childAt(2); + var seriesModel = data.hostModel; + var itemModel = data.getItemModel(idx); + var layout = data.getItemLayout(idx); + var labelLayout = layout.label; + var visualColor = data.getItemVisual(idx, 'color'); + + if (!labelLayout || isNaN(labelLayout.x) || isNaN(labelLayout.y)) { + labelText.ignore = labelText.normalIgnore = labelText.hoverIgnore = labelLine.ignore = labelLine.normalIgnore = labelLine.hoverIgnore = true; + return; + } + + var targetLineShape = { + points: labelLayout.linePoints || [[labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y]] + }; + var targetTextStyle = { + x: labelLayout.x, + y: labelLayout.y + }; + + if (withAnimation) { + updateProps(labelLine, { + shape: targetLineShape + }, seriesModel, idx); + updateProps(labelText, { + style: targetTextStyle + }, seriesModel, idx); + } else { + labelLine.attr({ + shape: targetLineShape + }); + labelText.attr({ + style: targetTextStyle + }); + } + + labelText.attr({ + rotation: labelLayout.rotation, + origin: [labelLayout.x, labelLayout.y], + z2: 10 + }); + var labelModel = itemModel.getModel('label'); + var labelHoverModel = itemModel.getModel('emphasis.label'); + var labelLineModel = itemModel.getModel('labelLine'); + var labelLineHoverModel = itemModel.getModel('emphasis.labelLine'); + var visualColor = data.getItemVisual(idx, 'color'); + setLabelStyle(labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel, { + labelFetcher: data.hostModel, + labelDataIndex: idx, + defaultText: data.getName(idx), + autoColor: visualColor, + useInsideStyle: !!labelLayout.inside + }, { + textAlign: labelLayout.textAlign, + textVerticalAlign: labelLayout.verticalAlign, + opacity: data.getItemVisual(idx, 'opacity') + }); + labelText.ignore = labelText.normalIgnore = !labelModel.get('show'); + labelText.hoverIgnore = !labelHoverModel.get('show'); + labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show'); + labelLine.hoverIgnore = !labelLineHoverModel.get('show'); // Default use item visual color + + labelLine.setStyle({ + stroke: visualColor, + opacity: data.getItemVisual(idx, 'opacity') + }); + labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle()); + labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle(); + var smooth = labelLineModel.get('smooth'); + + if (smooth && smooth === true) { + smooth = 0.4; + } + + labelLine.setShape({ + smooth: smooth + }); +}; + +inherits(PiePiece, Group); // Pie view + +var PieView = Chart.extend({ + type: 'pie', + init: function () { + var sectorGroup = new Group(); + this._sectorGroup = sectorGroup; + }, + render: function (seriesModel, ecModel, api, payload) { + if (payload && payload.from === this.uid) { + return; + } + + var data = seriesModel.getData(); + var oldData = this._data; + var group = this.group; + var hasAnimation = ecModel.get('animation'); + var isFirstRender = !oldData; + var animationType = seriesModel.get('animationType'); + var animationTypeUpdate = seriesModel.get('animationTypeUpdate'); + var onSectorClick = curry(updateDataSelected, this.uid, seriesModel, hasAnimation, api); + var selectedMode = seriesModel.get('selectedMode'); + data.diff(oldData).add(function (idx) { + var piePiece = new PiePiece(data, idx); // Default expansion animation + + if (isFirstRender && animationType !== 'scale') { + piePiece.eachChild(function (child) { + child.stopAnimation(true); + }); + } + + selectedMode && piePiece.on('click', onSectorClick); + data.setItemGraphicEl(idx, piePiece); + group.add(piePiece); + }).update(function (newIdx, oldIdx) { + var piePiece = oldData.getItemGraphicEl(oldIdx); + + if (!isFirstRender && animationTypeUpdate !== 'transition') { + piePiece.eachChild(function (child) { + child.stopAnimation(true); + }); + } + + piePiece.updateData(data, newIdx); + piePiece.off('click'); + selectedMode && piePiece.on('click', onSectorClick); + group.add(piePiece); + data.setItemGraphicEl(newIdx, piePiece); + }).remove(function (idx) { + var piePiece = oldData.getItemGraphicEl(idx); + group.remove(piePiece); + }).execute(); + + if (hasAnimation && data.count() > 0 && (isFirstRender ? animationType !== 'scale' : animationTypeUpdate !== 'transition')) { + var shape = data.getItemLayout(0); + + for (var s = 1; isNaN(shape.startAngle) && s < data.count(); ++s) { + shape = data.getItemLayout(s); + } + + var r = Math.max(api.getWidth(), api.getHeight()) / 2; + var removeClipPath = bind(group.removeClipPath, group); + group.setClipPath(this._createClipPath(shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel, isFirstRender)); + } else { + // clipPath is used in first-time animation, so remove it when otherwise. See: #8994 + group.removeClipPath(); + } + + this._data = data; + }, + dispose: function () {}, + _createClipPath: function (cx, cy, r, startAngle, clockwise, cb, seriesModel, isFirstRender) { + var clipPath = new Sector({ + shape: { + cx: cx, + cy: cy, + r0: 0, + r: r, + startAngle: startAngle, + endAngle: startAngle, + clockwise: clockwise + } + }); + var initOrUpdate = isFirstRender ? initProps : updateProps; + initOrUpdate(clipPath, { + shape: { + endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2 + } + }, seriesModel, cb); + return clipPath; + }, + + /** + * @implement + */ + 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; + } + } +}); + +/* +* 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 createDataSelectAction = function (seriesType, actionInfos) { + each$1(actionInfos, function (actionInfo) { + actionInfo.update = 'updateView'; + /** + * @payload + * @property {string} seriesName + * @property {string} name + */ + + registerAction(actionInfo, function (payload, ecModel) { + var selected = {}; + ecModel.eachComponent({ + mainType: 'series', + subType: seriesType, + query: payload + }, function (seriesModel) { + if (seriesModel[actionInfo.method]) { + seriesModel[actionInfo.method](payload.name, payload.dataIndex); + } + + var data = seriesModel.getData(); // Create selected map + + data.each(function (idx) { + var name = data.getName(idx); + selected[name] = seriesModel.isSelected(name) || false; + }); + }); + return { + name: payload.name, + selected: selected, + seriesId: payload.seriesId + }; + }); + }); +}; + +/* +* 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. +*/ +// Pick color from palette for each data item. +// Applicable for charts that require applying color palette +// in data level (like pie, funnel, chord). +var dataColor = function (seriesType) { + return { + getTargetSeries: function (ecModel) { + // Pie and funnel may use diferrent scope + var paletteScope = {}; + var seiresModelMap = createHashMap(); + ecModel.eachSeriesByType(seriesType, function (seriesModel) { + seriesModel.__paletteScope = paletteScope; + seiresModelMap.set(seriesModel.uid, seriesModel); + }); + return seiresModelMap; + }, + reset: function (seriesModel, ecModel) { + var dataAll = seriesModel.getRawData(); + var idxMap = {}; + var data = seriesModel.getData(); + data.each(function (idx) { + var rawIdx = data.getRawIndex(idx); + idxMap[rawIdx] = idx; + }); + dataAll.each(function (rawIdx) { + var filteredIdx = idxMap[rawIdx]; // If series.itemStyle.normal.color is a function. itemVisual may be encoded + + var singleDataColor = filteredIdx != null && data.getItemVisual(filteredIdx, 'color', true); + var singleDataBorderColor = filteredIdx != null && data.getItemVisual(filteredIdx, 'borderColor', true); + var itemModel; + + if (!singleDataColor || !singleDataBorderColor) { + // FIXME Performance + itemModel = dataAll.getItemModel(rawIdx); + } + + if (!singleDataColor) { + var color = itemModel.get('itemStyle.color') || seriesModel.getColorFromPalette(dataAll.getName(rawIdx) || rawIdx + '', seriesModel.__paletteScope, dataAll.count()); // Legend may use the visual info in data before processed + + dataAll.setItemVisual(rawIdx, 'color', color); // Data is not filtered + + if (filteredIdx != null) { + data.setItemVisual(filteredIdx, 'color', color); + } + } else { + // Set data all color for legend + dataAll.setItemVisual(rawIdx, 'color', singleDataColor); + } + + if (!singleDataBorderColor) { + var borderColor = itemModel.get('itemStyle.borderColor'); // Legend may use the visual info in data before processed + + dataAll.setItemVisual(rawIdx, 'borderColor', borderColor); // Data is not filtered + + if (filteredIdx != null) { + data.setItemVisual(filteredIdx, 'borderColor', borderColor); + } + } else { + // Set data all borderColor for legend + dataAll.setItemVisual(rawIdx, 'borderColor', singleDataBorderColor); + } + }); + } + }; +}; + +/* +* 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. +*/ +// FIXME emphasis label position is not same with normal label position +var RADIAN$1 = Math.PI / 180; + +function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) { + list.sort(function (a, b) { + return a.y - b.y; + }); + + function shiftDown(start, end, delta, dir) { + for (var j = start; j < end; j++) { + list[j].y += delta; + + if (j > start && j + 1 < end && list[j + 1].y > list[j].y + list[j].height) { + shiftUp(j, delta / 2); + return; + } + } + + shiftUp(end - 1, delta / 2); + } + + function shiftUp(end, delta) { + for (var j = end; j >= 0; j--) { + list[j].y -= delta; + + if (j > 0 && list[j].y > list[j - 1].y + list[j - 1].height) { + break; + } + } + } + + function changeX(list, isDownList, cx, cy, r, dir) { + var lastDeltaX = dir > 0 ? isDownList // right-side + ? Number.MAX_VALUE // down + : 0 // up + : isDownList // left-side + ? Number.MAX_VALUE // down + : 0; // up + + for (var i = 0, l = list.length; i < l; i++) { + var deltaY = Math.abs(list[i].y - cy); + var length = list[i].len; + var length2 = list[i].len2; + var deltaX = deltaY < r + length ? Math.sqrt((r + length + length2) * (r + length + length2) - deltaY * deltaY) : Math.abs(list[i].x - cx); + + if (isDownList && deltaX >= lastDeltaX) { + // right-down, left-down + deltaX = lastDeltaX - 10; + } + + if (!isDownList && deltaX <= lastDeltaX) { + // right-up, left-up + deltaX = lastDeltaX + 10; + } + + list[i].x = cx + deltaX * dir; + lastDeltaX = deltaX; + } + } + + var lastY = 0; + var delta; + var len = list.length; + var upList = []; + var downList = []; + + for (var i = 0; i < len; i++) { + delta = list[i].y - lastY; + + if (delta < 0) { + shiftDown(i, len, -delta, dir); + } + + lastY = list[i].y + list[i].height; + } + + if (viewHeight - lastY < 0) { + shiftUp(len - 1, lastY - viewHeight); + } + + for (var i = 0; i < len; i++) { + if (list[i].y >= cy) { + downList.push(list[i]); + } else { + upList.push(list[i]); + } + } + + changeX(upList, false, cx, cy, r, dir); + changeX(downList, true, cx, cy, r, dir); +} + +function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) { + var leftList = []; + var rightList = []; + + for (var i = 0; i < labelLayoutList.length; i++) { + if (isPositionCenter(labelLayoutList[i])) { + continue; + } + + if (labelLayoutList[i].x < cx) { + leftList.push(labelLayoutList[i]); + } else { + rightList.push(labelLayoutList[i]); + } + } + + adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight); + adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight); + + for (var i = 0; i < labelLayoutList.length; i++) { + if (isPositionCenter(labelLayoutList[i])) { + continue; + } + + var linePoints = labelLayoutList[i].linePoints; + + if (linePoints) { + var dist = linePoints[1][0] - linePoints[2][0]; + + if (labelLayoutList[i].x < cx) { + linePoints[2][0] = labelLayoutList[i].x + 3; + } else { + linePoints[2][0] = labelLayoutList[i].x - 3; + } + + linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y; + linePoints[1][0] = linePoints[2][0] + dist; + } + } +} + +function isPositionCenter(layout) { + // Not change x for center label + return layout.position === 'center'; +} + +var labelLayout = function (seriesModel, r, viewWidth, viewHeight, sum) { + var data = seriesModel.getData(); + var labelLayoutList = []; + var cx; + var cy; + var hasLabelRotate = false; + var minShowLabelRadian = (seriesModel.get('minShowLabelAngle') || 0) * RADIAN$1; + data.each(function (idx) { + var layout = data.getItemLayout(idx); + 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 labelLineModel = itemModel.getModel('labelLine'); + var labelLineLen = labelLineModel.get('length'); + var labelLineLen2 = labelLineModel.get('length2'); + + if (layout.angle < minShowLabelRadian) { + return; + } + + var midAngle = (layout.startAngle + layout.endAngle) / 2; + var dx = Math.cos(midAngle); + var dy = Math.sin(midAngle); + var textX; + var textY; + var linePoints; + var textAlign; + cx = layout.cx; + cy = layout.cy; + var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner'; + + if (labelPosition === 'center') { + textX = layout.cx; + textY = layout.cy; + textAlign = 'center'; + } else { + var x1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dx : layout.r * dx) + cx; + var y1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dy : layout.r * dy) + cy; + textX = x1 + dx * 3; + textY = y1 + dy * 3; + + if (!isLabelInside) { + // For roseType + var x2 = x1 + dx * (labelLineLen + r - layout.r); + var y2 = y1 + dy * (labelLineLen + r - layout.r); + var x3 = x2 + (dx < 0 ? -1 : 1) * labelLineLen2; + var y3 = y2; + textX = x3 + (dx < 0 ? -5 : 5); + textY = y3; + linePoints = [[x1, y1], [x2, y2], [x3, y3]]; + } + + textAlign = isLabelInside ? 'center' : dx > 0 ? 'left' : 'right'; + } + + var font = labelModel.getFont(); + var labelRotate; + var rotate = labelModel.get('rotate'); + + if (typeof rotate === 'number') { + labelRotate = rotate * (Math.PI / 180); + } else { + labelRotate = rotate ? dx < 0 ? -midAngle + Math.PI : -midAngle : 0; + } + + var text = seriesModel.getFormattedLabel(idx, 'normal') || data.getName(idx); + var textRect = getBoundingRect(text, font, textAlign, 'top'); + hasLabelRotate = !!labelRotate; + layout.label = { + x: textX, + y: textY, + position: labelPosition, + height: textRect.height, + len: labelLineLen, + len2: labelLineLen2, + linePoints: linePoints, + textAlign: textAlign, + verticalAlign: 'middle', + rotation: labelRotate, + inside: isLabelInside + }; // Not layout the inside label + + if (!isLabelInside) { + labelLayoutList.push(layout.label); + } + }); + + if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) { + avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight); + } +}; + +/* +* 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 PI2$4 = Math.PI * 2; +var RADIAN = Math.PI / 180; +var pieLayout = function (seriesType, ecModel, api, payload) { + ecModel.eachSeriesByType(seriesType, function (seriesModel) { + var data = seriesModel.getData(); + var valueDim = data.mapDimension('value'); + 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; + 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$4; + var valueSumLargerThanMinAngle = 0; + var currentAngle = startAngle; + var dir = clockwise ? 1 : -1; + 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$4 / 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$4 && validDataCount) { + // Average the angle if rest angle is not enough after all angles is + // Constrained by minAngle + if (restAngle <= 1e-3) { + var angle = PI2$4 / validDataCount; + data.each(valueDim, function (value, idx) { + if (!isNaN(value)) { + var layout = data.getItemLayout(idx); + layout.angle = angle; + layout.startAngle = startAngle + dir * idx * angle; + layout.endAngle = startAngle + dir * (idx + 1) * angle; + } + }); + } else { + unitRadian = restAngle / valueSumLargerThanMinAngle; + currentAngle = startAngle; + data.each(valueDim, function (value, idx) { + if (!isNaN(value)) { + var layout = data.getItemLayout(idx); + var angle = layout.angle === minAngle ? minAngle : value * unitRadian; + layout.startAngle = currentAngle; + layout.endAngle = currentAngle + dir * angle; + currentAngle += dir * angle; + } + }); + } + } + + labelLayout(seriesModel, r, width, height); + }); +}; + +/* +* 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 dataFilter = function (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++) { + if (!legendModels[i].isSelected(name)) { + return false; + } + } + + return 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. +*/ +createDataSelectAction('pie', [{ + type: 'pieToggleSelect', + event: 'pieselectchanged', + method: 'toggleSelected' +}, { + type: 'pieSelect', + event: 'pieselected', + method: 'select' +}, { + type: 'pieUnSelect', + event: 'pieunselected', + method: 'unSelect' +}]); +registerVisual(dataColor('pie')); +registerLayout(curry(pieLayout, 'pie')); +registerProcessor(dataFilter('pie')); + +/* +* 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. +*/ + +/* global Uint32Array, Float64Array, Float32Array */ +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) { + 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 LinesSeries = SeriesModel.extend({ + type: 'series.lines', + dependencies: ['grid', 'polar'], + visualColorAccessPath: 'lineStyle.color', + 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); + } + + LinesSeries.superApply(this, 'init', arguments); + }, + mergeOption: function (option) { + // The input data may be null/undefined. + option.data = option.data || []; + 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); + } + } + + LinesSeries.superApply(this, 'mergeOption', arguments); + }, + 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); + }, + _getCoordsFromItemModel: function (idx) { + var itemModel = this.getData().getItemModel(idx); + var coords = itemModel.option instanceof Array ? itemModel.option : itemModel.getShallow('coords'); + return coords; + }, + getLineCoordsCount: function (idx) { + if (this._flatCoordsOffset) { + return this._flatCoordsOffset[idx * 2 + 1]; + } else { + return this._getCoordsFromItemModel(idx).length; + } + }, + 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; + } + }, + _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 (typeof data[0] === 'number') { + 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; + + + } + } + + return { + flatCoordsOffset: new Uint32Array(coordsOffsetAndLenStorage.buffer, 0, offsetCursor), + flatCoords: coordsStorage, + count: dataCount + }; + } + + return { + flatCoordsOffset: null, + flatCoords: null, + count: data.length + }; + }, + getInitialData: function (option, ecModel) { + var lineData = new List(['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; + }, + formatTooltip: function (dataIndex) { + 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 html = []; + fromName != null && html.push(fromName); + toName != null && html.push(toName); + return encodeHTML(html.join(' > ')); + }, + preventIncremental: function () { + return !!this.get('effect.show'); + }, + getProgressive: function () { + var progressive = this.option.progressive; + + if (progressive == null) { + return this.option.large ? 1e4 : this.get('progressive'); + } + + return progressive; + }, + getProgressiveThreshold: function () { + var progressiveThreshold = this.option.progressiveThreshold; + + if (progressiveThreshold == null) { + return this.option.large ? 2e4 : this.get('progressiveThreshold'); + } + + return progressiveThreshold; + }, + defaultOption: { + coordinateSystem: 'geo', + zlevel: 0, + z: 2, + legendHoverLink: true, + hoverAnimation: true, + // Cartesian coordinate system + xAxisIndex: 0, + yAxisIndex: 0, + symbol: ['none', 'none'], + symbolSize: [10, 10], + // Geo coordinate system + geoIndex: 0, + effect: { + show: false, + period: 4, + // Animation delay. support callback + // delay: 0, + // If move with constant speed px/sec + // period will be ignored if this property is > 0, + constantSpeed: 0, + symbol: 'circle', + symbolSize: 3, + loop: true, + // Length of trail, 0 - 1 + trailLength: 0.2 // Same with lineStyle.color + // color + + }, + large: false, + // Available when large is true + largeThreshold: 2000, + // If lines are polyline + // polyline not support curveness, label, animation + polyline: false, + // If clip the overflow. + // Available when coordinateSystem is cartesian or polar. + clip: true, + label: { + show: false, + position: 'end' // distance: 5, + // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调 + + }, + lineStyle: { + opacity: 0.5 + } + } +}); + +/* +* 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. +*/ + +/** + * Line path for bezier and straight line draw + */ +var straightLineProto = Line.prototype; +var bezierCurveProto = BezierCurve.prototype; + +function isLine(shape) { + return isNaN(+shape.cpx1) || isNaN(+shape.cpy1); +} + +var LinePath = extendShape({ + type: 'ec-line', + style: { + stroke: '#000', + fill: null + }, + shape: { + x1: 0, + y1: 0, + x2: 0, + y2: 0, + percent: 1, + cpx1: null, + cpy1: null + }, + buildPath: function (ctx, shape) { + this[isLine(shape) ? '_buildPathLine' : '_buildPathCurve'](ctx, shape); + }, + _buildPathLine: straightLineProto.buildPath, + _buildPathCurve: bezierCurveProto.buildPath, + pointAt: function (t) { + return this[isLine(this.shape) ? '_pointAtLine' : '_pointAtCurve'](t); + }, + _pointAtLine: straightLineProto.pointAt, + _pointAtCurve: bezierCurveProto.pointAt, + tangentAt: function (t) { + var shape = this.shape; + var p = isLine(shape) ? [shape.x2 - shape.x1, shape.y2 - shape.y1] : this._tangentAtCurve(t); + return normalize(p, p); + }, + _tangentAtCurve: bezierCurveProto.tangentAt +}); + +/* +* 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. +*/ + +/** + * @module echarts/chart/helper/Line + */ +var SYMBOL_CATEGORIES = ['fromSymbol', 'toSymbol']; + +function makeSymbolTypeKey(symbolCategory) { + return '_' + symbolCategory + 'Type'; +} +/** + * @inner + */ + + +function createSymbol$1(name, lineData, idx) { + var color = lineData.getItemVisual(idx, 'color'); + var symbolType = lineData.getItemVisual(idx, name); + var symbolSize = lineData.getItemVisual(idx, name + 'Size'); + + if (!symbolType || symbolType === 'none') { + return; + } + + if (!isArray(symbolSize)) { + symbolSize = [symbolSize, symbolSize]; + } + + var symbolPath = createSymbol(symbolType, -symbolSize[0] / 2, -symbolSize[1] / 2, symbolSize[0], symbolSize[1], color); + symbolPath.name = name; + return symbolPath; +} + +function createLine(points) { + var line = new LinePath({ + 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; + } +} + +function updateSymbolAndLabelBeforeLineUpdate() { + var lineGroup = this; + var symbolFrom = lineGroup.childOfName('fromSymbol'); + var symbolTo = lineGroup.childOfName('toSymbol'); + var label = lineGroup.childOfName('label'); // Quick reject + + if (!symbolFrom && !symbolTo && label.ignore) { + return; + } + + var invScale = 1; + var parentNode = this.parent; + + while (parentNode) { + if (parentNode.scale) { + invScale /= parentNode.scale[0]; + } + + 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); + + if (symbolFrom) { + symbolFrom.attr('position', fromPos); + var tangent = line.tangentAt(0); + symbolFrom.attr('rotation', Math.PI / 2 - Math.atan2(tangent[1], tangent[0])); + symbolFrom.attr('scale', [invScale * percent, invScale * percent]); + } + + if (symbolTo) { + symbolTo.attr('position', toPos); + var tangent = line.tangentAt(1); + symbolTo.attr('rotation', -Math.PI / 2 - Math.atan2(tangent[1], tangent[0])); + symbolTo.attr('scale', [invScale * percent, invScale * percent]); + } + + if (!label.ignore) { + label.attr('position', toPos); + var textPosition; + var textAlign; + var textVerticalAlign; + var distance$$1 = 5 * invScale; // End + + if (label.__position === 'end') { + textPosition = [d[0] * distance$$1 + toPos[0], d[1] * distance$$1 + 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'; + } // Middle + else if (label.__position === 'middle') { + 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]; + } + + textPosition = [cp[0] + n[0] * distance$$1, cp[1] + n[1] * distance$$1]; + textAlign = 'center'; + textVerticalAlign = 'bottom'; + var rotation = -Math.atan2(tangent[1], tangent[0]); + + if (toPos[0] < fromPos[0]) { + rotation = Math.PI + rotation; + } + + label.attr('rotation', rotation); + } // Start + else { + textPosition = [-d[0] * distance$$1 + fromPos[0], -d[1] * distance$$1 + 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'; + } + + label.attr({ + style: { + // Use the user specified text align and baseline first + textVerticalAlign: label.__verticalAlign || textVerticalAlign, + textAlign: label.__textAlign || textAlign + }, + position: textPosition, + scale: [invScale, invScale] + }); + } +} +/** + * @constructor + * @extends {module:zrender/graphic/Group} + * @alias {module:echarts/chart/helper/Line} + */ + + +function Line$1(lineData, idx, seriesScope) { + Group.call(this); + + this._createLine(lineData, idx, seriesScope); +} + +var lineProto = Line$1.prototype; // Update symbol position and rotation + +lineProto.beforeUpdate = updateSymbolAndLabelBeforeLineUpdate; + +lineProto._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); + var label = new Text({ + name: 'label', + // FIXME + // Temporary solution for `focusNodeAdjacency`. + // line label do not use the opacity of lineStyle. + lineLabelOriginalOpacity: 1 + }); + this.add(label); + each$1(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); +}; + +lineProto.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$1(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); +}; + +lineProto._updateCommonStl = function (lineData, idx, seriesScope) { + var seriesModel = lineData.hostModel; + var line = this.childOfName('line'); + var lineStyle = seriesScope && seriesScope.lineStyle; + var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle; + var labelModel = seriesScope && seriesScope.labelModel; + var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel; // Optimization for large dataset + + if (!seriesScope || lineData.hasItemOption) { + var itemModel = lineData.getItemModel(idx); + lineStyle = itemModel.getModel('lineStyle').getLineStyle(); + hoverLineStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle(); + labelModel = itemModel.getModel('label'); + hoverLabelModel = itemModel.getModel('emphasis.label'); + } + + var visualColor = lineData.getItemVisual(idx, 'color'); + var visualOpacity = retrieve3(lineData.getItemVisual(idx, 'opacity'), lineStyle.opacity, 1); + line.useStyle(defaults({ + strokeNoScale: true, + fill: 'none', + stroke: visualColor, + opacity: visualOpacity + }, lineStyle)); + line.hoverStyle = hoverLineStyle; // Update symbol + + each$1(SYMBOL_CATEGORIES, function (symbolCategory) { + var symbol = this.childOfName(symbolCategory); + + if (symbol) { + symbol.setColor(visualColor); + symbol.setStyle({ + opacity: visualOpacity + }); + } + }, this); + var showLabel = labelModel.getShallow('show'); + var hoverShowLabel = hoverLabelModel.getShallow('show'); + var label = this.childOfName('label'); + var defaultLabelColor; + var baseText; // FIXME: the logic below probably should be merged to `graphic.setLabelStyle`. + + if (showLabel || hoverShowLabel) { + defaultLabelColor = visualColor || '#000'; + baseText = seriesModel.getFormattedLabel(idx, 'normal', lineData.dataType); + + if (baseText == null) { + var rawVal = seriesModel.getRawValue(idx); + baseText = rawVal == null ? lineData.getName(idx) : isFinite(rawVal) ? round$1(rawVal) : rawVal; + } + } + + var normalText = showLabel ? baseText : null; + var emphasisText = hoverShowLabel ? retrieve2(seriesModel.getFormattedLabel(idx, 'emphasis', lineData.dataType), baseText) : null; + var labelStyle = label.style; // Always set `textStyle` even if `normalStyle.text` is null, because default + // values have to be set on `normalStyle`. + + if (normalText != null || emphasisText != null) { + setTextStyle(label.style, labelModel, { + text: normalText + }, { + autoColor: defaultLabelColor + }); + label.__textAlign = labelStyle.textAlign; + label.__verticalAlign = labelStyle.textVerticalAlign; // 'start', 'middle', 'end' + + label.__position = labelModel.get('position') || 'middle'; + } + + if (emphasisText != null) { + // Only these properties supported in this emphasis style here. + label.hoverStyle = { + text: emphasisText, + textFill: hoverLabelModel.getTextColor(true), + // For merging hover style to normal style, do not use + // `hoverLabelModel.getFont()` here. + fontStyle: hoverLabelModel.getShallow('fontStyle'), + fontWeight: hoverLabelModel.getShallow('fontWeight'), + fontSize: hoverLabelModel.getShallow('fontSize'), + fontFamily: hoverLabelModel.getShallow('fontFamily') + }; + } else { + label.hoverStyle = { + text: null + }; + } + + label.ignore = !showLabel && !hoverShowLabel; + setHoverStyle(this); +}; + +lineProto.highlight = function () { + this.trigger('emphasis'); +}; + +lineProto.downplay = function () { + this.trigger('normal'); +}; + +lineProto.updateLayout = function (lineData, idx) { + this.setLinePoints(lineData.getItemLayout(idx)); +}; + +lineProto.setLinePoints = function (points) { + var linePath = this.childOfName('line'); + setLinePoints(linePath.shape, points); + linePath.dirty(); +}; + +inherits(Line$1, Group); + +/* +* 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. +*/ + +/** + * @module echarts/chart/helper/LineDraw + */ +/** + * @alias module:echarts/component/marker/LineDraw + * @constructor + */ + +function LineDraw(ctor) { + this._ctor = ctor || Line$1; + this.group = new Group(); +} + +var lineDrawProto = LineDraw.prototype; + +lineDrawProto.isPersistent = function () { + return true; +}; +/** + * @param {module:echarts/data/List} lineData + */ + + +lineDrawProto.updateData = function (lineData) { + 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) { + doAdd(lineDraw, lineData, idx, seriesScope); + }).update(function (newIdx, oldIdx) { + doUpdate(lineDraw, oldLineData, lineData, oldIdx, newIdx, seriesScope); + }).remove(function (idx) { + group.remove(oldLineData.getItemGraphicEl(idx)); + }).execute(); +}; + +function doAdd(lineDraw, lineData, idx, seriesScope) { + var itemLayout = lineData.getItemLayout(idx); + + if (!lineNeedsDraw(itemLayout)) { + return; + } + + var el = new lineDraw._ctor(lineData, idx, seriesScope); + lineData.setItemGraphicEl(idx, el); + lineDraw.group.add(el); +} + +function doUpdate(lineDraw, oldLineData, newLineData, oldIdx, newIdx, seriesScope) { + var itemEl = oldLineData.getItemGraphicEl(oldIdx); + + if (!lineNeedsDraw(newLineData.getItemLayout(newIdx))) { + lineDraw.group.remove(itemEl); + return; + } + + if (!itemEl) { + itemEl = new lineDraw._ctor(newLineData, newIdx, seriesScope); + } else { + itemEl.updateData(newLineData, newIdx, seriesScope); + } + + newLineData.setItemGraphicEl(newIdx, itemEl); + lineDraw.group.add(itemEl); +} + +lineDrawProto.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); +}; + +lineDrawProto.incrementalPrepareUpdate = function (lineData) { + this._seriesScope = makeSeriesScope$1(lineData); + this._lineData = null; + this.group.removeAll(); +}; + +lineDrawProto.incrementalUpdate = function (taskParams, lineData) { + function updateIncrementalAndHover(el) { + if (!el.isGroup) { + el.incremental = el.useHoverLayer = true; + } + } + + for (var idx = taskParams.start; idx < taskParams.end; idx++) { + var itemLayout = lineData.getItemLayout(idx); + + if (lineNeedsDraw(itemLayout)) { + var el = new this._ctor(lineData, idx, this._seriesScope); + el.traverse(updateIncrementalAndHover); + this.group.add(el); + lineData.setItemGraphicEl(idx, el); + } + } +}; + +function makeSeriesScope$1(lineData) { + var hostModel = lineData.hostModel; + return { + lineStyle: hostModel.getModel('lineStyle').getLineStyle(), + hoverLineStyle: hostModel.getModel('emphasis.lineStyle').getLineStyle(), + labelModel: hostModel.getModel('label'), + hoverLabelModel: hostModel.getModel('emphasis.label') + }; +} + +lineDrawProto.remove = function () { + this._clearIncremental(); + + this._incremental = null; + this.group.removeAll(); +}; + +lineDrawProto._clearIncremental = function () { + var incremental = this._incremental; + + if (incremental) { + incremental.clearDisplaybles(); + } +}; + +function isPointNaN(pt) { + return isNaN(pt[0]) || isNaN(pt[1]); +} + +function lineNeedsDraw(pts) { + return !isPointNaN(pts[0]) && !isPointNaN(pts[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. +*/ + +/** + * Provide effect for line + * @module echarts/chart/helper/EffectLine + */ +/** + * @constructor + * @extends {module:zrender/graphic/Group} + * @alias {module:echarts/chart/helper/Line} + */ + +function EffectLine(lineData, idx, seriesScope) { + Group.call(this); + this.add(this.createLine(lineData, idx, seriesScope)); + + this._updateEffectSymbol(lineData, idx); +} + +var effectLineProto = EffectLine.prototype; + +effectLineProto.createLine = function (lineData, idx, seriesScope) { + return new Line$1(lineData, idx, seriesScope); +}; + +effectLineProto._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 color = effectModel.get('color') || lineData.getItemVisual(idx, 'color'); + 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.attr('scale', size); + symbol.setColor(color); + symbol.attr('scale', size); + this._symbolType = symbolType; + + this._updateEffectAnimation(lineData, effectModel, idx); +}; + +effectLineProto._updateEffectAnimation = function (lineData, effectModel, idx) { + var symbol = this.childAt(1); + + if (!symbol) { + return; + } + + var self = this; + 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; + }); + var isDelayFunc = typeof delayExpr === 'function'; // 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 delay = delayExpr; + + if (isDelayFunc) { + delay = delayExpr(idx); + } + + if (symbol.__t > 0) { + delay = -period * symbol.__t; + } + + symbol.__t = 0; + var animator = symbol.animate('', loop).when(period, { + __t: 1 + }).delay(delay).during(function () { + self.updateSymbolPosition(symbol); + }); + + if (!loop) { + animator.done(function () { + self.remove(symbol); + }); + } + + animator.start(); + } + + this._period = period; + this._loop = loop; +}; + +effectLineProto.getLineLength = function (symbol) { + // Not so accurate + return dist(symbol.__p1, symbol.__cp1) + dist(symbol.__cp1, symbol.__p2); +}; + +effectLineProto.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]; +}; + +effectLineProto.updateData = function (lineData, idx, seriesScope) { + this.childAt(0).updateData(lineData, idx, seriesScope); + + this._updateEffectSymbol(lineData, idx); +}; + +effectLineProto.updateSymbolPosition = function (symbol) { + var p1 = symbol.__p1; + var p2 = symbol.__p2; + var cp1 = symbol.__cp1; + var t = symbol.__t; + var pos = symbol.position; + 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; + symbol.ignore = false; +}; + +effectLineProto.updateLayout = function (lineData, idx) { + this.childAt(0).updateLayout(lineData, idx); + var effectModel = lineData.getItemModel(idx).getModel('effect'); + + this._updateEffectAnimation(lineData, effectModel, idx); +}; + +inherits(EffectLine, Group); + +/* +* 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. +*/ + +/** + * @module echarts/chart/helper/Line + */ +/** + * @constructor + * @extends {module:zrender/graphic/Group} + * @alias {module:echarts/chart/helper/Polyline} + */ + +function Polyline$2(lineData, idx, seriesScope) { + Group.call(this); + + this._createPolyline(lineData, idx, seriesScope); +} + +var polylineProto = Polyline$2.prototype; + +polylineProto._createPolyline = function (lineData, idx, seriesScope) { + // var seriesModel = lineData.hostModel; + var points = lineData.getItemLayout(idx); + var line = new Polyline({ + shape: { + points: points + } + }); + this.add(line); + + this._updateCommonStl(lineData, idx, seriesScope); +}; + +polylineProto.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); +}; + +polylineProto._updateCommonStl = function (lineData, idx, seriesScope) { + var line = this.childAt(0); + var itemModel = lineData.getItemModel(idx); + var visualColor = lineData.getItemVisual(idx, 'color'); + var lineStyle = seriesScope && seriesScope.lineStyle; + var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle; + + if (!seriesScope || lineData.hasItemOption) { + lineStyle = itemModel.getModel('lineStyle').getLineStyle(); + hoverLineStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle(); + } + + line.useStyle(defaults({ + strokeNoScale: true, + fill: 'none', + stroke: visualColor + }, lineStyle)); + line.hoverStyle = hoverLineStyle; + setHoverStyle(this); +}; + +polylineProto.updateLayout = function (lineData, idx) { + var polyline = this.childAt(0); + polyline.setShape('points', lineData.getItemLayout(idx)); +}; + +inherits(Polyline$2, Group); + +/* +* 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. +*/ + +/** + * Provide effect for line + * @module echarts/chart/helper/EffectLine + */ +/** + * @constructor + * @extends {module:echarts/chart/helper/EffectLine} + * @alias {module:echarts/chart/helper/Polyline} + */ + +function EffectPolyline(lineData, idx, seriesScope) { + EffectLine.call(this, lineData, idx, seriesScope); + this._lastFrame = 0; + this._lastFramePercent = 0; +} + +var effectPolylineProto = EffectPolyline.prototype; // Overwrite + +effectPolylineProto.createLine = function (lineData, idx, seriesScope) { + return new Polyline$2(lineData, idx, seriesScope); +}; // Overwrite + + +effectPolylineProto.updateAnimationPoints = function (symbol, points) { + this._points = points; + var accLenArr = [0]; + var len$$1 = 0; + + for (var i = 1; i < points.length; i++) { + var p1 = points[i - 1]; + var p2 = points[i]; + len$$1 += dist(p1, p2); + accLenArr.push(len$$1); + } + + if (len$$1 === 0) { + return; + } + + for (var i = 0; i < accLenArr.length; i++) { + accLenArr[i] /= len$$1; + } + + this._offsets = accLenArr; + this._length = len$$1; +}; // Overwrite + + +effectPolylineProto.getLineLength = function (symbol) { + return this._length; +}; // Overwrite + + +effectPolylineProto.updateSymbolPosition = function (symbol) { + var t = symbol.__t; + var points = this._points; + var offsets = this._offsets; + var len$$1 = 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 - 1); + + for (frame = start; frame >= 0; frame--) { + if (offsets[frame] <= t) { + break; + } + } // PENDING really need to do this ? + + + frame = Math.min(frame, len$$1 - 2); + } else { + for (var frame = lastFrame; frame < len$$1; frame++) { + if (offsets[frame] > t) { + break; + } + } + + frame = Math.min(frame - 1, len$$1 - 2); + } + + lerp(symbol.position, points[frame], points[frame + 1], (t - offsets[frame]) / (offsets[frame + 1] - offsets[frame])); + var tx = points[frame + 1][0] - points[frame][0]; + var ty = points[frame + 1][1] - points[frame][1]; + symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2; + this._lastFrame = frame; + this._lastFramePercent = t; + symbol.ignore = false; +}; + +inherits(EffectPolyline, EffectLine); + +/* +* 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. +*/ +// TODO Batch by color +var LargeLineShape = extendShape({ + shape: { + polyline: false, + curveness: 0, + segs: [] + }, + buildPath: function (path, shape) { + var segs = shape.segs; + var curveness = shape.curveness; + + if (shape.polyline) { + for (var i = 0; i < segs.length;) { + var count = segs[i++]; + + if (count > 0) { + path.moveTo(segs[i++], segs[i++]); + + for (var k = 1; k < count; k++) { + path.lineTo(segs[i++], segs[i++]); + } + } + } + } else { + for (var i = 0; i < segs.length;) { + var x0 = segs[i++]; + var y0 = segs[i++]; + var x1 = segs[i++]; + var y1 = segs[i++]; + path.moveTo(x0, y0); + + if (curveness > 0) { + var x2 = (x0 + x1) / 2 - (y0 - y1) * curveness; + var y2 = (y0 + y1) / 2 - (x1 - x0) * curveness; + path.quadraticCurveTo(x2, y2, x1, y1); + } else { + path.lineTo(x1, y1); + } + } + } + }, + findDataIndex: function (x, y) { + var shape = this.shape; + var segs = shape.segs; + var curveness = shape.curveness; + + 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$1(x0, y0, x1, y1)) { + 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$3(x0, y0, x2, y2, x1, y1)) { + return dataIndex; + } + } else { + if (containStroke$1(x0, y0, x1, y1)) { + return dataIndex; + } + } + + dataIndex++; + } + } + + return -1; + } +}); + +function LargeLineDraw() { + this.group = new Group(); +} + +var largeLineProto = LargeLineDraw.prototype; + +largeLineProto.isPersistent = function () { + return !this._incremental; +}; +/** + * Update symbols draw by new data + * @param {module:echarts/data/List} data + */ + + +largeLineProto.updateData = function (data) { + this.group.removeAll(); + var lineEl = new LargeLineShape({ + rectHover: true, + cursor: 'default' + }); + lineEl.setShape({ + segs: data.getLayout('linesPoints') + }); + + this._setCommon(lineEl, data); // Add back + + + this.group.add(lineEl); + this._incremental = null; +}; +/** + * @override + */ + + +largeLineProto.incrementalPrepareUpdate = function (data) { + this.group.removeAll(); + + this._clearIncremental(); + + if (data.count() > 5e5) { + if (!this._incremental) { + this._incremental = new IncrementalDisplayble({ + silent: true + }); + } + + this.group.add(this._incremental); + } else { + this._incremental = null; + } +}; +/** + * @override + */ + + +largeLineProto.incrementalUpdate = function (taskParams, data) { + var lineEl = new LargeLineShape(); + lineEl.setShape({ + segs: data.getLayout('linesPoints') + }); + + this._setCommon(lineEl, data, !!this._incremental); + + if (!this._incremental) { + lineEl.rectHover = true; + lineEl.cursor = 'default'; + lineEl.__startIndex = taskParams.start; + this.group.add(lineEl); + } else { + this._incremental.addDisplayable(lineEl, true); + } +}; +/** + * @override + */ + + +largeLineProto.remove = function () { + this._clearIncremental(); + + this._incremental = null; + this.group.removeAll(); +}; + +largeLineProto._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 visualColor = data.getVisual('color'); + + if (visualColor) { + lineEl.setStyle('stroke', visualColor); + } + + lineEl.setStyle('fill'); + + if (!isIncremental) { + // Enable tooltip + // PENDING May have performance issue when path is extremely large + lineEl.seriesIndex = hostModel.seriesIndex; + lineEl.on('mousemove', function (e) { + lineEl.dataIndex = null; + var dataIndex = lineEl.findDataIndex(e.offsetX, e.offsetY); + + if (dataIndex > 0) { + // Provide dataIndex for tooltip + lineEl.dataIndex = dataIndex + lineEl.__startIndex; + } + }); + } +}; + +largeLineProto._clearIncremental = function () { + var incremental = this._incremental; + + if (incremental) { + incremental.clearDisplaybles(); + } +}; + +/* +* 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. +*/ + +/* global Float32Array */ +var linesLayout = { + seriesType: 'lines', + plan: createRenderPlanner(), + reset: function (seriesModel) { + var coordSys = seriesModel.coordinateSystem; + var isPolyline = seriesModel.get('polyline'); + var isLarge = seriesModel.pipelineContext.large; + + function progress(params, lineData) { + var lineCoords = []; + + if (isLarge) { + var points; + 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); + } + } + } + + return { + progress: progress + }; + } +}; + +/* +* 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. +*/ +extendChartView({ + type: 'lines', + init: function () {}, + 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) { + if (!isSvg) { + zr.configLayer(zlevel, { + motionBlur: true, + lastFrameAlpha: Math.max(Math.min(trailLength / 10 + 0.9, 1), 0) + }); + } + } + + 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; + }, + incrementalPrepareRender: function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + + var lineDraw = this._updateLineDraw(data, seriesModel); + + lineDraw.incrementalPrepareUpdate(data); + + this._clearLayer(api); + + this._finished = false; + }, + incrementalRender: function (taskParams, seriesModel, ecModel) { + this._lineDraw.incrementalUpdate(taskParams, seriesModel.getData()); + + this._finished = taskParams.end === seriesModel.getData().count(); + }, + 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); + + if (res.progress) { + res.progress({ + start: 0, + end: data.count() + }, data); + } + + this._lineDraw.updateLayout(); + + this._clearLayer(api); + } + }, + _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 (!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$2 : hasEffect ? EffectLine : Line$1); + this._hasEffet = hasEffect; + this._isPolyline = isPolyline; + this._isLargeDraw = isLargeDraw; + this.group.removeAll(); + } + + this.group.add(lineDraw.group); + return lineDraw; + }, + _showEffect: function (seriesModel) { + return !!seriesModel.get('effect.show'); + }, + _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); + } + }, + remove: function (ecModel, api) { + this._lineDraw && this._lineDraw.remove(); + this._lineDraw = null; // Clear motion when lineDraw is removed + + this._clearLayer(api); + }, + dispose: function () {} +}); + +/* +* 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$1(a) { + if (!(a instanceof Array)) { + a = [a, a]; + } + + return a; +} + +var opacityQuery = 'lineStyle.opacity'.split('.'); +var linesVisual = { + seriesType: 'lines', + reset: function (seriesModel, ecModel, api) { + var symbolType = normalize$1(seriesModel.get('symbol')); + var symbolSize = normalize$1(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]); + data.setVisual('opacity', seriesModel.get(opacityQuery)); + + function dataEach(data, idx) { + var itemModel = data.getItemModel(idx); + var symbolType = normalize$1(itemModel.getShallow('symbol', true)); + var symbolSize = normalize$1(itemModel.getShallow('symbolSize', true)); + var opacity = itemModel.get(opacityQuery); + 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]); + data.setItemVisual(idx, 'opacity', opacity); + } + + 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. +*/ +registerLayout(linesLayout); +registerVisual(linesVisual); + +/* +* 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. +*/ +extendComponentModel({ + type: 'title', + layoutMode: { + type: 'box', + ignoreSize: true + }, + defaultOption: { + // 一级层叠 + zlevel: 0, + // 二级层叠 + z: 6, + show: true, + text: '', + // 超链接跳转 + // link: null, + // 仅支持self | blank + target: 'blank', + subtext: '', + // 超链接跳转 + // sublink: null, + // 仅支持self | blank + subtarget: 'blank', + // 'center' ¦ 'left' ¦ 'right' + // ¦ {number}(x坐标,单位px) + left: 0, + // 'top' ¦ 'bottom' ¦ 'center' + // ¦ {number}(y坐标,单位px) + top: 0, + // 水平对齐 + // 'auto' | 'left' | 'right' | 'center' + // 默认根据 left 的位置判断是左对齐还是右对齐 + // textAlign: null + // + // 垂直对齐 + // 'auto' | 'top' | 'bottom' | 'middle' + // 默认根据 top 位置判断是上对齐还是下对齐 + // textVerticalAlign: null + // textBaseline: null // The same as textVerticalAlign. + backgroundColor: 'rgba(0,0,0,0)', + // 标题边框颜色 + borderColor: '#ccc', + // 标题边框线宽,单位px,默认为0(无边框) + borderWidth: 0, + // 标题内边距,单位px,默认各方向内边距为5, + // 接受数组分别设定上右下左边距,同css + padding: 5, + // 主副标题纵向间隔,单位px,默认为10, + itemGap: 10, + textStyle: { + fontSize: 18, + fontWeight: 'bolder', + color: '#333' + }, + subtextStyle: { + color: '#aaa' + } + } +}); // View + +extendComponentView({ + type: 'title', + 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 Text({ + style: setTextStyle({}, textStyleModel, { + text: titleModel.get('text'), + textFill: textStyleModel.getTextColor() + }, { + disableBox: true + }), + z2: 10 + }); + var textRect = textEl.getBoundingRect(); + var subText = titleModel.get('subtext'); + var subTextEl = new Text({ + style: setTextStyle({}, subtextStyleModel, { + text: subText, + textFill: subtextStyleModel.getTextColor(), + y: textRect.height + titleModel.get('itemGap'), + textVerticalAlign: '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 () { + window.open(link, '_' + titleModel.get('target')); + }); + } + + if (sublink) { + subTextEl.on('click', function () { + window.open(sublink, '_' + titleModel.get('subtarget')); + }); + } + + textEl.eventData = 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'); + + 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'); + + 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.attr('position', [layoutRect.x, layoutRect.y]); + var alignStyle = { + textAlign: textAlign, + textVerticalAlign: 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); + } +}); + +/* +* 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 langSelector = lang.legend.selector; +var defaultSelectorOption = { + all: { + type: 'all', + title: clone(langSelector.all) + }, + inverse: { + type: 'inverse', + title: clone(langSelector.inverse) + } +}; +var LegendModel = extendComponentModel({ + type: 'legend.plain', + dependencies: ['series'], + 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 + }, + init: function (option, parentModel, ecModel) { + this.mergeDefaultAndTheme(option, ecModel); + option.selected = option.selected || {}; + + this._updateSelector(option); + }, + mergeOption: function (option) { + LegendModel.superCall(this, 'mergeOption', option); + + this._updateSelector(option); + }, + _updateSelector: function (option) { + var selector = option.selector; + + if (selector === true) { + selector = option.selector = ['all', 'inverse']; + } + + if (isArray(selector)) { + each$1(selector, function (item, index) { + isString(item) && (item = { + type: item + }); + selector[index] = merge(item, defaultSelectorOption[item.type]); + }); + } + }, + 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 = legendData[i].get('name'); + + if (this.isSelected(name)) { + // Force to unselect others + this.select(name); + hasSelected = true; + break; + } + } // Try select the first if selectedMode is single + + + !hasSelected && this.select(legendData[0].get('name')); + } + }, + _updateData: function (ecModel) { + var potentialData = []; + var availableNames = []; + ecModel.eachRawSeries(function (seriesModel) { + var seriesName = seriesModel.name; + availableNames.push(seriesName); + var isPotential; + + if (seriesModel.legendDataProvider) { + var data = seriesModel.legendDataProvider(); + var names = data.mapArray(data.getName); + + 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 (typeof dataItem === 'string' || typeof dataItem === 'number') { + dataItem = { + name: dataItem + }; + } + + return new Model(dataItem, this, this.ecModel); + }, this); + /** + * @type {Array.} + * @private + */ + + this._data = legendData; + }, + + /** + * @return {Array.} + */ + getData: function () { + return this._data; + }, + + /** + * @param {string} name + */ + select: function (name) { + var selected = this.option.selected; + var selectedMode = this.get('selectedMode'); + + if (selectedMode === 'single') { + var data = this._data; + each$1(data, function (dataItem) { + selected[dataItem.get('name')] = false; + }); + } + + selected[name] = true; + }, + + /** + * @param {string} name + */ + unSelect: function (name) { + if (this.get('selectedMode') !== 'single') { + this.option.selected[name] = false; + } + }, + + /** + * @param {string} name + */ + toggleSelected: function (name) { + var selected = this.option.selected; // Default is true + + if (!selected.hasOwnProperty(name)) { + selected[name] = true; + } + + this[selected[name] ? 'unSelect' : 'select'](name); + }, + allSelect: function () { + var data = this._data; + var selected = this.option.selected; + each$1(data, function (dataItem) { + selected[dataItem.get('name', true)] = true; + }); + }, + inverseSelect: function () { + var data = this._data; + var selected = this.option.selected; + each$1(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]; + }); + }, + + /** + * @param {string} name + */ + isSelected: function (name) { + var selected = this.option.selected; + return !(selected.hasOwnProperty(name) && !selected[name]) && indexOf(this._availableNames, name) >= 0; + }, + getOrient: function () { + return this.get('orient') === 'vertical' ? { + index: 1, + name: 'vertical' + } : { + index: 0, + name: 'horizontal' + }; + }, + defaultOption: { + // 一级层叠 + zlevel: 0, + // 二级层叠 + z: 4, + show: true, + // 布局方式,默认为水平布局,可选为: + // 'horizontal' | 'vertical' + orient: 'horizontal', + left: 'center', + // right: 'center', + top: 0, + // bottom: null, + // 水平对齐 + // 'auto' | 'left' | 'right' + // 默认为 'auto', 根据 x 的位置判断是左对齐还是右对齐 + align: 'auto', + backgroundColor: 'rgba(0,0,0,0)', + // 图例边框颜色 + borderColor: '#ccc', + borderRadius: 0, + // 图例边框线宽,单位px,默认为0(无边框) + borderWidth: 0, + // 图例内边距,单位px,默认各方向内边距为5, + // 接受数组分别设定上右下左边距,同css + padding: 5, + // 各个item之间的间隔,单位px,默认为10, + // 横向布局时为水平间隔,纵向布局时为纵向间隔 + itemGap: 10, + // the width of legend symbol + itemWidth: 25, + // the height of legend symbol + itemHeight: 14, + // the color of unselected legend symbol + inactiveColor: '#ccc', + // the borderColor of unselected legend symbol + inactiveBorderColor: '#ccc', + itemStyle: { + // the default borderWidth of legend symbol + borderWidth: 0 + }, + textStyle: { + // 图例文字颜色 + color: '#333' + }, + // formatter: '', + // 选择模式,默认开启图例开关 + selectedMode: true, + // 配置默认选中状态,可配合LEGEND.SELECTED事件做动态数据载入 + // selected: null, + // 图例内容(详见legend.data,数组中每一项代表一个item + // data: [], + // Usage: + // selector: [{type: 'all or inverse', title: xxx}] + // or + // selector: true + // or + // selector: ['all', 'inverse'] + 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' + } + }, + // Value can be 'start' or 'end' + selectorPosition: 'auto', + selectorItemGap: 7, + selectorButtonGap: 10, + // Tooltip 相关配置 + tooltip: { + show: false + } + } +}); + +/* +* 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 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$1(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 + }; +} +/** + * @event legendToggleSelect + * @type {Object} + * @property {string} type 'legendToggleSelect' + * @property {string} [from] + * @property {string} name Series name or data item name + */ + + +registerAction('legendToggleSelect', 'legendselectchanged', curry(legendSelectActionHandler, 'toggleSelected')); +registerAction('legendAllSelect', 'legendselectall', curry(legendSelectActionHandler, 'allSelect')); +registerAction('legendInverseSelect', 'legendinverseselect', curry(legendSelectActionHandler, 'inverseSelect')); +/** + * @event legendSelect + * @type {Object} + * @property {string} type 'legendSelect' + * @property {string} name Series name or data item name + */ + +registerAction('legendSelect', 'legendselected', curry(legendSelectActionHandler, 'select')); +/** + * @event legendUnSelect + * @type {Object} + * @property {string} type 'legendUnSelect' + * @property {string} name Series name or data item name + */ + +registerAction('legendUnSelect', 'legendunselected', curry(legendSelectActionHandler, 'unSelect')); + +/* +* 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. +*/ +/** + * 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 makeBackground(rect, componentModel) { + var padding = normalizeCssArray$1(componentModel.get('padding')); + var style = componentModel.getItemStyle(['color', 'opacity']); + style.fill = componentModel.get('backgroundColor'); + var 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; +} + +/* +* 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 curry$2 = curry; +var each$7 = each$1; +var Group$2 = Group; +var LegendView = extendComponentView({ + type: 'legend.plain', + newlineDisabled: false, + + /** + * @override + */ + init: function () { + /** + * @private + * @type {module:zrender/container/Group} + */ + this.group.add(this._contentGroup = new Group$2()); + /** + * @private + * @type {module:zrender/Element} + */ + + this._backgroundEl; + /** + * @private + * @type {module:zrender/container/Group} + */ + + this.group.add(this._selectorGroup = new Group$2()); + /** + * If first rendering, `contentGroup.position` is [0, 0], which + * does not make sense and may cause unexepcted animation if adopted. + * @private + * @type {boolean} + */ + + this._isFirstRender = true; + }, + + /** + * @protected + */ + getContentGroup: function () { + return this._contentGroup; + }, + + /** + * @protected + */ + getSelectorGroup: function () { + return this._selectorGroup; + }, + + /** + * @override + */ + 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'; + } + + 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.attr('position', [layoutRect.x - mainRect.x, layoutRect.y - mainRect.y]); // Render background after group is layout. + + this.group.add(this._backgroundEl = makeBackground(mainRect, legendModel)); + }, + + /** + * @protected + */ + resetInner: function () { + this.getContentGroup().removeAll(); + this._backgroundEl && this.group.remove(this._backgroundEl); + this.getSelectorGroup().removeAll(); + }, + + /** + * @protected + */ + 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$7(legendModel.getData(), function (itemModel, dataIndex) { + var name = itemModel.get('name'); // Use empty string or \n as a newline string + + if (!this.newlineDisabled && (name === '' || name === '\n')) { + contentGroup.add(new Group$2({ + newline: true + })); + return; + } // Representitive series. + + + var seriesModel = ecModel.getSeriesByName(name)[0]; + + if (legendDrawnMap.get(name)) { + // Have been drawed + return; + } // Series legend + + + if (seriesModel) { + var data = seriesModel.getData(); + var color = data.getVisual('color'); + var borderColor = data.getVisual('borderColor'); // If color is a callback function + + if (typeof color === 'function') { + // Use the first data + color = color(seriesModel.getDataParams(0)); + } // If borderColor is a callback function + + + if (typeof borderColor === 'function') { + // Use the first data + borderColor = borderColor(seriesModel.getDataParams(0)); + } // Using rect symbol defaultly + + + var legendSymbolType = data.getVisual('legendSymbol') || 'roundRect'; + var symbolType = data.getVisual('symbol'); + + var itemGroup = this._createItem(name, dataIndex, itemModel, legendModel, legendSymbolType, symbolType, itemAlign, color, borderColor, selectMode); + + itemGroup.on('click', curry$2(dispatchSelectAction, name, api)).on('mouseover', curry$2(dispatchHighlightAction, seriesModel.name, null, api, excludeSeriesId)).on('mouseout', curry$2(dispatchDownplayAction, seriesModel.name, null, api, excludeSeriesId)); + legendDrawnMap.set(name, true); + } else { + // Data legend of pie, funnel + ecModel.eachRawSeries(function (seriesModel) { + // In case multiple series has same data name + if (legendDrawnMap.get(name)) { + return; + } + + if (seriesModel.legendDataProvider) { + var data = seriesModel.legendDataProvider(); + var idx = data.indexOfName(name); + + if (idx < 0) { + return; + } + + var color = data.getItemVisual(idx, 'color'); + var borderColor = data.getItemVisual(idx, 'borderColor'); + var legendSymbolType = 'roundRect'; + + var itemGroup = this._createItem(name, dataIndex, itemModel, legendModel, legendSymbolType, null, itemAlign, color, borderColor, selectMode); // FIXME: consider different series has items with the same name. + + + itemGroup.on('click', curry$2(dispatchSelectAction, name, api)) // Should not specify the series name, consider legend controls + // more than one pie series. + .on('mouseover', curry$2(dispatchHighlightAction, null, name, api, excludeSeriesId)).on('mouseout', curry$2(dispatchDownplayAction, null, name, api, excludeSeriesId)); + legendDrawnMap.set(name, true); + } + }, this); + } + }, this); + + if (selector) { + this._createSelector(selector, legendModel, api, orient, selectorPosition); + } + }, + _createSelector: function (selector, legendModel, api, orient, selectorPosition) { + var selectorGroup = this.getSelectorGroup(); + each$7(selector, function (selectorItem) { + createSelectorButton(selectorItem); + }); + + function createSelectorButton(selectorItem) { + var type = selectorItem.type; + var labelText = new Text({ + 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.style, labelText.hoverStyle = {}, labelModel, emphasisLabelModel, { + defaultText: selectorItem.title, + isRectText: false + }); + setHoverStyle(labelText); + } + }, + _createItem: function (name, dataIndex, itemModel, legendModel, legendSymbolType, symbolType, itemAlign, color, borderColor, selectMode) { + var itemWidth = legendModel.get('itemWidth'); + var itemHeight = legendModel.get('itemHeight'); + var inactiveColor = legendModel.get('inactiveColor'); + var inactiveBorderColor = legendModel.get('inactiveBorderColor'); + var symbolKeepAspect = legendModel.get('symbolKeepAspect'); + var legendModelItemStyle = legendModel.getModel('itemStyle'); + var isSelected = legendModel.isSelected(name); + var itemGroup = new Group$2(); + var textStyleModel = itemModel.getModel('textStyle'); + var itemIcon = itemModel.get('icon'); + var tooltipModel = itemModel.getModel('tooltip'); + var legendGlobalTooltipModel = tooltipModel.parentModel; // Use user given icon first + + legendSymbolType = itemIcon || legendSymbolType; + var legendSymbol = createSymbol(legendSymbolType, 0, 0, itemWidth, itemHeight, isSelected ? color : inactiveColor, // symbolKeepAspect default true for legend + symbolKeepAspect == null ? true : symbolKeepAspect); + itemGroup.add(setSymbolStyle(legendSymbol, legendSymbolType, legendModelItemStyle, borderColor, inactiveBorderColor, isSelected)); // Compose symbols + // PENDING + + if (!itemIcon && symbolType // At least show one symbol, can't be all none + && (symbolType !== legendSymbolType || symbolType === 'none')) { + var size = itemHeight * 0.8; + + if (symbolType === 'none') { + symbolType = 'circle'; + } + + var legendSymbolCenter = createSymbol(symbolType, (itemWidth - size) / 2, (itemHeight - size) / 2, size, size, isSelected ? color : inactiveColor, // symbolKeepAspect default true for legend + symbolKeepAspect == null ? true : symbolKeepAspect); // Put symbol in the center + + itemGroup.add(setSymbolStyle(legendSymbolCenter, symbolType, legendModelItemStyle, borderColor, inactiveBorderColor, isSelected)); + } + + var textX = itemAlign === 'left' ? itemWidth + 5 : -5; + var textAlign = itemAlign; + var formatter = legendModel.get('formatter'); + var content = name; + + if (typeof formatter === 'string' && formatter) { + content = formatter.replace('{name}', name != null ? name : ''); + } else if (typeof formatter === 'function') { + content = formatter(name); + } + + itemGroup.add(new Text({ + style: setTextStyle({}, textStyleModel, { + text: content, + x: textX, + y: itemHeight / 2, + textFill: isSelected ? textStyleModel.getTextColor() : inactiveColor, + textAlign: textAlign, + textVerticalAlign: 'middle' + }) + })); // Add a invisible rect to increase the area of mouse hover + + var hitRect = new Rect({ + shape: itemGroup.getBoundingRect(), + invisible: true, + tooltip: tooltipModel.get('show') ? extend({ + content: name, + // Defaul formatter + formatter: legendGlobalTooltipModel.get('formatter', true) || function () { + return name; + }, + formatterParams: { + componentType: 'legend', + legendIndex: legendModel.componentIndex, + name: name, + $vars: ['name'] + } + }, tooltipModel.option) : null + }); + itemGroup.add(hitRect); + itemGroup.eachChild(function (child) { + child.silent = true; + }); + hitRect.silent = !selectMode; + this.getContentGroup().add(itemGroup); + setHoverStyle(itemGroup); + itemGroup.__legendDataIndex = dataIndex; + return itemGroup; + }, + + /** + * @protected + */ + 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]; + + 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.attr('position', selectorPos); + contentGroup.attr('position', contentPos); + 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.attr('position', contentPos); + return this.group.getBoundingRect(); + } + }, + + /** + * @protected + */ + remove: function () { + this.getContentGroup().removeAll(); + this._isFirstRender = true; + } +}); + +function setSymbolStyle(symbol, symbolType, legendModelItemStyle, borderColor, inactiveBorderColor, isSelected) { + var itemStyle; + + if (symbolType !== 'line' && symbolType.indexOf('empty') < 0) { + itemStyle = legendModelItemStyle.getItemStyle(); + symbol.style.stroke = borderColor; + + if (!isSelected) { + itemStyle.stroke = inactiveBorderColor; + } + } else { + itemStyle = legendModelItemStyle.getItemStyle(['borderWidth', 'borderColor']); + } + + return symbol.setStyle(itemStyle); +} + +function dispatchSelectAction(name, api) { + api.dispatchAction({ + type: 'legendToggleSelect', + name: name + }); +} + +function dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId) { + // If element hover will move to a hoverLayer. + var el = api.getZr().storage.getDisplayList()[0]; + + if (!(el && el.useHoverLayer)) { + api.dispatchAction({ + type: 'highlight', + seriesName: seriesName, + name: dataName, + excludeSeriesId: excludeSeriesId + }); + } +} + +function dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId) { + // If element hover will move to a hoverLayer. + var el = api.getZr().storage.getDisplayList()[0]; + + if (!(el && el.useHoverLayer)) { + 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. +*/ +var legendFilter = function (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; + }); + } +}; + +/* +* 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. +*/ +// Do not contain scrollable legend, for sake of file size. +registerProcessor(PRIORITY.PROCESSOR.SERIES_FILTER, legendFilter); +ComponentModel.registerSubTypeDefaulter('legend', function () { + // Default 'plain' when no type specified. + return 'plain'; +}); + +/* +* 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 ScrollableLegendModel = LegendModel.extend({ + type: 'legend.scroll', + + /** + * @param {number} scrollDataIndex + */ + setScrollDataIndex: function (scrollDataIndex) { + this.option.scrollDataIndex = scrollDataIndex; + }, + defaultOption: { + scrollDataIndex: 0, + pageButtonItemGap: 5, + pageButtonGap: null, + pageButtonPosition: 'end', + // 'start' or 'end' + pageFormatter: '{current}/{total}', + // If null/undefined, do not show page. + 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, + // Can be [10, 3], which represents [width, height] + pageTextStyle: { + color: '#333' + }, + animationDurationUpdate: 800 + }, + + /** + * @override + */ + init: function (option, parentModel, ecModel, extraOpt) { + var inputPositionParams = getLayoutParams(option); + ScrollableLegendModel.superCall(this, 'init', option, parentModel, ecModel, extraOpt); + mergeAndNormalizeLayoutParams(this, option, inputPositionParams); + }, + + /** + * @override + */ + mergeOption: function (option, extraOpt) { + ScrollableLegendModel.superCall(this, 'mergeOption', option, extraOpt); + mergeAndNormalizeLayoutParams(this, this.option, option); + } +}); // Do not `ignoreSize` to enable setting {left: 10, right: 10}. + +function mergeAndNormalizeLayoutParams(legendModel, target, raw) { + var orient = legendModel.getOrient(); + var ignoreSize = [1, 1]; + ignoreSize[orient.index] = 0; + mergeLayoutParam(target, raw, { + type: 'box', + ignoreSize: ignoreSize + }); +} + +/* +* 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. +*/ + +/** + * Separate legend and scrollable legend to reduce package size. + */ +var Group$3 = Group; +var WH = ['width', 'height']; +var XY = ['x', 'y']; +var ScrollableLegendView = LegendView.extend({ + type: 'legend.scroll', + newlineDisabled: true, + init: function () { + ScrollableLegendView.superCall(this, 'init'); + /** + * @private + * @type {number} For `scroll`. + */ + + this._currentIndex = 0; + /** + * @private + * @type {module:zrender/container/Group} + */ + + this.group.add(this._containerGroup = new Group$3()); + + this._containerGroup.add(this.getContentGroup()); + /** + * @private + * @type {module:zrender/container/Group} + */ + + + this.group.add(this._controllerGroup = new Group$3()); + /** + * + * @private + */ + + this._showController; + }, + + /** + * @override + */ + resetInner: function () { + ScrollableLegendView.superCall(this, 'resetInner'); + + this._controllerGroup.removeAll(); + + this._containerGroup.removeClipPath(); + + this._containerGroup.__rectSize = null; + }, + + /** + * @override + */ + renderInner: function (itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition) { + var me = this; // Render content items. + + ScrollableLegendView.superCall(this, 'renderInner', 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); + + if (!isArray(pageIconSize)) { + pageIconSize = [pageIconSize, pageIconSize]; + } + + createPageButton('pagePrev', 0); + var pageTextStyleModel = legendModel.getModel('pageTextStyle'); + controllerGroup.add(new Text({ + name: 'pageText', + style: { + textFill: pageTextStyleModel.getTextColor(), + font: pageTextStyleModel.getFont(), + textVerticalAlign: 'middle', + textAlign: '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(me._pageGo, me, pageDataIndexName, legendModel, api) + }, { + x: -pageIconSize[0] / 2, + y: -pageIconSize[1] / 2, + width: pageIconSize[0], + height: pageIconSize[1] + }); + icon.name = name; + controllerGroup.add(icon); + } + }, + + /** + * @override + */ + layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition) { + var selectorGroup = this.getSelectorGroup(); + var orientIdx = legendModel.getOrient().index; + var wh = WH[orientIdx]; + var xy = XY[orientIdx]; + var hw = WH[1 - orientIdx]; + var yx = XY[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); + + 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.attr('position', selectorPos); + } + + return mainRect; + }, + _layoutContentAndController: function (legendModel, isFirstRender, maxSize, orientIdx, wh, hw, yx) { + 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]; + 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.position[orientIdx]; + } // 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.attr('position', contentPos); + containerGroup.attr('position', containerPos); + controllerGroup.attr('position', 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, { + position: pageInfo.contentPosition + }, // When switch from "show controller" to "not show controller", view should be + // updated immediately without animation, otherwise causes weird effect. + showController ? legendModel : false); + + this._updatePageInfoView(legendModel, pageInfo); + + return mainRect; + }, + _pageGo: function (to, legendModel, api) { + var scrollDataIndex = this._getPageInfo(legendModel)[to]; + + scrollDataIndex != null && api.dispatchAction({ + type: 'legendScroll', + scrollDataIndex: scrollDataIndex, + legendId: legendModel.id + }); + }, + _updatePageInfoView: function (legendModel, pageInfo) { + var controllerGroup = this._controllerGroup; + each$1(['pagePrev', 'pageNext'], function (name) { + var canJump = pageInfo[name + 'DataIndex'] != 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).replace('{total}', total) : pageFormatter({ + current: current, + total: total + })); + }, + + /** + * @param {module:echarts/model/Model} legendModel + * @return {Object} { + * 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. + * } + */ + _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[orientIdx]; + var xy = XY[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.position.slice(), + 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.position[orientIdx]; + return { + s: start, + e: start + itemRect[wh], + i: el.__legendDataIndex + }; + } + } + + function intersect(itemInfo, winStart) { + return itemInfo.e >= winStart && itemInfo.s <= winStart + containerRectSize; + } + }, + _findTargetItemIndex: function (targetDataIndex) { + var index; + var contentGroup = this.getContentGroup(); + var defaultIndex; + + if (this._showController) { + contentGroup.eachChild(function (child, idx) { + var legendDataIdx = child.__legendDataIndex; // FIXME + // If the given targetDataIndex (from model) is illegal, + // we use defualtIndex. 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; + } +}); + +/* +* 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. +*/ +/** + * @event legendScroll + * @type {Object} + * @property {string} type 'legendScroll' + * @property {string} scrollDataIndex + */ + +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); + }); +}); + +/* +* 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. +*/ + +/** + * Legend component entry file8 + */ + +/* +* 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. +*/ +/** + * @param {Object} finder contains {seriesIndex, dataIndex, dataIndexInside} + * @param {module:echarts/model/Global} ecModel + * @return {Object} {point: [x, y], el: ...} point Will not be null. + */ + +var findPointFromSeries = function (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) { + point = coordSys.dataToPoint(data.getValues(map(coordSys.dimensions, function (dim) { + return data.mapDimension(dim); + }), dataIndex, true)) || []; + } 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 + }; +}; + +/* +* 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 each$8 = each$1; +var curry$3 = curry; +var inner$7 = makeInner(); +/** + * Basic logic: check all axis, if they do not demand show/highlight, + * then hide/downplay them. + * + * @param {Object} coordSysAxesInfo + * @param {Object} payload + * @param {string} [payload.currTrigger] 'click' | 'mousemove' | 'leave' + * @param {Array.} [payload.x] x and y, which are mandatory, specify a point to + * trigger axisPointer and tooltip. + * @param {Array.} [payload.y] x and y, which are mandatory, specify a point to + * trigger axisPointer and tooltip. + * @param {Object} [payload.seriesIndex] finder, optional, restrict target axes. + * @param {Object} [payload.dataIndex] finder, restrict target axes. + * @param {Object} [payload.axesInfo] finder, restrict target axes. + * [{ + * axisDim: 'x'|'y'|'angle'|..., + * axisIndex: ..., + * value: ... + * }, ...] + * @param {Function} [payload.dispatchAction] + * @param {Object} [payload.tooltipOption] + * @param {Object|Array.|Function} [payload.position] Tooltip position, + * which can be specified in dispatchAction + * @param {module:echarts/model/Global} ecModel + * @param {module:echarts/ExtensionAPI} api + * @return {Object} content of event obj for echarts.connect. + */ + +var axisTrigger = function (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 outputFinder = {}; + var showValueMap = {}; + var dataByCoordSys = { + list: [], + map: {} + }; + var updaters = { + showPointer: curry$3(showPointer, showValueMap), + showTooltip: curry$3(showTooltip, dataByCoordSys) + }; // Process for triggered axes. + + each$8(coordSysAxesInfo.coordSysMap, function (coordSys, coordSysKey) { + // If a point given, it must be contained by the coordinate system. + var coordSysContainsPoint = isIllegalPoint || coordSys.containPoint(point); + each$8(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, outputFinder); + } + }); + }); // Process for linked axes. + + var linkTriggers = {}; + each$8(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$8(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$8(linkTriggers, function (val, tarKey) { + processOnAxis(axesInfo[tarKey], val, updaters, true, outputFinder); + }); + updateModelActually(showValueMap, axesInfo, outputFinder); + dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction); + dispatchHighDownActually(axesInfo, dispatchAction, api); + return outputFinder; +}; + +function processOnAxis(axisInfo, newValue, updaters, dontSnap, 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 defualt 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 (!dontSnap && axisInfo.snap) { + if (axis.containData(snapToValue) && snapToValue != null) { + newValue = snapToValue; + } + } + + updaters.showPointer(axisInfo, newValue, payloadBatch, outputFinder); // 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$8(axisInfo.seriesModels, function (series, idx) { + var dataDim = series.getData().mapDimension(dim, true); + 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$8(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, outputFinder) { + var outputAxesInfo = outputFinder.axesInfo = []; // Basic logic: If no 'show' required, 'hide' this axisPointer. + + each$8(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$7(zr)[highDownKey] || {}; + var newHighlights = inner$7(zr)[highDownKey] = {}; // Update highlight/downplay status according to axisPointer model. + // Build hash map and remove duplicate incidentally. + + each$8(axesInfo, function (axisInfo, key) { + var option = axisInfo.axisPointerModel.option; + option.status === 'show' && each$8(option.seriesDataIndices, function (batchItem) { + var key = batchItem.seriesIndex + ' | ' + batchItem.dataIndex; + newHighlights[key] = batchItem; + }); + }); // Diff. + + var toHighlight = []; + var toDownplay = []; + each$1(lastHighlights, function (batchItem, key) { + !newHighlights[key] && toDownplay.push(batchItem); + }); + each$1(newHighlights, function (batchItem, key) { + !lastHighlights[key] && toHighlight.push(batchItem); + }); + toDownplay.length && api.dispatchAction({ + type: 'downplay', + escapeConnect: true, + batch: toDownplay + }); + toHighlight.length && api.dispatchAction({ + type: 'highlight', + escapeConnect: 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]); +} + +/* +* 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 AxisPointerModel = extendComponentModel({ + type: 'axisPointer', + coordSysAxesInfo: null, + defaultOption: { + // 'auto' means that show when triggered by tooltip or handle. + show: 'auto', + // 'click' | 'mousemove' | 'none' + triggerOn: null, + // set default in AxisPonterView.js + zlevel: 0, + z: 50, + type: 'line', + // 'line' 'shadow' 'cross' 'none'. + // axispointer triggered by tootip determine snap automatically, + // see `modelHelper`. + snap: false, + triggerTooltip: true, + value: null, + status: null, + // Init value depends on whether handle is used. + // [group0, group1, ...] + // Each group can be: { + // mapper: function () {}, + // singleTooltip: 'multiple', // 'multiple' or 'single' + // xAxisId: ..., + // yAxisName: ..., + // angleAxisIndex: ... + // } + // mapper: can be ignored. + // input: {axisInfo, value} + // output: {axisInfo, value} + link: [], + // Do not set 'auto' here, otherwise global animation: false + // will not effect at this axispointer. + animation: null, + animationDurationUpdate: 200, + lineStyle: { + color: '#aaa', + width: 1, + type: 'solid' + }, + shadowStyle: { + color: 'rgba(150,150,150,0.3)' + }, + label: { + show: true, + formatter: null, + // string | Function + precision: 'auto', + // Or a number like 0, 1, 2 ... + margin: 3, + color: '#fff', + padding: [5, 7, 5, 7], + backgroundColor: 'auto', + // default: axis line color + borderColor: null, + borderWidth: 0, + shadowBlur: 3, + shadowColor: '#aaa' // Considering applicability, common style should + // better not have shadowOffset. + // shadowOffsetX: 0, + // shadowOffsetY: 2 + + }, + handle: { + show: false, + + /* eslint-disable */ + 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', + // jshint ignore:line + + /* eslint-enable */ + 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 + } + } +}); + +/* +* 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 inner$8 = makeInner(); +var each$9 = each$1; +/** + * @param {string} key + * @param {module:echarts/ExtensionAPI} api + * @param {Function} handler + * param: {string} currTrigger + * param: {Array.} point + */ + +function register(key, api, handler) { + if (env$1.node) { + return; + } + + var zr = api.getZr(); + inner$8(zr).records || (inner$8(zr).records = {}); + initGlobalListeners(zr, api); + var record = inner$8(zr).records[key] || (inner$8(zr).records[key] = {}); + record.handler = handler; +} + +function initGlobalListeners(zr, api) { + if (inner$8(zr).initialized) { + return; + } + + inner$8(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$9(inner$8(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 + }; +} +/** + * @param {string} key + * @param {module:echarts/ExtensionAPI} api + */ + + +function unregister(key, api) { + if (env$1.node) { + return; + } + + var zr = api.getZr(); + var record = (inner$8(zr).records || {})[key]; + + if (record) { + inner$8(zr).records[key] = 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. +*/ +var AxisPointerView = extendComponentView({ + type: 'axisPointer', + 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 + }); + } + }); + }, + + /** + * @override + */ + remove: function (ecModel, api) { + unregister(api.getZr(), 'axisPointer'); + AxisPointerView.superApply(this._model, 'remove', arguments); + }, + + /** + * @override + */ + dispose: function (ecModel, api) { + unregister('axisPointer', api); + AxisPointerView.superApply(this._model, 'dispose', arguments); + } +}); + +/* +* 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 inner$9 = makeInner(); +var clone$4 = clone; +var bind$1 = bind; +/** + * Base axis pointer class in 2D. + * Implemenents {module:echarts/component/axis/IAxisPointer}. + */ + +function BaseAxisPointer() {} + +BaseAxisPointer.prototype = { + /** + * @private + */ + _group: null, + + /** + * @private + */ + _lastGraphicKey: null, + + /** + * @private + */ + _handle: null, + + /** + * @private + */ + _dragging: false, + + /** + * @private + */ + _lastValue: null, + + /** + * @private + */ + _lastStatus: null, + + /** + * @private + */ + _payloadInfo: null, + + /** + * In px, arbitrary value. Do not set too small, + * no animation is ok for most cases. + * @protected + */ + animationThreshold: 15, + + /** + * @implement + */ + 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, axisPointerModel); + this.updateLabelEl(group, elOption, doUpdateProps, axisPointerModel); + } + + updateMandatoryProps(group, axisPointerModel, true); + + this._renderHandle(value); + }, + + /** + * @implement + */ + remove: function (api) { + this.clear(api); + }, + + /** + * @implement + */ + dispose: function (api) { + this.clear(api); + }, + + /** + * @protected + */ + 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 + */ + makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {// Shoule be implemenented by sub-class. + }, + + /** + * @protected + */ + createPointerEl: function (group, elOption, axisModel, axisPointerModel) { + var pointerOption = elOption.pointer; + + if (pointerOption) { + var pointerEl = inner$9(group).pointerEl = new graphic[pointerOption.type](clone$4(elOption.pointer)); + group.add(pointerEl); + } + }, + + /** + * @protected + */ + createLabelEl: function (group, elOption, axisModel, axisPointerModel) { + if (elOption.label) { + var labelEl = inner$9(group).labelEl = new Rect(clone$4(elOption.label)); + group.add(labelEl); + updateLabelShowHide(labelEl, axisPointerModel); + } + }, + + /** + * @protected + */ + updatePointerEl: function (group, elOption, updateProps$$1) { + var pointerEl = inner$9(group).pointerEl; + + if (pointerEl && elOption.pointer) { + pointerEl.setStyle(elOption.pointer.style); + updateProps$$1(pointerEl, { + shape: elOption.pointer.shape + }); + } + }, + + /** + * @protected + */ + updateLabelEl: function (group, elOption, updateProps$$1, axisPointerModel) { + var labelEl = inner$9(group).labelEl; + + if (labelEl) { + labelEl.setStyle(elOption.label.style); + updateProps$$1(labelEl, { + // Consider text length change in vertical axis, animation should + // be used on shape, otherwise the effect will be weird. + shape: elOption.label.shape, + position: elOption.label.position + }); + updateLabelShowHide(labelEl, axisPointerModel); + } + }, + + /** + * @private + */ + _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 + + var includeStyles = ['color', 'borderColor', 'borderWidth', 'opacity', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY']; + handle.setStyle(handleModel.getItemStyle(null, includeStyles)); // update position + + var handleSize = handleModel.get('size'); + + if (!isArray(handleSize)) { + handleSize = [handleSize, handleSize]; + } + + handle.attr('scale', [handleSize[0] / 2, handleSize[1] / 2]); + createOrUpdate(this, '_doDispatchAxisPointer', handleModel.get('throttle') || 0, 'fixRate'); + + this._moveHandleToValue(value, isInit); + }, + + /** + * @private + */ + _moveHandleToValue: function (value, isInit) { + updateProps$1(this._axisPointerModel, !isInit && this._moveAnimation, this._handle, getHandleTransProps(this.getHandleTransform(value, this._axisModel, this._axisPointerModel))); + }, + + /** + * @private + */ + _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$9(handle).lastProp = null; + + this._doDispatchAxisPointer(); + }, + + /** + * Throttled method. + * @private + */ + _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 + }] + }); + }, + + /** + * @private + */ + _onHandleDragEnd: function (moveAnimation) { + 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' + }); + }, + + /** + * Should be implemenented by sub-class if support `handle`. + * @protected + * @param {number} value + * @param {module:echarts/model/Model} axisModel + * @param {module:echarts/model/Model} axisPointerModel + * @return {Object} {position: [x, y], rotation: 0} + */ + getHandleTransform: null, + + /** + * * Should be implemenented by sub-class if support `handle`. + * @protected + * @param {Object} transform {position, rotation} + * @param {Array.} delta [dx, dy] + * @param {module:echarts/model/Model} axisModel + * @param {module:echarts/model/Model} axisPointerModel + * @return {Object} {position: [x, y], rotation: 0, cursorPoint: [x, y]} + */ + updateHandleTransform: null, + + /** + * @private + */ + 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; + } + }, + + /** + * @protected + */ + doClear: function () {// Implemented by sub-class if necessary. + }, + + /** + * @protected + * @param {Array.} xy + * @param {Array.} wh + * @param {number} [xDimIndex=0] or 1 + */ + buildLabel: function (xy, wh, xDimIndex) { + xDimIndex = xDimIndex || 0; + return { + x: xy[xDimIndex], + y: xy[1 - xDimIndex], + width: wh[xDimIndex], + height: wh[1 - xDimIndex] + }; + } +}; +BaseAxisPointer.prototype.constructor = BaseAxisPointer; + +function updateProps$1(animationModel, moveAnimation, el, props) { + // Animation optimize. + if (!propsEqual(inner$9(el).lastProp, props)) { + inner$9(el).lastProp = props; + moveAnimation ? updateProps(el, props, animationModel) : (el.stopAnimation(), el.attr(props)); + } +} + +function propsEqual(lastProps, newProps) { + if (isObject$1(lastProps) && isObject$1(newProps)) { + var equals = true; + each$1(newProps, function (item, key) { + equals = equals && propsEqual(lastProps[key], item); + }); + return !!equals; + } else { + return lastProps === newProps; + } +} + +function updateLabelShowHide(labelEl, axisPointerModel) { + labelEl[axisPointerModel.get('label.show') ? 'show' : 'hide'](); +} + +function getHandleTransProps(trans) { + return { + position: trans.position.slice(), + 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; + } + }); +} + +enableClassExtend(BaseAxisPointer); + +/* +* 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. +*/ +/** + * @param {module:echarts/model/Model} axisPointerModel + */ + +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') + }, + position: position.slice(), + // TODO: rich + style: { + text: text, + textFont: font, + textFill: labelModel.getTextColor(), + textPosition: 'inside', + textPadding: paddings, + fill: bgColor, + stroke: labelModel.get('borderColor') || 'transparent', + lineWidth: labelModel.get('borderWidth') || 0, + shadowBlur: labelModel.get('shadowBlur'), + shadowColor: labelModel.get('shadowColor'), + shadowOffsetX: labelModel.get('shadowOffsetX'), + shadowOffsetY: labelModel.get('shadowOffsetY') + }, + // 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); +} +/** + * @param {number} value + * @param {module:echarts/coord/Axis} axis + * @param {module:echarts/model/Global} ecModel + * @param {Object} opt + * @param {Array.} seriesDataIndices + * @param {number|string} opt.precision 'auto' or a number + * @param {string|Function} opt.formatter label formatter + */ + + +function getValueLabel(value, axis, ecModel, seriesDataIndices, opt) { + value = axis.scale.parse(value); + var text = axis.scale.getLabel( // If `precision` is set, width can be fixed (like '12.00500'), which + // helps to debounce when when moving label. + value, { + precision: opt.precision + }); + var formatter = opt.formatter; + + if (formatter) { + var params = { + value: getAxisRawValue(axis, value), + axisDimension: axis.dim, + axisIndex: axis.index, + seriesData: [] + }; + each$1(seriesDataIndices, function (idxItem) { + var series = ecModel.getSeriesByIndex(idxItem.seriesIndex); + var dataIndex = idxItem.dataIndexInside; + var dataParams = series && series.getDataParams(dataIndex); + dataParams && params.seriesData.push(dataParams); + }); + + if (isString(formatter)) { + text = formatter.replace('{value}', text); + } else if (isFunction$1(formatter)) { + text = formatter(params); + } + } + + return text; +} +/** + * @param {module:echarts/coord/Axis} axis + * @param {number} value + * @param {Object} layoutInfo { + * rotation, position, labelOffset, labelDirection, labelMargin + * } + */ + +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) { + 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 + }); +} +/** + * @param {Array.} p1 + * @param {Array.} p2 + * @param {number} [xDimIndex=0] or 1 + */ + +function makeLineShape(p1, p2, xDimIndex) { + xDimIndex = xDimIndex || 0; + return { + x1: p1[xDimIndex], + y1: p1[1 - xDimIndex], + x2: p2[xDimIndex], + y2: p2[1 - xDimIndex] + }; +} +/** + * @param {Array.} xy + * @param {Array.} wh + * @param {number} [xDimIndex=0] or 1 + */ + +function makeRectShape(xy, wh, xDimIndex) { + xDimIndex = xDimIndex || 0; + return { + x: xy[xDimIndex], + y: xy[1 - xDimIndex], + width: wh[xDimIndex], + height: wh[1 - xDimIndex] + }; +} + +/* +* 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 CartesianAxisPointer = BaseAxisPointer.extend({ + /** + * @override + */ + 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(value, elOption, layoutInfo, axisModel, axisPointerModel, api); + }, + + /** + * @override + */ + getHandleTransform: function (value, axisModel, axisPointerModel) { + var layoutInfo = layout$1(axisModel.axis.grid.model, axisModel, { + labelInside: false + }); + layoutInfo.labelMargin = axisPointerModel.get('handle.margin'); + return { + position: getTransformedPosition(axisModel.axis, value, layoutInfo), + rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0) + }; + }, + + /** + * @override + */ + 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.position; + 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 { + position: currPosition, + rotation: transform.rotation, + cursorPoint: cursorPoint, + tooltipOption: tooltipOptions[dimIndex] + }; + } +}); + +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; +} + +AxisView.registerAxisPointerClass('CartesianAxisPointer', CartesianAxisPointer); + +/* +* 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. +*/ +// echarts.simple.js and online build tooltip, which only require gridSimple, +// CartesianAxisPointer should be able to required somewhere. + +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. + +registerProcessor(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. + +registerAction({ + type: 'updateAxisPointer', + event: 'updateAxisPointer', + update: ':updateAxisPointer' +}, axisTrigger); + +/* +* 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. +*/ +extendComponentModel({ + type: 'tooltip', + dependencies: ['axisPointer'], + defaultOption: { + zlevel: 0, + z: 60, + show: true, + // tooltip主体内容 + showContent: true, + // 'trigger' only works on coordinate system. + // 'item' | 'axis' | 'none' + trigger: 'item', + // 'click' | 'mousemove' | 'none' + triggerOn: 'mousemove|click', + alwaysShowContent: false, + displayMode: 'single', + // 'single' | 'multipleByCoordSys' + renderMode: 'auto', + // 'auto' | 'html' | 'richText' + // 'auto': use html by default, and use non-html if `document` is not defined + // 'html': use html for tooltip + // 'richText': use canvas, svg, and etc. for tooltip + // 位置 {Array} | {Function} + // position: null + // Consider triggered from axisPointer handle, verticalAlign should be 'middle' + // align: null, + // verticalAlign: null, + // 是否约束 content 在 viewRect 中。默认 false 是为了兼容以前版本。 + confine: false, + // 内容格式器:{string}(Template) ¦ {Function} + // formatter: null + showDelay: 0, + // 隐藏延迟,单位ms + hideDelay: 100, + // 动画变换时间,单位s + transitionDuration: 0.4, + enterable: false, + // 提示背景颜色,默认为透明度为0.7的黑色 + backgroundColor: 'rgba(50,50,50,0.7)', + // 提示边框颜色 + borderColor: '#333', + // 提示边框圆角,单位px,默认为4 + borderRadius: 4, + // 提示边框线宽,单位px,默认为0(无边框) + borderWidth: 0, + // 提示内边距,单位px,默认各方向内边距为5, + // 接受数组分别设定上右下左边距,同css + padding: 5, + // Extra css text + extraCssText: '', + // 坐标轴指示器,坐标轴触发有效 + axisPointer: { + // 默认为直线 + // 可选为:'line' | 'shadow' | 'cross' + type: 'line', + // type 为 line 的时候有效,指定 tooltip line 所在的轴,可选 + // 可选 'x' | 'y' | 'angle' | 'radius' | 'auto' + // 默认 'auto',会选择类型为 category 的轴,对于双数值轴,笛卡尔坐标系会默认选择 x 轴 + // 极坐标系会默认选择 angle 轴 + 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: '#fff', + fontSize: 14 + } + } +}); + +/* +* 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 each$11 = each$1; +var toCamelCase$1 = toCamelCase; +var vendors = ['', '-webkit-', '-moz-', '-o-']; +var gCssText = 'position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;'; +/** + * @param {number} duration + * @return {string} + * @inner + */ + +function assembleTransition(duration) { + var transitionCurve = 'cubic-bezier(0.23, 1, 0.32, 1)'; + var transitionText = 'left ' + duration + 's ' + transitionCurve + ',' + 'top ' + duration + 's ' + transitionCurve; + return map(vendors, function (vendorPrefix) { + return vendorPrefix + 'transition:' + transitionText; + }).join(';'); +} +/** + * @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 && cssText.push('line-height:' + Math.round(fontSize * 3 / 2) + 'px'); + each$11(['decoration', 'align'], function (name) { + var val = textStyleModel.get(name); + val && cssText.push('text-' + name + ':' + val); + }); + return cssText.join(';'); +} +/** + * @param {Object} tooltipModel + * @return {string} + * @inner + */ + + +function assembleCssText(tooltipModel) { + var cssText = []; + var transitionDuration = tooltipModel.get('transitionDuration'); + var backgroundColor = tooltipModel.get('backgroundColor'); + var textStyleModel = tooltipModel.getModel('textStyle'); + var padding = tooltipModel.get('padding'); // Animation transition. Do not animate when transitionDuration is 0. + + transitionDuration && cssText.push(assembleTransition(transitionDuration)); + + if (backgroundColor) { + if (env$1.canvasSupported) { + cssText.push('background-Color:' + backgroundColor); + } else { + // for ie + cssText.push('background-Color:#' + toHex(backgroundColor)); + cssText.push('filter:alpha(opacity=70)'); + } + } // Border style + + + each$11(['width', 'color', 'radius'], function (name) { + var borderName = 'border-' + name; + var camelCase = toCamelCase$1(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(';') + ';'; +} +/** + * @alias module:echarts/component/tooltip/TooltipContent + * @constructor + */ + + +function TooltipContent(container, api) { + if (env$1.wxa) { + return null; + } + + var el = document.createElement('div'); + var zr = this._zr = api.getZr(); + this.el = el; + this._x = api.getWidth() / 2; + this._y = api.getHeight() / 2; + container.appendChild(el); + this._container = container; + this._show = false; + /** + * @private + */ + + this._hideTimeout; // 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; + normalizeEvent(container, e, true); + handler.dispatch('mousemove', e); + } + }; + + el.onmouseleave = function () { + if (self._enterable) { + if (self._show) { + self.hideLater(self._hideDelay); + } + } + + self._inContent = false; + }; +} + +TooltipContent.prototype = { + constructor: TooltipContent, + + /** + * @private + * @type {boolean} + */ + _enterable: true, + + /** + * Update when tooltip is rendered + */ + update: function () { + // FIXME + // Move this logic to ec main? + var container = this._container; + var stl = container.currentStyle || document.defaultView.getComputedStyle(container); + var domStyle = container.style; + + if (domStyle.position !== 'absolute' && stl.position !== 'absolute') { + domStyle.position = 'relative'; + } // Hide the tooltip + // PENDING + // this.hide(); + + }, + show: function (tooltipModel) { + clearTimeout(this._hideTimeout); + var el = this.el; + el.style.cssText = gCssText + assembleCssText(tooltipModel) // Because of the reason described in: + // http://stackoverflow.com/questions/21125587/css3-transition-not-working-in-chrome-anymore + // we should set initial value to `left` and `top`. + + ';left:' + this._x + 'px;top:' + this._y + 'px;' + (tooltipModel.get('extraCssText') || ''); + el.style.display = el.innerHTML ? 'block' : 'none'; // If mouse occsionally move over the tooltip, a mouseout event will be + // triggered by canvas, and cuase some unexpectable result like dragging + // stop, "unfocusAdjacency". Here `pointer-events: none` is used to solve + // it. Although it is not suppored by IE8~IE10, fortunately it is a rare + // scenario. + + el.style.pointerEvents = this._enterable ? 'auto' : 'none'; + this._show = true; + }, + setContent: function (content) { + this.el.innerHTML = content == null ? '' : content; + }, + setEnterable: function (enterable) { + this._enterable = enterable; + }, + getSize: function () { + var el = this.el; + return [el.clientWidth, el.clientHeight]; + }, + moveTo: function (x, y) { + // 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 zr = this._zr; + var viewportRootOffset; + + if (zr && zr.painter && (viewportRootOffset = zr.painter.getViewportRootOffset())) { + x += viewportRootOffset.offsetLeft; + y += viewportRootOffset.offsetTop; + } + + var style = this.el.style; + style.left = x + 'px'; + style.top = y + 'px'; + this._x = x; + this._y = y; + }, + hide: function () { + this.el.style.display = 'none'; + this._show = false; + }, + hideLater: function (time) { + if (this._show && !(this._inContent && this._enterable)) { + if (time) { + this._hideDelay = time; // Set show false to avoid invoke hideLater mutiple times + + this._show = false; + this._hideTimeout = setTimeout(bind(this.hide, this), time); + } else { + this.hide(); + } + } + }, + isShow: function () { + return this._show; + }, + getOuterSize: function () { + var width = this.el.clientWidth; + var height = this.el.clientHeight; // Consider browser compatibility. + // IE8 does not support getComputedStyle. + + if (document.defaultView && document.defaultView.getComputedStyle) { + var stl = document.defaultView.getComputedStyle(this.el); + + if (stl) { + width += parseInt(stl.borderLeftWidth, 10) + parseInt(stl.borderRightWidth, 10); + height += parseInt(stl.borderTopWidth, 10) + parseInt(stl.borderBottomWidth, 10); + } + } + + return { + width: width, + height: height + }; + } +}; + +/* +* 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. +*/ +/** + * @alias module:echarts/component/tooltip/TooltipRichContent + * @constructor + */ + +function TooltipRichContent(api) { + this._zr = api.getZr(); + this._show = false; + /** + * @private + */ + + this._hideTimeout; +} + +TooltipRichContent.prototype = { + constructor: TooltipRichContent, + + /** + * @private + * @type {boolean} + */ + _enterable: true, + + /** + * Update when tooltip is rendered + */ + update: function () {// noop + }, + show: function (tooltipModel) { + if (this._hideTimeout) { + clearTimeout(this._hideTimeout); + } + + this.el.attr('show', true); + this._show = true; + }, + + /** + * Set tooltip content + * + * @param {string} content rich text string of content + * @param {Object} markerRich rich text style + * @param {Object} tooltipModel tooltip model + */ + setContent: function (content, markerRich, tooltipModel) { + if (this.el) { + this._zr.remove(this.el); + } + + var markers = {}; + var text = content; + var prefix = '{marker'; + var suffix = '|}'; + var startId = text.indexOf(prefix); + + while (startId >= 0) { + var endId = text.indexOf(suffix); + var name = text.substr(startId + prefix.length, endId - startId - prefix.length); + + if (name.indexOf('sub') > -1) { + markers['marker' + name] = { + textWidth: 4, + textHeight: 4, + textBorderRadius: 2, + textBackgroundColor: markerRich[name], + // TODO: textOffset is not implemented for rich text + textOffset: [3, 0] + }; + } else { + markers['marker' + name] = { + textWidth: 10, + textHeight: 10, + textBorderRadius: 5, + textBackgroundColor: markerRich[name] + }; + } + + text = text.substr(endId + 1); + startId = text.indexOf('{marker'); + } + + this.el = new Text({ + style: { + rich: markers, + text: content, + textLineHeight: 20, + textBackgroundColor: tooltipModel.get('backgroundColor'), + textBorderRadius: tooltipModel.get('borderRadius'), + textFill: tooltipModel.get('textStyle.color'), + textPadding: tooltipModel.get('padding') + }, + z: tooltipModel.get('z') + }); + + 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; + }); + }, + setEnterable: function (enterable) { + this._enterable = enterable; + }, + getSize: function () { + var bounding = this.el.getBoundingRect(); + return [bounding.width, bounding.height]; + }, + moveTo: function (x, y) { + if (this.el) { + this.el.attr('position', [x, y]); + } + }, + hide: function () { + if (this.el) { + this.el.hide(); + } + + this._show = false; + }, + hideLater: function (time) { + if (this._show && !(this._inContent && this._enterable)) { + if (time) { + this._hideDelay = time; // Set show false to avoid invoke hideLater mutiple times + + this._show = false; + this._hideTimeout = setTimeout(bind(this.hide, this), time); + } else { + this.hide(); + } + } + }, + isShow: function () { + return this._show; + }, + getOuterSize: function () { + var size = this.getSize(); + return { + width: size[0], + height: size[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. +*/ +var bind$2 = bind; +var each$10 = each$1; +var parsePercent$2 = parsePercent$1; +var proxyRect = new Rect({ + shape: { + x: -1, + y: -1, + width: 2, + height: 2 + } +}); +extendComponentView({ + type: 'tooltip', + init: function (ecModel, api) { + if (env$1.node) { + return; + } + + var tooltipModel = ecModel.getComponent('tooltip'); + var renderMode = tooltipModel.get('renderMode'); + this._renderMode = getTooltipRenderMode(renderMode); + var tooltipContent; + + if (this._renderMode === 'html') { + tooltipContent = new TooltipContent(api.getDom(), api); + this._newLine = '
'; + } else { + tooltipContent = new TooltipRichContent(api); + this._newLine = '\n'; + } + + this._tooltipContent = tooltipContent; + }, + render: function (tooltipModel, ecModel, api) { + if (env$1.node) { + return; + } // Reset + + + this.group.removeAll(); + /** + * @private + * @type {module:echarts/component/tooltip/TooltipModel} + */ + + this._tooltipModel = tooltipModel; + /** + * @private + * @type {module:echarts/model/Global} + */ + + this._ecModel = ecModel; + /** + * @private + * @type {module:echarts/ExtensionAPI} + */ + + this._api = api; + /** + * Should be cleaned when render. + * @private + * @type {Array.>} + */ + + this._lastDataByCoordSys = null; + /** + * @private + * @type {boolean} + */ + + this._alwaysShowContent = tooltipModel.get('alwaysShowContent'); + var tooltipContent = this._tooltipContent; + tooltipContent.update(); + tooltipContent.setEnterable(tooltipModel.get('enterable')); + + this._initGlobalListener(); + + this._keepShow(); + }, + _initGlobalListener: function () { + var tooltipModel = this._tooltipModel; + var triggerOn = tooltipModel.get('triggerOn'); + register('itemTooltip', this._api, bind$2(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)); + }, + _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 = 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.manuallyShowTip(tooltipModel, ecModel, api, { + x: self._lastX, + y: self._lastY + }); + }); + } + }, + + /** + * Show tip manually by + * dispatchAction({ + * type: 'showTip', + * x: 10, + * y: 10 + * }); + * Or + * dispatchAction({ + * type: 'showTip', + * seriesIndex: 0, + * dataIndex or dataIndexInside or name + * }); + * + * TODO Batch + */ + manuallyShowTip: function (tooltipModel, ecModel, api, payload) { + if (payload.from === this.uid || env$1.node) { + return; + } + + var dispatchAction = makeDispatchAction$1(payload, api); // Reset ticket + + this._ticket = ''; // When triggered from axisPointer. + + var dataByCoordSys = payload.dataByCoordSys; + + if (payload.tooltip && payload.x != null && payload.y != null) { + var el = proxyRect; + el.position = [payload.x, payload.y]; + el.update(); + el.tooltip = 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, + event: {}, + dataByCoordSys: payload.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, + position: payload.position, + target: pointInfo.el, + event: {} + }, 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, + event: {} + }, dispatchAction); + } + }, + 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 = 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. + _manuallyAxisShowTip: function (tooltipModel, ecModel, api, payload) { + var seriesIndex = payload.seriesIndex; + var dataIndex = payload.dataIndex; + 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 tooltipModel = buildTooltipModel([data.getItemModel(dataIndex), seriesModel, (seriesModel.coordinateSystem || {}).model, tooltipModel]); + + if (tooltipModel.get('trigger') !== 'axis') { + return; + } + + api.dispatchAction({ + type: 'updateAxisPointer', + seriesIndex: seriesIndex, + dataIndex: dataIndex, + position: payload.position + }); + return true; + }, + _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); + } // Always show item tooltip if mouse is on the element with dataIndex + else if (el && el.dataIndex != null) { + this._lastDataByCoordSys = null; + + this._showSeriesItemTooltip(e, el, dispatchAction); + } // Tooltip provided directly. Like legend. + else if (el && el.tooltip) { + this._lastDataByCoordSys = null; + + this._showComponentItemTooltip(e, el, dispatchAction); + } else { + this._lastDataByCoordSys = null; + + this._hide(dispatchAction); + } + }, + _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 easyer 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(); + }, + _showAxisTooltip: function (dataByCoordSys, e) { + var ecModel = this._ecModel; + var globalTooltipModel = this._tooltipModel; + var point = [e.offsetX, e.offsetY]; + var singleDefaultHTML = []; + var singleParamsList = []; + var singleTooltipModel = buildTooltipModel([e.tooltipOption, globalTooltipModel]); + var renderMode = this._renderMode; + var newLine = this._newLine; + var markers = {}; + each$10(dataByCoordSys, function (itemCoordSys) { + // var coordParamList = []; + // var coordDefaultHTML = []; + // var coordTooltipModel = buildTooltipModel([ + // e.tooltipOption, + // itemCoordSys.tooltipOption, + // ecModel.getComponent(itemCoordSys.coordSysMainType, itemCoordSys.coordSysIndex), + // globalTooltipModel + // ]); + // var displayMode = coordTooltipModel.get('displayMode'); + // var paramsList = displayMode === 'single' ? singleParamsList : []; + each$10(itemCoordSys.dataByAxis, function (item) { + var axisModel = ecModel.getComponent(item.axisDim + 'Axis', item.axisIndex); + var axisValue = item.value; + var seriesDefaultHTML = []; + + if (!axisModel || axisValue == null) { + return; + } + + var valueLabel = getValueLabel(axisValue, axisModel.axis, ecModel, item.seriesDataIndices, item.valueLabelOpt); + each$1(item.seriesDataIndices, function (idxItem) { + var series = ecModel.getSeriesByIndex(idxItem.seriesIndex); + var dataIndex = idxItem.dataIndexInside; + var dataParams = series && series.getDataParams(dataIndex); + dataParams.axisDim = item.axisDim; + dataParams.axisIndex = item.axisIndex; + dataParams.axisType = item.axisType; + dataParams.axisId = item.axisId; + dataParams.axisValue = getAxisRawValue(axisModel.axis, axisValue); + dataParams.axisValueLabel = valueLabel; + + if (dataParams) { + singleParamsList.push(dataParams); + var seriesTooltip = series.formatTooltip(dataIndex, true, null, renderMode); + var html; + + if (isObject$1(seriesTooltip)) { + html = seriesTooltip.html; + var newMarkers = seriesTooltip.markers; + merge(markers, newMarkers); + } else { + html = seriesTooltip; + } + + seriesDefaultHTML.push(html); + } + }); // Default tooltip content + // FIXME + // (1) shold be the first data which has name? + // (2) themeRiver, firstDataIndex is array, and first line is unnecessary. + + var firstLine = valueLabel; + + if (renderMode !== 'html') { + singleDefaultHTML.push(seriesDefaultHTML.join(newLine)); + } else { + singleDefaultHTML.push((firstLine ? encodeHTML(firstLine) + newLine : '') + seriesDefaultHTML.join(newLine)); + } + }); + }, this); // In most case, the second axis is shown upper than the first one. + + singleDefaultHTML.reverse(); + singleDefaultHTML = singleDefaultHTML.join(this._newLine + this._newLine); + var positionExpr = e.position; + + this._showOrMove(singleTooltipModel, function () { + if (this._updateContentNotChangedOnAxis(dataByCoordSys)) { + this._updatePosition(singleTooltipModel, positionExpr, point[0], point[1], this._tooltipContent, singleParamsList); + } else { + this._showTooltipContent(singleTooltipModel, singleDefaultHTML, singleParamsList, Math.random(), point[0], point[1], positionExpr, undefined, markers); + } + }); // Do not trigger events here, because this branch only be entered + // from dispatchAction. + + }, + _showSeriesItemTooltip: function (e, el, dispatchAction) { + var ecModel = this._ecModel; // 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 = el.seriesIndex; + var seriesModel = ecModel.getSeriesByIndex(seriesIndex); // For example, graph link. + + var dataModel = el.dataModel || seriesModel; + var dataIndex = el.dataIndex; + var dataType = el.dataType; + var data = dataModel.getData(); + var tooltipModel = buildTooltipModel([data.getItemModel(dataIndex), dataModel, seriesModel && (seriesModel.coordinateSystem || {}).model, this._tooltipModel]); + var tooltipTrigger = tooltipModel.get('trigger'); + + if (tooltipTrigger != null && tooltipTrigger !== 'item') { + return; + } + + var params = dataModel.getDataParams(dataIndex, dataType); + var seriesTooltip = dataModel.formatTooltip(dataIndex, false, dataType, this._renderMode); + var defaultHtml; + var markers; + + if (isObject$1(seriesTooltip)) { + defaultHtml = seriesTooltip.html; + markers = seriesTooltip.markers; + } else { + defaultHtml = seriesTooltip; + markers = null; + } + + var asyncTicket = 'item_' + dataModel.name + '_' + dataIndex; + + this._showOrMove(tooltipModel, function () { + this._showTooltipContent(tooltipModel, defaultHtml, params, asyncTicket, e.offsetX, e.offsetY, e.position, e.target, markers); + }); // FIXME + // duplicated showtip if manuallyShowTip is called from dispatchAction. + + + dispatchAction({ + type: 'showTip', + dataIndexInside: dataIndex, + dataIndex: data.getRawIndex(dataIndex), + seriesIndex: seriesIndex, + from: this.uid + }); + }, + _showComponentItemTooltip: function (e, el, dispatchAction) { + var tooltipOpt = el.tooltip; + + if (typeof tooltipOpt === 'string') { + var content = tooltipOpt; + tooltipOpt = { + content: content, + // Fixed formatter + formatter: content + }; + } + + var subTooltipModel = new Model(tooltipOpt, this._tooltipModel, this._ecModel); + var defaultHtml = subTooltipModel.get('content'); + var asyncTicket = Math.random(); // Do not check whether `trigger` is 'none' here, because `trigger` + // only works on cooridinate system. In fact, we have not found case + // that requires setting `trigger` nothing on component yet. + + this._showOrMove(subTooltipModel, function () { + this._showTooltipContent(subTooltipModel, defaultHtml, subTooltipModel.get('formatterParams') || {}, asyncTicket, e.offsetX, e.offsetY, e.position, el); + }); // If not dispatch showTip, tip may be hide triggered by axis. + + + dispatchAction({ + type: 'showTip', + from: this.uid + }); + }, + _showTooltipContent: function (tooltipModel, defaultHtml, params, asyncTicket, x, y, positionExpr, el, markers) { + // Reset ticket + this._ticket = ''; + + if (!tooltipModel.get('showContent') || !tooltipModel.get('show')) { + return; + } + + var tooltipContent = this._tooltipContent; + var formatter = tooltipModel.get('formatter'); + positionExpr = positionExpr || tooltipModel.get('position'); + var html = defaultHtml; + + if (formatter && typeof formatter === 'string') { + html = formatTpl(formatter, params, true); + } else if (typeof formatter === 'function') { + var callback = bind$2(function (cbTicket, html) { + if (cbTicket === this._ticket) { + tooltipContent.setContent(html, markers, tooltipModel); + + this._updatePosition(tooltipModel, positionExpr, x, y, tooltipContent, params, el); + } + }, this); + this._ticket = asyncTicket; + html = formatter(params, asyncTicket, callback); + } + + tooltipContent.setContent(html, markers, tooltipModel); + tooltipContent.show(tooltipModel); + + this._updatePosition(tooltipModel, positionExpr, x, y, tooltipContent, params, el); + }, + + /** + * @param {string|Function|Array.|Object} positionExpr + * @param {number} x Mouse x + * @param {number} y Mouse y + * @param {boolean} confine Whether confine tooltip content in view rect. + * @param {Object|} params + * @param {module:zrender/Element} el target element + * @param {module:echarts/ExtensionAPI} api + * @return {Array.} + */ + _updatePosition: function (tooltipModel, positionExpr, x, 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 (typeof positionExpr === 'function') { + // 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$2(positionExpr[0], viewWidth); + y = parsePercent$2(positionExpr[1], viewHeight); + } else if (isObject$1(positionExpr)) { + positionExpr.width = contentSize[0]; + positionExpr.height = contentSize[1]; + var layoutRect = getLayoutRect(positionExpr, { + 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 (typeof positionExpr === 'string' && el) { + var pos = calcTooltipPosition(positionExpr, rect, contentSize); + 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 (tooltipModel.get('confine')) { + 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? + _updateContentNotChangedOnAxis: function (dataByCoordSys) { + var lastCoordSys = this._lastDataByCoordSys; + var contentNotChanged = !!lastCoordSys && lastCoordSys.length === dataByCoordSys.length; + contentNotChanged && each$10(lastCoordSys, function (lastItemCoordSys, indexCoordSys) { + var lastDataByAxis = lastItemCoordSys.dataByAxis || {}; + var thisItemCoordSys = dataByCoordSys[indexCoordSys] || {}; + var thisDataByAxis = thisItemCoordSys.dataByAxis || []; + contentNotChanged &= lastDataByAxis.length === thisDataByAxis.length; + contentNotChanged && each$10(lastDataByAxis, function (lastItem, indexAxis) { + var thisItem = thisDataByAxis[indexAxis] || {}; + var lastIndices = lastItem.seriesDataIndices || []; + var newIndices = thisItem.seriesDataIndices || []; + contentNotChanged &= lastItem.value === thisItem.value && lastItem.axisType === thisItem.axisType && lastItem.axisId === thisItem.axisId && lastIndices.length === newIndices.length; + contentNotChanged && each$10(lastIndices, function (lastIdxItem, j) { + var newIdxItem = newIndices[j]; + contentNotChanged &= lastIdxItem.seriesIndex === newIdxItem.seriesIndex && lastIdxItem.dataIndex === newIdxItem.dataIndex; + }); + }); + }); + this._lastDataByCoordSys = dataByCoordSys; + return !!contentNotChanged; + }, + _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 + }); + }, + dispose: function (ecModel, api) { + if (env$1.node) { + return; + } + + this._tooltipContent.hide(); + + unregister('itemTooltip', api); + } +}); +/** + * @param {Array.} modelCascade + * From top to bottom. (the last one should be globalTooltipModel); + */ + +function buildTooltipModel(modelCascade) { + var resultModel = modelCascade.pop(); + + while (modelCascade.length) { + var tooltipOpt = modelCascade.pop(); + + if (tooltipOpt) { + if (Model.isInstance(tooltipOpt)) { + tooltipOpt = tooltipOpt.get('tooltip', true); + } // In each data item tooltip can be simply write: + // { + // value: 10, + // tooltip: 'Something you need to know' + // } + + + if (typeof tooltipOpt === 'string') { + tooltipOpt = { + formatter: tooltipOpt + }; + } + + resultModel = new Model(tooltipOpt, resultModel, 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.getOuterSize(); + var width = size.width; + var height = size.height; + + if (gapH != null) { + if (x + width + gapH > 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.getOuterSize(); + var width = size.width; + var height = size.height; + 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) { + var domWidth = contentSize[0]; + var domHeight = contentSize[1]; + var gap = 5; + 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 - gap; + break; + + case 'bottom': + x = rect.x + rectWidth / 2 - domWidth / 2; + y = rect.y + rectHeight + gap; + break; + + case 'left': + x = rect.x - domWidth - gap; + y = rect.y + rectHeight / 2 - domHeight / 2; + break; + + case 'right': + x = rect.x + rectWidth + gap; + y = rect.y + rectHeight / 2 - domHeight / 2; + } + + return [x, y]; +} + +function isCenterAlign(align) { + return align === 'center' || align === 'middle'; +} + +/* +* 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. +*/ +// FIXME Better way to pack data in graphic element +/** + * @action + * @property {string} type + * @property {number} seriesIndex + * @property {number} dataIndex + * @property {number} [x] + * @property {number} [y] + */ + +registerAction({ + type: 'showTip', + event: 'showTip', + update: 'tooltip:manuallyShowTip' +}, // noop +function () {}); +registerAction({ + type: 'hideTip', + event: 'hideTip', + update: 'tooltip:manuallyHideTip' +}, // noop +function () {}); + +var urn = 'urn:schemas-microsoft-com:vml'; +var win = typeof window === 'undefined' ? null : window; +var vmlInited = false; +var doc = win && win.document; +function createNode(tagName) { + return doCreateNode(tagName); +} // Avoid assign to an exported variable, for transforming to cjs. + +var doCreateNode; + +if (doc && !env$1.canvasSupported) { + try { + !doc.namespaces.zrvml && doc.namespaces.add('zrvml', urn); + + doCreateNode = function (tagName) { + return doc.createElement(''); + }; + } catch (e) { + doCreateNode = function (tagName) { + return doc.createElement('<' + tagName + ' xmlns="' + urn + '" class="zrvml">'); + }; + } +} // From raphael + + +function initVML() { + if (vmlInited || !doc) { + return; + } + + vmlInited = true; + var styleSheets = doc.styleSheets; + + if (styleSheets.length < 31) { + doc.createStyleSheet().addRule('.zrvml', 'behavior:url(#default#VML)'); + } else { + // http://msdn.microsoft.com/en-us/library/ms531194%28VS.85%29.aspx + styleSheets[0].addRule('.zrvml', 'behavior:url(#default#VML)'); + } +} + +// http://www.w3.org/TR/NOTE-VML +// TODO Use proxy like svg instead of overwrite brush methods +var CMD$3 = PathProxy.CMD; +var round$2 = Math.round; +var sqrt = Math.sqrt; +var abs$1 = Math.abs; +var cos = Math.cos; +var sin = Math.sin; +var mathMax$5 = Math.max; + +if (!env$1.canvasSupported) { + var comma = ','; + var imageTransformPrefix = 'progid:DXImageTransform.Microsoft'; + var Z = 21600; + var Z2 = Z / 2; + var ZLEVEL_BASE = 100000; + var Z_BASE = 1000; + + var initRootElStyle = function (el) { + el.style.cssText = 'position:absolute;left:0;top:0;width:1px;height:1px;'; + el.coordsize = Z + ',' + Z; + el.coordorigin = '0,0'; + }; + + var encodeHtmlAttribute = function (s) { + return String(s).replace(/&/g, '&').replace(/"/g, '"'); + }; + + var rgb2Str = function (r, g, b) { + return 'rgb(' + [r, g, b].join(',') + ')'; + }; + + var append = function (parent, child) { + if (child && parent && child.parentNode !== parent) { + parent.appendChild(child); + } + }; + + var remove = function (parent, child) { + if (child && parent && child.parentNode === parent) { + parent.removeChild(child); + } + }; + + var getZIndex = function (zlevel, z, z2) { + // z 的取值范围为 [0, 1000] + return (parseFloat(zlevel) || 0) * ZLEVEL_BASE + (parseFloat(z) || 0) * Z_BASE + z2; + }; + + var parsePercent$3 = parsePercent; + /*************************************************** + * PATH + **************************************************/ + + var setColorAndOpacity = function (el, color, opacity) { + var colorArr = parse(color); + opacity = +opacity; + + if (isNaN(opacity)) { + opacity = 1; + } + + if (colorArr) { + el.color = rgb2Str(colorArr[0], colorArr[1], colorArr[2]); + el.opacity = opacity * colorArr[3]; + } + }; + + var getColorAndAlpha = function (color) { + var colorArr = parse(color); + return [rgb2Str(colorArr[0], colorArr[1], colorArr[2]), colorArr[3]]; + }; + + var updateFillNode = function (el, style, zrEl) { + // TODO pattern + var fill = style.fill; + + if (fill != null) { + // Modified from excanvas + if (fill instanceof Gradient) { + var gradientType; + var angle = 0; + var focus = [0, 0]; // additional offset + + var shift = 0; // scale factor for offset + + var expansion = 1; + var rect = zrEl.getBoundingRect(); + var rectWidth = rect.width; + var rectHeight = rect.height; + + if (fill.type === 'linear') { + gradientType = 'gradient'; + var transform = zrEl.transform; + var p0 = [fill.x * rectWidth, fill.y * rectHeight]; + var p1 = [fill.x2 * rectWidth, fill.y2 * rectHeight]; + + if (transform) { + applyTransform(p0, p0, transform); + applyTransform(p1, p1, transform); + } + + var dx = p1[0] - p0[0]; + var dy = p1[1] - p0[1]; + angle = Math.atan2(dx, dy) * 180 / Math.PI; // The angle should be a non-negative number. + + if (angle < 0) { + angle += 360; + } // Very small angles produce an unexpected result because they are + // converted to a scientific notation string. + + + if (angle < 1e-6) { + angle = 0; + } + } else { + gradientType = 'gradientradial'; + var p0 = [fill.x * rectWidth, fill.y * rectHeight]; + var transform = zrEl.transform; + var scale$$1 = zrEl.scale; + var width = rectWidth; + var height = rectHeight; + focus = [// Percent in bounding rect + (p0[0] - rect.x) / width, (p0[1] - rect.y) / height]; + + if (transform) { + applyTransform(p0, p0, transform); + } + + width /= scale$$1[0] * Z; + height /= scale$$1[1] * Z; + var dimension = mathMax$5(width, height); + shift = 2 * 0 / dimension; + expansion = 2 * fill.r / dimension - shift; + } // We need to sort the color stops in ascending order by offset, + // otherwise IE won't interpret it correctly. + + + var stops = fill.colorStops.slice(); + stops.sort(function (cs1, cs2) { + return cs1.offset - cs2.offset; + }); + var length$$1 = stops.length; // Color and alpha list of first and last stop + + var colorAndAlphaList = []; + var colors = []; + + for (var i = 0; i < length$$1; i++) { + var stop = stops[i]; + var colorAndAlpha = getColorAndAlpha(stop.color); + colors.push(stop.offset * expansion + shift + ' ' + colorAndAlpha[0]); + + if (i === 0 || i === length$$1 - 1) { + colorAndAlphaList.push(colorAndAlpha); + } + } + + if (length$$1 >= 2) { + var color1 = colorAndAlphaList[0][0]; + var color2 = colorAndAlphaList[1][0]; + var opacity1 = colorAndAlphaList[0][1] * style.opacity; + var opacity2 = colorAndAlphaList[1][1] * style.opacity; + el.type = gradientType; + el.method = 'none'; + el.focus = '100%'; + el.angle = angle; + el.color = color1; + el.color2 = color2; + el.colors = colors.join(','); // When colors attribute is used, the meanings of opacity and o:opacity2 + // are reversed. + + el.opacity = opacity2; // FIXME g_o_:opacity ? + + el.opacity2 = opacity1; + } + + if (gradientType === 'radial') { + el.focusposition = focus.join(','); + } + } else { + // FIXME Change from Gradient fill to color fill + setColorAndOpacity(el, fill, style.opacity); + } + } + }; + + var updateStrokeNode = function (el, style) { + // if (style.lineJoin != null) { + // el.joinstyle = style.lineJoin; + // } + // if (style.miterLimit != null) { + // el.miterlimit = style.miterLimit * Z; + // } + // if (style.lineCap != null) { + // el.endcap = style.lineCap; + // } + if (style.lineDash) { + el.dashstyle = style.lineDash.join(' '); + } + + if (style.stroke != null && !(style.stroke instanceof Gradient)) { + setColorAndOpacity(el, style.stroke, style.opacity); + } + }; + + var updateFillAndStroke = function (vmlEl, type, style, zrEl) { + var isFill = type === 'fill'; + var el = vmlEl.getElementsByTagName(type)[0]; // Stroke must have lineWidth + + if (style[type] != null && style[type] !== 'none' && (isFill || !isFill && style.lineWidth)) { + vmlEl[isFill ? 'filled' : 'stroked'] = 'true'; // FIXME Remove before updating, or set `colors` will throw error + + if (style[type] instanceof Gradient) { + remove(vmlEl, el); + } + + if (!el) { + el = createNode(type); + } + + isFill ? updateFillNode(el, style, zrEl) : updateStrokeNode(el, style); + append(vmlEl, el); + } else { + vmlEl[isFill ? 'filled' : 'stroked'] = 'false'; + remove(vmlEl, el); + } + }; + + var points$1 = [[], [], []]; + + var pathDataToString = function (path, m) { + var M = CMD$3.M; + var C = CMD$3.C; + var L = CMD$3.L; + var A = CMD$3.A; + var Q = CMD$3.Q; + var str = []; + var nPoint; + var cmdStr; + var cmd; + var i; + var xi; + var yi; + var data = path.data; + var dataLength = path.len(); + + for (i = 0; i < dataLength;) { + cmd = data[i++]; + cmdStr = ''; + nPoint = 0; + + switch (cmd) { + case M: + cmdStr = ' m '; + nPoint = 1; + xi = data[i++]; + yi = data[i++]; + points$1[0][0] = xi; + points$1[0][1] = yi; + break; + + case L: + cmdStr = ' l '; + nPoint = 1; + xi = data[i++]; + yi = data[i++]; + points$1[0][0] = xi; + points$1[0][1] = yi; + break; + + case Q: + case C: + cmdStr = ' c '; + nPoint = 3; + var x1 = data[i++]; + var y1 = data[i++]; + var x2 = data[i++]; + var y2 = data[i++]; + var x3; + var y3; + + if (cmd === Q) { + // Convert quadratic to cubic using degree elevation + x3 = x2; + y3 = y2; + x2 = (x2 + 2 * x1) / 3; + y2 = (y2 + 2 * y1) / 3; + x1 = (xi + 2 * x1) / 3; + y1 = (yi + 2 * y1) / 3; + } else { + x3 = data[i++]; + y3 = data[i++]; + } + + points$1[0][0] = x1; + points$1[0][1] = y1; + points$1[1][0] = x2; + points$1[1][1] = y2; + points$1[2][0] = x3; + points$1[2][1] = y3; + xi = x3; + yi = y3; + break; + + case A: + var x = 0; + var y = 0; + var sx = 1; + var sy = 1; + var angle = 0; + + if (m) { + // Extract SRT from matrix + x = m[4]; + y = m[5]; + sx = sqrt(m[0] * m[0] + m[1] * m[1]); + sy = sqrt(m[2] * m[2] + m[3] * m[3]); + angle = Math.atan2(-m[1] / sy, m[0] / sx); + } + + var cx = data[i++]; + var cy = data[i++]; + var rx = data[i++]; + var ry = data[i++]; + var startAngle = data[i++] + angle; + var endAngle = data[i++] + startAngle + angle; // FIXME + // var psi = data[i++]; + + i++; + var clockwise = data[i++]; + var x0 = cx + cos(startAngle) * rx; + var y0 = cy + sin(startAngle) * ry; + var x1 = cx + cos(endAngle) * rx; + var y1 = cy + sin(endAngle) * ry; + var type = clockwise ? ' wa ' : ' at '; + + if (Math.abs(x0 - x1) < 1e-4) { + // IE won't render arches drawn counter clockwise if x0 == x1. + if (Math.abs(endAngle - startAngle) > 1e-2) { + // Offset x0 by 1/80 of a pixel. Use something + // that can be represented in binary + if (clockwise) { + x0 += 270 / Z; + } + } else { + // Avoid case draw full circle + if (Math.abs(y0 - cy) < 1e-4) { + if (clockwise && x0 < cx || !clockwise && x0 > cx) { + y1 -= 270 / Z; + } else { + y1 += 270 / Z; + } + } else if (clockwise && y0 < cy || !clockwise && y0 > cy) { + x1 += 270 / Z; + } else { + x1 -= 270 / Z; + } + } + } + + str.push(type, round$2(((cx - rx) * sx + x) * Z - Z2), comma, round$2(((cy - ry) * sy + y) * Z - Z2), comma, round$2(((cx + rx) * sx + x) * Z - Z2), comma, round$2(((cy + ry) * sy + y) * Z - Z2), comma, round$2((x0 * sx + x) * Z - Z2), comma, round$2((y0 * sy + y) * Z - Z2), comma, round$2((x1 * sx + x) * Z - Z2), comma, round$2((y1 * sy + y) * Z - Z2)); + xi = x1; + yi = y1; + break; + + case CMD$3.R: + var p0 = points$1[0]; + var p1 = points$1[1]; // x0, y0 + + p0[0] = data[i++]; + p0[1] = data[i++]; // x1, y1 + + p1[0] = p0[0] + data[i++]; + p1[1] = p0[1] + data[i++]; + + if (m) { + applyTransform(p0, p0, m); + applyTransform(p1, p1, m); + } + + p0[0] = round$2(p0[0] * Z - Z2); + p1[0] = round$2(p1[0] * Z - Z2); + p0[1] = round$2(p0[1] * Z - Z2); + p1[1] = round$2(p1[1] * Z - Z2); + str.push( // x0, y0 + ' m ', p0[0], comma, p0[1], // x1, y0 + ' l ', p1[0], comma, p0[1], // x1, y1 + ' l ', p1[0], comma, p1[1], // x0, y1 + ' l ', p0[0], comma, p1[1]); + break; + + case CMD$3.Z: + // FIXME Update xi, yi + str.push(' x '); + } + + if (nPoint > 0) { + str.push(cmdStr); + + for (var k = 0; k < nPoint; k++) { + var p = points$1[k]; + m && applyTransform(p, p, m); // 不 round 会非常慢 + + str.push(round$2(p[0] * Z - Z2), comma, round$2(p[1] * Z - Z2), k < nPoint - 1 ? comma : ''); + } + } + } + + return str.join(''); + }; // Rewrite the original path method + + + Path.prototype.brushVML = function (vmlRoot) { + var style = this.style; + var vmlEl = this._vmlEl; + + if (!vmlEl) { + vmlEl = createNode('shape'); + initRootElStyle(vmlEl); + this._vmlEl = vmlEl; + } + + updateFillAndStroke(vmlEl, 'fill', style, this); + updateFillAndStroke(vmlEl, 'stroke', style, this); + var m = this.transform; + var needTransform = m != null; + var strokeEl = vmlEl.getElementsByTagName('stroke')[0]; + + if (strokeEl) { + var lineWidth = style.lineWidth; // Get the line scale. + // Determinant of this.m_ means how much the area is enlarged by the + // transformation. So its square root can be used as a scale factor + // for width. + + if (needTransform && !style.strokeNoScale) { + var det = m[0] * m[3] - m[1] * m[2]; + lineWidth *= sqrt(abs$1(det)); + } + + strokeEl.weight = lineWidth + 'px'; + } + + var path = this.path || (this.path = new PathProxy()); + + if (this.__dirtyPath) { + path.beginPath(); + path.subPixelOptimize = false; + this.buildPath(path, this.shape); + path.toStatic(); + this.__dirtyPath = false; + } + + vmlEl.path = pathDataToString(path, this.transform); + vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2); // Append to root + + append(vmlRoot, vmlEl); // Text + + if (style.text != null) { + this.drawRectText(vmlRoot, this.getBoundingRect()); + } else { + this.removeRectText(vmlRoot); + } + }; + + Path.prototype.onRemove = function (vmlRoot) { + remove(vmlRoot, this._vmlEl); + this.removeRectText(vmlRoot); + }; + + Path.prototype.onAdd = function (vmlRoot) { + append(vmlRoot, this._vmlEl); + this.appendRectText(vmlRoot); + }; + /*************************************************** + * IMAGE + **************************************************/ + + + var isImage = function (img) { + // FIXME img instanceof Image 如果 img 是一个字符串的时候,IE8 下会报错 + return typeof img === 'object' && img.tagName && img.tagName.toUpperCase() === 'IMG'; // return img instanceof Image; + }; // Rewrite the original path method + + + ZImage.prototype.brushVML = function (vmlRoot) { + var style = this.style; + var image = style.image; // Image original width, height + + var ow; + var oh; + + if (isImage(image)) { + var src = image.src; + + if (src === this._imageSrc) { + ow = this._imageWidth; + oh = this._imageHeight; + } else { + var imageRuntimeStyle = image.runtimeStyle; + var oldRuntimeWidth = imageRuntimeStyle.width; + var oldRuntimeHeight = imageRuntimeStyle.height; + imageRuntimeStyle.width = 'auto'; + imageRuntimeStyle.height = 'auto'; // get the original size + + ow = image.width; + oh = image.height; // and remove overides + + imageRuntimeStyle.width = oldRuntimeWidth; + imageRuntimeStyle.height = oldRuntimeHeight; // Caching image original width, height and src + + this._imageSrc = src; + this._imageWidth = ow; + this._imageHeight = oh; + } + + image = src; + } else { + if (image === this._imageSrc) { + ow = this._imageWidth; + oh = this._imageHeight; + } + } + + if (!image) { + return; + } + + var x = style.x || 0; + var y = style.y || 0; + var dw = style.width; + var dh = style.height; + var sw = style.sWidth; + var sh = style.sHeight; + var sx = style.sx || 0; + var sy = style.sy || 0; + var hasCrop = sw && sh; + var vmlEl = this._vmlEl; + + if (!vmlEl) { + // FIXME 使用 group 在 left, top 都不是 0 的时候就无法显示了。 + // vmlEl = vmlCore.createNode('group'); + vmlEl = doc.createElement('div'); + initRootElStyle(vmlEl); + this._vmlEl = vmlEl; + } + + var vmlElStyle = vmlEl.style; + var hasRotation = false; + var m; + var scaleX = 1; + var scaleY = 1; + + if (this.transform) { + m = this.transform; + scaleX = sqrt(m[0] * m[0] + m[1] * m[1]); + scaleY = sqrt(m[2] * m[2] + m[3] * m[3]); + hasRotation = m[1] || m[2]; + } + + if (hasRotation) { + // If filters are necessary (rotation exists), create them + // filters are bog-slow, so only create them if abbsolutely necessary + // The following check doesn't account for skews (which don't exist + // in the canvas spec (yet) anyway. + // From excanvas + var p0 = [x, y]; + var p1 = [x + dw, y]; + var p2 = [x, y + dh]; + var p3 = [x + dw, y + dh]; + applyTransform(p0, p0, m); + applyTransform(p1, p1, m); + applyTransform(p2, p2, m); + applyTransform(p3, p3, m); + var maxX = mathMax$5(p0[0], p1[0], p2[0], p3[0]); + var maxY = mathMax$5(p0[1], p1[1], p2[1], p3[1]); + var transformFilter = []; + transformFilter.push('M11=', m[0] / scaleX, comma, 'M12=', m[2] / scaleY, comma, 'M21=', m[1] / scaleX, comma, 'M22=', m[3] / scaleY, comma, 'Dx=', round$2(x * scaleX + m[4]), comma, 'Dy=', round$2(y * scaleY + m[5])); + vmlElStyle.padding = '0 ' + round$2(maxX) + 'px ' + round$2(maxY) + 'px 0'; // FIXME DXImageTransform 在 IE11 的兼容模式下不起作用 + + vmlElStyle.filter = imageTransformPrefix + '.Matrix(' + transformFilter.join('') + ', SizingMethod=clip)'; + } else { + if (m) { + x = x * scaleX + m[4]; + y = y * scaleY + m[5]; + } + + vmlElStyle.filter = ''; + vmlElStyle.left = round$2(x) + 'px'; + vmlElStyle.top = round$2(y) + 'px'; + } + + var imageEl = this._imageEl; + var cropEl = this._cropEl; + + if (!imageEl) { + imageEl = doc.createElement('div'); + this._imageEl = imageEl; + } + + var imageELStyle = imageEl.style; + + if (hasCrop) { + // Needs know image original width and height + if (!(ow && oh)) { + var tmpImage = new Image(); + var self = this; + + tmpImage.onload = function () { + tmpImage.onload = null; + ow = tmpImage.width; + oh = tmpImage.height; // Adjust image width and height to fit the ratio destinationSize / sourceSize + + imageELStyle.width = round$2(scaleX * ow * dw / sw) + 'px'; + imageELStyle.height = round$2(scaleY * oh * dh / sh) + 'px'; // Caching image original width, height and src + + self._imageWidth = ow; + self._imageHeight = oh; + self._imageSrc = image; + }; + + tmpImage.src = image; + } else { + imageELStyle.width = round$2(scaleX * ow * dw / sw) + 'px'; + imageELStyle.height = round$2(scaleY * oh * dh / sh) + 'px'; + } + + if (!cropEl) { + cropEl = doc.createElement('div'); + cropEl.style.overflow = 'hidden'; + this._cropEl = cropEl; + } + + var cropElStyle = cropEl.style; + cropElStyle.width = round$2((dw + sx * dw / sw) * scaleX); + cropElStyle.height = round$2((dh + sy * dh / sh) * scaleY); + cropElStyle.filter = imageTransformPrefix + '.Matrix(Dx=' + -sx * dw / sw * scaleX + ',Dy=' + -sy * dh / sh * scaleY + ')'; + + if (!cropEl.parentNode) { + vmlEl.appendChild(cropEl); + } + + if (imageEl.parentNode !== cropEl) { + cropEl.appendChild(imageEl); + } + } else { + imageELStyle.width = round$2(scaleX * dw) + 'px'; + imageELStyle.height = round$2(scaleY * dh) + 'px'; + vmlEl.appendChild(imageEl); + + if (cropEl && cropEl.parentNode) { + vmlEl.removeChild(cropEl); + this._cropEl = null; + } + } + + var filterStr = ''; + var alpha = style.opacity; + + if (alpha < 1) { + filterStr += '.Alpha(opacity=' + round$2(alpha * 100) + ') '; + } + + filterStr += imageTransformPrefix + '.AlphaImageLoader(src=' + image + ', SizingMethod=scale)'; + imageELStyle.filter = filterStr; + vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2); // Append to root + + append(vmlRoot, vmlEl); // Text + + if (style.text != null) { + this.drawRectText(vmlRoot, this.getBoundingRect()); + } + }; + + ZImage.prototype.onRemove = function (vmlRoot) { + remove(vmlRoot, this._vmlEl); + this._vmlEl = null; + this._cropEl = null; + this._imageEl = null; + this.removeRectText(vmlRoot); + }; + + ZImage.prototype.onAdd = function (vmlRoot) { + append(vmlRoot, this._vmlEl); + this.appendRectText(vmlRoot); + }; + /*************************************************** + * TEXT + **************************************************/ + + + var DEFAULT_STYLE_NORMAL = 'normal'; + var fontStyleCache = {}; + var fontStyleCacheCount = 0; + var MAX_FONT_CACHE_SIZE = 100; + var fontEl = document.createElement('div'); + + var getFontStyle = function (fontString) { + var fontStyle = fontStyleCache[fontString]; + + if (!fontStyle) { + // Clear cache + if (fontStyleCacheCount > MAX_FONT_CACHE_SIZE) { + fontStyleCacheCount = 0; + fontStyleCache = {}; + } + + var style = fontEl.style; + var fontFamily; + + try { + style.font = fontString; + fontFamily = style.fontFamily.split(',')[0]; + } catch (e) {} + + fontStyle = { + style: style.fontStyle || DEFAULT_STYLE_NORMAL, + variant: style.fontVariant || DEFAULT_STYLE_NORMAL, + weight: style.fontWeight || DEFAULT_STYLE_NORMAL, + size: parseFloat(style.fontSize || 12) | 0, + family: fontFamily || 'Microsoft YaHei' + }; + fontStyleCache[fontString] = fontStyle; + fontStyleCacheCount++; + } + + return fontStyle; + }; + + var textMeasureEl; // Overwrite measure text method + + $override$1('measureText', function (text, textFont) { + var doc$$1 = doc; + + if (!textMeasureEl) { + textMeasureEl = doc$$1.createElement('div'); + textMeasureEl.style.cssText = 'position:absolute;top:-20000px;left:0;' + 'padding:0;margin:0;border:none;white-space:pre;'; + doc.body.appendChild(textMeasureEl); + } + + try { + textMeasureEl.style.font = textFont; + } catch (ex) {// Ignore failures to set to invalid font. + } + + textMeasureEl.innerHTML = ''; // Don't use innerHTML or innerText because they allow markup/whitespace. + + textMeasureEl.appendChild(doc$$1.createTextNode(text)); + return { + width: textMeasureEl.offsetWidth + }; + }); + var tmpRect$2 = new BoundingRect(); + + var drawRectText = function (vmlRoot, rect, textRect, fromTextEl) { + var style = this.style; // Optimize, avoid normalize every time. + + this.__dirty && normalizeTextStyle(style, true); + var text = style.text; // Convert to string + + text != null && (text += ''); + + if (!text) { + return; + } // Convert rich text to plain text. Rich text is not supported in + // IE8-, but tags in rich text template will be removed. + + + if (style.rich) { + var contentBlock = parseRichText(text, style); + text = []; + + for (var i = 0; i < contentBlock.lines.length; i++) { + var tokens = contentBlock.lines[i].tokens; + var textLine = []; + + for (var j = 0; j < tokens.length; j++) { + textLine.push(tokens[j].text); + } + + text.push(textLine.join('')); + } + + text = text.join('\n'); + } + + var x; + var y; + var align = style.textAlign; + var verticalAlign = style.textVerticalAlign; + var fontStyle = getFontStyle(style.font); // FIXME encodeHtmlAttribute ? + + var font = fontStyle.style + ' ' + fontStyle.variant + ' ' + fontStyle.weight + ' ' + fontStyle.size + 'px "' + fontStyle.family + '"'; + textRect = textRect || getBoundingRect(text, font, align, verticalAlign, style.textPadding, style.textLineHeight); // Transform rect to view space + + var m = this.transform; // Ignore transform for text in other element + + if (m && !fromTextEl) { + tmpRect$2.copy(rect); + tmpRect$2.applyTransform(m); + rect = tmpRect$2; + } + + if (!fromTextEl) { + var textPosition = style.textPosition; // Text position represented by coord + + if (textPosition instanceof Array) { + x = rect.x + parsePercent$3(textPosition[0], rect.width); + y = rect.y + parsePercent$3(textPosition[1], rect.height); + align = align || 'left'; + } else { + var res = this.calculateTextPosition ? this.calculateTextPosition({}, style, rect) : calculateTextPosition({}, style, rect); + x = res.x; + y = res.y; // Default align and baseline when has textPosition + + align = align || res.textAlign; + verticalAlign = verticalAlign || res.textVerticalAlign; + } + } else { + x = rect.x; + y = rect.y; + } + + x = adjustTextX(x, textRect.width, align); + y = adjustTextY(y, textRect.height, verticalAlign); // Force baseline 'middle' + + y += textRect.height / 2; // var fontSize = fontStyle.size; + // 1.75 is an arbitrary number, as there is no info about the text baseline + // switch (baseline) { + // case 'hanging': + // case 'top': + // y += fontSize / 1.75; + // break; + // case 'middle': + // break; + // default: + // // case null: + // // case 'alphabetic': + // // case 'ideographic': + // // case 'bottom': + // y -= fontSize / 2.25; + // break; + // } + // switch (align) { + // case 'left': + // break; + // case 'center': + // x -= textRect.width / 2; + // break; + // case 'right': + // x -= textRect.width; + // break; + // case 'end': + // align = elementStyle.direction == 'ltr' ? 'right' : 'left'; + // break; + // case 'start': + // align = elementStyle.direction == 'rtl' ? 'right' : 'left'; + // break; + // default: + // align = 'left'; + // } + + var createNode$$1 = createNode; + var textVmlEl = this._textVmlEl; + var pathEl; + var textPathEl; + var skewEl; + + if (!textVmlEl) { + textVmlEl = createNode$$1('line'); + pathEl = createNode$$1('path'); + textPathEl = createNode$$1('textpath'); + skewEl = createNode$$1('skew'); // FIXME Why here is not cammel case + // Align 'center' seems wrong + + textPathEl.style['v-text-align'] = 'left'; + initRootElStyle(textVmlEl); + pathEl.textpathok = true; + textPathEl.on = true; + textVmlEl.from = '0 0'; + textVmlEl.to = '1000 0.05'; + append(textVmlEl, skewEl); + append(textVmlEl, pathEl); + append(textVmlEl, textPathEl); + this._textVmlEl = textVmlEl; + } else { + // 这里是在前面 appendChild 保证顺序的前提下 + skewEl = textVmlEl.firstChild; + pathEl = skewEl.nextSibling; + textPathEl = pathEl.nextSibling; + } + + var coords = [x, y]; + var textVmlElStyle = textVmlEl.style; // Ignore transform for text in other element + + if (m && fromTextEl) { + applyTransform(coords, coords, m); + skewEl.on = true; + skewEl.matrix = m[0].toFixed(3) + comma + m[2].toFixed(3) + comma + m[1].toFixed(3) + comma + m[3].toFixed(3) + ',0,0'; // Text position + + skewEl.offset = (round$2(coords[0]) || 0) + ',' + (round$2(coords[1]) || 0); // Left top point as origin + + skewEl.origin = '0 0'; + textVmlElStyle.left = '0px'; + textVmlElStyle.top = '0px'; + } else { + skewEl.on = false; + textVmlElStyle.left = round$2(x) + 'px'; + textVmlElStyle.top = round$2(y) + 'px'; + } + + textPathEl.string = encodeHtmlAttribute(text); // TODO + + try { + textPathEl.style.font = font; + } // Error font format + catch (e) {} + + updateFillAndStroke(textVmlEl, 'fill', { + fill: style.textFill, + opacity: style.opacity + }, this); + updateFillAndStroke(textVmlEl, 'stroke', { + stroke: style.textStroke, + opacity: style.opacity, + lineDash: style.lineDash || null // style.lineDash can be `false`. + + }, this); + textVmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2); // Attached to root + + append(vmlRoot, textVmlEl); + }; + + var removeRectText = function (vmlRoot) { + remove(vmlRoot, this._textVmlEl); + this._textVmlEl = null; + }; + + var appendRectText = function (vmlRoot) { + append(vmlRoot, this._textVmlEl); + }; + + var list = [RectText, Displayable, ZImage, Path, Text]; // In case Displayable has been mixed in RectText + + for (var i$1 = 0; i$1 < list.length; i$1++) { + var proto$2 = list[i$1].prototype; + proto$2.drawRectText = drawRectText; + proto$2.removeRectText = removeRectText; + proto$2.appendRectText = appendRectText; + } + + Text.prototype.brushVML = function (vmlRoot) { + var style = this.style; + + if (style.text != null) { + this.drawRectText(vmlRoot, { + x: style.x || 0, + y: style.y || 0, + width: 0, + height: 0 + }, this.getBoundingRect(), true); + } else { + this.removeRectText(vmlRoot); + } + }; + + Text.prototype.onRemove = function (vmlRoot) { + this.removeRectText(vmlRoot); + }; + + Text.prototype.onAdd = function (vmlRoot) { + this.appendRectText(vmlRoot); + }; +} + +/** + * VML Painter. + * + * @module zrender/vml/Painter + */ +function parseInt10$1(val) { + return parseInt(val, 10); +} +/** + * @alias module:zrender/vml/Painter + */ + + +function VMLPainter(root, storage) { + initVML(); + this.root = root; + this.storage = storage; + var vmlViewport = document.createElement('div'); + var vmlRoot = document.createElement('div'); + vmlViewport.style.cssText = 'display:inline-block;overflow:hidden;position:relative;width:300px;height:150px;'; + vmlRoot.style.cssText = 'position:absolute;left:0;top:0;'; + root.appendChild(vmlViewport); + this._vmlRoot = vmlRoot; + this._vmlViewport = vmlViewport; + this.resize(); // Modify storage + + var oldDelFromStorage = storage.delFromStorage; + var oldAddToStorage = storage.addToStorage; + + storage.delFromStorage = function (el) { + oldDelFromStorage.call(storage, el); + + if (el) { + el.onRemove && el.onRemove(vmlRoot); + } + }; + + storage.addToStorage = function (el) { + // Displayable already has a vml node + el.onAdd && el.onAdd(vmlRoot); + oldAddToStorage.call(storage, el); + }; + + this._firstPaint = true; +} + +VMLPainter.prototype = { + constructor: VMLPainter, + getType: function () { + return 'vml'; + }, + + /** + * @return {HTMLDivElement} + */ + getViewportRoot: function () { + return this._vmlViewport; + }, + getViewportRootOffset: function () { + var viewportRoot = this.getViewportRoot(); + + if (viewportRoot) { + return { + offsetLeft: viewportRoot.offsetLeft || 0, + offsetTop: viewportRoot.offsetTop || 0 + }; + } + }, + + /** + * 刷新 + */ + refresh: function () { + var list = this.storage.getDisplayList(true, true); + + this._paintList(list); + }, + _paintList: function (list) { + var vmlRoot = this._vmlRoot; + + for (var i = 0; i < list.length; i++) { + var el = list[i]; + + if (el.invisible || el.ignore) { + if (!el.__alreadyNotVisible) { + el.onRemove(vmlRoot); + } // Set as already invisible + + + el.__alreadyNotVisible = true; + } else { + if (el.__alreadyNotVisible) { + el.onAdd(vmlRoot); + } + + el.__alreadyNotVisible = false; + + if (el.__dirty) { + el.beforeBrush && el.beforeBrush(); + (el.brushVML || el.brush).call(el, vmlRoot); + el.afterBrush && el.afterBrush(); + } + } + + el.__dirty = false; + } + + if (this._firstPaint) { + // Detached from document at first time + // to avoid page refreshing too many times + // FIXME 如果每次都先 removeChild 可能会导致一些填充和描边的效果改变 + this._vmlViewport.appendChild(vmlRoot); + + this._firstPaint = false; + } + }, + resize: function (width, height) { + var width = width == null ? this._getWidth() : width; + var height = height == null ? this._getHeight() : height; + + if (this._width !== width || this._height !== height) { + this._width = width; + this._height = height; + var vmlViewportStyle = this._vmlViewport.style; + vmlViewportStyle.width = width + 'px'; + vmlViewportStyle.height = height + 'px'; + } + }, + dispose: function () { + this.root.innerHTML = ''; + this._vmlRoot = this._vmlViewport = this.storage = null; + }, + getWidth: function () { + return this._width; + }, + getHeight: function () { + return this._height; + }, + clear: function () { + if (this._vmlViewport) { + this.root.removeChild(this._vmlViewport); + } + }, + _getWidth: function () { + var root = this.root; + var stl = root.currentStyle; + return (root.clientWidth || parseInt10$1(stl.width)) - parseInt10$1(stl.paddingLeft) - parseInt10$1(stl.paddingRight) | 0; + }, + _getHeight: function () { + var root = this.root; + var stl = root.currentStyle; + return (root.clientHeight || parseInt10$1(stl.height)) - parseInt10$1(stl.paddingTop) - parseInt10$1(stl.paddingBottom) | 0; + } +}; // Not supported methods + +function createMethodNotSupport(method) { + return function () { + logError$1('In IE8.0 VML mode painter not support method "' + method + '"'); + }; +} // Unsupported methods + + +each$1(['getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer', 'eachOtherLayer', 'getLayers', 'modLayer', 'delLayer', 'clearLayer', 'toDataURL', 'pathToImage'], function (name) { + VMLPainter.prototype[name] = createMethodNotSupport(name); +}); + +registerPainter('vml', VMLPainter); + +exports.version = version; +exports.dependencies = dependencies; +exports.PRIORITY = PRIORITY; +exports.init = init; +exports.connect = connect; +exports.disConnect = disConnect; +exports.disconnect = disconnect; +exports.dispose = dispose; +exports.getInstanceByDom = getInstanceByDom; +exports.getInstanceById = getInstanceById; +exports.registerTheme = registerTheme; +exports.registerPreprocessor = registerPreprocessor; +exports.registerProcessor = registerProcessor; +exports.registerPostUpdate = registerPostUpdate; +exports.registerAction = registerAction; +exports.registerCoordinateSystem = registerCoordinateSystem; +exports.getCoordinateSystemDimensions = getCoordinateSystemDimensions; +exports.registerLayout = registerLayout; +exports.registerVisual = registerVisual; +exports.registerLoading = registerLoading; +exports.extendComponentModel = extendComponentModel; +exports.extendComponentView = extendComponentView; +exports.extendSeriesModel = extendSeriesModel; +exports.extendChartView = extendChartView; +exports.setCanvasCreator = setCanvasCreator; +exports.registerMap = registerMap; +exports.getMap = getMap; +exports.dataTool = dataTool; +exports.zrender = zrender; +exports.number = number; +exports.format = format; +exports.throttle = throttle; +exports.helper = helper; +exports.matrix = matrix; +exports.vector = vector; +exports.color = color; +exports.parseGeoJSON = parseGeoJSON; +exports.parseGeoJson = parseGeoJson; +exports.util = ecUtil; +exports.graphic = graphic$1; +exports.List = List; +exports.Model = Model; +exports.Axis = Axis; +exports.env = env$1; + +}))); diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/jquery/canvas-to-blob.min.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/jquery/canvas-to-blob.min.js" new file mode 100644 index 00000000..0f786459 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/jquery/canvas-to-blob.min.js" @@ -0,0 +1,968 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + JavaScript-Canvas-to-Blob/canvas-to-blob.min.js at master · qiyubu/JavaScript-Canvas-to-Blob · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Skip to content + + + + + + + + + + + +
+ +
+ + +
+ + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + Permalink + + + + + +
+ + +
+ + Branch: + master + + + + +
+ + + +
+
+
+ +
+ + Find file + + + Copy path + +
+
+ + +
+ + Find file + + + Copy path + +
+
+ + + + +
+ Fetching contributors… +
+ +
+ + Cannot retrieve contributors at this time +
+
+ + + + + +
+ +
+
+ + 2 lines (2 sloc) + + 1.24 KB +
+ +
+ +
+ Raw + Blame + History +
+ + +
+ + + + + + +
+
+
+ + + + + +
+ + + + + + + + + + +
!function(t){"use strict";var e=t.HTMLCanvasElement&&t.HTMLCanvasElement.prototype,o=t.Blob&&function(){try{return Boolean(new Blob)}catch(t){return!1}}(),n=o&&t.Uint8Array&&function(){try{return 100===new Blob([new Uint8Array(100)]).size}catch(t){return!1}}(),r=t.BlobBuilder||t.WebKitBlobBuilder||t.MozBlobBuilder||t.MSBlobBuilder,a=/^data:((.*?)(;charset=.*?)?)(;base64)?,/,i=(o||r)&&t.atob&&t.ArrayBuffer&&t.Uint8Array&&function(t){var e,i,l,u,c,f,b,d,B;if(!(e=t.match(a)))throw new Error("invalid data URI");for(i=e[2]?e[1]:"text/plain"+(e[3]||";charset=US-ASCII"),l=!!e[4],u=t.slice(e[0].length),c=l?atob(u):decodeURIComponent(u),f=new ArrayBuffer(c.length),b=new Uint8Array(f),d=0;d<c.length;d+=1)b[d]=c.charCodeAt(d);return o?new Blob([n?b:f],{type:i}):((B=new r).append(f),B.getBlob(i))};t.HTMLCanvasElement&&!e.toBlob&&(e.mozGetAsFile?e.toBlob=function(t,o,n){var r=this;setTimeout(function(){t(n&&e.toDataURL&&i?i(r.toDataURL(o,n)):r.mozGetAsFile("blob",o))})}:e.toDataURL&&i&&(e.toBlob=function(t,e,o){var n=this;setTimeout(function(){t(i(n.toDataURL(e,o)))})})),"function"==typeof define&&define.amd?define(function(){return i}):"object"==typeof module&&module.exports?module.exports=i:t.dataURLtoBlob=i}(window);
//# sourceMappingURL=canvas-to-blob.min.js.map
+ + + +
+ +
+ + + +
+ + +
+ + +
+
+ + + + + +
+
+ +
+
+ + +
+ + + + + + +
+ + + You can’t perform that action at this time. +
+ + + + + + + + + + + + + + + + +
+ + + + diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/jquery/jquery-1.10.2.min.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/jquery/jquery-1.10.2.min.js" new file mode 100644 index 00000000..da417064 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/jquery/jquery-1.10.2.min.js" @@ -0,0 +1,6 @@ +/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license +//@ sourceMappingURL=jquery-1.10.2.min.map +*/ +(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="
",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===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]||at.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]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
a",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="
t
",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t +}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X
","
"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle); +u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("',"",""].join(""));return l.ie&&l.ie<8?c.removeClass("layui-hide").addClass(o):(d[0]&&d.remove(),s.call(a,m,c[0],y),c.addClass("layui-hide").after(m),a.index)},c.prototype.getContent=function(t){var e=u(t);if(e[0])return d(e[0].document.body.innerHTML)},c.prototype.getText=function(t){var i=u(t);if(i[0])return e(i[0].document.body).text()},c.prototype.setContent=function(t,i,a){var l=u(t);l[0]&&(a?e(l[0].document.body).append(i):e(l[0].document.body).html(i),layedit.sync(t))},c.prototype.sync=function(t){var i=u(t);if(i[0]){var a=e("#"+i[1].attr("textarea"));a.val(d(i[0].document.body.innerHTML))}},c.prototype.getSelection=function(t){var e=u(t);if(e[0]){var i=m(e[0].document);return document.selection?i.text:i.toString()}};var s=function(t,i,a){var l=this,n=t.find("iframe");n.css({height:a.height}).on("load",function(){var o=n.contents(),r=n.prop("contentWindow"),c=o.find("head"),s=e([""].join("")),u=o.find("body");c.append(s),u.attr("contenteditable","true").css({"min-height":a.height}).html(i.value||""),y.apply(l,[r,n,i,a]),g.call(l,r,t,a)})},u=function(t){var i=e("#LAY_layedit_"+t),a=i.prop("contentWindow");return[a,i]},d=function(t){return 8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),t},y=function(t,a,n,o){var r=t.document,c=e(r.body);c.on("keydown",function(t){var e=t.keyCode;if(13===e){var a=m(r),l=p(a),n=l.parentNode;if("pre"===n.tagName.toLowerCase()){if(t.shiftKey)return;return i.msg("请暂时用shift+enter"),!1}r.execCommand("formatBlock",!1,"

")}}),e(n).parents("form").on("submit",function(){var t=c.html();8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),n.value=t}),c.on("paste",function(e){r.execCommand("formatBlock",!1,"

"),setTimeout(function(){f.call(t,c),n.value=c.html()},100)})},f=function(t){var i=this;i.document;t.find("*[style]").each(function(){var t=this.style.textAlign;this.removeAttribute("style"),e(this).css({"text-align":t||""})}),t.find("table").addClass("layui-table"),t.find("script,link").remove()},m=function(t){return t.selection?t.selection.createRange():t.getSelection().getRangeAt(0)},p=function(t){return t.endContainer||t.parentElement().childNodes[0]},v=function(t,i,a){var l=this.document,n=document.createElement(t);for(var o in i)n.setAttribute(o,i[o]);if(n.removeAttribute("text"),l.selection){var r=a.text||i.text;if("a"===t&&!r)return;r&&(n.innerHTML=r),a.pasteHTML(e(n).prop("outerHTML")),a.select()}else{var r=a.toString()||i.text;if("a"===t&&!r)return;r&&(n.innerHTML=r),a.deleteContents(),a.insertNode(n)}},h=function(t,i){var a=this.document,l="layedit-tool-active",n=p(m(a)),o=function(e){return t.find(".layedit-tool-"+e)};i&&i[i.hasClass(l)?"removeClass":"addClass"](l),t.find(">i").removeClass(l),o("unlink").addClass(r),e(n).parents().each(function(){var t=this.tagName.toLowerCase(),e=this.style.textAlign;"b"!==t&&"strong"!==t||o("b").addClass(l),"i"!==t&&"em"!==t||o("i").addClass(l),"u"===t&&o("u").addClass(l),"strike"===t&&o("d").addClass(l),"p"===t&&("center"===e?o("center").addClass(l):"right"===e?o("right").addClass(l):o("left").addClass(l)),"a"===t&&(o("link").addClass(l),o("unlink").removeClass(r))})},g=function(t,a,l){var n=t.document,o=e(n.body),c={link:function(i){var a=p(i),l=e(a).parent();b.call(o,{href:l.attr("href"),target:l.attr("target")},function(e){var a=l[0];"A"===a.tagName?a.href=e.url:v.call(t,"a",{target:e.target,href:e.url,text:e.url},i)})},unlink:function(t){n.execCommand("unlink")},face:function(e){x.call(this,function(i){v.call(t,"img",{src:i.src,alt:i.alt},e)})},image:function(a){var n=this;layui.use("upload",function(o){var r=l.uploadImage||{};o.render({url:r.url,method:r.type,elem:e(n).find("input")[0],done:function(e){0==e.code?(e.data=e.data||{},v.call(t,"img",{src:e.data.src,alt:e.data.title},a)):i.msg(e.msg||"上传失败")}})})},code:function(e){k.call(o,function(i){v.call(t,"pre",{text:i.code,"lay-lang":i.lang},e)})},help:function(){i.open({type:2,title:"帮助",area:["600px","380px"],shadeClose:!0,shade:.1,skin:"layui-layer-msg",content:["http://www.layui.com/about/layedit/help.html","no"]})}},s=a.find(".layui-layedit-tool"),u=function(){var i=e(this),a=i.attr("layedit-event"),l=i.attr("lay-command");if(!i.hasClass(r)){o.focus();var u=m(n);u.commonAncestorContainer;l?(n.execCommand(l),/justifyLeft|justifyCenter|justifyRight/.test(l)&&n.execCommand("formatBlock",!1,"

"),setTimeout(function(){o.focus()},10)):c[a]&&c[a].call(this,u),h.call(t,s,i)}},d=/image/;s.find(">i").on("mousedown",function(){var t=e(this),i=t.attr("layedit-event");d.test(i)||u.call(this)}).on("click",function(){var t=e(this),i=t.attr("layedit-event");d.test(i)&&u.call(this)}),o.on("click",function(){h.call(t,s),i.close(x.index)})},b=function(t,e){var l=this,n=i.open({type:1,id:"LAY_layedit_link",area:"350px",shade:.05,shadeClose:!0,moveType:1,title:"超链接",skin:"layui-layer-msg",content:['

    ','
  • ','','
    ','',"
    ","
  • ",'
  • ','','
    ','",'","
    ","
  • ",'
  • ','','',"
  • ","
"].join(""),success:function(t,n){var o="submit(layedit-link-yes)";a.render("radio"),t.find(".layui-btn-primary").on("click",function(){i.close(n),l.focus()}),a.on(o,function(t){i.close(b.index),e&&e(t.field)})}});b.index=n},x=function(t){var a=function(){var t=["[微笑]","[嘻嘻]","[哈哈]","[可爱]","[可怜]","[挖鼻]","[吃惊]","[害羞]","[挤眼]","[闭嘴]","[鄙视]","[爱你]","[泪]","[偷笑]","[亲亲]","[生病]","[太开心]","[白眼]","[右哼哼]","[左哼哼]","[嘘]","[衰]","[委屈]","[吐]","[哈欠]","[抱抱]","[怒]","[疑问]","[馋嘴]","[拜拜]","[思考]","[汗]","[困]","[睡]","[钱]","[失望]","[酷]","[色]","[哼]","[鼓掌]","[晕]","[悲伤]","[抓狂]","[黑线]","[阴险]","[怒骂]","[互粉]","[心]","[伤心]","[猪头]","[熊猫]","[兔子]","[ok]","[耶]","[good]","[NO]","[赞]","[来]","[弱]","[草泥马]","[神马]","[囧]","[浮云]","[给力]","[围观]","[威武]","[奥特曼]","[礼物]","[钟]","[话筒]","[蜡烛]","[蛋糕]"],e={};return layui.each(t,function(t,i){e[i]=layui.cache.dir+"images/face/"+t+".gif"}),e}();return x.hide=x.hide||function(t){"face"!==e(t.target).attr("layedit-event")&&i.close(x.index)},x.index=i.tips(function(){var t=[];return layui.each(a,function(e,i){t.push('
  • '+e+'
  • ')}),'
      '+t.join("")+"
    "}(),this,{tips:1,time:0,skin:"layui-box layui-util-face",maxWidth:500,success:function(l,n){l.css({marginTop:-4,marginLeft:-10}).find(".layui-clear>li").on("click",function(){t&&t({src:a[this.title],alt:this.title}),i.close(n)}),e(document).off("click",x.hide).on("click",x.hide)}})},k=function(t){var e=this,l=i.open({type:1,id:"LAY_layedit_code",area:"550px",shade:.05,shadeClose:!0,moveType:1,title:"插入代码",skin:"layui-layer-msg",content:['
      ','
    • ','','
      ','","
      ","
    • ",'
    • ','','
      ','',"
      ","
    • ",'
    • ','','',"
    • ","
    "].join(""),success:function(l,n){var o="submit(layedit-code-yes)";a.render("select"),l.find(".layui-btn-primary").on("click",function(){i.close(n),e.focus()}),a.on(o,function(e){i.close(k.index),t&&t(e.field)})}});k.index=l},C={html:'',strong:'',italic:'',underline:'',del:'',"|":'',left:'',center:'',right:'',link:'',unlink:'',face:'',image:'',code:'',help:''},w=new c;t(n,w)}); \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/layer.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/layer.js" new file mode 100644 index 00000000..bc816610 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/layer.js" @@ -0,0 +1,2 @@ +/** layui-v2.5.5 MIT License By https://www.layui.com */ + ;!function(e,t){"use strict";var i,n,a=e.layui&&layui.define,o={getPath:function(){var e=document.currentScript?document.currentScript.src:function(){for(var e,t=document.scripts,i=t.length-1,n=i;n>0;n--)if("interactive"===t[n].readyState){e=t[n].src;break}return e||t[i].src}();return e.substring(0,e.lastIndexOf("/")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:["确定","取消"],type:["dialog","page","iframe","loading","tips"],getStyle:function(t,i){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](i)},link:function(t,i,n){if(r.path){var a=document.getElementsByTagName("head")[0],s=document.createElement("link");"string"==typeof i&&(n=i);var l=(n||t).replace(/\.|\//g,""),f="layuicss-"+l,c=0;s.rel="stylesheet",s.href=r.path+t,s.id=f,document.getElementById(f)||a.appendChild(s),"function"==typeof i&&!function u(){return++c>80?e.console&&console.error("layer.css: Invalid"):void(1989===parseInt(o.getStyle(document.getElementById(f),"width"))?i():setTimeout(u,100))}()}}},r={v:"3.1.1",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||"ActiveXObject"in e)&&((t.match(/msie\s(\d+)/)||[])[1]||"11")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,"string"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss("modules/layer/"+e.extend):o.link("theme/"+e.extend),this):this},ready:function(e){var t="layer",i="",n=(a?"modules/layer/":"theme/")+"default/layer.css?v="+r.v+i;return a?layui.addcss(n,e,t):o.link(n,e,t),this},alert:function(e,t,n){var a="function"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var s="function"==typeof t;return s&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},s?{}:t))},msg:function(e,n,a){var s="function"==typeof n,f=o.config.skin,c=(f?f+" "+f+"-msg":"")||"layui-layer-msg",u=l.anim.length-1;return s&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},s&&!o.config.skin?{skin:c+" layui-layer-hui",anim:u}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+" "+(n.skin||"layui-layer-hui")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:210},n))}},s=function(e){var t=this;t.index=++r.index,t.config=i.extend({},t.config,o.config,e),document.body?t.creat():setTimeout(function(){t.creat()},30)};s.pt=s.prototype;var l=["layui-layer",".layui-layer-title",".layui-layer-main",".layui-layer-dialog","layui-layer-iframe","layui-layer-content","layui-layer-btn","layui-layer-close"];l.anim=["layer-anim-00","layer-anim-01","layer-anim-02","layer-anim-03","layer-anim-04","layer-anim-05","layer-anim-06"],s.pt.config={type:0,shade:.3,fixed:!0,move:l[1],title:"信息",offset:"auto",area:"auto",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},s.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,s=r.zIndex+a,f="object"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),u=r.title?'
    '+(f?r.title[0]:r.title)+"
    ":"";return r.zIndex=s,t([r.shade?'
    ':"",'
    '+(e&&2!=r.type?"":u)+'
    '+(0==r.type&&r.icon!==-1?'':"")+(1==r.type&&e?"":r.content||"")+'
    '+function(){var e=c?'':"";return r.closeBtn&&(e+=''),e}()+""+(r.btn?function(){var e="";"string"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t'+r.btn[t]+"";return'
    '+e+"
    "}():"")+(r.resize?'':"")+"
    "],u,i('
    ')),n},s.pt.creat=function(){var e=this,t=e.config,a=e.index,s=t.content,f="object"==typeof s,c=i("body");if(!t.id||!i("#"+t.id)[0]){switch("string"==typeof t.area&&(t.area="auto"===t.area?["",""]:[t.area,""]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn="btn"in t?t.btn:o.btn[0],r.closeAll("dialog");break;case 2:var s=t.content=f?t.content:[t.content||"","auto"];t.content='';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll("loading");break;case 4:f||(t.content=[t.content,"body"]),t.follow=t.content[1],t.content=t.content[0]+'',delete t.title,t.tips="object"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll("tips")}if(e.vessel(f,function(n,r,u){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i("body").append(n[1])}():function(){s.parents("."+l[0])[0]||(s.data("display",s.css("display")).show().addClass("layui-layer-wrap").wrap(n[1]),i("#"+l[0]+a).find("."+l[5]).before(r))}()}():c.append(n[1]),i(".layui-layer-move")[0]||c.append(o.moveElem=u),e.layero=i("#"+l[0]+a),t.scrollbar||l.html.css("overflow","hidden").attr("layer-full",a)}).auto(a),i("#layui-layer-shade"+e.index).css({"background-color":t.shade[1]||"#000",opacity:t.shade[0]||t.shade}),2==t.type&&6==r.ie&&e.layero.find("iframe").attr("src",s[0]),4==t.type?e.tips():e.offset(),t.fixed&&n.on("resize",function(){e.offset(),(/^\d+%$/.test(t.area[0])||/^\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),l.anim[t.anim]){var u="layer-anim "+l.anim[t.anim];e.layero.addClass(u).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",function(){i(this).removeClass(u)})}t.isOutAnim&&e.layero.data("isOutAnim",!0)}},s.pt.auto=function(e){var t=this,a=t.config,o=i("#"+l[0]+e);""===a.area[0]&&a.maxWidth>0&&(r.ie&&r.ie<8&&a.btn&&o.width(o.innerWidth()),o.outerWidth()>a.maxWidth&&o.width(a.maxWidth));var s=[o.innerWidth(),o.innerHeight()],f=o.find(l[1]).outerHeight()||0,c=o.find("."+l[6]).outerHeight()||0,u=function(e){e=o.find(e),e.height(s[1]-f-c-2*(0|parseFloat(e.css("padding-top"))))};switch(a.type){case 2:u("iframe");break;default:""===a.area[1]?a.maxHeight>0&&o.outerHeight()>a.maxHeight?(s[1]=a.maxHeight,u("."+l[5])):a.fixed&&s[1]>=n.height()&&(s[1]=n.height(),u("."+l[5])):u("."+l[5])}return t},s.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o="object"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(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=n.width()-a[0]:"b"===t.offset?e.offsetTop=n.height()-a[1]:"l"===t.offset?e.offsetLeft=0:"lt"===t.offset?(e.offsetTop=0,e.offsetLeft=0):"lb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):"rt"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):"rb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr("minLeft")&&(e.offsetTop=n.height()-(i.find(l[1]).outerHeight()||0),e.offsetLeft=i.css("left")),i.css({top:e.offsetTop,left:e.offsetLeft})},s.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i("body"));var s={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(".layui-layer-TipsG"),c=t.tips[0];t.tips[1]||f.remove(),s.autoLeft=function(){s.left+o[0]-n.width()>0?(s.tipLeft=s.left+s.width-o[0],f.css({right:12,left:"auto"})):s.tipLeft=s.left},s.where=[function(){s.autoLeft(),s.tipTop=s.top-o[1]-10,f.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left+s.width+10,s.tipTop=s.top,f.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color",t.tips[1])},function(){s.autoLeft(),s.tipTop=s.top+s.height+10,f.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left-o[0]-10,s.tipTop=s.top,f.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color",t.tips[1])}],s.where[c-1](),1===c?s.top-(n.scrollTop()+o[1]+16)<0&&s.where[2]():2===c?n.width()-(s.left+s.width+o[0]+16)>0||s.where[3]():3===c?s.top-n.scrollTop()+s.height+o[1]+16-n.height()>0&&s.where[0]():4===c&&o[0]+16-s.left>0&&s.where[1](),a.find("."+l[5]).css({"background-color":t.tips[1],"padding-right":t.closeBtn?"30px":""}),a.css({left:s.tipLeft-(t.fixed?n.scrollLeft():0),top:s.tipTop-(t.fixed?n.scrollTop():0)})},s.pt.move=function(){var e=this,t=e.config,a=i(document),s=e.layero,l=s.find(t.move),f=s.find(".layui-layer-resize"),c={};return t.move&&l.css("cursor","move"),l.on("mousedown",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(s.css("left")),e.clientY-parseFloat(s.css("top"))],o.moveElem.css("cursor","move").show())}),f.on("mousedown",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[s.outerWidth(),s.outerHeight()],o.moveElem.css("cursor","se-resize").show()}),a.on("mousemove",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],l="fixed"===s.css("position");if(i.preventDefault(),c.stX=l?0:n.scrollLeft(),c.stY=l?0:n.scrollTop(),!t.moveOut){var f=n.width()-s.outerWidth()+c.stX,u=n.height()-s.outerHeight()+c.stY;af&&(a=f),ou&&(o=u)}s.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0,t.resizing&&t.resizing(s)}}).on("mouseup",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd(s)),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},s.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find("iframe").on("load",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find("."+l[6]).children("a").on("click",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a["btn"+(e+1)]&&a["btn"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find("."+l[7]).on("click",e),a.shadeClose&&i("#layui-layer-shade"+t.index).on("click",function(){r.close(t.index)}),n.find(".layui-layer-min").on("click",function(){var e=a.min&&a.min(n);e===!1||r.min(t.index,a)}),n.find(".layui-layer-max").on("click",function(){i(this).hasClass("layui-layer-maxmin")?(r.restore(t.index),a.restore&&a.restore(n)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i("select"),function(e,t){var n=i(this);n.parents("."+l[0])[0]||1==n.attr("layer")&&i("."+l[0]).length<1&&n.removeAttr("layer").show(),n=null})},s.pt.IE6=function(e){i("select").each(function(e,t){var n=i(this);n.parents("."+l[0])[0]||"none"===n.css("display")||n.attr({layer:"1"}).hide(),n=null})},s.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css("z-index",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on("mousedown",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css("margin-left"))];e.find(".layui-layer-max").addClass("layui-layer-maxmin"),e.attr({area:t})},o.rescollbar=function(e){l.html.attr("layer-full")==e&&(l.html[0].style.removeProperty?l.html[0].style.removeProperty("overflow"):l.html[0].style.removeAttribute("overflow"),l.html.removeAttr("layer-full"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i("."+l[4]).attr("times"),i("#"+l[0]+t).find("iframe").contents().find(e)},r.getFrameIndex=function(e){return i("#"+e).parents("."+l[4]).attr("times")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame("html",e).outerHeight(),n=i("#"+l[0]+e),a=n.find(l[1]).outerHeight()||0,o=n.find("."+l[6]).outerHeight()||0;n.css({height:t+a+o}),n.find("iframe").css({height:t})}},r.iframeSrc=function(e,t){i("#"+l[0]+e).find("iframe").attr("src",t)},r.style=function(e,t,n){var a=i("#"+l[0]+e),r=a.find(".layui-layer-content"),s=a.attr("type"),f=a.find(l[1]).outerHeight()||0,c=a.find("."+l[6]).outerHeight()||0;a.attr("minLeft");s!==o.type[3]&&s!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find("."+l[6]).outerHeight(),s===o.type[2]?a.find("iframe").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css("padding-top"))-parseFloat(r.css("padding-bottom"))}))},r.min=function(e,t){var a=i("#"+l[0]+e),s=a.find(l[1]).outerHeight()||0,f=a.attr("minLeft")||181*o.minIndex+"px",c=a.css("position");o.record(a),o.minLeft[0]&&(f=o.minLeft[0],o.minLeft.shift()),a.attr("position",c),r.style(e,{width:180,height:s,left:f,top:n.height()-s,position:"fixed",overflow:"hidden"},!0),a.find(".layui-layer-min").hide(),"page"===a.attr("type")&&a.find(l[4]).hide(),o.rescollbar(e),a.attr("minLeft")||o.minIndex++,a.attr("minLeft",f)},r.restore=function(e){var t=i("#"+l[0]+e),n=t.attr("area").split(",");t.attr("type");r.style(e,{width:parseFloat(n[0]),height:parseFloat(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"===t.attr("type")&&t.find(l[4]).show(),o.rescollbar(e)},r.full=function(e){var t,a=i("#"+l[0]+e);o.record(a),l.html.attr("layer-full")||l.html.css("overflow","hidden").attr("layer-full",e),clearTimeout(t),t=setTimeout(function(){var t="fixed"===a.css("position");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(".layui-layer-min").hide()},100)},r.title=function(e,t){var n=i("#"+l[0]+(t||r.index)).find(l[1]);n.html(e)},r.close=function(e){var t=i("#"+l[0]+e),n=t.attr("type"),a="layer-anim-close";if(t[0]){var s="layui-layer-wrap",f=function(){if(n===o.type[1]&&"object"===t.attr("conType")){t.children(":not(."+l[5]+")").remove();for(var a=t.find("."+s),r=0;r<2;r++)a.unwrap();a.css("display",a.data("display")).removeClass(s)}else{if(n===o.type[2])try{var f=i("#"+l[4]+e)[0];f.contentWindow.document.write(""),f.contentWindow.close(),t.find("."+l[5])[0].removeChild(f)}catch(c){}t[0].innerHTML="",t.remove()}"function"==typeof o.end[e]&&o.end[e](),delete o.end[e]};t.data("isOutAnim")&&t.addClass("layer-anim "+a),i("#layui-layer-moves, #layui-layer-shade"+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),t.attr("minLeft")&&(o.minIndex--,o.minLeft.push(t.attr("minLeft"))),r.ie&&r.ie<10||!t.data("isOutAnim")?f():setTimeout(function(){f()},200)}},r.closeAll=function(e){i.each(i("."+l[0]),function(){var t=i(this),n=e?t.attr("type")===e:1;n&&r.close(t.attr("times")),n=null})};var f=r.cache||{},c=function(e){return f.skin?" "+f.skin+" "+f.skin+"-"+e:""};r.prompt=function(e,t){var a="";if(e=e||{},"function"==typeof e&&(t=e),e.area){var o=e.area;a='style="width: '+o[0]+"; height: "+o[1]+';"',delete e.area}var s,l=2==e.formType?'":function(){return''}(),f=e.success;return delete e.success,r.open(i.extend({type:1,btn:["确定","取消"],content:l,skin:"layui-layer-prompt"+c("prompt"),maxWidth:n.width(),success:function(t){s=t.find(".layui-layer-input"),s.val(e.value||"").focus(),"function"==typeof f&&f(t)},resize:!1,yes:function(i){var n=s.val();""===n?s.focus():n.length>(e.maxlength||500)?r.tips("最多输入"+(e.maxlength||500)+"个字数",s,{tips:1}):t&&t(n,i,s)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{},n="layui-this",a=e.success;return delete e.success,r.open(i.extend({type:1,skin:"layui-layer-tab"+c("tab"),resize:!1,title:function(){var e=t.length,i=1,a="";if(e>0)for(a=''+t[0].title+"";i"+t[i].title+"";return a}(),content:'
      '+function(){var e=t.length,i=1,a="";if(e>0)for(a='
    • '+(t[0].content||"no content")+"
    • ";i'+(t[i].content||"no content")+"";return a}()+"
    ",success:function(t){var o=t.find(".layui-layer-title").children(),r=t.find(".layui-layer-tabmain").children();o.on("mousedown",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var a=i(this),o=a.index();a.addClass(n).siblings().removeClass(n),r.eq(o).show().siblings().hide(),"function"==typeof e.change&&e.change(o)}),"function"==typeof a&&a(t)}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var s={};if(t=t||{},t.photos){var l=t.photos.constructor===Object,f=l?t.photos:{},u=f.data||[],d=f.start||0;s.imgIndex=(0|d)+1,t.img=t.img||"img";var y=t.success;if(delete t.success,l){if(0===u.length)return r.msg("没有图片")}else{var p=i(t.photos),h=function(){u=[],p.find(t.img).each(function(e){var t=i(this);t.attr("layer-index",e),u.push({alt:t.attr("alt"),pid:t.attr("layer-pid"),src:t.attr("layer-src")||t.attr("src"),thumb:t.attr("src")})})};if(h(),0===u.length)return;if(n||p.on("click",t.img,function(){var e=i(this),n=e.attr("layer-index");r.photos(i.extend(t,{photos:{start:n,data:u,tab:t.tab},full:t.full}),!0),h()}),!n)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=u.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>u.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){if(!s.end){var t=e.keyCode;e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&r.close(s.index)}},s.tabimg=function(e){if(!(u.length<=1))return f.start=s.imgIndex-1,r.close(s.index),r.photos(t,!0,e)},s.event=function(){s.bigimg.hover(function(){s.imgsee.show()},function(){s.imgsee.hide()}),s.bigimg.find(".layui-layer-imgprev").on("click",function(e){e.preventDefault(),s.imgprev()}),s.bigimg.find(".layui-layer-imgnext").on("click",function(e){e.preventDefault(),s.imgnext()}),i(document).on("keyup",s.keyup)},s.loadi=r.load(1,{shade:!("shade"in t)&&.9,scrollbar:!1}),o(u[d].src,function(n){r.close(s.loadi),s.index=r.open(i.extend({type:1,id:"layui-layer-photos",area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]'+(u[d].alt||
    '+(u.length>1?'':"")+'
    '+(u[d].alt||"")+""+s.imgIndex+"/"+u.length+"
    ",success:function(e,i){s.bigimg=e.find(".layui-layer-phimg"),s.imgsee=e.find(".layui-layer-imguide,.layui-layer-imgbar"),s.event(e),t.tab&&t.tab(u[d],e),"function"==typeof y&&y(e)},end:function(){s.end=!0,i(document).off("keyup",s.keyup)}},t))},function(){r.close(s.loadi),r.msg("当前图片地址异常
    是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){u.length>1&&s.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),l.html=i("html"),r.open=function(e){var t=new s(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define("jquery",function(t){r.path=layui.cache.dir,o.run(layui.$),e.layer=r,t("layer",r)})):"function"==typeof define&&define.amd?define(["jquery"],function(){return o.run(e.jQuery),r}):function(){o.run(e.jQuery),r.ready()}()}(window); \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/laypage.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/laypage.js" new file mode 100644 index 00000000..478c11f2 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/laypage.js" @@ -0,0 +1,2 @@ +/** layui-v2.5.5 MIT License By https://www.layui.com */ + ;layui.define(function(e){"use strict";var a=document,t="getElementById",n="getElementsByTagName",i="laypage",r="layui-disabled",u=function(e){var a=this;a.config=e||{},a.config.index=++s.index,a.render(!0)};u.prototype.type=function(){var e=this.config;if("object"==typeof e.elem)return void 0===e.elem.length?2:3},u.prototype.view=function(){var e=this,a=e.config,t=a.groups="groups"in a?0|a.groups:5;a.layout="object"==typeof a.layout?a.layout:["prev","page","next"],a.count=0|a.count,a.curr=0|a.curr||1,a.limits="object"==typeof a.limits?a.limits:[10,20,30,40,50],a.limit=0|a.limit||10,a.pages=Math.ceil(a.count/a.limit)||1,a.curr>a.pages&&(a.curr=a.pages),t<0?t=1:t>a.pages&&(t=a.pages),a.prev="prev"in a?a.prev:"上一页",a.next="next"in a?a.next:"下一页";var n=a.pages>t?Math.ceil((a.curr+(t>1?1:0))/(t>0?t:1)):1,i={prev:function(){return a.prev?''+a.prev+"":""}(),page:function(){var e=[];if(a.count<1)return"";n>1&&a.first!==!1&&0!==t&&e.push(''+(a.first||1)+"");var i=Math.floor((t-1)/2),r=n>1?a.curr-i:1,u=n>1?function(){var e=a.curr+(t-i-1);return e>a.pages?a.pages:e}():t;for(u-r2&&e.push('');r<=u;r++)r===a.curr?e.push('"+r+""):e.push(''+r+"");return a.pages>t&&a.pages>u&&a.last!==!1&&(u+1…'),0!==t&&e.push(''+(a.last||a.pages)+"")),e.join("")}(),next:function(){return a.next?''+a.next+"":""}(),count:'共 '+a.count+" 条",limit:function(){var e=['"}(),refresh:['','',""].join(""),skip:function(){return['到第','','页',""].join("")}()};return['
    ',function(){var e=[];return layui.each(a.layout,function(a,t){i[t]&&e.push(i[t])}),e.join("")}(),"
    "].join("")},u.prototype.jump=function(e,a){if(e){var t=this,i=t.config,r=e.children,u=e[n]("button")[0],l=e[n]("input")[0],p=e[n]("select")[0],c=function(){var e=0|l.value.replace(/\s|\D/g,"");e&&(i.curr=e,t.render())};if(a)return c();for(var o=0,y=r.length;oi.pages||(i.curr=e,t.render())});p&&s.on(p,"change",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),u&&s.on(u,"click",function(){c()})}},u.prototype.skip=function(e){if(e){var a=this,t=e[n]("input")[0];t&&s.on(t,"keyup",function(t){var n=this.value,i=t.keyCode;/^(37|38|39|40)$/.test(i)||(/\D/.test(n)&&(this.value=n.replace(/\D/,"")),13===i&&a.jump(e,!0))})}},u.prototype.render=function(e){var n=this,i=n.config,r=n.type(),u=n.view();2===r?i.elem&&(i.elem.innerHTML=u):3===r?i.elem.html(u):a[t](i.elem)&&(a[t](i.elem).innerHTML=u),i.jump&&i.jump(i,e);var s=a[t]("layui-laypage-"+i.index);n.jump(s),i.hash&&!e&&(location.hash="!"+i.hash+"="+i.curr),n.skip(s)};var s={render:function(e){var a=new u(e);return a.index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(e,a,t){return e.attachEvent?e.attachEvent("on"+a,function(a){a.target=a.srcElement,t.call(e,a)}):e.addEventListener(a,t,!1),this}};e(i,s)}); \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/laytpl.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/laytpl.js" new file mode 100644 index 00000000..dd0d5671 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/laytpl.js" @@ -0,0 +1,2 @@ +/** layui-v2.5.5 MIT License By https://www.layui.com */ + ;layui.define(function(e){"use strict";var r={open:"{{",close:"}}"},c={exp:function(e){return new RegExp(e,"g")},query:function(e,c,t){var o=["#([\\s\\S])+?","([^{#}])*?"][e||0];return n((c||"")+r.open+o+r.close+(t||""))},escape:function(e){return String(e||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")},error:function(e,r){var c="Laytpl Error:";return"object"==typeof console&&console.error(c+e+"\n"+(r||"")),c+e}},n=c.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=n("^"+r.open+"#",""),l=n(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(n(r.open+"#"),r.open+"# ").replace(n(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(n(r.open+"!(.+?)!"+r.close),function(e){return e=e.replace(n("^"+r.open+"!"),"").replace(n("!"+r.close),"").replace(n(r.open+"|"+r.close),function(e){return e.replace(/(.)/g,"\\$1")})}).replace(/(?="|')/g,"\\").replace(c.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(c.query(1),function(e){var c='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(n(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),c='"+_escape_('),c+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,c.escape)}catch(u){return delete o.cache,c.error(u,p)}},t.pt.render=function(e,r){var n,t=this;return e?(n=t.cache?t.cache(e,c.escape):t.parse(t.tpl,e),r?void r(n):n):c.error("no data")};var o=function(e){return"string"!=typeof e?c.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var c in e)r[c]=e[c]},o.v="1.2.0",e("laytpl",o)}); \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/mobile.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/mobile.js" new file mode 100644 index 00000000..cba72cb6 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/mobile.js" @@ -0,0 +1,2 @@ +/** layui-v2.5.5 MIT License By https://www.layui.com */ + ;layui.define(function(i){i("layui.mobile",layui.v)});layui.define(function(e){"use strict";var r={open:"{{",close:"}}"},c={exp:function(e){return new RegExp(e,"g")},query:function(e,c,t){var o=["#([\\s\\S])+?","([^{#}])*?"][e||0];return n((c||"")+r.open+o+r.close+(t||""))},escape:function(e){return String(e||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")},error:function(e,r){var c="Laytpl Error:";return"object"==typeof console&&console.error(c+e+"\n"+(r||"")),c+e}},n=c.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=n("^"+r.open+"#",""),l=n(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(n(r.open+"#"),r.open+"# ").replace(n(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(n(r.open+"!(.+?)!"+r.close),function(e){return e=e.replace(n("^"+r.open+"!"),"").replace(n("!"+r.close),"").replace(n(r.open+"|"+r.close),function(e){return e.replace(/(.)/g,"\\$1")})}).replace(/(?="|')/g,"\\").replace(c.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(c.query(1),function(e){var c='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(n(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),c='"+_escape_('),c+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,c.escape)}catch(u){return delete o.cache,c.error(u,p)}},t.pt.render=function(e,r){var n,t=this;return e?(n=t.cache?t.cache(e,c.escape):t.parse(t.tpl,e),r?void r(n):n):c.error("no data")};var o=function(e){return"string"!=typeof e?c.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var c in e)r[c]=e[c]},o.v="1.2.0",e("laytpl",o)});layui.define(function(e){"use strict";var t=(window,document),i="querySelectorAll",n="getElementsByClassName",a=function(e){return t[i](e)},s={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:"scale"},l={extend:function(e){var t=JSON.parse(JSON.stringify(s));for(var i in e)t[i]=e[i];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener("click",function(e){t.call(this,e)},!1)};var o=0,r=["layui-m-layer"],d=function(e){var t=this;t.config=l.extend(e),t.view()};d.prototype.view=function(){var e=this,i=e.config,s=t.createElement("div");e.id=s.id=r[0]+o,s.setAttribute("class",r[0]+" "+r[0]+(i.type||0)),s.setAttribute("index",o);var l=function(){var e="object"==typeof i.title;return i.title?'

    '+(e?i.title[0]:i.title)+"

    ":""}(),d=function(){"string"==typeof i.btn&&(i.btn=[i.btn]);var e,t=(i.btn||[]).length;return 0!==t&&i.btn?(e=''+i.btn[0]+"",2===t&&(e=''+i.btn[1]+""+e),'
    '+e+"
    "):""}();if(i.fixed||(i.top=i.hasOwnProperty("top")?i.top:100,i.style=i.style||"",i.style+=" top:"+(t.body.scrollTop+i.top)+"px"),2===i.type&&(i.content='

    '+(i.content||"")+"

    "),i.skin&&(i.anim="up"),"msg"===i.skin&&(i.shade=!1),s.innerHTML=(i.shade?"
    ':"")+'
    "+l+'
    '+i.content+"
    "+d+"
    ",!i.type||2===i.type){var y=t[n](r[0]+i.type),u=y.length;u>=1&&c.close(y[0].getAttribute("index"))}document.body.appendChild(s);var m=e.elem=a("#"+e.id)[0];i.success&&i.success(m),e.index=o++,e.action(i,m)},d.prototype.action=function(e, t){var i=this;e.time&&(l.timer[i.index]=setTimeout(function(){c.close(i.index)},1e3*e.time));var a=function(){var t=this.getAttribute("type");0==t?(e.no&&e.no(),c.close(i.index)):e.yes?e.yes(i.index):c.close(i.index)};if(e.btn)for(var s=t[n]("layui-m-layerbtn")[0].children,o=s.length,r=0; r0&&e-1 in t)}function s(t){return A.call(t,function(t){return null!=t})}function u(t){return t.length>0?T.fn.concat.apply([],t):t}function c(t){return t.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function l(t){return t in F?F[t]:F[t]=new RegExp("(^|\\s)"+t+"(\\s|$)")}function f(t,e){return"number"!=typeof e||k[c(t)]?e:e+"px"}function h(t){var e,n;return $[t]||(e=L.createElement(t),L.body.appendChild(e),n=getComputedStyle(e,"").getPropertyValue("display"),e.parentNode.removeChild(e),"none"==n&&(n="block"),$[t]=n),$[t]}function p(t){return"children"in t?D.call(t.children):T.map(t.childNodes,function(t){if(1==t.nodeType)return t})}function d(t,e){var n,r=t?t.length:0;for(n=0;n]*>/,R=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,z=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,Z=/^(?:body|html)$/i,q=/([A-Z])/g,H=["val","css","html","text","data","width","height","offset"],I=["after","prepend","before","append"],V=L.createElement("table"),_=L.createElement("tr"),B={tr:L.createElement("tbody"),tbody:V,thead:V,tfoot:V,td:_,th:_,"*":L.createElement("div")},U=/complete|loaded|interactive/,X=/^[\w-]*$/,J={},W=J.toString,Y={},G=L.createElement("div"),K={tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},Q=Array.isArray||function(t){return t instanceof Array};return Y.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var n=t.matches||t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(n)return n.call(t,e);var r,i=t.parentNode,o=!i;return o&&(i=G).appendChild(t),r=~Y.qsa(i,e).indexOf(t),o&&G.removeChild(t),r},C=function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():""})},N=function(t){return A.call(t,function(e,n){return t.indexOf(e)==n})},Y.fragment=function(t,e,n){var r,i,a;return R.test(t)&&(r=T(L.createElement(RegExp.$1))),r||(t.replace&&(t=t.replace(z,"<$1>")),e===E&&(e=M.test(t)&&RegExp.$1),e in B||(e="*"),a=B[e],a.innerHTML=""+t,r=T.each(D.call(a.childNodes),function(){a.removeChild(this)})),o(n)&&(i=T(r),T.each(n,function(t,e){H.indexOf(t)>-1?i[t](e):i.attr(t,e)})),r},Y.Z=function(t,e){return new d(t,e)},Y.isZ=function(t){return t instanceof Y.Z},Y.init=function(t,n){var r;if(!t)return Y.Z();if("string"==typeof t)if(t=t.trim(),"<"==t[0]&&M.test(t))r=Y.fragment(t,RegExp.$1,n),t=null;else{if(n!==E)return T(n).find(t);r=Y.qsa(L,t)}else{if(e(t))return T(L).ready(t);if(Y.isZ(t))return t;if(Q(t))r=s(t);else if(i(t))r=[t],t=null;else if(M.test(t))r=Y.fragment(t.trim(),RegExp.$1,n),t=null;else{if(n!==E)return T(n).find(t);r=Y.qsa(L,t)}}return Y.Z(r,t)},T=function(t,e){return Y.init(t,e)},T.extend=function(t){var e,n=D.call(arguments,1);return"boolean"==typeof t&&(e=t,t=n.shift()),n.forEach(function(n){m(t,n,e)}),t},Y.qsa=function(t,e){var n,r="#"==e[0],i=!r&&"."==e[0],o=r||i?e.slice(1):e,a=X.test(o);return t.getElementById&&a&&r?(n=t.getElementById(o))?[n]:[]:1!==t.nodeType&&9!==t.nodeType&&11!==t.nodeType?[]:D.call(a&&!r&&t.getElementsByClassName?i?t.getElementsByClassName(o):t.getElementsByTagName(e):t.querySelectorAll(e))},T.contains=L.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e&&(e=e.parentNode);)if(e===t)return!0;return!1},T.type=t,T.isFunction=e,T.isWindow=n,T.isArray=Q,T.isPlainObject=o,T.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},T.isNumeric=function(t){var e=Number(t),n=typeof t;return null!=t&&"boolean"!=n&&("string"!=n||t.length)&&!isNaN(e)&&isFinite(e)||!1},T.inArray=function(t,e,n){return O.indexOf.call(e,t,n)},T.camelCase=C,T.trim=function(t){return null==t?"":String.prototype.trim.call(t)},T.uuid=0,T.support={},T.expr={},T.noop=function(){},T.map=function(t,e){var n,r,i,o=[];if(a(t))for(r=0;r=0?t:t+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(t){return O.every.call(this,function(e,n){return t.call(e,n,e)!==!1}),this},filter:function(t){return e(t)?this.not(this.not(t)):T(A.call(this,function(e){return Y.matches(e,t)}))},add:function(t,e){return T(N(this.concat(T(t,e))))},is:function(t){return this.length>0&&Y.matches(this[0],t)},not:function(t){var n=[];if(e(t)&&t.call!==E)this.each(function(e){t.call(this,e)||n.push(this)});else{var r="string"==typeof t?this.filter(t):a(t)&&e(t.item)?D.call(t):T(t);this.forEach(function(t){r.indexOf(t)<0&&n.push(t)})}return T(n)},has:function(t){return this.filter(function(){return i(t)?T.contains(this,t):T(this).find(t).size()})},eq:function(t){return t===-1?this.slice(t):this.slice(t,+t+1)},first:function(){var t=this[0];return t&&!i(t)?t:T(t)},last:function(){var t=this[this.length-1];return t&&!i(t)?t:T(t)},find:function(t){var e,n=this;return e=t?"object"==typeof t?T(t).filter(function(){var t=this;return O.some.call(n,function(e){return T.contains(e,t)})}):1==this.length?T(Y.qsa(this[0],t)):this.map(function(){return Y.qsa(this,t)}):T()},closest:function(t,e){var n=[],i="object"==typeof t&&T(t);return this.each(function(o,a){for(;a&&!(i?i.indexOf(a)>=0:Y.matches(a,t));)a=a!==e&&!r(a)&&a.parentNode;a&&n.indexOf(a)<0&&n.push(a)}),T(n)},parents:function(t){for(var e=[],n=this;n.length>0;)n=T.map(n,function(t){if((t=t.parentNode)&&!r(t)&&e.indexOf(t)<0)return e.push(t),t});return v(e,t)},parent:function(t){return v(N(this.pluck("parentNode")),t)},children:function(t){return v(this.map(function(){return p(this)}),t)},contents:function(){return this.map(function(){return this.contentDocument||D.call(this.childNodes)})},siblings:function(t){return v(this.map(function(t,e){return A.call(p(e.parentNode),function(t){return t!==e})}),t)},empty:function(){return this.each(function(){this.innerHTML=""})},pluck:function(t){return T.map(this,function(e){return e[t]})},show:function(){return this.each(function(){"none"==this.style.display&&(this.style.display=""),"none"==getComputedStyle(this,"").getPropertyValue("display")&&(this.style.display=h(this.nodeName))})},replaceWith:function(t){return this.before(t).remove()},wrap:function(t){var n=e(t);if(this[0]&&!n)var r=T(t).get(0),i=r.parentNode||this.length>1;return this.each(function(e){T(this).wrapAll(n?t.call(this,e):i?r.cloneNode(!0):r)})},wrapAll:function(t){if(this[0]){T(this[0]).before(t=T(t));for(var e;(e=t.children()).length;)t=e.first();T(t).append(this)}return this},wrapInner:function(t){var n=e(t);return this.each(function(e){var r=T(this),i=r.contents(),o=n?t.call(this,e):t;i.length?i.wrapAll(o):r.append(o)})},unwrap:function(){return this.parent().each(function(){T(this).replaceWith(T(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css("display","none")},toggle:function(t){return this.each(function(){var e=T(this);(t===E?"none"==e.css("display"):t)?e.show():e.hide()})},prev:function(t){return T(this.pluck("previousElementSibling")).filter(t||"*")},next:function(t){return T(this.pluck("nextElementSibling")).filter(t||"*")},html:function(t){return 0 in arguments?this.each(function(e){var n=this.innerHTML;T(this).empty().append(g(this,t,e,n))}):0 in this?this[0].innerHTML:null},text:function(t){return 0 in arguments?this.each(function(e){var n=g(this,t,e,this.textContent);this.textContent=null==n?"":""+n}):0 in this?this.pluck("textContent").join(""):null},attr:function(t,e){var n;return"string"!=typeof t||1 in arguments?this.each(function(n){if(1===this.nodeType)if(i(t))for(j in t)y(this,j,t[j]);else y(this,t,g(this,e,n,this.getAttribute(t)))}):0 in this&&1==this[0].nodeType&&null!=(n=this[0].getAttribute(t))?n:E},removeAttr:function(t){return this.each(function(){1===this.nodeType&&t.split(" ").forEach(function(t){y(this,t)},this)})},prop:function(t,e){return t=K[t]||t,1 in arguments?this.each(function(n){this[t]=g(this,e,n,this[t])}):this[0]&&this[0][t]},removeProp:function(t){return t=K[t]||t,this.each(function(){delete this[t]})},data:function(t,e){var n="data-"+t.replace(q,"-$1").toLowerCase(),r=1 in arguments?this.attr(n,e):this.attr(n);return null!==r?b(r):E},val:function(t){return 0 in arguments?(null==t&&(t=""),this.each(function(e){this.value=g(this,t,e,this.value)})):this[0]&&(this[0].multiple?T(this[0]).find("option").filter(function(){return this.selected}).pluck("value"):this[0].value)},offset:function(t){if(t)return this.each(function(e){var n=T(this),r=g(this,t,e,n.offset()),i=n.offsetParent().offset(),o={top:r.top-i.top,left:r.left-i.left};"static"==n.css("position")&&(o.position="relative"),n.css(o)});if(!this.length)return null;if(L.documentElement!==this[0]&&!T.contains(L.documentElement,this[0]))return{top:0,left:0};var e=this[0].getBoundingClientRect();return{left:e.left+window.pageXOffset,top:e.top+window.pageYOffset,width:Math.round(e.width),height:Math.round(e.height)}},css:function(e,n){if(arguments.length<2){var r=this[0];if("string"==typeof e){if(!r)return;return r.style[C(e)]||getComputedStyle(r,"").getPropertyValue(e)}if(Q(e)){if(!r)return;var i={},o=getComputedStyle(r,"");return T.each(e,function(t,e){i[e]=r.style[C(e)]||o.getPropertyValue(e)}),i}}var a="";if("string"==t(e))n||0===n?a=c(e)+":"+f(e,n):this.each(function(){this.style.removeProperty(c(e))});else for(j in e)e[j]||0===e[j]?a+=c(j)+":"+f(j,e[j])+";":this.each(function(){this.style.removeProperty(c(j))});return this.each(function(){this.style.cssText+=";"+a})},index:function(t){return t?this.indexOf(T(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return!!t&&O.some.call(this,function(t){return this.test(x(t))},l(t))},addClass:function(t){return t?this.each(function(e){if("className"in this){S=[];var n=x(this),r=g(this,t,e,n);r.split(/\s+/g).forEach(function(t){T(this).hasClass(t)||S.push(t)},this),S.length&&x(this,n+(n?" ":"")+S.join(" "))}}):this},removeClass:function(t){return this.each(function(e){if("className"in this){if(t===E)return x(this,"");S=x(this),g(this,t,e,S).split(/\s+/g).forEach(function(t){S=S.replace(l(t)," ")}),x(this,S.trim())}})},toggleClass:function(t,e){return t?this.each(function(n){var r=T(this),i=g(this,t,n,x(this));i.split(/\s+/g).forEach(function(t){(e===E?!r.hasClass(t):e)?r.addClass(t):r.removeClass(t)})}):this},scrollTop:function(t){if(this.length){var e="scrollTop"in this[0];return t===E?e?this[0].scrollTop:this[0].pageYOffset:this.each(e?function(){this.scrollTop=t}:function(){this.scrollTo(this.scrollX,t)})}},scrollLeft:function(t){if(this.length){var e="scrollLeft"in this[0];return t===E?e?this[0].scrollLeft:this[0].pageXOffset:this.each(e?function(){this.scrollLeft=t}:function(){this.scrollTo(t,this.scrollY)})}},position:function(){if(this.length){var t=this[0],e=this.offsetParent(),n=this.offset(),r=Z.test(e[0].nodeName)?{top:0,left:0}:e.offset();return n.top-=parseFloat(T(t).css("margin-top"))||0,n.left-=parseFloat(T(t).css("margin-left"))||0,r.top+=parseFloat(T(e[0]).css("border-top-width"))||0,r.left+=parseFloat(T(e[0]).css("border-left-width"))||0,{top:n.top-r.top,left:n.left-r.left}}},offsetParent:function(){return this.map(function(){for(var t=this.offsetParent||L.body;t&&!Z.test(t.nodeName)&&"static"==T(t).css("position");)t=t.offsetParent;return t})}},T.fn.detach=T.fn.remove,["width","height"].forEach(function(t){var e=t.replace(/./,function(t){return t[0].toUpperCase()});T.fn[t]=function(i){var o,a=this[0];return i===E?n(a)?a["inner"+e]:r(a)?a.documentElement["scroll"+e]:(o=this.offset())&&o[t]:this.each(function(e){a=T(this),a.css(t,g(this,i,e,a[t]()))})}}),I.forEach(function(e,n){var r=n%2;T.fn[e]=function(){var e,i,o=T.map(arguments,function(n){var r=[];return e=t(n),"array"==e?(n.forEach(function(t){return t.nodeType!==E?r.push(t):T.zepto.isZ(t)?r=r.concat(t.get()):void(r=r.concat(Y.fragment(t)))}),r):"object"==e||null==n?n:Y.fragment(n)}),a=this.length>1;return o.length<1?this:this.each(function(t,e){i=r?e:e.parentNode,e=0==n?e.nextSibling:1==n?e.firstChild:2==n?e:null;var s=T.contains(L.documentElement,i);o.forEach(function(t){if(a)t=t.cloneNode(!0);else if(!i)return T(t).remove();i.insertBefore(t,e),s&&w(t,function(t){if(!(null==t.nodeName||"SCRIPT"!==t.nodeName.toUpperCase()||t.type&&"text/javascript"!==t.type||t.src)){var e=t.ownerDocument?t.ownerDocument.defaultView:window;e.eval.call(e,t.innerHTML)}})})})},T.fn[r?e+"To":"insert"+(n?"Before":"After")]=function(t){return T(t)[e](this),this}}),Y.Z.prototype=d.prototype=T.fn,Y.uniq=N,Y.deserializeValue=b,T.zepto=Y,T}();!function(t){function e(t){return t._zid||(t._zid=h++)}function n(t,n,o,a){if(n=r(n),n.ns)var s=i(n.ns);return(v[e(t)]||[]).filter(function(t){return t&&(!n.e||t.e==n.e)&&(!n.ns||s.test(t.ns))&&(!o||e(t.fn)===e(o))&&(!a||t.sel==a)})}function r(t){var e=(""+t).split(".");return{e:e[0],ns:e.slice(1).sort().join(" ")}}function i(t){return new RegExp("(?:^| )"+t.replace(" "," .* ?")+"(?: |$)")}function o(t,e){return t.del&&!y&&t.e in x||!!e}function a(t){return b[t]||y&&x[t]||t}function s(n,i,s,u,l,h,p){var d=e(n),m=v[d]||(v[d]=[]);i.split(/\s/).forEach(function(e){if("ready"==e)return t(document).ready(s);var i=r(e);i.fn=s,i.sel=l,i.e in b&&(s=function(e){var n=e.relatedTarget;if(!n||n!==this&&!t.contains(this,n))return i.fn.apply(this,arguments)}),i.del=h;var d=h||s;i.proxy=function(t){if(t=c(t),!t.isImmediatePropagationStopped()){t.data=u;var e=d.apply(n,t._args==f?[t]:[t].concat(t._args));return e===!1&&(t.preventDefault(),t.stopPropagation()),e}},i.i=m.length,m.push(i),"addEventListener"in n&&n.addEventListener(a(i.e),i.proxy,o(i,p))})}function u(t,r,i,s,u){var c=e(t);(r||"").split(/\s/).forEach(function(e){n(t,e,i,s).forEach(function(e){delete v[c][e.i],"removeEventListener"in t&&t.removeEventListener(a(e.e),e.proxy,o(e,u))})})}function c(e,n){return!n&&e.isDefaultPrevented||(n||(n=e),t.each(T,function(t,r){var i=n[t];e[t]=function(){return this[r]=w,i&&i.apply(n,arguments)},e[r]=E}),e.timeStamp||(e.timeStamp=Date.now()),(n.defaultPrevented!==f?n.defaultPrevented:"returnValue"in n?n.returnValue===!1:n.getPreventDefault&&n.getPreventDefault())&&(e.isDefaultPrevented=w)),e}function l(t){var e,n={originalEvent:t};for(e in t)j.test(e)||t[e]===f||(n[e]=t[e]);return c(n,t)}var f,h=1,p=Array.prototype.slice,d=t.isFunction,m=function(t){return"string"==typeof t},v={},g={},y="onfocusin"in window,x={focus:"focusin",blur:"focusout"},b={mouseenter:"mouseover",mouseleave:"mouseout"};g.click=g.mousedown=g.mouseup=g.mousemove="MouseEvents",t.event={add:s,remove:u},t.proxy=function(n,r){var i=2 in arguments&&p.call(arguments,2);if(d(n)){var o=function(){return n.apply(r,i?i.concat(p.call(arguments)):arguments)};return o._zid=e(n),o}if(m(r))return i?(i.unshift(n[r],n),t.proxy.apply(null,i)):t.proxy(n[r],n);throw new TypeError("expected function")},t.fn.bind=function(t,e,n){return this.on(t,e,n)},t.fn.unbind=function(t,e){return this.off(t,e)},t.fn.one=function(t,e,n,r){return this.on(t,e,n,r,1)};var w=function(){return!0},E=function(){return!1},j=/^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/,T={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};t.fn.delegate=function(t,e,n){return this.on(e,t,n)},t.fn.undelegate=function(t,e,n){return this.off(e,t,n)},t.fn.live=function(e,n){return t(document.body).delegate(this.selector,e,n),this},t.fn.die=function(e,n){return t(document.body).undelegate(this.selector,e,n),this},t.fn.on=function(e,n,r,i,o){var a,c,h=this;return e&&!m(e)?(t.each(e,function(t,e){h.on(t,n,r,e,o)}),h):(m(n)||d(i)||i===!1||(i=r,r=n,n=f),i!==f&&r!==!1||(i=r,r=f),i===!1&&(i=E),h.each(function(f,h){o&&(a=function(t){return u(h,t.type,i),i.apply(this,arguments)}),n&&(c=function(e){var r,o=t(e.target).closest(n,h).get(0);if(o&&o!==h)return r=t.extend(l(e),{currentTarget:o,liveFired:h}),(a||i).apply(o,[r].concat(p.call(arguments,1)))}),s(h,e,i,r,n,c||a)}))},t.fn.off=function(e,n,r){var i=this;return e&&!m(e)?(t.each(e,function(t,e){i.off(t,n,e)}),i):(m(n)||d(r)||r===!1||(r=n,n=f),r===!1&&(r=E),i.each(function(){u(this,e,r,n)}))},t.fn.trigger=function(e,n){return e=m(e)||t.isPlainObject(e)?t.Event(e):c(e),e._args=n,this.each(function(){e.type in x&&"function"==typeof this[e.type]?this[e.type]():"dispatchEvent"in this?this.dispatchEvent(e):t(this).triggerHandler(e,n)})},t.fn.triggerHandler=function(e,r){var i,o;return this.each(function(a,s){i=l(m(e)?t.Event(e):e),i._args=r,i.target=s,t.each(n(s,e.type||e),function(t,e){if(o=e.proxy(i),i.isImmediatePropagationStopped())return!1})}),o},"focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function(e){t.fn[e]=function(t){return 0 in arguments?this.bind(e,t):this.trigger(e)}}),t.Event=function(t,e){m(t)||(e=t,t=e.type);var n=document.createEvent(g[t]||"Events"),r=!0;if(e)for(var i in e)"bubbles"==i?r=!!e[i]:n[i]=e[i];return n.initEvent(t,r,!0),c(n)}}(e),function(t){function e(e,n,r){var i=t.Event(n);return t(e).trigger(i,r),!i.isDefaultPrevented()}function n(t,n,r,i){if(t.global)return e(n||x,r,i)}function r(e){e.global&&0===t.active++&&n(e,null,"ajaxStart")}function i(e){e.global&&!--t.active&&n(e,null,"ajaxStop")}function o(t,e){var r=e.context;return e.beforeSend.call(r,t,e)!==!1&&n(e,r,"ajaxBeforeSend",[t,e])!==!1&&void n(e,r,"ajaxSend",[t,e])}function a(t,e,r,i){var o=r.context,a="success";r.success.call(o,t,a,e),i&&i.resolveWith(o,[t,a,e]),n(r,o,"ajaxSuccess",[e,r,t]),u(a,e,r)}function s(t,e,r,i,o){var a=i.context;i.error.call(a,r,e,t),o&&o.rejectWith(a,[r,e,t]),n(i,a,"ajaxError",[r,i,t||e]),u(e,r,i)}function u(t,e,r){var o=r.context;r.complete.call(o,e,t),n(r,o,"ajaxComplete",[e,r]),i(r)}function c(t,e,n){if(n.dataFilter==l)return t;var r=n.context;return n.dataFilter.call(r,t,e)}function l(){}function f(t){return t&&(t=t.split(";",2)[0]),t&&(t==T?"html":t==j?"json":w.test(t)?"script":E.test(t)&&"xml")||"text"}function h(t,e){return""==e?t:(t+"&"+e).replace(/[&?]{1,2}/,"?")}function p(e){e.processData&&e.data&&"string"!=t.type(e.data)&&(e.data=t.param(e.data,e.traditional)),!e.data||e.type&&"GET"!=e.type.toUpperCase()&&"jsonp"!=e.dataType||(e.url=h(e.url,e.data),e.data=void 0)}function d(e,n,r,i){return t.isFunction(n)&&(i=r,r=n,n=void 0),t.isFunction(r)||(i=r,r=void 0),{url:e,data:n,success:r,dataType:i}}function m(e,n,r,i){var o,a=t.isArray(n),s=t.isPlainObject(n);t.each(n,function(n,u){o=t.type(u),i&&(n=r?i:i+"["+(s||"object"==o||"array"==o?n:"")+"]"),!i&&a?e.add(u.name,u.value):"array"==o||!r&&"object"==o?m(e,u,r,n):e.add(n,u)})}var v,g,y=+new Date,x=window.document,b=/)<[^<]*)*<\/script>/gi,w=/^(?:text|application)\/javascript/i,E=/^(?:text|application)\/xml/i,j="application/json",T="text/html",S=/^\s*$/,C=x.createElement("a");C.href=window.location.href,t.active=0,t.ajaxJSONP=function(e,n){if(!("type"in e))return t.ajax(e);var r,i,u=e.jsonpCallback,c=(t.isFunction(u)?u():u)||"Zepto"+y++,l=x.createElement("script"),f=window[c],h=function(e){t(l).triggerHandler("error",e||"abort")},p={abort:h};return n&&n.promise(p),t(l).on("load error",function(o,u){clearTimeout(i),t(l).off().remove(),"error"!=o.type&&r?a(r[0],p,e,n):s(null,u||"error",p,e,n),window[c]=f,r&&t.isFunction(f)&&f(r[0]),f=r=void 0}),o(p,e)===!1?(h("abort"),p):(window[c]=function(){r=arguments},l.src=e.url.replace(/\?(.+)=\?/,"?$1="+c),x.head.appendChild(l),e.timeout>0&&(i=setTimeout(function(){h("timeout")},e.timeout)),p)},t.ajaxSettings={type:"GET",beforeSend:l,success:l,error:l,complete:l,context:null,global:!0,xhr:function(){return new window.XMLHttpRequest},accepts:{script:"text/javascript, application/javascript, application/x-javascript",json:j,xml:"application/xml, text/xml",html:T,text:"text/plain"},crossDomain:!1,timeout:0,processData:!0,cache:!0,dataFilter:l},t.ajax=function(e){var n,i,u=t.extend({},e||{}),d=t.Deferred&&t.Deferred();for(v in t.ajaxSettings)void 0===u[v]&&(u[v]=t.ajaxSettings[v]);r(u),u.crossDomain||(n=x.createElement("a"),n.href=u.url,n.href=n.href,u.crossDomain=C.protocol+"//"+C.host!=n.protocol+"//"+n.host),u.url||(u.url=window.location.toString()),(i=u.url.indexOf("#"))>-1&&(u.url=u.url.slice(0,i)),p(u);var m=u.dataType,y=/\?.+=\?/.test(u.url);if(y&&(m="jsonp"),u.cache!==!1&&(e&&e.cache===!0||"script"!=m&&"jsonp"!=m)||(u.url=h(u.url,"_="+Date.now())),"jsonp"==m)return y||(u.url=h(u.url,u.jsonp?u.jsonp+"=?":u.jsonp===!1?"":"callback=?")),t.ajaxJSONP(u,d);var b,w=u.accepts[m],E={},j=function(t,e){E[t.toLowerCase()]=[t,e]},T=/^([\w-]+:)\/\//.test(u.url)?RegExp.$1:window.location.protocol,N=u.xhr(),O=N.setRequestHeader;if(d&&d.promise(N),u.crossDomain||j("X-Requested-With","XMLHttpRequest"),j("Accept",w||"*/*"),(w=u.mimeType||w)&&(w.indexOf(",")>-1&&(w=w.split(",",2)[0]),N.overrideMimeType&&N.overrideMimeType(w)),(u.contentType||u.contentType!==!1&&u.data&&"GET"!=u.type.toUpperCase())&&j("Content-Type",u.contentType||"application/x-www-form-urlencoded"),u.headers)for(g in u.headers)j(g,u.headers[g]);if(N.setRequestHeader=j,N.onreadystatechange=function(){if(4==N.readyState){N.onreadystatechange=l,clearTimeout(b);var e,n=!1;if(N.status>=200&&N.status<300||304==N.status||0==N.status&&"file:"==T){if(m=m||f(u.mimeType||N.getResponseHeader("content-type")),"arraybuffer"==N.responseType||"blob"==N.responseType)e=N.response;else{e=N.responseText;try{e=c(e,m,u),"script"==m?(0,eval)(e):"xml"==m?e=N.responseXML:"json"==m&&(e=S.test(e)?null:t.parseJSON(e))}catch(r){n=r}if(n)return s(n,"parsererror",N,u,d)}a(e,N,u,d)}else s(N.statusText||null,N.status?"error":"abort",N,u,d)}},o(N,u)===!1)return N.abort(),s(null,"abort",N,u,d),N;var P=!("async"in u)||u.async;if(N.open(u.type,u.url,P,u.username,u.password),u.xhrFields)for(g in u.xhrFields)N[g]=u.xhrFields[g];for(g in E)O.apply(N,E[g]);return u.timeout>0&&(b=setTimeout(function(){N.onreadystatechange=l,N.abort(),s(null,"timeout",N,u,d)},u.timeout)),N.send(u.data?u.data:null),N},t.get=function(){return t.ajax(d.apply(null,arguments))},t.post=function(){var e=d.apply(null,arguments);return e.type="POST",t.ajax(e)},t.getJSON=function(){var e=d.apply(null,arguments);return e.dataType="json",t.ajax(e)},t.fn.load=function(e,n,r){if(!this.length)return this;var i,o=this,a=e.split(/\s/),s=d(e,n,r),u=s.success;return a.length>1&&(s.url=a[0],i=a[1]),s.success=function(e){o.html(i?t("
    ").html(e.replace(b,"")).find(i):e),u&&u.apply(o,arguments)},t.ajax(s),this};var N=encodeURIComponent;t.param=function(e,n){var r=[];return r.add=function(e,n){t.isFunction(n)&&(n=n()),null==n&&(n=""),this.push(N(e)+"="+N(n))},m(r,e,n),r.join("&").replace(/%20/g,"+")}}(e),function(t){t.fn.serializeArray=function(){var e,n,r=[],i=function(t){return t.forEach?t.forEach(i):void r.push({name:e,value:t})};return this[0]&&t.each(this[0].elements,function(r,o){n=o.type,e=o.name,e&&"fieldset"!=o.nodeName.toLowerCase()&&!o.disabled&&"submit"!=n&&"reset"!=n&&"button"!=n&&"file"!=n&&("radio"!=n&&"checkbox"!=n||o.checked)&&i(t(o).val())}),r},t.fn.serialize=function(){var t=[];return this.serializeArray().forEach(function(e){t.push(encodeURIComponent(e.name)+"="+encodeURIComponent(e.value))}),t.join("&")},t.fn.submit=function(e){if(0 in arguments)this.bind("submit",e);else if(this.length){var n=t.Event("submit");this.eq(0).trigger(n),n.isDefaultPrevented()||this.get(0).submit()}return this}}(e),function(){try{getComputedStyle(void 0)}catch(t){var e=getComputedStyle;window.getComputedStyle=function(t,n){try{return e(t,n)}catch(r){return null}}}}(),t("zepto",e)});layui.define(function(i){i("layim-mobile",layui.v)});layui["layui.mobile"]||layui.config({base:layui.cache.dir+"lay/modules/mobile/"}).extend({"layer-mobile":"layer-mobile",zepto:"zepto","upload-mobile":"upload-mobile","layim-mobile":"layim-mobile"}),layui.define(["layer-mobile","zepto","layim-mobile"],function(l){l("mobile",{layer:layui["layer-mobile"],layim:layui["layim-mobile"]})}); \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/rate.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/rate.js" new file mode 100644 index 00000000..bcc103fe --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/rate.js" @@ -0,0 +1,2 @@ +/** layui-v2.5.5 MIT License By https://www.layui.com */ + ;layui.define("jquery",function(e){"use strict";var a=layui.jquery,i={config:{},index:layui.rate?layui.rate.index+1e4:0,set:function(e){var i=this;return i.config=a.extend({},i.config,e),i},on:function(e,a){return layui.onevent.call(this,n,e,a)}},l=function(){var e=this,a=e.config;return{setvalue:function(a){e.setvalue.call(e,a)},config:a}},n="rate",t="layui-rate",o="layui-icon-rate",s="layui-icon-rate-solid",u="layui-icon-rate-half",r="layui-icon-rate-solid layui-icon-rate-half",c="layui-icon-rate-solid layui-icon-rate",f="layui-icon-rate layui-icon-rate-half",v=function(e){var l=this;l.index=++i.index,l.config=a.extend({},l.config,i.config,e),l.render()};v.prototype.config={length:5,text:!1,readonly:!1,half:!1,value:0,theme:""},v.prototype.render=function(){var e=this,i=e.config,l=i.theme?'style="color: '+i.theme+';"':"";i.elem=a(i.elem),parseInt(i.value)!==i.value&&(i.half||(i.value=Math.ceil(i.value)-i.value<.5?Math.ceil(i.value):Math.floor(i.value)));for(var n='
      ",u=1;u<=i.length;u++){var r='
    • ";i.half&&parseInt(i.value)!==i.value&&u==Math.ceil(i.value)?n=n+'
    • ":n+=r}n+="
    "+(i.text?''+i.value+"星":"")+"";var c=i.elem,f=c.next("."+t);f[0]&&f.remove(),e.elemTemp=a(n),i.span=e.elemTemp.next("span"),i.setText&&i.setText(i.value),c.html(e.elemTemp),c.addClass("layui-inline"),i.readonly||e.action()},v.prototype.setvalue=function(e){var a=this,i=a.config;i.value=e,a.render()},v.prototype.action=function(){var e=this,i=e.config,l=e.elemTemp,n=l.find("i").width();l.children("li").each(function(e){var t=e+1,v=a(this);v.on("click",function(e){if(i.value=t,i.half){var o=e.pageX-a(this).offset().left;o<=n/2&&(i.value=i.value-.5)}i.text&&l.next("span").text(i.value+"星"),i.choose&&i.choose(i.value),i.setText&&i.setText(i.value)}),v.on("mousemove",function(e){if(l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+t+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half){var c=e.pageX-a(this).offset().left;c<=n/2&&v.children("i").addClass(u).removeClass(s)}}),v.on("mouseleave",function(){l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+Math.floor(i.value)+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half&&parseInt(i.value)!==i.value&&l.children("li:eq("+Math.floor(i.value)+")").children("i").addClass(u).removeClass(c)})})},v.prototype.events=function(){var e=this;e.config},i.render=function(e){var a=new v(e);return l.call(a)},e(n,i)}); \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/slider.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/slider.js" new file mode 100644 index 00000000..c39707d0 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/slider.js" @@ -0,0 +1,2 @@ +/** layui-v2.5.5 MIT License By https://www.layui.com */ + ;layui.define("jquery",function(e){"use strict";var i=layui.jquery,t={config:{},index:layui.slider?layui.slider.index+1e4:0,set:function(e){var t=this;return t.config=i.extend({},t.config,e),t},on:function(e,i){return layui.onevent.call(this,n,e,i)}},a=function(){var e=this,i=e.config;return{setValue:function(i,t){return e.slide("set",i,t||0)},config:i}},n="slider",l="layui-disabled",s="layui-slider",r="layui-slider-bar",o="layui-slider-wrap",u="layui-slider-wrap-btn",d="layui-slider-tips",v="layui-slider-input",c="layui-slider-input-txt",m="layui-slider-input-btn",p="layui-slider-hover",f=function(e){var a=this;a.index=++t.index,a.config=i.extend({},a.config,t.config,e),a.render()};f.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:"#009688"},f.prototype.render=function(){var e=this,t=e.config;if(t.step<1&&(t.step=1),t.maxt.min?a:t.min,t.value[1]=n>t.min?n:t.min,t.value[0]=t.value[0]>t.max?t.max:t.value[0],t.value[1]=t.value[1]>t.max?t.max:t.value[1];var r=Math.floor((t.value[0]-t.min)/(t.max-t.min)*100),v=Math.floor((t.value[1]-t.min)/(t.max-t.min)*100),m=v-r+"%";r+="%",v+="%"}else{"object"==typeof t.value&&(t.value=Math.min.apply(null,t.value)),t.valuet.max&&(t.value=t.max);var m=Math.floor((t.value-t.min)/(t.max-t.min)*100)+"%"}var p=t.disabled?"#c2c2c2":t.theme,f='
    '+(t.tips?'
    ':"")+'
    '+(t.range?'
    ':"")+"
    ",h=i(t.elem),y=h.next("."+s);if(y[0]&&y.remove(),e.elemTemp=i(f),t.range?(e.elemTemp.find("."+o).eq(0).data("value",t.value[0]),e.elemTemp.find("."+o).eq(1).data("value",t.value[1])):e.elemTemp.find("."+o).data("value",t.value),h.html(e.elemTemp),"vertical"===t.type&&e.elemTemp.height(t.height+"px"),t.showstep){for(var g=(t.max-t.min)/t.step,b="",x=1;x
    ')}e.elemTemp.append(b)}if(t.input&&!t.range){var w=i('
    ');h.css("position","relative"),h.append(w),h.find("."+c).children("input").val(t.value),"vertical"===t.type?w.css({left:0,top:-48}):e.elemTemp.css("margin-right",w.outerWidth()+15)}t.disabled?(e.elemTemp.addClass(l),e.elemTemp.find("."+u).addClass(l)):e.slide(),e.elemTemp.find("."+u).on("mouseover",function(){var a="vertical"===t.type?t.height:e.elemTemp[0].offsetWidth,n=e.elemTemp.find("."+o),l="vertical"===t.type?a-i(this).parent()[0].offsetTop-n.height():i(this).parent()[0].offsetLeft,s=l/a*100,r=i(this).parent().data("value"),u=t.setTips?t.setTips(r):r;e.elemTemp.find("."+d).html(u),"vertical"===t.type?e.elemTemp.find("."+d).css({bottom:s+"%","margin-bottom":"20px",display:"inline-block"}):e.elemTemp.find("."+d).css({left:s+"%",display:"inline-block"})}).on("mouseout",function(){e.elemTemp.find("."+d).css("display","none")})},f.prototype.slide=function(e,t,a){var n=this,l=n.config,s=n.elemTemp,f=function(){return"vertical"===l.type?l.height:s[0].offsetWidth},h=s.find("."+o),y=s.next("."+v),g=y.children("."+c).children("input").val(),b=100/((l.max-l.min)/Math.ceil(l.step)),x=function(e,i){e=Math.ceil(e)*b>100?Math.ceil(e)*b:Math.round(e)*b,e=e>100?100:e,h.eq(i).css("vertical"===l.type?"bottom":"left",e+"%");var t=T(h[0].offsetLeft),a=l.range?T(h[1].offsetLeft):0;"vertical"===l.type?(s.find("."+d).css({bottom:e+"%","margin-bottom":"20px"}),t=T(f()-h[0].offsetTop-h.height()),a=l.range?T(f()-h[1].offsetTop-h.height()):0):s.find("."+d).css("left",e+"%"),t=t>100?100:t,a=a>100?100:a;var n=Math.min(t,a),o=Math.abs(t-a);"vertical"===l.type?s.find("."+r).css({height:o+"%",bottom:n+"%"}):s.find("."+r).css({width:o+"%",left:n+"%"});var u=l.min+Math.round((l.max-l.min)*e/100);if(g=u,y.children("."+c).children("input").val(g),h.eq(i).data("value",u),u=l.setTips?l.setTips(u):u,s.find("."+d).html(u),l.range){var v=[h.eq(0).data("value"),h.eq(1).data("value")];v[0]>v[1]&&v.reverse()}l.change&&l.change(l.range?v:u)},T=function(e){var i=e/f()*100/b,t=Math.round(i)*b;return e==f()&&(t=Math.ceil(i)*b),t},w=i(['
    f()&&(r=f());var o=r/f()*100/b;x(o,e),t.addClass(p),s.find("."+d).show(),i.preventDefault()},o=function(){t.removeClass(p),s.find("."+d).hide()};M(r,o)})}),s.on("click",function(e){var t=i("."+u);if(!t.is(event.target)&&0===t.has(event.target).length&&t.length){var a,n="vertical"===l.type?f()-e.clientY+i(this).offset().top:e.clientX-i(this).offset().left;n<0&&(n=0),n>f()&&(n=f());var s=n/f()*100/b;a=l.range?"vertical"===l.type?Math.abs(n-parseInt(i(h[0]).css("bottom")))>Math.abs(n-parseInt(i(h[1]).css("bottom")))?1:0:Math.abs(n-h[0].offsetLeft)>Math.abs(n-h[1].offsetLeft)?1:0:0,x(s,a),e.preventDefault()}}),y.hover(function(){var e=i(this);e.children("."+m).fadeIn("fast")},function(){var e=i(this);e.children("."+m).fadeOut("fast")}),y.children("."+m).children("i").each(function(e){i(this).on("click",function(){g=1==e?g-l.stepl.max?l.max:Number(g)+l.step;var i=(g-l.min)/(l.max-l.min)*100/b;x(i,0)})});var q=function(){var e=this.value;e=isNaN(e)?0:e,e=el.max?l.max:e,this.value=e;var i=(e-l.min)/(l.max-l.min)*100/b;x(i,0)};y.children("."+c).children("input").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),q.call(this))}).on("change",q)},f.prototype.events=function(){var e=this;e.config},t.render=function(e){var i=new f(e);return a.call(i)},e(n,t)}); \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/table.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/table.js" new file mode 100644 index 00000000..2e9921e7 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/table.js" @@ -0,0 +1,2 @@ +/** layui-v2.5.5 MIT License By https://www.layui.com */ + ;layui.define(["laytpl","laypage","layer","form","util"],function(e){"use strict";var t=layui.$,i=layui.laytpl,a=layui.laypage,l=layui.layer,n=layui.form,o=(layui.util,layui.hint()),r=layui.device(),d={config:{checkName:"LAY_CHECKED",indexName:"LAY_TABLE_INDEX"},cache:{},index:layui.table?layui.table.index+1e4:0,set:function(e){var i=this;return i.config=t.extend({},i.config,e),i},on:function(e,t){return layui.onevent.call(this,y,e,t)}},c=function(){var e=this,t=e.config,i=t.id||t.index;return i&&(c.that[i]=e,c.config[i]=t),{config:t,reload:function(t){e.reload.call(e,t)},setColsWidth:function(){e.setColsWidth.call(e)},resize:function(){e.resize.call(e)}}},s=function(e){var t=c.config[e];return t||o.error("The ID option was not found in the table instance"),t||null},u=function(e,a,l,n){var o=e.templet?function(){return"function"==typeof e.templet?e.templet(l):i(t(e.templet).html()||String(a)).render(l)}():a;return n?t("
    "+o+"
    ").text():o},y="table",h=".layui-table",f="layui-hide",p="layui-none",v="layui-table-view",m=".layui-table-tool",g=".layui-table-box",b=".layui-table-init",x=".layui-table-header",k=".layui-table-body",C=".layui-table-main",w=".layui-table-fixed",T=".layui-table-fixed-l",A=".layui-table-fixed-r",L=".layui-table-total",N=".layui-table-page",S=".layui-table-sort",W="layui-table-edit",_="layui-table-hover",E=function(e){var t='{{#if(item2.colspan){}} colspan="{{item2.colspan}}"{{#} if(item2.rowspan){}} rowspan="{{item2.rowspan}}"{{#}}}';return e=e||{},['
    ',"","{{# 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; } }}',function(){return 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("")},z=['',"","
    "].join(""),H=['
    ',"{{# if(d.data.toolbar){ }}",'
    ','
    ','
    ',"
    ","{{# } }}",'
    ',"{{# if(d.data.loading){ }}",'
    ','',"
    ","{{# } }}","{{# var left, right; }}",'
    ',E(),"
    ",'
    ',z,"
    ","{{# if(left){ }}",'
    ','
    ',E({fixed:!0}),"
    ",'
    ',z,"
    ","
    ","{{# }; }}","{{# if(right){ }}",'
    ','
    ',E({fixed:"right"}),'
    ',"
    ",'
    ',z,"
    ","
    ","{{# }; }}","
    ","{{# if(d.data.totalRow){ }}",'
    ','','',"
    ","
    ","{{# } }}","{{# if(d.data.page){ }}",'
    ','
    ',"
    ","{{# } }}","","
    "].join(""),R=t(window),F=t(document),j=function(e){var i=this;i.index=++d.index,i.config=t.extend({},i.config,d.config,e),i.render()};j.prototype.config={limit:10,loading:!0,cellMinWidth:60,defaultToolbar:["filter","exports","print"],autoSort:!0,text:{none:"无数据"}},j.prototype.render=function(){var e=this,a=e.config;if(a.elem=t(a.elem),a.where=a.where||{},a.id=a.id||a.elem.attr("id")||e.index,a.request=t.extend({pageName:"page",limitName:"limit"},a.request),a.response=t.extend({statusName:"code",statusCode:0,msgName:"msg",dataName:"data",countName:"count"},a.response),"object"==typeof a.page&&(a.limit=a.page.limit||a.limit,a.limits=a.page.limits||a.limits,e.page=a.page.curr=a.page.curr||1,delete a.page.elem,delete a.page.jump),!a.elem[0])return e;a.height&&/^full-\d+$/.test(a.height)&&(e.fullHeightGap=a.height.split("-")[1],a.height=R.height()-e.fullHeightGap),e.setInit();var l=a.elem,n=l.next("."+v),o=e.elem=t(i(H).render({VIEW_CLASS:v,data:a,index:e.index}));if(a.index=e.index,e.key=a.id||a.index,n[0]&&n.remove(),l.after(o),e.layTool=o.find(m),e.layBox=o.find(g),e.layHeader=o.find(x),e.layMain=o.find(C),e.layBody=o.find(k),e.layFixed=o.find(w),e.layFixLeft=o.find(T),e.layFixRight=o.find(A),e.layTotal=o.find(L),e.layPage=o.find(N),e.renderToolbar(),e.fullSize(),a.cols.length>1){var r=e.layFixed.find(x).find("th");r.height(e.layHeader.height()-1-parseFloat(r.css("padding-top"))-parseFloat(r.css("padding-bottom")))}e.pullData(e.page),e.events()},j.prototype.initOpts=function(e){var t=this,i=(t.config,{checkbox:48,radio:48,space:15,numbers:40});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||i[e.type])},j.prototype.setInit=function(e){var t=this,i=t.config;return i.clientWidth=i.width||function(){var e=function(t){var a,l;t=t||i.elem.parent(),a=t.width();try{l="none"===t.css("display")}catch(n){}return!t[0]||a&&!l?a:e(t.parent())};return e()}(),"width"===e?i.clientWidth:void layui.each(i.cols,function(e,a){layui.each(a,function(l,n){if(!n)return void a.splice(l,1);if(n.key=e+"-"+l,n.hide=n.hide||!1,n.colGroup||n.colspan>1){var o=0;layui.each(i.cols[e+1],function(t,i){i.HAS_PARENT||o>1&&o==n.colspan||(i.HAS_PARENT=!0,i.parentKey=e+"-"+l,o+=parseInt(i.colspan>1?i.colspan:1))}),n.colGroup=!0}t.initOpts(n)})})},j.prototype.renderToolbar=function(){var e=this,a=e.config,l=['
    ','
    ','
    '].join(""),n=e.layTool.find(".layui-table-tool-temp");if("default"===a.toolbar)n.html(l);else if("string"==typeof a.toolbar){var o=t(a.toolbar).html()||"";o&&n.html(i(o).render(a))}var r={filter:{title:"筛选列",layEvent:"LAYTABLE_COLS",icon:"layui-icon-cols"},exports:{title:"导出",layEvent:"LAYTABLE_EXPORT",icon:"layui-icon-export"},print:{title:"打印",layEvent:"LAYTABLE_PRINT",icon:"layui-icon-print"}},d=[];"object"==typeof a.defaultToolbar&&layui.each(a.defaultToolbar,function(e,t){var i="string"==typeof t?r[t]:t;i&&d.push('
    ')}),e.layTool.find(".layui-table-tool-self").html(d.join(""))},j.prototype.setParentCol=function(e,t){var i=this,a=i.config,l=i.layHeader.find('th[data-key="'+a.index+"-"+t+'"]'),n=parseInt(l.attr("colspan"))||0;if(l[0]){var o=t.split("-"),r=a.cols[o[0]][o[1]];e?n--:n++,l.attr("colspan",n),l[n<1?"addClass":"removeClass"](f),r.colspan=n,r.hide=n<1;var d=l.data("parentkey");d&&i.setParentCol(e,d)}},j.prototype.setColsPatch=function(){var e=this,t=e.config;layui.each(t.cols,function(t,i){layui.each(i,function(t,i){i.hide&&e.setParentCol(i.hide,i.parentKey)})})},j.prototype.setColsWidth=function(){var e=this,t=e.config,i=0,a=0,l=0,n=0,o=e.setInit("width");e.eachCols(function(e,t){t.hide||i++}),o=o-function(){return"line"===t.skin||"nob"===t.skin?2:i+1}()-e.getScrollWidth(e.layMain[0])-1;var r=function(e){layui.each(t.cols,function(i,r){layui.each(r,function(i,d){var c=0,s=d.minWidth||t.cellMinWidth;return d?void(d.colGroup||d.hide||(e?l&&ln&&a&&(l=(o-n)/a)};r(),r(!0),e.autoColNums=a,e.eachCols(function(i,a){var n=a.minWidth||t.cellMinWidth;a.colGroup||a.hide||(0===a.width?e.getCssRule(t.index+"-"+a.key,function(e){e.style.width=Math.floor(l>=n?l:n)+"px"}):/\d+%$/.test(a.width)&&e.getCssRule(t.index+"-"+a.key,function(e){e.style.width=Math.floor(parseFloat(a.width)/100*o)+"px"}))});var d=e.layMain.width()-e.getScrollWidth(e.layMain[0])-e.layMain.children("table").outerWidth();if(e.autoColNums&&d>=-i&&d<=i){var c=function(t){var i;return t=t||e.layHeader.eq(0).find("thead th:last-child"),i=t.data("field"),!i&&t.prev()[0]?c(t.prev()):t},s=c(),u=s.data("key");e.getCssRule(u,function(t){var i=t.style.width||s.outerWidth();t.style.width=parseFloat(i)+d+"px",e.layMain.height()-e.layMain.prop("clientHeight")>0&&(t.style.width=parseFloat(t.style.width)-1+"px")})}e.loading(!0)},j.prototype.resize=function(){var e=this;e.fullSize(),e.setColsWidth(),e.scrollPatch()},j.prototype.reload=function(e){var i=this;e=e||{},delete i.haveInit,e.data&&e.data.constructor===Array&&delete i.config.data,i.config=t.extend(!0,{},i.config,e),i.render()},j.prototype.errorView=function(e){var i=this,a=i.layMain.find("."+p),l=t('
    '+(e||"Error")+"
    ");a[0]&&(i.layNone.remove(),a.remove()),i.layFixed.addClass(f),i.layMain.find("tbody").html(""),i.layMain.append(i.layNone=l),d.cache[i.key]=[]},j.prototype.page=1,j.prototype.pullData=function(e){var i=this,a=i.config,l=a.request,n=a.response,o=function(){"object"==typeof a.initSort&&i.sort(a.initSort.field,a.initSort.type)};if(i.startTime=(new Date).getTime(),a.url){var r={};r[l.pageName]=e,r[l.limitName]=a.limit;var d=t.extend(r,a.where);a.contentType&&0==a.contentType.indexOf("application/json")&&(d=JSON.stringify(d)),i.loading(),t.ajax({type:a.method||"get",url:a.url,contentType:a.contentType,data:d,dataType:"json",headers:a.headers||{},success:function(t){"function"==typeof a.parseData&&(t=a.parseData(t)||t),t[n.statusName]!=n.statusCode?(i.renderForm(),i.errorView(t[n.msgName]||'返回的数据不符合规范,正确的成功状态码应为:"'+n.statusName+'": '+n.statusCode)):(i.renderData(t,e,t[n.countName]),o(),a.time=(new Date).getTime()-i.startTime+" ms"),i.setColsWidth(),"function"==typeof a.done&&a.done(t,e,t[n.countName])},error:function(e,t){i.errorView("数据接口请求异常:"+t),i.renderForm(),i.setColsWidth()}})}else if(a.data&&a.data.constructor===Array){var c={},s=e*a.limit-a.limit;c[n.dataName]=a.data.concat().splice(s,a.limit),c[n.countName]=a.data.length,i.renderData(c,e,c[n.countName]),o(),i.setColsWidth(),"function"==typeof a.done&&a.done(c,e,c[n.countName])}},j.prototype.eachCols=function(e){var t=this;return d.eachCols(null,e,t.config.cols),t},j.prototype.renderData=function(e,n,o,r){var c=this,s=c.config,y=e[s.response.dataName]||[],h=[],v=[],m=[],g=function(){var e;return!r&&c.sortKey?c.sort(c.sortKey.field,c.sortKey.sort,!0):(layui.each(y,function(a,l){var o=[],y=[],p=[],g=a+s.limit*(n-1)+1;0!==l.length&&(r||(l[d.config.indexName]=a),c.eachCols(function(n,r){var c=r.field||n,h=s.index+"-"+r.key,v=l[c];if(void 0!==v&&null!==v||(v=""),!r.colGroup){var m=['','
    '+function(){var n=t.extend(!0,{LAY_INDEX:g},l),o=d.config.checkName;switch(r.type){case"checkbox":return'";case"radio":return n[o]&&(e=a),'';case"numbers":return g}return r.toolbar?i(t(r.toolbar).html()||"").render(n):u(r,v,n)}(),"
    "].join("");o.push(m),r.fixed&&"right"!==r.fixed&&y.push(m),"right"===r.fixed&&p.push(m)}}),h.push(''+o.join("")+""),v.push(''+y.join("")+""),m.push(''+p.join("")+""))}),c.layBody.scrollTop(0),c.layMain.find("."+p).remove(),c.layMain.find("tbody").html(h.join("")),c.layFixLeft.find("tbody").html(v.join("")),c.layFixRight.find("tbody").html(m.join("")),c.renderForm(),"number"==typeof e&&c.setThisRowChecked(e),c.syncCheckAll(),c.haveInit?c.scrollPatch():setTimeout(function(){c.scrollPatch()},50),c.haveInit=!0,l.close(c.tipsIndex),s.HAS_SET_COLS_PATCH||c.setColsPatch(),void(s.HAS_SET_COLS_PATCH=!0))};return d.cache[c.key]=y,c.layPage[0==o||0===y.length&&1==n?"addClass":"removeClass"](f),r?g():0===y.length?(c.renderForm(),c.errorView(s.text.none)):(c.layFixed.removeClass(f),g(),c.renderTotal(y),void(s.page&&(s.page=t.extend({elem:"layui-table-page"+s.index,count:o,limit:s.limit,limits:s.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||(c.page=e.curr,s.limit=e.limit,c.pullData(e.curr))}},s.page),s.page.count=o,a.render(s.page))))},j.prototype.renderTotal=function(e){var t=this,i=t.config,a={};if(i.totalRow){layui.each(e,function(e,i){0!==i.length&&t.eachCols(function(e,t){var l=t.field||e,n=i[l];t.totalRow&&(a[l]=(a[l]||0)+(parseFloat(n)||0))})}),t.dataTotal={};var l=[];t.eachCols(function(e,n){var o=n.field||e,r=function(){var e=n.totalRowText||"",t=parseFloat(a[o]).toFixed(2),i={};return i[o]=t,t=u(n,t,i),n.totalRow?t||e:e}(),d=['','
    '+r,"
    "].join("");n.field&&(t.dataTotal[o]=r),l.push(d)}),t.layTotal.find("tbody").html(""+l.join("")+"")}},j.prototype.getColElem=function(e,t){var i=this,a=i.config;return e.eq(0).find(".laytable-cell-"+(a.index+"-"+t)+":eq(0)")},j.prototype.renderForm=function(e){n.render(e,"LAY-table-"+this.index)},j.prototype.setThisRowChecked=function(e){var t=this,i=(t.config,"layui-table-click"),a=t.layBody.find('tr[data-index="'+e+'"]');a.addClass(i).siblings("tr").removeClass(i)},j.prototype.sort=function(e,i,a,l){var n,r,c=this,s={},u=c.config,h=u.elem.attr("lay-filter"),f=d.cache[c.key];"string"==typeof e&&c.layHeader.find("th").each(function(i,a){var l=t(this),o=l.data("field");if(o===e)return e=l,n=o,!1});try{var n=n||e.data("field"),p=e.data("key");if(c.sortKey&&!a&&n===c.sortKey.field&&i===c.sortKey.sort)return;var v=c.layHeader.find("th .laytable-cell-"+p).find(S);c.layHeader.find("th").find(S).removeAttr("lay-sort"),v.attr("lay-sort",i||null),c.layFixed.find("th")}catch(m){return o.error("Table modules: Did not match to field")}c.sortKey={field:n,sort:i},u.autoSort&&("asc"===i?r=layui.sort(f,n):"desc"===i?r=layui.sort(f,n,!0):(r=layui.sort(f,d.config.indexName),delete c.sortKey)),s[u.response.dataName]=r||f,c.renderData(s,c.page,c.count,!0),l&&layui.event.call(e,y,"sort("+h+")",{field:n,type:i})},j.prototype.loading=function(e){var i=this,a=i.config;a.loading&&(e?(i.layInit&&i.layInit.remove(),delete i.layInit,i.layBox.find(b).remove()):(i.layInit=t(['
    ','',"
    "].join("")),i.layBox.append(i.layInit)))},j.prototype.setCheckData=function(e,t){var i=this,a=i.config,l=d.cache[i.key];l[e]&&l[e].constructor!==Array&&(l[e][a.checkName]=t)},j.prototype.syncCheckAll=function(){var e=this,t=e.config,i=e.layHeader.find('input[name="layTableCheckbox"]'),a=function(i){return e.eachCols(function(e,a){"checkbox"===a.type&&(a[t.checkName]=i)}),i};i[0]&&(d.checkStatus(e.key).isAll?(i[0].checked||(i.prop("checked",!0),e.renderForm("checkbox")),a(!0)):(i[0].checked&&(i.prop("checked",!1),e.renderForm("checkbox")),a(!1)))},j.prototype.getCssRule=function(e,t){var i=this,a=i.elem.find("style")[0],l=a.sheet||a.styleSheet||{},n=l.cssRules||l.rules;layui.each(n,function(i,a){if(a.selectorText===".laytable-cell-"+e)return t(a),!0})},j.prototype.fullSize=function(){var e,t=this,i=t.config,a=i.height;t.fullHeightGap&&(a=R.height()-t.fullHeightGap,a<135&&(a=135),t.elem.css("height",a)),a&&(e=parseFloat(a)-(t.layHeader.outerHeight()||38),i.toolbar&&(e-=t.layTool.outerHeight()||50),i.totalRow&&(e-=t.layTotal.outerHeight()||40),i.page&&(e-=t.layPage.outerHeight()||41),t.layMain.css("height",e-2))},j.prototype.getScrollWidth=function(e){var t=0;return e?t=e.offsetWidth-e.clientWidth:(e=document.createElement("div"),e.style.width="100px",e.style.height="100px",e.style.overflowY="scroll",document.body.appendChild(e),t=e.offsetWidth-e.clientWidth,document.body.removeChild(e)),t},j.prototype.scrollPatch=function(){var e=this,i=e.layMain.children("table"),a=e.layMain.width()-e.layMain.prop("clientWidth"),l=e.layMain.height()-e.layMain.prop("clientHeight"),n=(e.getScrollWidth(e.layMain[0]),i.outerWidth()-e.layMain.width()),o=function(e){if(a&&l){if(e=e.eq(0),!e.find(".layui-table-patch")[0]){var i=t('
    ');i.find("div").css({width:a}),e.find("tr").append(i)}}else e.find(".layui-table-patch").remove()};o(e.layHeader),o(e.layTotal);var r=e.layMain.height(),d=r-l;e.layFixed.find(k).css("height",i.height()>=d?d:"auto"),e.layFixRight[n>0?"removeClass":"addClass"](f),e.layFixRight.css("right",a-1)},j.prototype.events=function(){var e,i=this,a=i.config,o=t("body"),c={},s=i.layHeader.find("th"),h=".layui-table-cell",p=a.elem.attr("lay-filter");i.layTool.on("click","*[lay-event]",function(e){var o=t(this),c=o.attr("lay-event"),s=function(e){var l=t(e.list),n=t('
      ');n.html(l),a.height&&n.css("max-height",a.height-(i.layTool.outerHeight()||50)),o.find(".layui-table-tool-panel")[0]||o.append(n),i.renderForm(),n.on("click",function(e){layui.stope(e)}),e.done&&e.done(n,l)};switch(layui.stope(e),F.trigger("table.tool.panel.remove"),l.close(i.tipsIndex),c){case"LAYTABLE_COLS":s({list:function(){var e=[];return i.eachCols(function(t,i){i.field&&"normal"==i.type&&e.push('
    • ')}),e.join("")}(),done:function(){n.on("checkbox(LAY_TABLE_TOOL_COLS)",function(e){var l=t(e.elem),n=this.checked,o=l.data("key"),r=l.data("parentkey");layui.each(a.cols,function(e,t){layui.each(t,function(t,l){if(e+"-"+t===o){var d=l.hide;l.hide=!n,i.elem.find('*[data-key="'+a.index+"-"+o+'"]')[n?"removeClass":"addClass"](f),d!=l.hide&&i.setParentCol(!n,r),i.resize()}})})})}});break;case"LAYTABLE_EXPORT":r.ie?l.tips("导出功能不支持 IE,请用 Chrome 等高级浏览器导出",this,{tips:3}):s({list:function(){return['
    • 导出到 Csv 文件
    • ','
    • 导出到 Excel 文件
    • '].join("")}(),done:function(e,l){l.on("click",function(){var e=t(this).data("type");d.exportFile.call(i,a.id,null,e)})}});break;case"LAYTABLE_PRINT":var u=window.open("打印窗口","_blank"),h=[""].join(""),v=t(i.layHeader.html());v.append(i.layMain.find("table").html()),v.append(i.layTotal.find("table").html()),v.find("th.layui-table-patch").remove(),v.find(".layui-table-col-special").remove(),u.document.write(h+v.prop("outerHTML")),u.document.close(),u.print(),u.close()}layui.event.call(this,y,"toolbar("+p+")",t.extend({event:c,config:a},{}))}),s.on("mousemove",function(e){var i=t(this),a=i.offset().left,l=e.clientX-a;i.data("unresize")||c.resizeStart||(c.allowResize=i.width()-l<=10,o.css("cursor",c.allowResize?"col-resize":""))}).on("mouseleave",function(){t(this);c.resizeStart||o.css("cursor","")}).on("mousedown",function(e){var l=t(this);if(c.allowResize){var n=l.data("key");e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],i.getCssRule(n,function(e){var t=e.style.width||l.outerWidth();c.rule=e,c.ruleWidth=parseFloat(t),c.minWidth=l.data("minwidth")||a.cellMinWidth})}}),F.on("mousemove",function(t){if(c.resizeStart){if(t.preventDefault(),c.rule){var a=c.ruleWidth+t.clientX-c.offset[0];a');return n[0].value=i.data("content")||l.text(),i.find("."+W)[0]||i.append(n),n.focus(),void layui.stope(e)}}).on("mouseenter","td",function(){b.call(this)}).on("mouseleave","td",function(){b.call(this,"hide")});var g="layui-table-grid-down",b=function(e){var i=t(this),a=i.children(h);if(!i.data("off"))if(e)i.find(".layui-table-grid-down").remove();else if(a.prop("scrollWidth")>a.outerWidth()){if(a.find("."+g)[0])return;i.append('
      ')}};i.layBody.on("click","."+g,function(e){var n=t(this),o=n.parent(),d=o.children(h);i.tipsIndex=l.tips(['
      ',d.html(),"
      ",''].join(""),d[0],{tips:[3,""],time:-1,anim:-1,maxWidth:r.ios||r.android?300:i.elem.width()/2,isOutAnim:!1,skin:"layui-table-tips",success:function(e, t){e.find(".layui-table-tips-c").on("click",function(){l.close(t)})}}),layui.stope(e)}),i.layBody.on("click","*[lay-event]",function(){var e=t(this),a=e.parents("tr").eq(0).data("index");layui.event.call(this,y,"tool("+p+")",v.call(this,{event:e.attr("lay-event")})),i.setThisRowChecked(a)}),i.layMain.on("scroll",function(){var e=t(this),a=e.scrollLeft(),n=e.scrollTop();i.layHeader.scrollLeft(a),i.layTotal.scrollLeft(a),i.layFixed.find(k).scrollTop(n),l.close(i.tipsIndex)}),R.on("resize",function(){i.resize()})},function(){F.on("click",function(){F.trigger("table.remove.tool.panel")}),F.on("table.remove.tool.panel",function(){t(".layui-table-tool-panel").remove()})}(),d.init=function(e,i){i=i||{};var a=this,l=t(e?'table[lay-filter="'+e+'"]':h+"[lay-data]"),n="Table element property lay-data configuration item has a syntax error: ";return l.each(function(){var a=t(this),l=a.attr("lay-data");try{l=new Function("return "+l)()}catch(r){o.error(n+l)}var c=[],s=t.extend({elem:this,cols:[],data:[],skin:a.attr("lay-skin"),size:a.attr("lay-size"),even:"string"==typeof a.attr("lay-even")},d.config,i,l);e&&a.hide(),a.find("thead>tr").each(function(e){s.cols[e]=[],t(this).children().each(function(i){var a=t(this),l=a.attr("lay-data");try{l=new Function("return "+l)()}catch(r){return o.error(n+l)}var d=t.extend({title:a.text(),colspan:a.attr("colspan")||0,rowspan:a.attr("rowspan")||0},l);d.colspan<2&&c.push(d),s.cols[e].push(d)})}),a.find("tbody>tr").each(function(e){var i=t(this),a={};i.children("td").each(function(e,i){var l=t(this),n=l.data("field");if(n)return a[n]=l.html()}),layui.each(c,function(e,t){var l=i.children("td").eq(e);a[t.field]=l.html()}),s.data[e]=a}),d.render(s)}),a},c.that={},c.config={},d.eachCols=function(e,i,a){var l=c.config[e]||{},n=[],o=0;a=t.extend(!0,[],a||l.cols),layui.each(a,function(e,t){layui.each(t,function(t,i){if(i.colGroup){var l=0;o++,i.CHILD_COLS=[],layui.each(a[e+1],function(e,t){t.PARENT_COL_INDEX||l>1&&l==i.colspan||(t.PARENT_COL_INDEX=o,i.CHILD_COLS.push(t),l+=parseInt(t.colspan>1?t.colspan:1))})}i.PARENT_COL_INDEX||n.push(i)})});var r=function(e){layui.each(e||n,function(e,t){return t.CHILD_COLS?r(t.CHILD_COLS):void("function"==typeof i&&i(e,t))})};r()},d.checkStatus=function(e){var t=0,i=0,a=[],l=d.cache[e]||[];return layui.each(l,function(e,l){return l.constructor===Array?void i++:void(l[d.config.checkName]&&(t++,a.push(d.clearCacheKey(l))))}),{data:a,isAll:!!l.length&&t===l.length-i}},d.exportFile=function(e,t,i){var a=this;t=t||d.clearCacheKey(d.cache[e]),i=i||"csv";var l=c.config[e]||{},n={csv:"text/csv",xls:"application/vnd.ms-excel"}[i],s=document.createElement("a");return r.ie?o.error("IE_NOT_SUPPORT_EXPORTS"):(s.href="data:"+n+";charset=utf-8,\ufeff"+encodeURIComponent(function(){var i=[],l=[],n=[];return layui.each(t,function(t,a){var n=[];"object"==typeof e?(layui.each(e,function(e,a){0==t&&i.push(a||"")}),layui.each(d.clearCacheKey(a),function(e,t){n.push('"'+(t||"")+'"')})):d.eachCols(e,function(e,l){if(l.field&&"normal"==l.type&&!l.hide){var o=a[l.field];void 0!==o&&null!==o||(o=""),0==t&&i.push(l.title||""),n.push('"'+u(l,o,a,"text")+'"')}}),l.push(n.join(","))}),layui.each(a.dataTotal,function(e,t){n.push(t)}),i.join(",")+"\r\n"+l.join("\r\n")+"\r\n"+n.join(",")}()),s.download=(l.title||"table_"+(l.index||""))+"."+i,document.body.appendChild(s),s.click(),void document.body.removeChild(s))},d.resize=function(e){if(e){var t=s(e);if(!t)return;c.that[e].resize()}else layui.each(c.that,function(){this.resize()})},d.reload=function(e,t){var i=s(e);if(i){var a=c.that[e];return a.reload(t),c.call(a)}},d.render=function(e){var t=new j(e);return c.call(t)},d.clearCacheKey=function(e){return e=t.extend({},e),delete e[d.config.checkName],delete e[d.config.indexName],e},d.init(),e(y,d)}); \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/transfer.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/transfer.js" new file mode 100644 index 00000000..6b7b6777 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/transfer.js" @@ -0,0 +1,2 @@ +/** layui-v2.5.5 MIT License By https://www.layui.com */ + ;layui.define(["laytpl","form"],function(e){"use strict";var a=layui.$,t=layui.laytpl,n=layui.form,i="transfer",l={config:{},index:layui[i]?layui[i].index+1e4:0,set:function(e){var t=this;return t.config=a.extend({},t.config,e),t},on:function(e,a){return layui.onevent.call(this,i,e,a)}},r=function(){var e=this,a=e.config,t=a.id||e.index;return r.that[t]=e,r.config[t]=a,{config:a,reload:function(a){e.reload.call(e,a)},getData:function(){return e.getData.call(e)}}},c="layui-hide",o="layui-btn-disabled",d="layui-none",s="layui-transfer-box",u="layui-transfer-header",h="layui-transfer-search",f="layui-transfer-active",y="layui-transfer-data",p=function(e){return e=e||{},['
      ','
      ','","
      ","{{# if(d.data.showSearch){ }}",'","{{# } }}",'
        ',"
        "].join("")},v=['
        ',p({index:0,checkAllName:"layTransferLeftCheckAll"}),'
        ','",'","
        ",p({index:1,checkAllName:"layTransferRightCheckAll"}),"
        "].join(""),x=function(e){var t=this;t.index=++l.index,t.config=a.extend({},t.config,l.config,e),t.render()};x.prototype.config={title:["列表一","列表二"],width:200,height:360,data:[],value:[],showSearch:!1,id:"",text:{none:"无数据",searchNone:"无匹配数据"}},x.prototype.reload=function(e){var t=this;layui.each(e,function(e,a){a.constructor===Array&&delete t.config[e]}),t.config=a.extend(!0,{},t.config,e),t.render()},x.prototype.render=function(){var e=this,n=e.config,i=e.elem=a(t(v).render({data:n,index:e.index})),l=n.elem=a(n.elem);l[0]&&(n.data=n.data||[],n.value=n.value||[],e.key=n.id||e.index,l.html(e.elem),e.layBox=e.elem.find("."+s),e.layHeader=e.elem.find("."+u),e.laySearch=e.elem.find("."+h),e.layData=i.find("."+y),e.layBtn=i.find("."+f+" .layui-btn"),e.layBox.css({width:n.width,height:n.height}),e.layData.css({height:function(){return n.height-e.layHeader.outerHeight()-e.laySearch.outerHeight()-2}()}),e.renderData(),e.events())},x.prototype.renderData=function(){var e=this,a=(e.config,[{checkName:"layTransferLeftCheck",views:[]},{checkName:"layTransferRightCheck",views:[]}]);e.parseData(function(e){var t=e.selected?1:0,n=["
      • ",'',"
      • "].join("");a[t].views.push(n),delete e.selected}),e.layData.eq(0).html(a[0].views.join("")),e.layData.eq(1).html(a[1].views.join("")),e.renderCheckBtn()},x.prototype.renderForm=function(e){n.render(e,"LAY-transfer-"+this.index)},x.prototype.renderCheckBtn=function(e){var t=this,n=t.config;e=e||{},t.layBox.each(function(i){var l=a(this),r=l.find("."+y),d=l.find("."+u).find('input[type="checkbox"]'),s=r.find('input[type="checkbox"]'),h=0,f=!1;if(s.each(function(){var e=a(this).data("hide");(this.checked||this.disabled||e)&&h++,this.checked&&!e&&(f=!0)}),d.prop("checked",f&&h===s.length),t.layBtn.eq(i)[f?"removeClass":"addClass"](o),!e.stopNone){var p=r.children("li:not(."+c+")").length;t.noneView(r,p?"":n.text.none)}}),t.renderForm("checkbox")},x.prototype.noneView=function(e,t){var n=a('

        '+(t||"")+"

        ");e.find("."+d)[0]&&e.find("."+d).remove(),t.replace(/\s/g,"")&&e.append(n)},x.prototype.setValue=function(){var e=this,t=e.config,n=[];return e.layBox.eq(1).find("."+y+' input[type="checkbox"]').each(function(){var e=a(this).data("hide");e||n.push(this.value)}),t.value=n,e},x.prototype.parseData=function(e){var t=this,n=t.config,i=[];return layui.each(n.data,function(t,l){l=("function"==typeof n.parseData?n.parseData(l):l)||l,i.push(l=a.extend({},l)),layui.each(n.value,function(e,a){a==l.value&&(l.selected=!0)}),e&&e(l)}),n.data=i,t},x.prototype.getData=function(e){var a=this,t=a.config,n=[];return a.setValue(),layui.each(e||t.value,function(e,a){layui.each(t.data,function(e,t){delete t.selected,a==t.value&&n.push(t)})}),n},x.prototype.events=function(){var e=this,t=e.config;e.elem.on("click",'input[lay-filter="layTransferCheckbox"]+',function(){var t=a(this).prev(),n=t[0].checked,i=t.parents("."+s).eq(0).find("."+y);t[0].disabled||("all"===t.attr("lay-type")&&i.find('input[type="checkbox"]').each(function(){this.disabled||(this.checked=n)}),e.renderCheckBtn({stopNone:!0}))}),e.layBtn.on("click",function(){var n=a(this),i=n.data("index"),l=e.layBox.eq(i),r=[];if(!n.hasClass(o)){e.layBox.eq(i).each(function(t){var n=a(this),i=n.find("."+y);i.children("li").each(function(){var t=a(this),n=t.find('input[type="checkbox"]'),i=n.data("hide");n[0].checked&&!i&&(n[0].checked=!1,l.siblings("."+s).find("."+y).append(t.clone()),t.remove(),r.push(n[0].value)),e.setValue()})}),e.renderCheckBtn();var c=l.siblings("."+s).find("."+h+" input");""===c.val()||c.trigger("keyup"),t.onchange&&t.onchange(e.getData(r),i)}}),e.laySearch.find("input").on("keyup",function(){var n=this.value,i=a(this).parents("."+h).eq(0).siblings("."+y),l=i.children("li");l.each(function(){var e=a(this),t=e.find('input[type="checkbox"]'),i=t[0].title.indexOf(n)!==-1;e[i?"removeClass":"addClass"](c),t.data("hide",!i)}),e.renderCheckBtn();var r=l.length===i.children("li."+c).length;e.noneView(i,r?t.text.searchNone:"")})},r.that={},r.config={},l.reload=function(e,a){var t=r.that[e];return t.reload(a),r.call(t)},l.getData=function(e){var a=r.that[e];return a.getData()},l.render=function(e){var a=new x(e);return r.call(a)},e(i,l)}); \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/tree.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/tree.js" new file mode 100644 index 00000000..15fb294d --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/tree.js" @@ -0,0 +1,2 @@ +/** layui-v2.5.5 MIT License By https://www.layui.com */ + ;layui.define("form",function(e){"use strict";var i=layui.$,a=layui.form,n=layui.layer,t="tree",r={config:{},index:layui[t]?layui[t].index+1e4:0,set:function(e){var a=this;return a.config=i.extend({},a.config,e),a},on:function(e,i){return layui.onevent.call(this,t,e,i)}},l=function(){var e=this,i=e.config,a=i.id||e.index;return l.that[a]=e,l.config[a]=i,{config:i,reload:function(i){e.reload.call(e,i)},getChecked:function(){return e.getChecked.call(e)},setChecked:function(i){return e.setChecked.call(e,i)}}},c="layui-hide",d="layui-disabled",s="layui-tree-set",o="layui-tree-iconClick",h="layui-icon-addition",u="layui-icon-subtraction",p="layui-tree-entry",f="layui-tree-main",y="layui-tree-txt",v="layui-tree-pack",C="layui-tree-spread",k="layui-tree-setLineShort",m="layui-tree-showLine",x="layui-tree-lineExtend",b=function(e){var a=this;a.index=++r.index,a.config=i.extend({},a.config,r.config,e),a.render()};b.prototype.config={data:[],showCheckbox:!1,showLine:!0,accordion:!1,onlyIconControl:!1,isJump:!1,edit:!1,text:{defaultNodeName:"未命名",none:"无数据"}},b.prototype.reload=function(e){var a=this;layui.each(e,function(e,i){i.constructor===Array&&delete a.config[e]}),a.config=i.extend(!0,{},a.config,e),a.render()},b.prototype.render=function(){var e=this,a=e.config;e.checkids=[];var n=i('
        ');e.tree(n);var t=a.elem=i(a.elem);if(t[0]){if(e.key=a.id||e.index,e.elem=n,e.elemNone=i('
        '+a.text.none+"
        "),t.html(e.elem),0==e.elem.find(".layui-tree-set").length)return e.elem.append(e.elemNone);a.showCheckbox&&e.renderForm("checkbox"),e.elem.find(".layui-tree-set").each(function(){var e=i(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(k),e.next()[0]||e.parents(".layui-tree-set").eq(0).next()[0]||e.addClass(k)}),e.events()}},b.prototype.renderForm=function(e){a.render(e,"LAY-tree-"+this.index)},b.prototype.tree=function(e,a){var n=this,t=n.config,r=a||t.data;layui.each(r,function(a,r){var l=r.children&&r.children.length>0,o=i('
        '),h=i(['
        ','
        ','
        ',function(){return t.showLine?l?'':'':''}(),function(){return t.showCheckbox?'':""}(),function(){return t.isJump&&r.href?''+(r.title||r.label||t.text.defaultNodeName)+"":''+(r.title||r.label||t.text.defaultNodeName)+""}(),"
        ",function(){if(!t.edit)return"";var e={add:'',update:'',del:''},i=['
        '];return t.edit===!0&&(t.edit=["update","del"]),"object"==typeof t.edit?(layui.each(t.edit,function(a,n){i.push(e[n]||"")}),i.join("")+"
        "):void 0}(),"
        "].join(""));l&&(h.append(o),n.tree(o,r.children)),e.append(h),h.prev("."+s)[0]&&h.prev().children(".layui-tree-pack").addClass("layui-tree-showLine"),l||h.parent(".layui-tree-pack").addClass("layui-tree-lineExtend"),n.spread(h,r),t.showCheckbox&&(r.checked&&n.checkids.push(r.id),n.checkClick(h,r)),t.edit&&n.operate(h,r)})},b.prototype.spread=function(e,a){var n=this,t=n.config,r=e.children("."+p),l=r.children("."+f),c=r.find("."+o),k=r.find("."+y),m=t.onlyIconControl?c:l,x="";m.on("click",function(i){var a=e.children("."+v),n=m.children(".layui-icon")[0]?m.children(".layui-icon"):m.find(".layui-tree-icon").children(".layui-icon");if(a[0]){if(e.hasClass(C))e.removeClass(C),a.slideUp(200),n.removeClass(u).addClass(h);else if(e.addClass(C),a.slideDown(200),n.addClass(u).removeClass(h),t.accordion){var r=e.siblings("."+s);r.removeClass(C),r.children("."+v).slideUp(200),r.find(".layui-tree-icon").children(".layui-icon").removeClass(u).addClass(h)}}else x="normal"}),k.on("click",function(){var n=i(this);n.hasClass(d)||(x=e.hasClass(C)?t.onlyIconControl?"open":"close":t.onlyIconControl?"close":"open",t.click&&t.click({elem:e,state:x,data:a}))})},b.prototype.setCheckbox=function(e,i,a){var n=this,t=(n.config,a.prop("checked"));if(!a.prop("disabled")){if("object"==typeof i.children||e.find("."+v)[0]){var r=e.find("."+v).find('input[same="layuiTreeCheck"]');r.each(function(){this.disabled||(this.checked=t)})}var l=function(e){if(e.parents("."+s)[0]){var i,a=e.parent("."+v),n=a.parent(),r=a.prev().find('input[same="layuiTreeCheck"]');t?r.prop("checked",t):(a.find('input[same="layuiTreeCheck"]').each(function(){this.checked&&(i=!0)}),i||r.prop("checked",!1)),l(n)}};l(e),n.renderForm("checkbox")}},b.prototype.checkClick=function(e,a){var n=this,t=n.config,r=e.children("."+p),l=r.children("."+f);l.on("click",'input[same="layuiTreeCheck"]+',function(r){layui.stope(r);var l=i(this).prev(),c=l.prop("checked");l.prop("disabled")||(n.setCheckbox(e,a,l),t.oncheck&&t.oncheck({elem:e,checked:c,data:a}))})},b.prototype.operate=function(e,a){var t=this,r=t.config,l=e.children("."+p),d=l.children("."+f);l.children(".layui-tree-btnGroup").on("click",".layui-icon",function(l){layui.stope(l);var f=i(this).data("type"),b=e.children("."+v),g={data:a,type:f,elem:e};if("add"==f){b[0]||(r.showLine?(d.find("."+o).addClass("layui-tree-icon"),d.find("."+o).children(".layui-icon").addClass(h).removeClass("layui-icon-file")):d.find(".layui-tree-iconArrow").removeClass(c),e.append('
        '));var w=r.operate&&r.operate(g),N={};if(N.title=r.text.defaultNodeName,N.id=w,t.tree(e.children("."+v),[N]),r.showLine)if(b[0])b.hasClass(x)||b.addClass(x),e.find("."+v).each(function(){i(this).children("."+s).last().addClass(k)}),b.children("."+s).last().prev().hasClass(k)?b.children("."+s).last().prev().removeClass(k):b.children("."+s).last().removeClass(k),!e.parent("."+v)[0]&&e.next()[0]&&b.children("."+s).last().removeClass(k);else{var T=e.siblings("."+s),L=1,A=e.parent("."+v);layui.each(T,function(e,a){i(a).children("."+v)[0]||(L=0)}),1==L?(T.children("."+v).addClass(m),T.children("."+v).children("."+s).removeClass(k),e.children("."+v).addClass(m),A.removeClass(x),A.children("."+s).last().children("."+v).children("."+s).last().addClass(k)):e.children("."+v).children("."+s).addClass(k)}if(!r.showCheckbox)return;if(d.find('input[same="layuiTreeCheck"]')[0].checked){var I=e.children("."+v).children("."+s).last();I.find('input[same="layuiTreeCheck"]')[0].checked=!0}t.renderForm("checkbox")}else if("update"==f){var F=d.children("."+y).html();d.children("."+y).html(""),d.append(''),d.children(".layui-tree-editInput").val(F).focus();var j=function(e){var i=e.val().trim();i=i?i:r.text.defaultNodeName,e.remove(),d.children("."+y).html(i),g.data.title=i,r.operate&&r.operate(g)};d.children(".layui-tree-editInput").blur(function(){j(i(this))}),d.children(".layui-tree-editInput").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),j(i(this)))})}else n.confirm('确认删除该节点 "'+(a.title||"")+'" 吗?',function(a){if(r.operate&&r.operate(g),g.status="remove",n.close(a),!e.prev("."+s)[0]&&!e.next("."+s)[0]&&!e.parent("."+v)[0])return e.remove(),void t.elem.append(t.elemNone);if(e.siblings("."+s).children("."+p)[0]){if(r.showCheckbox){var l=function(e){if(e.parents("."+s)[0]){var a=e.siblings("."+s).children("."+p),n=e.parent("."+v).prev(),r=n.find('input[same="layuiTreeCheck"]')[0],c=1,d=0;0==r.checked&&(a.each(function(e,a){var n=i(a).find('input[same="layuiTreeCheck"]')[0];0!=n.checked||n.disabled||(c=0),n.disabled||(d=1)}),1==c&&1==d&&(r.checked=!0,t.renderForm("checkbox"),l(n.parent("."+s))))}};l(e)}if(r.showLine){var d=e.siblings("."+s),h=1,f=e.parent("."+v);layui.each(d,function(e,a){i(a).children("."+v)[0]||(h=0)}),1==h?(b[0]||(f.removeClass(x),d.children("."+v).addClass(m),d.children("."+v).children("."+s).removeClass(k)),e.next()[0]?f.children("."+s).last().children("."+v).children("."+s).last().addClass(k):e.prev().children("."+v).children("."+s).last().addClass(k),e.next()[0]||e.parents("."+s)[1]||e.parents("."+s).eq(0).next()[0]||e.prev("."+s).addClass(k)):!e.next()[0]&&e.hasClass(k)&&e.prev().addClass(k)}}else{var y=e.parent("."+v).prev();if(r.showLine){y.find("."+o).removeClass("layui-tree-icon"),y.find("."+o).children(".layui-icon").removeClass(u).addClass("layui-icon-file");var w=y.parents("."+v).eq(0);w.addClass(x),w.children("."+s).each(function(){i(this).children("."+v).children("."+s).last().addClass(k)})}else y.find(".layui-tree-iconArrow").addClass(c);e.parents("."+s).eq(0).removeClass(C),e.parent("."+v).remove()}e.remove()})})},b.prototype.events=function(){var e=this,a=e.config;e.elem.find(".layui-tree-checkedFirst");e.setChecked(e.checkids),e.elem.find(".layui-tree-search").on("keyup",function(){var n=i(this),t=n.val(),r=n.nextAll(),l=[];r.find("."+y).each(function(){var e=i(this).parents("."+p);if(i(this).html().indexOf(t)!=-1){l.push(i(this).parent());var a=function(e){e.addClass("layui-tree-searchShow"),e.parent("."+v)[0]&&a(e.parent("."+v).parent("."+s))};a(e.parent("."+s))}}),r.find("."+p).each(function(){var e=i(this).parent("."+s);e.hasClass("layui-tree-searchShow")||e.addClass(c)}),0==r.find(".layui-tree-searchShow").length&&e.elem.append(e.elemNone),a.onsearch&&a.onsearch({elem:l})}),e.elem.find(".layui-tree-search").on("keydown",function(){i(this).nextAll().find("."+p).each(function(){var e=i(this).parent("."+s);e.removeClass("layui-tree-searchShow "+c)}),i(".layui-tree-emptyText")[0]&&i(".layui-tree-emptyText").remove()})},b.prototype.getChecked=function(){var e=this,a=e.config,n=[],t=[];e.elem.find(".layui-form-checked").each(function(){n.push(i(this).prev()[0].value)});var r=function(e,a){layui.each(e,function(e,t){layui.each(n,function(e,n){if(t.id==n){var l=i.extend({},t);return delete l.children,a.push(l),t.children&&(l.children=[],r(t.children,l.children)),!0}})})};return r(i.extend({},a.data),t),t},b.prototype.setChecked=function(e){var a=this;a.config;a.elem.find("."+s).each(function(a,n){var t=i(this).data("id"),r=i(n).children("."+p).find('input[same="layuiTreeCheck"]'),l=r.next();if("number"==typeof e){if(t==e)return r[0].checked||l.click(),!1}else"object"==typeof e&&layui.each(e,function(e,i){if(i==t&&!r[0].checked)return l.click(),!0})})},l.that={},l.config={},r.reload=function(e,i){var a=l.that[e];return a.reload(i),l.call(a)},r.getChecked=function(e){var i=l.that[e];return i.getChecked()},r.setChecked=function(e,i){var a=l.that[e];return a.setChecked(i)},r.render=function(e){var i=new b(e);return l.call(i)},e(t,r)}); \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/upload.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/upload.js" new file mode 100644 index 00000000..262b5130 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/upload.js" @@ -0,0 +1,2 @@ +/** layui-v2.5.5 MIT License By https://www.layui.com */ + ;layui.define("layer",function(e){"use strict";var t=layui.$,i=layui.layer,n=layui.hint(),o=layui.device(),a={config:{},set:function(e){var i=this;return i.config=t.extend({},i.config,e),i},on:function(e,t){return layui.onevent.call(this,r,e,t)}},l=function(){var e=this;return{upload:function(t){e.upload.call(e,t)},reload:function(t){e.reload.call(e,t)},config:e.config}},r="upload",u="layui-upload-file",c="layui-upload-form",f="layui-upload-iframe",s="layui-upload-choose",p=function(e){var i=this;i.config=t.extend({},i.config,a.config,e),i.render()};p.prototype.config={accept:"images",exts:"",auto:!0,bindAction:"",url:"",field:"file",acceptMime:"",method:"post",data:{},drag:!0,size:0,number:0,multiple:!1},p.prototype.render=function(e){var i=this,e=i.config;e.elem=t(e.elem),e.bindAction=t(e.bindAction),i.file(),i.events()},p.prototype.file=function(){var e=this,i=e.config,n=e.elemFile=t(['"].join("")),a=i.elem.next();(a.hasClass(u)||a.hasClass(c))&&a.remove(),o.ie&&o.ie<10&&i.elem.wrap('
        '),e.isFile()?(e.elemFile=i.elem,i.field=i.elem[0].name):i.elem.after(n),o.ie&&o.ie<10&&e.initIE()},p.prototype.initIE=function(){var e=this,i=e.config,n=t(''),o=t(['
        ',"
        "].join(""));t("#"+f)[0]||t("body").append(n),i.elem.next().hasClass(c)||(e.elemFile.wrap(o),i.elem.next("."+c).append(function(){var e=[];return layui.each(i.data,function(t,i){i="function"==typeof i?i():i,e.push('')}),e.join("")}()))},p.prototype.msg=function(e){return i.msg(e,{icon:2,shift:6})},p.prototype.isFile=function(){var e=this.config.elem[0];if(e)return"input"===e.tagName.toLocaleLowerCase()&&"file"===e.type},p.prototype.preview=function(e){var t=this;window.FileReader&&layui.each(t.chooseFiles,function(t,i){var n=new FileReader;n.readAsDataURL(i),n.onload=function(){e&&e(t,i,this.result)}})},p.prototype.upload=function(e,i){var n,a=this,l=a.config,r=a.elemFile[0],u=function(){var i=0,n=0,o=e||a.files||a.chooseFiles||r.files,u=function(){l.multiple&&i+n===a.fileLength&&"function"==typeof l.allDone&&l.allDone({total:a.fileLength,successful:i,aborted:n})};layui.each(o,function(e,o){var r=new FormData;r.append(l.field,o),layui.each(l.data,function(e,t){t="function"==typeof t?t():t,r.append(e,t)}),t.ajax({url:l.url,type:"post",data:r,contentType:!1,processData:!1,dataType:"json",headers:l.headers||{},success:function(t){i++,d(e,t),u()},error:function(){n++,a.msg("请求上传接口出现异常"),m(e),u()},xhr:function(){var e=new XMLHttpRequest;return e.upload.addEventListener("progress",function(e){if(e.lengthComputable){var t=Math.floor(e.loaded/e.total*100);"function"==typeof l.progress&&l.progress(t,e)}}),e}})})},c=function(){var e=t("#"+f);a.elemFile.parent().submit(),clearInterval(p.timer),p.timer=setInterval(function(){var t,i=e.contents().find("body");try{t=i.text()}catch(n){a.msg("获取上传后的响应信息出现异常"),clearInterval(p.timer),m()}t&&(clearInterval(p.timer),i.html(""),d(0,t))},30)},d=function(e,t){if(a.elemFile.next("."+s).remove(),r.value="","object"!=typeof t)try{t=JSON.parse(t)}catch(i){return t={},a.msg("请对上传接口返回有效JSON")}"function"==typeof l.done&&l.done(t,e||0,function(e){a.upload(e)})},m=function(e){l.auto&&(r.value=""),"function"==typeof l.error&&l.error(e||0,function(e){a.upload(e)})},h=l.exts,v=function(){var t=[];return layui.each(e||a.chooseFiles,function(e,i){t.push(i.name)}),t}(),g={preview:function(e){a.preview(e)},upload:function(e,t){var i={};i[e]=t,a.upload(i)},pushFile:function(){return a.files=a.files||{},layui.each(a.chooseFiles,function(e,t){a.files[e]=t}),a.files},resetFile:function(e,t,i){var n=new File([t],i);a.files=a.files||{},a.files[e]=n}},y=function(){if("choose"!==i&&!l.auto||(l.choose&&l.choose(g),"choose"!==i))return l.before&&l.before(g),o.ie?o.ie>9?u():c():void u()};if(v=0===v.length?r.value.match(/[^\/\\]+\..+/g)||[]||"":v,0!==v.length){switch(l.accept){case"file":if(h&&!RegExp("\\w\\.("+h+")$","i").test(escape(v)))return a.msg("选择的文件中包含不支持的格式"),r.value="";break;case"video":if(!RegExp("\\w\\.("+(h||"avi|mp4|wma|rmvb|rm|flash|3gp|flv")+")$","i").test(escape(v)))return a.msg("选择的视频中包含不支持的格式"),r.value="";break;case"audio":if(!RegExp("\\w\\.("+(h||"mp3|wav|mid")+")$","i").test(escape(v)))return a.msg("选择的音频中包含不支持的格式"),r.value="";break;default:if(layui.each(v,function(e,t){RegExp("\\w\\.("+(h||"jpg|png|gif|bmp|jpeg$")+")","i").test(escape(t))||(n=!0)}),n)return a.msg("选择的图片中包含不支持的格式"),r.value=""}if(a.fileLength=function(){var t=0,i=e||a.files||a.chooseFiles||r.files;return layui.each(i,function(){t++}),t}(),l.number&&a.fileLength>l.number)return a.msg("同时最多只能上传的数量为:"+l.number);if(l.size>0&&!(o.ie&&o.ie<10)){var F;if(layui.each(a.chooseFiles,function(e,t){if(t.size>1024*l.size){var i=l.size/1024;i=i>=1?i.toFixed(2)+"MB":l.size+"KB",r.value="",F=i}}),F)return a.msg("文件不能超过"+F)}y()}},p.prototype.reload=function(e){e=e||{},delete e.elem,delete e.bindAction;var i=this,e=i.config=t.extend({},i.config,a.config,e),n=e.elem.next();n.attr({name:e.name,accept:e.acceptMime,multiple:e.multiple})},p.prototype.events=function(){var e=this,i=e.config,a=function(t){e.chooseFiles={},layui.each(t,function(t,i){var n=(new Date).getTime();e.chooseFiles[n+"-"+t]=i})},l=function(t,n){var o=e.elemFile,a=t.length>1?t.length+"个文件":(t[0]||{}).name||o[0].value.match(/[^\/\\]+\..+/g)||[]||"";o.next().hasClass(s)&&o.next().remove(),e.upload(null,"choose"),e.isFile()||i.choose||o.after(''+a+"")};i.elem.off("upload.start").on("upload.start",function(){var o=t(this),a=o.attr("lay-data");if(a)try{a=new Function("return "+a)(),e.config=t.extend({},i,a)}catch(l){n.error("Upload element property lay-data configuration item has a syntax error: "+a)}e.config.item=o,e.elemFile[0].click()}),o.ie&&o.ie<10||i.elem.off("upload.over").on("upload.over",function(){var e=t(this);e.attr("lay-over","")}).off("upload.leave").on("upload.leave",function(){var e=t(this);e.removeAttr("lay-over")}).off("upload.drop").on("upload.drop",function(n,o){var r=t(this),u=o.originalEvent.dataTransfer.files||[];r.removeAttr("lay-over"),a(u),i.auto?e.upload(u):l(u)}),e.elemFile.off("upload.change").on("upload.change",function(){var t=this.files||[];a(t),i.auto?e.upload():l(t)}),i.bindAction.off("upload.action").on("upload.action",function(){e.upload()}),i.elem.data("haveEvents")||(e.elemFile.on("change",function(){t(this).trigger("upload.change")}),i.elem.on("click",function(){e.isFile()||t(this).trigger("upload.start")}),i.drag&&i.elem.on("dragover",function(e){e.preventDefault(),t(this).trigger("upload.over")}).on("dragleave",function(e){t(this).trigger("upload.leave")}).on("drop",function(e){e.preventDefault(),t(this).trigger("upload.drop",e)}),i.bindAction.on("click",function(){t(this).trigger("upload.action")}),i.elem.data("haveEvents",!0))},a.render=function(e){var t=new p(e);return l.call(t)},e(r,a)}); \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/util.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/util.js" new file mode 100644 index 00000000..256f47aa --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/lay/modules/util.js" @@ -0,0 +1,2 @@ +/** layui-v2.5.5 MIT License By https://www.layui.com */ + ;layui.define("jquery",function(t){"use strict";var e=layui.$,i={fixbar:function(t){var i,n,a="layui-fixbar",o="layui-fixbar-top",r=e(document),l=e("body");t=e.extend({showHeight:200},t),t.bar1=t.bar1===!0?"":t.bar1,t.bar2=t.bar2===!0?"":t.bar2,t.bgcolor=t.bgcolor?"background-color:"+t.bgcolor:"";var c=[t.bar1,t.bar2,""],g=e(['
          ',t.bar1?'
        • '+c[0]+"
        • ":"",t.bar2?'
        • '+c[1]+"
        • ":"",'
        • '+c[2]+"
        • ","
        "].join("")),s=g.find("."+o),u=function(){var e=r.scrollTop();e>=t.showHeight?i||(s.show(),i=1):i&&(s.hide(),i=0)};e("."+a)[0]||("object"==typeof t.css&&g.css(t.css),l.append(g),u(),g.find("li").on("click",function(){var i=e(this),n=i.attr("lay-type");"top"===n&&e("html,body").animate({scrollTop:0},200),t.click&&t.click.call(this,n)}),r.on("scroll",function(){clearTimeout(n),n=setTimeout(function(){u()},100)}))},countdown:function(t,e,i){var n=this,a="function"==typeof e,o=new Date(t).getTime(),r=new Date(!e||a?(new Date).getTime():e).getTime(),l=o-r,c=[Math.floor(l/864e5),Math.floor(l/36e5)%24,Math.floor(l/6e4)%60,Math.floor(l/1e3)%60];a&&(i=e);var g=setTimeout(function(){n.countdown(t,r+1e3,i)},1e3);return i&&i(l>0?c:[0,0,0,0],e,g),l<=0&&clearTimeout(g),g},timeAgo:function(t,e){var i=this,n=[[],[]],a=(new Date).getTime()-new Date(t).getTime();return a>6912e5?(a=new Date(t),n[0][0]=i.digit(a.getFullYear(),4),n[0][1]=i.digit(a.getMonth()+1),n[0][2]=i.digit(a.getDate()),e||(n[1][0]=i.digit(a.getHours()),n[1][1]=i.digit(a.getMinutes()),n[1][2]=i.digit(a.getSeconds())),n[0].join("-")+" "+n[1].join(":")):a>=864e5?(a/1e3/60/60/24|0)+"天前":a>=36e5?(a/1e3/60/60|0)+"小时前":a>=12e4?(a/1e3/60|0)+"分钟前":a<0?"未来":"刚刚"},digit:function(t,e){var i="";t=String(t),e=e||2;for(var n=t.length;n/g,">").replace(/'/g,"'").replace(/"/g,""")},event:function(t,n,a){n=i.event[t]=e.extend(!0,i.event[t],n)||{},e("body").on(a||"click","*["+t+"]",function(){var i=e(this),a=i.attr(t);n[a]&&n[a].call(this,i)})}};!function(t,e,i){"$:nomunge";function n(){a=e[l](function(){o.each(function(){var e=t(this),i=e.width(),n=e.height(),a=t.data(this,g);(i!==a.w||n!==a.h)&&e.trigger(c,[a.w=i,a.h=n])}),n()},r[s])}var a,o=t([]),r=t.resize=t.extend(t.resize,{}),l="setTimeout",c="resize",g=c+"-special-event",s="delay",u="throttleWindow";r[s]=250,r[u]=!0,t.event.special[c]={setup:function(){if(!r[u]&&this[l])return!1;var e=t(this);o=o.add(e),t.data(this,g,{w:e.width(),h:e.height()}),1===o.length&&n()},teardown:function(){if(!r[u]&&this[l])return!1;var e=t(this);o=o.not(e),e.removeData(g),o.length||clearTimeout(a)},add:function(e){function n(e,n,o){var r=t(this),l=t.data(this,g)||{};l.w=n!==i?n:r.width(),l.h=o!==i?o:r.height(),a.apply(this,arguments)}if(!r[u]&&this[l])return!1;var a;return t.isFunction(e)?(a=e,n):(a=e.handler,void(e.handler=n))}}}(e,window),t("util",i)}); \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/layui.all.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/layui.all.js" new file mode 100644 index 00000000..7d2fafaa --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/layui.all.js" @@ -0,0 +1,5 @@ +/** layui-v2.5.5 MIT License By https://www.layui.com */ + ;!function(e){"use strict";var t=document,o={modules:{},status:{},timeout:10,event:{}},n=function(){this.v="2.5.5"},r=function(){var e=t.currentScript?t.currentScript.src:function(){for(var e,o=t.scripts,n=o.length-1,r=n;r>0;r--)if("interactive"===o[r].readyState){e=o[r].src;break}return e||o[n].src}();return e.substring(0,e.lastIndexOf("/")+1)}(),i=function(t){e.console&&console.error&&console.error("Layui hint: "+t)},a="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),u={layer:"modules/layer",laydate:"modules/laydate",laypage:"modules/laypage",laytpl:"modules/laytpl",layim:"modules/layim",layedit:"modules/layedit",form:"modules/form",upload:"modules/upload",transfer:"modules/transfer",tree:"modules/tree",table:"modules/table",element:"modules/element",rate:"modules/rate",colorpicker:"modules/colorpicker",slider:"modules/slider",carousel:"modules/carousel",flow:"modules/flow",util:"modules/util",code:"modules/code",jquery:"modules/jquery",mobile:"modules/mobile","layui.all":"../layui.all"};n.prototype.cache=o,n.prototype.define=function(e,t){var n=this,r="function"==typeof e,i=function(){var e=function(e,t){layui[e]=t,o.status[e]=!0};return"function"==typeof t&&t(function(n,r){e(n,r),o.callback[n]=function(){t(e)}}),this};return r&&(t=e,e=[]),!layui["layui.all"]&&layui["layui.mobile"]?i.call(n):(n.use(e,i),n)},n.prototype.use=function(e,n,l){function s(e,t){var n="PLaySTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/;("load"===e.type||n.test((e.currentTarget||e.srcElement).readyState))&&(o.modules[f]=t,d.removeChild(v),function r(){return++m>1e3*o.timeout/4?i(f+" is not a valid module"):void(o.status[f]?c():setTimeout(r,4))}())}function c(){l.push(layui[f]),e.length>1?y.use(e.slice(1),n,l):"function"==typeof n&&n.apply(layui,l)}var y=this,p=o.dir=o.dir?o.dir:r,d=t.getElementsByTagName("head")[0];e="string"==typeof e?[e]:e,window.jQuery&&jQuery.fn.on&&(y.each(e,function(t,o){"jquery"===o&&e.splice(t,1)}),layui.jquery=layui.$=jQuery);var f=e[0],m=0;if(l=l||[],o.host=o.host||(p.match(/\/\/([\s\S]+?)\//)||["//"+location.host+"/"])[0],0===e.length||layui["layui.all"]&&u[f]||!layui["layui.all"]&&layui["layui.mobile"]&&u[f])return c(),y;if(o.modules[f])!function g(){return++m>1e3*o.timeout/4?i(f+" is not a valid module"):void("string"==typeof o.modules[f]&&o.status[f]?c():setTimeout(g,4))}();else{var v=t.createElement("script"),h=(u[f]?p+"lay/":/^\{\/\}/.test(y.modules[f])?"":o.base||"")+(y.modules[f]||f)+".js";h=h.replace(/^\{\/\}/,""),v.async=!0,v.charset="utf-8",v.src=h+function(){var e=o.version===!0?o.v||(new Date).getTime():o.version||"";return e?"?v="+e:""}(),d.appendChild(v),!v.attachEvent||v.attachEvent.toString&&v.attachEvent.toString().indexOf("[native code")<0||a?v.addEventListener("load",function(e){s(e,h)},!1):v.attachEvent("onreadystatechange",function(e){s(e,h)}),o.modules[f]=h}return y},n.prototype.getStyle=function(t,o){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](o)},n.prototype.link=function(e,n,r){var a=this,u=t.createElement("link"),l=t.getElementsByTagName("head")[0];"string"==typeof n&&(r=n);var s=(r||e).replace(/\.|\//g,""),c=u.id="layuicss-"+s,y=0;return u.rel="stylesheet",u.href=e+(o.debug?"?v="+(new Date).getTime():""),u.media="all",t.getElementById(c)||l.appendChild(u),"function"!=typeof n?a:(function p(){return++y>1e3*o.timeout/100?i(e+" timeout"):void(1989===parseInt(a.getStyle(t.getElementById(c),"width"))?function(){n()}():setTimeout(p,100))}(),a)},o.callback={},n.prototype.factory=function(e){if(layui[e])return"function"==typeof o.callback[e]?o.callback[e]:null},n.prototype.addcss=function(e,t,n){return layui.link(o.dir+"css/"+e,t,n)},n.prototype.img=function(e,t,o){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,"function"==typeof t&&t(n)},void(n.onerror=function(e){n.onerror=null,"function"==typeof o&&o(e)}))},n.prototype.config=function(e){e=e||{};for(var t in e)o[t]=e[t];return this},n.prototype.modules=function(){var e={};for(var t in u)e[t]=u[t];return e}(),n.prototype.extend=function(e){var t=this;e=e||{};for(var o in e)t[o]||t.modules[o]?i("模块名 "+o+" 已被占用"):t.modules[o]=e[o];return t},n.prototype.router=function(e){var t=this,e=e||location.hash,o={path:[],search:{},hash:(e.match(/[^#](#.*$)/)||[])[1]||""};return/^#\//.test(e)?(e=e.replace(/^#\//,""),o.href="/"+e,e=e.replace(/([^#])(#.*$)/,"$1").split("/")||[],t.each(e,function(e,t){/^\w+=/.test(t)?function(){t=t.split("="),o.search[t[0]]=t[1]}():o.path.push(t)}),o):o},n.prototype.data=function(t,o,n){if(t=t||"layui",n=n||localStorage,e.JSON&&e.JSON.parse){if(null===o)return delete n[t];o="object"==typeof o?o:{key:o};try{var r=JSON.parse(n[t])}catch(i){var r={}}return"value"in o&&(r[o.key]=o.value),o.remove&&delete r[o.key],n[t]=JSON.stringify(r),o.key?r[o.key]:r}},n.prototype.sessionData=function(e,t){return this.data(e,t,sessionStorage)},n.prototype.device=function(t){var o=navigator.userAgent.toLowerCase(),n=function(e){var t=new RegExp(e+"/([^\\s\\_\\-]+)");return e=(o.match(t)||[])[1],e||!1},r={os:function(){return/windows/.test(o)?"windows":/linux/.test(o)?"linux":/iphone|ipod|ipad|ios/.test(o)?"ios":/mac/.test(o)?"mac":void 0}(),ie:function(){return!!(e.ActiveXObject||"ActiveXObject"in e)&&((o.match(/msie\s(\d+)/)||[])[1]||"11")}(),weixin:n("micromessenger")};return t&&!r[t]&&(r[t]=n(t)),r.android=/android/.test(o),r.ios="ios"===r.os,r},n.prototype.hint=function(){return{error:i}},n.prototype.each=function(e,t){var o,n=this;if("function"!=typeof t)return n;if(e=e||[],e.constructor===Object){for(o in e)if(t.call(e[o],o,e[o]))break}else for(o=0;oi?1:r/g,">").replace(/'/g,"'").replace(/"/g,""")},error:function(e,r){var c="Laytpl Error:";return"object"==typeof console&&console.error(c+e+"\n"+(r||"")),c+e}},n=c.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=n("^"+r.open+"#",""),l=n(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(n(r.open+"#"),r.open+"# ").replace(n(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(n(r.open+"!(.+?)!"+r.close),function(e){return e=e.replace(n("^"+r.open+"!"),"").replace(n("!"+r.close),"").replace(n(r.open+"|"+r.close),function(e){return e.replace(/(.)/g,"\\$1")})}).replace(/(?="|')/g,"\\").replace(c.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(c.query(1),function(e){var c='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(n(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),c='"+_escape_('),c+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,c.escape)}catch(u){return delete o.cache,c.error(u,p)}},t.pt.render=function(e,r){var n,t=this;return e?(n=t.cache?t.cache(e,c.escape):t.parse(t.tpl,e),r?void r(n):n):c.error("no data")};var o=function(e){return"string"!=typeof e?c.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var c in e)r[c]=e[c]},o.v="1.2.0",e("laytpl",o)});layui.define(function(e){"use strict";var a=document,t="getElementById",n="getElementsByTagName",i="laypage",r="layui-disabled",u=function(e){var a=this;a.config=e||{},a.config.index=++s.index,a.render(!0)};u.prototype.type=function(){var e=this.config;if("object"==typeof e.elem)return void 0===e.elem.length?2:3},u.prototype.view=function(){var e=this,a=e.config,t=a.groups="groups"in a?0|a.groups:5;a.layout="object"==typeof a.layout?a.layout:["prev","page","next"],a.count=0|a.count,a.curr=0|a.curr||1,a.limits="object"==typeof a.limits?a.limits:[10,20,30,40,50],a.limit=0|a.limit||10,a.pages=Math.ceil(a.count/a.limit)||1,a.curr>a.pages&&(a.curr=a.pages),t<0?t=1:t>a.pages&&(t=a.pages),a.prev="prev"in a?a.prev:"上一页",a.next="next"in a?a.next:"下一页";var n=a.pages>t?Math.ceil((a.curr+(t>1?1:0))/(t>0?t:1)):1,i={prev:function(){return a.prev?''+a.prev+"":""}(),page:function(){var e=[];if(a.count<1)return"";n>1&&a.first!==!1&&0!==t&&e.push(''+(a.first||1)+"");var i=Math.floor((t-1)/2),r=n>1?a.curr-i:1,u=n>1?function(){var e=a.curr+(t-i-1);return e>a.pages?a.pages:e}():t;for(u-r2&&e.push('');r<=u;r++)r===a.curr?e.push('"+r+""):e.push(''+r+"");return a.pages>t&&a.pages>u&&a.last!==!1&&(u+1…'),0!==t&&e.push(''+(a.last||a.pages)+"")),e.join("")}(),next:function(){return a.next?''+a.next+"":""}(),count:'共 '+a.count+" 条",limit:function(){var e=['"}(),refresh:['','',""].join(""),skip:function(){return['到第','','页',""].join("")}()};return['
        ',function(){var e=[];return layui.each(a.layout,function(a,t){i[t]&&e.push(i[t])}),e.join("")}(),"
        "].join("")},u.prototype.jump=function(e,a){if(e){var t=this,i=t.config,r=e.children,u=e[n]("button")[0],l=e[n]("input")[0],p=e[n]("select")[0],c=function(){var e=0|l.value.replace(/\s|\D/g,"");e&&(i.curr=e,t.render())};if(a)return c();for(var o=0,y=r.length;oi.pages||(i.curr=e,t.render())});p&&s.on(p,"change",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),u&&s.on(u,"click",function(){c()})}},u.prototype.skip=function(e){if(e){var a=this,t=e[n]("input")[0];t&&s.on(t,"keyup",function(t){var n=this.value,i=t.keyCode;/^(37|38|39|40)$/.test(i)||(/\D/.test(n)&&(this.value=n.replace(/\D/,"")),13===i&&a.jump(e,!0))})}},u.prototype.render=function(e){var n=this,i=n.config,r=n.type(),u=n.view();2===r?i.elem&&(i.elem.innerHTML=u):3===r?i.elem.html(u):a[t](i.elem)&&(a[t](i.elem).innerHTML=u),i.jump&&i.jump(i,e);var s=a[t]("layui-laypage-"+i.index);n.jump(s),i.hash&&!e&&(location.hash="!"+i.hash+"="+i.curr),n.skip(s)};var s={render:function(e){var a=new u(e);return a.index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(e,a,t){return e.attachEvent?e.attachEvent("on"+a,function(a){a.target=a.srcElement,t.call(e,a)}):e.addEventListener(a,t,!1),this}};e(i,s)});!function(){"use strict";var e=window.layui&&layui.define,t={getPath:function(){var e=document.currentScript?document.currentScript.src:function(){for(var e,t=document.scripts,n=t.length-1,a=n;a>0;a--)if("interactive"===t[a].readyState){e=t[a].src;break}return e||t[n].src}();return e.substring(0,e.lastIndexOf("/")+1)}(),getStyle:function(e,t){var n=e.currentStyle?e.currentStyle:window.getComputedStyle(e,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](t)},link:function(e,a,i){if(n.path){var r=document.getElementsByTagName("head")[0],o=document.createElement("link");"string"==typeof a&&(i=a);var s=(i||e).replace(/\.|\//g,""),l="layuicss-"+s,d=0;o.rel="stylesheet",o.href=n.path+e,o.id=l,document.getElementById(l)||r.appendChild(o),"function"==typeof a&&!function c(){return++d>80?window.console&&console.error("laydate.css: Invalid"):void(1989===parseInt(t.getStyle(document.getElementById(l),"width"))?a():setTimeout(c,100))}()}}},n={v:"5.0.9",config:{},index:window.laydate&&window.laydate.v?1e5:0,path:t.getPath,set:function(e){var t=this;return t.config=w.extend({},t.config,e),t},ready:function(a){var i="laydate",r="",o=(e?"modules/laydate/":"theme/")+"default/laydate.css?v="+n.v+r;return e?layui.addcss(o,a,i):t.link(o,a,i),this}},a=function(){var e=this;return{hint:function(t){e.hint.call(e,t)},config:e.config}},i="laydate",r=".layui-laydate",o="layui-this",s="laydate-disabled",l="开始日期超出了结束日期
        建议重新选择",d=[100,2e5],c="layui-laydate-static",m="layui-laydate-list",u="laydate-selected",h="layui-laydate-hint",y="laydate-day-prev",f="laydate-day-next",p="layui-laydate-footer",g=".laydate-btns-confirm",v="laydate-time-text",D=".laydate-btns-time",T=function(e){var t=this;t.index=++n.index,t.config=w.extend({},t.config,n.config,e),n.ready(function(){t.init()})},w=function(e){return new C(e)},C=function(e){for(var t=0,n="object"==typeof e?[e]:(this.selector=e,document.querySelectorAll(e||null));t0)return n[0].getAttribute(e)}():n.each(function(n,a){a.setAttribute(e,t)})},C.prototype.removeAttr=function(e){return this.each(function(t,n){n.removeAttribute(e)})},C.prototype.html=function(e){return this.each(function(t,n){n.innerHTML=e})},C.prototype.val=function(e){return this.each(function(t,n){n.value=e})},C.prototype.append=function(e){return this.each(function(t,n){"object"==typeof e?n.appendChild(e):n.innerHTML=n.innerHTML+e})},C.prototype.remove=function(e){return this.each(function(t,n){e?n.removeChild(e):n.parentNode.removeChild(n)})},C.prototype.on=function(e,t){return this.each(function(n,a){a.attachEvent?a.attachEvent("on"+e,function(e){e.target=e.srcElement,t.call(a,e)}):a.addEventListener(e,t,!1)})},C.prototype.off=function(e,t){return this.each(function(n,a){a.detachEvent?a.detachEvent("on"+e,t):a.removeEventListener(e,t,!1)})},T.isLeapYear=function(e){return e%4===0&&e%100!==0||e%400===0},T.prototype.config={type:"date",range:!1,format:"yyyy-MM-dd",value:null,isInitValue:!0,min:"1900-1-1",max:"2099-12-31",trigger:"focus",show:!1,showBottom:!0,btns:["clear","now","confirm"],lang:"cn",theme:"default",position:null,calendar:!1,mark:{},zIndex:null,done:null,change:null},T.prototype.lang=function(){var e=this,t=e.config,n={cn:{weeks:["日","一","二","三","四","五","六"],time:["时","分","秒"],timeTips:"选择时间",startTime:"开始时间",endTime:"结束时间",dateTips:"返回日期",month:["一","二","三","四","五","六","七","八","九","十","十一","十二"],tools:{confirm:"确定",clear:"清空",now:"现在"}},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"}}};return n[t.lang]||n.cn},T.prototype.init=function(){var e=this,t=e.config,n="yyyy|y|MM|M|dd|d|HH|H|mm|m|ss|s",a="static"===t.position,i={year:"yyyy",month:"yyyy-MM",date:"yyyy-MM-dd",time:"HH:mm:ss",datetime:"yyyy-MM-dd HH:mm:ss"};t.elem=w(t.elem),t.eventElem=w(t.eventElem),t.elem[0]&&(t.range===!0&&(t.range="-"),t.format===i.date&&(t.format=i[t.type]),e.format=t.format.match(new RegExp(n+"|.","g"))||[],e.EXP_IF="",e.EXP_SPLIT="",w.each(e.format,function(t,a){var i=new RegExp(n).test(a)?"\\d{"+function(){return new RegExp(n).test(e.format[0===t?t+1:t-1]||"")?/^yyyy|y$/.test(a)?4:a.length:/^yyyy$/.test(a)?"1,4":/^y$/.test(a)?"1,308":"1,2"}()+"}":"\\"+a;e.EXP_IF=e.EXP_IF+i,e.EXP_SPLIT=e.EXP_SPLIT+"("+i+")"}),e.EXP_IF=new RegExp("^"+(t.range?e.EXP_IF+"\\s\\"+t.range+"\\s"+e.EXP_IF:e.EXP_IF)+"$"),e.EXP_SPLIT=new RegExp("^"+e.EXP_SPLIT+"$",""),e.isInput(t.elem[0])||"focus"===t.trigger&&(t.trigger="click"),t.elem.attr("lay-key")||(t.elem.attr("lay-key",e.index),t.eventElem.attr("lay-key",e.index)),t.mark=w.extend({},t.calendar&&"cn"===t.lang?{"0-1-1":"元旦","0-2-14":"情人","0-3-8":"妇女","0-3-12":"植树","0-4-1":"愚人","0-5-1":"劳动","0-5-4":"青年","0-6-1":"儿童","0-9-10":"教师","0-9-18":"国耻","0-10-1":"国庆","0-12-25":"圣诞"}:{},t.mark),w.each(["min","max"],function(e,n){var a=[],i=[];if("number"==typeof t[n]){var r=t[n],o=(new Date).getTime(),s=864e5,l=new Date(r?r0)return!0;var a=w.elem("div",{"class":"layui-laydate-header"}),i=[function(){var e=w.elem("i",{"class":"layui-icon laydate-icon laydate-prev-y"});return e.innerHTML="",e}(),function(){var e=w.elem("i",{"class":"layui-icon laydate-icon laydate-prev-m"});return e.innerHTML="",e}(),function(){var e=w.elem("div",{"class":"laydate-set-ym"}),t=w.elem("span"),n=w.elem("span");return e.appendChild(t),e.appendChild(n),e}(),function(){var e=w.elem("i",{"class":"layui-icon laydate-icon laydate-next-m"});return e.innerHTML="",e}(),function(){var e=w.elem("i",{"class":"layui-icon laydate-icon laydate-next-y"});return e.innerHTML="",e}()],d=w.elem("div",{"class":"layui-laydate-content"}),c=w.elem("table"),m=w.elem("thead"),u=w.elem("tr");w.each(i,function(e,t){a.appendChild(t)}),m.appendChild(u),w.each(new Array(6),function(e){var t=c.insertRow(0);w.each(new Array(7),function(a){if(0===e){var i=w.elem("th");i.innerHTML=n.weeks[a],u.appendChild(i)}t.insertCell(a)})}),c.insertBefore(m,c.children[0]),d.appendChild(c),r[e]=w.elem("div",{"class":"layui-laydate-main laydate-main-list-"+e}),r[e].appendChild(a),r[e].appendChild(d),o.push(i),s.push(d),l.push(c)}),w(d).html(function(){var e=[],i=[];return"datetime"===t.type&&e.push(''+n.timeTips+""),w.each(t.btns,function(e,r){var o=n.tools[r]||"btn";t.range&&"now"===r||(a&&"clear"===r&&(o="cn"===t.lang?"重置":"Reset"),i.push(''+o+""))}),e.push('"),e.join("")}()),w.each(r,function(e,t){i.appendChild(t)}),t.showBottom&&i.appendChild(d),/^#/.test(t.theme)){var m=w.elem("style"),u=["#{{id}} .layui-laydate-header{background-color:{{theme}};}","#{{id}} .layui-this{background-color:{{theme}} !important;}"].join("").replace(/{{id}}/g,e.elemID).replace(/{{theme}}/g,t.theme);"styleSheet"in m?(m.setAttribute("type","text/css"),m.styleSheet.cssText=u):m.innerHTML=u,w(i).addClass("laydate-theme-molv"),i.appendChild(m)}e.remove(T.thisElemDate),a?t.elem.append(i):(document.body.appendChild(i),e.position()),e.checkDate().calendar(),e.changeEvent(),T.thisElemDate=e.elemID,"function"==typeof t.ready&&t.ready(w.extend({},t.dateTime,{month:t.dateTime.month+1}))},T.prototype.remove=function(e){var t=this,n=(t.config,w("#"+(e||t.elemID)));return n.hasClass(c)||t.checkDate(function(){n.remove()}),t},T.prototype.position=function(){var e=this,t=e.config,n=e.bindElem||t.elem[0],a=n.getBoundingClientRect(),i=e.elem.offsetWidth,r=e.elem.offsetHeight,o=function(e){return e=e?"scrollLeft":"scrollTop",document.body[e]|document.documentElement[e]},s=function(e){return document.documentElement[e?"clientWidth":"clientHeight"]},l=5,d=a.left,c=a.bottom;d+i+l>s("width")&&(d=s("width")-i-l),c+r+l>s()&&(c=a.top>r?a.top-r:s()-r,c-=2*l),t.position&&(e.elem.style.position=t.position),e.elem.style.left=d+("fixed"===t.position?0:o(1))+"px",e.elem.style.top=c+("fixed"===t.position?0:o())+"px"},T.prototype.hint=function(e){var t=this,n=(t.config,w.elem("div",{"class":h}));t.elem&&(n.innerHTML=e||"",w(t.elem).find("."+h).remove(),t.elem.appendChild(n),clearTimeout(t.hinTimer),t.hinTimer=setTimeout(function(){w(t.elem).find("."+h).remove()},3e3))},T.prototype.getAsYM=function(e,t,n){return n?t--:t++,t<0&&(t=11,e--),t>11&&(t=0,e++),[e,t]},T.prototype.systemDate=function(e){var t=e||new Date;return{year:t.getFullYear(),month:t.getMonth(),date:t.getDate(),hours:e?e.getHours():0,minutes:e?e.getMinutes():0,seconds:e?e.getSeconds():0}},T.prototype.checkDate=function(e){var t,a,i=this,r=(new Date,i.config),o=r.dateTime=r.dateTime||i.systemDate(),s=i.bindElem||r.elem[0],l=(i.isInput(s)?"val":"html",i.isInput(s)?s.value:"static"===r.position?"":s.innerHTML),c=function(e){e.year>d[1]&&(e.year=d[1],a=!0),e.month>11&&(e.month=11,a=!0),e.hours>23&&(e.hours=0,a=!0),e.minutes>59&&(e.minutes=0,e.hours++,a=!0),e.seconds>59&&(e.seconds=0,e.minutes++,a=!0),t=n.getEndDate(e.month+1,e.year),e.date>t&&(e.date=t,a=!0)},m=function(e,t,n){var o=["startTime","endTime"];t=(t.match(i.EXP_SPLIT)||[]).slice(1),n=n||0,r.range&&(i[o[n]]=i[o[n]]||{}),w.each(i.format,function(s,l){var c=parseFloat(t[s]);t[s].length必须遵循下述格式:
        "+(r.range?r.format+" "+r.range+" "+r.format:r.format)+"
        已为你重置"),a=!0):l&&l.constructor===Date?r.dateTime=i.systemDate(l):(r.dateTime=i.systemDate(),delete i.startState,delete i.endState,delete i.startDate,delete i.endDate,delete i.startTime,delete i.endTime),c(o),a&&l&&i.setValue(r.range?i.endDate?i.parse():"":i.parse()),e&&e(),i)},T.prototype.mark=function(e,t){var n,a=this,i=a.config;return w.each(i.mark,function(e,a){var i=e.split("-");i[0]!=t[0]&&0!=i[0]||i[1]!=t[1]&&0!=i[1]||i[2]!=t[2]||(n=a||t[2])}),n&&e.html(''+n+""),a},T.prototype.limit=function(e,t,n,a){var i,r=this,o=r.config,l={},d=o[n>41?"endDate":"dateTime"],c=w.extend({},d,t||{});return w.each({now:c,min:o.min,max:o.max},function(e,t){l[e]=r.newDate(w.extend({year:t.year,month:t.month,date:t.date},function(){var e={};return w.each(a,function(n,a){e[a]=t[a]}),e}())).getTime()}),i=l.nowl.max,e&&e[i?"addClass":"removeClass"](s),i},T.prototype.calendar=function(e){var t,a,i,r=this,s=r.config,l=e||s.dateTime,c=new Date,m=r.lang(),u="date"!==s.type&&"datetime"!==s.type,h=e?1:0,y=w(r.table[h]).find("td"),f=w(r.elemHeader[h][2]).find("span");if(l.yeard[1]&&(l.year=d[1],r.hint("最高只能支持到公元"+d[1]+"年")),r.firstDate||(r.firstDate=w.extend({},l)),c.setFullYear(l.year,l.month,1),t=c.getDay(),a=n.getEndDate(l.month||12,l.year),i=n.getEndDate(l.month+1,l.year),w.each(y,function(e,n){var d=[l.year,l.month],c=0;n=w(n),n.removeAttr("class"),e=t&&e=n.firstDate.year&&(r.month=a.max.month,r.date=a.max.date),n.limit(w(i),r,t),M++}),w(u[f?0:1]).attr("lay-ym",M-8+"-"+T[1]).html(b+p+" - "+(M-1+p))}else if("month"===e)w.each(new Array(12),function(e){var i=w.elem("li",{"lay-ym":e}),s={year:T[0],month:e};e+1==T[1]&&w(i).addClass(o),i.innerHTML=r.month[e]+(f?"月":""),d.appendChild(i),T[0]=n.firstDate.year&&(s.date=a.max.date),n.limit(w(i),s,t)}),w(u[f?0:1]).attr("lay-ym",T[0]+"-"+T[1]).html(T[0]+p);else if("time"===e){var E=function(){w(d).find("ol").each(function(e,a){w(a).find("li").each(function(a,i){n.limit(w(i),[{hours:a},{hours:n[x].hours,minutes:a},{hours:n[x].hours,minutes:n[x].minutes,seconds:a}][e],t,[["hours"],["hours","minutes"],["hours","minutes","seconds"]][e])})}),a.range||n.limit(w(n.footer).find(g),n[x],0,["hours","minutes","seconds"])};a.range?n[x]||(n[x]={hours:0,minutes:0,seconds:0}):n[x]=i,w.each([24,60,60],function(e,t){var a=w.elem("li"),i=["

        "+r.time[e]+"

          "];w.each(new Array(t),function(t){i.push(""+w.digit(t,2)+"")}),a.innerHTML=i.join("")+"
        ",d.appendChild(a)}),E()}if(y&&h.removeChild(y),h.appendChild(d),"year"===e||"month"===e)w(n.elemMain[t]).addClass("laydate-ym-show"),w(d).find("li").on("click",function(){var r=0|w(this).attr("lay-ym");if(!w(this).hasClass(s)){if(0===t)i[e]=r,l&&(n.startDate[e]=r),n.limit(w(n.footer).find(g),null,0);else if(l)n.endDate[e]=r;else{var c="year"===e?n.getAsYM(r,T[1]-1,"sub"):n.getAsYM(T[0],r,"sub");w.extend(i,{year:c[0],month:c[1]})}"year"===a.type||"month"===a.type?(w(d).find("."+o).removeClass(o),w(this).addClass(o),"month"===a.type&&"year"===e&&(n.listYM[t][0]=r,l&&(n[["startDate","endDate"][t]].year=r),n.list("month",t))):(n.checkDate("limit").calendar(),n.closeList()),n.setBtnStatus(),a.range||n.done(null,"change"),w(n.footer).find(D).removeClass(s)}});else{var S=w.elem("span",{"class":v}),k=function(){w(d).find("ol").each(function(e){var t=this,a=w(t).find("li");t.scrollTop=30*(n[x][C[e]]-2),t.scrollTop<=0&&a.each(function(e,n){if(!w(this).hasClass(s))return t.scrollTop=30*(e-2),!0})})},H=w(c[2]).find("."+v);k(),S.innerHTML=a.range?[r.startTime,r.endTime][t]:r.timeTips,w(n.elemMain[t]).addClass("laydate-time-show"),H[0]&&H.remove(),c[2].appendChild(S),w(d).find("ol").each(function(e){var t=this;w(t).find("li").on("click",function(){var r=0|this.innerHTML;w(this).hasClass(s)||(a.range?n[x][C[e]]=r:i[C[e]]=r,w(t).find("."+o).removeClass(o),w(this).addClass(o),E(),k(),(n.endDate||"time"===a.type)&&n.done(null,"change"),n.setBtnStatus())})})}return n},T.prototype.listYM=[],T.prototype.closeList=function(){var e=this;e.config;w.each(e.elemCont,function(t,n){w(this).find("."+m).remove(),w(e.elemMain[t]).removeClass("laydate-ym-show laydate-time-show")}),w(e.elem).find("."+v).remove()},T.prototype.setBtnStatus=function(e,t,n){var a,i=this,r=i.config,o=w(i.footer).find(g),d=r.range&&"date"!==r.type&&"time"!==r.type;d&&(t=t||i.startDate,n=n||i.endDate,a=i.newDate(t).getTime()>i.newDate(n).getTime(),i.limit(null,t)||i.limit(null,n)?o.addClass(s):o[a?"addClass":"removeClass"](s),e&&a&&i.hint("string"==typeof e?l.replace(/日期/g,e):l))},T.prototype.parse=function(e,t){var n=this,a=n.config,i=t||(e?w.extend({},n.endDate,n.endTime):a.range?w.extend({},n.startDate,n.startTime):a.dateTime),r=n.format.concat();return w.each(r,function(e,t){/yyyy|y/.test(t)?r[e]=w.digit(i.year,t.length):/MM|M/.test(t)?r[e]=w.digit(i.month+1,t.length):/dd|d/.test(t)?r[e]=w.digit(i.date,t.length):/HH|H/.test(t)?r[e]=w.digit(i.hours,t.length):/mm|m/.test(t)?r[e]=w.digit(i.minutes,t.length):/ss|s/.test(t)&&(r[e]=w.digit(i.seconds,t.length))}),a.range&&!e?r.join("")+" "+a.range+" "+n.parse(1):r.join("")},T.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)},T.prototype.setValue=function(e){var t=this,n=t.config,a=t.bindElem||n.elem[0],i=t.isInput(a)?"val":"html";return"static"===n.position||w(a)[i](e||""),this},T.prototype.stampRange=function(){var e,t,n=this,a=n.config,i=w(n.elem).find("td");if(a.range&&!n.endDate&&w(n.footer).find(g).addClass(s),n.endDate)return e=n.newDate({year:n.startDate.year,month:n.startDate.month,date:n.startDate.date}).getTime(),t=n.newDate({year:n.endDate.year,month:n.endDate.month,date:n.endDate.date}).getTime(),e>t?n.hint(l):void w.each(i,function(a,i){var r=w(i).attr("lay-ymd").split("-"),s=n.newDate({year:r[0],month:r[1]-1,date:r[2]}).getTime();w(i).removeClass(u+" "+o),s!==e&&s!==t||w(i).addClass(w(i).hasClass(y)||w(i).hasClass(f)?u:o),s>e&&s0&&t-1 in e)}function r(e,t,n){if(pe.isFunction(t))return pe.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return pe.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(Ce.test(t))return pe.filter(t,e,n);t=pe.filter(t,e)}return pe.grep(e,function(e){return pe.inArray(e,t)>-1!==n})}function i(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function o(e){var t={};return pe.each(e.match(De)||[],function(e,n){t[n]=!0}),t}function a(){re.addEventListener?(re.removeEventListener("DOMContentLoaded",s),e.removeEventListener("load",s)):(re.detachEvent("onreadystatechange",s),e.detachEvent("onload",s))}function s(){(re.addEventListener||"load"===e.event.type||"complete"===re.readyState)&&(a(),pe.ready())}function u(e,t,n){if(void 0===n&&1===e.nodeType){var r="data-"+t.replace(_e,"-$1").toLowerCase();if(n=e.getAttribute(r),"string"==typeof n){try{n="true"===n||"false"!==n&&("null"===n?null:+n+""===n?+n:qe.test(n)?pe.parseJSON(n):n)}catch(i){}pe.data(e,t,n)}else n=void 0}return n}function l(e){var t;for(t in e)if(("data"!==t||!pe.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function c(e,t,n,r){if(He(e)){var i,o,a=pe.expando,s=e.nodeType,u=s?pe.cache:e,l=s?e[a]:e[a]&&a;if(l&&u[l]&&(r||u[l].data)||void 0!==n||"string"!=typeof t)return l||(l=s?e[a]=ne.pop()||pe.guid++:a),u[l]||(u[l]=s?{}:{toJSON:pe.noop}),"object"!=typeof t&&"function"!=typeof t||(r?u[l]=pe.extend(u[l],t):u[l].data=pe.extend(u[l].data,t)),o=u[l],r||(o.data||(o.data={}),o=o.data),void 0!==n&&(o[pe.camelCase(t)]=n),"string"==typeof t?(i=o[t],null==i&&(i=o[pe.camelCase(t)])):i=o,i}}function f(e,t,n){if(He(e)){var r,i,o=e.nodeType,a=o?pe.cache:e,s=o?e[pe.expando]:pe.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){pe.isArray(t)?t=t.concat(pe.map(t,pe.camelCase)):t in r?t=[t]:(t=pe.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;for(;i--;)delete r[t[i]];if(n?!l(r):!pe.isEmptyObject(r))return}(n||(delete a[s].data,l(a[s])))&&(o?pe.cleanData([e],!0):fe.deleteExpando||a!=a.window?delete a[s]:a[s]=void 0)}}}function d(e,t,n,r){var i,o=1,a=20,s=r?function(){return r.cur()}:function(){return pe.css(e,t,"")},u=s(),l=n&&n[3]||(pe.cssNumber[t]?"":"px"),c=(pe.cssNumber[t]||"px"!==l&&+u)&&Me.exec(pe.css(e,t));if(c&&c[3]!==l){l=l||c[3],n=n||[],c=+u||1;do o=o||".5",c/=o,pe.style(e,t,c+l);while(o!==(o=s()/u)&&1!==o&&--a)}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}function p(e){var t=ze.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function h(e,t){var n,r,i=0,o="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):void 0;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||pe.nodeName(r,t)?o.push(r):pe.merge(o,h(r,t));return void 0===t||t&&pe.nodeName(e,t)?pe.merge([e],o):o}function g(e,t){for(var n,r=0;null!=(n=e[r]);r++)pe._data(n,"globalEval",!t||pe._data(t[r],"globalEval"))}function m(e){Be.test(e.type)&&(e.defaultChecked=e.checked)}function y(e,t,n,r,i){for(var o,a,s,u,l,c,f,d=e.length,y=p(t),v=[],x=0;x"!==f[1]||Ve.test(a)?0:u:u.firstChild,o=a&&a.childNodes.length;o--;)pe.nodeName(c=a.childNodes[o],"tbody")&&!c.childNodes.length&&a.removeChild(c);for(pe.merge(v,u.childNodes),u.textContent="";u.firstChild;)u.removeChild(u.firstChild);u=y.lastChild}else v.push(t.createTextNode(a));for(u&&y.removeChild(u),fe.appendChecked||pe.grep(h(v,"input"),m),x=0;a=v[x++];)if(r&&pe.inArray(a,r)>-1)i&&i.push(a);else if(s=pe.contains(a.ownerDocument,a),u=h(y.appendChild(a),"script"),s&&g(u),n)for(o=0;a=u[o++];)Ie.test(a.type||"")&&n.push(a);return u=null,y}function v(){return!0}function x(){return!1}function b(){try{return re.activeElement}catch(e){}}function w(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)w(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),i===!1)i=x;else if(!i)return e;return 1===o&&(a=i,i=function(e){return pe().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=pe.guid++)),e.each(function(){pe.event.add(this,t,i,r,n)})}function T(e,t){return pe.nodeName(e,"table")&&pe.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function C(e){return e.type=(null!==pe.find.attr(e,"type"))+"/"+e.type,e}function E(e){var t=it.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function N(e,t){if(1===t.nodeType&&pe.hasData(e)){var n,r,i,o=pe._data(e),a=pe._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;r1&&"string"==typeof p&&!fe.checkClone&&rt.test(p))return e.each(function(i){var o=e.eq(i);g&&(t[0]=p.call(this,i,o.html())),S(o,t,n,r)});if(f&&(l=y(t,e[0].ownerDocument,!1,e,r),i=l.firstChild,1===l.childNodes.length&&(l=i),i||r)){for(s=pe.map(h(l,"script"),C),a=s.length;c")).appendTo(t.documentElement),t=(ut[0].contentWindow||ut[0].contentDocument).document,t.write(),t.close(),n=D(e,t),ut.detach()),lt[e]=n),n}function L(e,t){return{get:function(){return e()?void delete this.get:(this.get=t).apply(this,arguments)}}}function H(e){if(e in Et)return e;for(var t=e.charAt(0).toUpperCase()+e.slice(1),n=Ct.length;n--;)if(e=Ct[n]+t,e in Et)return e}function q(e,t){for(var n,r,i,o=[],a=0,s=e.length;a=0&&n=0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},isPlainObject:function(e){var t;if(!e||"object"!==pe.type(e)||e.nodeType||pe.isWindow(e))return!1;try{if(e.constructor&&!ce.call(e,"constructor")&&!ce.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}if(!fe.ownFirst)for(t in e)return ce.call(e,t);for(t in e);return void 0===t||ce.call(e,t)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?ue[le.call(e)]||"object":typeof e},globalEval:function(t){t&&pe.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(ge,"ms-").replace(me,ye)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t){var r,i=0;if(n(e))for(r=e.length;iT.cacheLength&&delete e[t.shift()],e[n+" "]=r}var t=[];return e}function r(e){return e[P]=!0,e}function i(e){var t=H.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function o(e,t){for(var n=e.split("|"),r=n.length;r--;)T.attrHandle[n[r]]=t}function a(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||V)-(~e.sourceIndex||V);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function s(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function u(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function l(e){return r(function(t){return t=+t,r(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function c(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function f(){}function d(e){for(var t=0,n=e.length,r="";t1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function g(e,n,r){for(var i=0,o=n.length;i-1&&(r[l]=!(a[l]=f))}}else x=m(x===a?x.splice(h,x.length):x),o?o(null,a,x,u):Q.apply(a,x)})}function v(e){for(var t,n,r,i=e.length,o=T.relative[e[0].type],a=o||T.relative[" "],s=o?1:0,u=p(function(e){return e===t},a,!0),l=p(function(e){return ee(t,e)>-1},a,!0),c=[function(e,n,r){var i=!o&&(r||n!==A)||((t=n).nodeType?u(e,n,r):l(e,n,r));return t=null,i}];s1&&h(c),s>1&&d(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(se,"$1"),n,s0,o=e.length>0,a=function(r,a,s,u,l){var c,f,d,p=0,h="0",g=r&&[],y=[],v=A,x=r||o&&T.find.TAG("*",l),b=W+=null==v?1:Math.random()||.1,w=x.length;for(l&&(A=a===H||a||l);h!==w&&null!=(c=x[h]);h++){if(o&&c){for(f=0,a||c.ownerDocument===H||(L(c),s=!_);d=e[f++];)if(d(c,a||H,s)){u.push(c);break}l&&(W=b)}i&&((c=!d&&c)&&p--,r&&g.push(c))}if(p+=h,i&&h!==p){for(f=0;d=n[f++];)d(g,y,a,s);if(r){if(p>0)for(;h--;)g[h]||y[h]||(y[h]=G.call(u));y=m(y)}Q.apply(u,y),l&&!r&&y.length>0&&p+n.length>1&&t.uniqueSort(u)}return l&&(W=b,A=v),g};return i?r(a):a}var b,w,T,C,E,N,k,S,A,D,j,L,H,q,_,F,M,O,R,P="sizzle"+1*new Date,B=e.document,W=0,I=0,$=n(),z=n(),X=n(),U=function(e,t){return e===t&&(j=!0),0},V=1<<31,Y={}.hasOwnProperty,J=[],G=J.pop,K=J.push,Q=J.push,Z=J.slice,ee=function(e,t){for(var n=0,r=e.length;n+~]|"+ne+")"+ne+"*"),ce=new RegExp("="+ne+"*([^\\]'\"]*?)"+ne+"*\\]","g"),fe=new RegExp(oe),de=new RegExp("^"+re+"$"),pe={ID:new RegExp("^#("+re+")"),CLASS:new RegExp("^\\.("+re+")"),TAG:new RegExp("^("+re+"|[*])"),ATTR:new RegExp("^"+ie),PSEUDO:new RegExp("^"+oe),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ne+"*(even|odd|(([+-]|)(\\d*)n|)"+ne+"*(?:([+-]|)"+ne+"*(\\d+)|))"+ne+"*\\)|)","i"),bool:new RegExp("^(?:"+te+")$","i"),needsContext:new RegExp("^"+ne+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ne+"*((?:-\\d)?\\d*)"+ne+"*\\)|)(?=[^-]|$)","i")},he=/^(?:input|select|textarea|button)$/i,ge=/^h\d$/i,me=/^[^{]+\{\s*\[native \w/,ye=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ve=/[+~]/,xe=/'|\\/g,be=new RegExp("\\\\([\\da-f]{1,6}"+ne+"?|("+ne+")|.)","ig"),we=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},Te=function(){L()};try{Q.apply(J=Z.call(B.childNodes),B.childNodes),J[B.childNodes.length].nodeType}catch(Ce){Q={apply:J.length?function(e,t){K.apply(e,Z.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}w=t.support={},E=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},L=t.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:B;return r!==H&&9===r.nodeType&&r.documentElement?(H=r,q=H.documentElement,_=!E(H),(n=H.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",Te,!1):n.attachEvent&&n.attachEvent("onunload",Te)),w.attributes=i(function(e){return e.className="i",!e.getAttribute("className")}),w.getElementsByTagName=i(function(e){return e.appendChild(H.createComment("")),!e.getElementsByTagName("*").length}),w.getElementsByClassName=me.test(H.getElementsByClassName),w.getById=i(function(e){return q.appendChild(e).id=P,!H.getElementsByName||!H.getElementsByName(P).length}),w.getById?(T.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&_){var n=t.getElementById(e);return n?[n]:[]}},T.filter.ID=function(e){var t=e.replace(be,we);return function(e){return e.getAttribute("id")===t}}):(delete T.find.ID,T.filter.ID=function(e){var t=e.replace(be,we);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}}),T.find.TAG=w.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):w.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},T.find.CLASS=w.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&_)return t.getElementsByClassName(e)},M=[],F=[],(w.qsa=me.test(H.querySelectorAll))&&(i(function(e){q.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&F.push("[*^$]="+ne+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||F.push("\\["+ne+"*(?:value|"+te+")"),e.querySelectorAll("[id~="+P+"-]").length||F.push("~="),e.querySelectorAll(":checked").length||F.push(":checked"),e.querySelectorAll("a#"+P+"+*").length||F.push(".#.+[+~]")}),i(function(e){var t=H.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&F.push("name"+ne+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||F.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),F.push(",.*:")})),(w.matchesSelector=me.test(O=q.matches||q.webkitMatchesSelector||q.mozMatchesSelector||q.oMatchesSelector||q.msMatchesSelector))&&i(function(e){w.disconnectedMatch=O.call(e,"div"),O.call(e,"[s!='']:x"),M.push("!=",oe)}),F=F.length&&new RegExp(F.join("|")),M=M.length&&new RegExp(M.join("|")),t=me.test(q.compareDocumentPosition),R=t||me.test(q.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},U=t?function(e,t){if(e===t)return j=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n?n:(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&n||!w.sortDetached&&t.compareDocumentPosition(e)===n?e===H||e.ownerDocument===B&&R(B,e)?-1:t===H||t.ownerDocument===B&&R(B,t)?1:D?ee(D,e)-ee(D,t):0:4&n?-1:1)}:function(e,t){if(e===t)return j=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,s=[e],u=[t];if(!i||!o)return e===H?-1:t===H?1:i?-1:o?1:D?ee(D,e)-ee(D,t):0;if(i===o)return a(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)u.unshift(n);for(;s[r]===u[r];)r++;return r?a(s[r],u[r]):s[r]===B?-1:u[r]===B?1:0},H):H},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==H&&L(e),n=n.replace(ce,"='$1']"),w.matchesSelector&&_&&!X[n+" "]&&(!M||!M.test(n))&&(!F||!F.test(n)))try{var r=O.call(e,n);if(r||w.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return t(n,H,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==H&&L(e),R(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==H&&L(e);var n=T.attrHandle[t.toLowerCase()],r=n&&Y.call(T.attrHandle,t.toLowerCase())?n(e,t,!_):void 0;return void 0!==r?r:w.attributes||!_?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},t.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},t.uniqueSort=function(e){var t,n=[],r=0,i=0;if(j=!w.detectDuplicates,D=!w.sortStable&&e.slice(0),e.sort(U),j){for(;t=e[i++];)t===e[i]&&(r=n.push(i));for(;r--;)e.splice(n[r],1)}return D=null,e},C=t.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=C(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r++];)n+=C(t);return n},T=t.selectors={cacheLength:50,createPseudo:r,match:pe,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(be,we),e[3]=(e[3]||e[4]||e[5]||"").replace(be,we),"~="===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]||t.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]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return pe.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&fe.test(n)&&(t=N(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(be,we).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=$[e+" "];return t||(t=new RegExp("(^|"+ne+")"+e+"("+ne+"|$)"))&&$(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,n,r){return function(i){var o=t.attr(i,e);return null==o?"!="===n:!n||(o+="","="===n?o===r:"!="===n?o!==r:"^="===n?r&&0===o.indexOf(r):"*="===n?r&&o.indexOf(r)>-1:"$="===n?r&&o.slice(-r.length)===r:"~="===n?(" "+o.replace(ae," ")+" ").indexOf(r)>-1:"|="===n&&(o===r||o.slice(0,r.length+1)===r+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,d,p,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s,x=!1;if(m){if(o){for(;g;){for(d=t;d=d[g];)if(s?d.nodeName.toLowerCase()===y:1===d.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){for(d=m,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}), +l=c[e]||[],p=l[0]===W&&l[1],x=p&&l[2],d=p&&m.childNodes[p];d=++p&&d&&d[g]||(x=p=0)||h.pop();)if(1===d.nodeType&&++x&&d===t){c[e]=[W,p,x];break}}else if(v&&(d=t,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),l=c[e]||[],p=l[0]===W&&l[1],x=p),x===!1)for(;(d=++p&&d&&d[g]||(x=p=0)||h.pop())&&((s?d.nodeName.toLowerCase()!==y:1!==d.nodeType)||!++x||(v&&(f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),c[e]=[W,x]),d!==t)););return x-=i,x===r||x%r===0&&x/r>=0}}},PSEUDO:function(e,n){var i,o=T.pseudos[e]||T.setFilters[e.toLowerCase()]||t.error("unsupported pseudo: "+e);return o[P]?o(n):o.length>1?(i=[e,e,"",n],T.setFilters.hasOwnProperty(e.toLowerCase())?r(function(e,t){for(var r,i=o(e,n),a=i.length;a--;)r=ee(e,i[a]),e[r]=!(t[r]=i[a])}):function(e){return o(e,0,i)}):o}},pseudos:{not:r(function(e){var t=[],n=[],i=k(e.replace(se,"$1"));return i[P]?r(function(e,t,n,r){for(var o,a=i(e,null,r,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,r,o){return t[0]=e,i(t,null,o,n),t[0]=null,!n.pop()}}),has:r(function(e){return function(n){return t(e,n).length>0}}),contains:r(function(e){return e=e.replace(be,we),function(t){return(t.textContent||t.innerText||C(t)).indexOf(e)>-1}}),lang:r(function(e){return de.test(e||"")||t.error("unsupported lang: "+e),e=e.replace(be,we).toLowerCase(),function(t){var n;do if(n=_?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===q},focus:function(e){return e===H.activeElement&&(!H.hasFocus||H.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!T.pseudos.empty(e)},header:function(e){return ge.test(e.nodeName)},input:function(e){return he.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:l(function(){return[0]}),last:l(function(e,t){return[t-1]}),eq:l(function(e,t,n){return[n<0?n+t:n]}),even:l(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:l(function(e,t,n){for(var r=n<0?n+t:n;++r2&&"ID"===(a=o[0]).type&&w.getById&&9===t.nodeType&&_&&T.relative[o[1].type]){if(t=(T.find.ID(a.matches[0].replace(be,we),t)||[])[0],!t)return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}for(i=pe.needsContext.test(e)?0:o.length;i--&&(a=o[i],!T.relative[s=a.type]);)if((u=T.find[s])&&(r=u(a.matches[0].replace(be,we),ve.test(o[0].type)&&c(t.parentNode)||t))){if(o.splice(i,1),e=r.length&&d(o),!e)return Q.apply(n,r),n;break}}return(l||k(e,f))(r,t,!_,n,!t||ve.test(e)&&c(t.parentNode)||t),n},w.sortStable=P.split("").sort(U).join("")===P,w.detectDuplicates=!!j,L(),w.sortDetached=i(function(e){return 1&e.compareDocumentPosition(H.createElement("div"))}),i(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||o("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),w.attributes&&i(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||o("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),i(function(e){return null==e.getAttribute("disabled")})||o(te,function(e,t,n){var r;if(!n)return e[t]===!0?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),t}(e);pe.find=ve,pe.expr=ve.selectors,pe.expr[":"]=pe.expr.pseudos,pe.uniqueSort=pe.unique=ve.uniqueSort,pe.text=ve.getText,pe.isXMLDoc=ve.isXML,pe.contains=ve.contains;var xe=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&pe(e).is(n))break;r.push(e)}return r},be=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},we=pe.expr.match.needsContext,Te=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,Ce=/^.[^:#\[\.,]*$/;pe.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?pe.find.matchesSelector(r,e)?[r]:[]:pe.find.matches(e,pe.grep(t,function(e){return 1===e.nodeType}))},pe.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(pe(e).filter(function(){for(t=0;t1?pe.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},filter:function(e){return this.pushStack(r(this,e||[],!1))},not:function(e){return this.pushStack(r(this,e||[],!0))},is:function(e){return!!r(this,"string"==typeof e&&we.test(e)?pe(e):e||[],!1).length}});var Ee,Ne=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,ke=pe.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||Ee,"string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:Ne.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof pe?t[0]:t,pe.merge(this,pe.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:re,!0)),Te.test(r[1])&&pe.isPlainObject(t))for(r in t)pe.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}if(i=re.getElementById(r[2]),i&&i.parentNode){if(i.id!==r[2])return Ee.find(e);this.length=1,this[0]=i}return this.context=re,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):pe.isFunction(e)?"undefined"!=typeof n.ready?n.ready(e):e(pe):(void 0!==e.selector&&(this.selector=e.selector,this.context=e.context),pe.makeArray(e,this))};ke.prototype=pe.fn,Ee=pe(re);var Se=/^(?:parents|prev(?:Until|All))/,Ae={children:!0,contents:!0,next:!0,prev:!0};pe.fn.extend({has:function(e){var t,n=pe(e,this),r=n.length;return this.filter(function(){for(t=0;t-1:1===n.nodeType&&pe.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?pe.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?pe.inArray(this[0],pe(e)):pe.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(pe.uniqueSort(pe.merge(this.get(),pe(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),pe.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return xe(e,"parentNode")},parentsUntil:function(e,t,n){return xe(e,"parentNode",n)},next:function(e){return i(e,"nextSibling")},prev:function(e){return i(e,"previousSibling")},nextAll:function(e){return xe(e,"nextSibling")},prevAll:function(e){return xe(e,"previousSibling")},nextUntil:function(e,t,n){return xe(e,"nextSibling",n)},prevUntil:function(e,t,n){return xe(e,"previousSibling",n)},siblings:function(e){return be((e.parentNode||{}).firstChild,e)},children:function(e){return be(e.firstChild)},contents:function(e){return pe.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:pe.merge([],e.childNodes)}},function(e,t){pe.fn[e]=function(n,r){var i=pe.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=pe.filter(r,i)),this.length>1&&(Ae[e]||(i=pe.uniqueSort(i)),Se.test(e)&&(i=i.reverse())),this.pushStack(i)}});var De=/\S+/g;pe.Callbacks=function(e){e="string"==typeof e?o(e):pe.extend({},e);var t,n,r,i,a=[],s=[],u=-1,l=function(){for(i=e.once,r=t=!0;s.length;u=-1)for(n=s.shift();++u-1;)a.splice(n,1),n<=u&&u--}),this},has:function(e){return e?pe.inArray(e,a)>-1:a.length>0},empty:function(){return a&&(a=[]),this},disable:function(){return i=s=[],a=n="",this},disabled:function(){return!a},lock:function(){return i=!0,n||c.disable(),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=n||[],n=[e,n.slice?n.slice():n],s.push(n),t||l()),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},pe.extend({Deferred:function(e){var t=[["resolve","done",pe.Callbacks("once memory"),"resolved"],["reject","fail",pe.Callbacks("once memory"),"rejected"],["notify","progress",pe.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return pe.Deferred(function(n){pe.each(t,function(t,o){var a=pe.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&pe.isFunction(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[o[0]+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?pe.extend(e,r):r}},i={};return r.pipe=r.then,pe.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t,n,r,i=0,o=ie.call(arguments),a=o.length,s=1!==a||e&&pe.isFunction(e.promise)?a:0,u=1===s?e:pe.Deferred(),l=function(e,n,r){return function(i){n[e]=this,r[e]=arguments.length>1?ie.call(arguments):i,r===t?u.notifyWith(n,r):--s||u.resolveWith(n,r)}};if(a>1)for(t=new Array(a),n=new Array(a),r=new Array(a);i0||(je.resolveWith(re,[pe]),pe.fn.triggerHandler&&(pe(re).triggerHandler("ready"),pe(re).off("ready"))))}}),pe.ready.promise=function(t){if(!je)if(je=pe.Deferred(),"complete"===re.readyState||"loading"!==re.readyState&&!re.documentElement.doScroll)e.setTimeout(pe.ready);else if(re.addEventListener)re.addEventListener("DOMContentLoaded",s),e.addEventListener("load",s);else{re.attachEvent("onreadystatechange",s),e.attachEvent("onload",s);var n=!1;try{n=null==e.frameElement&&re.documentElement}catch(r){}n&&n.doScroll&&!function i(){if(!pe.isReady){try{n.doScroll("left")}catch(t){return e.setTimeout(i,50)}a(),pe.ready()}}()}return je.promise(t)},pe.ready.promise();var Le;for(Le in pe(fe))break;fe.ownFirst="0"===Le,fe.inlineBlockNeedsLayout=!1,pe(function(){var e,t,n,r;n=re.getElementsByTagName("body")[0],n&&n.style&&(t=re.createElement("div"),r=re.createElement("div"),r.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",n.appendChild(r).appendChild(t),"undefined"!=typeof t.style.zoom&&(t.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",fe.inlineBlockNeedsLayout=e=3===t.offsetWidth,e&&(n.style.zoom=1)),n.removeChild(r))}),function(){var e=re.createElement("div");fe.deleteExpando=!0;try{delete e.test}catch(t){fe.deleteExpando=!1}e=null}();var He=function(e){var t=pe.noData[(e.nodeName+" ").toLowerCase()],n=+e.nodeType||1;return(1===n||9===n)&&(!t||t!==!0&&e.getAttribute("classid")===t)},qe=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,_e=/([A-Z])/g;pe.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?pe.cache[e[pe.expando]]:e[pe.expando],!!e&&!l(e)},data:function(e,t,n){return c(e,t,n)},removeData:function(e,t){return f(e,t)},_data:function(e,t,n){return c(e,t,n,!0)},_removeData:function(e,t){return f(e,t,!0)}}),pe.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if(void 0===e){if(this.length&&(i=pe.data(o),1===o.nodeType&&!pe._data(o,"parsedAttrs"))){for(n=a.length;n--;)a[n]&&(r=a[n].name,0===r.indexOf("data-")&&(r=pe.camelCase(r.slice(5)),u(o,r,i[r])));pe._data(o,"parsedAttrs",!0)}return i}return"object"==typeof e?this.each(function(){pe.data(this,e)}):arguments.length>1?this.each(function(){pe.data(this,e,t)}):o?u(o,e,pe.data(o,e)):void 0},removeData:function(e){return this.each(function(){pe.removeData(this,e)})}}),pe.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=pe._data(e,t),n&&(!r||pe.isArray(n)?r=pe._data(e,t,pe.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=pe.queue(e,t),r=n.length,i=n.shift(),o=pe._queueHooks(e,t),a=function(){pe.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return pe._data(e,n)||pe._data(e,n,{empty:pe.Callbacks("once memory").add(function(){pe._removeData(e,t+"queue"),pe._removeData(e,n)})})}}),pe.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length
        a",fe.leadingWhitespace=3===e.firstChild.nodeType,fe.tbody=!e.getElementsByTagName("tbody").length,fe.htmlSerialize=!!e.getElementsByTagName("link").length,fe.html5Clone="<:nav>"!==re.createElement("nav").cloneNode(!0).outerHTML,n.type="checkbox",n.checked=!0,t.appendChild(n),fe.appendChecked=n.checked,e.innerHTML="",fe.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue,t.appendChild(e),n=re.createElement("input"),n.setAttribute("type","radio"),n.setAttribute("checked","checked"),n.setAttribute("name","t"),e.appendChild(n),fe.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,fe.noCloneEvent=!!e.addEventListener,e[pe.expando]=1,fe.attributes=!e.getAttribute(pe.expando)}();var Xe={option:[1,""],legend:[1,"
        ","
        "],area:[1,"",""],param:[1,"",""],thead:[1,"","
        "],tr:[2,"","
        "],col:[2,"","
        "],td:[3,"","
        "],_default:fe.htmlSerialize?[0,"",""]:[1,"X
        ","
        "]};Xe.optgroup=Xe.option,Xe.tbody=Xe.tfoot=Xe.colgroup=Xe.caption=Xe.thead,Xe.th=Xe.td;var Ue=/<|&#?\w+;/,Ve=/-1&&(h=p.split("."),p=h.shift(),h.sort()),a=p.indexOf(":")<0&&"on"+p,t=t[pe.expando]?t:new pe.Event(p,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=h.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=r),n=null==n?[t]:pe.makeArray(n,[t]),l=pe.event.special[p]||{},i||!l.trigger||l.trigger.apply(r,n)!==!1)){if(!i&&!l.noBubble&&!pe.isWindow(r)){for(u=l.delegateType||p,Ke.test(u+p)||(s=s.parentNode);s;s=s.parentNode)d.push(s),c=s;c===(r.ownerDocument||re)&&d.push(c.defaultView||c.parentWindow||e)}for(f=0;(s=d[f++])&&!t.isPropagationStopped();)t.type=f>1?u:l.bindType||p,o=(pe._data(s,"events")||{})[t.type]&&pe._data(s,"handle"),o&&o.apply(s,n),o=a&&s[a],o&&o.apply&&He(s)&&(t.result=o.apply(s,n),t.result===!1&&t.preventDefault());if(t.type=p,!i&&!t.isDefaultPrevented()&&(!l._default||l._default.apply(d.pop(),n)===!1)&&He(r)&&a&&r[p]&&!pe.isWindow(r)){c=r[a],c&&(r[a]=null),pe.event.triggered=p;try{r[p]()}catch(g){}pe.event.triggered=void 0,c&&(r[a]=c)}return t.result}},dispatch:function(e){e=pe.event.fix(e);var t,n,r,i,o,a=[],s=ie.call(arguments),u=(pe._data(this,"events")||{})[e.type]||[],l=pe.event.special[e.type]||{};if(s[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){for(a=pe.event.handlers.call(this,e,u),t=0;(i=a[t++])&&!e.isPropagationStopped();)for(e.currentTarget=i.elem,n=0;(o=i.handlers[n++])&&!e.isImmediatePropagationStopped();)e.rnamespace&&!e.rnamespace.test(o.namespace)||(e.handleObj=o,e.data=o.data,r=((pe.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s),void 0!==r&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()));return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,a=[],s=t.delegateCount,u=e.target;if(s&&u.nodeType&&("click"!==e.type||isNaN(e.button)||e.button<1))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(r=[],n=0;n-1:pe.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&a.push({elem:u,handlers:r})}return s]","i"),tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,nt=/\s*$/g,at=p(re),st=at.appendChild(re.createElement("div"));pe.extend({htmlPrefilter:function(e){return e.replace(tt,"<$1>")},clone:function(e,t,n){var r,i,o,a,s,u=pe.contains(e.ownerDocument,e);if(fe.html5Clone||pe.isXMLDoc(e)||!et.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(st.innerHTML=e.outerHTML,st.removeChild(o=st.firstChild)),!(fe.noCloneEvent&&fe.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||pe.isXMLDoc(e)))for(r=h(o),s=h(e),a=0;null!=(i=s[a]);++a)r[a]&&k(i,r[a]);if(t)if(n)for(s=s||h(e),r=r||h(o),a=0;null!=(i=s[a]);a++)N(i,r[a]);else N(e,o);return r=h(o,"script"),r.length>0&&g(r,!u&&h(e,"script")),r=s=i=null,o},cleanData:function(e,t){for(var n,r,i,o,a=0,s=pe.expando,u=pe.cache,l=fe.attributes,c=pe.event.special;null!=(n=e[a]);a++)if((t||He(n))&&(i=n[s],o=i&&u[i])){if(o.events)for(r in o.events)c[r]?pe.event.remove(n,r):pe.removeEvent(n,r,o.handle);u[i]&&(delete u[i],l||"undefined"==typeof n.removeAttribute?n[s]=void 0:n.removeAttribute(s),ne.push(i))}}}),pe.fn.extend({domManip:S,detach:function(e){return A(this,e,!0)},remove:function(e){return A(this,e)},text:function(e){return Pe(this,function(e){return void 0===e?pe.text(this):this.empty().append((this[0]&&this[0].ownerDocument||re).createTextNode(e))},null,e,arguments.length)},append:function(){return S(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=T(this,e);t.appendChild(e)}})},prepend:function(){return S(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=T(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return S(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return S(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&&pe.cleanData(h(e,!1));e.firstChild;)e.removeChild(e.firstChild);e.options&&pe.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 pe.clone(this,e,t)})},html:function(e){return Pe(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e)return 1===t.nodeType?t.innerHTML.replace(Ze,""):void 0;if("string"==typeof e&&!nt.test(e)&&(fe.htmlSerialize||!et.test(e))&&(fe.leadingWhitespace||!$e.test(e))&&!Xe[(We.exec(e)||["",""])[1].toLowerCase()]){e=pe.htmlPrefilter(e);try{for(;nt",t=l.getElementsByTagName("td"),t[0].style.cssText="margin:0;border:0;padding:0;display:none",o=0===t[0].offsetHeight,o&&(t[0].style.display="",t[1].style.display="none",o=0===t[0].offsetHeight)),f.removeChild(u)}var n,r,i,o,a,s,u=re.createElement("div"),l=re.createElement("div");l.style&&(l.style.cssText="float:left;opacity:.5",fe.opacity="0.5"===l.style.opacity,fe.cssFloat=!!l.style.cssFloat,l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",fe.clearCloneStyle="content-box"===l.style.backgroundClip,u=re.createElement("div"),u.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",l.innerHTML="",u.appendChild(l),fe.boxSizing=""===l.style.boxSizing||""===l.style.MozBoxSizing||""===l.style.WebkitBoxSizing,pe.extend(fe,{reliableHiddenOffsets:function(){return null==n&&t(),o},boxSizingReliable:function(){return null==n&&t(),i},pixelMarginRight:function(){return null==n&&t(),r},pixelPosition:function(){return null==n&&t(),n},reliableMarginRight:function(){return null==n&&t(),a},reliableMarginLeft:function(){return null==n&&t(),s}}))}();var ht,gt,mt=/^(top|right|bottom|left)$/;e.getComputedStyle?(ht=function(t){var n=t.ownerDocument.defaultView;return n&&n.opener||(n=e),n.getComputedStyle(t)},gt=function(e,t,n){var r,i,o,a,s=e.style;return n=n||ht(e),a=n?n.getPropertyValue(t)||n[t]:void 0,""!==a&&void 0!==a||pe.contains(e.ownerDocument,e)||(a=pe.style(e,t)),n&&!fe.pixelMarginRight()&&ft.test(a)&&ct.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o),void 0===a?a:a+""}):pt.currentStyle&&(ht=function(e){return e.currentStyle},gt=function(e,t,n){var r,i,o,a,s=e.style;return n=n||ht(e),a=n?n[t]:void 0,null==a&&s&&s[t]&&(a=s[t]),ft.test(a)&&!mt.test(t)&&(r=s.left,i=e.runtimeStyle,o=i&&i.left,o&&(i.left=e.currentStyle.left),s.left="fontSize"===t?"1em":a,a=s.pixelLeft+"px",s.left=r,o&&(i.left=o)),void 0===a?a:a+""||"auto"});var yt=/alpha\([^)]*\)/i,vt=/opacity\s*=\s*([^)]*)/i,xt=/^(none|table(?!-c[ea]).+)/,bt=new RegExp("^("+Fe+")(.*)$","i"),wt={position:"absolute",visibility:"hidden",display:"block"},Tt={letterSpacing:"0",fontWeight:"400"},Ct=["Webkit","O","Moz","ms"],Et=re.createElement("div").style;pe.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=gt(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":fe.cssFloat?"cssFloat":"styleFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=pe.camelCase(t),u=e.style;if(t=pe.cssProps[s]||(pe.cssProps[s]=H(s)||s),a=pe.cssHooks[t]||pe.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:u[t];if(o=typeof n,"string"===o&&(i=Me.exec(n))&&i[1]&&(n=d(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(pe.cssNumber[s]?"":"px")),fe.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),!(a&&"set"in a&&void 0===(n=a.set(e,n,r)))))try{u[t]=n}catch(l){}}},css:function(e,t,n,r){var i,o,a,s=pe.camelCase(t);return t=pe.cssProps[s]||(pe.cssProps[s]=H(s)||s),a=pe.cssHooks[t]||pe.cssHooks[s],a&&"get"in a&&(o=a.get(e,!0,n)),void 0===o&&(o=gt(e,t,r)),"normal"===o&&t in Tt&&(o=Tt[t]),""===n||n?(i=parseFloat(o),n===!0||isFinite(i)?i||0:o):o}}),pe.each(["height","width"],function(e,t){pe.cssHooks[t]={get:function(e,n,r){if(n)return xt.test(pe.css(e,"display"))&&0===e.offsetWidth?dt(e,wt,function(){return M(e,t,r)}):M(e,t,r)},set:function(e,n,r){var i=r&&ht(e);return _(e,n,r?F(e,t,r,fe.boxSizing&&"border-box"===pe.css(e,"boxSizing",!1,i),i):0)}}}),fe.opacity||(pe.cssHooks.opacity={get:function(e,t){return vt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=pe.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===pe.trim(o.replace(yt,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=yt.test(o)?o.replace(yt,i):o+" "+i)}}),pe.cssHooks.marginRight=L(fe.reliableMarginRight,function(e,t){if(t)return dt(e,{display:"inline-block"},gt,[e,"marginRight"])}),pe.cssHooks.marginLeft=L(fe.reliableMarginLeft,function(e,t){if(t)return(parseFloat(gt(e,"marginLeft"))||(pe.contains(e.ownerDocument,e)?e.getBoundingClientRect().left-dt(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}):0))+"px"}),pe.each({margin:"",padding:"",border:"Width"},function(e,t){pe.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+Oe[r]+t]=o[r]||o[r-2]||o[0];return i}},ct.test(e)||(pe.cssHooks[e+t].set=_)}),pe.fn.extend({css:function(e,t){return Pe(this,function(e,t,n){var r,i,o={},a=0;if(pe.isArray(t)){for(r=ht(e),i=t.length;a1)},show:function(){return q(this,!0)},hide:function(){return q(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){Re(this)?pe(this).show():pe(this).hide()})}}),pe.Tween=O,O.prototype={constructor:O,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||pe.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(pe.cssNumber[n]?"":"px")},cur:function(){var e=O.propHooks[this.prop];return e&&e.get?e.get(this):O.propHooks._default.get(this)},run:function(e){var t,n=O.propHooks[this.prop];return this.options.duration?this.pos=t=pe.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):O.propHooks._default.set(this),this}},O.prototype.init.prototype=O.prototype,O.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=pe.css(e.elem,e.prop,""),t&&"auto"!==t?t:0)},set:function(e){pe.fx.step[e.prop]?pe.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[pe.cssProps[e.prop]]&&!pe.cssHooks[e.prop]?e.elem[e.prop]=e.now:pe.style(e.elem,e.prop,e.now+e.unit)}}},O.propHooks.scrollTop=O.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},pe.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},pe.fx=O.prototype.init,pe.fx.step={};var Nt,kt,St=/^(?:toggle|show|hide)$/,At=/queueHooks$/;pe.Animation=pe.extend($,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return d(n.elem,e,Me.exec(t),n),n}]},tweener:function(e,t){pe.isFunction(e)?(t=e,e=["*"]):e=e.match(De);for(var n,r=0,i=e.length;r
        a",e=n.getElementsByTagName("a")[0],t.setAttribute("type","checkbox"),n.appendChild(t),e=n.getElementsByTagName("a")[0],e.style.cssText="top:1px",fe.getSetAttribute="t"!==n.className,fe.style=/top/.test(e.getAttribute("style")),fe.hrefNormalized="/a"===e.getAttribute("href"),fe.checkOn=!!t.value,fe.optSelected=i.selected,fe.enctype=!!re.createElement("form").enctype,r.disabled=!0,fe.optDisabled=!i.disabled,t=re.createElement("input"),t.setAttribute("value",""),fe.input=""===t.getAttribute("value"),t.value="t",t.setAttribute("type","radio"),fe.radioValue="t"===t.value}();var Dt=/\r/g,jt=/[\x20\t\r\n\f]+/g;pe.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=pe.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,pe(this).val()):e,null==i?i="":"number"==typeof i?i+="":pe.isArray(i)&&(i=pe.map(i,function(e){return null==e?"":e+""})),t=pe.valHooks[this.type]||pe.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return t=pe.valHooks[i.type]||pe.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:(n=i.value,"string"==typeof n?n.replace(Dt,""):null==n?"":n)}}}),pe.extend({valHooks:{option:{get:function(e){var t=pe.find.attr(e,"value");return null!=t?t:pe.trim(pe.text(e)).replace(jt," ")}},select:{get:function(e){for(var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||i<0,a=o?null:[],s=o?i+1:r.length,u=i<0?s:o?i:0;u-1)try{r.selected=n=!0}catch(s){r.scrollHeight}else r.selected=!1;return n||(e.selectedIndex=-1),i}}}}),pe.each(["radio","checkbox"],function(){pe.valHooks[this]={set:function(e,t){if(pe.isArray(t))return e.checked=pe.inArray(pe(e).val(),t)>-1}},fe.checkOn||(pe.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Lt,Ht,qt=pe.expr.attrHandle,_t=/^(?:checked|selected)$/i,Ft=fe.getSetAttribute,Mt=fe.input;pe.fn.extend({attr:function(e,t){return Pe(this,pe.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){pe.removeAttr(this,e)})}}),pe.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?pe.prop(e,t,n):(1===o&&pe.isXMLDoc(e)||(t=t.toLowerCase(),i=pe.attrHooks[t]||(pe.expr.match.bool.test(t)?Ht:Lt)),void 0!==n?null===n?void pe.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:(r=pe.find.attr(e,t),null==r?void 0:r))},attrHooks:{type:{set:function(e,t){if(!fe.radioValue&&"radio"===t&&pe.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(De);if(o&&1===e.nodeType)for(;n=o[i++];)r=pe.propFix[n]||n,pe.expr.match.bool.test(n)?Mt&&Ft||!_t.test(n)?e[r]=!1:e[pe.camelCase("default-"+n)]=e[r]=!1:pe.attr(e,n,""),e.removeAttribute(Ft?n:r)}}),Ht={set:function(e,t,n){return t===!1?pe.removeAttr(e,n):Mt&&Ft||!_t.test(n)?e.setAttribute(!Ft&&pe.propFix[n]||n,n):e[pe.camelCase("default-"+n)]=e[n]=!0,n}},pe.each(pe.expr.match.bool.source.match(/\w+/g),function(e,t){var n=qt[t]||pe.find.attr;Mt&&Ft||!_t.test(t)?qt[t]=function(e,t,r){var i,o;return r||(o=qt[t],qt[t]=i,i=null!=n(e,t,r)?t.toLowerCase():null,qt[t]=o),i}:qt[t]=function(e,t,n){if(!n)return e[pe.camelCase("default-"+t)]?t.toLowerCase():null}}),Mt&&Ft||(pe.attrHooks.value={set:function(e,t,n){return pe.nodeName(e,"input")?void(e.defaultValue=t):Lt&&Lt.set(e,t,n)}}),Ft||(Lt={set:function(e,t,n){var r=e.getAttributeNode(n);if(r||e.setAttributeNode(r=e.ownerDocument.createAttribute(n)),r.value=t+="","value"===n||t===e.getAttribute(n))return t}},qt.id=qt.name=qt.coords=function(e,t,n){var r;if(!n)return(r=e.getAttributeNode(t))&&""!==r.value?r.value:null},pe.valHooks.button={get:function(e,t){var n=e.getAttributeNode(t);if(n&&n.specified)return n.value},set:Lt.set},pe.attrHooks.contenteditable={set:function(e,t,n){Lt.set(e,""!==t&&t,n)}},pe.each(["width","height"],function(e,t){pe.attrHooks[t]={set:function(e,n){if(""===n)return e.setAttribute(t,"auto"),n}}})),fe.style||(pe.attrHooks.style={get:function(e){return e.style.cssText||void 0},set:function(e,t){return e.style.cssText=t+""}});var Ot=/^(?:input|select|textarea|button|object)$/i,Rt=/^(?:a|area)$/i;pe.fn.extend({prop:function(e,t){return Pe(this,pe.prop,e,t,arguments.length>1)},removeProp:function(e){return e=pe.propFix[e]||e,this.each(function(){try{this[e]=void 0,delete this[e]}catch(t){}})}}),pe.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&pe.isXMLDoc(e)||(t=pe.propFix[t]||t,i=pe.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=pe.find.attr(e,"tabindex");return t?parseInt(t,10):Ot.test(e.nodeName)||Rt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),fe.hrefNormalized||pe.each(["href","src"],function(e,t){pe.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),fe.optSelected||(pe.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),pe.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){pe.propFix[this.toLowerCase()]=this}),fe.enctype||(pe.propFix.enctype="encoding");var Pt=/[\t\r\n\f]/g;pe.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(pe.isFunction(e))return this.each(function(t){pe(this).addClass(e.call(this,t,z(this)))});if("string"==typeof e&&e)for(t=e.match(De)||[];n=this[u++];)if(i=z(n),r=1===n.nodeType&&(" "+i+" ").replace(Pt," ")){for(a=0;o=t[a++];)r.indexOf(" "+o+" ")<0&&(r+=o+" ");s=pe.trim(r),i!==s&&pe.attr(n,"class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(pe.isFunction(e))return this.each(function(t){pe(this).removeClass(e.call(this,t,z(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof e&&e)for(t=e.match(De)||[];n=this[u++];)if(i=z(n),r=1===n.nodeType&&(" "+i+" ").replace(Pt," ")){for(a=0;o=t[a++];)for(;r.indexOf(" "+o+" ")>-1;)r=r.replace(" "+o+" "," ");s=pe.trim(r),i!==s&&pe.attr(n,"class",s)}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):pe.isFunction(e)?this.each(function(n){pe(this).toggleClass(e.call(this,n,z(this),t),t)}):this.each(function(){var t,r,i,o;if("string"===n)for(r=0,i=pe(this),o=e.match(De)||[];t=o[r++];)i.hasClass(t)?i.removeClass(t):i.addClass(t);else void 0!==e&&"boolean"!==n||(t=z(this),t&&pe._data(this,"__className__",t),pe.attr(this,"class",t||e===!1?"":pe._data(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;for(t=" "+e+" ";n=this[r++];)if(1===n.nodeType&&(" "+z(n)+" ").replace(Pt," ").indexOf(t)>-1)return!0;return!1}}),pe.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){pe.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),pe.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}});var Bt=e.location,Wt=pe.now(),It=/\?/,$t=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;pe.parseJSON=function(t){if(e.JSON&&e.JSON.parse)return e.JSON.parse(t+"");var n,r=null,i=pe.trim(t+"");return i&&!pe.trim(i.replace($t,function(e,t,i,o){return n&&t&&(r=0),0===r?e:(n=i||t,r+=!o-!i,"")}))?Function("return "+i)():pe.error("Invalid JSON: "+t)},pe.parseXML=function(t){var n,r;if(!t||"string"!=typeof t)return null;try{e.DOMParser?(r=new e.DOMParser,n=r.parseFromString(t,"text/xml")):(n=new e.ActiveXObject("Microsoft.XMLDOM"),n.async="false",n.loadXML(t))}catch(i){n=void 0}return n&&n.documentElement&&!n.getElementsByTagName("parsererror").length||pe.error("Invalid XML: "+t),n};var zt=/#.*$/,Xt=/([?&])_=[^&]*/,Ut=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Vt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Yt=/^(?:GET|HEAD)$/,Jt=/^\/\//,Gt=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Kt={},Qt={},Zt="*/".concat("*"),en=Bt.href,tn=Gt.exec(en.toLowerCase())||[];pe.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:en,type:"GET",isLocal:Vt.test(tn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Zt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":pe.parseJSON,"text xml":pe.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?V(V(e,pe.ajaxSettings),t):V(pe.ajaxSettings,e)},ajaxPrefilter:X(Kt),ajaxTransport:X(Qt),ajax:function(t,n){function r(t,n,r,i){var o,f,v,x,w,C=n;2!==b&&(b=2,u&&e.clearTimeout(u),c=void 0,s=i||"",T.readyState=t>0?4:0,o=t>=200&&t<300||304===t,r&&(x=Y(d,T,r)),x=J(d,x,T,o),o?(d.ifModified&&(w=T.getResponseHeader("Last-Modified"),w&&(pe.lastModified[a]=w),w=T.getResponseHeader("etag"),w&&(pe.etag[a]=w)),204===t||"HEAD"===d.type?C="nocontent":304===t?C="notmodified":(C=x.state,f=x.data,v=x.error,o=!v)):(v=C,!t&&C||(C="error",t<0&&(t=0))),T.status=t,T.statusText=(n||C)+"",o?g.resolveWith(p,[f,C,T]):g.rejectWith(p,[T,C,v]),T.statusCode(y),y=void 0,l&&h.trigger(o?"ajaxSuccess":"ajaxError",[T,d,o?f:v]),m.fireWith(p,[T,C]),l&&(h.trigger("ajaxComplete",[T,d]),--pe.active||pe.event.trigger("ajaxStop")))}"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,d=pe.ajaxSetup({},n),p=d.context||d,h=d.context&&(p.nodeType||p.jquery)?pe(p):pe.event,g=pe.Deferred(),m=pe.Callbacks("once memory"),y=d.statusCode||{},v={},x={},b=0,w="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!f)for(f={};t=Ut.exec(s);)f[t[1].toLowerCase()]=t[2];t=f[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?s:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=x[n]=x[n]||e,v[e]=t),this},overrideMimeType:function(e){return b||(d.mimeType=e),this},statusCode:function(e){var t;if(e)if(b<2)for(t in e)y[t]=[y[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||w;return c&&c.abort(t),r(0,t),this}};if(g.promise(T).complete=m.add,T.success=T.done,T.error=T.fail,d.url=((t||d.url||en)+"").replace(zt,"").replace(Jt,tn[1]+"//"),d.type=n.method||n.type||d.method||d.type,d.dataTypes=pe.trim(d.dataType||"*").toLowerCase().match(De)||[""],null==d.crossDomain&&(i=Gt.exec(d.url.toLowerCase()),d.crossDomain=!(!i||i[1]===tn[1]&&i[2]===tn[2]&&(i[3]||("http:"===i[1]?"80":"443"))===(tn[3]||("http:"===tn[1]?"80":"443")))),d.data&&d.processData&&"string"!=typeof d.data&&(d.data=pe.param(d.data,d.traditional)),U(Kt,d,n,T),2===b)return T;l=pe.event&&d.global,l&&0===pe.active++&&pe.event.trigger("ajaxStart"),d.type=d.type.toUpperCase(),d.hasContent=!Yt.test(d.type),a=d.url,d.hasContent||(d.data&&(a=d.url+=(It.test(a)?"&":"?")+d.data,delete d.data),d.cache===!1&&(d.url=Xt.test(a)?a.replace(Xt,"$1_="+Wt++):a+(It.test(a)?"&":"?")+"_="+Wt++)),d.ifModified&&(pe.lastModified[a]&&T.setRequestHeader("If-Modified-Since",pe.lastModified[a]),pe.etag[a]&&T.setRequestHeader("If-None-Match",pe.etag[a])),(d.data&&d.hasContent&&d.contentType!==!1||n.contentType)&&T.setRequestHeader("Content-Type",d.contentType),T.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+("*"!==d.dataTypes[0]?", "+Zt+"; q=0.01":""):d.accepts["*"]);for(o in d.headers)T.setRequestHeader(o,d.headers[o]);if(d.beforeSend&&(d.beforeSend.call(p,T,d)===!1||2===b))return T.abort();w="abort";for(o in{success:1,error:1,complete:1})T[o](d[o]);if(c=U(Qt,d,n,T)){if(T.readyState=1,l&&h.trigger("ajaxSend",[T,d]),2===b)return T;d.async&&d.timeout>0&&(u=e.setTimeout(function(){T.abort("timeout")},d.timeout));try{b=1,c.send(v,r)}catch(C){if(!(b<2))throw C;r(-1,C)}}else r(-1,"No Transport");return T},getJSON:function(e,t,n){return pe.get(e,t,n,"json")},getScript:function(e,t){return pe.get(e,void 0,t,"script")}}),pe.each(["get","post"],function(e,t){pe[t]=function(e,n,r,i){return pe.isFunction(n)&&(i=i||r,r=n,n=void 0),pe.ajax(pe.extend({url:e,type:t,dataType:i,data:n,success:r},pe.isPlainObject(e)&&e))}}),pe._evalUrl=function(e){return pe.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},pe.fn.extend({wrapAll:function(e){if(pe.isFunction(e))return this.each(function(t){pe(this).wrapAll(e.call(this,t))});if(this[0]){var t=pe(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstChild&&1===e.firstChild.nodeType;)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return pe.isFunction(e)?this.each(function(t){pe(this).wrapInner(e.call(this,t))}):this.each(function(){var t=pe(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=pe.isFunction(e);return this.each(function(n){pe(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){pe.nodeName(this,"body")||pe(this).replaceWith(this.childNodes)}).end()}}),pe.expr.filters.hidden=function(e){return fe.reliableHiddenOffsets()?e.offsetWidth<=0&&e.offsetHeight<=0&&!e.getClientRects().length:K(e)},pe.expr.filters.visible=function(e){return!pe.expr.filters.hidden(e)};var nn=/%20/g,rn=/\[\]$/,on=/\r?\n/g,an=/^(?:submit|button|image|reset|file)$/i,sn=/^(?:input|select|textarea|keygen)/i;pe.param=function(e,t){var n,r=[],i=function(e,t){t=pe.isFunction(t)?t():null==t?"":t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(void 0===t&&(t=pe.ajaxSettings&&pe.ajaxSettings.traditional),pe.isArray(e)||e.jquery&&!pe.isPlainObject(e))pe.each(e,function(){i(this.name,this.value)});else for(n in e)Q(n,e[n],t,i);return r.join("&").replace(nn,"+")},pe.fn.extend({serialize:function(){return pe.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=pe.prop(this,"elements");return e?pe.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!pe(this).is(":disabled")&&sn.test(this.nodeName)&&!an.test(e)&&(this.checked||!Be.test(e))}).map(function(e,t){var n=pe(this).val();return null==n?null:pe.isArray(n)?pe.map(n,function(e){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),pe.ajaxSettings.xhr=void 0!==e.ActiveXObject?function(){return this.isLocal?ee():re.documentMode>8?Z():/^(get|post|head|put|delete|options)$/i.test(this.type)&&Z()||ee()}:Z;var un=0,ln={},cn=pe.ajaxSettings.xhr();e.attachEvent&&e.attachEvent("onunload",function(){for(var e in ln)ln[e](void 0,!0)}),fe.cors=!!cn&&"withCredentials"in cn,cn=fe.ajax=!!cn,cn&&pe.ajaxTransport(function(t){if(!t.crossDomain||fe.cors){var n;return{send:function(r,i){var o,a=t.xhr(),s=++un;if(a.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(o in t.xhrFields)a[o]=t.xhrFields[o];t.mimeType&&a.overrideMimeType&&a.overrideMimeType(t.mimeType),t.crossDomain||r["X-Requested-With"]||(r["X-Requested-With"]="XMLHttpRequest");for(o in r)void 0!==r[o]&&a.setRequestHeader(o,r[o]+"");a.send(t.hasContent&&t.data||null),n=function(e,r){var o,u,l;if(n&&(r||4===a.readyState))if(delete ln[s],n=void 0,a.onreadystatechange=pe.noop,r)4!==a.readyState&&a.abort();else{l={},o=a.status,"string"==typeof a.responseText&&(l.text=a.responseText);try{u=a.statusText}catch(c){u=""}o||!t.isLocal||t.crossDomain?1223===o&&(o=204):o=l.text?200:404}l&&i(o,u,l,a.getAllResponseHeaders())},t.async?4===a.readyState?e.setTimeout(n):a.onreadystatechange=ln[s]=n:n()},abort:function(){n&&n(void 0,!0)}}}}),pe.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return pe.globalEval(e),e}}}),pe.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),pe.ajaxTransport("script",function(e){if(e.crossDomain){var t,n=re.head||pe("head")[0]||re.documentElement;return{send:function(r,i){t=re.createElement("script"),t.async=!0,e.scriptCharset&&(t.charset=e.scriptCharset),t.src=e.url,t.onload=t.onreadystatechange=function(e,n){(n||!t.readyState||/loaded|complete/.test(t.readyState))&&(t.onload=t.onreadystatechange=null,t.parentNode&&t.parentNode.removeChild(t),t=null,n||i(200,"success"))},n.insertBefore(t,n.firstChild)},abort:function(){t&&t.onload(void 0,!0)}}}});var fn=[],dn=/(=)\?(?=&|$)|\?\?/;pe.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=fn.pop()||pe.expando+"_"+Wt++;return this[e]=!0,e}}),pe.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,a,s=t.jsonp!==!1&&(dn.test(t.url)?"url":"string"==typeof t.data&&0===(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&dn.test(t.data)&&"data");if(s||"jsonp"===t.dataTypes[0])return i=t.jsonpCallback=pe.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,s?t[s]=t[s].replace(dn,"$1"+i):t.jsonp!==!1&&(t.url+=(It.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return a||pe.error(i+" was not called"),a[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){a=arguments},r.always(function(){void 0===o?pe(e).removeProp(i):e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,fn.push(i)),a&&pe.isFunction(o)&&o(a[0]),a=o=void 0}),"script"}),pe.parseHTML=function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||re;var r=Te.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=y([e],t,i),i&&i.length&&pe(i).remove(),pe.merge([],r.childNodes))};var pn=pe.fn.load;return pe.fn.load=function(e,t,n){if("string"!=typeof e&&pn)return pn.apply(this,arguments);var r,i,o,a=this,s=e.indexOf(" ");return s>-1&&(r=pe.trim(e.slice(s,e.length)),e=e.slice(0,s)),pe.isFunction(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),a.length>0&&pe.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?pe("
        ").append(pe.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},pe.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){pe.fn[t]=function(e){return this.on(t,e)}}),pe.expr.filters.animated=function(e){return pe.grep(pe.timers,function(t){return e===t.elem}).length},pe.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l,c=pe.css(e,"position"),f=pe(e),d={};"static"===c&&(e.style.position="relative"),s=f.offset(),o=pe.css(e,"top"),u=pe.css(e,"left"),l=("absolute"===c||"fixed"===c)&&pe.inArray("auto",[o,u])>-1,l?(r=f.position(),a=r.top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),pe.isFunction(t)&&(t=t.call(e,n,pe.extend({},s))),null!=t.top&&(d.top=t.top-s.top+a),null!=t.left&&(d.left=t.left-s.left+i),"using"in t?t.using.call(e,d):f.css(d)}},pe.fn.extend({offset:function(e){if(arguments.length)return void 0===e?this:this.each(function(t){pe.offset.setOffset(this,e,t)});var t,n,r={top:0,left:0},i=this[0],o=i&&i.ownerDocument;if(o)return t=o.documentElement,pe.contains(t,i)?("undefined"!=typeof i.getBoundingClientRect&&(r=i.getBoundingClientRect()),n=te(o),{top:r.top+(n.pageYOffset||t.scrollTop)-(t.clientTop||0),left:r.left+(n.pageXOffset||t.scrollLeft)-(t.clientLeft||0)}):r},position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===pe.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),pe.nodeName(e[0],"html")||(n=e.offset()),n.top+=pe.css(e[0],"borderTopWidth",!0),n.left+=pe.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-pe.css(r,"marginTop",!0),left:t.left-n.left-pe.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){ +for(var e=this.offsetParent;e&&!pe.nodeName(e,"html")&&"static"===pe.css(e,"position");)e=e.offsetParent;return e||pt})}}),pe.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,t){var n=/Y/.test(t);pe.fn[e]=function(r){return Pe(this,function(e,r,i){var o=te(e);return void 0===i?o?t in o?o[t]:o.document.documentElement[r]:e[r]:void(o?o.scrollTo(n?pe(o).scrollLeft():i,n?i:pe(o).scrollTop()):e[r]=i)},e,r,arguments.length,null)}}),pe.each(["top","left"],function(e,t){pe.cssHooks[t]=L(fe.pixelPosition,function(e,n){if(n)return n=gt(e,t),ft.test(n)?pe(e).position()[t]+"px":n})}),pe.each({Height:"height",Width:"width"},function(e,t){pe.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){pe.fn[r]=function(r,i){var o=arguments.length&&(n||"boolean"!=typeof r),a=n||(r===!0||i===!0?"margin":"border");return Pe(this,function(t,n,r){var i;return pe.isWindow(t)?t.document.documentElement["client"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body["scroll"+e],i["scroll"+e],t.body["offset"+e],i["offset"+e],i["client"+e])):void 0===r?pe.css(t,n,a):pe.style(t,n,r,a)},t,o?r:void 0,o,null)}})}),pe.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}}),pe.fn.size=function(){return this.length},pe.fn.andSelf=pe.fn.addBack,layui.define(function(e){layui.$=pe,e("jquery",pe)}),pe});!function(e,t){"use strict";var i,n,a=e.layui&&layui.define,o={getPath:function(){var e=document.currentScript?document.currentScript.src:function(){for(var e,t=document.scripts,i=t.length-1,n=i;n>0;n--)if("interactive"===t[n].readyState){e=t[n].src;break}return e||t[i].src}();return e.substring(0,e.lastIndexOf("/")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:["确定","取消"],type:["dialog","page","iframe","loading","tips"],getStyle:function(t,i){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](i)},link:function(t,i,n){if(r.path){var a=document.getElementsByTagName("head")[0],s=document.createElement("link");"string"==typeof i&&(n=i);var l=(n||t).replace(/\.|\//g,""),f="layuicss-"+l,c=0;s.rel="stylesheet",s.href=r.path+t,s.id=f,document.getElementById(f)||a.appendChild(s),"function"==typeof i&&!function u(){return++c>80?e.console&&console.error("layer.css: Invalid"):void(1989===parseInt(o.getStyle(document.getElementById(f),"width"))?i():setTimeout(u,100))}()}}},r={v:"3.1.1",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||"ActiveXObject"in e)&&((t.match(/msie\s(\d+)/)||[])[1]||"11")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,"string"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss("modules/layer/"+e.extend):o.link("theme/"+e.extend),this):this},ready:function(e){var t="layer",i="",n=(a?"modules/layer/":"theme/")+"default/layer.css?v="+r.v+i;return a?layui.addcss(n,e,t):o.link(n,e,t),this},alert:function(e,t,n){var a="function"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var s="function"==typeof t;return s&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},s?{}:t))},msg:function(e,n,a){var s="function"==typeof n,f=o.config.skin,c=(f?f+" "+f+"-msg":"")||"layui-layer-msg",u=l.anim.length-1;return s&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},s&&!o.config.skin?{skin:c+" layui-layer-hui",anim:u}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+" "+(n.skin||"layui-layer-hui")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:210},n))}},s=function(e){var t=this;t.index=++r.index,t.config=i.extend({},t.config,o.config,e),document.body?t.creat():setTimeout(function(){t.creat()},30)};s.pt=s.prototype;var l=["layui-layer",".layui-layer-title",".layui-layer-main",".layui-layer-dialog","layui-layer-iframe","layui-layer-content","layui-layer-btn","layui-layer-close"];l.anim=["layer-anim-00","layer-anim-01","layer-anim-02","layer-anim-03","layer-anim-04","layer-anim-05","layer-anim-06"],s.pt.config={type:0,shade:.3,fixed:!0,move:l[1],title:"信息",offset:"auto",area:"auto",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},s.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,s=r.zIndex+a,f="object"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),u=r.title?'
        '+(f?r.title[0]:r.title)+"
        ":"";return r.zIndex=s,t([r.shade?'
        ':"",'
        '+(e&&2!=r.type?"":u)+'
        '+(0==r.type&&r.icon!==-1?'':"")+(1==r.type&&e?"":r.content||"")+'
        '+function(){var e=c?'':"";return r.closeBtn&&(e+=''),e}()+""+(r.btn?function(){var e="";"string"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t'+r.btn[t]+"";return'
        '+e+"
        "}():"")+(r.resize?'':"")+"
        "],u,i('
        ')),n},s.pt.creat=function(){var e=this,t=e.config,a=e.index,s=t.content,f="object"==typeof s,c=i("body");if(!t.id||!i("#"+t.id)[0]){switch("string"==typeof t.area&&(t.area="auto"===t.area?["",""]:[t.area,""]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn="btn"in t?t.btn:o.btn[0],r.closeAll("dialog");break;case 2:var s=t.content=f?t.content:[t.content||"","auto"];t.content='';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll("loading");break;case 4:f||(t.content=[t.content,"body"]),t.follow=t.content[1],t.content=t.content[0]+'',delete t.title,t.tips="object"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll("tips")}if(e.vessel(f,function(n,r,u){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i("body").append(n[1])}():function(){s.parents("."+l[0])[0]||(s.data("display",s.css("display")).show().addClass("layui-layer-wrap").wrap(n[1]),i("#"+l[0]+a).find("."+l[5]).before(r))}()}():c.append(n[1]),i(".layui-layer-move")[0]||c.append(o.moveElem=u),e.layero=i("#"+l[0]+a),t.scrollbar||l.html.css("overflow","hidden").attr("layer-full",a)}).auto(a),i("#layui-layer-shade"+e.index).css({"background-color":t.shade[1]||"#000",opacity:t.shade[0]||t.shade}),2==t.type&&6==r.ie&&e.layero.find("iframe").attr("src",s[0]),4==t.type?e.tips():e.offset(),t.fixed&&n.on("resize",function(){e.offset(),(/^\d+%$/.test(t.area[0])||/^\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),l.anim[t.anim]){var u="layer-anim "+l.anim[t.anim];e.layero.addClass(u).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",function(){i(this).removeClass(u)})}t.isOutAnim&&e.layero.data("isOutAnim",!0)}},s.pt.auto=function(e){var t=this,a=t.config,o=i("#"+l[0]+e);""===a.area[0]&&a.maxWidth>0&&(r.ie&&r.ie<8&&a.btn&&o.width(o.innerWidth()),o.outerWidth()>a.maxWidth&&o.width(a.maxWidth));var s=[o.innerWidth(),o.innerHeight()],f=o.find(l[1]).outerHeight()||0,c=o.find("."+l[6]).outerHeight()||0,u=function(e){e=o.find(e),e.height(s[1]-f-c-2*(0|parseFloat(e.css("padding-top"))))};switch(a.type){case 2:u("iframe");break;default:""===a.area[1]?a.maxHeight>0&&o.outerHeight()>a.maxHeight?(s[1]=a.maxHeight,u("."+l[5])):a.fixed&&s[1]>=n.height()&&(s[1]=n.height(),u("."+l[5])):u("."+l[5])}return t},s.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o="object"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(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=n.width()-a[0]:"b"===t.offset?e.offsetTop=n.height()-a[1]:"l"===t.offset?e.offsetLeft=0:"lt"===t.offset?(e.offsetTop=0,e.offsetLeft=0):"lb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):"rt"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):"rb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr("minLeft")&&(e.offsetTop=n.height()-(i.find(l[1]).outerHeight()||0),e.offsetLeft=i.css("left")),i.css({top:e.offsetTop,left:e.offsetLeft})},s.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i("body"));var s={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(".layui-layer-TipsG"),c=t.tips[0];t.tips[1]||f.remove(),s.autoLeft=function(){s.left+o[0]-n.width()>0?(s.tipLeft=s.left+s.width-o[0],f.css({right:12,left:"auto"})):s.tipLeft=s.left},s.where=[function(){s.autoLeft(),s.tipTop=s.top-o[1]-10,f.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left+s.width+10,s.tipTop=s.top,f.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color",t.tips[1])},function(){s.autoLeft(),s.tipTop=s.top+s.height+10,f.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left-o[0]-10,s.tipTop=s.top,f.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color",t.tips[1])}],s.where[c-1](),1===c?s.top-(n.scrollTop()+o[1]+16)<0&&s.where[2]():2===c?n.width()-(s.left+s.width+o[0]+16)>0||s.where[3]():3===c?s.top-n.scrollTop()+s.height+o[1]+16-n.height()>0&&s.where[0]():4===c&&o[0]+16-s.left>0&&s.where[1](),a.find("."+l[5]).css({"background-color":t.tips[1],"padding-right":t.closeBtn?"30px":""}),a.css({left:s.tipLeft-(t.fixed?n.scrollLeft():0),top:s.tipTop-(t.fixed?n.scrollTop():0)})},s.pt.move=function(){var e=this,t=e.config,a=i(document),s=e.layero,l=s.find(t.move),f=s.find(".layui-layer-resize"),c={};return t.move&&l.css("cursor","move"),l.on("mousedown",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(s.css("left")),e.clientY-parseFloat(s.css("top"))],o.moveElem.css("cursor","move").show())}),f.on("mousedown",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[s.outerWidth(),s.outerHeight()],o.moveElem.css("cursor","se-resize").show()}),a.on("mousemove",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],l="fixed"===s.css("position");if(i.preventDefault(),c.stX=l?0:n.scrollLeft(),c.stY=l?0:n.scrollTop(),!t.moveOut){var f=n.width()-s.outerWidth()+c.stX,u=n.height()-s.outerHeight()+c.stY;af&&(a=f),ou&&(o=u)}s.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0,t.resizing&&t.resizing(s)}}).on("mouseup",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd(s)),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},s.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find("iframe").on("load",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find("."+l[6]).children("a").on("click",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a["btn"+(e+1)]&&a["btn"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find("."+l[7]).on("click",e),a.shadeClose&&i("#layui-layer-shade"+t.index).on("click",function(){r.close(t.index)}),n.find(".layui-layer-min").on("click",function(){var e=a.min&&a.min(n);e===!1||r.min(t.index,a)}),n.find(".layui-layer-max").on("click",function(){i(this).hasClass("layui-layer-maxmin")?(r.restore(t.index),a.restore&&a.restore(n)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i("select"),function(e,t){var n=i(this);n.parents("."+l[0])[0]||1==n.attr("layer")&&i("."+l[0]).length<1&&n.removeAttr("layer").show(),n=null})},s.pt.IE6=function(e){i("select").each(function(e,t){var n=i(this);n.parents("."+l[0])[0]||"none"===n.css("display")||n.attr({layer:"1"}).hide(),n=null})},s.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css("z-index",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on("mousedown",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css("margin-left"))];e.find(".layui-layer-max").addClass("layui-layer-maxmin"),e.attr({area:t})},o.rescollbar=function(e){l.html.attr("layer-full")==e&&(l.html[0].style.removeProperty?l.html[0].style.removeProperty("overflow"):l.html[0].style.removeAttribute("overflow"),l.html.removeAttr("layer-full"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i("."+l[4]).attr("times"),i("#"+l[0]+t).find("iframe").contents().find(e)},r.getFrameIndex=function(e){return i("#"+e).parents("."+l[4]).attr("times")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame("html",e).outerHeight(),n=i("#"+l[0]+e),a=n.find(l[1]).outerHeight()||0,o=n.find("."+l[6]).outerHeight()||0;n.css({height:t+a+o}),n.find("iframe").css({height:t})}},r.iframeSrc=function(e,t){i("#"+l[0]+e).find("iframe").attr("src",t)},r.style=function(e,t,n){var a=i("#"+l[0]+e),r=a.find(".layui-layer-content"),s=a.attr("type"),f=a.find(l[1]).outerHeight()||0,c=a.find("."+l[6]).outerHeight()||0;a.attr("minLeft");s!==o.type[3]&&s!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find("."+l[6]).outerHeight(),s===o.type[2]?a.find("iframe").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css("padding-top"))-parseFloat(r.css("padding-bottom"))}))},r.min=function(e,t){var a=i("#"+l[0]+e),s=a.find(l[1]).outerHeight()||0,f=a.attr("minLeft")||181*o.minIndex+"px",c=a.css("position");o.record(a),o.minLeft[0]&&(f=o.minLeft[0],o.minLeft.shift()),a.attr("position",c),r.style(e,{width:180,height:s,left:f,top:n.height()-s,position:"fixed",overflow:"hidden"},!0),a.find(".layui-layer-min").hide(),"page"===a.attr("type")&&a.find(l[4]).hide(),o.rescollbar(e),a.attr("minLeft")||o.minIndex++,a.attr("minLeft",f)},r.restore=function(e){var t=i("#"+l[0]+e),n=t.attr("area").split(",");t.attr("type");r.style(e,{width:parseFloat(n[0]),height:parseFloat(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"===t.attr("type")&&t.find(l[4]).show(),o.rescollbar(e)},r.full=function(e){var t,a=i("#"+l[0]+e);o.record(a),l.html.attr("layer-full")||l.html.css("overflow","hidden").attr("layer-full",e),clearTimeout(t),t=setTimeout(function(){var t="fixed"===a.css("position");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(".layui-layer-min").hide()},100)},r.title=function(e,t){var n=i("#"+l[0]+(t||r.index)).find(l[1]);n.html(e)},r.close=function(e){var t=i("#"+l[0]+e),n=t.attr("type"),a="layer-anim-close";if(t[0]){var s="layui-layer-wrap",f=function(){if(n===o.type[1]&&"object"===t.attr("conType")){t.children(":not(."+l[5]+")").remove();for(var a=t.find("."+s),r=0;r<2;r++)a.unwrap();a.css("display",a.data("display")).removeClass(s)}else{if(n===o.type[2])try{var f=i("#"+l[4]+e)[0];f.contentWindow.document.write(""),f.contentWindow.close(),t.find("."+l[5])[0].removeChild(f)}catch(c){}t[0].innerHTML="",t.remove()}"function"==typeof o.end[e]&&o.end[e](),delete o.end[e]};t.data("isOutAnim")&&t.addClass("layer-anim "+a),i("#layui-layer-moves, #layui-layer-shade"+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),t.attr("minLeft")&&(o.minIndex--,o.minLeft.push(t.attr("minLeft"))),r.ie&&r.ie<10||!t.data("isOutAnim")?f():setTimeout(function(){f()},200)}},r.closeAll=function(e){i.each(i("."+l[0]),function(){var t=i(this),n=e?t.attr("type")===e:1;n&&r.close(t.attr("times")),n=null})};var f=r.cache||{},c=function(e){return f.skin?" "+f.skin+" "+f.skin+"-"+e:""};r.prompt=function(e,t){var a="";if(e=e||{},"function"==typeof e&&(t=e),e.area){var o=e.area;a='style="width: '+o[0]+"; height: "+o[1]+';"',delete e.area}var s,l=2==e.formType?'":function(){return''}(),f=e.success;return delete e.success,r.open(i.extend({type:1,btn:["确定","取消"],content:l,skin:"layui-layer-prompt"+c("prompt"),maxWidth:n.width(),success:function(t){s=t.find(".layui-layer-input"),s.val(e.value||"").focus(),"function"==typeof f&&f(t)},resize:!1,yes:function(i){var n=s.val();""===n?s.focus():n.length>(e.maxlength||500)?r.tips("最多输入"+(e.maxlength||500)+"个字数",s,{tips:1}):t&&t(n,i,s)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{},n="layui-this",a=e.success;return delete e.success,r.open(i.extend({type:1,skin:"layui-layer-tab"+c("tab"),resize:!1,title:function(){var e=t.length,i=1,a="";if(e>0)for(a=''+t[0].title+"";i"+t[i].title+"";return a}(),content:'
          '+function(){var e=t.length,i=1,a="";if(e>0)for(a='
        • '+(t[0].content||"no content")+"
        • ";i'+(t[i].content||"no content")+"";return a}()+"
        ",success:function(t){var o=t.find(".layui-layer-title").children(),r=t.find(".layui-layer-tabmain").children();o.on("mousedown",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var a=i(this),o=a.index();a.addClass(n).siblings().removeClass(n),r.eq(o).show().siblings().hide(),"function"==typeof e.change&&e.change(o)}),"function"==typeof a&&a(t)}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var s={};if(t=t||{},t.photos){var l=t.photos.constructor===Object,f=l?t.photos:{},u=f.data||[],d=f.start||0;s.imgIndex=(0|d)+1,t.img=t.img||"img";var y=t.success;if(delete t.success,l){if(0===u.length)return r.msg("没有图片")}else{var p=i(t.photos),h=function(){u=[],p.find(t.img).each(function(e){var t=i(this);t.attr("layer-index",e),u.push({alt:t.attr("alt"),pid:t.attr("layer-pid"),src:t.attr("layer-src")||t.attr("src"),thumb:t.attr("src")})})};if(h(),0===u.length)return;if(n||p.on("click",t.img,function(){var e=i(this),n=e.attr("layer-index");r.photos(i.extend(t,{photos:{start:n,data:u,tab:t.tab},full:t.full}),!0),h()}),!n)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=u.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>u.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){if(!s.end){var t=e.keyCode;e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&r.close(s.index)}},s.tabimg=function(e){if(!(u.length<=1))return f.start=s.imgIndex-1,r.close(s.index),r.photos(t,!0,e)},s.event=function(){s.bigimg.hover(function(){s.imgsee.show()},function(){s.imgsee.hide()}),s.bigimg.find(".layui-layer-imgprev").on("click",function(e){e.preventDefault(),s.imgprev()}),s.bigimg.find(".layui-layer-imgnext").on("click",function(e){e.preventDefault(),s.imgnext()}),i(document).on("keyup",s.keyup)},s.loadi=r.load(1,{shade:!("shade"in t)&&.9,scrollbar:!1}),o(u[d].src,function(n){r.close(s.loadi),s.index=r.open(i.extend({type:1,id:"layui-layer-photos",area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]'+(u[d].alt||
        '+(u.length>1?'':"")+'
        '+(u[d].alt||"")+""+s.imgIndex+"/"+u.length+"
        ",success:function(e,i){s.bigimg=e.find(".layui-layer-phimg"),s.imgsee=e.find(".layui-layer-imguide,.layui-layer-imgbar"),s.event(e),t.tab&&t.tab(u[d],e),"function"==typeof y&&y(e)},end:function(){s.end=!0,i(document).off("keyup",s.keyup)}},t))},function(){r.close(s.loadi),r.msg("当前图片地址异常
        是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){u.length>1&&s.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),l.html=i("html"),r.open=function(e){var t=new s(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define("jquery",function(t){r.path=layui.cache.dir,o.run(layui.$),e.layer=r,t("layer",r)})):"function"==typeof define&&define.amd?define(["jquery"],function(){return o.run(e.jQuery),r}):function(){o.run(e.jQuery),r.ready()}()}(window);layui.define("jquery",function(t){"use strict";var a=layui.$,i=(layui.hint(),layui.device()),e="element",l="layui-this",n="layui-show",s=function(){this.config={}};s.prototype.set=function(t){var i=this;return a.extend(!0,i.config,t),i},s.prototype.on=function(t,a){return layui.onevent.call(this,e,t,a)},s.prototype.tabAdd=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.children(".layui-tab-bar"),o=l.children(".layui-tab-content"),r='
      • "+(i.title||"unnaming")+"
      • ";return s[0]?s.before(r):n.append(r),o.append('
        '+(i.content||"")+"
        "),f.hideTabMore(!0),f.tabAuto(),this},s.prototype.tabDelete=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.find('>li[lay-id="'+i+'"]');return f.tabDelete(null,s),this},s.prototype.tabChange=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.find('>li[lay-id="'+i+'"]');return f.tabClick.call(s[0],null,null,s),this},s.prototype.tab=function(t){t=t||{},b.on("click",t.headerElem,function(i){var e=a(this).index();f.tabClick.call(this,i,e,null,t)})},s.prototype.progress=function(t,i){var e="layui-progress",l=a("."+e+"[lay-filter="+t+"]"),n=l.find("."+e+"-bar"),s=n.find("."+e+"-text");return n.css("width",i),s.text(i),this};var o=".layui-nav",r="layui-nav-item",c="layui-nav-bar",u="layui-nav-tree",d="layui-nav-child",y="layui-nav-more",h="layui-anim layui-anim-upbit",f={tabClick:function(t,i,s,o){o=o||{};var r=s||a(this),i=i||r.parent().children("li").index(r),c=o.headerElem?r.parent():r.parents(".layui-tab").eq(0),u=o.bodyElem?a(o.bodyElem):c.children(".layui-tab-content").children(".layui-tab-item"),d=r.find("a"),y=c.attr("lay-filter");"javascript:;"!==d.attr("href")&&"_blank"===d.attr("target")||(r.addClass(l).siblings().removeClass(l),u.eq(i).addClass(n).siblings().removeClass(n)),layui.event.call(this,e,"tab("+y+")",{elem:c,index:i})},tabDelete:function(t,i){var n=i||a(this).parent(),s=n.index(),o=n.parents(".layui-tab").eq(0),r=o.children(".layui-tab-content").children(".layui-tab-item"),c=o.attr("lay-filter");n.hasClass(l)&&(n.next()[0]?f.tabClick.call(n.next()[0],null,s+1):n.prev()[0]&&f.tabClick.call(n.prev()[0],null,s-1)),n.remove(),r.eq(s).remove(),setTimeout(function(){f.tabAuto()},50),layui.event.call(this,e,"tabDelete("+c+")",{elem:o,index:s})},tabAuto:function(){var t="layui-tab-more",e="layui-tab-bar",l="layui-tab-close",n=this;a(".layui-tab").each(function(){var s=a(this),o=s.children(".layui-tab-title"),r=(s.children(".layui-tab-content").children(".layui-tab-item"),'lay-stope="tabmore"'),c=a('');if(n===window&&8!=i.ie&&f.hideTabMore(!0),s.attr("lay-allowClose")&&o.find("li").each(function(){var t=a(this);if(!t.find("."+l)[0]){var i=a('');i.on("click",f.tabDelete),t.append(i)}}),"string"!=typeof s.attr("lay-unauto"))if(o.prop("scrollWidth")>o.outerWidth()+1){if(o.find("."+e)[0])return;o.append(c),s.attr("overflow",""),c.on("click",function(a){o[this.title?"removeClass":"addClass"](t),this.title=this.title?"":"收缩"})}else o.find("."+e).remove(),s.removeAttr("overflow")})},hideTabMore:function(t){var i=a(".layui-tab-title");t!==!0&&"tabmore"===a(t.target).attr("lay-stope")||(i.removeClass("layui-tab-more"),i.find(".layui-tab-bar").attr("title",""))},clickThis:function(){var t=a(this),i=t.parents(o),n=i.attr("lay-filter"),s=t.parent(),c=t.siblings("."+d),y="string"==typeof s.attr("lay-unselect");"javascript:;"!==t.attr("href")&&"_blank"===t.attr("target")||y||c[0]||(i.find("."+l).removeClass(l),s.addClass(l)),i.hasClass(u)&&(c.removeClass(h),c[0]&&(s["none"===c.css("display")?"addClass":"removeClass"](r+"ed"),"all"===i.attr("lay-shrink")&&s.siblings().removeClass(r+"ed"))),layui.event.call(this,e,"nav("+n+")",t)},collapse:function(){var t=a(this),i=t.find(".layui-colla-icon"),l=t.siblings(".layui-colla-content"),s=t.parents(".layui-collapse").eq(0),o=s.attr("lay-filter"),r="none"===l.css("display");if("string"==typeof s.attr("lay-accordion")){var c=s.children(".layui-colla-item").children("."+n);c.siblings(".layui-colla-title").children(".layui-colla-icon").html(""),c.removeClass(n)}l[r?"addClass":"removeClass"](n),i.html(r?"":""),layui.event.call(this,e,"collapse("+o+")",{title:t,content:l,show:r})}};s.prototype.init=function(t,e){var l=function(){return e?'[lay-filter="'+e+'"]':""}(),s={tab:function(){f.tabAuto.call({})},nav:function(){var t=200,e={},s={},p={},b=function(l,o,r){var c=a(this),f=c.find("."+d);o.hasClass(u)?l.css({top:c.position().top,height:c.children("a").outerHeight(),opacity:1}):(f.addClass(h),l.css({left:c.position().left+parseFloat(c.css("marginLeft")),top:c.position().top+c.height()-l.height()}),e[r]=setTimeout(function(){l.css({width:c.width(),opacity:1})},i.ie&&i.ie<10?0:t),clearTimeout(p[r]),"block"===f.css("display")&&clearTimeout(s[r]),s[r]=setTimeout(function(){f.addClass(n),c.find("."+y).addClass(y+"d")},300))};a(o+l).each(function(i){var l=a(this),o=a(''),h=l.find("."+r);l.find("."+c)[0]||(l.append(o),h.on("mouseenter",function(){b.call(this,o,l,i)}).on("mouseleave",function(){l.hasClass(u)||(clearTimeout(s[i]),s[i]=setTimeout(function(){l.find("."+d).removeClass(n),l.find("."+y).removeClass(y+"d")},300))}),l.on("mouseleave",function(){clearTimeout(e[i]),p[i]=setTimeout(function(){l.hasClass(u)?o.css({height:0,top:o.position().top+o.height()/2,opacity:0}):o.css({width:0,left:o.position().left+o.width()/2,opacity:0})},t)})),h.find("a").each(function(){var t=a(this),i=(t.parent(),t.siblings("."+d));i[0]&&!t.children("."+y)[0]&&t.append(''),t.off("click",f.clickThis).on("click",f.clickThis)})})},breadcrumb:function(){var t=".layui-breadcrumb";a(t+l).each(function(){var t=a(this),i="lay-separator",e=t.attr(i)||"/",l=t.find("a");l.next("span["+i+"]")[0]||(l.each(function(t){t!==l.length-1&&a(this).after(""+e+"")}),t.css("visibility","visible"))})},progress:function(){var t="layui-progress";a("."+t+l).each(function(){var i=a(this),e=i.find(".layui-progress-bar"),l=e.attr("lay-percent");e.css("width",function(){return/^.+\/.+$/.test(l)?100*new Function("return "+l)()+"%":l}()),i.attr("lay-showPercent")&&setTimeout(function(){e.html(''+l+"")},350)})},collapse:function(){var t="layui-collapse";a("."+t+l).each(function(){var t=a(this).find(".layui-colla-item");t.each(function(){var t=a(this),i=t.find(".layui-colla-title"),e=t.find(".layui-colla-content"),l="none"===e.css("display");i.find(".layui-colla-icon").remove(),i.append(''+(l?"":"")+""),i.off("click",f.collapse).on("click",f.collapse)})})}};return s[t]?s[t]():layui.each(s,function(t,a){a()})},s.prototype.render=s.prototype.init;var p=new s,b=a(document);p.render();var v=".layui-tab-title li";b.on("click",v,f.tabClick),b.on("click",f.hideTabMore),a(window).on("resize",f.tabAuto),t(e,p)});layui.define("layer",function(e){"use strict";var t=layui.$,i=layui.layer,n=layui.hint(),o=layui.device(),a={config:{},set:function(e){var i=this;return i.config=t.extend({},i.config,e),i},on:function(e,t){return layui.onevent.call(this,r,e,t)}},l=function(){var e=this;return{upload:function(t){e.upload.call(e,t)},reload:function(t){e.reload.call(e,t)},config:e.config}},r="upload",u="layui-upload-file",c="layui-upload-form",f="layui-upload-iframe",s="layui-upload-choose",p=function(e){var i=this;i.config=t.extend({},i.config,a.config,e),i.render()};p.prototype.config={accept:"images",exts:"",auto:!0,bindAction:"",url:"",field:"file",acceptMime:"",method:"post",data:{},drag:!0,size:0,number:0,multiple:!1},p.prototype.render=function(e){var i=this,e=i.config;e.elem=t(e.elem),e.bindAction=t(e.bindAction),i.file(),i.events()},p.prototype.file=function(){var e=this,i=e.config,n=e.elemFile=t(['"].join("")),a=i.elem.next();(a.hasClass(u)||a.hasClass(c))&&a.remove(),o.ie&&o.ie<10&&i.elem.wrap('
        '),e.isFile()?(e.elemFile=i.elem,i.field=i.elem[0].name):i.elem.after(n),o.ie&&o.ie<10&&e.initIE()},p.prototype.initIE=function(){var e=this,i=e.config,n=t(''),o=t(['
        ',"
        "].join(""));t("#"+f)[0]||t("body").append(n),i.elem.next().hasClass(c)||(e.elemFile.wrap(o),i.elem.next("."+c).append(function(){var e=[];return layui.each(i.data,function(t,i){i="function"==typeof i?i():i,e.push('')}),e.join("")}()))},p.prototype.msg=function(e){return i.msg(e,{icon:2,shift:6})},p.prototype.isFile=function(){var e=this.config.elem[0];if(e)return"input"===e.tagName.toLocaleLowerCase()&&"file"===e.type},p.prototype.preview=function(e){var t=this;window.FileReader&&layui.each(t.chooseFiles,function(t,i){var n=new FileReader;n.readAsDataURL(i),n.onload=function(){e&&e(t,i,this.result)}})},p.prototype.upload=function(e,i){var n,a=this,l=a.config,r=a.elemFile[0],u=function(){var i=0,n=0,o=e||a.files||a.chooseFiles||r.files,u=function(){l.multiple&&i+n===a.fileLength&&"function"==typeof l.allDone&&l.allDone({total:a.fileLength,successful:i,aborted:n})};layui.each(o,function(e,o){var r=new FormData;r.append(l.field,o),layui.each(l.data,function(e,t){t="function"==typeof t?t():t,r.append(e,t)}),t.ajax({url:l.url,type:"post",data:r,contentType:!1,processData:!1,dataType:"json",headers:l.headers||{},success:function(t){i++,d(e,t),u()},error:function(){n++,a.msg("请求上传接口出现异常"),m(e),u()},xhr:function(){var e=new XMLHttpRequest;return e.upload.addEventListener("progress",function(e){if(e.lengthComputable){var t=Math.floor(e.loaded/e.total*100);"function"==typeof l.progress&&l.progress(t,e)}}),e}})})},c=function(){var e=t("#"+f);a.elemFile.parent().submit(),clearInterval(p.timer),p.timer=setInterval(function(){var t,i=e.contents().find("body");try{t=i.text()}catch(n){a.msg("获取上传后的响应信息出现异常"),clearInterval(p.timer),m()}t&&(clearInterval(p.timer),i.html(""),d(0,t))},30)},d=function(e,t){if(a.elemFile.next("."+s).remove(),r.value="","object"!=typeof t)try{t=JSON.parse(t)}catch(i){return t={},a.msg("请对上传接口返回有效JSON")}"function"==typeof l.done&&l.done(t,e||0,function(e){a.upload(e)})},m=function(e){l.auto&&(r.value=""),"function"==typeof l.error&&l.error(e||0,function(e){a.upload(e)})},h=l.exts,v=function(){var t=[];return layui.each(e||a.chooseFiles,function(e,i){t.push(i.name)}),t}(),g={preview:function(e){a.preview(e)},upload:function(e,t){var i={};i[e]=t,a.upload(i)},pushFile:function(){return a.files=a.files||{},layui.each(a.chooseFiles,function(e,t){a.files[e]=t}),a.files},resetFile:function(e,t,i){var n=new File([t],i);a.files=a.files||{},a.files[e]=n}},y=function(){if("choose"!==i&&!l.auto||(l.choose&&l.choose(g),"choose"!==i))return l.before&&l.before(g),o.ie?o.ie>9?u():c():void u()};if(v=0===v.length?r.value.match(/[^\/\\]+\..+/g)||[]||"":v,0!==v.length){switch(l.accept){case"file":if(h&&!RegExp("\\w\\.("+h+")$","i").test(escape(v)))return a.msg("选择的文件中包含不支持的格式"),r.value="";break;case"video":if(!RegExp("\\w\\.("+(h||"avi|mp4|wma|rmvb|rm|flash|3gp|flv")+")$","i").test(escape(v)))return a.msg("选择的视频中包含不支持的格式"),r.value="";break;case"audio":if(!RegExp("\\w\\.("+(h||"mp3|wav|mid")+")$","i").test(escape(v)))return a.msg("选择的音频中包含不支持的格式"),r.value="";break;default:if(layui.each(v,function(e,t){RegExp("\\w\\.("+(h||"jpg|png|gif|bmp|jpeg$")+")","i").test(escape(t))||(n=!0)}),n)return a.msg("选择的图片中包含不支持的格式"),r.value=""}if(a.fileLength=function(){var t=0,i=e||a.files||a.chooseFiles||r.files;return layui.each(i,function(){t++}),t}(),l.number&&a.fileLength>l.number)return a.msg("同时最多只能上传的数量为:"+l.number);if(l.size>0&&!(o.ie&&o.ie<10)){var F;if(layui.each(a.chooseFiles,function(e,t){if(t.size>1024*l.size){var i=l.size/1024;i=i>=1?i.toFixed(2)+"MB":l.size+"KB",r.value="",F=i}}),F)return a.msg("文件不能超过"+F)}y()}},p.prototype.reload=function(e){e=e||{},delete e.elem,delete e.bindAction;var i=this,e=i.config=t.extend({},i.config,a.config,e),n=e.elem.next();n.attr({name:e.name,accept:e.acceptMime,multiple:e.multiple})},p.prototype.events=function(){var e=this,i=e.config,a=function(t){e.chooseFiles={},layui.each(t,function(t,i){var n=(new Date).getTime();e.chooseFiles[n+"-"+t]=i})},l=function(t,n){var o=e.elemFile,a=t.length>1?t.length+"个文件":(t[0]||{}).name||o[0].value.match(/[^\/\\]+\..+/g)||[]||"";o.next().hasClass(s)&&o.next().remove(),e.upload(null,"choose"),e.isFile()||i.choose||o.after(''+a+"")};i.elem.off("upload.start").on("upload.start",function(){var o=t(this),a=o.attr("lay-data");if(a)try{a=new Function("return "+a)(),e.config=t.extend({},i,a)}catch(l){n.error("Upload element property lay-data configuration item has a syntax error: "+a)}e.config.item=o,e.elemFile[0].click()}),o.ie&&o.ie<10||i.elem.off("upload.over").on("upload.over",function(){var e=t(this);e.attr("lay-over","")}).off("upload.leave").on("upload.leave",function(){var e=t(this);e.removeAttr("lay-over")}).off("upload.drop").on("upload.drop",function(n,o){var r=t(this),u=o.originalEvent.dataTransfer.files||[];r.removeAttr("lay-over"),a(u),i.auto?e.upload(u):l(u)}),e.elemFile.off("upload.change").on("upload.change",function(){var t=this.files||[];a(t),i.auto?e.upload():l(t)}),i.bindAction.off("upload.action").on("upload.action",function(){e.upload()}),i.elem.data("haveEvents")||(e.elemFile.on("change",function(){t(this).trigger("upload.change")}),i.elem.on("click",function(){e.isFile()||t(this).trigger("upload.start")}),i.drag&&i.elem.on("dragover",function(e){e.preventDefault(),t(this).trigger("upload.over")}).on("dragleave",function(e){t(this).trigger("upload.leave")}).on("drop",function(e){e.preventDefault(),t(this).trigger("upload.drop",e)}),i.bindAction.on("click",function(){t(this).trigger("upload.action")}),i.elem.data("haveEvents",!0))},a.render=function(e){var t=new p(e);return l.call(t)},e(r,a)});layui.define("jquery",function(e){"use strict";var i=layui.jquery,t={config:{},index:layui.slider?layui.slider.index+1e4:0,set:function(e){var t=this;return t.config=i.extend({},t.config,e),t},on:function(e,i){return layui.onevent.call(this,n,e,i)}},a=function(){var e=this,i=e.config;return{setValue:function(i,t){return e.slide("set",i,t||0)},config:i}},n="slider",l="layui-disabled",s="layui-slider",r="layui-slider-bar",o="layui-slider-wrap",u="layui-slider-wrap-btn",d="layui-slider-tips",v="layui-slider-input",c="layui-slider-input-txt",m="layui-slider-input-btn",p="layui-slider-hover",f=function(e){var a=this;a.index=++t.index,a.config=i.extend({},a.config,t.config,e),a.render()};f.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:"#009688"},f.prototype.render=function(){var e=this,t=e.config;if(t.step<1&&(t.step=1),t.maxt.min?a:t.min,t.value[1]=n>t.min?n:t.min,t.value[0]=t.value[0]>t.max?t.max:t.value[0],t.value[1]=t.value[1]>t.max?t.max:t.value[1];var r=Math.floor((t.value[0]-t.min)/(t.max-t.min)*100),v=Math.floor((t.value[1]-t.min)/(t.max-t.min)*100),m=v-r+"%";r+="%",v+="%"}else{"object"==typeof t.value&&(t.value=Math.min.apply(null,t.value)),t.valuet.max&&(t.value=t.max);var m=Math.floor((t.value-t.min)/(t.max-t.min)*100)+"%"}var p=t.disabled?"#c2c2c2":t.theme,f='
        '+(t.tips?'
        ':"")+'
        '+(t.range?'
        ':"")+"
        ",h=i(t.elem),y=h.next("."+s);if(y[0]&&y.remove(),e.elemTemp=i(f),t.range?(e.elemTemp.find("."+o).eq(0).data("value",t.value[0]),e.elemTemp.find("."+o).eq(1).data("value",t.value[1])):e.elemTemp.find("."+o).data("value",t.value),h.html(e.elemTemp),"vertical"===t.type&&e.elemTemp.height(t.height+"px"),t.showstep){for(var g=(t.max-t.min)/t.step,b="",x=1;x')}e.elemTemp.append(b)}if(t.input&&!t.range){var w=i('
        ');h.css("position","relative"),h.append(w),h.find("."+c).children("input").val(t.value),"vertical"===t.type?w.css({left:0,top:-48}):e.elemTemp.css("margin-right",w.outerWidth()+15)}t.disabled?(e.elemTemp.addClass(l),e.elemTemp.find("."+u).addClass(l)):e.slide(),e.elemTemp.find("."+u).on("mouseover",function(){var a="vertical"===t.type?t.height:e.elemTemp[0].offsetWidth,n=e.elemTemp.find("."+o),l="vertical"===t.type?a-i(this).parent()[0].offsetTop-n.height():i(this).parent()[0].offsetLeft,s=l/a*100,r=i(this).parent().data("value"),u=t.setTips?t.setTips(r):r;e.elemTemp.find("."+d).html(u),"vertical"===t.type?e.elemTemp.find("."+d).css({bottom:s+"%","margin-bottom":"20px",display:"inline-block"}):e.elemTemp.find("."+d).css({left:s+"%",display:"inline-block"})}).on("mouseout",function(){e.elemTemp.find("."+d).css("display","none")})},f.prototype.slide=function(e,t,a){var n=this,l=n.config,s=n.elemTemp,f=function(){return"vertical"===l.type?l.height:s[0].offsetWidth},h=s.find("."+o),y=s.next("."+v),g=y.children("."+c).children("input").val(),b=100/((l.max-l.min)/Math.ceil(l.step)),x=function(e,i){e=Math.ceil(e)*b>100?Math.ceil(e)*b:Math.round(e)*b,e=e>100?100:e,h.eq(i).css("vertical"===l.type?"bottom":"left",e+"%");var t=T(h[0].offsetLeft),a=l.range?T(h[1].offsetLeft):0;"vertical"===l.type?(s.find("."+d).css({bottom:e+"%","margin-bottom":"20px"}),t=T(f()-h[0].offsetTop-h.height()),a=l.range?T(f()-h[1].offsetTop-h.height()):0):s.find("."+d).css("left",e+"%"),t=t>100?100:t,a=a>100?100:a;var n=Math.min(t,a),o=Math.abs(t-a);"vertical"===l.type?s.find("."+r).css({height:o+"%",bottom:n+"%"}):s.find("."+r).css({width:o+"%",left:n+"%"});var u=l.min+Math.round((l.max-l.min)*e/100);if(g=u,y.children("."+c).children("input").val(g),h.eq(i).data("value",u),u=l.setTips?l.setTips(u):u,s.find("."+d).html(u),l.range){var v=[h.eq(0).data("value"),h.eq(1).data("value")];v[0]>v[1]&&v.reverse()}l.change&&l.change(l.range?v:u)},T=function(e){var i=e/f()*100/b,t=Math.round(i)*b;return e==f()&&(t=Math.ceil(i)*b),t},w=i(['
        f()&&(r=f());var o=r/f()*100/b;x(o,e),t.addClass(p),s.find("."+d).show(),i.preventDefault()},o=function(){t.removeClass(p),s.find("."+d).hide()};M(r,o)})}),s.on("click",function(e){var t=i("."+u);if(!t.is(event.target)&&0===t.has(event.target).length&&t.length){var a,n="vertical"===l.type?f()-e.clientY+i(this).offset().top:e.clientX-i(this).offset().left;n<0&&(n=0),n>f()&&(n=f());var s=n/f()*100/b;a=l.range?"vertical"===l.type?Math.abs(n-parseInt(i(h[0]).css("bottom")))>Math.abs(n-parseInt(i(h[1]).css("bottom")))?1:0:Math.abs(n-h[0].offsetLeft)>Math.abs(n-h[1].offsetLeft)?1:0:0,x(s,a),e.preventDefault()}}),y.hover(function(){var e=i(this);e.children("."+m).fadeIn("fast")},function(){var e=i(this);e.children("."+m).fadeOut("fast")}),y.children("."+m).children("i").each(function(e){i(this).on("click",function(){g=1==e?g-l.stepl.max?l.max:Number(g)+l.step;var i=(g-l.min)/(l.max-l.min)*100/b;x(i,0)})});var q=function(){var e=this.value;e=isNaN(e)?0:e,e=el.max?l.max:e,this.value=e;var i=(e-l.min)/(l.max-l.min)*100/b;x(i,0)};y.children("."+c).children("input").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),q.call(this))}).on("change",q)},f.prototype.events=function(){var e=this;e.config},t.render=function(e){var i=new f(e);return a.call(i)},e(n,t)});layui.define("jquery",function(e){"use strict";var i=layui.jquery,o={config:{},index:layui.colorpicker?layui.colorpicker.index+1e4:0,set:function(e){var o=this;return o.config=i.extend({},o.config,e),o},on:function(e,i){return layui.onevent.call(this,"colorpicker",e,i)}},r=function(){var e=this,i=e.config;return{config:i}},t="colorpicker",n="layui-show",l="layui-colorpicker",c=".layui-colorpicker-main",a="layui-icon-down",s="layui-icon-close",f="layui-colorpicker-trigger-span",d="layui-colorpicker-trigger-i",u="layui-colorpicker-side",p="layui-colorpicker-side-slider",g="layui-colorpicker-basis",v="layui-colorpicker-alpha-bgcolor",h="layui-colorpicker-alpha-slider",m="layui-colorpicker-basis-cursor",b="layui-colorpicker-main-input",k=function(e){var i={h:0,s:0,b:0},o=Math.min(e.r,e.g,e.b),r=Math.max(e.r,e.g,e.b),t=r-o;return i.b=r,i.s=0!=r?255*t/r:0,0!=i.s?e.r==r?i.h=(e.g-e.b)/t:e.g==r?i.h=2+(e.b-e.r)/t:i.h=4+(e.r-e.g)/t:i.h=-1,r==o&&(i.h=0),i.h*=60,i.h<0&&(i.h+=360),i.s*=100/255,i.b*=100/255,i},y=function(e){var e=e.indexOf("#")>-1?e.substring(1):e;if(3==e.length){var i=e.split("");e=i[0]+i[0]+i[1]+i[1]+i[2]+i[2]}e=parseInt(e,16);var o={r:e>>16,g:(65280&e)>>8,b:255&e};return k(o)},x=function(e){var i={},o=e.h,r=255*e.s/100,t=255*e.b/100;if(0==r)i.r=i.g=i.b=t;else{var n=t,l=(255-r)*t/255,c=(n-l)*(o%60)/60;360==o&&(o=0),o<60?(i.r=n,i.b=l,i.g=l+c):o<120?(i.g=n,i.b=l,i.r=n-c):o<180?(i.g=n,i.r=l,i.b=l+c):o<240?(i.b=n,i.r=l,i.g=n-c):o<300?(i.b=n,i.g=l,i.r=l+c):o<360?(i.r=n,i.g=l,i.b=n-c):(i.r=0,i.g=0,i.b=0)}return{r:Math.round(i.r),g:Math.round(i.g),b:Math.round(i.b)}},C=function(e){var o=x(e),r=[o.r.toString(16),o.g.toString(16),o.b.toString(16)];return i.each(r,function(e,i){1==i.length&&(r[e]="0"+i)}),r.join("")},P=function(e){var i=/[0-9]{1,3}/g,o=e.match(i)||[];return{r:o[0],g:o[1],b:o[2]}},B=i(window),w=i(document),D=function(e){var r=this;r.index=++o.index,r.config=i.extend({},r.config,o.config,e),r.render()};D.prototype.config={color:"",size:null,alpha:!1,format:"hex",predefine:!1,colors:["#009688","#5FB878","#1E9FFF","#FF5722","#FFB800","#01AAED","#999","#c00","#ff8c00","#ffd700","#90ee90","#00ced1","#1e90ff","#c71585","rgb(0, 186, 189)","rgb(255, 120, 0)","rgb(250, 212, 0)","#393D49","rgba(0,0,0,.5)","rgba(255, 69, 0, 0.68)","rgba(144, 240, 144, 0.5)","rgba(31, 147, 255, 0.73)"]},D.prototype.render=function(){var e=this,o=e.config,r=i(['
        ',"",'3&&(o.alpha&&"rgb"==o.format||(e="#"+C(k(P(o.color))))),"background: "+e):e}()+'">','',"","","
        "].join("")),t=i(o.elem);o.size&&r.addClass("layui-colorpicker-"+o.size),t.addClass("layui-inline").html(e.elemColorBox=r),e.color=e.elemColorBox.find("."+f)[0].style.background,e.events()},D.prototype.renderPicker=function(){var e=this,o=e.config,r=e.elemColorBox[0],t=e.elemPicker=i(['
        ','
        ','
        ','
        ','
        ','
        ',"
        ",'
        ','
        ',"
        ","
        ",'
        ','
        ','
        ',"
        ","
        ",function(){if(o.predefine){var e=['
        '];return layui.each(o.colors,function(i,o){e.push(['
        ','
        ',"
        "].join(""))}),e.push("
        "),e.join("")}return""}(),'
        ','
        ','',"
        ",'
        ','','',"","
        "].join(""));e.elemColorBox.find("."+f)[0];i(c)[0]&&i(c).data("index")==e.index?e.removePicker(D.thisElemInd):(e.removePicker(D.thisElemInd),i("body").append(t)),D.thisElemInd=e.index,D.thisColor=r.style.background,e.position(),e.pickerEvents()},D.prototype.removePicker=function(e){var o=this;o.config;return i("#layui-colorpicker"+(e||o.index)).remove(),o},D.prototype.position=function(){var e=this,i=e.config,o=e.bindElem||e.elemColorBox[0],r=e.elemPicker[0],t=o.getBoundingClientRect(),n=r.offsetWidth,l=r.offsetHeight,c=function(e){return e=e?"scrollLeft":"scrollTop",document.body[e]|document.documentElement[e]},a=function(e){return document.documentElement[e?"clientWidth":"clientHeight"]},s=5,f=t.left,d=t.bottom;f-=(n-o.offsetWidth)/2,d+=s,f+n+s>a("width")?f=a("width")-n-s:fa()&&(d=t.top>l?t.top-l:a()-l,d-=2*s),i.position&&(r.style.position=i.position),r.style.left=f+("fixed"===i.position?0:c(1))+"px",r.style.top=d+("fixed"===i.position?0:c())+"px"},D.prototype.val=function(){var e=this,i=(e.config,e.elemColorBox.find("."+f)),o=e.elemPicker.find("."+b),r=i[0],t=r.style.backgroundColor;if(t){var n=k(P(t)),l=i.attr("lay-type");if(e.select(n.h,n.s,n.b),"torgb"===l&&o.find("input").val(t),"rgba"===l){var c=P(t);if(3==(t.match(/[0-9]{1,3}/g)||[]).length)o.find("input").val("rgba("+c.r+", "+c.g+", "+c.b+", 1)"),e.elemPicker.find("."+h).css("left",280);else{o.find("input").val(t);var a=280*t.slice(t.lastIndexOf(",")+1,t.length-1);e.elemPicker.find("."+h).css("left",a)}e.elemPicker.find("."+v)[0].style.background="linear-gradient(to right, rgba("+c.r+", "+c.g+", "+c.b+", 0), rgb("+c.r+", "+c.g+", "+c.b+"))"}}else e.select(0,100,100),o.find("input").val(""),e.elemPicker.find("."+v)[0].style.background="",e.elemPicker.find("."+h).css("left",280)},D.prototype.side=function(){var e=this,o=e.config,r=e.elemColorBox.find("."+f),t=r.attr("lay-type"),n=e.elemPicker.find("."+u),l=e.elemPicker.find("."+p),c=e.elemPicker.find("."+g),y=e.elemPicker.find("."+m),C=e.elemPicker.find("."+v),w=e.elemPicker.find("."+h),D=l[0].offsetTop/180*360,E=100-(y[0].offsetTop+3)/180*100,H=(y[0].offsetLeft+3)/260*100,W=Math.round(w[0].offsetLeft/280*100)/100,j=e.elemColorBox.find("."+d),F=e.elemPicker.find(".layui-colorpicker-pre").children("div"),L=function(i,n,l,c){e.select(i,n,l);var f=x({h:i,s:n,b:l});if(j.addClass(a).removeClass(s),r[0].style.background="rgb("+f.r+", "+f.g+", "+f.b+")","torgb"===t&&e.elemPicker.find("."+b).find("input").val("rgb("+f.r+", "+f.g+", "+f.b+")"),"rgba"===t){var d=0;d=280*c,w.css("left",d),e.elemPicker.find("."+b).find("input").val("rgba("+f.r+", "+f.g+", "+f.b+", "+c+")"),r[0].style.background="rgba("+f.r+", "+f.g+", "+f.b+", "+c+")",C[0].style.background="linear-gradient(to right, rgba("+f.r+", "+f.g+", "+f.b+", 0), rgb("+f.r+", "+f.g+", "+f.b+"))"}o.change&&o.change(e.elemPicker.find("."+b).find("input").val())},M=i(['
        t&&(r=t);var l=r/180*360;D=l,L(l,H,E,W),e.preventDefault()};Y(r),e.preventDefault()}),n.on("click",function(e){var o=e.clientY-i(this).offset().top;o<0&&(o=0),o>this.offsetHeight&&(o=this.offsetHeight);var r=o/180*360;D=r,L(r,H,E,W),e.preventDefault()}),y.on("mousedown",function(e){var i=this.offsetTop,o=this.offsetLeft,r=e.clientY,t=e.clientX,n=function(e){var n=i+(e.clientY-r),l=o+(e.clientX-t),a=c[0].offsetHeight-3,s=c[0].offsetWidth-3;n<-3&&(n=-3),n>a&&(n=a),l<-3&&(l=-3),l>s&&(l=s);var f=(l+3)/260*100,d=100-(n+3)/180*100;E=d,H=f,L(D,f,d,W),e.preventDefault()};layui.stope(e),Y(n),e.preventDefault()}),c.on("mousedown",function(e){var o=e.clientY-i(this).offset().top-3+B.scrollTop(),r=e.clientX-i(this).offset().left-3+B.scrollLeft();o<-3&&(o=-3),o>this.offsetHeight-3&&(o=this.offsetHeight-3),r<-3&&(r=-3),r>this.offsetWidth-3&&(r=this.offsetWidth-3);var t=(r+3)/260*100,n=100-(o+3)/180*100;E=n,H=t,L(D,t,n,W),e.preventDefault(),y.trigger(e,"mousedown")}),w.on("mousedown",function(e){var i=this.offsetLeft,o=e.clientX,r=function(e){var r=i+(e.clientX-o),t=C[0].offsetWidth;r<0&&(r=0),r>t&&(r=t);var n=Math.round(r/280*100)/100;W=n,L(D,H,E,n),e.preventDefault()};Y(r),e.preventDefault()}),C.on("click",function(e){var o=e.clientX-i(this).offset().left;o<0&&(o=0),o>this.offsetWidth&&(o=this.offsetWidth);var r=Math.round(o/280*100)/100;W=r,L(D,H,E,r),e.preventDefault()}),F.each(function(){i(this).on("click",function(){i(this).parent(".layui-colorpicker-pre").addClass("selected").siblings().removeClass("selected");var e,o=this.style.backgroundColor,r=k(P(o)),t=o.slice(o.lastIndexOf(",")+1,o.length-1);D=r.h,H=r.s,E=r.b,3==(o.match(/[0-9]{1,3}/g)||[]).length&&(t=1),W=t,e=280*t,L(r.h,r.s,r.b,t)})})},D.prototype.select=function(e,i,o,r){var t=this,n=(t.config,C({h:e,s:100,b:100})),l=C({h:e,s:i,b:o}),c=e/360*180,a=180-o/100*180-3,s=i/100*260-3;t.elemPicker.find("."+p).css("top",c),t.elemPicker.find("."+g)[0].style.background="#"+n,t.elemPicker.find("."+m).css({top:a,left:s}),"change"!==r&&t.elemPicker.find("."+b).find("input").val("#"+l)},D.prototype.pickerEvents=function(){var e=this,o=e.config,r=e.elemColorBox.find("."+f),t=e.elemPicker.find("."+b+" input"),n={clear:function(i){r[0].style.background="",e.elemColorBox.find("."+d).removeClass(a).addClass(s),e.color="",o.done&&o.done(""),e.removePicker()},confirm:function(i,n){var l=t.val(),c=l,f={};if(l.indexOf(",")>-1){if(f=k(P(l)),e.select(f.h,f.s,f.b),r[0].style.background=c="#"+C(f),(l.match(/[0-9]{1,3}/g)||[]).length>3&&"rgba"===r.attr("lay-type")){var u=280*l.slice(l.lastIndexOf(",")+1,l.length-1);e.elemPicker.find("."+h).css("left",u),r[0].style.background=l,c=l}}else f=y(l),r[0].style.background=c="#"+C(f),e.elemColorBox.find("."+d).removeClass(s).addClass(a);return"change"===n?(e.select(f.h,f.s,f.b,n),void(o.change&&o.change(c))):(e.color=l,o.done&&o.done(l),void e.removePicker())}};e.elemPicker.on("click","*[colorpicker-events]",function(){var e=i(this),o=e.attr("colorpicker-events");n[o]&&n[o].call(this,e)}),t.on("keyup",function(e){var o=i(this);n.confirm.call(this,o,13===e.keyCode?null:"change")})},D.prototype.events=function(){var e=this,o=e.config,r=e.elemColorBox.find("."+f);e.elemColorBox.on("click",function(){e.renderPicker(),i(c)[0]&&(e.val(),e.side())}),o.elem[0]&&!e.elemColorBox[0].eventHandler&&(w.on("click",function(o){if(!i(o.target).hasClass(l)&&!i(o.target).parents("."+l)[0]&&!i(o.target).hasClass(c.replace(/\./g,""))&&!i(o.target).parents(c)[0]&&e.elemPicker){if(e.color){var t=k(P(e.color));e.select(t.h,t.s,t.b)}else e.elemColorBox.find("."+d).removeClass(a).addClass(s);r[0].style.background=e.color||"",e.removePicker()}}),B.on("resize",function(){return!(!e.elemPicker||!i(c)[0])&&void e.position()}),e.elemColorBox[0].eventHandler=!0)},o.render=function(e){var i=new D(e);return r.call(i)},e(t,o)});layui.define("layer",function(e){"use strict";var t=layui.$,i=layui.layer,a=layui.hint(),n=layui.device(),l="form",r=".layui-form",s="layui-this",o="layui-hide",c="layui-disabled",u=function(){this.config={verify:{required:[/[\S]+/,"必填项不能为空"],phone:[/^1\d{10}$/,"请输入正确的手机号"],email:[/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/,"邮箱格式不正确"],url:[/(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/,"链接格式不正确"],number:function(e){if(!e||isNaN(e))return"只能填写数字"},date:[/^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/,"日期格式不正确"],identity:[/(^\d{15}$)|(^\d{17}(x|X|\d)$)/,"请输入正确的身份证号"]}}};u.prototype.set=function(e){var i=this;return t.extend(!0,i.config,e),i},u.prototype.verify=function(e){var i=this;return t.extend(!0,i.config.verify,e),i},u.prototype.on=function(e,t){return layui.onevent.call(this,l,e,t)},u.prototype.val=function(e,i){var a=this,n=t(r+'[lay-filter="'+e+'"]');return n.each(function(e,a){var n=t(this);layui.each(i,function(e,t){var i,a=n.find('[name="'+e+'"]');a[0]&&(i=a[0].type,"checkbox"===i?a[0].checked=t:"radio"===i?a.each(function(){this.value==t&&(this.checked=!0)}):a.val(t))})}),f.render(null,e),a.getValue(e)},u.prototype.getValue=function(e,i){i=i||t(r+'[lay-filter="'+e+'"]').eq(0);var a={},n={},l=i.find("input,select,textarea");return layui.each(l,function(e,t){if(t.name=(t.name||"").replace(/^\s*|\s*&/,""),t.name){if(/^.*\[\]$/.test(t.name)){var i=t.name.match(/^(.*)\[\]$/g)[0];a[i]=0|a[i],t.name=t.name.replace(/^(.*)\[\]$/,"$1["+a[i]++ +"]")}/^checkbox|radio$/.test(t.type)&&!t.checked||(n[t.name]=t.value)}}),n},u.prototype.render=function(e,i){var n=this,u=t(r+function(){return i?'[lay-filter="'+i+'"]':""}()),d={select:function(){var e,i="请选择",a="layui-form-select",n="layui-select-title",r="layui-select-none",d="",f=u.find("select"),v=function(i,l){t(i.target).parent().hasClass(n)&&!l||(t("."+a).removeClass(a+"ed "+a+"up"),e&&d&&e.val(d)),e=null},y=function(i,u,f){var y,p=t(this),m=i.find("."+n),k=m.find("input"),g=i.find("dl"),x=g.children("dd"),b=this.selectedIndex;if(!u){var C=function(){var e=i.offset().top+i.outerHeight()+5-h.scrollTop(),t=g.outerHeight();b=p[0].selectedIndex,i.addClass(a+"ed"),x.removeClass(o),y=null,x.eq(b).addClass(s).siblings().removeClass(s),e+t>h.height()&&e>=t&&i.addClass(a+"up"),T()},w=function(e){i.removeClass(a+"ed "+a+"up"),k.blur(),y=null,e||$(k.val(),function(e){var i=p[0].selectedIndex;e&&(d=t(p[0].options[i]).html(),0===i&&d===k.attr("placeholder")&&(d=""),k.val(d||""))})},T=function(){var e=g.children("dd."+s);if(e[0]){var t=e.position().top,i=g.height(),a=e.height();t>i&&g.scrollTop(t+g.scrollTop()-i+a-5),t<0&&g.scrollTop(t+g.scrollTop()-5)}};m.on("click",function(e){i.hasClass(a+"ed")?w():(v(e,!0),C()),g.find("."+r).remove()}),m.find(".layui-edge").on("click",function(){k.focus()}),k.on("keyup",function(e){var t=e.keyCode;9===t&&C()}).on("keydown",function(e){var t=e.keyCode;9===t&&w();var i=function(t,a){var n,l;e.preventDefault();var r=function(){var e=g.children("dd."+s);if(g.children("dd."+o)[0]&&"next"===t){var i=g.children("dd:not(."+o+",."+c+")"),n=i.eq(0).index();if(n>=0&&n无匹配项

        '):g.find("."+r).remove()},"keyup"),""===t&&g.find("."+r).remove(),void T())};f&&k.on("keyup",q).on("blur",function(i){var a=p[0].selectedIndex;e=k,d=t(p[0].options[a]).html(),0===a&&d===k.attr("placeholder")&&(d=""),setTimeout(function(){$(k.val(),function(e){d||k.val("")},"blur")},200)}),x.on("click",function(){var e=t(this),a=e.attr("lay-value"),n=p.attr("lay-filter");return!e.hasClass(c)&&(e.hasClass("layui-select-tips")?k.val(""):(k.val(e.text()),e.addClass(s)),e.siblings().removeClass(s),p.val(a).removeClass("layui-form-danger"),layui.event.call(this,l,"select("+n+")",{elem:p[0],value:a,othis:i}),w(!0),!1)}),i.find("dl>dt").on("click",function(e){return!1}),t(document).off("click",v).on("click",v)}};f.each(function(e,l){var r=t(this),o=r.next("."+a),u=this.disabled,d=l.value,f=t(l.options[l.selectedIndex]),v=l.options[0];if("string"==typeof r.attr("lay-ignore"))return r.show();var h="string"==typeof r.attr("lay-search"),p=v?v.value?i:v.innerHTML||i:i,m=t(['
        ','
        ','','
        ','
        ',function(e){var t=[];return layui.each(e,function(e,a){0!==e||a.value?"optgroup"===a.tagName.toLowerCase()?t.push("
        "+a.label+"
        "):t.push('
        '+a.innerHTML+"
        "):t.push('
        '+(a.innerHTML||i)+"
        ")}),0===t.length&&t.push('
        没有选项
        '),t.join("")}(r.find("*"))+"
        ","
        "].join(""));o[0]&&o.remove(),r.after(m),y.call(this,m,u,h)})},checkbox:function(){var e={checkbox:["layui-form-checkbox","layui-form-checked","checkbox"],_switch:["layui-form-switch","layui-form-onswitch","switch"]},i=u.find("input[type=checkbox]"),a=function(e,i){var a=t(this);e.on("click",function(){var t=a.attr("lay-filter"),n=(a.attr("lay-text")||"").split("|");a[0].disabled||(a[0].checked?(a[0].checked=!1,e.removeClass(i[1]).find("em").text(n[1])):(a[0].checked=!0,e.addClass(i[1]).find("em").text(n[0])),layui.event.call(a[0],l,i[2]+"("+t+")",{elem:a[0],value:a[0].value,othis:e}))})};i.each(function(i,n){var l=t(this),r=l.attr("lay-skin"),s=(l.attr("lay-text")||"").split("|"),o=this.disabled;"switch"===r&&(r="_"+r);var u=e[r]||e.checkbox;if("string"==typeof l.attr("lay-ignore"))return l.show();var d=l.next("."+u[0]),f=t(['
        ",function(){var e=n.title.replace(/\s/g,""),t={checkbox:[e?""+n.title+"":"",''].join(""),_switch:""+((n.checked?s[0]:s[1])||"")+""};return t[r]||t.checkbox}(),"
        "].join(""));d[0]&&d.remove(),l.after(f),a.call(this,f,u)})},radio:function(){var e="layui-form-radio",i=["",""],a=u.find("input[type=radio]"),n=function(a){var n=t(this),s="layui-anim-scaleSpring";a.on("click",function(){var o=n[0].name,c=n.parents(r),u=n.attr("lay-filter"),d=c.find("input[name="+o.replace(/(\.|#|\[|\])/g,"\\$1")+"]");n[0].disabled||(layui.each(d,function(){var a=t(this).next("."+e);this.checked=!1,a.removeClass(e+"ed"),a.find(".layui-icon").removeClass(s).html(i[1])}),n[0].checked=!0,a.addClass(e+"ed"),a.find(".layui-icon").addClass(s).html(i[0]),layui.event.call(n[0],l,"radio("+u+")",{elem:n[0],value:n[0].value,othis:a}))})};a.each(function(a,l){var r=t(this),s=r.next("."+e),o=this.disabled;if("string"==typeof r.attr("lay-ignore"))return r.show();s[0]&&s.remove();var u=t(['
        ',''+i[l.checked?0:1]+"","
        "+function(){var e=l.title||"";return"string"==typeof r.next().attr("lay-radio")&&(e=r.next().html(),r.next().remove()),e}()+"
        ","
        "].join(""));r.after(u),n.call(this,u)})}};return e?d[e]?d[e]():a.error("不支持的"+e+"表单渲染"):layui.each(d,function(e,t){t()}),n};var d=function(){var e=null,a=f.config.verify,s="layui-form-danger",o={},c=t(this),u=c.parents(r),d=u.find("*[lay-verify]"),v=c.parents("form")[0],h=c.attr("lay-filter");return layui.each(d,function(l,r){var o=t(this),c=o.attr("lay-verify").split("|"),u=o.attr("lay-verType"),d=o.val();if(o.removeClass(s),layui.each(c,function(t,l){var c,f="",v="function"==typeof a[l];if(a[l]){var c=v?f=a[l](d,r):!a[l][0].test(d);if(f=f||a[l][1],"required"===l&&(f=o.attr("lay-reqText")||f),c)return"tips"===u?i.tips(f,function(){return"string"==typeof o.attr("lay-ignore")||"select"!==r.tagName.toLowerCase()&&!/^checkbox|radio$/.test(r.type)?o:o.next()}(),{tips:1}):"alert"===u?i.alert(f,{title:"提示",shadeClose:!0}):i.msg(f,{icon:5,shift:6}),n.android||n.ios||setTimeout(function(){r.focus()},7),o.addClass(s),e=!0}}),e)return e}),!e&&(o=f.getValue(null,u),layui.event.call(this,l,"submit("+h+")",{elem:this,form:v,field:o}))},f=new u,v=t(document),h=t(window);f.render(),v.on("reset",r,function(){var e=t(this).attr("lay-filter");setTimeout(function(){f.render(null,e)},50)}),v.on("submit",r,d).on("click","*[lay-submit]",d),e(l,f)});layui.define("form",function(e){"use strict";var i=layui.$,a=layui.form,n=layui.layer,t="tree",r={config:{},index:layui[t]?layui[t].index+1e4:0,set:function(e){var a=this;return a.config=i.extend({},a.config,e),a},on:function(e,i){return layui.onevent.call(this,t,e,i)}},l=function(){var e=this,i=e.config,a=i.id||e.index;return l.that[a]=e,l.config[a]=i,{config:i,reload:function(i){e.reload.call(e,i)},getChecked:function(){return e.getChecked.call(e)},setChecked:function(i){return e.setChecked.call(e,i)}}},c="layui-hide",d="layui-disabled",s="layui-tree-set",o="layui-tree-iconClick",h="layui-icon-addition",u="layui-icon-subtraction",p="layui-tree-entry",f="layui-tree-main",y="layui-tree-txt",v="layui-tree-pack",C="layui-tree-spread",k="layui-tree-setLineShort",m="layui-tree-showLine",x="layui-tree-lineExtend",b=function(e){var a=this;a.index=++r.index,a.config=i.extend({},a.config,r.config,e),a.render()};b.prototype.config={data:[],showCheckbox:!1,showLine:!0,accordion:!1,onlyIconControl:!1,isJump:!1,edit:!1,text:{defaultNodeName:"未命名",none:"无数据"}},b.prototype.reload=function(e){var a=this;layui.each(e,function(e,i){i.constructor===Array&&delete a.config[e]}),a.config=i.extend(!0,{},a.config,e),a.render()},b.prototype.render=function(){var e=this,a=e.config;e.checkids=[];var n=i('
        ');e.tree(n);var t=a.elem=i(a.elem);if(t[0]){if(e.key=a.id||e.index,e.elem=n,e.elemNone=i('
        '+a.text.none+"
        "),t.html(e.elem),0==e.elem.find(".layui-tree-set").length)return e.elem.append(e.elemNone);a.showCheckbox&&e.renderForm("checkbox"),e.elem.find(".layui-tree-set").each(function(){var e=i(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(k),e.next()[0]||e.parents(".layui-tree-set").eq(0).next()[0]||e.addClass(k)}),e.events()}},b.prototype.renderForm=function(e){a.render(e,"LAY-tree-"+this.index)},b.prototype.tree=function(e,a){var n=this,t=n.config,r=a||t.data;layui.each(r,function(a,r){var l=r.children&&r.children.length>0,o=i('
        '),h=i(['
        ','
        ','
        ',function(){return t.showLine?l?'':'':''}(),function(){return t.showCheckbox?'':""}(),function(){return t.isJump&&r.href?''+(r.title||r.label||t.text.defaultNodeName)+"":''+(r.title||r.label||t.text.defaultNodeName)+""}(),"
        ",function(){if(!t.edit)return"";var e={add:'',update:'',del:''},i=['
        '];return t.edit===!0&&(t.edit=["update","del"]),"object"==typeof t.edit?(layui.each(t.edit,function(a,n){i.push(e[n]||"")}),i.join("")+"
        "):void 0}(),"
        "].join(""));l&&(h.append(o),n.tree(o,r.children)),e.append(h),h.prev("."+s)[0]&&h.prev().children(".layui-tree-pack").addClass("layui-tree-showLine"),l||h.parent(".layui-tree-pack").addClass("layui-tree-lineExtend"),n.spread(h,r),t.showCheckbox&&(r.checked&&n.checkids.push(r.id),n.checkClick(h,r)),t.edit&&n.operate(h,r)})},b.prototype.spread=function(e,a){var n=this,t=n.config,r=e.children("."+p),l=r.children("."+f),c=r.find("."+o),k=r.find("."+y),m=t.onlyIconControl?c:l,x="";m.on("click",function(i){var a=e.children("."+v),n=m.children(".layui-icon")[0]?m.children(".layui-icon"):m.find(".layui-tree-icon").children(".layui-icon");if(a[0]){if(e.hasClass(C))e.removeClass(C),a.slideUp(200),n.removeClass(u).addClass(h);else if(e.addClass(C),a.slideDown(200),n.addClass(u).removeClass(h),t.accordion){var r=e.siblings("."+s);r.removeClass(C),r.children("."+v).slideUp(200),r.find(".layui-tree-icon").children(".layui-icon").removeClass(u).addClass(h)}}else x="normal"}),k.on("click",function(){var n=i(this);n.hasClass(d)||(x=e.hasClass(C)?t.onlyIconControl?"open":"close":t.onlyIconControl?"close":"open",t.click&&t.click({elem:e,state:x,data:a}))})},b.prototype.setCheckbox=function(e,i,a){var n=this,t=(n.config,a.prop("checked"));if(!a.prop("disabled")){if("object"==typeof i.children||e.find("."+v)[0]){var r=e.find("."+v).find('input[same="layuiTreeCheck"]');r.each(function(){this.disabled||(this.checked=t)})}var l=function(e){if(e.parents("."+s)[0]){var i,a=e.parent("."+v),n=a.parent(),r=a.prev().find('input[same="layuiTreeCheck"]');t?r.prop("checked",t):(a.find('input[same="layuiTreeCheck"]').each(function(){this.checked&&(i=!0)}),i||r.prop("checked",!1)),l(n)}};l(e),n.renderForm("checkbox")}},b.prototype.checkClick=function(e,a){var n=this,t=n.config,r=e.children("."+p),l=r.children("."+f);l.on("click",'input[same="layuiTreeCheck"]+',function(r){layui.stope(r);var l=i(this).prev(),c=l.prop("checked");l.prop("disabled")||(n.setCheckbox(e,a,l),t.oncheck&&t.oncheck({elem:e,checked:c,data:a}))})},b.prototype.operate=function(e,a){var t=this,r=t.config,l=e.children("."+p),d=l.children("."+f);l.children(".layui-tree-btnGroup").on("click",".layui-icon",function(l){layui.stope(l);var f=i(this).data("type"),b=e.children("."+v),g={data:a,type:f,elem:e};if("add"==f){b[0]||(r.showLine?(d.find("."+o).addClass("layui-tree-icon"),d.find("."+o).children(".layui-icon").addClass(h).removeClass("layui-icon-file")):d.find(".layui-tree-iconArrow").removeClass(c),e.append('
        '));var w=r.operate&&r.operate(g),N={};if(N.title=r.text.defaultNodeName,N.id=w,t.tree(e.children("."+v),[N]),r.showLine)if(b[0])b.hasClass(x)||b.addClass(x),e.find("."+v).each(function(){i(this).children("."+s).last().addClass(k)}),b.children("."+s).last().prev().hasClass(k)?b.children("."+s).last().prev().removeClass(k):b.children("."+s).last().removeClass(k),!e.parent("."+v)[0]&&e.next()[0]&&b.children("."+s).last().removeClass(k);else{var T=e.siblings("."+s),L=1,A=e.parent("."+v);layui.each(T,function(e,a){i(a).children("."+v)[0]||(L=0)}),1==L?(T.children("."+v).addClass(m),T.children("."+v).children("."+s).removeClass(k),e.children("."+v).addClass(m),A.removeClass(x),A.children("."+s).last().children("."+v).children("."+s).last().addClass(k)):e.children("."+v).children("."+s).addClass(k)}if(!r.showCheckbox)return;if(d.find('input[same="layuiTreeCheck"]')[0].checked){var I=e.children("."+v).children("."+s).last();I.find('input[same="layuiTreeCheck"]')[0].checked=!0}t.renderForm("checkbox")}else if("update"==f){var F=d.children("."+y).html();d.children("."+y).html(""),d.append(''),d.children(".layui-tree-editInput").val(F).focus();var j=function(e){var i=e.val().trim();i=i?i:r.text.defaultNodeName,e.remove(),d.children("."+y).html(i),g.data.title=i,r.operate&&r.operate(g)};d.children(".layui-tree-editInput").blur(function(){j(i(this))}),d.children(".layui-tree-editInput").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),j(i(this)))})}else n.confirm('确认删除该节点 "'+(a.title||"")+'" 吗?',function(a){if(r.operate&&r.operate(g),g.status="remove",n.close(a),!e.prev("."+s)[0]&&!e.next("."+s)[0]&&!e.parent("."+v)[0])return e.remove(),void t.elem.append(t.elemNone);if(e.siblings("."+s).children("."+p)[0]){if(r.showCheckbox){var l=function(e){if(e.parents("."+s)[0]){var a=e.siblings("."+s).children("."+p),n=e.parent("."+v).prev(),r=n.find('input[same="layuiTreeCheck"]')[0],c=1,d=0;0==r.checked&&(a.each(function(e,a){var n=i(a).find('input[same="layuiTreeCheck"]')[0];0!=n.checked||n.disabled||(c=0),n.disabled||(d=1)}),1==c&&1==d&&(r.checked=!0,t.renderForm("checkbox"),l(n.parent("."+s))))}};l(e)}if(r.showLine){var d=e.siblings("."+s),h=1,f=e.parent("."+v);layui.each(d,function(e,a){i(a).children("."+v)[0]||(h=0)}),1==h?(b[0]||(f.removeClass(x),d.children("."+v).addClass(m),d.children("."+v).children("."+s).removeClass(k)),e.next()[0]?f.children("."+s).last().children("."+v).children("."+s).last().addClass(k):e.prev().children("."+v).children("."+s).last().addClass(k),e.next()[0]||e.parents("."+s)[1]||e.parents("."+s).eq(0).next()[0]||e.prev("."+s).addClass(k)):!e.next()[0]&&e.hasClass(k)&&e.prev().addClass(k)}}else{var y=e.parent("."+v).prev();if(r.showLine){y.find("."+o).removeClass("layui-tree-icon"),y.find("."+o).children(".layui-icon").removeClass(u).addClass("layui-icon-file");var w=y.parents("."+v).eq(0);w.addClass(x),w.children("."+s).each(function(){i(this).children("."+v).children("."+s).last().addClass(k)})}else y.find(".layui-tree-iconArrow").addClass(c);e.parents("."+s).eq(0).removeClass(C),e.parent("."+v).remove()}e.remove()})})},b.prototype.events=function(){var e=this,a=e.config;e.elem.find(".layui-tree-checkedFirst");e.setChecked(e.checkids),e.elem.find(".layui-tree-search").on("keyup",function(){var n=i(this),t=n.val(),r=n.nextAll(),l=[];r.find("."+y).each(function(){var e=i(this).parents("."+p);if(i(this).html().indexOf(t)!=-1){l.push(i(this).parent());var a=function(e){e.addClass("layui-tree-searchShow"),e.parent("."+v)[0]&&a(e.parent("."+v).parent("."+s))};a(e.parent("."+s))}}),r.find("."+p).each(function(){var e=i(this).parent("."+s);e.hasClass("layui-tree-searchShow")||e.addClass(c)}),0==r.find(".layui-tree-searchShow").length&&e.elem.append(e.elemNone),a.onsearch&&a.onsearch({elem:l})}),e.elem.find(".layui-tree-search").on("keydown",function(){i(this).nextAll().find("."+p).each(function(){var e=i(this).parent("."+s);e.removeClass("layui-tree-searchShow "+c)}),i(".layui-tree-emptyText")[0]&&i(".layui-tree-emptyText").remove()})},b.prototype.getChecked=function(){var e=this,a=e.config,n=[],t=[];e.elem.find(".layui-form-checked").each(function(){n.push(i(this).prev()[0].value)});var r=function(e,a){layui.each(e,function(e,t){layui.each(n,function(e,n){if(t.id==n){var l=i.extend({},t);return delete l.children,a.push(l),t.children&&(l.children=[],r(t.children,l.children)),!0}})})};return r(i.extend({},a.data),t),t},b.prototype.setChecked=function(e){var a=this;a.config;a.elem.find("."+s).each(function(a,n){var t=i(this).data("id"),r=i(n).children("."+p).find('input[same="layuiTreeCheck"]'),l=r.next();if("number"==typeof e){if(t==e)return r[0].checked||l.click(),!1}else"object"==typeof e&&layui.each(e,function(e,i){if(i==t&&!r[0].checked)return l.click(),!0})})},l.that={},l.config={},r.reload=function(e,i){var a=l.that[e];return a.reload(i),l.call(a)},r.getChecked=function(e){var i=l.that[e];return i.getChecked()},r.setChecked=function(e,i){var a=l.that[e];return a.setChecked(i)},r.render=function(e){var i=new b(e);return l.call(i)},e(t,r)});layui.define(["laytpl","form"],function(e){"use strict";var a=layui.$,t=layui.laytpl,n=layui.form,i="transfer",l={config:{},index:layui[i]?layui[i].index+1e4:0,set:function(e){var t=this;return t.config=a.extend({},t.config,e),t},on:function(e,a){return layui.onevent.call(this,i,e,a)}},r=function(){var e=this,a=e.config,t=a.id||e.index;return r.that[t]=e,r.config[t]=a,{config:a,reload:function(a){e.reload.call(e,a)},getData:function(){return e.getData.call(e)}}},c="layui-hide",o="layui-btn-disabled",d="layui-none",s="layui-transfer-box",u="layui-transfer-header",h="layui-transfer-search",f="layui-transfer-active",y="layui-transfer-data",p=function(e){return e=e||{},['
        ','
        ','","
        ","{{# if(d.data.showSearch){ }}",'","{{# } }}",'
          ',"
          "].join("")},v=['
          ',p({index:0,checkAllName:"layTransferLeftCheckAll"}),'
          ','",'","
          ",p({index:1,checkAllName:"layTransferRightCheckAll"}),"
          "].join(""),x=function(e){var t=this;t.index=++l.index,t.config=a.extend({},t.config,l.config,e),t.render()};x.prototype.config={title:["列表一","列表二"],width:200,height:360,data:[],value:[],showSearch:!1,id:"",text:{none:"无数据",searchNone:"无匹配数据"}},x.prototype.reload=function(e){var t=this;layui.each(e,function(e,a){a.constructor===Array&&delete t.config[e]}),t.config=a.extend(!0,{},t.config,e),t.render()},x.prototype.render=function(){var e=this,n=e.config,i=e.elem=a(t(v).render({data:n,index:e.index})),l=n.elem=a(n.elem);l[0]&&(n.data=n.data||[],n.value=n.value||[],e.key=n.id||e.index,l.html(e.elem),e.layBox=e.elem.find("."+s),e.layHeader=e.elem.find("."+u),e.laySearch=e.elem.find("."+h),e.layData=i.find("."+y),e.layBtn=i.find("."+f+" .layui-btn"),e.layBox.css({width:n.width,height:n.height}),e.layData.css({height:function(){return n.height-e.layHeader.outerHeight()-e.laySearch.outerHeight()-2}()}),e.renderData(),e.events())},x.prototype.renderData=function(){var e=this,a=(e.config,[{checkName:"layTransferLeftCheck",views:[]},{checkName:"layTransferRightCheck",views:[]}]);e.parseData(function(e){var t=e.selected?1:0,n=["
        • ",'',"
        • "].join("");a[t].views.push(n),delete e.selected}),e.layData.eq(0).html(a[0].views.join("")),e.layData.eq(1).html(a[1].views.join("")),e.renderCheckBtn()},x.prototype.renderForm=function(e){n.render(e,"LAY-transfer-"+this.index)},x.prototype.renderCheckBtn=function(e){var t=this,n=t.config;e=e||{},t.layBox.each(function(i){var l=a(this),r=l.find("."+y),d=l.find("."+u).find('input[type="checkbox"]'),s=r.find('input[type="checkbox"]'),h=0,f=!1;if(s.each(function(){var e=a(this).data("hide");(this.checked||this.disabled||e)&&h++,this.checked&&!e&&(f=!0)}),d.prop("checked",f&&h===s.length),t.layBtn.eq(i)[f?"removeClass":"addClass"](o),!e.stopNone){var p=r.children("li:not(."+c+")").length;t.noneView(r,p?"":n.text.none)}}),t.renderForm("checkbox")},x.prototype.noneView=function(e,t){var n=a('

          '+(t||"")+"

          ");e.find("."+d)[0]&&e.find("."+d).remove(),t.replace(/\s/g,"")&&e.append(n)},x.prototype.setValue=function(){var e=this,t=e.config,n=[];return e.layBox.eq(1).find("."+y+' input[type="checkbox"]').each(function(){var e=a(this).data("hide");e||n.push(this.value)}),t.value=n,e},x.prototype.parseData=function(e){var t=this,n=t.config,i=[];return layui.each(n.data,function(t,l){l=("function"==typeof n.parseData?n.parseData(l):l)||l,i.push(l=a.extend({},l)),layui.each(n.value,function(e,a){a==l.value&&(l.selected=!0)}),e&&e(l)}),n.data=i,t},x.prototype.getData=function(e){var a=this,t=a.config,n=[];return a.setValue(),layui.each(e||t.value,function(e, a){layui.each(t.data,function(e, t){delete t.selected,a==t.value&&n.push(t)})}),n},x.prototype.events=function(){var e=this,t=e.config;e.elem.on("click",'input[lay-filter="layTransferCheckbox"]+',function(){var t=a(this).prev(),n=t[0].checked,i=t.parents("."+s).eq(0).find("."+y);t[0].disabled||("all"===t.attr("lay-type")&&i.find('input[type="checkbox"]').each(function(){this.disabled||(this.checked=n)}),e.renderCheckBtn({stopNone:!0}))}),e.layBtn.on("click",function(){var n=a(this),i=n.data("index"),l=e.layBox.eq(i),r=[];if(!n.hasClass(o)){e.layBox.eq(i).each(function(t){var n=a(this),i=n.find("."+y);i.children("li").each(function(){var t=a(this),n=t.find('input[type="checkbox"]'),i=n.data("hide");n[0].checked&&!i&&(n[0].checked=!1,l.siblings("."+s).find("."+y).append(t.clone()),t.remove(),r.push(n[0].value)),e.setValue()})}),e.renderCheckBtn();var c=l.siblings("."+s).find("."+h+" input");""===c.val()||c.trigger("keyup"),t.onchange&&t.onchange(e.getData(r),i)}}),e.laySearch.find("input").on("keyup",function(){var n=this.value,i=a(this).parents("."+h).eq(0).siblings("."+y),l=i.children("li");l.each(function(){var e=a(this),t=e.find('input[type="checkbox"]'),i=t[0].title.indexOf(n)!==-1;e[i?"removeClass":"addClass"](c),t.data("hide",!i)}),e.renderCheckBtn();var r=l.length===i.children("li."+c).length;e.noneView(i,r?t.text.searchNone:"")})},r.that={},r.config={},l.reload=function(e,a){var t=r.that[e];return t.reload(a),r.call(t)},l.getData=function(e){var a=r.that[e];return a.getData()},l.render=function(e){var a=new x(e);return r.call(a)},e(i,l)});layui.define(["laytpl","laypage","layer","form","util"],function(e){"use strict";var t=layui.$,i=layui.laytpl,a=layui.laypage,l=layui.layer,n=layui.form,o=(layui.util,layui.hint()),r=layui.device(),d={config:{checkName:"LAY_CHECKED",indexName:"LAY_TABLE_INDEX"},cache:{},index:layui.table?layui.table.index+1e4:0,set:function(e){var i=this;return i.config=t.extend({},i.config,e),i},on:function(e,t){return layui.onevent.call(this,y,e,t)}},c=function(){var e=this,t=e.config,i=t.id||t.index;return i&&(c.that[i]=e,c.config[i]=t),{config:t,reload:function(t){e.reload.call(e,t)},setColsWidth:function(){e.setColsWidth.call(e)},resize:function(){e.resize.call(e)}}},s=function(e){var t=c.config[e];return t||o.error("The ID option was not found in the table instance"),t||null},u=function(e,a,l,n){var o=e.templet?function(){return"function"==typeof e.templet?e.templet(l):i(t(e.templet).html()||String(a)).render(l)}():a;return n?t("
          "+o+"
          ").text():o},y="table",h=".layui-table",f="layui-hide",p="layui-none",v="layui-table-view",m=".layui-table-tool",g=".layui-table-box",b=".layui-table-init",x=".layui-table-header",k=".layui-table-body",C=".layui-table-main",w=".layui-table-fixed",T=".layui-table-fixed-l",A=".layui-table-fixed-r",L=".layui-table-total",N=".layui-table-page",S=".layui-table-sort",W="layui-table-edit",_="layui-table-hover",E=function(e){var t='{{#if(item2.colspan){}} colspan="{{item2.colspan}}"{{#} if(item2.rowspan){}} rowspan="{{item2.rowspan}}"{{#}}}';return e=e||{},['',"","{{# 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; } }}',function(){return 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("")},z=['',"","
          "].join(""),H=['
          ',"{{# if(d.data.toolbar){ }}",'
          ','
          ','
          ',"
          ","{{# } }}",'
          ',"{{# if(d.data.loading){ }}",'
          ','',"
          ","{{# } }}","{{# var left, right; }}",'
          ',E(),"
          ",'
          ',z,"
          ","{{# if(left){ }}",'
          ','
          ',E({fixed:!0}),"
          ",'
          ',z,"
          ","
          ","{{# }; }}","{{# if(right){ }}",'
          ','
          ',E({fixed:"right"}),'
          ',"
          ",'
          ',z,"
          ","
          ","{{# }; }}","
          ","{{# if(d.data.totalRow){ }}",'
          ','','',"
          ","
          ","{{# } }}","{{# if(d.data.page){ }}",'
          ','
          ',"
          ","{{# } }}","","
          "].join(""),R=t(window),F=t(document),j=function(e){var i=this;i.index=++d.index,i.config=t.extend({},i.config,d.config,e),i.render()};j.prototype.config={limit:10,loading:!0,cellMinWidth:60,defaultToolbar:["filter","exports","print"],autoSort:!0,text:{none:"无数据"}},j.prototype.render=function(){var e=this,a=e.config;if(a.elem=t(a.elem),a.where=a.where||{},a.id=a.id||a.elem.attr("id")||e.index,a.request=t.extend({pageName:"page",limitName:"limit"},a.request),a.response=t.extend({statusName:"code",statusCode:0,msgName:"msg",dataName:"data",countName:"count"},a.response),"object"==typeof a.page&&(a.limit=a.page.limit||a.limit,a.limits=a.page.limits||a.limits,e.page=a.page.curr=a.page.curr||1,delete a.page.elem,delete a.page.jump),!a.elem[0])return e;a.height&&/^full-\d+$/.test(a.height)&&(e.fullHeightGap=a.height.split("-")[1],a.height=R.height()-e.fullHeightGap),e.setInit();var l=a.elem,n=l.next("."+v),o=e.elem=t(i(H).render({VIEW_CLASS:v,data:a,index:e.index}));if(a.index=e.index,e.key=a.id||a.index,n[0]&&n.remove(),l.after(o),e.layTool=o.find(m),e.layBox=o.find(g),e.layHeader=o.find(x),e.layMain=o.find(C),e.layBody=o.find(k),e.layFixed=o.find(w),e.layFixLeft=o.find(T),e.layFixRight=o.find(A),e.layTotal=o.find(L),e.layPage=o.find(N),e.renderToolbar(),e.fullSize(),a.cols.length>1){var r=e.layFixed.find(x).find("th");r.height(e.layHeader.height()-1-parseFloat(r.css("padding-top"))-parseFloat(r.css("padding-bottom")))}e.pullData(e.page),e.events()},j.prototype.initOpts=function(e){var t=this,i=(t.config,{checkbox:48,radio:48,space:15,numbers:40});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||i[e.type])},j.prototype.setInit=function(e){var t=this,i=t.config;return i.clientWidth=i.width||function(){var e=function(t){var a,l;t=t||i.elem.parent(),a=t.width();try{l="none"===t.css("display")}catch(n){}return!t[0]||a&&!l?a:e(t.parent())};return e()}(),"width"===e?i.clientWidth:void layui.each(i.cols,function(e,a){layui.each(a,function(l,n){if(!n)return void a.splice(l,1);if(n.key=e+"-"+l,n.hide=n.hide||!1,n.colGroup||n.colspan>1){var o=0;layui.each(i.cols[e+1],function(t,i){i.HAS_PARENT||o>1&&o==n.colspan||(i.HAS_PARENT=!0,i.parentKey=e+"-"+l,o+=parseInt(i.colspan>1?i.colspan:1))}),n.colGroup=!0}t.initOpts(n)})})},j.prototype.renderToolbar=function(){var e=this,a=e.config,l=['
          ','
          ','
          '].join(""),n=e.layTool.find(".layui-table-tool-temp");if("default"===a.toolbar)n.html(l);else if("string"==typeof a.toolbar){var o=t(a.toolbar).html()||"";o&&n.html(i(o).render(a))}var r={filter:{title:"筛选列",layEvent:"LAYTABLE_COLS",icon:"layui-icon-cols"},exports:{title:"导出",layEvent:"LAYTABLE_EXPORT",icon:"layui-icon-export"},print:{title:"打印",layEvent:"LAYTABLE_PRINT",icon:"layui-icon-print"}},d=[];"object"==typeof a.defaultToolbar&&layui.each(a.defaultToolbar,function(e,t){var i="string"==typeof t?r[t]:t;i&&d.push('
          ')}),e.layTool.find(".layui-table-tool-self").html(d.join(""))},j.prototype.setParentCol=function(e,t){var i=this,a=i.config,l=i.layHeader.find('th[data-key="'+a.index+"-"+t+'"]'),n=parseInt(l.attr("colspan"))||0;if(l[0]){var o=t.split("-"),r=a.cols[o[0]][o[1]];e?n--:n++,l.attr("colspan",n),l[n<1?"addClass":"removeClass"](f),r.colspan=n,r.hide=n<1;var d=l.data("parentkey");d&&i.setParentCol(e,d)}},j.prototype.setColsPatch=function(){var e=this,t=e.config;layui.each(t.cols,function(t,i){layui.each(i,function(t,i){i.hide&&e.setParentCol(i.hide,i.parentKey)})})},j.prototype.setColsWidth=function(){var e=this,t=e.config,i=0,a=0,l=0,n=0,o=e.setInit("width");e.eachCols(function(e,t){t.hide||i++}),o=o-function(){return"line"===t.skin||"nob"===t.skin?2:i+1}()-e.getScrollWidth(e.layMain[0])-1;var r=function(e){layui.each(t.cols,function(i,r){layui.each(r,function(i,d){var c=0,s=d.minWidth||t.cellMinWidth;return d?void(d.colGroup||d.hide||(e?l&&ln&&a&&(l=(o-n)/a)};r(),r(!0),e.autoColNums=a,e.eachCols(function(i,a){var n=a.minWidth||t.cellMinWidth;a.colGroup||a.hide||(0===a.width?e.getCssRule(t.index+"-"+a.key,function(e){e.style.width=Math.floor(l>=n?l:n)+"px"}):/\d+%$/.test(a.width)&&e.getCssRule(t.index+"-"+a.key,function(e){e.style.width=Math.floor(parseFloat(a.width)/100*o)+"px"}))});var d=e.layMain.width()-e.getScrollWidth(e.layMain[0])-e.layMain.children("table").outerWidth();if(e.autoColNums&&d>=-i&&d<=i){var c=function(t){var i;return t=t||e.layHeader.eq(0).find("thead th:last-child"),i=t.data("field"),!i&&t.prev()[0]?c(t.prev()):t},s=c(),u=s.data("key");e.getCssRule(u,function(t){var i=t.style.width||s.outerWidth();t.style.width=parseFloat(i)+d+"px",e.layMain.height()-e.layMain.prop("clientHeight")>0&&(t.style.width=parseFloat(t.style.width)-1+"px")})}e.loading(!0)},j.prototype.resize=function(){var e=this;e.fullSize(),e.setColsWidth(),e.scrollPatch()},j.prototype.reload=function(e){var i=this;e=e||{},delete i.haveInit,e.data&&e.data.constructor===Array&&delete i.config.data,i.config=t.extend(!0,{},i.config,e),i.render()},j.prototype.errorView=function(e){var i=this,a=i.layMain.find("."+p),l=t('
          '+(e||"Error")+"
          ");a[0]&&(i.layNone.remove(),a.remove()),i.layFixed.addClass(f),i.layMain.find("tbody").html(""),i.layMain.append(i.layNone=l),d.cache[i.key]=[]},j.prototype.page=1,j.prototype.pullData=function(e){var i=this,a=i.config,l=a.request,n=a.response,o=function(){"object"==typeof a.initSort&&i.sort(a.initSort.field,a.initSort.type)};if(i.startTime=(new Date).getTime(),a.url){var r={};r[l.pageName]=e,r[l.limitName]=a.limit;var d=t.extend(r,a.where);a.contentType&&0==a.contentType.indexOf("application/json")&&(d=JSON.stringify(d)),i.loading(),t.ajax({type:a.method||"get",url:a.url,contentType:a.contentType,data:d,dataType:"json",headers:a.headers||{},success:function(t){"function"==typeof a.parseData&&(t=a.parseData(t)||t),t[n.statusName]!=n.statusCode?(i.renderForm(),i.errorView(t[n.msgName]||'返回的数据不符合规范,正确的成功状态码应为:"'+n.statusName+'": '+n.statusCode)):(i.renderData(t,e,t[n.countName]),o(),a.time=(new Date).getTime()-i.startTime+" ms"),i.setColsWidth(),"function"==typeof a.done&&a.done(t,e,t[n.countName])},error:function(e,t){i.errorView("数据接口请求异常:"+t),i.renderForm(),i.setColsWidth()}})}else if(a.data&&a.data.constructor===Array){var c={},s=e*a.limit-a.limit;c[n.dataName]=a.data.concat().splice(s,a.limit),c[n.countName]=a.data.length,i.renderData(c,e,c[n.countName]),o(),i.setColsWidth(),"function"==typeof a.done&&a.done(c,e,c[n.countName])}},j.prototype.eachCols=function(e){var t=this;return d.eachCols(null,e,t.config.cols),t},j.prototype.renderData=function(e,n,o,r){var c=this,s=c.config,y=e[s.response.dataName]||[],h=[],v=[],m=[],g=function(){var e;return!r&&c.sortKey?c.sort(c.sortKey.field,c.sortKey.sort,!0):(layui.each(y,function(a,l){var o=[],y=[],p=[],g=a+s.limit*(n-1)+1;0!==l.length&&(r||(l[d.config.indexName]=a),c.eachCols(function(n,r){var c=r.field||n,h=s.index+"-"+r.key,v=l[c];if(void 0!==v&&null!==v||(v=""),!r.colGroup){var m=['','
          '+function(){var n=t.extend(!0,{LAY_INDEX:g},l),o=d.config.checkName;switch(r.type){case"checkbox":return'";case"radio":return n[o]&&(e=a),'';case"numbers":return g}return r.toolbar?i(t(r.toolbar).html()||"").render(n):u(r,v,n)}(),"
          "].join("");o.push(m),r.fixed&&"right"!==r.fixed&&y.push(m),"right"===r.fixed&&p.push(m)}}),h.push(''+o.join("")+""),v.push(''+y.join("")+""),m.push(''+p.join("")+""))}),c.layBody.scrollTop(0),c.layMain.find("."+p).remove(),c.layMain.find("tbody").html(h.join("")),c.layFixLeft.find("tbody").html(v.join("")),c.layFixRight.find("tbody").html(m.join("")),c.renderForm(),"number"==typeof e&&c.setThisRowChecked(e),c.syncCheckAll(),c.haveInit?c.scrollPatch():setTimeout(function(){c.scrollPatch()},50),c.haveInit=!0,l.close(c.tipsIndex),s.HAS_SET_COLS_PATCH||c.setColsPatch(),void(s.HAS_SET_COLS_PATCH=!0))};return d.cache[c.key]=y,c.layPage[0==o||0===y.length&&1==n?"addClass":"removeClass"](f),r?g():0===y.length?(c.renderForm(),c.errorView(s.text.none)):(c.layFixed.removeClass(f),g(),c.renderTotal(y),void(s.page&&(s.page=t.extend({elem:"layui-table-page"+s.index,count:o,limit:s.limit,limits:s.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||(c.page=e.curr,s.limit=e.limit,c.pullData(e.curr))}},s.page),s.page.count=o,a.render(s.page))))},j.prototype.renderTotal=function(e){var t=this,i=t.config,a={};if(i.totalRow){layui.each(e,function(e,i){0!==i.length&&t.eachCols(function(e,t){var l=t.field||e,n=i[l];t.totalRow&&(a[l]=(a[l]||0)+(parseFloat(n)||0))})}),t.dataTotal={};var l=[];t.eachCols(function(e,n){var o=n.field||e,r=function(){var e=n.totalRowText||"",t=parseFloat(a[o]).toFixed(2),i={};return i[o]=t,t=u(n,t,i),n.totalRow?t||e:e}(),d=['','
          '+r,"
          "].join("");n.field&&(t.dataTotal[o]=r),l.push(d)}),t.layTotal.find("tbody").html(""+l.join("")+"")}},j.prototype.getColElem=function(e,t){var i=this,a=i.config;return e.eq(0).find(".laytable-cell-"+(a.index+"-"+t)+":eq(0)")},j.prototype.renderForm=function(e){n.render(e,"LAY-table-"+this.index)},j.prototype.setThisRowChecked=function(e){var t=this,i=(t.config,"layui-table-click"),a=t.layBody.find('tr[data-index="'+e+'"]');a.addClass(i).siblings("tr").removeClass(i)},j.prototype.sort=function(e,i,a,l){var n,r,c=this,s={},u=c.config,h=u.elem.attr("lay-filter"),f=d.cache[c.key];"string"==typeof e&&c.layHeader.find("th").each(function(i,a){var l=t(this),o=l.data("field");if(o===e)return e=l,n=o,!1});try{var n=n||e.data("field"),p=e.data("key");if(c.sortKey&&!a&&n===c.sortKey.field&&i===c.sortKey.sort)return;var v=c.layHeader.find("th .laytable-cell-"+p).find(S);c.layHeader.find("th").find(S).removeAttr("lay-sort"),v.attr("lay-sort",i||null),c.layFixed.find("th")}catch(m){return o.error("Table modules: Did not match to field")}c.sortKey={field:n,sort:i},u.autoSort&&("asc"===i?r=layui.sort(f,n):"desc"===i?r=layui.sort(f,n,!0):(r=layui.sort(f,d.config.indexName),delete c.sortKey)),s[u.response.dataName]=r||f,c.renderData(s,c.page,c.count,!0),l&&layui.event.call(e,y,"sort("+h+")",{field:n,type:i})},j.prototype.loading=function(e){var i=this,a=i.config;a.loading&&(e?(i.layInit&&i.layInit.remove(),delete i.layInit,i.layBox.find(b).remove()):(i.layInit=t(['
          ','',"
          "].join("")),i.layBox.append(i.layInit)))},j.prototype.setCheckData=function(e,t){var i=this,a=i.config,l=d.cache[i.key];l[e]&&l[e].constructor!==Array&&(l[e][a.checkName]=t)},j.prototype.syncCheckAll=function(){var e=this,t=e.config,i=e.layHeader.find('input[name="layTableCheckbox"]'),a=function(i){return e.eachCols(function(e,a){"checkbox"===a.type&&(a[t.checkName]=i)}),i};i[0]&&(d.checkStatus(e.key).isAll?(i[0].checked||(i.prop("checked",!0),e.renderForm("checkbox")),a(!0)):(i[0].checked&&(i.prop("checked",!1),e.renderForm("checkbox")),a(!1)))},j.prototype.getCssRule=function(e,t){var i=this,a=i.elem.find("style")[0],l=a.sheet||a.styleSheet||{},n=l.cssRules||l.rules;layui.each(n,function(i,a){if(a.selectorText===".laytable-cell-"+e)return t(a),!0})},j.prototype.fullSize=function(){var e,t=this,i=t.config,a=i.height;t.fullHeightGap&&(a=R.height()-t.fullHeightGap,a<135&&(a=135),t.elem.css("height",a)),a&&(e=parseFloat(a)-(t.layHeader.outerHeight()||38),i.toolbar&&(e-=t.layTool.outerHeight()||50),i.totalRow&&(e-=t.layTotal.outerHeight()||40),i.page&&(e-=t.layPage.outerHeight()||41),t.layMain.css("height",e-2))},j.prototype.getScrollWidth=function(e){var t=0;return e?t=e.offsetWidth-e.clientWidth:(e=document.createElement("div"),e.style.width="100px",e.style.height="100px",e.style.overflowY="scroll",document.body.appendChild(e),t=e.offsetWidth-e.clientWidth,document.body.removeChild(e)),t},j.prototype.scrollPatch=function(){var e=this,i=e.layMain.children("table"),a=e.layMain.width()-e.layMain.prop("clientWidth"),l=e.layMain.height()-e.layMain.prop("clientHeight"),n=(e.getScrollWidth(e.layMain[0]),i.outerWidth()-e.layMain.width()),o=function(e){if(a&&l){if(e=e.eq(0),!e.find(".layui-table-patch")[0]){var i=t('
          ');i.find("div").css({width:a}),e.find("tr").append(i)}}else e.find(".layui-table-patch").remove()};o(e.layHeader),o(e.layTotal);var r=e.layMain.height(),d=r-l;e.layFixed.find(k).css("height",i.height()>=d?d:"auto"),e.layFixRight[n>0?"removeClass":"addClass"](f),e.layFixRight.css("right",a-1)},j.prototype.events=function(){var e,i=this,a=i.config,o=t("body"),c={},s=i.layHeader.find("th"),h=".layui-table-cell",p=a.elem.attr("lay-filter");i.layTool.on("click","*[lay-event]",function(e){var o=t(this),c=o.attr("lay-event"),s=function(e){var l=t(e.list),n=t('
            ');n.html(l),a.height&&n.css("max-height",a.height-(i.layTool.outerHeight()||50)),o.find(".layui-table-tool-panel")[0]||o.append(n),i.renderForm(),n.on("click",function(e){layui.stope(e)}),e.done&&e.done(n,l)};switch(layui.stope(e),F.trigger("table.tool.panel.remove"),l.close(i.tipsIndex),c){case"LAYTABLE_COLS":s({list:function(){var e=[];return i.eachCols(function(t,i){i.field&&"normal"==i.type&&e.push('
          • ')}),e.join("")}(),done:function(){n.on("checkbox(LAY_TABLE_TOOL_COLS)",function(e){var l=t(e.elem),n=this.checked,o=l.data("key"),r=l.data("parentkey");layui.each(a.cols,function(e,t){layui.each(t,function(t,l){if(e+"-"+t===o){var d=l.hide;l.hide=!n,i.elem.find('*[data-key="'+a.index+"-"+o+'"]')[n?"removeClass":"addClass"](f),d!=l.hide&&i.setParentCol(!n,r),i.resize()}})})})}});break;case"LAYTABLE_EXPORT":r.ie?l.tips("导出功能不支持 IE,请用 Chrome 等高级浏览器导出",this,{tips:3}):s({list:function(){return['
          • 导出到 Csv 文件
          • ','
          • 导出到 Excel 文件
          • '].join("")}(),done:function(e,l){l.on("click",function(){var e=t(this).data("type");d.exportFile.call(i,a.id,null,e)})}});break;case"LAYTABLE_PRINT":var u=window.open("打印窗口","_blank"),h=[""].join(""),v=t(i.layHeader.html());v.append(i.layMain.find("table").html()),v.append(i.layTotal.find("table").html()),v.find("th.layui-table-patch").remove(),v.find(".layui-table-col-special").remove(),u.document.write(h+v.prop("outerHTML")),u.document.close(),u.print(),u.close()}layui.event.call(this,y,"toolbar("+p+")",t.extend({event:c,config:a},{}))}),s.on("mousemove",function(e){var i=t(this),a=i.offset().left,l=e.clientX-a;i.data("unresize")||c.resizeStart||(c.allowResize=i.width()-l<=10,o.css("cursor",c.allowResize?"col-resize":""))}).on("mouseleave",function(){t(this);c.resizeStart||o.css("cursor","")}).on("mousedown",function(e){var l=t(this);if(c.allowResize){var n=l.data("key");e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],i.getCssRule(n,function(e){var t=e.style.width||l.outerWidth();c.rule=e,c.ruleWidth=parseFloat(t),c.minWidth=l.data("minwidth")||a.cellMinWidth})}}),F.on("mousemove",function(t){if(c.resizeStart){if(t.preventDefault(),c.rule){var a=c.ruleWidth+t.clientX-c.offset[0];a');return n[0].value=i.data("content")||l.text(),i.find("."+W)[0]||i.append(n),n.focus(),void layui.stope(e)}}).on("mouseenter","td",function(){b.call(this)}).on("mouseleave","td",function(){b.call(this,"hide")});var g="layui-table-grid-down",b=function(e){var i=t(this),a=i.children(h);if(!i.data("off"))if(e)i.find(".layui-table-grid-down").remove();else if(a.prop("scrollWidth")>a.outerWidth()){if(a.find("."+g)[0])return;i.append('
            ')}};i.layBody.on("click","."+g,function(e){var n=t(this),o=n.parent(),d=o.children(h);i.tipsIndex=l.tips(['
            ',d.html(),"
            ",''].join(""),d[0],{tips:[3,""],time:-1,anim:-1,maxWidth:r.ios||r.android?300:i.elem.width()/2,isOutAnim:!1,skin:"layui-table-tips",success:function(e, t){e.find(".layui-table-tips-c").on("click",function(){l.close(t)})}}),layui.stope(e)}),i.layBody.on("click","*[lay-event]",function(){var e=t(this),a=e.parents("tr").eq(0).data("index");layui.event.call(this,y,"tool("+p+")",v.call(this,{event:e.attr("lay-event")})),i.setThisRowChecked(a)}),i.layMain.on("scroll",function(){var e=t(this),a=e.scrollLeft(),n=e.scrollTop();i.layHeader.scrollLeft(a),i.layTotal.scrollLeft(a),i.layFixed.find(k).scrollTop(n),l.close(i.tipsIndex)}),R.on("resize",function(){i.resize()})},function(){F.on("click",function(){F.trigger("table.remove.tool.panel")}),F.on("table.remove.tool.panel",function(){t(".layui-table-tool-panel").remove()})}(),d.init=function(e,i){i=i||{};var a=this,l=t(e?'table[lay-filter="'+e+'"]':h+"[lay-data]"),n="Table element property lay-data configuration item has a syntax error: ";return l.each(function(){var a=t(this),l=a.attr("lay-data");try{l=new Function("return "+l)()}catch(r){o.error(n+l)}var c=[],s=t.extend({elem:this,cols:[],data:[],skin:a.attr("lay-skin"),size:a.attr("lay-size"),even:"string"==typeof a.attr("lay-even")},d.config,i,l);e&&a.hide(),a.find("thead>tr").each(function(e){s.cols[e]=[],t(this).children().each(function(i){var a=t(this),l=a.attr("lay-data");try{l=new Function("return "+l)()}catch(r){return o.error(n+l)}var d=t.extend({title:a.text(),colspan:a.attr("colspan")||0,rowspan:a.attr("rowspan")||0},l);d.colspan<2&&c.push(d),s.cols[e].push(d)})}),a.find("tbody>tr").each(function(e){var i=t(this),a={};i.children("td").each(function(e,i){var l=t(this),n=l.data("field");if(n)return a[n]=l.html()}),layui.each(c,function(e,t){var l=i.children("td").eq(e);a[t.field]=l.html()}),s.data[e]=a}),d.render(s)}),a},c.that={},c.config={},d.eachCols=function(e,i,a){var l=c.config[e]||{},n=[],o=0;a=t.extend(!0,[],a||l.cols),layui.each(a,function(e,t){layui.each(t,function(t,i){if(i.colGroup){var l=0;o++,i.CHILD_COLS=[],layui.each(a[e+1],function(e,t){t.PARENT_COL_INDEX||l>1&&l==i.colspan||(t.PARENT_COL_INDEX=o,i.CHILD_COLS.push(t),l+=parseInt(t.colspan>1?t.colspan:1))})}i.PARENT_COL_INDEX||n.push(i)})});var r=function(e){layui.each(e||n,function(e,t){return t.CHILD_COLS?r(t.CHILD_COLS):void("function"==typeof i&&i(e,t))})};r()},d.checkStatus=function(e){var t=0,i=0,a=[],l=d.cache[e]||[];return layui.each(l,function(e,l){return l.constructor===Array?void i++:void(l[d.config.checkName]&&(t++,a.push(d.clearCacheKey(l))))}),{data:a,isAll:!!l.length&&t===l.length-i}},d.exportFile=function(e,t,i){var a=this;t=t||d.clearCacheKey(d.cache[e]),i=i||"csv";var l=c.config[e]||{},n={csv:"text/csv",xls:"application/vnd.ms-excel"}[i],s=document.createElement("a");return r.ie?o.error("IE_NOT_SUPPORT_EXPORTS"):(s.href="data:"+n+";charset=utf-8,\ufeff"+encodeURIComponent(function(){var i=[],l=[],n=[];return layui.each(t,function(t,a){var n=[];"object"==typeof e?(layui.each(e,function(e,a){0==t&&i.push(a||"")}),layui.each(d.clearCacheKey(a),function(e,t){n.push('"'+(t||"")+'"')})):d.eachCols(e,function(e,l){if(l.field&&"normal"==l.type&&!l.hide){var o=a[l.field];void 0!==o&&null!==o||(o=""),0==t&&i.push(l.title||""),n.push('"'+u(l,o,a,"text")+'"')}}),l.push(n.join(","))}),layui.each(a.dataTotal,function(e,t){n.push(t)}),i.join(",")+"\r\n"+l.join("\r\n")+"\r\n"+n.join(",")}()),s.download=(l.title||"table_"+(l.index||""))+"."+i,document.body.appendChild(s),s.click(),void document.body.removeChild(s))},d.resize=function(e){if(e){var t=s(e);if(!t)return;c.that[e].resize()}else layui.each(c.that,function(){this.resize()})},d.reload=function(e,t){var i=s(e);if(i){var a=c.that[e];return a.reload(t),c.call(a)}},d.render=function(e){var t=new j(e);return c.call(t)},d.clearCacheKey=function(e){return e=t.extend({},e),delete e[d.config.checkName],delete e[d.config.indexName],e},d.init(),e(y,d)});layui.define("jquery",function(e){"use strict";var i=layui.$,n=(layui.hint(),layui.device(),{config:{},set:function(e){var n=this;return n.config=i.extend({},n.config,e),n},on:function(e,i){return layui.onevent.call(this,t,e,i)}}),t="carousel",a="layui-this",l=">*[carousel-item]>*",o="layui-carousel-left",r="layui-carousel-right",d="layui-carousel-prev",s="layui-carousel-next",u="layui-carousel-arrow",c="layui-carousel-ind",m=function(e){var t=this;t.config=i.extend({},t.config,n.config,e),t.render()};m.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},m.prototype.render=function(){var e=this,n=e.config;n.elem=i(n.elem),n.elem[0]&&(e.elemItem=n.elem.find(l),n.index<0&&(n.index=0),n.index>=e.elemItem.length&&(n.index=e.elemItem.length-1),n.interval<800&&(n.interval=800),n.full?n.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):n.elem.css({width:n.width,height:n.height}),n.elem.attr("lay-anim",n.anim),e.elemItem.eq(n.index).addClass(a),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},m.prototype.reload=function(e){var n=this;clearInterval(n.timer),n.config=i.extend({},n.config,e),n.render()},m.prototype.prevIndex=function(){var e=this,i=e.config,n=i.index-1;return n<0&&(n=e.elemItem.length-1),n},m.prototype.nextIndex=function(){var e=this,i=e.config,n=i.index+1;return n>=e.elemItem.length&&(n=0),n},m.prototype.addIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index+e,n.index>=i.elemItem.length&&(n.index=0)},m.prototype.subIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index-e,n.index<0&&(n.index=i.elemItem.length-1)},m.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(clearInterval(e.timer),e.timer=setInterval(function(){e.slide()},i.interval))},m.prototype.arrow=function(){var e=this,n=e.config,t=i(['",'"].join(""));n.elem.attr("lay-arrow",n.arrow),n.elem.find("."+u)[0]&&n.elem.find("."+u).remove(),n.elem.append(t),t.on("click",function(){var n=i(this),t=n.attr("lay-type");e.slide(t)})},m.prototype.indicator=function(){var e=this,n=e.config,t=e.elemInd=i(['
              ',function(){var i=[];return layui.each(e.elemItem,function(e){i.push("")}),i.join("")}(),"
            "].join(""));n.elem.attr("lay-indicator",n.indicator),n.elem.find("."+c)[0]&&n.elem.find("."+c).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(){var t=i(this),a=t.index();a>n.index?e.slide("add",a-n.index):a",u=1;u<=i.length;u++){var r='
          • ";i.half&&parseInt(i.value)!==i.value&&u==Math.ceil(i.value)?n=n+'
          • ":n+=r}n+=""+(i.text?''+i.value+"星":"")+"";var c=i.elem,f=c.next("."+t);f[0]&&f.remove(),e.elemTemp=a(n),i.span=e.elemTemp.next("span"),i.setText&&i.setText(i.value),c.html(e.elemTemp),c.addClass("layui-inline"),i.readonly||e.action()},v.prototype.setvalue=function(e){var a=this,i=a.config;i.value=e,a.render()},v.prototype.action=function(){var e=this,i=e.config,l=e.elemTemp,n=l.find("i").width();l.children("li").each(function(e){var t=e+1,v=a(this);v.on("click",function(e){if(i.value=t,i.half){var o=e.pageX-a(this).offset().left;o<=n/2&&(i.value=i.value-.5)}i.text&&l.next("span").text(i.value+"星"),i.choose&&i.choose(i.value),i.setText&&i.setText(i.value)}),v.on("mousemove",function(e){if(l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+t+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half){var c=e.pageX-a(this).offset().left;c<=n/2&&v.children("i").addClass(u).removeClass(s)}}),v.on("mouseleave",function(){l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+Math.floor(i.value)+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half&&parseInt(i.value)!==i.value&&l.children("li:eq("+Math.floor(i.value)+")").children("i").addClass(u).removeClass(c)})})},v.prototype.events=function(){var e=this;e.config},i.render=function(e){var a=new v(e);return l.call(a)},e(n,i)});layui.define("jquery",function(t){"use strict";var e=layui.$,i={fixbar:function(t){var i,n,a="layui-fixbar",o="layui-fixbar-top",r=e(document),l=e("body");t=e.extend({showHeight:200},t),t.bar1=t.bar1===!0?"":t.bar1,t.bar2=t.bar2===!0?"":t.bar2,t.bgcolor=t.bgcolor?"background-color:"+t.bgcolor:"";var c=[t.bar1,t.bar2,""],g=e(['
              ',t.bar1?'
            • '+c[0]+"
            • ":"",t.bar2?'
            • '+c[1]+"
            • ":"",'
            • '+c[2]+"
            • ","
            "].join("")),s=g.find("."+o),u=function(){var e=r.scrollTop();e>=t.showHeight?i||(s.show(),i=1):i&&(s.hide(),i=0)};e("."+a)[0]||("object"==typeof t.css&&g.css(t.css),l.append(g),u(),g.find("li").on("click",function(){var i=e(this),n=i.attr("lay-type");"top"===n&&e("html,body").animate({scrollTop:0},200),t.click&&t.click.call(this,n)}),r.on("scroll",function(){clearTimeout(n),n=setTimeout(function(){u()},100)}))},countdown:function(t,e,i){var n=this,a="function"==typeof e,o=new Date(t).getTime(),r=new Date(!e||a?(new Date).getTime():e).getTime(),l=o-r,c=[Math.floor(l/864e5),Math.floor(l/36e5)%24,Math.floor(l/6e4)%60,Math.floor(l/1e3)%60];a&&(i=e);var g=setTimeout(function(){n.countdown(t,r+1e3,i)},1e3);return i&&i(l>0?c:[0,0,0,0],e,g),l<=0&&clearTimeout(g),g},timeAgo:function(t,e){var i=this,n=[[],[]],a=(new Date).getTime()-new Date(t).getTime();return a>6912e5?(a=new Date(t),n[0][0]=i.digit(a.getFullYear(),4),n[0][1]=i.digit(a.getMonth()+1),n[0][2]=i.digit(a.getDate()),e||(n[1][0]=i.digit(a.getHours()),n[1][1]=i.digit(a.getMinutes()),n[1][2]=i.digit(a.getSeconds())),n[0].join("-")+" "+n[1].join(":")):a>=864e5?(a/1e3/60/60/24|0)+"天前":a>=36e5?(a/1e3/60/60|0)+"小时前":a>=12e4?(a/1e3/60|0)+"分钟前":a<0?"未来":"刚刚"},digit:function(t,e){var i="";t=String(t),e=e||2;for(var n=t.length;n/g,">").replace(/'/g,"'").replace(/"/g,""")},event:function(t,n,a){n=i.event[t]=e.extend(!0,i.event[t],n)||{},e("body").on(a||"click","*["+t+"]",function(){var i=e(this),a=i.attr(t);n[a]&&n[a].call(this,i)})}};!function(t,e,i){"$:nomunge";function n(){a=e[l](function(){o.each(function(){var e=t(this),i=e.width(),n=e.height(),a=t.data(this,g);(i!==a.w||n!==a.h)&&e.trigger(c,[a.w=i,a.h=n])}),n()},r[s])}var a,o=t([]),r=t.resize=t.extend(t.resize,{}),l="setTimeout",c="resize",g=c+"-special-event",s="delay",u="throttleWindow";r[s]=250,r[u]=!0,t.event.special[c]={setup:function(){if(!r[u]&&this[l])return!1;var e=t(this);o=o.add(e),t.data(this,g,{w:e.width(),h:e.height()}),1===o.length&&n()},teardown:function(){if(!r[u]&&this[l])return!1;var e=t(this);o=o.not(e),e.removeData(g),o.length||clearTimeout(a)},add:function(e){function n(e,n,o){var r=t(this),l=t.data(this,g)||{};l.w=n!==i?n:r.width(),l.h=o!==i?o:r.height(),a.apply(this,arguments)}if(!r[u]&&this[l])return!1;var a;return t.isFunction(e)?(a=e,n):(a=e.handler,void(e.handler=n))}}}(e,window),t("util",i)});layui.define("jquery",function(e){"use strict";var l=layui.$,o=function(e){},t='';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var f=l(e.elem);if(f[0]){var m=l(e.scrollElem||document),u=e.mb||50,s=!("isAuto"in e)||e.isAuto,v=e.end||"没有更多了",y=e.scrollElem&&e.scrollElem!==document,d="加载更多",h=l('");f.find(".layui-flow-more")[0]||f.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(v):h.find("a").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find("a").html(t),"function"==typeof e.done&&e.done(++c,p)};if(g(),h.find("a").on("click",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+" img",scrollElem:e.scrollElem});return s?(m.on("scroll",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),i||(r=setTimeout(function(){var i=y?e.height():l(window).height(),n=y?e.prop("scrollHeight"):document.documentElement.scrollHeight;n-t-i<=u&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||"img",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr("src")){var m=e.attr("lay-src");layui.img(m,function(){var l=t.lazyimg.elem.eq(i);e.attr("src",m).removeAttr("lay-src"),l[0]&&f(l),i++})}},f=function(e,o){var f=a?(o||n).height():l(window).height(),m=n.scrollTop(),u=m+f;if(t.lazyimg.elem=l(r),e)c(e,f);else for(var s=0;su)break}};if(f(),!o){var m;n.on("scroll",function(){var e=l(this);m&&clearTimeout(m),m=setTimeout(function(){f(null,e)},50)}),o=!0}return f},e("flow",new o)});layui.define(["layer","form"],function(t){"use strict";var e=layui.$,i=layui.layer,a=layui.form,l=(layui.hint(),layui.device()),n="layedit",o="layui-show",r="layui-disabled",c=function(){var t=this;t.index=0,t.config={tool:["strong","italic","underline","del","|","left","center","right","|","link","unlink","face","image"],hideTool:[],height:280}};c.prototype.set=function(t){var i=this;return e.extend(!0,i.config,t),i},c.prototype.on=function(t,e){return layui.onevent(n,t,e)},c.prototype.build=function(t,i){i=i||{};var a=this,n=a.config,r="layui-layedit",c=e("string"==typeof t?"#"+t:t),u="LAY_layedit_"+ ++a.index,d=c.next("."+r),y=e.extend({},n,i),f=function(){var t=[],e={};return layui.each(y.hideTool,function(t,i){e[i]=!0}),layui.each(y.tool,function(i,a){C[a]&&!e[a]&&t.push(C[a])}),t.join("")}(),m=e(['
            ','
            '+f+"
            ",'
            ','',"
            ","
            "].join(""));return l.ie&&l.ie<8?c.removeClass("layui-hide").addClass(o):(d[0]&&d.remove(),s.call(a,m,c[0],y),c.addClass("layui-hide").after(m),a.index)},c.prototype.getContent=function(t){var e=u(t);if(e[0])return d(e[0].document.body.innerHTML)},c.prototype.getText=function(t){var i=u(t);if(i[0])return e(i[0].document.body).text()},c.prototype.setContent=function(t,i,a){var l=u(t);l[0]&&(a?e(l[0].document.body).append(i):e(l[0].document.body).html(i),layedit.sync(t))},c.prototype.sync=function(t){var i=u(t);if(i[0]){var a=e("#"+i[1].attr("textarea"));a.val(d(i[0].document.body.innerHTML))}},c.prototype.getSelection=function(t){var e=u(t);if(e[0]){var i=m(e[0].document);return document.selection?i.text:i.toString()}};var s=function(t,i,a){var l=this,n=t.find("iframe");n.css({height:a.height}).on("load",function(){var o=n.contents(),r=n.prop("contentWindow"),c=o.find("head"),s=e([""].join("")),u=o.find("body");c.append(s),u.attr("contenteditable","true").css({"min-height":a.height}).html(i.value||""),y.apply(l,[r,n,i,a]),g.call(l,r,t,a)})},u=function(t){var i=e("#LAY_layedit_"+t),a=i.prop("contentWindow");return[a,i]},d=function(t){return 8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),t},y=function(t,a,n,o){var r=t.document,c=e(r.body);c.on("keydown",function(t){var e=t.keyCode;if(13===e){var a=m(r),l=p(a),n=l.parentNode;if("pre"===n.tagName.toLowerCase()){if(t.shiftKey)return;return i.msg("请暂时用shift+enter"),!1}r.execCommand("formatBlock",!1,"

            ")}}),e(n).parents("form").on("submit",function(){var t=c.html();8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),n.value=t}),c.on("paste",function(e){r.execCommand("formatBlock",!1,"

            "),setTimeout(function(){f.call(t,c),n.value=c.html()},100)})},f=function(t){var i=this;i.document;t.find("*[style]").each(function(){var t=this.style.textAlign;this.removeAttribute("style"),e(this).css({"text-align":t||""})}),t.find("table").addClass("layui-table"),t.find("script,link").remove()},m=function(t){return t.selection?t.selection.createRange():t.getSelection().getRangeAt(0)},p=function(t){return t.endContainer||t.parentElement().childNodes[0]},v=function(t,i,a){var l=this.document,n=document.createElement(t);for(var o in i)n.setAttribute(o,i[o]);if(n.removeAttribute("text"),l.selection){var r=a.text||i.text;if("a"===t&&!r)return;r&&(n.innerHTML=r),a.pasteHTML(e(n).prop("outerHTML")),a.select()}else{var r=a.toString()||i.text;if("a"===t&&!r)return;r&&(n.innerHTML=r),a.deleteContents(),a.insertNode(n)}},h=function(t,i){var a=this.document,l="layedit-tool-active",n=p(m(a)),o=function(e){return t.find(".layedit-tool-"+e)};i&&i[i.hasClass(l)?"removeClass":"addClass"](l),t.find(">i").removeClass(l),o("unlink").addClass(r),e(n).parents().each(function(){var t=this.tagName.toLowerCase(),e=this.style.textAlign;"b"!==t&&"strong"!==t||o("b").addClass(l),"i"!==t&&"em"!==t||o("i").addClass(l),"u"===t&&o("u").addClass(l),"strike"===t&&o("d").addClass(l),"p"===t&&("center"===e?o("center").addClass(l):"right"===e?o("right").addClass(l):o("left").addClass(l)),"a"===t&&(o("link").addClass(l),o("unlink").removeClass(r))})},g=function(t,a,l){var n=t.document,o=e(n.body),c={link:function(i){var a=p(i),l=e(a).parent();b.call(o,{href:l.attr("href"),target:l.attr("target")},function(e){var a=l[0];"A"===a.tagName?a.href=e.url:v.call(t,"a",{target:e.target,href:e.url,text:e.url},i)})},unlink:function(t){n.execCommand("unlink")},face:function(e){x.call(this,function(i){v.call(t,"img",{src:i.src,alt:i.alt},e)})},image:function(a){var n=this;layui.use("upload",function(o){var r=l.uploadImage||{};o.render({url:r.url,method:r.type,elem:e(n).find("input")[0],done:function(e){0==e.code?(e.data=e.data||{},v.call(t,"img",{src:e.data.src,alt:e.data.title},a)):i.msg(e.msg||"上传失败")}})})},code:function(e){k.call(o,function(i){v.call(t,"pre",{text:i.code,"lay-lang":i.lang},e)})},help:function(){i.open({type:2,title:"帮助",area:["600px","380px"],shadeClose:!0,shade:.1,skin:"layui-layer-msg",content:["http://www.layui.com/about/layedit/help.html","no"]})}},s=a.find(".layui-layedit-tool"),u=function(){var i=e(this),a=i.attr("layedit-event"),l=i.attr("lay-command");if(!i.hasClass(r)){o.focus();var u=m(n);u.commonAncestorContainer;l?(n.execCommand(l),/justifyLeft|justifyCenter|justifyRight/.test(l)&&n.execCommand("formatBlock",!1,"

            "),setTimeout(function(){o.focus()},10)):c[a]&&c[a].call(this,u),h.call(t,s,i)}},d=/image/;s.find(">i").on("mousedown",function(){var t=e(this),i=t.attr("layedit-event");d.test(i)||u.call(this)}).on("click",function(){var t=e(this),i=t.attr("layedit-event");d.test(i)&&u.call(this)}),o.on("click",function(){h.call(t,s),i.close(x.index)})},b=function(t,e){var l=this,n=i.open({type:1,id:"LAY_layedit_link",area:"350px",shade:.05,shadeClose:!0,moveType:1,title:"超链接",skin:"layui-layer-msg",content:['

              ','
            • ','','
              ','',"
              ","
            • ",'
            • ','','
              ','",'","
              ","
            • ",'
            • ','','',"
            • ","
            "].join(""),success:function(t,n){var o="submit(layedit-link-yes)";a.render("radio"),t.find(".layui-btn-primary").on("click",function(){i.close(n),l.focus()}),a.on(o,function(t){i.close(b.index),e&&e(t.field)})}});b.index=n},x=function(t){var a=function(){var t=["[微笑]","[嘻嘻]","[哈哈]","[可爱]","[可怜]","[挖鼻]","[吃惊]","[害羞]","[挤眼]","[闭嘴]","[鄙视]","[爱你]","[泪]","[偷笑]","[亲亲]","[生病]","[太开心]","[白眼]","[右哼哼]","[左哼哼]","[嘘]","[衰]","[委屈]","[吐]","[哈欠]","[抱抱]","[怒]","[疑问]","[馋嘴]","[拜拜]","[思考]","[汗]","[困]","[睡]","[钱]","[失望]","[酷]","[色]","[哼]","[鼓掌]","[晕]","[悲伤]","[抓狂]","[黑线]","[阴险]","[怒骂]","[互粉]","[心]","[伤心]","[猪头]","[熊猫]","[兔子]","[ok]","[耶]","[good]","[NO]","[赞]","[来]","[弱]","[草泥马]","[神马]","[囧]","[浮云]","[给力]","[围观]","[威武]","[奥特曼]","[礼物]","[钟]","[话筒]","[蜡烛]","[蛋糕]"],e={};return layui.each(t,function(t,i){e[i]=layui.cache.dir+"images/face/"+t+".gif"}),e}();return x.hide=x.hide||function(t){"face"!==e(t.target).attr("layedit-event")&&i.close(x.index)},x.index=i.tips(function(){var t=[];return layui.each(a,function(e,i){t.push('
          • '+e+'
          • ')}),'
              '+t.join("")+"
            "}(),this,{tips:1,time:0,skin:"layui-box layui-util-face",maxWidth:500,success:function(l,n){l.css({marginTop:-4,marginLeft:-10}).find(".layui-clear>li").on("click",function(){t&&t({src:a[this.title],alt:this.title}),i.close(n)}),e(document).off("click",x.hide).on("click",x.hide)}})},k=function(t){var e=this,l=i.open({type:1,id:"LAY_layedit_code",area:"550px",shade:.05,shadeClose:!0,moveType:1,title:"插入代码",skin:"layui-layer-msg",content:['
              ','
            • ','','
              ','","
              ","
            • ",'
            • ','','
              ','',"
              ","
            • ",'
            • ','','',"
            • ","
            "].join(""),success:function(l,n){var o="submit(layedit-code-yes)";a.render("select"),l.find(".layui-btn-primary").on("click",function(){i.close(n),e.focus()}),a.on(o,function(e){i.close(k.index),t&&t(e.field)})}});k.index=l},C={html:'',strong:'',italic:'',underline:'',del:'',"|":'',left:'',center:'',right:'',link:'',unlink:'',face:'',image:'',code:'',help:''},w=new c;t(n,w)});layui.define("jquery",function(e){"use strict";var a=layui.$,l="http://www.layui.com/doc/modules/code.html";e("code",function(e){var t=[];e=e||{},e.elem=a(e.elem||".layui-code"),e.about=!("about"in e)||e.about,e.elem.each(function(){t.push(this)}),layui.each(t.reverse(),function(t,i){var c=a(i),o=c.html();(c.attr("lay-encode")||e.encode)&&(o=o.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")),c.html('
            1. '+o.replace(/[\r\t\n]+/g,"
            2. ")+"
            "),c.find(">.layui-code-h3")[0]||c.prepend('

            '+(c.attr("lay-title")||e.title||"code")+(e.about?'layui.code':"")+"

            ");var d=c.find(">.layui-code-ol");c.addClass("layui-box layui-code-view"),(c.attr("lay-skin")||e.skin)&&c.addClass("layui-code-"+(c.attr("lay-skin")||e.skin)),(d.find("li").length/100|0)>0&&d.css("margin-left",(d.find("li").length/100|0)+"px"),(c.attr("lay-height")||e.height)&&d.css("max-height",c.attr("lay-height")||e.height)})})}).addcss("modules/code.css","skincodecss"); \ No newline at end of file diff --git "a/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/layui.js" "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/layui.js" new file mode 100644 index 00000000..4615b577 --- /dev/null +++ "b/Projects/\344\275\240\350\257\264\347\232\204\351\203\275\345\257\271/src/main/resources/static/components/layui/layui.js" @@ -0,0 +1,2 @@ +/** layui-v2.5.5 MIT License By https://www.layui.com */ + ;!function(e){"use strict";var t=document,o={modules:{},status:{},timeout:10,event:{}},n=function(){this.v="2.5.5"},r=function(){var e=t.currentScript?t.currentScript.src:function(){for(var e,o=t.scripts,n=o.length-1,r=n;r>0;r--)if("interactive"===o[r].readyState){e=o[r].src;break}return e||o[n].src}();return e.substring(0,e.lastIndexOf("/")+1)}(),i=function(t){e.console&&console.error&&console.error("Layui hint: "+t)},a="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),u={layer:"modules/layer",laydate:"modules/laydate",laypage:"modules/laypage",laytpl:"modules/laytpl",layim:"modules/layim",layedit:"modules/layedit",form:"modules/form",upload:"modules/upload",transfer:"modules/transfer",tree:"modules/tree",table:"modules/table",element:"modules/element",rate:"modules/rate",colorpicker:"modules/colorpicker",slider:"modules/slider",carousel:"modules/carousel",flow:"modules/flow",util:"modules/util",code:"modules/code",jquery:"modules/jquery",mobile:"modules/mobile","layui.all":"../layui.all"};n.prototype.cache=o,n.prototype.define=function(e,t){var n=this,r="function"==typeof e,i=function(){var e=function(e,t){layui[e]=t,o.status[e]=!0};return"function"==typeof t&&t(function(n,r){e(n,r),o.callback[n]=function(){t(e)}}),this};return r&&(t=e,e=[]),!layui["layui.all"]&&layui["layui.mobile"]?i.call(n):(n.use(e,i),n)},n.prototype.use=function(e,n,l){function s(e,t){var n="PLaySTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/;("load"===e.type||n.test((e.currentTarget||e.srcElement).readyState))&&(o.modules[f]=t,d.removeChild(v),function r(){return++m>1e3*o.timeout/4?i(f+" is not a valid module"):void(o.status[f]?c():setTimeout(r,4))}())}function c(){l.push(layui[f]),e.length>1?y.use(e.slice(1),n,l):"function"==typeof n&&n.apply(layui,l)}var y=this,p=o.dir=o.dir?o.dir:r,d=t.getElementsByTagName("head")[0];e="string"==typeof e?[e]:e,window.jQuery&&jQuery.fn.on&&(y.each(e,function(t,o){"jquery"===o&&e.splice(t,1)}),layui.jquery=layui.$=jQuery);var f=e[0],m=0;if(l=l||[],o.host=o.host||(p.match(/\/\/([\s\S]+?)\//)||["//"+location.host+"/"])[0],0===e.length||layui["layui.all"]&&u[f]||!layui["layui.all"]&&layui["layui.mobile"]&&u[f])return c(),y;if(o.modules[f])!function g(){return++m>1e3*o.timeout/4?i(f+" is not a valid module"):void("string"==typeof o.modules[f]&&o.status[f]?c():setTimeout(g,4))}();else{var v=t.createElement("script"),h=(u[f]?p+"lay/":/^\{\/\}/.test(y.modules[f])?"":o.base||"")+(y.modules[f]||f)+".js";h=h.replace(/^\{\/\}/,""),v.async=!0,v.charset="utf-8",v.src=h+function(){var e=o.version===!0?o.v||(new Date).getTime():o.version||"";return e?"?v="+e:""}(),d.appendChild(v),!v.attachEvent||v.attachEvent.toString&&v.attachEvent.toString().indexOf("[native code")<0||a?v.addEventListener("load",function(e){s(e,h)},!1):v.attachEvent("onreadystatechange",function(e){s(e,h)}),o.modules[f]=h}return y},n.prototype.getStyle=function(t,o){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](o)},n.prototype.link=function(e,n,r){var a=this,u=t.createElement("link"),l=t.getElementsByTagName("head")[0];"string"==typeof n&&(r=n);var s=(r||e).replace(/\.|\//g,""),c=u.id="layuicss-"+s,y=0;return u.rel="stylesheet",u.href=e+(o.debug?"?v="+(new Date).getTime():""),u.media="all",t.getElementById(c)||l.appendChild(u),"function"!=typeof n?a:(function p(){return++y>1e3*o.timeout/100?i(e+" timeout"):void(1989===parseInt(a.getStyle(t.getElementById(c),"width"))?function(){n()}():setTimeout(p,100))}(),a)},o.callback={},n.prototype.factory=function(e){if(layui[e])return"function"==typeof o.callback[e]?o.callback[e]:null},n.prototype.addcss=function(e,t,n){return layui.link(o.dir+"css/"+e,t,n)},n.prototype.img=function(e,t,o){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,"function"==typeof t&&t(n)},void(n.onerror=function(e){n.onerror=null,"function"==typeof o&&o(e)}))},n.prototype.config=function(e){e=e||{};for(var t in e)o[t]=e[t];return this},n.prototype.modules=function(){var e={};for(var t in u)e[t]=u[t];return e}(),n.prototype.extend=function(e){var t=this;e=e||{};for(var o in e)t[o]||t.modules[o]?i("模块名 "+o+" 已被占用"):t.modules[o]=e[o];return t},n.prototype.router=function(e){var t=this,e=e||location.hash,o={path:[],search:{},hash:(e.match(/[^#](#.*$)/)||[])[1]||""};return/^#\//.test(e)?(e=e.replace(/^#\//,""),o.href="/"+e,e=e.replace(/([^#])(#.*$)/,"$1").split("/")||[],t.each(e,function(e,t){/^\w+=/.test(t)?function(){t=t.split("="),o.search[t[0]]=t[1]}():o.path.push(t)}),o):o},n.prototype.data=function(t,o,n){if(t=t||"layui",n=n||localStorage,e.JSON&&e.JSON.parse){if(null===o)return delete n[t];o="object"==typeof o?o:{key:o};try{var r=JSON.parse(n[t])}catch(i){var r={}}return"value"in o&&(r[o.key]=o.value),o.remove&&delete r[o.key],n[t]=JSON.stringify(r),o.key?r[o.key]:r}},n.prototype.sessionData=function(e,t){return this.data(e,t,sessionStorage)},n.prototype.device=function(t){var o=navigator.userAgent.toLowerCase(),n=function(e){var t=new RegExp(e+"/([^\\s\\_\\-]+)");return e=(o.match(t)||[])[1],e||!1},r={os:function(){return/windows/.test(o)?"windows":/linux/.test(o)?"linux":/iphone|ipod|ipad|ios/.test(o)?"ios":/mac/.test(o)?"mac":void 0}(),ie:function(){return!!(e.ActiveXObject||"ActiveXObject"in e)&&((o.match(/msie\s(\d+)/)||[])[1]||"11")}(),weixin:n("micromessenger")};return t&&!r[t]&&(r[t]=n(t)),r.android=/android/.test(o),r.ios="ios"===r.os,r},n.prototype.hint=function(){return{error:i}},n.prototype.each=function(e,t){var o,n=this;if("function"!=typeof t)return n;if(e=e||[],e.constructor===Object){for(o in e)if(t.call(e[o],o,e[o]))break}else for(o=0;oi?1:r