diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/docs/200.html b/docs/200.html new file mode 100644 index 000000000..567f5f39a --- /dev/null +++ b/docs/200.html @@ -0,0 +1,15 @@ + + + + + + + + + +
Loading...
+ + + + + diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..cf004353b --- /dev/null +++ b/docs/README.md @@ -0,0 +1,11 @@ +# STATIC + +**This directory is not required, you can delete it if you don't want to use it.** + +This directory contains your static files. +Each file inside this directory is mapped to `/`. +Thus you'd want to delete this README.md before deploying to production. + +Example: `/static/robots.txt` is mapped as `/robots.txt`. + +More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static). diff --git a/docs/_nuxt/5230358.js b/docs/_nuxt/5230358.js new file mode 100644 index 000000000..4f17d59a2 --- /dev/null +++ b/docs/_nuxt/5230358.js @@ -0,0 +1 @@ +!function(e){function c(data){for(var c,f,t=data[0],o=data[1],l=data[2],i=0,h=[];i + * @author Lea Verou + * @namespace + * @public + */ + + +/*! + * vue-client-only v0.0.0-semantic-release + * (c) 2021-present egoist <0x142857@gmail.com> + * Released under the MIT License. + */ + +/*! + * vue-i18n v8.28.2 + * (c) 2022 kazuya kawaguchi + * Released under the MIT License. + */ + +/*! + * vue-no-ssr v1.1.1 + * (c) 2018-present egoist <0x142857@gmail.com> + * Released under the MIT License. + */ + + +/*! + * Vue.js v2.6.14 + * (c) 2014-2021 Evan You + * Released under the MIT License. + */ + +/*! + * cookie + * Copyright(c) 2012-2014 Roman Shtylman + * Copyright(c) 2015 Douglas Christopher Wilson + * MIT Licensed + */ + +/*! + * vuex v3.6.2 + * (c) 2021 Evan You + * @license MIT + */ diff --git a/docs/_nuxt/css/093f748.css b/docs/_nuxt/css/093f748.css new file mode 100644 index 000000000..f42db0b4c --- /dev/null +++ b/docs/_nuxt/css/093f748.css @@ -0,0 +1 @@ +.__nuxt-error-page{padding:1rem;background:#f7f8fb;color:#47494e;text-align:center;display:flex;justify-content:center;align-items:center;flex-direction:column;font-family:sans-serif;font-weight:100!important;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;position:absolute;top:0;left:0;right:0;bottom:0}.__nuxt-error-page .error{max-width:450px}.__nuxt-error-page .title{font-size:1.5rem;margin-top:15px;color:#47494e;margin-bottom:8px}.__nuxt-error-page .description{color:#7f828b;line-height:21px;margin-bottom:10px}.__nuxt-error-page a{color:#7f828b!important;text-decoration:none}.__nuxt-error-page .logo{position:fixed;left:12px;bottom:12px}.nuxt-progress{position:fixed;top:0;left:0;right:0;height:2px;width:0;opacity:1;transition:width .1s,opacity .4s;background-color:#f72c5b;z-index:999999}.nuxt-progress.nuxt-progress-notransition{transition:none}.nuxt-progress-failed{background-color:red}.page-content .nav-item{margin:0}.page-content .nav-item .nav-link{--tw-text-opacity:1;color:rgba(100,116,139,var(--tw-text-opacity))}.page-content .nav-item a.nav-link{cursor:pointer}.page-content .nav-item .nav-link.nuxt-link-active{font-weight:700;color:#337ab7}.algolia-autocomplete .ds-dropdown-menu{border-style:none;--tw-shadow:0 20px 25px -5px rgba(0,0,0,0.1),0 10px 10px -5px rgba(0,0,0,0.04);box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-]{border-style:none}.algolia-autocomplete .ds-dropdown-menu:before{border-style:none;--tw-shadow:0 20px 25px -5px rgba(0,0,0,0.1),0 10px 10px -5px rgba(0,0,0,0.04);box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.bd-sidebar{position:sticky;z-index:1000;top:0;left:0;padding:0;overflow:visible;border-right:1px solid #eee;border-bottom:none;max-width:350px;height:calc(100vh - 50px)}.bd-sidebar .open-sidebar{display:none}.bd-sidebar .bd-docs-nav{overflow-x:hidden;overflow-y:auto;height:calc(100% - 83px);padding-bottom:10px;padding-top:10px;margin-top:5px;margin-bottom:5px}.bd-sidebar .sidebar-search{padding:15px 20px;border-bottom:1px solid #eee}.bd-sidebar .sidebar-search .algolia-autocomplete{width:100%}.bd-sidebar .sidebar-search input{width:100%;border-radius:.75rem;border-width:0;--tw-shadow:0 1px 3px 0 rgba(0,0,0,0.1),0 1px 2px 0 rgba(0,0,0,0.06);box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow);outline:2px solid transparent;outline-offset:2px;padding:1rem 3rem 1rem 1rem}.bd-sidebar .sidebar-search .search-icon{position:absolute;right:3rem;top:28px}@media (max-width:768px){.bd-sidebar.closed{left:-280px;--tw-shadow:0 0 transparent}.bd-sidebar,.bd-sidebar.closed{box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.bd-sidebar{position:fixed;left:0;width:280px;top:50px;bottom:0;background-color:#fff;--tw-shadow:0 25px 50px -12px rgba(0,0,0,0.25);border-right:none;overflow:visible;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.bd-sidebar .bd-docs-nav{width:280px}.bd-sidebar .open-sidebar{display:block;position:absolute;left:280px;bottom:60px;width:40px;height:40px;padding:5px;color:#000;z-index:1200;background:#eee;border-top-right-radius:1rem;border-bottom-right-radius:1rem;--tw-shadow:0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05);box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.bd-sidebar .open-sidebar svg{width:100%;height:100%}}.bd-sidenav{display:none}.page-content{padding-bottom:0}.page-content .nav{display:block}.page-content ul.nav{padding-left:0}.page-content .nav>li>a:focus,.page-content .nav>li>a:hover{background-color:#f6f8fc}.page-content .nav .b-icon.bi{font-size:90%;opacity:.6;position:relative;top:-2px}.page-content .glyphicon{padding:5px;color:#cfd9e2;cursor:pointer;transform:scale(.8);top:2px;left:-4px;margin:-5px 0}.page-content .level0>li>.nav-link{margin-top:5px;padding:6px 0 6px 20px;font-weight:700;--tw-text-opacity:1;color:rgba(30,41,59,var(--tw-text-opacity))}.page-content .level1{margin-top:4px;font-size:14px}.page-content .level1 .nav-link{padding:6px 0 6px 35px}.page-content .level2 .nav-link{padding:5px 0 5px 50px}.page-content .level3{margin-top:1px}.page-content .level3 .nav-link{padding:5px 0 5px 60px}svg.icon-external-link{display:initial;vertical-align:initial}body{font-family:Open Sans,PingFang SC,Helvetica,Arial,sans-serif}.page-main{overflow-x:hidden}.handbook-content{padding-left:0;padding-right:0}.bd-content{padding-left:50px}@media (max-width:768px){.bd-content{padding-left:30px;padding-right:30px}}.post-content{margin:0 auto;max-width:960px}.post-inner{margin:20px 0 80px;--tw-text-opacity:1;color:rgba(100,116,139,var(--tw-text-opacity))}.post-inner h1,.post-inner h2,.post-inner h3,.post-inner h4,.post-inner h5,.post-inner h6{font-weight:500;scroll-margin-top:20px}.post-inner h1:hover .permalink,.post-inner h2:hover .permalink,.post-inner h3:hover .permalink,.post-inner h4:hover .permalink,.post-inner h5:hover .permalink,.post-inner h6:hover .permalink{display:inline-block}.post-inner h1{margin:40px 0 30px;font-size:36px;font-weight:700;--tw-text-opacity:1;color:rgba(51,65,85,var(--tw-text-opacity))}.post-inner h2{margin:60px 0 20px;padding-bottom:20px;font-size:28px;--tw-text-opacity:1;color:rgba(71,85,105,var(--tw-text-opacity));border-bottom:1px solid #eee}.post-inner h1+h2{margin-top:40px}.post-inner h3{margin:40px 0 20px;font-size:22px}.post-inner h3,.post-inner h4{--tw-text-opacity:1;color:rgba(71,85,105,var(--tw-text-opacity))}.post-inner h4{margin:25px 0 20px;font-size:18px}.post-inner h5{font-size:16px}.post-inner h5,.post-inner h6{--tw-text-opacity:1;color:rgba(100,116,139,var(--tw-text-opacity))}.post-inner h6{font-size:14px}.post-inner .permalink{display:none}.post-inner blockquote{margin:15px 0;padding:20px 15px;border-radius:.5rem;border-left-width:4px;--tw-border-opacity:1;border-color:rgba(96,165,250,var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgba(219,234,254,var(--tw-bg-opacity))}.post-inner blockquote code{border-width:0;--tw-bg-opacity:1;background-color:rgba(191,219,254,var(--tw-bg-opacity));color:currentColor;--tw-shadow:0 0 transparent;box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.post-inner blockquote :first-child{margin-top:0}.post-inner blockquote :last-child{margin-bottom:0}.post-inner blockquote pre{margin:20px 0;border-radius:5px;border:none;padding:10px;background:none;font-size:13px}.post-inner code{font-size:14px}.post-inner iframe{border:none;margin:10px 0}.post-inner ol,.post-inner ul{padding-left:20px}.post-inner li,.post-inner p{line-height:1.7em;font-size:16px}.post-inner p{margin:15px 0}.post-inner img{border-radius:.5rem;--tw-shadow:0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05);box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.post-inner a{color:#337ab7}.post-inner .table-of-contents{position:fixed;left:77%;width:21%;top:65px;max-height:calc(100% - 85px);display:flex;flex-direction:column;background-color:transparent;padding:10px;overflow:hidden;z-index:10}@media (max-width:768px){.post-inner .table-of-contents{position:relative;width:100%;left:0;top:0;padding:0;margin:0 0 10px}}.post-inner .table-of-contents .toc-container-header{font-size:16px;font-weight:700}.post-inner .table-of-contents ul{padding-left:0;margin-bottom:0;flex-grow:1;overflow:auto}.post-inner .table-of-contents ul li{list-style:none;font-size:14px}.post-inner .table-of-contents ul li.toc2{font-size:15px}.post-inner .table-of-contents ul li.toc3{font-size:14px;padding-left:15px}.post-inner .table-of-contents ul li.toc3+.toc2{margin-top:15px}.post-inner .table-of-contents a{--tw-text-opacity:1;color:rgba(100,116,139,var(--tw-text-opacity));transition:.5s}.post-inner .table-of-contents a:hover{color:#555} \ No newline at end of file diff --git a/docs/_nuxt/css/3556c50.css b/docs/_nuxt/css/3556c50.css new file mode 100644 index 000000000..1a5325eab --- /dev/null +++ b/docs/_nuxt/css/3556c50.css @@ -0,0 +1 @@ +.prism-editor-wrapper{width:100%;height:100%;display:flex;align-items:flex-start;overflow:auto;-o-tab-size:1.5em;tab-size:1.5em;-moz-tab-size:1.5em}@media (-ms-high-contrast:active),(-ms-high-contrast:none){.prism-editor-wrapper .prism-editor__textarea{color:transparent!important}.prism-editor-wrapper .prism-editor__textarea::-moz-selection{background-color:#accef7!important;color:transparent!important}.prism-editor-wrapper .prism-editor__textarea::selection{background-color:#accef7!important;color:transparent!important}}.prism-editor-wrapper .prism-editor__container{position:relative;text-align:left;box-sizing:border-box;padding:0;overflow:hidden;width:100%}.prism-editor-wrapper .prism-editor__line-numbers{height:100%;overflow:hidden;flex-shrink:0;padding-top:4px;margin-top:0;margin-right:10px}.prism-editor-wrapper .prism-editor__line-number{text-align:right;white-space:nowrap}.prism-editor-wrapper .prism-editor__textarea{position:absolute;top:0;left:0;height:100%;width:100%;resize:none;color:inherit;overflow:hidden;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;-webkit-text-fill-color:transparent}.prism-editor-wrapper .prism-editor__editor,.prism-editor-wrapper .prism-editor__textarea{margin:0;border:0;background:none;box-sizing:inherit;display:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-variant-ligatures:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;-moz-tab-size:inherit;-o-tab-size:inherit;tab-size:inherit;text-indent:inherit;text-rendering:inherit;text-transform:inherit;white-space:pre-wrap;word-wrap:keep-all;overflow-wrap:break-word;padding:0}.prism-editor-wrapper .prism-editor__textarea--empty{-webkit-text-fill-color:inherit!important}.prism-editor-wrapper .prism-editor__editor{position:relative;pointer-events:none}code[class*=language-],pre[class*=language-]{text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;color:#c3cee3;background:#263238;font-family:Roboto Mono,monospace;font-size:1em;line-height:1.5em;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}code[class*=language-]::-moz-selection,code[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection{background:#363636}code[class*=language-]::selection,code[class*=language-] ::selection,pre[class*=language-]::selection,pre[class*=language-] ::selection{background:#363636}:not(pre)>code[class*=language-]{white-space:normal;border-radius:.2em;padding:.1em}pre[class*=language-]{overflow:auto;position:relative;margin:.5em 0;padding:1.25em 1em}.language-css>code,.language-sass>code,.language-scss>code{color:#fd9170}[class*=language-] .namespace{opacity:.7}.token.atrule{color:#c792ea}.token.attr-name{color:#ffcb6b}.token.attr-value,.token.attribute{color:#c3e88d}.token.boolean{color:#c792ea}.token.builtin{color:#ffcb6b}.token.cdata,.token.char{color:#80cbc4}.token.class{color:#ffcb6b}.token.class-name,.token.color{color:#f2ff00}.token.comment{color:#546e7a}.token.constant{color:#c792ea}.token.deleted{color:#f07178}.token.doctype{color:#546e7a}.token.entity{color:#f07178}.token.function{color:#c792ea}.token.hexcode{color:#f2ff00}.token.id,.token.important{color:#c792ea;font-weight:700}.token.inserted{color:#80cbc4}.token.keyword{color:#c792ea;font-style:italic}.token.number{color:#fd9170}.token.operator{color:#89ddff}.token.prolog{color:#546e7a}.token.property{color:#80cbc4}.token.pseudo-class,.token.pseudo-element{color:#c3e88d}.token.punctuation{color:#89ddff}.token.regex{color:#f2ff00}.token.selector{color:#f07178}.token.string{color:#c3e88d}.token.symbol{color:#c792ea}.token.tag,.token.unit{color:#f07178}.token.url{color:#fd9170}.token.variable{color:#f07178} \ No newline at end of file diff --git a/docs/_nuxt/css/8117eb7.css b/docs/_nuxt/css/8117eb7.css new file mode 100644 index 000000000..346001dfc --- /dev/null +++ b/docs/_nuxt/css/8117eb7.css @@ -0,0 +1,3 @@ +/*! tailwindcss v2.2.19 | MIT License | https://tailwindcss.com*/ + +/*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */html{-moz-tab-size:4;-o-tab-size:4;tab-size:4;line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji}hr{height:0;color:inherit}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=button],button{-webkit-appearance:button}::-moz-focus-inner{border-style:none;padding:0}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}button{background-color:transparent;background-image:none}fieldset,ol,ul{margin:0;padding:0}ol,ul{list-style:none}html{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{font-family:inherit;line-height:inherit}*,:after,:before{box-sizing:border-box;border:0 solid}hr{border-top-width:1px}img{border-style:solid}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}table{border-collapse:collapse}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:after,:before{--tw-border-opacity:1;border-color:rgba(229,231,235,var(--tw-border-opacity))}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.static{position:static}.fixed{position:fixed}.mt-10{margin-top:2.5rem}.mr-4{margin-right:1rem}.mr-7{margin-right:1.75rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.table{display:table}.hidden{display:none}.h-6{height:1.5rem}.h-8{height:2rem}.w-6{width:1.5rem}.w-8{width:2rem}.w-full{width:100%}.flex-grow{flex-grow:1}.transform{--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;transform:translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(1turn)}}@keyframes ping{75%,to{transform:scale(2);opacity:0}}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.resize{resize:both}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.border-0{border-width:0}.border{border-width:1px}.border-l-4{border-left-width:4px}.border-blue-400{--tw-border-opacity:1;border-color:rgba(96,165,250,var(--tw-border-opacity))}.border-blue-gray-200{--tw-border-opacity:1;border-color:rgba(226,232,240,var(--tw-border-opacity))}.border-blue-gray-400{--tw-border-opacity:1;border-color:rgba(148,163,184,var(--tw-border-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgba(254,226,226,var(--tw-bg-opacity))}.bg-red-200{--tw-bg-opacity:1;background-color:rgba(254,202,202,var(--tw-bg-opacity))}.bg-green-100{--tw-bg-opacity:1;background-color:rgba(209,250,229,var(--tw-bg-opacity))}.bg-green-200{--tw-bg-opacity:1;background-color:rgba(167,243,208,var(--tw-bg-opacity))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgba(219,234,254,var(--tw-bg-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgba(191,219,254,var(--tw-bg-opacity))}.bg-orange-100{--tw-bg-opacity:1;background-color:rgba(255,237,213,var(--tw-bg-opacity))}.bg-orange-200{--tw-bg-opacity:1;background-color:rgba(254,215,170,var(--tw-bg-opacity))}.bg-blue-gray-400{--tw-bg-opacity:1;background-color:rgba(148,163,184,var(--tw-bg-opacity))}.p-4{padding:1rem}.align-middle{vertical-align:middle}.text-sm{font-size:.875rem;line-height:1.25rem}.text-blue-gray-400{--tw-text-opacity:1;color:rgba(148,163,184,var(--tw-text-opacity))}*,:after,:before{--tw-shadow:0 0 transparent}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,0.1),0 1px 2px 0 rgba(0,0,0,0.06)}.shadow,.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05)}.shadow-xl{--tw-shadow:0 20px 25px -5px rgba(0,0,0,0.1),0 10px 10px -5px rgba(0,0,0,0.04)}.shadow-none,.shadow-xl{box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.shadow-none{--tw-shadow:0 0 transparent}*,:after,:before{--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,0.5);--tw-ring-offset-shadow:0 0 transparent;--tw-ring-shadow:0 0 transparent}.transition{transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s} \ No newline at end of file diff --git a/docs/_nuxt/css/ba9ec8a.css b/docs/_nuxt/css/ba9ec8a.css new file mode 100644 index 000000000..f9b5cbde7 --- /dev/null +++ b/docs/_nuxt/css/ba9ec8a.css @@ -0,0 +1 @@ +.md-alert[data-v-baf1bad2]{border-radius:.5rem;border-left-width:4px}.md-alert-info[data-v-baf1bad2]{--tw-border-opacity:1;border-color:rgba(96,165,250,var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgba(219,234,254,var(--tw-bg-opacity))}.md-alert-info code[data-v-baf1bad2]{border-width:0;--tw-bg-opacity:1;background-color:rgba(191,219,254,var(--tw-bg-opacity));color:currentColor;--tw-shadow:0 0 transparent;box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.md-alert-info .md-alert-icon[data-v-baf1bad2]{--tw-text-opacity:1;color:rgba(96,165,250,var(--tw-text-opacity))}.md-alert-info .md-alert-content[data-v-baf1bad2]{--tw-text-opacity:1;color:rgba(29,78,216,var(--tw-text-opacity))}.md-alert-success[data-v-baf1bad2]{--tw-border-opacity:1;border-color:rgba(52,211,153,var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgba(209,250,229,var(--tw-bg-opacity))}.md-alert-success code[data-v-baf1bad2]{border-width:0;--tw-bg-opacity:1;background-color:rgba(167,243,208,var(--tw-bg-opacity));color:currentColor;--tw-shadow:0 0 transparent;box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.md-alert-success .md-alert-icon[data-v-baf1bad2]{--tw-text-opacity:1;color:rgba(52,211,153,var(--tw-text-opacity))}.md-alert-success .md-alert-content[data-v-baf1bad2]{--tw-text-opacity:1;color:rgba(4,120,87,var(--tw-text-opacity))}.md-alert-warning[data-v-baf1bad2]{--tw-border-opacity:1;border-color:rgba(251,146,60,var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgba(255,237,213,var(--tw-bg-opacity))}.md-alert-warning code[data-v-baf1bad2]{border-width:0;--tw-bg-opacity:1;background-color:rgba(254,215,170,var(--tw-bg-opacity));color:currentColor;--tw-shadow:0 0 transparent;box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.md-alert-warning .md-alert-icon[data-v-baf1bad2]{--tw-text-opacity:1;color:rgba(251,146,60,var(--tw-text-opacity))}.md-alert-warning .md-alert-content[data-v-baf1bad2]{--tw-text-opacity:1;color:rgba(194,65,12,var(--tw-text-opacity))}.md-alert-danger[data-v-baf1bad2]{--tw-border-opacity:1;border-color:rgba(248,113,113,var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgba(254,226,226,var(--tw-bg-opacity))}.md-alert-danger code[data-v-baf1bad2]{border-width:0;--tw-bg-opacity:1;background-color:rgba(254,202,202,var(--tw-bg-opacity));color:currentColor;--tw-shadow:0 0 transparent;box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.md-alert-danger .md-alert-icon[data-v-baf1bad2]{--tw-text-opacity:1;color:rgba(248,113,113,var(--tw-text-opacity))}.md-alert-danger .md-alert-content[data-v-baf1bad2]{--tw-text-opacity:1;color:rgba(185,28,28,var(--tw-text-opacity))}.clipboard[data-v-479657ca]{position:absolute;right:0;bottom:0;--tw-text-opacity:1;color:rgba(148,163,184,var(--tw-text-opacity));margin-right:1.75rem;margin-bottom:.75rem;border-radius:.5rem;border-width:1px;--tw-border-opacity:1;border-color:rgba(148,163,184,var(--tw-border-opacity));padding:.5rem;cursor:pointer}.clipboard[data-v-479657ca]:hover{--tw-bg-opacity:1;background-color:rgba(148,163,184,var(--tw-bg-opacity));--tw-bg-opacity:0.25}.clipboard[data-v-479657ca]{width:30px;height:30px}.clipboard svg[data-v-479657ca]{width:100%;height:100%}&:hover .clipboard[data-v-479657ca]{display:block}.md-live{overflow:hidden;margin-top:2.5rem;margin-bottom:5rem;border-radius:.5rem;--tw-shadow:0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05);box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow);display:flex;flex-direction:column-reverse}@media (max-width:768px){.md-live{min-height:500px}}@media (min-width:768px){.md-live.layout-lr{flex-direction:row}.md-live.layout-rl{flex-direction:row-reverse}.md-live.layout-tb{flex-direction:column}.md-live.layout-bt{flex-direction:column-reverse}.md-live.layout-lr,.md-live.layout-rl{align-items:stretch}.md-live.layout-lr .md-live-editor-container,.md-live.layout-rl .md-live-editor-container{height:100%}.md-live.layout-lr .md-live-editor,.md-live.layout-rl .md-live-editor{flex:1 1 0%}.md-live.layout-lr .md-live-preview,.md-live.layout-rl .md-live-preview{flex:1 1 0%;height:auto}}.md-live-editor{position:relative}.md-live-editor ::-webkit-scrollbar-thumb{background:hsla(0,0%,100%,.3)!important}.md-live-editor .md-live-editor-container{background:#263238;max-height:500px;overflow-y:auto;font-size:13px;padding:10px}@media (max-width:768px){.md-live-editor .md-live-editor-container{max-height:300px}}.md-live-editor pre{color:#c3cee3}.md-live-editor .md-live-tag{position:absolute;right:0;top:0;text-transform:uppercase;margin-top:.75rem;margin-right:1.75rem;color:#f7fafc;z-index:10}.md-live-editor .clipboard{display:none}.md-live-editor:hover .clipboard{display:block}.md-live-preview{height:300px;overflow:hidden}.prism-editor-wrapper .prism-editor__editor,.prism-editor-wrapper .prism-editor__textarea{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;line-height:1.5}.prism-editor__textarea:focus{outline:none}.md-code-block{position:relative}.nuxt-content-highlight{line-height:1em;font-size:13px}.nuxt-content-highlight code[class*=language-],.nuxt-content-highlight pre[class*=language-]{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;color:#c3cee3;background:#263238;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;text-align:left;border:none}.nuxt-content-highlight code[class*=language-]::-moz-selection,.nuxt-content-highlight code[class*=language-] ::-moz-selection,.nuxt-content-highlight pre[class*=language-]::-moz-selection,.nuxt-content-highlight pre[class*=language-] ::-moz-selection{background:rgba(0,116,255,.8);color:#fff}.nuxt-content-highlight code[class*=language-]::selection,.nuxt-content-highlight code[class*=language-] ::selection,.nuxt-content-highlight pre[class*=language-]::selection,.nuxt-content-highlight pre[class*=language-] ::selection{background:rgba(0,116,255,.8);color:#fff}.nuxt-content-highlight .filename{position:absolute;right:0;top:0;z-index:10;font-family:DM Mono,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.875rem;line-height:1.25rem;letter-spacing:-.025em;line-height:1;margin-top:.75rem;margin-right:1rem;--tw-text-opacity:1;color:rgba(148,163,184,var(--tw-text-opacity))}.nuxt-content-highlight .clipboard{display:none}.nuxt-content-highlight:hover .clipboard{display:block}.post-contributors{margin-bottom:50px;padding-top:10px;border-top:1px solid #ddd;--tw-text-opacity:1;color:rgba(71,85,105,var(--tw-text-opacity))}.post-contributors a{--tw-text-opacity:1;color:rgba(100,116,139,var(--tw-text-opacity))}.post-contributors .post-contributors-list{margin-top:10px}.post-contributors .post-contributor{display:inline-block;margin-right:15px;margin-top:10px;border-width:1px;--tw-border-opacity:1;border-color:rgba(226,232,240,var(--tw-border-opacity));border-radius:.5rem}.post-contributors .post-contributor:hover{text-decoration:none;--tw-border-opacity:1;border-color:rgba(203,213,225,var(--tw-border-opacity))}.post-contributors .post-contributor img{width:40px;height:40px;border-top-left-radius:.375rem;border-bottom-left-radius:.375rem}.post-contributors .post-contributor img,.post-contributors .post-contributor span{display:inline-block}.post-contributors .post-contributor span{margin:0 8px 0 5px;position:relative;top:2px}.post-edit{margin:20px 0} \ No newline at end of file diff --git a/docs/_nuxt/js/010c596d178e73731ef5.js b/docs/_nuxt/js/010c596d178e73731ef5.js new file mode 100644 index 000000000..b019c94fe --- /dev/null +++ b/docs/_nuxt/js/010c596d178e73731ef5.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[106],{404:function(n,w,o){"use strict";o.r(w),w.default=""}}]); \ No newline at end of file diff --git a/docs/_nuxt/js/03d93934d87588de59ab.js b/docs/_nuxt/js/03d93934d87588de59ab.js new file mode 100644 index 000000000..6d680f40a --- /dev/null +++ b/docs/_nuxt/js/03d93934d87588de59ab.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[92],{390:function(n,t,e){"use strict";e.r(t),t.default='# 基础折线图\n\n折线图主要用来展示数据项随着时间推移的趋势或变化。折线图非常适合用于展示一个连续的二维数据,如某网站访问人数或商品销量价格的波动。\n\n\n\n折线图除了展示某个事情发展的趋势,还可以用来比较多个不同的数据序列。如下图,可以通过对比同时间段的三种商品的销量,分析哪一种商品的销量最好。\n\n\n\n折线图是将数据点之间用线连接起来绘制成的图表。为了追求美观或特殊的效果,还可以如上图将点与点之间用曲线连接,这种图又叫曲线图或样条图样条。样条图与折线图用法相同,区别是数据点之间的连线使用曲线绘制。\n\n## 折线图的使用建议\n\n1、使用实线绘制数据线,首先要保证能够的区分数据线和坐标轴线,并且要尽力要所有的数据清晰可识别。\n\n2、建议不要绘制 4 条以上的折线,如下图错误的示例,线都折叠在一起并且又没有明显的对比,整张图表就会混乱并难以阅读。\n\n\n\n3、不建议使用过多的装饰来区分图表,图例虽然可以帮助区分不同数据系列,但如下图使用过多种类的图例有时会让用户分心。\n\n\n\n4、展示折线图的数据时,要避免刻意的歪曲趋势。如下图,左图过于扁平化掩盖了想传达的信息,右图过于夸大趋势。要根据展示数据波动的参考单位,做有意义的波动分析。正确的数据高度是线约占 Y 轴高度的 2/3。\n\n\n'}}]); \ No newline at end of file diff --git a/docs/_nuxt/js/046162615fcf1ace21da.js b/docs/_nuxt/js/046162615fcf1ace21da.js new file mode 100644 index 000000000..24a25d76d --- /dev/null +++ b/docs/_nuxt/js/046162615fcf1ace21da.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[38],{336:function(e,n,t){"use strict";t.r(n),n.default="# Data Transform\n\n`Data transform` has been supported since Apache EChartsTM 5. In echarts, the term `data transform` means that generate new data from user provided source data and transform functions. both This feature is enable users to process data in declarative way, and provides users some common \"transform functions\" to make that kind of tasks \"out-of-the-box\". (For consistency in the context, the noun form of the word we keep using the \"transform\" rather than \"transformation\").\n\nThe abstract formula of data transform is: `outData = f(inputData)`, where the transform function `f` can be like `filter`, `sort`, `regression`, `boxplot`, `cluster`, `aggregate`(todo) ...\nWith the help of those transform methods, users can be implements the features like:\n\n- Partition data into multiple series.\n- Make some statistics and visualize the result.\n- Adapt some visualization algorithms to data and display the result.\n- Sort data.\n- Remove or choose some kind of empty or special datums.\n- ...\n\n## Get Started to Data Transform\n\nIn echarts, data transform is implemented based on the concept of [dataset](~${optionPath}#dataset). A [dataset.transform](${optionPath}#dataset.transform) can be configured in a dataset instance to indicate that this dataset is to be generated from this `transform`. For example:\n\n```js live\nvar option = {\n dataset: [\n {\n // This dataset is on `datasetIndex: 0`.\n source: [\n ['Product', 'Sales', 'Price', 'Year'],\n ['Cake', 123, 32, 2011],\n ['Cereal', 231, 14, 2011],\n ['Tofu', 235, 5, 2011],\n ['Dumpling', 341, 25, 2011],\n ['Biscuit', 122, 29, 2011],\n ['Cake', 143, 30, 2012],\n ['Cereal', 201, 19, 2012],\n ['Tofu', 255, 7, 2012],\n ['Dumpling', 241, 27, 2012],\n ['Biscuit', 102, 34, 2012],\n ['Cake', 153, 28, 2013],\n ['Cereal', 181, 21, 2013],\n ['Tofu', 395, 4, 2013],\n ['Dumpling', 281, 31, 2013],\n ['Biscuit', 92, 39, 2013],\n ['Cake', 223, 29, 2014],\n ['Cereal', 211, 17, 2014],\n ['Tofu', 345, 3, 2014],\n ['Dumpling', 211, 35, 2014],\n ['Biscuit', 72, 24, 2014]\n ]\n // id: 'a'\n },\n {\n // This dataset is on `datasetIndex: 1`.\n // A `transform` is configured to indicate that the\n // final data of this dataset is transformed via this\n // transform function.\n transform: {\n type: 'filter',\n config: { dimension: 'Year', value: 2011 }\n }\n // There can be optional properties `fromDatasetIndex` or `fromDatasetId`\n // to indicate that where is the input data of the transform from.\n // For example, `fromDatasetIndex: 0` specify the input data is from\n // the dataset on `datasetIndex: 0`, or `fromDatasetId: 'a'` specify the\n // input data is from the dataset having `id: 'a'`.\n // [DEFAULT_RULE]\n // If both `fromDatasetIndex` and `fromDatasetId` are omitted,\n // `fromDatasetIndex: 0` are used by default.\n },\n {\n // This dataset is on `datasetIndex: 2`.\n // Similarly, if neither `fromDatasetIndex` nor `fromDatasetId` is\n // specified, `fromDatasetIndex: 0` is used by default\n transform: {\n // The \"filter\" transform filters and gets data items only match\n // the given condition in property `config`.\n type: 'filter',\n // Transforms has a property `config`. In this \"filter\" transform,\n // the `config` specify the condition that each result data item\n // should be satisfied. In this case, this transform get all of\n // the data items that the value on dimension \"Year\" equals to 2012.\n config: { dimension: 'Year', value: 2012 }\n }\n },\n {\n // This dataset is on `datasetIndex: 3`\n transform: {\n type: 'filter',\n config: { dimension: 'Year', value: 2013 }\n }\n }\n ],\n series: [\n {\n type: 'pie',\n radius: 50,\n center: ['25%', '50%'],\n // In this case, each \"pie\" series reference to a dataset that has\n // the result of its \"filter\" transform.\n datasetIndex: 1\n },\n {\n type: 'pie',\n radius: 50,\n center: ['50%', '50%'],\n datasetIndex: 2\n },\n {\n type: 'pie',\n radius: 50,\n center: ['75%', '50%'],\n datasetIndex: 3\n }\n ]\n};\n```\n\nLet's summarize the key points of using data transform:\n\n- Generate new data from existing declared data via the declaration of `transform`, `fromDatasetIndex`/`fromDatasetId` in some blank dataset.\n- Series references these datasets to show the result.\n\n## Advanced Usage\n\n#### Piped Transform\n\nThere is a syntactic sugar that pipe transforms like:\n\n```js\noption = {\n dataset: [\n {\n source: [] // The original data\n },\n {\n // Declare transforms in an array to pipe multiple transforms,\n // which makes them execute one by one and take the output of\n // the previous transform as the input of the next transform.\n transform: [\n {\n type: 'filter',\n config: { dimension: 'Product', value: 'Tofu' }\n },\n {\n type: 'sort',\n config: { dimension: 'Year', order: 'desc' }\n }\n ]\n }\n ],\n series: {\n type: 'pie',\n // Display the result of the piped transform.\n datasetIndex: 1\n }\n};\n```\n\n> Note: theoretically any type of transform is able to have multiple input data and multiple output data. But when a transform is piped, it is only able to take one input (except it is the first transform of the pipe) and product one output (except it is the last transform of the pipe).\n\n#### Output Multiple Data\n\nIn most cases, transform functions only need to produce one data. But there is indeed scenarios that a transform function needs to produce multiple data, each of whom might be used by different series.\n\nFor example, in the built-in boxplot transform, besides boxplot data produced, the outlier data are also produced, which can be used in a scatter series. See the [example](${exampleEditorPath}boxplot-light-velocity).\n\nWe use prop [dataset.fromTransformResult](${optionPath}#dataset.fromTransformResult) to satisfy this requirement. For example:\n\n```js\noption = {\n dataset: [\n {\n // Original source data.\n source: []\n },\n {\n transform: {\n type: 'boxplot'\n }\n // After this \"boxplot transform\" two result data generated:\n // result[0]: The boxplot data\n // result[1]: The outlier data\n // By default, when series or other dataset reference this dataset,\n // only result[0] can be visited.\n // If we need to visit result[1], we have to use another dataset\n // as follows:\n },\n {\n // This extra dataset references the dataset above, and retrieves\n // the result[1] as its own data. Thus series or other dataset can\n // reference this dataset to get the data from result[1].\n fromDatasetIndex: 1,\n fromTransformResult: 1\n }\n ],\n xAxis: {\n type: 'category'\n },\n yAxis: {},\n series: [\n {\n name: 'boxplot',\n type: 'boxplot',\n // Reference the data from result[0].\n datasetIndex: 1\n },\n {\n name: 'outlier',\n type: 'scatter',\n // Reference the data from result[1].\n datasetIndex: 2\n }\n ]\n};\n```\n\nWhat more, [dataset.fromTransformResult](${optionPath}#dataset.fromTransformResult) and [dataset.transform](${optionPath}#dataset.transform) can both appear in one dataset, which means that the input of the transform is from retrieved from the upstream result specified by `fromTransformResult`. For example:\n\n```js\n{\n fromDatasetIndex: 1,\n fromTransformResult: 1,\n transform: {\n type: 'sort',\n config: { dimension: 2, order: 'desc' }\n }\n}\n```\n\n#### Debug in Develop Environment\n\nWhen using data transform, we might run into the trouble that the final chart do not display correctly but we do not know where the config is wrong. There is a property `transform.print` might help in such case. (`transform.print` is only available in dev environment).\n\n```js\noption = {\n dataset: [\n {\n source: []\n },\n {\n transform: {\n type: 'filter',\n config: {},\n // The result of this transform will be printed\n // in dev tool via `console.log`.\n print: true\n }\n }\n ]\n};\n```\n\n## Filter Transform\n\nTransform type \"filter\" is a built-in transform that provide data filter according to specified conditions. The basic option is like:\n\n```js live\noption = {\n dataset: [\n {\n source: [\n ['Product', 'Sales', 'Price', 'Year'],\n ['Cake', 123, 32, 2011],\n ['Latte', 231, 14, 2011],\n ['Tofu', 235, 5, 2011],\n ['Milk Tee', 341, 25, 2011],\n ['Porridge', 122, 29, 2011],\n ['Cake', 143, 30, 2012],\n ['Latte', 201, 19, 2012],\n ['Tofu', 255, 7, 2012],\n ['Milk Tee', 241, 27, 2012],\n ['Porridge', 102, 34, 2012],\n ['Cake', 153, 28, 2013],\n ['Latte', 181, 21, 2013],\n ['Tofu', 395, 4, 2013],\n ['Milk Tee', 281, 31, 2013],\n ['Porridge', 92, 39, 2013],\n ['Cake', 223, 29, 2014],\n ['Latte', 211, 17, 2014],\n ['Tofu', 345, 3, 2014],\n ['Milk Tee', 211, 35, 2014],\n ['Porridge', 72, 24, 2014]\n ]\n },\n {\n transform: {\n type: 'filter',\n config: { dimension: 'Year', '=': 2011 }\n // The config is the \"condition\" of this filter.\n // This transform traverse the source data and\n // and retrieve all the items that the \"Year\"\n // is `2011`.\n }\n }\n ],\n series: {\n type: 'pie',\n datasetIndex: 1\n }\n};\n```\n\nThis is another example of filter transform:\n\n\n\n**About dimension:**\n\nThe `config.dimension` can be:\n\n- Dimension name declared in dataset, like `config: { dimension: 'Year', '=': 2011 }`. Dimension name declaration is not mandatory.\n- Dimension index (start from 0), like `config: { dimension: 3, '=': 2011 }`.\n\n**About relational operator:**\n\nThe relational operator can be:\n`>`(`gt`), `>=`(`gte`), `<`(`lt`), `<=`(`lte`), `=`(`eq`), `!=`(`ne`, `<>`), `reg`. (The name in the parentheses are aliases). They follows the common semantics.\nBesides the common number comparison, there is some extra features:\n\n- Multiple operators are able to appear in one {} item like `{ dimension: 'Price', '>=': 20, '<': 30 }`, which means logical \"and\" (Price >= 20 and Price < 30).\n- The data value can be \"numeric string\". Numeric string is a string that can be converted to number. Like ' 123 '. White spaces and line breaks will be auto trimmed in the conversion.\n- If we need to compare \"JS `Date` instance\" or date string (like '2012-05-12'), we need to specify `parser: 'time'` manually, like `config: { dimension: 3, lt: '2012-05-12', parser: 'time' }`.\n- Pure string comparison is supported but can only be used in `=`, `!=`. `>`, `>=`, `<`, `<=` do not support pure string comparison (the \"right value\" of the four operators can not be a \"string\").\n- The operator `reg` can be used to make regular expression test. Like using `{ dimension: 'Name', reg: /\\s+Müller\\s*$/ }` to select all data items that the \"Name\" dimension contains family name Müller.\n\n**About logical relationship:**\n\nSometimes we also need to express logical relationship ( `and` / `or` / `not` ):\n\n```js\noption = {\n dataset: [\n {\n source: [\n // ...\n ]\n },\n {\n transform: {\n type: 'filter',\n config: {\n // Use operator \"and\".\n // Similarly, we can also use \"or\", \"not\" in the same place.\n // But \"not\" should be followed with a {...} rather than `[...]`.\n and: [\n { dimension: 'Year', '=': 2011 },\n { dimension: 'Price', '>=': 20, '<': 30 }\n ]\n }\n // The condition is \"Year\" is 2011 and \"Price\" is greater\n // or equal to 20 but less than 30.\n }\n }\n ],\n series: {\n type: 'pie',\n datasetIndex: 1\n }\n};\n```\n\n`and`/`or`/`not` can be nested like:\n\n```js\ntransform: {\n type: 'filter',\n config: {\n or: [{\n and: [{\n dimension: 'Price', '>=': 10, '<': 20\n }, {\n dimension: 'Sales', '<': 100\n }, {\n not: { dimension: 'Product', '=': 'Tofu' }\n }]\n }, {\n and: [{\n dimension: 'Price', '>=': 10, '<': 20\n }, {\n dimension: 'Sales', '<': 100\n }, {\n not: { dimension: 'Product', '=': 'Cake' }\n }]\n }]\n }\n}\n```\n\n**About parser:**\n\nSome \"parser\" can be specified when make value comparison. At present only supported:\n\n- `parser: 'time'`: Parse the value to date time before comparing. The parser rule is the same as `echarts.time.parse`, where JS `Date` instance, timestamp number (in millisecond) and time string (like `'2012-05-12 03:11:22'`) are supported to be parse to timestamp number, while other value will be parsed to `NaN`.\n- `parser: 'trim'`: Trim the string before making comparison. For non-string, return the original value.\n- `parser: 'number'`: Force to convert the value to number before making comparison. If not possible to be converted to a meaningful number, converted to `NaN`. In most cases it is not necessary, because by default the value will be auto converted to number if possible before making comparison. But the default conversion is strict while this parser provide a loose strategy. If we meet the case that number string with unit suffix (like `'33%'`, `12px`), we should use `parser: 'number'` to convert them to number before making comparison.\n\nThis is an example to show the `parser: 'time'`:\n\n```js\noption = {\n dataset: [\n {\n source: [\n ['Product', 'Sales', 'Price', 'Date'],\n ['Milk Tee', 311, 21, '2012-05-12'],\n ['Cake', 135, 28, '2012-05-22'],\n ['Latte', 262, 36, '2012-06-02'],\n ['Milk Tee', 359, 21, '2012-06-22'],\n ['Cake', 121, 28, '2012-07-02'],\n ['Latte', 271, 36, '2012-06-22']\n // ...\n ]\n },\n {\n transform: {\n type: 'filter',\n config: {\n dimension: 'Date',\n '>=': '2012-05',\n '<': '2012-06',\n parser: 'time'\n }\n }\n }\n ]\n};\n```\n\n**Formally definition:**\n\nFinally, we give the formally definition of the filter transform config here:\n\n```ts\ntype FilterTransform = {\n type: 'filter';\n config: ConditionalExpressionOption;\n};\ntype ConditionalExpressionOption =\n | true\n | false\n | RelationalExpressionOption\n | LogicalExpressionOption;\ntype RelationalExpressionOption = {\n dimension: DimensionName | DimensionIndex;\n parser?: 'time' | 'trim' | 'number';\n lt?: DataValue; // less than\n lte?: DataValue; // less than or equal\n gt?: DataValue; // greater than\n gte?: DataValue; // greater than or equal\n eq?: DataValue; // equal\n ne?: DataValue; // not equal\n '<'?: DataValue; // lt\n '<='?: DataValue; // lte\n '>'?: DataValue; // gt\n '>='?: DataValue; // gte\n '='?: DataValue; // eq\n '!='?: DataValue; // ne\n '<>'?: DataValue; // ne (SQL style)\n reg?: RegExp | string; // RegExp\n};\ntype LogicalExpressionOption = {\n and?: ConditionalExpressionOption[];\n or?: ConditionalExpressionOption[];\n not?: ConditionalExpressionOption;\n};\ntype DataValue = string | number | Date;\ntype DimensionName = string;\ntype DimensionIndex = number;\n```\n\n> Note that when using [Minimal Bundle](${lang}/basics/import#shrinking-bundle-size), if you need to use this built-in transform, besides the `Dataset` component, it's required to import the `Transform` component.\n\n```ts\nimport {\n DatasetComponent,\n TransformComponent\n} from 'echarts/components';\n\necharts.use([\n DatasetComponent,\n TransformComponent\n]);\n```\n\n## Sort Transform\n\nAnother built-in transform is \"sort\".\n\n```js\noption = {\n dataset: [\n {\n dimensions: ['name', 'age', 'profession', 'score', 'date'],\n source: [\n [' Hannah Krause ', 41, 'Engineer', 314, '2011-02-12'],\n ['Zhao Qian ', 20, 'Teacher', 351, '2011-03-01'],\n [' Jasmin Krause ', 52, 'Musician', 287, '2011-02-14'],\n ['Li Lei', 37, 'Teacher', 219, '2011-02-18'],\n [' Karle Neumann ', 25, 'Engineer', 253, '2011-04-02'],\n [' Adrian Groß', 19, 'Teacher', null, '2011-01-16'],\n ['Mia Neumann', 71, 'Engineer', 165, '2011-03-19'],\n [' Böhm Fuchs', 36, 'Musician', 318, '2011-02-24'],\n ['Han Meimei ', 67, 'Engineer', 366, '2011-03-12']\n ]\n },\n {\n transform: {\n type: 'sort',\n // Sort by score.\n config: { dimension: 'score', order: 'asc' }\n }\n }\n ],\n series: {\n type: 'bar',\n datasetIndex: 1\n }\n // ...\n};\n```\n\n\n\nSome extra features about \"sort transform\":\n\n- Order by multiple dimensions is supported. See examples below.\n- The sort rule:\n - By default \"numeric\" (that is, number and numeric-string like `' 123 '`) are able to sorted by numeric order.\n - Otherwise \"non-numeric-string\" are also able to be ordered among themselves. This might help to the case like grouping data items with the same tag, especially when multiple dimensions participated in the sort (See example below).\n - When \"numeric\" is compared with \"non-numeric-string\", or either of them is compared with other types of value, they are not comparable. So we call the latter one as \"incomparable\" and treat it as \"min value\" or \"max value\" according to the prop `incomparable: 'min' | 'max'`. This feature usually helps to decide whether to put the empty values (like `null`, `undefined`, `NaN`, `''`, `'-'`) or other illegal values to the head or tail.\n- `parser: 'time' | 'trim' | 'number'` can be used, the same as \"filter transform\".\n - If intending to sort time values (JS `Date` instance or time string like `'2012-03-12 11:13:54'`), `parser: 'time'` should be specified. Like `config: { dimension: 'date', order: 'desc', parser: 'time' }`\n - If intending to sort values with unit suffix (like `'33%'`, `'16px'`), need to use `parser: 'number'`.\n\nSee an example of multiple order:\n\n```js\noption = {\n dataset: [\n {\n dimensions: ['name', 'age', 'profession', 'score', 'date'],\n source: [\n [' Hannah Krause ', 41, 'Engineer', 314, '2011-02-12'],\n ['Zhao Qian ', 20, 'Teacher', 351, '2011-03-01'],\n [' Jasmin Krause ', 52, 'Musician', 287, '2011-02-14'],\n ['Li Lei', 37, 'Teacher', 219, '2011-02-18'],\n [' Karle Neumann ', 25, 'Engineer', 253, '2011-04-02'],\n [' Adrian Groß', 19, 'Teacher', null, '2011-01-16'],\n ['Mia Neumann', 71, 'Engineer', 165, '2011-03-19'],\n [' Böhm Fuchs', 36, 'Musician', 318, '2011-02-24'],\n ['Han Meimei ', 67, 'Engineer', 366, '2011-03-12']\n ]\n },\n {\n transform: {\n type: 'sort',\n config: [\n // Sort by the two dimensions.\n { dimension: 'profession', order: 'desc' },\n { dimension: 'score', order: 'desc' }\n ]\n }\n }\n ],\n series: {\n type: 'bar',\n datasetIndex: 1\n }\n // ...\n};\n```\n\n\n\nFinally, we give the formally definition of the sort transform config here:\n\n```ts\ntype SortTransform = {\n type: 'sort';\n config: OrderExpression | OrderExpression[];\n};\ntype OrderExpression = {\n dimension: DimensionName | DimensionIndex;\n order: 'asc' | 'desc';\n incomparable?: 'min' | 'max';\n parser?: 'time' | 'trim' | 'number';\n};\ntype DimensionName = string;\ntype DimensionIndex = number;\n```\n\n> Note that when using [Minimal Bundle](${lang}/basics/import#shrinking-bundle-size), if you need to use this built-in transform, besides the `Dataset` component, it's required to import the `Transform` component.\n\n```ts\nimport {\n DatasetComponent,\n TransformComponent\n} from 'echarts/components';\n\necharts.use([\n DatasetComponent,\n TransformComponent\n]);\n```\n\n## Use External Transforms\n\nBesides built-in transforms (like 'filter', 'sort'), we can also use external transforms to provide more powerful functionalities. Here we use a third-party library [ecStat](https://github.com/ecomfe/echarts-stat) as an example:\n\nThis case show how to make a regression line via ecStat:\n\n```js\n// Register the external transform at first.\necharts.registerTransform(ecStatTransform(ecStat).regression);\n```\n\n```js\noption = {\n dataset: [\n {\n source: rawData\n },\n {\n transform: {\n // Reference the registered external transform.\n // Note that external transform has a namespace (like 'ecStat:xxx'\n // has namespace 'ecStat').\n // built-in transform (like 'filter', 'sort') does not have a namespace.\n type: 'ecStat:regression',\n config: {\n // Parameters needed by the external transform.\n method: 'exponential'\n }\n }\n }\n ],\n xAxis: { type: 'category' },\n yAxis: {},\n series: [\n {\n name: 'scatter',\n type: 'scatter',\n datasetIndex: 0\n },\n {\n name: 'regression',\n type: 'line',\n symbol: 'none',\n datasetIndex: 1\n }\n ]\n};\n```\n\nExamples with echarts-stat:\n\n- [Aggregate](${exampleEditorPath}data-transform-aggregate&edit=1&reset=1)\n- [Bar histogram](${exampleEditorPath}bar-histogram&edit=1&reset=1)\n- [Scatter clustering](${exampleEditorPath}scatter-clustering&edit=1&reset=1)\n- [Scatter linear regression](${exampleEditorPath}scatter-linear-regression&edit=1&reset=1)\n- [Scatter exponential regression](${exampleEditorPath}scatter-exponential-regression&edit=1&reset=1)\n- [Scatter logarithmic regression](${exampleEditorPath}scatter-logarithmic-regression&edit=1&reset=1)\n- [Scatter polynomial regression](${exampleEditorPath}scatter-polynomial-regression&edit=1&reset=1)\n"}}]); \ No newline at end of file diff --git a/docs/_nuxt/js/081a832b8d56a654ea69.js b/docs/_nuxt/js/081a832b8d56a654ea69.js new file mode 100644 index 000000000..4d4161f75 --- /dev/null +++ b/docs/_nuxt/js/081a832b8d56a654ea69.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[129],{427:function(n,t,e){"use strict";e.r(t),t.default="# 服务端渲染 ECharts 图表\n\n通常情况下,Apache EChartsTM 会在浏览器中动态的渲染图表,并且根据用户的交互来更新渲染。但是在下面这些比较特殊的场景,我们也需要在服务端中渲染图表并且输出到浏览器中:\n\n- 需要缩短前端的渲染时间,保证第一时间显示图表\n- 需要在 Markdown, PDF 等不支持动态运行脚本的环境中嵌入图表\n\n在这些场景下,ECharts 也提供了两种服务端渲染(server-side rendering,SSR)的方案:SVG 渲染或 Canvas 渲染。\n\n| 渲染方案 | 渲染结果的形式 | 优点 |\n| ----------------- | ----------------- | ----------------- |\n| 服务端 SVG 渲染 | SVG 字符串 | 比 Canvas 图片体积更小;
矢量 SVG 图片不会模糊;
支持初始动画 |\n| 服务端 Canvas 渲染 | 图片 | 图片形式适用场景更广泛,对不支持 SVG 的场景可选择 |\n\n通常情况下,应优先考虑使用服务端 SVG 渲染方案,如果 SVG 不适用,也可以考虑 Canvas 渲染方案。\n\n使用服务端渲染也有一定的局限性,尤其是和交互相关的一些操作无法支持。因此,如果有交互需求,可参考下文的“服务端渲染 Hydration”。\n\n## 服务端渲染\n\n### 服务端 SVG 渲染\n\n> 版本更新:\n>\n> - 5.3.0 版本:使用零依赖的服务端 SVG 字符串渲染方案,并支持图表的初始动画\n> - 5.5.0 版本:新增客户端轻量运行时,客户端无需加载完整 ECharts 即可实现部分交互\n\n5.3.0 里新引入了零依赖的服务端 SVG 字符串渲染方案:\n\n```ts\n// 服务端代码\nconst echarts = require('echarts');\n\n// 在 SSR 模式下第一个参数不需要再传入 DOM 对象\nconst chart = echarts.init(null, null, {\n renderer: 'svg', // 必须使用 SVG 模式\n ssr: true, // 开启 SSR\n width: 400, // 需要指明高和宽\n height: 300\n});\n\n// 像正常使用一样 setOption\nchart.setOption({\n //...\n});\n\n// 输出字符串\nconst svgStr = chart.renderToSVGString();\n\n// 如果不再需要图表,调用 dispose 以释放内存\nchart.dispose();\nchart = null;\n```\n\n整体使用的代码结构跟在浏览器中使用一样,首先是`init`初始化一个图表实例,然后通过`setOption`设置图表的配置项。但是`init`传入的参数会跟在跟浏览器中使用有所不同:\n\n- 首先因为在服务端会采用字符串拼接的方式来渲染得到 SVG,我们并不需要容器来展示渲染的内容,所以我们可以在`init`的时候第一个`container`参数传入`null`或者`undefined`。\n- 然后我们在`init`的第三个参数中,我们需要通过显示指定`ssr: true`来告诉 ECharts 我们需要开启服务端渲染的模式,该模式下 ECharts 会关闭动画循环的模块以及事件交互的模块。\n- 在服务端渲染中我们也必须要通过`width`和`height`显示的指定图表的高和宽,因此如果你的图表是需要根据容器大小自适应的话,可能需要思考一下服务端渲染是否适合你的场景了。一种可能的解决方案是,首屏获取到图表容器大小后,请求服务端渲染图表,然后在客户端渲染图表;当用户交互改变容器大小时,重新请求服务端渲染。\n\n在浏览器中我们在`setOption`完之后 ECharts 就会自动进行渲染将结果绘制到页面中,后续也会在每一帧判断是否有动画需要进行重绘。Node.js 中我们在设置了`ssr: true`后则没有这个过程。取而代之我们使用了`renderToSVGString`,将当前的图表渲染到 SVG 字符串,进一步得再通过 HTTP Response 返回给前端或者缓存到本地。\n\nHTTP Response 返回给前端(这里以 Express.js 为例):\n\n```ts\nres.writeHead(200, {\n 'Content-Type': 'application/xml'\n});\nres.write(svgStr); // svgStr 是上面 chart.renderToSVGString() 得到的字符串\nres.end();\n```\n\n或者保存到本地:\n\n```ts\nfs.writeFile('bar.svg', svgStr, 'utf-8');\n```\n\n#### 服务端渲染中的动画效果\n\n上面的例子中可以看到,就算是服务端渲染 ECharts 也可以提供动画效果,这个动画效果是通过在输出的 SVG 字符串中嵌入 CSS 动画实现的。并不需要额外的 JavaScript 再去控制动画。\n\n但是,也因为 CSS 动画的局限性,我们没法在服务端渲染中实现一些更灵活的动画功能,诸如柱状图排序动画,标签动画,路径图的特效动画等。部分系列诸如饼图的动画效果也为服务端渲染做了特殊的优化。\n\n如果你不希望有这个动画效果,可以在`setOption`的时候通过`animation: false`关闭动画。\n\n```ts\nsetOption({\n animation: false\n});\n```\n\n### 服务端 Canvas 渲染\n\n如果你希望输出的是一张图片而非 SVG 字符串,或者你还在使用更老的版本,我们会推荐使用 [node-canvas](https://github.com/Automattic/node-canvas) 来实现 ECharts 的服务渲染,[node-canvas](https://github.com/Automattic/node-canvas) 是在 Node.js 上的一套 Canvas 实现,它提供了跟浏览器中 Canvas 几乎一致的接口。\n\n下面是一个简单的例子\n\n```ts\nvar echarts = require('echarts');\nconst { createCanvas } = require('canvas');\n\n// 在 5.3.0 之前的版本中,你必须要通过该接口注册 canvas 实例创建方法。\n// 从 5.3.0 开始就不需要了\necharts.setCanvasCreator(() => {\n return createCanvas();\n});\n\nconst canvas = createCanvas(800, 600);\n// ECharts 可以直接使用 node-canvas 创建的 Canvas 实例作为容器\nconst chart = echarts.init(canvas);\n\n// 像正常使用一样 setOption\nchart.setOption({\n //...\n});\n\nconst buffer = renderChart().toBuffer('image/png');\n\n// 如果不再需要图表,调用 dispose 以释放内存\nchart.dispose();\nchart = null;\n\n// 通过 Response 输出 PNG 图片\nres.writeHead(200, {\n 'Content-Type': 'image/png'\n});\nres.write(buffer);\nres.end();\n```\n\n#### 图片的加载\n\n[node-canvas](https://github.com/Automattic/node-canvas) 提供了图片加载的`Image`实现,如果你在图表中使用了到了图片,我们可以使用`5.3.0`新增的`setPlatformAPI`接口来适配。\n\n```ts\necharts.setPlatformAPI({\n // 同老版本的 setCanvasCreator\n createCanvas() {\n return createCanvas();\n },\n loadImage(src, onload, onerror) {\n const img = new Image();\n // 必须要绑定 this context.\n img.onload = onload.bind(img);\n img.onerror = onerror.bind(img);\n img.src = src;\n return img;\n }\n});\n```\n\n如果你的图片是需要远程获取的,我们建议你通过 http 请求先预取该图片得到`base64`之后再作为图片的 URL 传入,这样可以保证在 Response 输出的时候图片是加载完成的。\n\n## 客户端二次渲染\n\n### 客户端懒加载完整 ECharts\n\n最新版本的 ECharts 服务端 SVG 渲染除了完成图表的渲染外,支持的功能包括:\n\n- 图表初始动画(例如:柱状图初始化时的柱子上升动画)\n- 高亮样式(例如:鼠标移动到柱状图柱子上时的高亮效果)\n\n但仅使用服务端渲染无法支持的功能包括:\n\n- 动态改变数据\n- 点击图例切换系列是否显示\n- 移动鼠标显示提示框\n- 其他交互相关的功能\n\n如果有相关需求,可以考虑先使用服务端渲染快速输出首屏图表,然后等待 `echarts.js` 加载完后,重新在客户端渲染同样的图表(称为 Hydration),这样就可以实现正常的交互效果和动态改变数据了。需要注意的是,在客户端渲染的时候,应开启 `tooltip: { show: true }` 之类的交互组件,并且用 `animation: 0` 关闭初始动画(初始动画应由服务端渲染结果的 SVG 动画完成)。\n\n从用户体验的角度,几乎感受不到二次渲染的过程,整个切换效果是非常无缝衔接的。你也可以像上面的例子中一样,在加载 `echarts.js` 的过程中使用 [pace-js](https://www.npmjs.com/package/pace-js) 之类的库实现显示加载进度条的效果,来解决 ECharts 尚未完全加载完之前没有交互反馈的问题。\n\n使用服务端渲染 SVG 加上客户端 ECharts 懒加载的方式,其优点是,能够在首屏快速展示图表,而懒加载完成后可以实现所有 ECharts 的功能和交互;而缺点是,懒加载完整的 ECharts 需要一定时间,在加载完成前无法实现除高亮之外的用户交互(在这种情况下,开发者可以通过显示“加载中”来解决无交互反馈带来的困惑)。这个方案也是目前比较推荐的对首屏加载时间敏感,对功能交互完整性要求高的方案。\n\n### 客户端轻量运行时\n\n方案一给出了实现完整交互的方案,但是有些场景下,我们并不需要很复杂的交互,只是希望在服务端渲染的基础上,能够在客户端进行一些简单的交互,例如:点击图例切换系列是否显示。这种情况下,我们能否不在客户端加载至少需要几百 KB 的 ECharts 代码呢?\n\n从 v5.5.0 版本起,如果图表只需要以下效果和交互,可以通过服务端 SVG 渲染 + 客户端轻量运行时来实现:\n\n- 图表初始动画(实现原理:服务端渲染的 SVG 带有 CSS 动画)\n- 高亮样式(实现原理:服务端渲染的 SVG 带有 CSS 动画)\n- 动态改变数据(实现原理:轻量运行时请求服务器进行二次渲染)\n- 点击图例切换系列是否显示(实现原理:轻量运行时请求服务器进行二次渲染)\n\n```html\n
\n\n + + +

Get Apache ECharts

Apache ECharts offers a variety of installation options, so you can choose any of the following options depending on your project.

  • Install From npm
  • Use From CDN
  • Download From GitHub
  • Online Customization

We'll go over each of these installation methods and the directory structure after download.

Installation

Install From npm

npm install echarts

See Import ECharts for details on usage.

Use From CDN

ECharts is available on the following free CDNs:

Download From GitHub

You can find links to each version on the releases page of the apache/echarts project. Click on the Source code under Assets at the bottom of the desired release version. After downloading, unzip the file and locate echarts.js file in the dist folder to include the full ECharts functionality.

Online Customization

If you want to introduce only some modules to reduce package size, you can use the ECharts online customization function to create a customized download of ECharts.

Contributors Edit this page on GitHub

plainheart plainheartOvilia Oviliapissang pissangzachary-svoboda-accesso zachary-svoboda-accesso
+ + + + + diff --git a/docs/en/basics/help/index.html b/docs/en/basics/help/index.html new file mode 100644 index 000000000..cb1da4a2c --- /dev/null +++ b/docs/en/basics/help/index.html @@ -0,0 +1,15 @@ + + + + + + + Get Help - Basics - Handbook - Apache ECharts + + +

Get Help

Technical Problems

Make sure that existing documentation do not solve your problem

ECharts has a very large number of users, so it's more than likely that someone else has encountered and solved the problem you've had. By reading the documentation and using the search engine, you can solve your problem quickly by yourself without help from the community.

Therefore, before doing anything else, make sure that current documentation and other resources can't solve your problem. Resources that can be helpful for you include,

Create the Minimal Reproducible Demo

Create an example on Official Editor, CodePen, CodeSandbox or JSFiddle, which will make it easier for others to reproduce your problem.

The example should reproduce your problem in the simplest way. Removing unnecessary code and data can enable those who want to help you to locate and then solve the problem more quickly. Please refer to How to Create a Minimal, Reproducible Example for more details.

Determining if It's a Bug

Report a Bug or Request a New Feature

If some behavior is different from the documentation or isn't what you expected, it's probably a bug. If it's a bug, or you have a feature request, please use the issue template to create a new issue and describe it in detail as per the prompts.

How-To Questions

If it's not a bug, but you don't know how to achieve something, try the stackoverflow.com

If you don't get an answer, you can also send an email to dev@echarts.apache.org. In order for more people to understand your question and to get help in future searches, it is highly recommended to write the email in English.

Non-technical questions

For other non-technical questions, you can send an email in English to dev@echarts.apache.org.

Contributors Edit this page on GitHub

plainheart plainheartpissang pissang
+ + + + + diff --git a/docs/en/basics/import/index.html b/docs/en/basics/import/index.html new file mode 100644 index 000000000..8172611d4 --- /dev/null +++ b/docs/en/basics/import/index.html @@ -0,0 +1,134 @@ + + + + + + + Import ECharts - Basics - Handbook - Apache ECharts + + +

Using ECharts as an NPM Package

There are two approaches to using ECharts as a package. The simplest approach is to make all functionality immediately available by importing from echarts. However, it is encouraged to substantially decrease bundle size by only importing as necessary such as echarts/core and echarts/charts.

Install ECharts via NPM

You can install ECharts via npm using the following command

npm install echarts

Import All ECharts Functionality

To include all of ECharts, we simply need to import echarts.

import * as echarts from 'echarts';
+
+// Create the echarts instance
+var myChart = echarts.init(document.getElementById('main'));
+
+// Draw the chart
+myChart.setOption({
+  title: {
+    text: 'ECharts Getting Started Example'
+  },
+  tooltip: {},
+  xAxis: {
+    data: ['shirt', 'cardigan', 'chiffon', 'pants', 'heels', 'socks']
+  },
+  yAxis: {},
+  series: [
+    {
+      name: 'sales',
+      type: 'bar',
+      data: [5, 20, 36, 10, 10, 20]
+    }
+  ]
+});

Shrinking Bundle Size

The above code will import all the charts and components in ECharts, but if you don't want to bring in all the components, you can use the tree-shakeable interface provided by ECharts to bundle the required components and get a minimal bundle.

// Import the echarts core module, which provides the necessary interfaces for using echarts.
+import * as echarts from 'echarts/core';
+
+// Import bar charts, all suffixed with Chart
+import { BarChart } from 'echarts/charts';
+
+// Import the tooltip, title, rectangular coordinate system, dataset and transform components
+import {
+  TitleComponent,
+  TooltipComponent,
+  GridComponent,
+  DatasetComponent,
+  TransformComponent
+} from 'echarts/components';
+
+// Features like Universal Transition and Label Layout
+import { LabelLayout, UniversalTransition } from 'echarts/features';
+
+// Import the Canvas renderer
+// Note that including the CanvasRenderer or SVGRenderer is a required step
+import { CanvasRenderer } from 'echarts/renderers';
+
+// Register the required components
+echarts.use([
+  BarChart,
+  TitleComponent,
+  TooltipComponent,
+  GridComponent,
+  DatasetComponent,
+  TransformComponent,
+  LabelLayout,
+  UniversalTransition,
+  CanvasRenderer
+]);
+
+// The chart is initialized and configured in the same manner as before
+var myChart = echarts.init(document.getElementById('main'));
+myChart.setOption({
+  // ...
+});

Note that in order to keep the size of the package to a minimum, ECharts does not provide any renderer in the tree-shakeable interface, so you need to choose to import CanvasRenderer or SVGRenderer as the renderer. The advantage of this is that if you only need to use the SVG rendering mode, the bundle will not include the CanvasRenderer module, which is not needed.

The "Full Code" tab on our sample editor page provides a very convenient way to generate a tree-shakable code. It will generate tree-shakable code based on the current option dynamically to use it directly in your project.

Creating an Option Type in TypeScript

For developers who are using TypeScript to develop ECharts, type interface is provided to create a minimal EChartsOption type. This type will be stricter than the default one provided because it will know exactly what components are being used. This can help you check for missing components or charts more effectively.

import * as echarts from 'echarts/core';
+import {
+  BarChart,
+  LineChart,
+} from 'echarts/charts';
+import {
+  TitleComponent,
+  TooltipComponent,
+  GridComponent,
+  // Dataset
+  DatasetComponent,
+  // Built-in transform (filter, sort)
+  TransformComponent
+} from 'echarts/components';
+import { LabelLayout, UniversalTransition } from 'echarts/features';
+import { CanvasRenderer } from 'echarts/renderers';
+import type {
+  // The series option types are defined with the SeriesOption suffix
+  BarSeriesOption, 
+  LineSeriesOption,
+} from 'echarts/charts';
+import type {
+  // The component option types are defined with the ComponentOption suffix
+  TitleComponentOption, 
+  TooltipComponentOption,
+  GridComponentOption,
+  DatasetComponentOption
+} from 'echarts/components';
+import type { 
+  ComposeOption, 
+} from 'echarts/core';
+
+// Create an Option type with only the required components and charts via ComposeOption
+type ECOption = ComposeOption<
+  | BarSeriesOption
+  | LineSeriesOption
+  | TitleComponentOption
+  | TooltipComponentOption
+  | GridComponentOption
+  | DatasetComponentOption
+>;
+
+// Register the required components
+echarts.use([
+  TitleComponent,
+  TooltipComponent,
+  GridComponent,
+  DatasetComponent,
+  TransformComponent,
+  BarChart,
+  LineChart,
+  LabelLayout,
+  UniversalTransition,
+  CanvasRenderer
+]);
+
+const option: ECOption = {
+  // ...
+};

Contributors Edit this page on GitHub

plainheart plainheartpissang pissangaimuz aimuzikeq ikeqzachary-svoboda-accesso zachary-svoboda-accessobtea btea
+ + + + + diff --git a/docs/en/basics/release-note/5-2-0/index.html b/docs/en/basics/release-note/5-2-0/index.html new file mode 100644 index 000000000..cee46745f --- /dev/null +++ b/docs/en/basics/release-note/5-2-0/index.html @@ -0,0 +1,604 @@ + + + + + + + 5.2 - What's New - Basics - Handbook - Apache ECharts + + +

What's New in Apache ECharts 5.2.0

Universal Transition

Natural and smooth transition animations have been an important feature in Apache ECharts. By avoiding abrupt changes from data update, it not only improves the visual effect, but also provides the possibility to express the association and evolution of data. Therefore, in 5.2.0, we have further enhanced this animation capability. Next, we will see how this Universal Transition adds expressiveness and narrative power to the chart.

In previous versions, transition animations had certain limitations: they could only be used for the position, size of the same shape, and they could only work on the same type of series. For example, the following example reflects the change in data percent through the change in sector shape in a pie chart.

function makeRandomData() {
+  return [
+    {
+      value: Math.random(),
+      name: 'A'
+    },
+    {
+      value: Math.random(),
+      name: 'B'
+    },
+    {
+      value: Math.random(),
+      name: 'C'
+    }
+  ];
+}
+option = {
+  series: [
+    {
+      type: 'pie',
+      radius: [0, '50%'],
+      data: makeRandomData()
+    }
+  ]
+};
+
+setInterval(() => {
+  myChart.setOption({
+    series: {
+      data: makeRandomData()
+    }
+  });
+}, 2000);
live

And starting with 5.2.0, we introduced universal transition, a more powerful animation feature. With that, transitions are no longer limited to between series of the same type. Now, we can use this cross-series morphing to animate between any type of series and any type of shapes.

How cool would this be? Let's have a look!

Morphing transition across series

With universalTransition: true set to enable universion transition feature, switching from pie charts to bar charts, or from bar charts to scatter charts, or even between more complex charts like Sunburst and Treemap, can be morphed naturally.

As follows, switching between a pie chart and a bar chart.

const dataset = {
+  dimensions: ['name', 'score'],
+  source: [
+    ['Hannah Krause', 314],
+    ['Zhao Qian', 351],
+    ['Jasmin Krause ', 287],
+    ['Li Lei', 219],
+    ['Karle Neumann', 253],
+    ['Mia Neumann', 165],
+    ['Böhm Fuchs', 318],
+    ['Han Meimei', 366]
+  ]
+};
+const pieOption = {
+  dataset: [dataset],
+  series: [
+    {
+      type: 'pie',
+      // associate the series to be animated by id
+      id: 'Score',
+      radius: [0, '50%'],
+      universalTransition: true,
+      animationDurationUpdate: 1000
+    }
+  ]
+};
+const barOption = {
+  dataset: [dataset],
+  xAxis: {
+    type: 'category'
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      // associate the series to be animated by id
+      id: 'Score',
+      // Each data will have a different color
+      colorBy: 'data',
+      encode: { x: 'name', y: 'score' },
+      universalTransition: true,
+      animationDurationUpdate: 1000
+    }
+  ]
+};
+
+option = barOption;
+
+setInterval(() => {
+  option = option === pieOption ? barOption : pieOption;
+  // Use the notMerge form to remove the axes
+  myChart.setOption(option, true);
+}, 2000);
live

More transitions between common charts.

Such transitions are no longer limited to just the basic line, bar, and pie charts, but also between bars and maps:

or between Sunburst and Treemap, or even between very flexible custom series can be transitions.

Note that you need to configure the series ids to ensure that there is a one-to-one correspondence between the series that need to be animated for the transition.

Minimal bundle needs to import this feature manually.

import { UniversalTransition } from 'echarts/features';
+echarts.use([UniversalTransition]);
+

Data split and merge animations

In addition to the common update of data values, sometimes we also encounter data aggregation, drill-down and other updates after interactions, when we can not directly apply one-to-one transitions, but need to use more animation effects like splitting and merging to express the transformation of data.

In order to be able to express the possible many-to-many connections between data, in 5.2.0 we introduced a new concept groupId. We can set the group to the whole series via series.dataGroupId, or more fine-grained by series.data.groupId to set the group to which each data belongs. It's even easier if you use a dataset to manage the data, you can use encode.itemGroupId to specify a dimension encoded as groupId.

For example, if we want to implement a drill-down animation for a bar chart, we can set the entire series of data after the drill-down to the same groupId, which then corresponds to the data before the drill-down

option = {
+  xAxis: {
+    data: ['Animals', 'Fruits', 'Cars']
+  },
+  yAxis: {},
+  dataGroupId: '',
+  animationDurationUpdate: 500,
+  series: {
+    type: 'bar',
+    id: 'sales',
+    data: [
+      {
+        value: 5,
+        groupId: 'animals'
+      },
+      {
+        value: 2,
+        groupId: 'fruits'
+      },
+      {
+        value: 4,
+        groupId: 'cars'
+      }
+    ],
+    universalTransition: {
+      enabled: true,
+      divideShape: 'clone'
+    }
+  }
+};
+
+const drilldownData = [
+  {
+    dataGroupId: 'animals',
+    data: [
+      ['Cats', 4],
+      ['Dogs', 2],
+      ['Cows', 1],
+      ['Sheep', 2],
+      ['Pigs', 1],
+      ['Cows', 1],
+      ['Sheep', 2],
+      ['Pigs', 1]
+    ]
+  },
+  {
+    dataGroupId: 'fruits',
+    data: [
+      ['Apples', 4],
+      ['Oranges', 2],
+      ['Oranges', 2]
+    ]
+  },
+  {
+    dataGroupId: 'cars',
+    data: [
+      ['Toyota', 4],
+      ['Opel', 2],
+      ['Volkswagen', 2],
+      ['Volkswagen', 2]
+    ]
+  }
+];
+
+myChart.on('click', event => {
+  if (event.data) {
+    const subData = drilldownData.find(data => {
+      return data.dataGroupId === event.data.groupId;
+    });
+    if (!subData) {
+      return;
+    }
+    myChart.setOption({
+      xAxis: {
+        data: subData.data.map(item => {
+          return item[0];
+        })
+      },
+      series: {
+        type: 'bar',
+        id: 'sales',
+        dataGroupId: subData.dataGroupId,
+        data: subData.data.map(item => {
+          return item[1];
+        }),
+        universalTransition: {
+          enabled: true,
+          divideShape: 'clone'
+        }
+      },
+      graphic: [
+        {
+          type: 'text',
+          left: 50,
+          top: 20,
+          style: {
+            text: 'Back',
+            fontSize: 18
+          },
+          onclick: function() {
+            myChart.setOption(option, true);
+          }
+        }
+      ]
+    });
+  }
+});
live

With groupId, we can also implement richer aggregation and drill-down animations.

Aggregation of data.

Drilling down of a single series into two series:

Universal transition take the ability to express the relationships and evolution of data to a new level, giving wings to your visualization creation inspiration.

At this point, we know you're already eager to try it out. But don't worry, there are even more new features in 5.2.0 that are worth checking out.

Color palette picking strategy

In the above universal transition example, you may have noticed that we use a colorBy configuration that was not available in the previous version. This configuration is also a new feature we added in this version to configure different granularity of color palette color picking for the series. This configuration currently supports two strategies.

  • 'series' assigns the colors in the palette by series, so that all data in the same series are in the same color.
  • 'data' assigns colors in the palette according to data items, with each data item using a different color.

Previously, we fixed this strategy for each type of series, for example, the bar chart was fixed with 'series' and the pie chart was fixed with 'data'.

And now with this new feature, we can assign a different color to each data item in the bar chart.

option = {
+  xAxis: {
+    type: 'category',
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      data: [120, 200, 150, 80, 70, 110, 130],
+      type: 'bar',
+      colorBy: 'data'
+    }
+  ]
+};
live

Or use one color uniformly in the pie chart.

option = {
+  series: {
+    type: 'pie',
+    colorBy: 'series',
+    radius: [0, '50%'],
+    itemStyle: {
+      borderColor: '#fff',
+      borderWidth: 1
+    },
+    data: [
+      {
+        value: 335,
+        name: 'Direct Visit'
+      },
+      {
+        value: 234,
+        name: 'Union Ad'
+      },
+      {
+        value: 1548,
+        name: 'Search Engine'
+      }
+    ]
+  }
+};
live

This configuration allows us to avoid the trouble of finding palette colors and setting them one by one, and may provide convenience in specific scenarios. We will further enhance this configuration later to provide more strategies.

Labels for polar bar charts

In this version we have implemented labels for bar charts on polar coordinates and support rich label positioning configurations. The following is a progress chart with labels displayed at the start points.

option = {
+  angleAxis: {
+    show: false,
+    max: 10
+  },
+  radiusAxis: {
+    show: false,
+    type: 'category',
+    data: ['AAA', 'BBB', 'CCC', 'DDD']
+  },
+  polar: {},
+  series: [
+    {
+      type: 'bar',
+      data: [3, 4, 5, 6],
+      colorBy: 'data',
+      roundCap: true,
+      label: {
+        show: true,
+        // Try changing it to 'insideStart'
+        position: 'start',
+        formatter: '{b}'
+      },
+      coordinateSystem: 'polar'
+    }
+  ]
+};
live

More configurations for label positions.

This flexible label position configuration item greatly enriches the expressiveness of the polar bar chart, allowing the text to clearly match the corresponding data.

Pie chart style for empty data

In the previous version, if there was no data in the pie chart, the screen might be completely blank. Because there was no visual element, users may wonder if there was a bug.

To solve this problem, in this version we will default to display a gray placeholder circle when there is no data to prevent the screen from being completely blank. We can configure the style of this placeholder circle with emptyCircleStyle.

option = {
+  series: [
+    {
+      type: 'pie',
+      data: [],
+      // showEmptyCircle: false,
+      emptyCircleStyle: {
+        // change the style to empty circle
+        color: 'transparent',
+        borderColor: '#ddd',
+        borderWidth: 1
+      }
+    }
+  ]
+};
live

If you don't want to show this gray circle, you can also set showEmptyCircle: false to turn it off.

Performance enhancements for high-dimensional data

We have introduced dataset since 4.0 to manage chart data. However, in some extreme scenarios with particularly high-dimensional (>100) data, we may encounter some dramatic performance degradation, such as the following scenario of visualizing a thousand-dimensional data through a thousand series (#11907), which may even may lead to getting stuck.

const indices = Array.from(Array(1000), (_, i) => {
+  return `index${i}`;
+});
+const option = {
+  xAxis: { type: 'category' },
+  yAxis: {},
+  dataset: {
+    // dimension: ['date', . . indices],
+    source: Array.from(Array(10), (_, i) => {
+      return {
+        date: i,
+        ... .indices.reduce((item, next) => {
+          item[next] = Math.random() * 100;
+          return item;
+        }, {})
+      };
+    })
+  },
+  series: indices.map(index => {
+    return { type: 'line', name: index };
+  })
+};

The reason for this performance problem is that we process the high-dimensional dataset at the bottom of each series as needed and save a copy of the processed data and the meta information about the dimensions of the data. This meant that the 1000 x 1000 dimensions had to be processed and saved in the example, which put a huge pressure on memory and garbage collection, resulting in a dramatic performance drop for high dimensions.

In the new version we have optimized this problem so that all series share the dataset storage as much as possible (whether or not they do depends on how the series uses the data). +This optimization ensure that memory does not explode as the dataset dimensions and series grow, significantly improving initialization performance in this extreme scenario. The rendering time for the example just described has also been reduced to an acceptable 300 ms or less.

It is not just this high-dimensional scenario that benefits from this optimization. When using a dataset with large amount of data, multiple series only process the data once because of data sharing, so it can also bring significant performance gains.

Type optimization for custom series

Custom series provide a very flexible way to create series graphs. Compared to other series, the learning curve for custom series can be a bit steep. Therefore, in this release, we have further optimized the type of the core method renderItem in the custom series by making more precise inferences about the types of the parameters and return values of renderItem, so that it is possible to infer which properties of the elements can be set based on the type returned:

series = {
+  type: 'custom',
+  renderItem(params) {
+    return {
+      type: 'group',
+      // The group type uses children to store children of other types
+      children: [
+        {
+          type: 'circle',
+          // circle has the following configurable shape attributes
+          shape: { r: 10, cx: 0, cy: 0 },
+          // Configurable styles
+          style: { fill: 'red' }
+        },
+        {
+          type: 'rect',
+          // rect has the following configurable shape properties
+          shape: { x: 0, y: 0, width: 100, height: 100 }
+        },
+        {
+          type: 'path',
+          // Custom path shapes
+          shape: { d: '...' }
+        }
+      ]
+    };
+  }
+};

Summary

If you're interested in some of the features and optimizations in 5.2.0, you may want to update to the latest version of Apache ECharts and try it out for yourself.

If you're interested in what's next for Apache ECharts, you can also follow our development plans at GitHub Milestone. Feel free to join us as a contributor (learn more at Wiki).

Full Changelog

View the Changelog

Contributors Edit this page on GitHub

pissang pissangOvilia Ovilia
+ + + + + diff --git a/docs/en/basics/release-note/5-3-0/index.html b/docs/en/basics/release-note/5-3-0/index.html new file mode 100644 index 000000000..3b8e3d258 --- /dev/null +++ b/docs/en/basics/release-note/5-3-0/index.html @@ -0,0 +1,851 @@ + + + + + + + 5.3 - What's New - Basics - Handbook - Apache ECharts + + +

Apache ECharts 5.3.0 Features

Apache ECharts 5.3.0 includes significant enhancements to animation expressiveness, rendering performance, and server-side rendering. It also adds long-awaited features from the community, such as automatic alignment of multi-axis ticks, tooltip value formatting, and map projection.

Keyframe Animations

Previously, ECharts animations were focused on transition animations for creating, updating, and removing elements, which often only had a start state and an end state. In order to express more complex animations, we introduced new keyframe animations for custom series and graphics components in 5.3.0.

Here is a simple effect of a breathing animation implemented via keyframe animation

option = {
+  graphic: {
+    type: 'circle',
+    shape: { r: 100 },
+    left: 'center',
+    top: 'center',
+    keyframeAnimation: [
+      {
+        duration: 3000,
+        loop: true,
+        keyframes: [
+          {
+            percent: 0.5,
+            easing: 'sinusoidalInOut',
+            scaleX: 0.1,
+            scaleY: 0.1
+          },
+          {
+            percent: 1,
+            easing: 'sinusoidalInOut',
+            scaleX: 1,
+            scaleY: 1
+          }
+        ]
+      }
+    ]
+  }
+};
live

In keyframe animation you can configure the animation duration, delay, easing, whether to loop or not, the position, easing, and graphic properties of each keyframe. You can also set multiple keyframe animations for each element at the same time with different configurations. The flexible configuration allows us to achieve very complex animation effects, and here are a few scenarios where keyframe animation can be applied.

Custom Loading Animations

ECharts has a built-in loading animation by default, which can be displayed by calling showLoading. More loading animation effects have been frequently asked in the community. Now with keyframe animations, we can use the graphic component with keyframe animations to achieve any loading animation effect we want.

Here is an example of the text stroke animation.

option = {
+  graphic: {
+    elements: [
+      {
+        type: 'text',
+        left: 'center',
+        top: 'center',
+        style: {
+          text: 'Apache ECharts',
+          fontSize: 40,
+          fontWeight: 'bold',
+          lineDash: [0, 200],
+          lineDashOffset: 0,
+          fill: 'transparent',
+          stroke: '#000',
+          lineWidth: 1
+        },
+        keyframeAnimation: {
+          duration: 3000,
+          loop: true,
+          keyframes: [
+            {
+              percent: 0.7,
+              style: {
+                fill: 'transparent',
+                lineDashOffset: 200,
+                lineDash: [200, 0]
+              }
+            },
+            {
+              // Stop for a while.
+              percent: 0.8,
+              style: {
+                fill: 'transparent'
+              }
+            },
+            {
+              percent: 1,
+              style: {
+                fill: 'black'
+              }
+            }
+          ]
+        }
+      }
+    ]
+  }
+};
live

Or animate columns.

const columns = [];
+for (let i = 0; i < 7; i++) {
+  columns.push({
+    type: 'rect',
+    x: i * 20,
+    shape: {
+      x: 0,
+      y: -40,
+      width: 10,
+      height: 80
+    },
+    style: {
+      fill: '#5470c6'
+    },
+    keyframeAnimation: {
+      duration: 1000,
+      delay: i * 200,
+      loop: true,
+      keyframes: [
+        {
+          percent: 0.5,
+          scaleY: 0.1,
+          easing: 'cubicIn'
+        },
+        {
+          percent: 1,
+          scaleY: 1,
+          easing: 'cubicOut'
+        }
+      ]
+    }
+  });
+}
+option = {
+  graphic: {
+    elements: [
+      {
+        type: 'group',
+        left: 'center',
+        top: 'center',
+        children: columns
+      }
+    ]
+  }
+};
live

Extending Richer Animation Effects in the Chart

Scatter charts with animation effects have long been a feature of ECharts. Developers can use the effectScatter series to implement dynamic scatter charts with ripple effects, which make charts more interesting and also serve to highlight the user. As with loading animations, developers often ask for more animation effects. Now we can achieve more complex effects by using keyframe animations in our custom series.

For example, the following example animates the pins drawn by the custom series on the SVG map with a jumping effect, along with a ripple animation.

fetch(
+  'https://fastly.jsdelivr.net/gh/apache/echarts-website@asf-site/examples/data/asset/geo/Map_of_Iceland.svg'
+)
+  .then(response => response.text())
+  .then(svg => {
+    echarts.registerMap('iceland_svg', { svg: svg });
+    option = {
+      geo: {
+        map: 'iceland_svg',
+        left: 0,
+        right: 0
+      },
+      series: {
+        type: 'custom',
+        coordinateSystem: 'geo',
+        geoIndex: 0,
+        zlevel: 1,
+        data: [
+          [488, 459, 100],
+          [770, 757, 30],
+          [1180, 743, 80],
+          [894, 1188, 61],
+          [1372, 477, 70],
+          [1378, 935, 81]
+        ],
+        renderItem(params, api) {
+          const coord = api.coord([
+            api.value(0, params.dataIndex),
+            api.value(1, params.dataIndex)
+          ]);
+
+          const circles = [];
+          for (let i = 0; i < 5; i++) {
+            circles.push({
+              type: 'circle',
+              shape: {
+                cx: 0,
+                cy: 0,
+                r: 30
+              },
+              style: {
+                stroke: 'red',
+                fill: 'none',
+                lineWidth: 2
+              },
+              // Ripple animation
+              keyframeAnimation: {
+                duration: 4000,
+                loop: true,
+                delay: (-i / 4) * 4000,
+                keyframes: [
+                  {
+                    percent: 0,
+                    scaleX: 0,
+                    scaleY: 0,
+                    style: {
+                      opacity: 1
+                    }
+                  },
+                  {
+                    percent: 1,
+                    scaleX: 1,
+                    scaleY: 0.4,
+                    style: {
+                      opacity: 0
+                    }
+                  }
+                ]
+              }
+            });
+          }
+          return {
+            type: 'group',
+            x: coord[0],
+            y: coord[1],
+            children: [
+              ...circles,
+              {
+                type: 'path',
+                shape: {
+                  d:
+                    'M16 0c-5.523 0-10 4.477-10 10 0 10 10 22 10 22s10-12 10-22c0-5.523-4.477-10-10-10zM16 16c-3.314 0-6-2.686-6-6s2.686-6 6-6 6 2.686 6 6-2.686 6-6 6z',
+                  x: -10,
+                  y: -35,
+                  width: 20,
+                  height: 40
+                },
+                style: {
+                  fill: 'red'
+                },
+                // Jump animation.
+                keyframeAnimation: {
+                  duration: 1000,
+                  loop: true,
+                  delay: Math.random() * 1000,
+                  keyframes: [
+                    {
+                      y: -10,
+                      percent: 0.5,
+                      easing: 'cubicOut'
+                    },
+                    {
+                      y: 0,
+                      percent: 1,
+                      easing: 'bounceOut'
+                    }
+                  ]
+                }
+              }
+            ]
+          };
+        }
+      }
+    };
+
+    myChart.setOption(option);
+  });
live

Loading Lottie animations

In order to fully exploit the power of new keyframe animations, Yi Shen from the ECharts team wrote a Lottie animation parsing library that can parse Lottie animation files into the ECharts graphics format for rendering. Combined with Lottie's expressive power we can introduce more amazing animations to our projects.

Graphical component transition animations

We have provided more flexible transition animation configurations for elements returned in the custom series in 5.0. The transition, enterFrom, and leaveTo configuration items allow you to configure which properties of each element will have transition animations and how they will be animated when the graphic is created and removed. Here is an example.

function renderItem() {
+  //...
+  return {
+    //...
+    x: 100,
+    // 'style', 'x', 'y' will be animated
+    transition: ['style', 'x', 'y'],
+    enterFrom: {
+      style: {
+        // Fade in
+        opacity: 0
+      },
+      // Fly in from the left
+      x: 0
+    },
+    leaveTo: {
+      // Fade out
+      opacity: 0
+    },
+    // Fly out to the right
+    x: 200
+  };
+}

In 5.3.0 we extended the configuration of these transition animations to the graphic component, with made additional enhancements.

If you don't want to write out each property to be animated, you can now directly configure transition: 'all' to animate all properties.

We also added enterAnimation, updateAnimation, and leaveAnimation to configure the duration, delay, and easing of the entry, update, and exit animations for each graphic, respectively. Gradient colors now also support animations.

New SVG renderer

In 5.3.0 we refactored our SVG renderer, which delivers 2x ~ 10x performance improvements, and even tens of times in some special scenes.

Previously, we updated the SVG renderer directly from the render queue to the DOM, but since zrender's graphics properties were not one-to-one with the DOM, we had to implement very complex diff logic in the middle, which was error-prone and did not provide the best performance in some scenarios. In this version, we reconstruct the full rendering to VDOM first, and then patch the VDOM to DOM to finish the rendering. Full rendering avoids potential bugs caused by complex diff logic, and the one-to-one correspondence between VDOM and DOM ensures that updates are minimal when patching, resulting in a huge performance boost.

This example gives you an intuitive impression of the performance improvement. The new version is much smoother than the previous version when dragging the chart in SVG mode.

5.2.2 (Before) 5.3.0 (After)
before after

In addition to the performance improvement, we can do more things with the rendered VDOM, such as server-side rendering, which will be described below.

Server-side Rendering with Zero Dependencies

In previous versions, ECharts could also implement server-side rendering, but it had to rely on node-canvas, or JSDOM if you were using SVG mode to simulate the DOM environment. These dependencies not only bring additional size and usage requirements, but also affect performance.

This new SVG renderer allows us to get the string from the intermediate rendered VDOM, bringing completely zero-dependency server-side rendering and outputting a more refined SVG string integrated CSS animation.

const echarts = require('echarts');
+
+// In SSR mode the first parameter does not need to be passed in as a DOM object
+const chart = echarts.init(null, null, {
+  renderer: 'svg', // must use SVG mode
+  ssr: true, // enable SSR
+  width: 400, // need to specify height and width
+  height: 300
+});
+
+// setOption as normal
+chart.setOption({
+  xAxis: {
+    type: 'category',
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      data: [120, 200, 150, 80, 70, 110, 130],
+      type: 'bar'
+    }
+  ]
+});
+
+// Output string
+const svgStr = chart.renderToSVGString();

Customizing Map Projections

Maps have always been a very widely used component in ECharts. Typically a map component uses GeoJSON formatted data with latitude and longitude stored. ECharts then calculates the appropriate display area and maps the latitude and longitude linearly to that area. This is the simplest way to project a map. However, the simple linear projection does not work for complex map scenarios, such as using Albers projection to solve the distortion problem in linear projection, or having the Pacific in the middle of the world map, etc.

So in 5.3.0 we introduced extending map projection. It tells ECharts how to project coordinates and how to calculate latitude and longitude from the projected coordinates via the project and unproject methods. The following is a simple example of using the Mercator projection.

series = {
+  type: 'map',
+  projection: {
+    project: point => [
+      (point[0] / 180) * Math.PI,
+      -Math.log(Math.tan((Math.PI / 2 + (point[1] / 180) * Math.PI) / 2))
+    ],
+    unproject: point => [
+      (point[0] * 180) / Math.PI,
+      ((2 * 180) / Math.PI) * Math.atan(Math.exp(point[1])) - 90
+    ]
+  }
+};

In addition to implementing our own projection formula, we can also use projections implementations provided by third-party libraries such as d3-geo.

const projection = d3.geoConicEqualArea();
+// ...
+series = {
+  type: 'map',
+  projection: {
+    project: point => projection(point),
+    unproject: point => projection.invert(point)
+  }
+};

In conjunction with the new global transition animation feature added in 5.2, we can animate the transition between different projection effects: !

map-projection-animation

In addition to the map projection, we have made the following two enhancements to the map in this release.

  • Provided 'LineString' and 'MultiLineString' support for GeoJSON data.
  • Changed the calculation of the default label position from the center of the bounding box to the centroid of the largest area for more accurate results.

Ticks Alignment of Multiple Axes

Ticks alignment of multiple axes is a long-standing requirement in the community, and we can see many articles in the community on how to implement axis alignment in ECharts, which is usually troublesome and limited.

In 5.3.0, we finally introduced the feature of aligning ticks on the 'value' and 'log' axes. You can configure alignTicks: true in the axis that needs to be aligned. The axis will then adjust its own ticks according to the first axis's ticks, enabling automatic alignment.

option = {
+  tooltip: {
+    trigger: 'axis'
+  },
+  legend: {},
+  xAxis: [
+    {
+      type: 'category',
+      data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+      axisPointer: {
+        type: 'shadow'
+      }
+    }
+  ],
+  yAxis: [
+    {
+      type: 'value',
+      name: 'Precipitation',
+      alignTicks: true,
+      axisLabel: {
+        formatter: '{value} ml'
+      }
+    },
+    {
+      type: 'value',
+      name: 'Temperature',
+      axisLabel: {
+        formatter: '{value} °C'
+      }
+    }
+  ],
+  series: [
+    {
+      name: 'Evaporation',
+      type: 'bar',
+      // prettier-ignore
+      data: [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3]
+    },
+    {
+      name: 'Precipitation',
+      type: 'bar',
+      // prettier-ignore
+      data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3]
+    },
+    {
+      name: 'Temperature',
+      type: 'line',
+      yAxisIndex: 1,
+      data: [2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2]
+    }
+  ]
+};
live

Disable Emphasis and Select State

The emphasis state in ECharts provides feedback to the user when the mouse is over an element, but in a chart with a large number of elements, the highlighting animation can cause performance issues. In particular, highlighting triggered by tooltip or legend component linkage can highlight multiple elements at the same time.

Therefore, in this release we have added emphasis.disabled configuration. If you don't need the highlighting feedback and you are concerned about the interactivity, you can disable the emphasis state with this option.

For the select state, we have also added select.disabled. This option can be used to configure some of the data to be unselectable.

Support for Selecting Entire Series

As of 5.3.0 we support configuring selectedMode to 'series' to enable selection of all data in a series.

Formatting of Values in Tooltip

Tooltips can be used to display more detailed information about the data item when the user hovers it. ECharts also provides a formatter callback function to give developers more flexibility to customize the content of the tooltip.

However, we found that most of the time, developers only needed to format the value part of the tooltip, such as fixed precision, prefixed with $, etc. Previously, in order to format the number, developers had to rewrite the entire content of the tooltip with formatter. Especially after 5.0, ECharts hint boxes have become more complex and beautiful, so rewriting them becomes costly and difficult to achieve the default results.

So in this version, we have added a valueFormatter configuration to the tooltip for formatting the value part.

As in the axis alignment example, we can add the °C and ml suffixes to the value part of the tooltip.

option = {
+  tooltip: {
+    trigger: 'axis'
+  },
+  legend: {},
+  xAxis: [
+    {
+      type: 'category',
+      data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+      axisPointer: {
+        type: 'shadow'
+      }
+    }
+  ],
+  yAxis: [
+    {
+      type: 'value',
+      name: 'Precipitation',
+      alignTicks: true,
+      axisLabel: {
+        formatter: '{value} ml'
+      }
+    },
+    {
+      type: 'value',
+      name: 'Temperature',
+      axisLabel: {
+        formatter: '{value} °C'
+      }
+    }
+  ],
+  series: [
+    {
+      name: 'Evaporation',
+      type: 'bar',
+      tooltip: {
+        valueFormatter: value => value + ' ml'
+      },
+      // prettier-ignore
+      data: [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3]
+    },
+    {
+      name: 'Precipitation',
+      type: 'bar',
+      tooltip: {
+        valueFormatter: value => value + ' ml'
+      },
+      // prettier-ignore
+      data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3]
+    },
+    {
+      name: 'Temperature',
+      type: 'line',
+      yAxisIndex: 1,
+      tooltip: {
+        valueFormatter: value => value + ' °C'
+      },
+      data: [2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2]
+    }
+  ]
+};
live

Each series can configure its own valueFormatter according to its own value format.

More Flexible Sector Corner Radius

In 5.0 we have added rounded corners configuration for sectors, which can make pie charts, sunburst charts more interesting. Previously, we only supported the inner and outer radius separately, this time we go a step further and support the four corners of the sector to be configured with different corner radius to bring more flexible display.

option = {
+  tooltip: {
+    trigger: 'item'
+  },
+  legend: {
+    top: '5%',
+    left: 'center'
+  },
+  series: [
+    {
+      name: 'Access From',
+      type: 'pie',
+      radius: ['30%', '70%'],
+      roseType: 'angle',
+      itemStyle: {
+        borderRadius: [20, 5, 5, 10],
+        borderColor: '#fff',
+        borderWidth: 2
+      },
+      label: {
+        show: false
+      },
+      data: [
+        { value: 800, name: 'Search Engine' },
+        { value: 735, name: 'Direct' },
+        { value: 580, name: 'Email' },
+        { value: 484, name: 'Union Ads' },
+        { value: 400, name: 'Video Ads' }
+      ]
+    }
+  ]
+};
live

Complex Label Optimization for Pie charts

Pie charts have always been one of the most complex charts on the label display in ECharts. We have been optimizing the layout and display of the pie chart labels for a long time.

This time, we have done a deep optimization for pie chart labels that use text wrapping, background colors, rich text, and other complex layouts. In the adaptive width, container overflow, guide line calculation than before there are better results:

5.2.2 (Before) 5.3.0 (After)
before after
before after

bar chart large mode optimization

In the cases of a large amount of data (> 2k), we support bar charts to speed up rendering and improve interactive performance by turning on large mode. But previously the layout of bar charts in large mode was simple and did not support the layout after stacking multiple series. In 5.3.0, we have optimized the layout of large mode to be consistent with the normal mode. We can optimize the performance of the bar chart in more scenarios by turning on large.

In addition, the optimized bar chart layout also fixes the bug of incorrect stacking on non-linear axes like logarithmic axes.

Breaking Changes

registerMap and getMap methods need to be used only after the map chart is imported

To reduce the size of the minimum bundle, we removed the map data management methods getMap and registerMap from the core module.

If you are only importing necessary charts and components, you need to ensure that you have imported GeoComponent or MapChart before you can register map data with registerMap.

import * as echarts from 'echarts/core';
+import { MapChart } from 'echarts/charts';
+
+echarts.use([MapChart]);
+
+// You must import the MapChart with the `use` method before you can register the map with registerMap
+echarts.registerMap('world', worldJSON);

If you are using import * as echarts from 'echarts' to import the whole package, this change will not affect you in any way.

Removing the default bolding emphasis effect in the line chart

We introduced the default bolding emphasis effect for line charts in 5.0, but the community feedback was that this didn't looks well in many scenarios. So in this version we changed this effect from on by default to off by default. You can enable it by:

series = {
+  type: 'line',
+  //...
+  emphasis: {
+    lineStyle: {
+      width: 'bolder'
+    }
+  }
+};

Full Changelog

View the Changelog

Contributors Edit this page on GitHub

Ovilia Oviliapissang pissangplainheart plainheart
+ + + + + diff --git a/docs/en/basics/release-note/5-4-0/index.html b/docs/en/basics/release-note/5-4-0/index.html new file mode 100644 index 000000000..658736ffe --- /dev/null +++ b/docs/en/basics/release-note/5-4-0/index.html @@ -0,0 +1,15 @@ + + + + + + + 5.4 - What's New - Basics - Handbook - Apache ECharts + + +

Apache ECharts 5.4.0 Features

Intelligent Pointer Snapping

Some interactive elements may be relatively small in charts, so sometimes it is difficult for users to click and do other operations accurately, especially on the mobile. Therefore, in Apache ECharts 5.4.0, we introduced the concept of "intelligent pointer snapping".

See intelligent pointer snapping for details.

Using Pie charts in more coordinate systems

A very powerful feature of Apache ECharts is the combination of various chart types, coordinate systems, and components. In this version, we have added the coordinate systems option for pie charts.

Thus, pie charts can appear in the Cartesian coordinate systems,

calendar coordinate systems,

geographical coordinate systems,

and even with the Baidu Map and Gaode Map extension.

This greatly extends the flexibility of pie charts, allowing developers to create more combinations of chart effects using Apache ECharts.

Ukrainian Translation

In this release, we added the support of the Ukrainian language. Now Apache ECharts supports 17 languages!

If you need to use a language other than English or Chinese, you need to call echarts.registerLocale to initialize the chart before initializing it, and then pass opts.locale to modify the chart language during init.

Gauge Label Rotation

In this version, we support text rotation of the Gauge series.

axisLabel.rotate can be set to 'tangential' | 'radial' | number. If it is of type number, it indicates the rotation angle of the label from -90 degrees to 90 degrees, with positive values being counterclockwise. In addition to this, it can also be the strings 'radial' for radial rotation and 'tangential' for tangential rotation.

Full Changelog

View the Changelog

Contributors Edit this page on GitHub

Ovilia Ovilia
+ + + + + diff --git a/docs/en/basics/release-note/5-5-0/index.html b/docs/en/basics/release-note/5-5-0/index.html new file mode 100644 index 000000000..c0ff17ab0 --- /dev/null +++ b/docs/en/basics/release-note/5-5-0/index.html @@ -0,0 +1,82 @@ + + + + + + + 5.5 - What's New - Basics - Handbook - Apache ECharts + + +

Apache ECharts 5.5.0 Features

Enhanced ESM Support

This feature is a significant change to the default ESM package, specifically designed for developer testing and Node.js usage in module customization scenarios.

Previously, ECharts only exported *.esm files in npm (in the lib directory of the npm package). While this worked well in bundlers, it didn’t perform as well in the Node.js runtime and some Node.js-based testing frameworks like vitest and jest.

With this new feature, we’ve made several changes to improve this:

  • Added "type": "module" to package.json
  • Added "exports": {...}" to package.json
  • Added some package.json files to the sub-directory, which only contain "type": "commonjs".

These changes mean that files like echarts/core.js can now be resolved as ESM in environments like pure Node.js, vitest, jest, and create-react-app.

We’ve also ensured that this new feature is compatible with a variety of environments, including runtime (node/vitest/jest(create-react-app)/ssr/…) and bundlers (webpack/rollup/vite/esbuild/…).

We’re excited about this new feature and believe it will significantly improve the developer experience.

Server-Side Rendering + Lightweight Client Runtime

Apache ECharts is powerful, but correspondingly, it has a large package size. We have made various efforts to improve this in previous versions. Developers can use TreeShaking to load parts of the code as needed, reducing the amount of code loaded. Starting from Apache ECharts version 5.3, we support a server-side SVG string rendering solution with zero dependencies, and support the initial animation of charts. In this way, using the result of server-side rendering as the first screen rendering can greatly reduce the first screen loading time.

Although server-side rendering is an effective solution to reduce the package size, if some interactions need to be implemented on the client side, it is still necessary to load echarts.js, which may increase the loading time. For some scenarios that require faster page loading, this may not be an ideal choice.

In version 5.5.0, we added a lightweight runtime for the client side, so the client does not need to load the full ECharts to implement some interactions. In this way, we can render charts on the server side, and then load the lightweight runtime on the client side to implement some common interactions. This means that only 4KB of lightweight runtime (1KB after gzip) is needed to implement charts with initial animations and some commonly used interaction forms. This improvement will greatly increase the page loading speed, especially for the mobile experience.

Take this pie chart with a title as an example, if the client only packages the pie chart and title components, it needs 135KB after gzip; if it follows the server-side rendering solution, the rendering result SVG is 1 KB after gzip, and the client runtime is 1KB after gzip, only 1.5% of the former volume. In terms of interaction, the latter can also achieve initial animation, highlighting after the mouse moves to the chart element, and get click events, which can meet most of the common interaction needs.

If you need to use this solution, the server-side code remains the same, but you need to make sure that the ECharts version is above 5.5.0.

// Server-side code
+const echarts = require('echarts');
+
+// In SSR mode the first container parameter is not required
+const chart = echarts.init(null, null, {
+  renderer: 'svg', // must use SVG rendering mode
+  ssr: true, // enable SSR
+  width: 400, // need to specify height and width
+  height: 300
+});
+
+// use setOption as normal
+chart.setOption({
+  //...
+});
+
+// Output a string
+const svgStr = chart.renderToSVGString();
+
+// Dispose it to release memory
+chart.dispose();
+chart = null;
+
+// Response to the browser (using Express.js as example):
+res.writeHead(200, {
+  'Content-Type': 'application/xml'
+});
+res.write(svgStr);
+res.end();

The client adds the obtained SVG string to the container and binds the lightweight runtime:

<div id="chart-container" style="width:800px;height:600px"></div>
+
+<script src="https://cdn.jsdelivr.net/npm/echarts/ssr/client/dist/index.min.js"></script>
+<script>
+const ssrClient = window['echarts-ssr-client'];
+
+let isSeriesShown = {
+  a: true,
+  b: true
+};
+
+function updateChart(svgStr) {
+  const container = document.getElementById('chart-container');
+  container.innerHTML = svgStr;
+
+  // Use lightweight runtime to give the chart interactive capabilities
+  ssrClient.hydrate(main, {
+    on: {
+      click: (params) => {
+        if (params.ssrType === 'legend') {
+          // Click the legend element, request the server for secondary rendering
+          isSeriesShown[params.seriesName] = !isSeriesShown[params.seriesName];
+          fetch('...?series=' + JSON.stringify(isSeriesShown))
+            .then(res => res.text())
+            .then(svgStr => {
+              updateChart(svgStr);
+            });
+        }
+      }
+    }
+  });
+}
+
+// Get the SVG string rendered by the server through AJAX request
+fetch('...')
+  .then(res => res.text())
+  .then(svgStr => {
+    updateChart(svgStr);
+  });
+</script>

The lightweight client runtime must be used in conjunction with the server-side rendering results in SVG format, supporting the following interactions:

  • Initial animation of the chart (implementation principle: the SVG rendered by the server has CSS animation)
  • Highlight style (implementation principle: the SVG rendered by the server has CSS animation)
  • Dynamically change data (implementation principle: the lightweight runtime requests the server for secondary rendering)
  • Click the legend to toggle whether the series is displayed (implementation principle: the lightweight runtime requests the server for secondary rendering)

As you can see, this can satisfy most interactive scenario needs. If more complex interactions are needed, the client needs to load echarts.js to implement complete functionality. For a complete introduction, please refer to Server-side Rendering ECharts Charts.

Data Drilldown Supports Transition Animation

In version 5.5.0, we added the childGroupId configuration item, which can realize the transition animation function of data drilldown.

In previous versions, we already support using groupId to represent the group to which the current data belongs. The newly added childGroupId can be used to express the group of the current data itself, forming a `parent-child-grandchild` relationship chain after being used in conjunction with groupId. When the user clicks on the data element in the chart, the chart will display the drilled down data in the form of transition animation.

Developers only need to specify groupId and childGroupId, and ECharts will automatically handle the hierarchical relationship and realize the transition animation.

Pie Chart Supports Gaps Between Sectors

By setting gaps between the sectors of the pie chart, the data blocks of the pie chart can be clearer and form unique visual effects. See (series-pie.padAngle).

Pie Chart and Polar Coordinate System Support End Angle

The end angle configuration item allows us to make incomplete pie charts such as semi-circles. See (series-pie.endAngle).

The polar coordinate system also supports the end angle, which can create more diverse polar coordinate charts. See (angleAxis.endAngle).

Added min-max Sampling Method

The ECharts sampling configuration item allows for setting the downsampling strategy for line charts when the amount of data is far greater than the number of pixels, which can effectively optimize the drawing efficiency of the chart. In version 5.5.0, we added the min-max sampling method, which can display the extremes of the data more accurately while retaining the overall trend of the data.

Added Two Languages: Arabic and Dutch

In version 5.5.0, we added support for two languages, Arabic (AR) and Dutch (NL). Developers can register new language packs through the echarts.registerLocale method.

Tooltip Supports Specifying Container

In previous versions, the Tooltip could only be inserted into the chart container or document.body. Now, you can specify the container through tooltip.appendTo, so you can control the position of the tooltip more flexibly.

Alignment Mode of Maximum and Minimum Labels on Axis

In version 5.5.0, we added axisLabel.alignMinLabel and axisLabel.alignMaxLabel configuration items, which can control the alignment mode of the maximum and minimum labels on the axis. If the drawing area of the chart is relatively large and you don't want the axis label to overflow, you can align the maximum and minimum labels to the right and left, respectively.

Pictorial Bar Chart Supports Clipping

The pictorial bar chart may exceed the drawing area. If you want to avoid this, you can clip it through the series-pictorialBar.clip configuration item.

Added dataIndex Parameter For Tooltip valueFormatter

valueFormatter can be used to customize the value part of the tooltip content, and now an dataIndex parameter has been added, which can be used to obtain the index of the current data.

Full Changelog

View the Changelog

Contributors Edit this page on GitHub

Ovilia Oviliaplainheart plainheart
+ + + + + diff --git a/docs/en/basics/release-note/v5-feature/index.html b/docs/en/basics/release-note/v5-feature/index.html new file mode 100644 index 000000000..f83405c4e --- /dev/null +++ b/docs/en/basics/release-note/v5-feature/index.html @@ -0,0 +1,19 @@ + + + + + + + ECharts 5 Features - What's New - Basics - Handbook - Apache ECharts + + +

New features in ECharts 5

Data visualization has come a long way in the last few years. Developers no longer expect visualization products to be simple chart creation tools, but have more advanced needs in terms of interaction, performance, data processing, and more.

Apache ECharts has always been committed to making it easier for developers to create flexible and rich visualizations. In the latest release of Apache ECharts 5, we have focused on enhancing the storytelling of charts, allowing developers to tell the story behind the data in a simpler way.

"The core of Apache ECharts 5 is "Show, do not tell", which is a comprehensive upgrade of five topics and 15 features around the stroy telling of visualizations, allowing charts to better tell the story behind the data. It helps developers to create visualizations that meet the needs of various scenarios more easily.

Storytelling

The importance of animation to human cognition cannot be overstated. In our previous work, we used initialization animations and transition animations to help users understand the connection between data transformations, making the appearance of charts and transformations seem less rigid. This time, we have even enhanced our animation capabilities, even more significantly. We hope to further exploit the role of animation to help users' cognition, and help them understand the story behind the chart more easily with the dynamic stroy function of the chart.

Bar/Line Racing

Apache ECharts 5 adds support for dynamically sorted bar-racing and dynamically sorted line-racing charts to help developers easily create time-series charts that show changes in data over time and tell the evolution of data.

The dynamic sorting chart shows the derivation of different categories in the ranking over time. The developer can enable this effect in ECharts with a few simple configuration code.

Custom Series Animation

In addition to dynamic sorting charts, Apache ECharts 5 provides even richer and more powerful animations in the custom series, supporting interpolation animations for label value text, transition animations for morph, combine, separate, and other effects of graphics.

Imagine what amazing visualizations you can create with these dynamic effects!

Visual Design

The role of visual design is not only to make the chart look better, but more importantly, a design that conforms to the principles of visualization can help users understand more quickly what the chart is trying to say and eliminate as much misunderstanding as possible from poor design.

Overall Design

We have found that a large percentage of developers use the default theme style for ECharts, so it is important to have an elegant default theme design. In Apache ECharts 5, we redesigned the default theme style, optimizing it for different charts and components. For example, we took into account factors such as differentiation between colors, contrast with background colors, and harmony with adjacent colors, and ensured that people with color blindness could clearly distinguish data.

Let's look at the new version of the light and dark theme styles using the most commonly used bar chart as an example.

For the line chart, there is an intuitive style change that the axis line and axis tick of the y axis (value axis) are hidden by default. Look at the following image, the left one is the default style of the line chart in v4 and the right one is the new style in v5. In fact, we already can figure out the values just by the split lines, so we hope to hide unnecessary elements to deliver the chart message in a clearer way.

For the data area zoom, timeline and other interactive components, we also designed a new style and provide a better interactive experience:

Label

Labels are one of the core elements of a chart, and clear and unambiguous labels help users to have a more accurate understanding of the data. Apache ECharts 5 provides a variety of new labeling features that allow dense labels to be clearly displayed and accurately represented.

Apache ECharts 5 can be enabled to automatically hide overlapping labels through a configuration item. For labels that exceed the display area, you can choose to automatically truncate or line break them. Dense pie chart labels now have a more aesthetically pleasing automatic layout.

These features can help avoid text that is too dense and affects readability. And, no additional code needs to be written by the developer for them to take effect by default, greatly simplifying the development cost for developers.

We also provide several configuration options to allow developers to actively control the layout strategy of tabs, such as tab dragging, overall display at the edge of the canvas, connecting with guide lines and graphical elements, and still linking to highlight the associated relationships.

The new label feature allows you to have very clear label presentation even in a confined space mobile:

Time Axis

Apache ECharts 5 brings a time axis suitable for expressing timestamp scales. The default design of the time axis highlights important information more prominently and provides more flexible customization capabilities, allowing developers to tailor the time axis's label content to different needs.

First of all, the time axis is no longer split absolutely evenly as before, but instead selects more meaningful points like year, month, day, and whole point to display, and can show different levels of scales at the same time. The formatter of labels supports templates for time (e.g. {yyyy}-{MM}-{dd}), and different formatter can be specified for labels with different time granularity, which can be combined with rich text labels to create eye-catching and diverse time effects.

The display of the time scale at different dataZoom granularities.

Tooltip

Tooltip is one of the most commonly used visualization components to help users interactively understand the details of data. In Apache ECharts 5, we have optimized the style of the tooltip, making the default display of the tooltip elegant and clear by adjusting the font style, color, arrow pointing to the graph, border color following the graph color, and other features. The rendering logic of rich text has been improved to ensure that the display is consistent with the HTML way, allowing users to choose different technical solutions to achieve the same effect in different scenarios.

In addition to this, we have also added the ability to sort the list in the tip box by value size or category order this time.

Gauge

We have seen a lot of cool gauge charts created by community users, but the way they are configured is often complex and tricky. Therefore, we have upgraded the gauge to support image or vector path drawing pointers, anchor configurations, progress bars, rounded corner effects, and more.

Different styles of gauge pointers.

These upgrades not only allow developers to achieve cool effects with simpler configuration items, but also bring richer customization capabilities.

Round Corner

Apache ECharts 5 supports round corner for pie charts, sunburst charts, and treemap charts. Don't underestimate the simplicity of the rounded corners configuration, but combine them with other effects to create a more personalized visualization.

Interactivity

The interactivity of the visualization helps users explore the work and deepen their understanding of the main idea of the diagram.

Multi-State

In ECharts 4, there were two interactive states, emphasis and normal, graph will enter the emphasis state when the mouse hovered to distinguish the data.

This time in Apache ECharts 5, we have added a new effect of blur other non-related elements to the original mouse hover highlighting, so that the target data can be focused.

For example, in this bar chart example, when the mouse hovers over a series, other non-related series will fade out, thus highlighting more clearly the comparison of data in the focused series. of data in the comparison. On diagrams with more complex data structures such as relationship, tree, sunburst, sankey, etc., it is also possible to see the connections between data by fading out non-related elements. Also, colors, shadows, and other styles that can be set in emphasis can now be set in blur.

In addition, we've added click to select to all series, an interaction that was previously only available in a few series such as pie charts and maps, allowing developers to set it to single or multiple selection mode, and to listen to the selectchanged event to get all the selected shapes for further processing. As with emphasis and blur, the selection style can also be configured in select.

Performance improvements

Dirty Rectangle Rendering

Apache ECharts 5 has new support for dirty rectangle rendering to address performance bottlenecks in large scenes with only local changes. When using the Canvas renderer, the dirty rectangle rendering technique detects and updates only the parts of the view that have changed, rather than any changes causing a complete redraw of the canvas. This can help improve rendering frame rates in some special scenarios, such as scenes where the mouse frequently triggers some graphical highlighting many times. In the past for such scenes, additional Canvas layers were used to optimize performance, but this approach is not universal for all scenes and does not work well for complex styles. Dirty Rectangle rendering does a good job of satisfying both performance and display correctness.

A visual demonstration of a dirty rectangle, with the red boxed area redrawn for the frame.

You can see the effect by enable dirty rectangle optimization on the new example page.

Line Chart Performance Optimization for Real-Time Time-Series Data

In addition, the performance of line graphs with large amounts of data has also seen a significant performance improvement. We often encounter the need for high-performance plotting of large amounts of real-time time-series data, which will be updated every hundreds or tens of milliseconds.

Apache ECharts 5 deeply optimizes CPU consumption, memory usage, and initialization time in these scenarios, enabling real-time updates (less than 30ms per update) for millions of data, and even rendering within 1s for ten millions of data, with low memory usage and smooth tooltip interactions.

Development Experience

We want such a powerful visualization tool to be used by more developers in a simpler way, so the developer experience is also a very important aspect for us.

Datasets

ECharts 5 enhances the data transformation capabilities of datasets, allowing developers to implement common data processing such as filtering, sorting, aggregating, histogram, simple clustering, regression, etc. in a simple way. Developers can use these functions in a uniform and declarative way, and can easily implement common data operations.

Internationalization

The original internationalization implementation of ECharts takes the form of different distribution files packaged according to different language parameters. In this way, the dynamic language and main code are bound together, and the only way to switch languages when using ECharts is to reload different language versions of ECharts distributions.

Therefore, starting with Apache ECharts 5, the dynamic language is separated from the main code. To switch languages, you only need to load the corresponding language, use the registerLocale function to mount the language object in a similar way to mount the theme, and then reinitialize it to complete the language switch.

// import the lang object and set when init
+echarts.registerLocale('DE', lang);
+echarts.init(DomElement, null, {
+  locale: 'DE'
+});

TypeScript Refactoring

In order to continue to refactor and develop new features more safely and efficiently, we started the development of Apache ECharts 5 by rewriting the code using TypeScript. The strong typing brought by TypeScript gave us the confidence to refactor the code drastically to achieve more exciting features during the development of ECharts 5.

For developers, we can also generate better and more code-compliant DTS type description files directly from TypeScript code. Until now, ECharts type description files have been maintained by community developers and published to DefinitelyTyped, which is a lot of work, so thanks for your contribution.

In addition, if a developer's component is introduced on-demand, we provide a ComposeOption type method that can combine a configuration item type that contains only the introduced components, which can bring stricter type checking and help you detect unintroduced component types in advance.

Accessibility

Apache ECharts has always taken accessibility design seriously, and we want to make the information conveyed by charts equally to be accessed. We also want to make this possible for chart developers at a very low development cost, thus making developers more willing to support the accessibility.

In the last major release, we supported automatic intelligent generation of chart descriptions based on different chart types and data, making it very easy for developers to support DOM description information for charts. In ECharts 5, we have also made more accessibility improvements to help people with visual impairments better understand the chart content.

Theme Colors

We took accessibility into account when designing the new default theme, and we repeatedly tested the brightness and color values of the colors to help accessibility users clearly identify the chart data.

Moreover, for developers with further accessibility needs, we also provide special high-contrast themes to further differentiate the data with higher contrast colors.

Decal Patterns

ECharts 5 also provides a new feature of decals to help users further differentiate data by using patterns to assist with color representation.

In addition, decal patterns can also help in some other scenarios, such as: helping to better distinguish data in printed materials like newspapers and books that have only a single color or very few colors; using graphical elements to facilitate a more intuitive understanding of the data by the user.

Summary

In addition to the features described above, Apache ECharts has been improved in a very large number of details to help developers more easily create charts that good by default, are flexible in configuration, and tell the story behind the data with charts.

Thank you to all the developers who have used ECharts, and even participated in community contributions, for making Apache ECharts 5 possible. We'll be working on future developments with even more enthusiasm, and we'll see you all in 6 with even more enthusiasm!

Contributors Edit this page on GitHub

pissang pissangplainheart plainhearttimonla timonla
+ + + + + diff --git a/docs/en/basics/release-note/v5-upgrade-guide/index.html b/docs/en/basics/release-note/v5-upgrade-guide/index.html new file mode 100644 index 000000000..eb00a7008 --- /dev/null +++ b/docs/en/basics/release-note/v5-upgrade-guide/index.html @@ -0,0 +1,97 @@ + + + + + + + Migration from v4 to v5 - What's New - Basics - Handbook - Apache ECharts + + +

Apache ECharts 5 Upgrade Guide

This guide is for those who want to upgrade from echarts 4.x (hereafter v4) to echarts 5.x (hereafter v5). You can find out what new features v5 brings that are worth upgrading in New Features in ECharts 5. In most cases, developers won't need to do anything extra for this upgrade, as echarts has always tried to keep the API as stable and backward-compatible as possible. However, v5 still brings some breaking changes that require special attention. In addition, in some cases, v5 provides a better API to replace the previous one, and these superseded APIs will no longer be recommended (though we have tried to be as compatible as possible with these changes). We'll try to explain these changes in detail in this document.

Breaking Changes

Default Theme

First of all, the default theme has been changed. v5 has made a lot of changes and optimizations on the theme design. If you still want to keep the colors of the old version, you can manually declare the colors as follows.

chart.setOption({
+  color: [
+    '#c23531',
+    '#2f4554',
+    '#61a0a8',
+    '#d48265',
+    '#91c7ae',
+    '#749f83',
+    '#ca8622',
+    '#bda29a',
+    '#6e7074',
+    '#546570',
+    '#c4ccd3'
+  ]
+  // ...
+});

Or, to make a simple v4 theme.

var themeEC4 = {
+  color: [
+    '#c23531',
+    '#2f4554',
+    '#61a0a8',
+    '#d48265',
+    '#91c7ae',
+    '#749f83',
+    '#ca8622',
+    '#bda29a',
+    '#6e7074',
+    '#546570',
+    '#c4ccd3'
+  ]
+};
+var chart = echarts.init(dom, themeEC4);
+chart.setOption(/* ... */);

Importing ECharts

Removing Support for Default Exports

Since v5, echarts only provides named exports.

So if you are importing echarts like this:

import echarts from 'echarts';
+// Or import core module
+import echarts from 'echarts/lib/echarts';

It will throw error in v5. You need to change the code as follows to import the entire module.

import * as echarts from 'echarts';
+// Or
+import * as echarts from 'echarts/lib/echarts';

Tree-shaking API

In 5.0.1, we introduced the new tree-shaking API

import * as echarts from 'echarts/core';
+import { BarChart } from 'echarts/charts';
+import { GridComponent } from 'echarts/components';
+// Note that the Canvas renderer is no longer included by default and needs to be imported explictly, or import the SVGRenderer if you need to use the SVG rendering mode
+import { CanvasRenderer } from 'echarts/renderers';
+
+echarts.use([BarChart, GridComponent, CanvasRenderer]);

To make it easier for you to know which modules you need to import based on your option, our new example page adds a new feature to generate the three-shakable code, you can check the Full Code tab on the example page to see the modules you need to introduce and the related code.

In most cases, we recommend using the new tree-shaking interface whenever possible, as it maximizes the power of the packaging tool tree-shaking and effectively resolves namespace conflicts and prevents the exposure of internal structures. If you are still using the CommonJS method of writing modules, the previous approach is still supported:

const echarts = require('echarts/lib/echarts');
+require('echarts/lib/chart/bar');
+require('echarts/lib/component/grid');

Second, because our source code has been rewritten using TypeScript, v5 will no longer support importing files from echarts/src. You need to change it to import from echarts/lib.

Dependency Changes

Note: This section is only for developers who use tree-shaking interfaces to ensure a minimal bundle size, not for those who imports the whole package.

In order to keep the size of the bundle small enough, we remove some dependencies that would have been imported by default. For example, as mentioned above, when using the new on-demand interface, CanvasRenderer is no longer included by default, which ensures that unneeded Canvas rendering code is not imported when only SVG rendering mode is used, and in addition, the following dependencies are adjusted.

  • The right-angle coordinate system component is no longer introduced by default when using line charts and bar charts, so the following introduction method was used before
const echarts = require('echarts/lib/echarts');
+require('echarts/lib/chart/bar');
+require('echarts/lib/chart/line');

Need to introduce the grid component separately again

require('echarts/lib/component/grid');

Reference issues: #14080, #13764

  • aria components are no longer imported by default. You need import it manually if necessary.
import { AriaComponent } from 'echarts/components';
+echarts.use(AriaComponent);

Or

require('echarts/lib/component/aria');

Built-in GeoJSON Removed

v5 removes the built-in geoJSON (previously in the echarts/map folder). These geoJSON files were always sourced from third parties. If users still need them, they can go get them from the old version, or find more appropriate data and register it with ECharts via the registerMap interface.

Browser Compatibility

IE8 is no longer supported by v5. We no longer maintain and upgrade the previous VML renderer for IE8 compatibility. If developers have a strong need for a VML renderer, they are welcome to submit a pull request to upgrade the VML renderer or maintain a separate third-party VML renderer, as we support registration of standalone renderers starting with v5.0.1.

Configuration Item Adjustment

Axis-Line and Axis-Tick of Y-Axis (Value Axis) Are Hidden by Default

The axis line and axis ticks of the Y axis (value axis) has been hidden by default since v5. If you prefer the previous style, you will need to explicitly configure as follows,

yAxis: {
+  type: 'value',
+  // explicitly set `axisLine.show` & `axisTick.show` as `true`
+  axisLine: {
+    show: true
+  },
+  axisTick: {
+    show: true
+  }
+}

Visual Style Settings Priority Changes

The priority of the visuals between visualMap component and itemStyle | lineStyle | areaStyle are reversed since v5.

That is, previously in v4, the visuals (i.e., color, symbol, symbolSize, ...) that generated by visualMap component has the highest priority, which will overwrite the same visuals settings in itemStyle | lineStyle | areaStyle. That brought troubles when needing to specify specific style to some certain data items while using visualMap component. Since v5, the visuals specified in itemStyle | lineStyle | areaStyle has the highest priority.

In most cases, users will probably not notice this change when migrating from v4 to v5. But users can still check that if visualMap component and itemStyle | lineStyle | areaStyle are both specified.

padding for Rich Text

v5 adjusts the rich.?.padding to make it more compliant with CSS specifications. In v4, for example rich. .padding: [11, 22, 33, 44] means that padding-top is 33 and padding-bottom is 11. The position of the top and bottom is adjusted in v5, rich. .padding: [11, 22, 33, 44] means that padding-top is 11 and padding-bottom is 33.

If the user is using rich.?.padding, this order needs to be adjusted.

Extensions

These extensions need to be upgraded to new version to support echarts v5:

Deprecated APIs

Some of the API and echarts options are deprecated since v5, but are still backward compatible. Users can keep using these deprecated API, with only some warning will be printed to console in dev mode. But if users have spare time, it is recommended to upgraded to new API for the consideration of long term maintenance.

The deprecated API and their corresponding new API are listed as follows:

  • Transform related props of a graphic element are changed: +
    • Changes: +
      • position: [number, number] are changed to x: number/y: number.
      • scale: [number, number] are changed to scaleX: number/scaleY: number.
      • origin: [number, number] are changed to originX: number/originY: number.
    • The position, scale and origin are still supported but deprecated.
    • It effects these places: +
      • In the graphic components: the declarations of each element.
      • In custom series: the declarations of each element in the return of renderItem.
      • Directly use zrender graphic elements.
  • Text related props on graphic elements are changed: +
    • Changes: +
      • The declaration of attached text (or say, rect text) are changed. +
        • Prop style.text are deprecated in elements except Text. Instead, Prop set textContent and textConfig are provided to support more powerful capabilities.
        • These related props at the left part below are deprecated. Use the right part below instead. +
          • textPosition => textConfig.position
          • textOffset => textConfig.offset
          • textRotation => textConfig.rotation
          • textDistance => textConfig.distance
      • The props at the left part below are deprecated in style and style.rich.?. Use the props at the right part below instead. +
        • textFill => fill
        • textStroke => stroke
        • textFont => font
        • textStrokeWidth => lineWidth
        • textAlign => align
        • textVerticalAlign => verticalAlign
        • textLineHeight => lineHeight
        • textWidth => width
        • textHeight => hight
        • textBackgroundColor => backgroundColor
        • textPadding => padding
        • textBorderColor => borderColor
        • textBorderWidth => borderWidth
        • textBorderRadius => borderRadius
        • textBoxShadowColor => shadowColor
        • textBoxShadowBlur => shadowBlur
        • textBoxShadowOffsetX => shadowOffsetX
        • textBoxShadowOffsetY => shadowOffsetY
      • Note: these props are not changed: +
        • textShadowColor
        • textShadowBlur
        • textShadowOffsetX
        • textShadowOffsetY
    • It effects these places: +
      • In the graphic components: the declarations of each element. [compat, but not accurately the same in some complicated cases.]
      • In custom series: the declarations of each element in the return of renderItem. [compat, but not accurately the same in some complicated cases].
      • Directly use zrender API to create graphic elements. [No compat, breaking change].
  • API on chart instance: +
    • chart.one(...) is deprecated.
  • label: +
    • In props color, textBorderColor, backgroundColor and borderColor, the value 'auto' is deprecated. Use the value 'inherit' instead.
  • hoverAnimation: +
    • option series.hoverAnimation is deprecated. Use series.emphasis.scale instead.
  • line series: +
    • option series.clipOverflow is deprecated. Use series.clip instead.
  • custom series: +
    • In renderItem, the api.style(...) and api.styleEmphasis(...) are deprecated. Because it is not really necessary and hard to ensure backward compatibility. Users can fetch system designated visual by api.visual(...).
  • sunburst series: +
    • Action type highlight is deprecated. Use sunburstHighlight instead.
    • Action type downplay is deprecated. Use sunburstUnhighlight instead.
    • option series.downplay is deprecated. Use series.blur instead.
    • option series.highlightPolicy is deprecated. Use series.emphasis.focus instead.
  • pie series: +
    • The action type at the left part below are deprecated. Use the right part instead: +
      • pieToggleSelect => toggleSelect
      • pieSelect => select
      • pieUnSelect => unselect
    • The event type at the left part below are deprecated. Use the right part instead: +
      • pieselectchanged => selectchanged
      • pieselected => selected
      • pieunselected => unselected
    • option series.label.margin is deprecated. Use series.label.edgeDistance instead.
    • option series.clockWise is deprecated. Use series.clockwise instead.
    • option series.hoverOffset is deprecated. Use series.emphasis.scaleSize instead.
  • map series: +
    • The action type at the left part below are deprecated. Use the right part instead: +
      • mapToggleSelect => toggleSelect
      • mapSelect => select
      • mapUnSelect => unselect
    • The event type at the left part below are deprecated. Use the right part instead: +
      • mapselectchanged => selectchanged
      • mapselected => selected
      • mapunselected => unselected
    • option series.mapType is deprecated. Use series.map instead.
    • option series.mapLocation is deprecated.
  • graph series: +
    • option series.focusNodeAdjacency is deprecated. Use series.emphasis: { focus: 'adjacency'} instead.
  • gauge series: +
    • option series.clockWise is deprecated. Use series.clockwise instead.
    • option series.hoverOffset is deprecated. Use series.emphasis.scaleSize instead.
  • dataZoom component: +
    • option dataZoom.handleIcon need prefix path:// if using SVGPath.
  • radar: +
    • option radar.name is deprecated. Use radar.axisName instead.
    • option radar.nameGap is deprecated. Use radar.axisNameGap instead.
  • Parse and format: +
    • echarts.format.formatTime is deprecated. Use echarts.time.format instead.
    • echarts.number.parseDate is deprecated. Use echarts.time.parse instead.
    • echarts.format.getTextRect is deprecated.

Contributors Edit this page on GitHub

plainheart plainheartOvilia Oviliafuchunhui fuchunhuipissang pissang
+ + + + + diff --git a/docs/en/best-practices/aria/index.html b/docs/en/best-practices/aria/index.html new file mode 100644 index 000000000..7c16d516b --- /dev/null +++ b/docs/en/best-practices/aria/index.html @@ -0,0 +1,37 @@ + + + + + + + Aria - Best Practices - Handbook - Apache ECharts + + +

Web Accessibility

WAI-ARIA, the Accessible Rich Internet Applications Suite developed by W3C, defines a way to make Web content and Web applications more accessible to people with disabilities.

ECharts 4.0 complied with the specification, supports generating a description based on the chart configuration intelligently to allow people with visual disabilities to understand the content of the chart with the help of reading devices. Apache ECharts 5 supports decal patterns that allow chart data to be distinguished by decal patterns in addition to color providing a better experience to those with color-blindness.

This accessibility function is turned off by default. It can be turned on by setting the value of aria.show to true.

Chart Labels

After setting aria.show to true, ECharts will automatically generate a description of the chart according to the title, chart, data, etc. Users can also set description manually through the configuration object.

Example configuration object:

option = {
+  aria: {
+    show: true
+  },
+  title: {
+    text: 'Referrer of a User',
+    x: 'center'
+  },
+  series: [
+    {
+      name: 'Referrer',
+      type: 'pie',
+      data: [
+        { value: 335, name: 'Direct Visit' },
+        { value: 310, name: 'Email Marketing' },
+        { value: 234, name: 'Union Ad' },
+        { value: 135, name: 'Video Ad' },
+        { value: 1548, name: 'Search Engine' }
+      ]
+    }
+  ]
+};

Enabling aria with add an aria-label attribute on the Chart HTML. Screen readers use this attribute to describe the contect; this chart would have the following description:

This is a chart about "Referrer of a User" with type Pie chart named Referrer. The data is as follows: the data of Direct Visit is 335,the data of Mail Marketing is 310,the data of Union Ad is 234,the data of Video Ad is 135,the data of Search Engine is 1548.
+

The configurated language will be used to build the description.

Customizing Title

The aria-label begins with the a general description. There are two templates, aria.general.withTitle to be used when title.text exists and aria.general.withoutTitle for when title.text is not defined.

In the withTitle template, the string {title} is replace with title.text. The template This is a chart named {title} with a title of Referrer of a User would yield This is a chart named Referrer of a User.

Customizing Description

The description of the series and data are added after the title. For some charts, the default item description cannot show all the information on the chart. In the following scatter chart the description generated by default includes all the items but it is not accessible due to the quantity of items making the list too long to understand.

Under this circumstance, the description should be set with the aria.description property.

In-Depth Customization

Every part of the aria-label can include template variables to be replaced by the actual value in the chart. More information on the process of generating a description is available in the API documentation: aria.label.

Decal Patterns

In addition, Apache ECharts 5 adds support for decal patterns as a secondary representation of color to further differentiate data. With aria.enabled set to true and aria.decal.show set to true, the default decal style will be applied.

If you need to customize the decal pattern, you can use aria.decal.decals to configure a flexible decal pattern.

Please refer to ARIA option for more detail.

Contributors Edit this page on GitHub

pissang pissangOvilia Oviliajulien-deramond julien-deramondzachary-svoboda-accesso zachary-svoboda-accesso
+ + + + + diff --git a/docs/en/best-practices/canvas-vs-svg/index.html b/docs/en/best-practices/canvas-vs-svg/index.html new file mode 100644 index 000000000..d8a574b06 --- /dev/null +++ b/docs/en/best-practices/canvas-vs-svg/index.html @@ -0,0 +1,26 @@ + + + + + + + Canvas vs. SVG - Best Practices - Handbook - Apache ECharts + + +

Render with SVG or Canvas

Most browser-side chart libraries use SVG or Canvas as the underlying renderer. Generally, both technologies are interchangeable and have a similar effect. However, the difference may be notable in some specific scenarios and cases. As a result, it's always a hard choice to decide which technology to render charts.

Canvas has been used as the renderer of ECharts from the beginning. Since v4.0, ECharts has provided the SVG renderer as an additional option. You can specify the renderer parameter as 'canvas' or 'svg' when initializing the chart.

SVG and Canvas have a significant difference in use. The uniform support for both technologies in ECharts is attributed to the abstraction and implementation of the underlying library ZRender.

How to Choose a Renderer

Generally, Canvas is more suitable for charts with a large number of elements (heat map, large-scale line or scatter plot in geo or parallel coordinates, etc.), and with visual effect. However, SVG has an important advantage: It has less memory usage (which is important for mobile devices) and won't be blurry when zooming in.

The choice of renderer can be based on a combination of hardware and software environment, data volume and functional requirements.

  • In scenarios where the hardware and software environment is good and the amount of data is not too large, both renderers will work and there is not much need to agonize over them.
  • In scenarios where the environment is poor and performance issues arise that require optimization, experimentation can be used to determine which renderer to use. For example, there are these experiences. +
    • In situations where many instances of ECharts have to be created and the browser is prone to crashing (probably because the number of Canvas is causing the memory footprint to exceed the phone's capacity), the SVG renderer can be used to make improvements. Roughly speaking, the SVG renderer may work better if the chart is running on a low-end Android, or if we are using specific charts such as the LiquidFill chart.
    • For larger amounts of data (>1k is an experience value), canvas renderer is always recommended.

We strongly welcome feedback from developers on their experiences and scenarios to help us make better optimizations.

Note: Currently, some special effects still relies on Canvas: e.g. trail effect, heatmap with blending effect, etc.

Since v5.3.0, the SVG renderer got refactored using the Virtual DOM, the performance got improved by 2-10 times and it can even be dozens of times in some specific scenarios! Refer to #836 for more details.

How to Use the Renderer

If echarts is fully imported in the following way, it already automatically imported and registered the SVG renderer and the Canvas renderer.

import * as echarts from 'echarts';

If you are using tree-shakable import, you will need to import the required renderers manually.

import * as echarts from 'echarts/core';
+// You can use only the renderers you need
+import { SVGRenderer, CanvasRenderer } from 'echarts/renderers';
+
+echarts.use([SVGRenderer, CanvasRenderer]);

Then you can set the renderer parameter when initializing the chart.

// Use the Canvas renderer (default)
+var chart = echarts.init(containerDom, null, { renderer: 'canvas' });
+// Equivalent to
+var chart = echarts.init(containerDom);
+
+// use the SVG renderer
+var chart = echarts.init(containerDom, null, { renderer: 'svg' });

Contributors Edit this page on GitHub

plainheart plainheartpissang pissangmrbrianevans mrbrianevans
+ + + + + diff --git a/docs/en/concepts/axis/index.html b/docs/en/concepts/axis/index.html new file mode 100644 index 000000000..e1082e628 --- /dev/null +++ b/docs/en/concepts/axis/index.html @@ -0,0 +1,288 @@ + + + + + + + Axis - Concepts - Handbook - Apache ECharts + + +

Axis

The x/y-axis in the Cartesian coordinate system.

x-axis, y-axis

Both x-axis and y-axis included axis line, tick, label and title. Some chart will use the grid to assist the data viewing and calculating.

A normal 2D coordinate system has x-axis and y-axis. X-axis located at the bottom while y-axis at the left side in common. The Config is shown below:

option = {
+  xAxis: {
+    // ...
+  },
+  yAxis: {
+    // ...
+  }
+  // ...
+};

The x-axis is usually used to declare the number of categories which was also called the aspects of observing the data: "Sales Time", "Sales Location" and "product name", etc.. The y-axis usually used to indicate the numerical value of categories. These data are used to examine the quantitative value of a certain type of data or some indicator you need to analyze, such as "Sales Quantity" and "Sales Price".

option = {
+  xAxis: {
+    type: 'time',
+    name: 'Sales Time'
+    // ...
+  },
+  yAxis: {
+    type: 'value',
+    name: 'Sales Quantity'
+    // ...
+  }
+  // ...
+};

When x-axis has a large span, we can use the zoom method to display part of the data in the chart.

option = {
+  xAxis: {
+    type: 'time',
+    name: 'Sales Time'
+    // ...
+  },
+  yAxis: {
+    type: 'value',
+    name: 'Sales Quantity'
+    // ...
+  },
+  dataZoom: []
+  // ...
+};

In two-dimensional data, there can be more than two axes. There are usually two x or y axes at the same time in ECharts. You can change the config offset to avoid overlaps of axes at the same place. X-axes can be displayed at the top and bottom, y-axes at left and right.

option = {
+  xAxis: {
+    type: 'time',
+    name: 'Sales Time'
+    // ...
+  },
+  yAxis: [
+    {
+      type: 'value',
+      name: 'Sales Quantity'
+      // ...
+    },
+    {
+      type: 'value',
+      name: 'Sales Price'
+      // ...
+    }
+  ]
+  // ...
+};

Axis Line

ECharts provide the config of axisLine. You can change the setting according to the demand, such as the arrow on two sides and the style of axes.

option = {
+  xAxis: {
+    axisLine: {
+      symbol: 'arrow',
+      lineStyle: {
+        type: 'dashed'
+        // ...
+      }
+    }
+    // ...
+  },
+  yAxis: {
+    axisLine: {
+      symbol: 'arrow',
+      lineStyle: {
+        type: 'dashed'
+        // ...
+      }
+    }
+  }
+  // ...
+};

Tick

ECharts provide the config axisTick. You can change the setting according to the demand, such as the length of ticks, and the style of ticks.

option = {
+  xAxis: {
+    axisTick: {
+      length: 6,
+      lineStyle: {
+        type: 'dashed'
+        // ...
+      }
+    }
+    // ...
+  },
+  yAxis: {
+    axisTick: {
+      length: 6,
+      lineStyle: {
+        type: 'dashed'
+        // ...
+      }
+    }
+  }
+  // ...
+};

Label

ECharts provide the config axisLabel. You can change the setting according to the demand, such as the text alignment and the customized label content.

option = {
+  xAxis: {
+    axisLabel: {
+      formatter: '{value} kg',
+      align: 'center'
+      // ...
+    }
+    // ...
+  },
+  yAxis: {
+    axisLabel: {
+      formatter: '{value} ¥',
+      align: 'center'
+      // ...
+    }
+  }
+  // ...
+};

Example

The y-axis on the left side represents the monthly average temperature in Tokyo, the y-axis on the right side represents the precipitation of Tokyo. The x-axis represents the time. It reflects the trend and relation between the average temperature and precipitation.

option = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: { type: 'cross' }
+  },
+  legend: {},
+  xAxis: [
+    {
+      type: 'category',
+      axisTick: {
+        alignWithLabel: true
+      },
+      axisLabel: {
+        rotate: 30
+      },
+      data: [
+        'January',
+        'February',
+        'March',
+        'April',
+        'May',
+        'June',
+        'July',
+        'August',
+        'September',
+        'October',
+        'November',
+        'December'
+      ]
+    }
+  ],
+  yAxis: [
+    {
+      type: 'value',
+      name: 'Precipitation',
+      min: 0,
+      max: 250,
+      position: 'right',
+      axisLabel: {
+        formatter: '{value} ml'
+      }
+    },
+    {
+      type: 'value',
+      name: 'Temperature',
+      min: 0,
+      max: 25,
+      position: 'left',
+      axisLabel: {
+        formatter: '{value} °C'
+      }
+    }
+  ],
+  series: [
+    {
+      name: 'Precipitation',
+      type: 'bar',
+      yAxisIndex: 0,
+      data: [6, 32, 70, 86, 68.7, 100.7, 125.6, 112.2, 78.7, 48.8, 36.0, 19.3]
+    },
+    {
+      name: 'Temperature',
+      type: 'line',
+      smooth: true,
+      yAxisIndex: 1,
+      data: [
+        6.0,
+        10.2,
+        10.3,
+        11.5,
+        10.3,
+        13.2,
+        14.3,
+        16.4,
+        18.0,
+        16.5,
+        12.0,
+        5.2
+      ]
+    }
+  ]
+};
live

These are the concise intro of the usage of axis config. Check more details at: Official Website.

Contributors Edit this page on GitHub

pissang pissang
+ + + + + diff --git a/docs/en/concepts/chart-size/index.html b/docs/en/concepts/chart-size/index.html new file mode 100644 index 000000000..144bf06e4 --- /dev/null +++ b/docs/en/concepts/chart-size/index.html @@ -0,0 +1,43 @@ + + + + + + + Chart Container - Concepts - Handbook - Apache ECharts + + +

Chart Container and Size

In Get Started, we introduced the API to initialize the ECharts echarts.init. API Document has introduced the specific meaning of each parameters. Please read and understand the document before reading the following content.

Refer to several common usage scenarios, here is the example to initialize a chart and change the size.

Initialization

Define a Parent Container in HTML

In general, you need to define a <div> node and use the CSS to change the width and height. While initializing, import the chart into the node. Without declaring opts.width or opts.height, the size of the chart will default to the size of the node.

<div id="main" style="width: 600px;height:400px;"></div>
+<script type="text/javascript">
+  var myChart = echarts.init(document.getElementById('main'));
+</script>

To be noticed, before calling echarts.init, you need to make sure the container already has width and height.

Specify the chart size

If the height and width of the container do not exist, or you wish the chart size not equal to the container, you can initialize the size at the beginning.

<div id="main"></div>
+<script type="text/javascript">
+  var myChart = echarts.init(document.getElementById('main'), null, {
+    width: 600,
+    height: 400
+  });
+</script>

Reactive of the Container Size

Listen to the Container Size to Change the Chart Size

In some cases, we want to accordingly change the chart size while the size of containers changed.

For instance, the container has a height of 400px and a width of 100% site width. If you are willing to change the site width while stable the chart width as 100% of it, try the following method.

You can listen to resize of the site to catch the event that the browser is resized. Then use echartsInstance.resize to resize the chart.

<style>
+  #main,
+  html,
+  body {
+    width: 100%;
+  }
+  #main {
+    height: 400px;
+  }
+</style>
+<div id="main"></div>
+<script type="text/javascript">
+  var myChart = echarts.init(document.getElementById('main'));
+  window.addEventListener('resize', function() {
+    myChart.resize();
+  });
+</script>

Tips:Sometimes we may adjust the container size by JS/CSS, but this doesn't change the page size so that the resize event won't be triggered. You can try the ResizeObserver API to cover this scenario.

State a Specific Chart Size

Except for calling resize() without parameters, you can state the height and width to implement the chart size different from the size of the container.

myChart.resize({
+  width: 800,
+  height: 400
+});

Tips: Pay attention to how the API defined while reading the documentation. resize() API was sometimes mistaken for the form like myCharts.resize(800, 400) which do not exist.

Dispose and Rebuild of the Container Node

We assume that there exist several bookmark pages and each page contained some charts. In this case, the content in other pages will be removed in DOM when select one page. The user will not find the chart after reselecting these pages.

Essentially, this is because the container node of the charts was removed. Even if the node is added again later, the node where the graph is located no longer exists.

The correct way is, call echartsInstance.dispose to dispose the instance after the container was disposed, and call echarts.init to initialize after the container was added again.

Tips: Call echartsInstance.dispose to release resources while disposing the node to avoid memory leaks.

Contributors Edit this page on GitHub

pissang pissangplainheart plainheartppd0705 ppd0705
+ + + + + diff --git a/docs/en/concepts/data-transform/index.html b/docs/en/concepts/data-transform/index.html new file mode 100644 index 000000000..85145cd79 --- /dev/null +++ b/docs/en/concepts/data-transform/index.html @@ -0,0 +1,612 @@ + + + + + + + Data Transform - Concepts - Handbook - Apache ECharts + + +

Data Transform

Data transform has been supported since Apache EChartsTM 5. In echarts, the term data transform means that generate new data from user provided source data and transform functions. both This feature is enable users to process data in declarative way, and provides users some common "transform functions" to make that kind of tasks "out-of-the-box". (For consistency in the context, the noun form of the word we keep using the "transform" rather than "transformation").

The abstract formula of data transform is: outData = f(inputData), where the transform function f can be like filter, sort, regression, boxplot, cluster, aggregate(todo) ... +With the help of those transform methods, users can be implements the features like:

  • Partition data into multiple series.
  • Make some statistics and visualize the result.
  • Adapt some visualization algorithms to data and display the result.
  • Sort data.
  • Remove or choose some kind of empty or special datums.
  • ...

Get Started to Data Transform

In echarts, data transform is implemented based on the concept of dataset. A dataset.transform can be configured in a dataset instance to indicate that this dataset is to be generated from this transform. For example:

var option = {
+  dataset: [
+    {
+      // This dataset is on `datasetIndex: 0`.
+      source: [
+        ['Product', 'Sales', 'Price', 'Year'],
+        ['Cake', 123, 32, 2011],
+        ['Cereal', 231, 14, 2011],
+        ['Tofu', 235, 5, 2011],
+        ['Dumpling', 341, 25, 2011],
+        ['Biscuit', 122, 29, 2011],
+        ['Cake', 143, 30, 2012],
+        ['Cereal', 201, 19, 2012],
+        ['Tofu', 255, 7, 2012],
+        ['Dumpling', 241, 27, 2012],
+        ['Biscuit', 102, 34, 2012],
+        ['Cake', 153, 28, 2013],
+        ['Cereal', 181, 21, 2013],
+        ['Tofu', 395, 4, 2013],
+        ['Dumpling', 281, 31, 2013],
+        ['Biscuit', 92, 39, 2013],
+        ['Cake', 223, 29, 2014],
+        ['Cereal', 211, 17, 2014],
+        ['Tofu', 345, 3, 2014],
+        ['Dumpling', 211, 35, 2014],
+        ['Biscuit', 72, 24, 2014]
+      ]
+      // id: 'a'
+    },
+    {
+      // This dataset is on `datasetIndex: 1`.
+      // A `transform` is configured to indicate that the
+      // final data of this dataset is transformed via this
+      // transform function.
+      transform: {
+        type: 'filter',
+        config: { dimension: 'Year', value: 2011 }
+      }
+      // There can be optional properties `fromDatasetIndex` or `fromDatasetId`
+      // to indicate that where is the input data of the transform from.
+      // For example, `fromDatasetIndex: 0` specify the input data is from
+      // the dataset on `datasetIndex: 0`, or `fromDatasetId: 'a'` specify the
+      // input data is from the dataset having `id: 'a'`.
+      // [DEFAULT_RULE]
+      // If both `fromDatasetIndex` and `fromDatasetId` are omitted,
+      // `fromDatasetIndex: 0` are used by default.
+    },
+    {
+      // This dataset is on `datasetIndex: 2`.
+      // Similarly, if neither `fromDatasetIndex` nor `fromDatasetId` is
+      // specified, `fromDatasetIndex: 0` is used by default
+      transform: {
+        // The "filter" transform filters and gets data items only match
+        // the given condition in property `config`.
+        type: 'filter',
+        // Transforms has a property `config`. In this "filter" transform,
+        // the `config` specify the condition that each result data item
+        // should be satisfied. In this case, this transform get all of
+        // the data items that the value on dimension "Year" equals to 2012.
+        config: { dimension: 'Year', value: 2012 }
+      }
+    },
+    {
+      // This dataset is on `datasetIndex: 3`
+      transform: {
+        type: 'filter',
+        config: { dimension: 'Year', value: 2013 }
+      }
+    }
+  ],
+  series: [
+    {
+      type: 'pie',
+      radius: 50,
+      center: ['25%', '50%'],
+      // In this case, each "pie" series reference to a dataset that has
+      // the result of its "filter" transform.
+      datasetIndex: 1
+    },
+    {
+      type: 'pie',
+      radius: 50,
+      center: ['50%', '50%'],
+      datasetIndex: 2
+    },
+    {
+      type: 'pie',
+      radius: 50,
+      center: ['75%', '50%'],
+      datasetIndex: 3
+    }
+  ]
+};
live

Let's summarize the key points of using data transform:

  • Generate new data from existing declared data via the declaration of transform, fromDatasetIndex/fromDatasetId in some blank dataset.
  • Series references these datasets to show the result.

Advanced Usage

Piped Transform

There is a syntactic sugar that pipe transforms like:

option = {
+  dataset: [
+    {
+      source: [] // The original data
+    },
+    {
+      // Declare transforms in an array to pipe multiple transforms,
+      // which makes them execute one by one and take the output of
+      // the previous transform as the input of the next transform.
+      transform: [
+        {
+          type: 'filter',
+          config: { dimension: 'Product', value: 'Tofu' }
+        },
+        {
+          type: 'sort',
+          config: { dimension: 'Year', order: 'desc' }
+        }
+      ]
+    }
+  ],
+  series: {
+    type: 'pie',
+    // Display the result of the piped transform.
+    datasetIndex: 1
+  }
+};

Note: theoretically any type of transform is able to have multiple input data and multiple output data. But when a transform is piped, it is only able to take one input (except it is the first transform of the pipe) and product one output (except it is the last transform of the pipe).

Output Multiple Data

In most cases, transform functions only need to produce one data. But there is indeed scenarios that a transform function needs to produce multiple data, each of whom might be used by different series.

For example, in the built-in boxplot transform, besides boxplot data produced, the outlier data are also produced, which can be used in a scatter series. See the example.

We use prop dataset.fromTransformResult to satisfy this requirement. For example:

option = {
+  dataset: [
+    {
+      // Original source data.
+      source: []
+    },
+    {
+      transform: {
+        type: 'boxplot'
+      }
+      // After this "boxplot transform" two result data generated:
+      // result[0]: The boxplot data
+      // result[1]: The outlier data
+      // By default, when series or other dataset reference this dataset,
+      // only result[0] can be visited.
+      // If we need to visit result[1], we have to use another dataset
+      // as follows:
+    },
+    {
+      // This extra dataset references the dataset above, and retrieves
+      // the result[1] as its own data. Thus series or other dataset can
+      // reference this dataset to get the data from result[1].
+      fromDatasetIndex: 1,
+      fromTransformResult: 1
+    }
+  ],
+  xAxis: {
+    type: 'category'
+  },
+  yAxis: {},
+  series: [
+    {
+      name: 'boxplot',
+      type: 'boxplot',
+      // Reference the data from result[0].
+      datasetIndex: 1
+    },
+    {
+      name: 'outlier',
+      type: 'scatter',
+      // Reference the data from result[1].
+      datasetIndex: 2
+    }
+  ]
+};

What more, dataset.fromTransformResult and dataset.transform can both appear in one dataset, which means that the input of the transform is from retrieved from the upstream result specified by fromTransformResult. For example:

{
+  fromDatasetIndex: 1,
+  fromTransformResult: 1,
+  transform: {
+    type: 'sort',
+    config: { dimension: 2, order: 'desc' }
+  }
+}

Debug in Develop Environment

When using data transform, we might run into the trouble that the final chart do not display correctly but we do not know where the config is wrong. There is a property transform.print might help in such case. (transform.print is only available in dev environment).

option = {
+  dataset: [
+    {
+      source: []
+    },
+    {
+      transform: {
+        type: 'filter',
+        config: {},
+        // The result of this transform will be printed
+        // in dev tool via `console.log`.
+        print: true
+      }
+    }
+  ]
+};

Filter Transform

Transform type "filter" is a built-in transform that provide data filter according to specified conditions. The basic option is like:

option = {
+  dataset: [
+    {
+      source: [
+        ['Product', 'Sales', 'Price', 'Year'],
+        ['Cake', 123, 32, 2011],
+        ['Latte', 231, 14, 2011],
+        ['Tofu', 235, 5, 2011],
+        ['Milk Tee', 341, 25, 2011],
+        ['Porridge', 122, 29, 2011],
+        ['Cake', 143, 30, 2012],
+        ['Latte', 201, 19, 2012],
+        ['Tofu', 255, 7, 2012],
+        ['Milk Tee', 241, 27, 2012],
+        ['Porridge', 102, 34, 2012],
+        ['Cake', 153, 28, 2013],
+        ['Latte', 181, 21, 2013],
+        ['Tofu', 395, 4, 2013],
+        ['Milk Tee', 281, 31, 2013],
+        ['Porridge', 92, 39, 2013],
+        ['Cake', 223, 29, 2014],
+        ['Latte', 211, 17, 2014],
+        ['Tofu', 345, 3, 2014],
+        ['Milk Tee', 211, 35, 2014],
+        ['Porridge', 72, 24, 2014]
+      ]
+    },
+    {
+      transform: {
+        type: 'filter',
+        config: { dimension: 'Year', '=': 2011 }
+        // The config is the "condition" of this filter.
+        // This transform traverse the source data and
+        // and retrieve all the items that the "Year"
+        // is `2011`.
+      }
+    }
+  ],
+  series: {
+    type: 'pie',
+    datasetIndex: 1
+  }
+};
live

This is another example of filter transform:

About dimension:

The config.dimension can be:

  • Dimension name declared in dataset, like config: { dimension: 'Year', '=': 2011 }. Dimension name declaration is not mandatory.
  • Dimension index (start from 0), like config: { dimension: 3, '=': 2011 }.

About relational operator:

The relational operator can be: +>(gt), >=(gte), <(lt), <=(lte), =(eq), !=(ne, <>), reg. (The name in the parentheses are aliases). They follows the common semantics. +Besides the common number comparison, there is some extra features:

  • Multiple operators are able to appear in one {} item like { dimension: 'Price', '>=': 20, '<': 30 }, which means logical "and" (Price >= 20 and Price < 30).
  • The data value can be "numeric string". Numeric string is a string that can be converted to number. Like ' 123 '. White spaces and line breaks will be auto trimmed in the conversion.
  • If we need to compare "JS Date instance" or date string (like '2012-05-12'), we need to specify parser: 'time' manually, like config: { dimension: 3, lt: '2012-05-12', parser: 'time' }.
  • Pure string comparison is supported but can only be used in =, !=. >, >=, <, <= do not support pure string comparison (the "right value" of the four operators can not be a "string").
  • The operator reg can be used to make regular expression test. Like using { dimension: 'Name', reg: /\s+Müller\s*$/ } to select all data items that the "Name" dimension contains family name Müller.

About logical relationship:

Sometimes we also need to express logical relationship ( and / or / not ):

option = {
+  dataset: [
+    {
+      source: [
+        // ...
+      ]
+    },
+    {
+      transform: {
+        type: 'filter',
+        config: {
+          // Use operator "and".
+          // Similarly, we can also use "or", "not" in the same place.
+          // But "not" should be followed with a {...} rather than `[...]`.
+          and: [
+            { dimension: 'Year', '=': 2011 },
+            { dimension: 'Price', '>=': 20, '<': 30 }
+          ]
+        }
+        // The condition is "Year" is 2011 and "Price" is greater
+        // or equal to 20 but less than 30.
+      }
+    }
+  ],
+  series: {
+    type: 'pie',
+    datasetIndex: 1
+  }
+};

and/or/not can be nested like:

transform: {
+  type: 'filter',
+  config: {
+    or: [{
+      and: [{
+        dimension: 'Price', '>=': 10, '<': 20
+      }, {
+        dimension: 'Sales', '<': 100
+      }, {
+        not: { dimension: 'Product', '=': 'Tofu' }
+      }]
+    }, {
+      and: [{
+        dimension: 'Price', '>=': 10, '<': 20
+      }, {
+        dimension: 'Sales', '<': 100
+      }, {
+        not: { dimension: 'Product', '=': 'Cake' }
+      }]
+    }]
+  }
+}

About parser:

Some "parser" can be specified when make value comparison. At present only supported:

  • parser: 'time': Parse the value to date time before comparing. The parser rule is the same as echarts.time.parse, where JS Date instance, timestamp number (in millisecond) and time string (like '2012-05-12 03:11:22') are supported to be parse to timestamp number, while other value will be parsed to NaN.
  • parser: 'trim': Trim the string before making comparison. For non-string, return the original value.
  • parser: 'number': Force to convert the value to number before making comparison. If not possible to be converted to a meaningful number, converted to NaN. In most cases it is not necessary, because by default the value will be auto converted to number if possible before making comparison. But the default conversion is strict while this parser provide a loose strategy. If we meet the case that number string with unit suffix (like '33%', 12px), we should use parser: 'number' to convert them to number before making comparison.

This is an example to show the parser: 'time':

option = {
+  dataset: [
+    {
+      source: [
+        ['Product', 'Sales', 'Price', 'Date'],
+        ['Milk Tee', 311, 21, '2012-05-12'],
+        ['Cake', 135, 28, '2012-05-22'],
+        ['Latte', 262, 36, '2012-06-02'],
+        ['Milk Tee', 359, 21, '2012-06-22'],
+        ['Cake', 121, 28, '2012-07-02'],
+        ['Latte', 271, 36, '2012-06-22']
+        // ...
+      ]
+    },
+    {
+      transform: {
+        type: 'filter',
+        config: {
+          dimension: 'Date',
+          '>=': '2012-05',
+          '<': '2012-06',
+          parser: 'time'
+        }
+      }
+    }
+  ]
+};

Formally definition:

Finally, we give the formally definition of the filter transform config here:

type FilterTransform = {
+  type: 'filter';
+  config: ConditionalExpressionOption;
+};
+type ConditionalExpressionOption =
+  | true
+  | false
+  | RelationalExpressionOption
+  | LogicalExpressionOption;
+type RelationalExpressionOption = {
+  dimension: DimensionName | DimensionIndex;
+  parser?: 'time' | 'trim' | 'number';
+  lt?: DataValue; // less than
+  lte?: DataValue; // less than or equal
+  gt?: DataValue; // greater than
+  gte?: DataValue; // greater than or equal
+  eq?: DataValue; // equal
+  ne?: DataValue; // not equal
+  '<'?: DataValue; // lt
+  '<='?: DataValue; // lte
+  '>'?: DataValue; // gt
+  '>='?: DataValue; // gte
+  '='?: DataValue; // eq
+  '!='?: DataValue; // ne
+  '<>'?: DataValue; // ne (SQL style)
+  reg?: RegExp | string; // RegExp
+};
+type LogicalExpressionOption = {
+  and?: ConditionalExpressionOption[];
+  or?: ConditionalExpressionOption[];
+  not?: ConditionalExpressionOption;
+};
+type DataValue = string | number | Date;
+type DimensionName = string;
+type DimensionIndex = number;

Note that when using Minimal Bundle, if you need to use this built-in transform, besides the Dataset component, it's required to import the Transform component.

import {
+  DatasetComponent,
+  TransformComponent
+} from 'echarts/components';
+
+echarts.use([
+  DatasetComponent,
+  TransformComponent
+]);

Sort Transform

Another built-in transform is "sort".

option = {
+  dataset: [
+    {
+      dimensions: ['name', 'age', 'profession', 'score', 'date'],
+      source: [
+        [' Hannah Krause ', 41, 'Engineer', 314, '2011-02-12'],
+        ['Zhao Qian ', 20, 'Teacher', 351, '2011-03-01'],
+        [' Jasmin Krause ', 52, 'Musician', 287, '2011-02-14'],
+        ['Li Lei', 37, 'Teacher', 219, '2011-02-18'],
+        [' Karle Neumann ', 25, 'Engineer', 253, '2011-04-02'],
+        [' Adrian Groß', 19, 'Teacher', null, '2011-01-16'],
+        ['Mia Neumann', 71, 'Engineer', 165, '2011-03-19'],
+        [' Böhm Fuchs', 36, 'Musician', 318, '2011-02-24'],
+        ['Han Meimei ', 67, 'Engineer', 366, '2011-03-12']
+      ]
+    },
+    {
+      transform: {
+        type: 'sort',
+        // Sort by score.
+        config: { dimension: 'score', order: 'asc' }
+      }
+    }
+  ],
+  series: {
+    type: 'bar',
+    datasetIndex: 1
+  }
+  // ...
+};

Some extra features about "sort transform":

  • Order by multiple dimensions is supported. See examples below.
  • The sort rule: +
    • By default "numeric" (that is, number and numeric-string like ' 123 ') are able to sorted by numeric order.
    • Otherwise "non-numeric-string" are also able to be ordered among themselves. This might help to the case like grouping data items with the same tag, especially when multiple dimensions participated in the sort (See example below).
    • When "numeric" is compared with "non-numeric-string", or either of them is compared with other types of value, they are not comparable. So we call the latter one as "incomparable" and treat it as "min value" or "max value" according to the prop incomparable: 'min' | 'max'. This feature usually helps to decide whether to put the empty values (like null, undefined, NaN, '', '-') or other illegal values to the head or tail.
  • parser: 'time' | 'trim' | 'number' can be used, the same as "filter transform". +
    • If intending to sort time values (JS Date instance or time string like '2012-03-12 11:13:54'), parser: 'time' should be specified. Like config: { dimension: 'date', order: 'desc', parser: 'time' }
    • If intending to sort values with unit suffix (like '33%', '16px'), need to use parser: 'number'.

See an example of multiple order:

option = {
+  dataset: [
+    {
+      dimensions: ['name', 'age', 'profession', 'score', 'date'],
+      source: [
+        [' Hannah Krause ', 41, 'Engineer', 314, '2011-02-12'],
+        ['Zhao Qian ', 20, 'Teacher', 351, '2011-03-01'],
+        [' Jasmin Krause ', 52, 'Musician', 287, '2011-02-14'],
+        ['Li Lei', 37, 'Teacher', 219, '2011-02-18'],
+        [' Karle Neumann ', 25, 'Engineer', 253, '2011-04-02'],
+        [' Adrian Groß', 19, 'Teacher', null, '2011-01-16'],
+        ['Mia Neumann', 71, 'Engineer', 165, '2011-03-19'],
+        [' Böhm Fuchs', 36, 'Musician', 318, '2011-02-24'],
+        ['Han Meimei ', 67, 'Engineer', 366, '2011-03-12']
+      ]
+    },
+    {
+      transform: {
+        type: 'sort',
+        config: [
+          // Sort by the two dimensions.
+          { dimension: 'profession', order: 'desc' },
+          { dimension: 'score', order: 'desc' }
+        ]
+      }
+    }
+  ],
+  series: {
+    type: 'bar',
+    datasetIndex: 1
+  }
+  // ...
+};

Finally, we give the formally definition of the sort transform config here:

type SortTransform = {
+  type: 'sort';
+  config: OrderExpression | OrderExpression[];
+};
+type OrderExpression = {
+  dimension: DimensionName | DimensionIndex;
+  order: 'asc' | 'desc';
+  incomparable?: 'min' | 'max';
+  parser?: 'time' | 'trim' | 'number';
+};
+type DimensionName = string;
+type DimensionIndex = number;

Note that when using Minimal Bundle, if you need to use this built-in transform, besides the Dataset component, it's required to import the Transform component.

import {
+  DatasetComponent,
+  TransformComponent
+} from 'echarts/components';
+
+echarts.use([
+  DatasetComponent,
+  TransformComponent
+]);

Use External Transforms

Besides built-in transforms (like 'filter', 'sort'), we can also use external transforms to provide more powerful functionalities. Here we use a third-party library ecStat as an example:

This case show how to make a regression line via ecStat:

// Register the external transform at first.
+echarts.registerTransform(ecStatTransform(ecStat).regression);
option = {
+  dataset: [
+    {
+      source: rawData
+    },
+    {
+      transform: {
+        // Reference the registered external transform.
+        // Note that external transform has a namespace (like 'ecStat:xxx'
+        // has namespace 'ecStat').
+        // built-in transform (like 'filter', 'sort') does not have a namespace.
+        type: 'ecStat:regression',
+        config: {
+          // Parameters needed by the external transform.
+          method: 'exponential'
+        }
+      }
+    }
+  ],
+  xAxis: { type: 'category' },
+  yAxis: {},
+  series: [
+    {
+      name: 'scatter',
+      type: 'scatter',
+      datasetIndex: 0
+    },
+    {
+      name: 'regression',
+      type: 'line',
+      symbol: 'none',
+      datasetIndex: 1
+    }
+  ]
+};

Examples with echarts-stat:

Contributors Edit this page on GitHub

plainheart plainheart100pah 100pahpissang pissangshangchen0531 shangchen0531
+ + + + + diff --git a/docs/en/concepts/dataset/index.html b/docs/en/concepts/dataset/index.html new file mode 100644 index 000000000..fb4cd158a --- /dev/null +++ b/docs/en/concepts/dataset/index.html @@ -0,0 +1,485 @@ + + + + + + + Dataset - Concepts - Handbook - Apache ECharts + + +

Dataset

dataset is a component dedicated to manage data. Although you can set the data in series.data for every series, we recommend you use the dataset to manage the data since ECharts 4 so that the data can be reused by multiple components and convenient for the separation of "data and configs". After all, data is the most common part to be changed while other configurations will mostly not change at runtime.

Define data under series

If data is defined under series, for example:

option = {
+  xAxis: {
+    type: 'category',
+    data: ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      name: '2015',
+      data: [89.3, 92.1, 94.4, 85.4]
+    },
+    {
+      type: 'bar',
+      name: '2016',
+      data: [95.8, 89.4, 91.2, 76.9]
+    },
+    {
+      type: 'bar',
+      name: '2017',
+      data: [97.7, 83.1, 92.5, 78.1]
+    }
+  ]
+};
live

Defining data under series is suitable for customization for some special data structures such as "tree", "graph" and large data. +However, it is not conducive to the data sharing for multiple series as well as mapping arrangement of chart types and series based on the original data. The other disadvantage is that programmers always need to divide the data in separate series (and categories) first.

Define data in dataset

Here are the advantages if you define data in dataset:

  • Follow the ideas of data visualization: (I) Provide the data, (II)Mapping from data to visual to become a chart.
  • Divide data from other configurations. The data often change but others not. It is +Easy to manage separately.
  • Data can be reused by several series or component, you don't need to create copies of a large amount of data for every series.
  • Support more common data format, such as a 2D array, array of classes, etc., to avoid users from converting for data format to a certain extent.

Here is a simple dataset example:

option = {
+  legend: {},
+  tooltip: {},
+  dataset: {
+    // Provide a set of data.
+    source: [
+      ['product', '2015', '2016', '2017'],
+      ['Matcha Latte', 43.3, 85.8, 93.7],
+      ['Milk Tea', 83.1, 73.4, 55.1],
+      ['Cheese Cocoa', 86.4, 65.2, 82.5],
+      ['Walnut Brownie', 72.4, 53.9, 39.1]
+    ]
+  },
+  // Declare an x-axis (category axis).
+  // The category map the first column in the dataset by default.
+  xAxis: { type: 'category' },
+  // Declare a y-axis (value axis).
+  yAxis: {},
+  // Declare several 'bar' series,
+  // every series will auto-map to each column by default.
+  series: [{ type: 'bar' }, { type: 'bar' }, { type: 'bar' }]
+};
live

Or try to use the "array of classes" format:

option = {
+  legend: {},
+  tooltip: {},
+  dataset: {
+    // Define the dimension of array. In cartesian coordinate system,
+    // if the type of x-axis is category, map the first dimension to
+    // x-axis by default, the second dimension to y-axis.
+    // You can also specify 'series.encode' to complete the map
+    // without specify dimensions. Please see below.
+
+    dimensions: ['product', '2015', '2016', '2017'],
+    source: [
+      { product: 'Matcha Latte', '2015': 43.3, '2016': 85.8, '2017': 93.7 },
+      { product: 'Milk Tea', '2015': 83.1, '2016': 73.4, '2017': 55.1 },
+      { product: 'Cheese Cocoa', '2015': 86.4, '2016': 65.2, '2017': 82.5 },
+      { product: 'Walnut Brownie', '2015': 72.4, '2016': 53.9, '2017': 39.1 }
+    ]
+  },
+  xAxis: { type: 'category' },
+  yAxis: {},
+  series: [{ type: 'bar' }, { type: 'bar' }, { type: 'bar' }]
+};
live

Map from Data to Chart

The ideas of data visualization: (I) Provide the data, (II)Mapping from data to visual to become a chart.

In short, you can set these configs of mapping:

  • Specify 'column' or 'row' of dataset to map the series. You can use series.seriesLayoutBy to configure it. The default is to map according to the column.
  • Rule of specifying dimension mapping: how to mapping from dimensions of 'dataset' to axis, tooltip, label and visualMap. To configure the mapping, please use series.encode and visualMap. The previous case did not give the mapping configuration so that ECharts will follow the default: if x-axis is category, mapping to the first row in dataset.source; three-column chart mapping with each row in dataset.source one by one.

The details of the configuration are shown below:

Map Row or Column of dataset to series

Having the dataset, you can configure flexibly how the data map to the axis and series.

You can use seriesLayoutBy to change the understanding of row and column of the chart. seriesLayoutBy can be:

  • 'column': Default value. The series are placed above the column of dataset.
  • 'row': The series are placed above the row of dataset.

Check this case:

option = {
+  legend: {},
+  tooltip: {},
+  dataset: {
+    source: [
+      ['product', '2012', '2013', '2014', '2015'],
+      ['Matcha Latte', 41.1, 30.4, 65.1, 53.3],
+      ['Milk Tea', 86.5, 92.1, 85.7, 83.1],
+      ['Cheese Cocoa', 24.1, 67.2, 79.5, 86.4]
+    ]
+  },
+  xAxis: [
+    { type: 'category', gridIndex: 0 },
+    { type: 'category', gridIndex: 1 }
+  ],
+  yAxis: [{ gridIndex: 0 }, { gridIndex: 1 }],
+  grid: [{ bottom: '55%' }, { top: '55%' }],
+  series: [
+    // These series will show in the first coordinate, each series map a row in dataset.
+    { type: 'bar', seriesLayoutBy: 'row' },
+    { type: 'bar', seriesLayoutBy: 'row' },
+    { type: 'bar', seriesLayoutBy: 'row' },
+    // These series will show in the second coordinate, each series map a column in dataset.
+    { type: 'bar', xAxisIndex: 1, yAxisIndex: 1 },
+    { type: 'bar', xAxisIndex: 1, yAxisIndex: 1 },
+    { type: 'bar', xAxisIndex: 1, yAxisIndex: 1 },
+    { type: 'bar', xAxisIndex: 1, yAxisIndex: 1 }
+  ]
+};
live

The effect of configuration is shown in this case.

Dimension

Most of the data described in commonly used charts is a "two-dimensional table" structure, in the previous case, we use a 2D array to contain a two-dimensional table. Now, when we map a series to a column, that column was called a "dimension" and each row was called "item", vice versa.

The dimension can have their name to display in the chart. Dimension name can be defined in the first column (row). In the previous case, 'score', 'amount', 'product' are the name of dimensions. The actual data locate from the second row. ECharts will automatically check if the first column (row) contained dimension name in dataset.source. You can also use dataset.sourceHeader: true to declare that the first column (row) represents the dimension name.

Try to use single dataset.dimensions or some series.dimensions to define the dimensions, therefore you can specify the name and type together.

var option1 = {
+  dataset: {
+    dimensions: [
+      { name: 'score' },
+      // can be abbreviated as 'string', to indicate dimension name 。
+      'amount',
+      // Specify dimensions in 'type'.
+      { name: 'product', type: 'ordinal' }
+    ],
+    source: []
+  }
+  // ...
+};
+
+var option2 = {
+  dataset: {
+    source: []
+  },
+  series: {
+    type: 'line',
+    // series.dimensions will cover the config in dataset.dimension
+    dimensions: [
+      null, // use null if you do not want dimension name.
+      'amount',
+      { name: 'product', type: 'ordinal' }
+    ]
+  }
+  // ...
+};

In most cases, you don't need to define the dimension type because the ECharts will automatically judge it. If the judgment is inaccurate, you can define it manually.

Dimension type can be the following values:

  • 'number': Default, normal data.
  • 'ordinal': String types data like categories, text can be used on the axis only with the dimension type 'ordinal'. ECharts will try to judge this type automatically but might be inaccurate, so you can specify manually.
  • 'time': To represent time data, ECharts can automatically analyze data as timestamp if the dimension type is defined as 'time'. For instance, ECharts will auto-analyze if the data of this dimension is '2017-05-10'. If the dimension is used as time axis (axis.type = 'time'), the dimension type will also be 'time'. See data for more time type support.
  • 'float': Use TypedArray to optimize the performance in 'float' dimension.
  • 'int': Use TypedArray to optimize the performance in 'int' dimension.

Map from Data to Charts (series.encode)

After understand the concept of dimension, you can use series.encode to make a mapping:

var option = {
+  dataset: {
+    source: [
+      ['score', 'amount', 'product'],
+      [89.3, 58212, 'Matcha Latte'],
+      [57.1, 78254, 'Milk Tea'],
+      [74.4, 41032, 'Cheese Cocoa'],
+      [50.1, 12755, 'Cheese Brownie'],
+      [89.7, 20145, 'Matcha Cocoa'],
+      [68.1, 79146, 'Tea'],
+      [19.6, 91852, 'Orange Juice'],
+      [10.6, 101852, 'Lemon Juice'],
+      [32.7, 20112, 'Walnut Brownie']
+    ]
+  },
+  xAxis: {},
+  yAxis: { type: 'category' },
+  series: [
+    {
+      type: 'bar',
+      encode: {
+        // Map "amount" column to x-axis.
+        x: 'amount',
+        // Map "product" row to y-axis.
+        y: 'product'
+      }
+    }
+  ]
+};
live

The basic structure of series.encode declaration:

  • To the left of the colon: Specific name of axis or label.
  • To the right of the colon: Dimension name (string) or number(int, count from 0), to specify one or several dimensions (using array).

Generally, the following info is not necessary to be defined. Fill in as needed.

Attribute suggested by series.encode

// Supported in every coordinate and series:
+encode: {
+  // Display the value of dimension named "product" and "score" in tooltip.
+  tooltip: ['product', 'score']
+  // Connect dimension name of "Dimension 1" and "Dimension 3" as the series name. (Avoid to repeat longer names in series.name)
+  seriesName: [1, 3],
+  // Means to use the value in "Dimension 2" as the id. It makes the new and old data correspond by id
+	// when using setOption to update data, so that it can show animation properly.
+  itemId: 2,
+  // The itemName will show in the legend of Pie Charts.
+  itemName: 3
+}
+
+// Grid/cartesian coordinate unique configs:
+encode: {
+  // Map "Dimension 1", "Dimension 5" and "dimension named 'score'" to x-axis:
+  x: [1, 5, 'score'],
+  // Map "Dimension 0" to y-axis:
+  y: 0
+}
+
+// singleAxis unique configs:
+encode: {
+  single: 3
+}
+
+// Polar coordinate unique configs:
+encode: {
+  radius: 3,
+  angle: 2
+}
+
+// Geo-coordinate unique configs:
+encode: {
+  lng: 3,
+  lat: 2
+}
+
+// For some charts without coordinate like pie chart, funnel chart:
+encode: {
+  value: 3
+}

This is a richer example of series.encode.

Default series.encode

It is worth mentioning that ECharts will use some default mapping rules for some general charts (line, bar, scatter, candlestick, etc.) if series.encode is not specified. The default rule is:

  • In coordinate system (e.g. Cartesian, Polar): +
    • If there is category axis (axis.type = 'category'), map the first column(row) to the axis and each subsequent column(row) to each series.
    • If both axes is not the category, then map every two columns in one series to two axes.
  • Without axis (e.g. Pie Chart): +
    • Use the first column(row) as the name, second column(row) as value. ECharts will not set the name if there is only one column(row).

While the default rule cannot fulfill the requirements, you can configure encode by yourself, which is not complicate. Here is an example.

Some Normal Settings of series.encode

Q: How to set the 3rd column as x-axis, 5th column as y-axis?

A:

option = {
+  series: {
+    // dimensionIndex count from 0, so the 3rd line is dimensions[2].
+    encode: { x: 2, y: 4 }
+    // ...
+  }
+};

Q: How to set the 3rd row as x-axis, 5th row as y-axis?

A:

option = {
+  series: {
+    encode: { x: 2, y: 4 },
+    seriesLayoutBy: 'row'
+    // ...
+  }
+};

Q: How to set the 2nd column as a label?

A: +We now support to trace value from specific dimension for label.formatter:

series: {
+  label: {
+    // `'{@score}'` means the value in the dimension named "score".
+    // `'{@[4]}'` means the value in dimension 4.
+    formatter: 'aaa{@product}bbb{@score}ccc{@[4]}ddd';
+  }
+}

Q: How to show the 2nd and 3rd column in the tooltip?

A:

option = {
+  series: {
+    encode: {
+      tooltip: [1, 2]
+      // ...
+    }
+    // ...
+  }
+};

Q: How to define the dimension name if is not included in the dataset?

A:

var option = {
+  dataset: {
+    dimensions: ['score', 'amount'],
+    source: [
+      [89.3, 3371],
+      [92.1, 8123],
+      [94.4, 1954],
+      [85.4, 829]
+    ]
+  }
+};

Q: How to map the 3rd column to the size of the scatter chart?

A:

var option = {
+  dataset: {
+    source: [
+      [12, 323, 11.2],
+      [23, 167, 8.3],
+      [81, 284, 12],
+      [91, 413, 4.1],
+      [13, 287, 13.5]
+    ]
+  },
+  visualMap: {
+    show: false,
+    dimension: 2, // means the 3rd column
+    min: 2, // lower bound
+    max: 15, // higher bound
+    inRange: {
+      // Size of the bubble.
+      symbolSize: [5, 60]
+    }
+  },
+  xAxis: {},
+  yAxis: {},
+  series: {
+    type: 'scatter'
+  }
+};
live

Q: I specified a mapping in encode, why it is not worked?

A: Check your spelling, such as misspell the dimension name 'Life Expectancy' to 'Life Expectency' in encode.

Visual Channel Mapping

We can map visual channel by using visualMap. Check details in the visualMap document. Here is an example.

Formats of Charts

In most of the normal chart, the data is suitable to be described in the form of a two-dimensional table. That well-known software like 'MS Excel' and 'Numbers' all uses a two-dimensional table. Their data can be exported to JSON format and input to dataset.source and avoid some steps of data processing.

You can switch .csv file to JSON using tools like dsv or PapaParse.

As the example shown behind, in the data transmission of JavaScript, the two-dimensional data can be stored directly by two-dimensional array.

Expect from the two-dimensional array, the dataset also supports using key-value which is also a common way. However, we don't support seriesLayoutBy in this format right now.

dataset: [
+  {
+    // column by column key-value array is a normal format
+    source: [
+      { product: 'Matcha Latte', count: 823, score: 95.8 },
+      { product: 'Milk Tea', count: 235, score: 81.4 },
+      { product: 'Cheese Cocoa', count: 1042, score: 91.2 },
+      { product: 'Walnut Brownie', count: 988, score: 76.9 }
+    ]
+  },
+  {
+    // row by row key-value
+    source: {
+      product: ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie'],
+      count: [823, 235, 1042, 988],
+      score: [95.8, 81.4, 91.2, 76.9]
+    }
+  }
+];

How to Reference Several Datasets

ECharts support to define several datasets at the same moment. Series can assign the one to reference by series.datasetIndex. For example:

var option = {
+  dataset: [
+    {
+      // 1st Dataset
+      source: []
+    },
+    {
+      // 2nd Dataset
+      source: []
+    },
+    {
+      // 3rd Dataset。
+      source: []
+    }
+  ],
+  series: [
+    {
+      // Use 2nd dataset
+      datasetIndex: 1
+    },
+    {
+      // Use 1st dataset
+      datasetIndex: 0
+    }
+  ]
+};

series.data in ECharts 3

ECharts 4 still supports the data declaration way in ECharts 3. If the series has already declared the series.data, then use series.data but not dataset.

option = {
+  xAxis: {
+    type: 'category',
+    data: ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      name: '2015',
+      data: [89.3, 92.1, 94.4, 85.4]
+    },
+    {
+      type: 'bar',
+      name: '2016',
+      data: [95.8, 89.4, 91.2, 76.9]
+    },
+    {
+      type: 'bar',
+      name: '2017',
+      data: [97.7, 83.1, 92.5, 78.1]
+    }
+  ]
+};

In fact, series.data is an important setting method which will always exist. Some special non-table format chart like treemap, graph and lines still cannot be edit in dataset, you still need to use series.data. In another way, for render huge amount of data (over a million), you need to use appendData which is not supported by dataset.

Others

The following charts now support dataset: +line, bar, pie, scatter, effectScatter, parallel, candlestick, map, funnel, custom. +ECharts will support more charts in the future.

In the end, here is an example of several charts shared one dataset with linkage interaction.

Contributors Edit this page on GitHub

plainheart plainheartpissang pissangOvilia Ovilia100pah 100pahBruce20190410 Bruce20190410simonmcconnell simonmcconnell
+ + + + + diff --git a/docs/en/concepts/event/index.html b/docs/en/concepts/event/index.html new file mode 100644 index 000000000..3adec576a --- /dev/null +++ b/docs/en/concepts/event/index.html @@ -0,0 +1,323 @@ + + + + + + + Event and Action - Concepts - Handbook - Apache ECharts + + +

Event and Action

Users can trigger corresponding events by their operation. The developer can handle the callback function by listening to these events, such as jump to a new website, pop-up a dialog box, or drill down the data.

The name of the event and the DOM event is both lowercase string. Here is an example of binding listening to click event.

myChart.on('click', function(params) {
+  // Print name in console
+  console.log(params.name);
+});

There are two kinds of event in ECharts, one happened when the user clicks the mouse or hover the elements in charts, the other happened while the user triggered some interactive actions. Such as 'legendselectchanged' triggered while changing the legend selected (please notice that legendselected won't be triggered in this situation), 'datazoom' triggered while zooming the data area.

Handling the Mouse Events

ECharts support general mouse events: 'click', 'dblclick', 'mousedown', 'mousemove', 'mouseup', 'mouseover', 'mouseout', 'globalout', 'contextmenu'. This is an example of opening the search result page after clicking the bar chart.

// Init the ECharts base on DOM
+var myChart = echarts.init(document.getElementById('main'));
+
+// Config
+var option = {
+  xAxis: {
+    data: [
+      'Shirt',
+      'Wool sweater',
+      'Chiffon shirt',
+      'Pants',
+      'High-heeled shoes',
+      'socks'
+    ]
+  },
+  yAxis: {},
+  series: [
+    {
+      name: 'Sales',
+      type: 'bar',
+      data: [5, 20, 36, 10, 10, 20]
+    }
+  ]
+};
+// Use the option and data to display the chart
+myChart.setOption(option);
+// Click and jump to Baidu search website
+myChart.on('click', function(params) {
+  window.open(
+    'https://www.google.com/search?q=' + encodeURIComponent(params.name)
+  );
+});

All mouse events included params which contained the data of the object.

Format:

type EventParams = {
+  // The component name clicked,
+  // component type, could be 'series'、'markLine'、'markPoint'、'timeLine', etc..
+  componentType: string,
+  // series type, could be 'line'、'bar'、'pie', etc.. Works when componentType is 'series'.
+  seriesType: string,
+  // the index in option.series. Works when componentType is 'series'.
+  seriesIndex: number,
+  // series name, works when componentType is 'series'.
+  seriesName: string,
+  // name of data (categories).
+  name: string,
+  // the index in 'data' array.
+  dataIndex: number,
+  // incoming raw data item
+  data: Object,
+  // charts like 'sankey' and 'graph' included nodeData and edgeData as the same time.
+  // dataType can be 'node' or 'edge', indicates whether the current click is on node or edge.
+  // most of charts have one kind of data, the dataType is meaningless
+  dataType: string,
+  // incoming data value
+  value: number | Array,
+  // color of the shape, works when componentType is 'series'.
+  color: string
+};

Identify where the mouse clicked.

myChart.on('click', function(params) {
+  if (params.componentType === 'markPoint') {
+    // Clicked on the markPoint
+    if (params.seriesIndex === 5) {
+      // clicked on the markPoint of the series with index = 5
+    }
+  } else if (params.componentType === 'series') {
+    if (params.seriesType === 'graph') {
+      if (params.dataType === 'edge') {
+        // clicked at the edge of graph.
+      } else {
+        // clicked at the node of graph.
+      }
+    }
+  }
+});

Use query to trigger callback of the specified component:

chart.on(eventName, query, handler);

query can be string or Object.

If it is string, the format can be mainType or mainType.subType, such as:

chart.on('click', 'series', function () {...});
+chart.on('click', 'series.line', function () {...});
+chart.on('click', 'dataZoom', function () {...});
+chart.on('click', 'xAxis.category', function () {...});

If it is Object, query can include more than one attribute:

{
+  ${mainType}Index: number // component index
+  ${mainType}Name: string // component name
+  ${mainType}Id: string // component id
+  dataIndex: number // data item index
+  name: string // data item name
+  dataType: string // date item type, such as 'node', 'edge'
+  element: string // name of element in custom series.
+}

Such as:

chart.setOption({
+  // ...
+  series: [
+    {
+      name: 'uuu'
+      // ...
+    }
+  ]
+});
+chart.on('mouseover', { seriesName: 'uuu' }, function() {
+  // when elements in series named 'uuu' triggered 'mouseover'
+});

For example:

chart.setOption({
+  // ...
+  series: [
+    {
+      // ...
+    },
+    {
+      // ...
+      data: [
+        { name: 'xx', value: 121 },
+        { name: 'yy', value: 33 }
+      ]
+    }
+  ]
+});
+chart.on('mouseover', { seriesIndex: 1, name: 'xx' }, function() {
+  // when data named 'xx' in series index 1 triggered 'mouseover'.
+});

For example:

chart.setOption({
+  // ...
+  series: [
+    {
+      type: 'graph',
+      nodes: [
+        { name: 'a', value: 10 },
+        { name: 'b', value: 20 }
+      ],
+      edges: [{ source: 0, target: 1 }]
+    }
+  ]
+});
+chart.on('click', { dataType: 'node' }, function() {
+  // call this method while the node of graph was clicked.
+});
+chart.on('click', { dataType: 'edge' }, function() {
+  // call this method while the edge of graph was clicked.
+});

For example:

chart.setOption({
+  // ...
+  series: {
+    // ...
+    type: 'custom',
+    renderItem: function(params, api) {
+      return {
+        type: 'group',
+        children: [
+          {
+            type: 'circle',
+            name: 'my_el'
+            // ...
+          },
+          {
+            // ...
+          }
+        ]
+      };
+    },
+    data: [[12, 33]]
+  }
+});
+chart.on('mouseup', { element: 'my_el' }, function() {
+  // when data named 'my_el' triggered 'mouseup'.
+});

You can display a popup, update the charts using the query result from your database by the data name or series name in the callback function. Here is an example:

myChart.on('click', function(parmas) {
+  $.get('detail?q=' + params.name, function(detail) {
+    myChart.setOption({
+      series: [
+        {
+          name: 'pie',
+          // using pie chart to show the data distribution in one column.
+          data: [detail.data]
+        }
+      ]
+    });
+  });
+});

Event of Component Interaction

All Component Interaction in ECharts will trigger a corresponding event. Normal events and parameters are listed in the events document.

Here is an example of listening to legend event:

// Show/hide the legend only trigger legendselectchanged event
+myChart.on('legendselectchanged', function(params) {
+  // State if legend is selected.
+  var isSelected = params.selected[params.name];
+  // print in the console.
+  console.log(
+    (isSelected ? 'Selected' : 'Not Selected') + 'legend' + params.name
+  );
+  // print for all legends.
+  console.log(params.selected);
+});

Writing Code to Trigger Component Action Manually

You can trigger events such as 'legendselectchanged' not only by the user but also with code manually. It can be used to display the tooltip, select the legend.

In ECharts myChart.dispatchAction({ type: '' }) is used to trigger the behavior. This manages all actions and can record the behaviors conveniently.

Commonly used behavior and corresponding parameters are listed in action.

The following example shows how to highlight each sector one by one in the pie chart using dispatchAction.

option = {
+  tooltip: {
+    trigger: 'item',
+    formatter: '{a} <br/>{b} : {c} ({d}%)'
+  },
+  legend: {
+    orient: 'vertical',
+    left: 'left',
+    data: [
+      'Direct Access',
+      'Email Marketing',
+      'Affiliate Ads',
+      'Video Ads',
+      'Search Engines'
+    ]
+  },
+  series: [
+    {
+      name: 'Access Source',
+      type: 'pie',
+      radius: '55%',
+      center: ['50%', '60%'],
+      data: [
+        { value: 335, name: 'Direct Access' },
+        { value: 310, name: 'Email Marketing' },
+        { value: 234, name: 'Affiliate Ads' },
+        { value: 135, name: 'Video Ads' },
+        { value: 1548, name: 'Search Engines' }
+      ],
+      emphasis: {
+        itemStyle: {
+          shadowBlur: 10,
+          shadowOffsetX: 0,
+          shadowColor: 'rgba(0, 0, 0, 0.5)'
+        }
+      }
+    }
+  ]
+};
+
+let currentIndex = -1;
+
+setInterval(function() {
+  var dataLen = option.series[0].data.length;
+  myChart.dispatchAction({
+    type: 'downplay',
+    seriesIndex: 0,
+    dataIndex: currentIndex
+  });
+  currentIndex = (currentIndex + 1) % dataLen;
+  myChart.dispatchAction({
+    type: 'highlight',
+    seriesIndex: 0,
+    dataIndex: currentIndex
+  });
+  myChart.dispatchAction({
+    type: 'showTip',
+    seriesIndex: 0,
+    dataIndex: currentIndex
+  });
+}, 1000);
live

Listen to Events on the Blank Area

Sometimes developers need to listen to the events that are triggered from the blank of the canvas. For example, need to reset the chart when users click on the blank area.

Before we talk about this feature, we need to clarify two kinds of events: zrender events and echarts events.

myChart.getZr().on('click', function(event) {
+  // This listener is listening to a `zrender event`.
+});
+myChart.on('click', function(event) {
+  // This listener is listening to a `echarts event`.
+});

zrender events are different from echarts events. The former one are triggered when mouse/pointer is at everywhere, while the latter one can only be triggered when mouse/pointer is at the graphic elements. In fact, echarts events are implemented based on zrender events, that is, when a zrender events is triggered at a graphic element, echarts will trigger a echarts event.

Having zrender events, we can implement listen to events from the blank as follows:

myChart.getZr().on('click', function(event) {
+  // No "target" means that mouse/pointer is not on
+  // any of the graphic elements, which is "blank".
+  if (!event.target) {
+    // Click on blank. Do something.
+  }
+});

Contributors Edit this page on GitHub

pissang pissangOvilia Ovilia100pah 100pah
+ + + + + diff --git a/docs/en/concepts/legend/index.html b/docs/en/concepts/legend/index.html new file mode 100644 index 000000000..1b655b73b --- /dev/null +++ b/docs/en/concepts/legend/index.html @@ -0,0 +1,126 @@ + + + + + + + Legend - Concepts - Handbook - Apache ECharts + + +

Legend

Legends are used to annotate the content in the chart using different colors, shapes and texts to indicate different categories. By clicking the legends, the user can show or hide the corresponding categories. Legend is one of the key to understand the chart.

Layout

Legend is always placed at the upper right corner of the chart. All legends in the same page need to be consistent, align horizontally or vertically by considering the layout of the overall chart space. When the chart has little vertical space or the content area is crowded, it is also a good choice to put the legend on the bottom of the chart. Here are some layouts of legend:

option = {
+  legend: {
+    // Try 'horizontal'
+    orient: 'vertical',
+    right: 10,
+    top: 'center'
+  },
+  dataset: {
+    source: [
+      ['product', '2015', '2016', '2017'],
+      ['Matcha Latte', 43.3, 85.8, 93.7],
+      ['Milk Tea', 83.1, 73.4, 55.1],
+      ['Cheese Cocoa', 86.4, 65.2, 82.5],
+      ['Walnut Brownie', 72.4, 53.9, 39.1]
+    ]
+  },
+  xAxis: { type: 'category' },
+  yAxis: {},
+  series: [{ type: 'bar' }, { type: 'bar' }, { type: 'bar' }]
+};
live

Use scrollable control if there are many legends.

option = {
+  legend: {
+    type: 'scroll',
+    orient: 'vertical',
+    right: 10,
+    top: 20,
+    bottom: 20,
+    data: ['Legend A', 'Legend B', 'Legend C' /* ... */, , 'Legend x']
+    // ...
+  }
+  // ...
+};

Style

For dark color background, use a light color for the background layer and text while changing the background to translucent.

option = {
+  legend: {
+    data: ['Legend A', 'Legend B', 'Legend C'],
+    backgroundColor: '#ccc',
+    textStyle: {
+      color: '#ccc'
+      // ...
+    }
+    // ...
+  }
+  // ...
+};

The color of legend has many ways to design. For different charts, the legend style can be different.

option = {
+  legend: {
+    data: ['Legend A', 'Legend B', 'Legend C'],
+    icon: 'rect'
+    // ...
+  }
+  // ...
+};

Interactive

Depend on the environmental demand, the legend can support interactive operation. Click the legend to show or hide corresponding categories:

option = {
+  legend: {
+    data: ['Legend A', 'Legend B', 'Legend C'],
+    selected: {
+      'Legend A': true,
+      'Legend B': true,
+      'Legend C': false
+    }
+    // ...
+  }
+  // ...
+};

Tips

The legend should be used according to the situation. Some dual-axis charts include multiple chart types. Different kinds of legend stypes should be distinguished.

option = {
+  legend: {
+    data: [
+      {
+        name: 'Legend A',
+        icon: 'rect'
+      },
+      {
+        name: 'Legend B',
+        icon: 'circle'
+      },
+      {
+        name: 'Legend C',
+        icon: 'pin'
+      }
+    ]
+    //  ...
+  },
+  series: [
+    {
+      name: 'Legend A'
+      //  ...
+    },
+    {
+      name: 'Legend B'
+      //  ...
+    },
+    {
+      name: 'Legend C'
+      //  ...
+    }
+  ]
+  //  ...
+};

While there is only one kind of data in the chart, use the chart title rather than the legend to explain it.

Contributors Edit this page on GitHub

pissang pissang
+ + + + + diff --git a/docs/en/concepts/style/index.html b/docs/en/concepts/style/index.html new file mode 100644 index 000000000..c32df352a --- /dev/null +++ b/docs/en/concepts/style/index.html @@ -0,0 +1,455 @@ + + + + + + + Style - Concepts - Handbook - Apache ECharts + + +

Overview of Style Customization

This article provides an overview of the different approaches about Apache EChartsTM style customization. For example, how to config the color, size, shadow of the graphic elements and labels.

The term "style" may not follow the convention of data visualization, but we use it in this article because it is popular and easy to understand.

These approaches below will be introduced. The functionalities of them might be overlapped, but they are suitable for different scenarios.

  • Theme
  • Color Palette
  • Customize style explicitly (itemStyle, lineStyle, areaStyle, label, ...)
  • Visual encoding (visualMap component)

Theme

Setting a theme is the simplest way to change the color style. For example, in Examples page, we can switch to dark mode and see the result of a different theme.

In our project, we can switch to dark theme like:

var chart = echarts.init(dom, 'dark');

Other themes are not included by default, and need to load them ourselves if we want to use them. Themes can be visited and downloaded in the theme builder. Theme can also be created or edited in it. The downloaded theme can be used as follows:

If a theme is downloaded as a JSON file, we should register it by ourselves, for example:

// Assume the theme name is "vintage".
+fetch('theme/vintage.json')
+  .then(r => r.json())
+  .then(theme => {
+    echarts.registerTheme('vintage', theme);
+    var chart = echarts.init(dom, 'vintage');
+  })

If a theme is downloaded as a JS file, it will auto register itself:

// Import the `vintage.js` file in HTML, then:
+var chart = echarts.init(dom, 'vintage');
+// ...

Color Palette

Color palette can be given in option. They provide a group of colors, which will be auto picked by series and data. We can give a global palette, or exclusive pallette for certain series.

option = {
+  // Global palette:
+  color: [
+    '#c23531',
+    '#2f4554',
+    '#61a0a8',
+    '#d48265',
+    '#91c7ae',
+    '#749f83',
+    '#ca8622',
+    '#bda29a',
+    '#6e7074',
+    '#546570',
+    '#c4ccd3'
+  ],
+
+  series: [
+    {
+      type: 'bar',
+      // A palette only work for the series:
+      color: [
+        '#dd6b66',
+        '#759aa0',
+        '#e69d87',
+        '#8dc1a9',
+        '#ea7e53',
+        '#eedd78',
+        '#73a373',
+        '#73b9bc',
+        '#7289ab',
+        '#91ca8c',
+        '#f49f42'
+      ]
+      // ...
+    },
+    {
+      type: 'pie',
+      // A palette only work for the series:
+      color: [
+        '#37A2DA',
+        '#32C5E9',
+        '#67E0E3',
+        '#9FE6B8',
+        '#FFDB5C',
+        '#ff9f7f',
+        '#fb7293',
+        '#E062AE',
+        '#E690D1',
+        '#e7bcf3',
+        '#9d96f5',
+        '#8378EA',
+        '#96BFFF'
+      ]
+      // ...
+    }
+  ]
+};

Customize Style Explicitly

It is a common way to set style explicitly. Throughout ECharts option, style related options can be set in various place, including itemStyle, lineStyle, areaStyle, label, etc.

Generally speaking, all of the built-in components and series follow the naming convention like itemStyle, lineStyle, areaStyle, label etc, although they may occur in different place according to different series or components.

In the following code we add shadow, gradient to bubble chart.

var data = [
+  [
+    [28604, 77, 17096869, 'Australia', 1990],
+    [31163, 77.4, 27662440, 'Canada', 1990],
+    [1516, 68, 1154605773, 'China', 1990],
+    [13670, 74.7, 10582082, 'Cuba', 1990],
+    [28599, 75, 4986705, 'Finland', 1990],
+    [29476, 77.1, 56943299, 'France', 1990],
+    [31476, 75.4, 78958237, 'Germany', 1990],
+    [28666, 78.1, 254830, 'Iceland', 1990],
+    [1777, 57.7, 870601776, 'India', 1990],
+    [29550, 79.1, 122249285, 'Japan', 1990],
+    [2076, 67.9, 20194354, 'North Korea', 1990],
+    [12087, 72, 42972254, 'South Korea', 1990],
+    [24021, 75.4, 3397534, 'New Zealand', 1990],
+    [43296, 76.8, 4240375, 'Norway', 1990],
+    [10088, 70.8, 38195258, 'Poland', 1990],
+    [19349, 69.6, 147568552, 'Russia', 1990],
+    [10670, 67.3, 53994605, 'Turkey', 1990],
+    [26424, 75.7, 57110117, 'United Kingdom', 1990],
+    [37062, 75.4, 252847810, 'United States', 1990]
+  ],
+  [
+    [44056, 81.8, 23968973, 'Australia', 2015],
+    [43294, 81.7, 35939927, 'Canada', 2015],
+    [13334, 76.9, 1376048943, 'China', 2015],
+    [21291, 78.5, 11389562, 'Cuba', 2015],
+    [38923, 80.8, 5503457, 'Finland', 2015],
+    [37599, 81.9, 64395345, 'France', 2015],
+    [44053, 81.1, 80688545, 'Germany', 2015],
+    [42182, 82.8, 329425, 'Iceland', 2015],
+    [5903, 66.8, 1311050527, 'India', 2015],
+    [36162, 83.5, 126573481, 'Japan', 2015],
+    [1390, 71.4, 25155317, 'North Korea', 2015],
+    [34644, 80.7, 50293439, 'South Korea', 2015],
+    [34186, 80.6, 4528526, 'New Zealand', 2015],
+    [64304, 81.6, 5210967, 'Norway', 2015],
+    [24787, 77.3, 38611794, 'Poland', 2015],
+    [23038, 73.13, 143456918, 'Russia', 2015],
+    [19360, 76.5, 78665830, 'Turkey', 2015],
+    [38225, 81.4, 64715810, 'United Kingdom', 2015],
+    [53354, 79.1, 321773631, 'United States', 2015]
+  ]
+];
+
+option = {
+  backgroundColor: {
+    type: 'radial',
+    x: 0.3,
+    y: 0.3,
+    r: 0.8,
+    colorStops: [
+      {
+        offset: 0,
+        color: '#f7f8fa'
+      },
+      {
+        offset: 1,
+        color: '#cdd0d5'
+      }
+    ]
+  },
+  grid: {
+    left: 10,
+    containLabel: true,
+    bottom: 10,
+    top: 10,
+    right: 30
+  },
+  xAxis: {
+    splitLine: {
+      show: false
+    }
+  },
+  yAxis: {
+    splitLine: {
+      show: false
+    },
+    scale: true
+  },
+  series: [
+    {
+      name: '1990',
+      data: data[0],
+      type: 'scatter',
+      symbolSize: function(data) {
+        return Math.sqrt(data[2]) / 5e2;
+      },
+      emphasis: {
+        focus: 'series',
+        label: {
+          show: true,
+          formatter: function(param) {
+            return param.data[3];
+          },
+          position: 'top'
+        }
+      },
+      itemStyle: {
+        shadowBlur: 10,
+        shadowColor: 'rgba(120, 36, 50, 0.5)',
+        shadowOffsetY: 5,
+        color: {
+          type: 'radial',
+          x: 0.4,
+          y: 0.3,
+          r: 1,
+          colorStops: [
+            {
+              offset: 0,
+              color: 'rgb(251, 118, 123)'
+            },
+            {
+              offset: 1,
+              color: 'rgb(204, 46, 72)'
+            }
+          ]
+        }
+      }
+    },
+    {
+      name: '2015',
+      data: data[1],
+      type: 'scatter',
+      symbolSize: function(data) {
+        return Math.sqrt(data[2]) / 5e2;
+      },
+      emphasis: {
+        focus: 'series',
+        label: {
+          show: true,
+          formatter: function(param) {
+            return param.data[3];
+          },
+          position: 'top'
+        }
+      },
+      itemStyle: {
+        shadowBlur: 10,
+        shadowColor: 'rgba(25, 100, 150, 0.5)',
+        shadowOffsetY: 5,
+        color: {
+          type: 'radial',
+          x: 0.4,
+          y: 0.3,
+          r: 1,
+          colorStops: [
+            {
+              offset: 0,
+              color: 'rgb(129, 227, 238)'
+            },
+            {
+              offset: 1,
+              color: 'rgb(25, 183, 207)'
+            }
+          ]
+        }
+      }
+    }
+  ]
+};
live

Style of Emphasis State

When mouse hovering a graphic elements, usually the emphasis style will be displayed. By default, the emphasis style is auto generated by the normal style. However they can be specified by emphasis property. The options in emphasis is the same as the ones for normal state, for example:

option = {
+  series: {
+    type: 'scatter',
+
+    // Styles for normal state.
+    itemStyle: {
+      // Color of the point.
+      color: 'red'
+    },
+    label: {
+      show: true,
+      // Text of labels.
+      formatter: 'This is a normal label.'
+    },
+
+    // Styles for emphasis state.
+    emphasis: {
+      itemStyle: {
+        // Color in emphasis state.
+        color: 'blue'
+      },
+      label: {
+        show: true,
+        // Text in emphasis.
+        formatter: 'This is a emphasis label.'
+      }
+    }
+  }
+};

Notice: Before ECharts4, the emphasis style should be written like this:

option = {
+  series: {
+    type: 'scatter',
+
+    itemStyle: {
+      // Styles for normal state.
+      normal: {
+        color: 'red'
+      },
+      // Styles for emphasis state.
+      emphasis: {
+        color: 'blue'
+      }
+    },
+
+    label: {
+      // Styles for normal state.
+      normal: {
+        show: true,
+        formatter: 'This is a normal label.'
+      },
+      // Styles for emphasis state.
+      emphasis: {
+        show: true,
+        formatter: 'This is a emphasis label.'
+      }
+    }
+  }
+};

The option format is still compatible, but not recommended. In fact, in most cases, users only set normal style, and use the default emphasis style. So since ECharts4, we support to write style without the "normal" term, which makes the option more simple and neat.

Visual Encoding by visualMap Component

visualMap component supports config the rule that mapping value to visual channel (color, size, ...). More details can be check in Visual Map of Data.

Contributors Edit this page on GitHub

plainheart plainheartKrzysztofMadejski KrzysztofMadejskipissang pissangfuchunhui fuchunhuizachary-svoboda-accesso zachary-svoboda-accesso
+ + + + + diff --git a/docs/en/concepts/visual-map/index.html b/docs/en/concepts/visual-map/index.html new file mode 100644 index 000000000..1b7517159 --- /dev/null +++ b/docs/en/concepts/visual-map/index.html @@ -0,0 +1,81 @@ + + + + + + + Visual Mapping - Concepts - Handbook - Apache ECharts + + +

Visual Map of Data

Data visualization is a procedure of mapping data into visual elements. This procedure can also be called visual coding, and visual elements can also be called visual channels.

Every type of charts in Apache EChartsTM has this built-in mapping procedure. For example, line chart map data into lines, bar chart map data into height. Some more complicated charts, like graph, themeRiver, and treemap have their own built-in mapping.

Besides, ECharts provides visualMap component for general visual mapping. Visual elements allowed in visualMap component are:

  • symbol, symbolSize
  • color, opacity, colorAlpha,
  • colorLightness, colorSaturation, colorHue

Next, we are going to introduce how to use visualMap component.

Data and Dimension

Data are usually stored in series.data in ECharts. Depending on chart types, like list, tree, graph, and so on, the form of data may vary somehow. But they have one common feature, that they are a collection of data items. Every data item contains data value, and other information if needed. Every data value can be a single value (one dimension) or an array (multiple dimensions).

For example, series.data is the most common form, which is a list, a common array:

series: {
+  data: [
+    {
+      // every item here is a dataItem
+      value: 2323, // this is data value
+      itemStyle: {}
+    },
+    1212, // it can also be a value of dataItem, which is a more common case
+    2323, // every data value here is one dimension
+    4343,
+    3434
+  ];
+}
series: {
+  data: [
+    {
+      // every item here is a dataItem
+      value: [3434, 129, 'San Marino'], // this is data value
+      itemStyle: {}
+    },
+    [1212, 5454, 'Vatican'], // it can also be a value of dataItem, which is a more common case
+    [2323, 3223, 'Nauru'], // every data value here is three dimension
+    [4343, 23, 'Tuvalu'] // If is scatter chart, usually map the first dimension to x axis,
+    // the second dimension to y axis,
+    // and the third dimension to symbolSize
+  ];
+}

Usually the first one or two dimensions are used for mapping. For example, map the first dimension to x axis, and the second dimension to y axis. If you want to represent more dimensions, visualMap is what you need. Most likely, scatter charts use radius to represent the third dimension.

The visualMap Component

visualMap component defines the mapping from which dimension of data to what visual elements.

The following two types of visualMap components are supported, identified with visualMap.type.

Its structure is defined as:

option = {
+  visualMap: [
+    // can define multiple visualMap components at the same time
+    {
+      // the first visualMap component
+      type: 'continuous' // defined as continuous visualMap
+      // ...
+    },
+    {
+      // the second visualMap component
+      type: 'piecewise' // defined as discrete visualMap
+      // ...
+    }
+  ]
+  // ...
+};

Continuous and Piecewise Visual Mapping Components

The visual mapping component of ECharts is divided into continuous (visualMapContinuous) and piecewise (visualMapPiecewise).

Continuous means that the data dimension for visual mapping is a continuous value, while piecewise means that the data is divided into multiple segments or discrete data.

Continuous Visual Mapping

Continuous type visual mapping can determine the range of visual mapping by specifying the maximum and minimum values.

option = {
+  visualMap: [
+    {
+      type: 'continuous',
+      min: 0,
+      max: 5000,
+      dimension: 3, // the fourth dimension of series.data (i.e. value[3]) is mapped
+      seriesIndex: 4, // The fourth series is mapped.
+      inRange: {
+        // The visual configuration in the selected range
+        color: ['blue', '#121122', 'red'], // A list of colors that defines the graph color mapping
+        // the minimum value of the data is mapped to 'blue', and
+        // the maximum value is mapped to 'red', // the maximum value is mapped to 'red', // the maximum value is mapped to 'red'.
+        // The rest is automatically calculated linearly.
+        symbolSize: [30, 100] // Defines the mapping range for the graphic size.
+        // The minimum value of the data is mapped to 30, // and the maximum value is mapped to 100.
+        // The maximum value is mapped to 100.
+        // The rest is calculated linearly automatically.
+      },
+      outOfRange: {
+        // Check the out of range visual configuration
+        symbolSize: [30, 100]
+      }
+    }
+    // ...
+  ]
+};

where visualMap.inRange indicates the style used for data within the data mapping range; while visualMap.outOfRange specifies the style for data outside the mapping range.

visualMap.dimension specifies which dimension of the data will be visually mapped.

Piecewise Visual Mapping

The piecewise visual mapping component has three modes.

To use segmented visual map, you need to set type to 'piecewise' and choose one of the above three configuration items.

Contributors Edit this page on GitHub

KrzysztofMadejski KrzysztofMadejskipissang pissang
+ + + + + diff --git a/docs/en/get-started/index.html b/docs/en/get-started/index.html new file mode 100644 index 000000000..0d66d6e31 --- /dev/null +++ b/docs/en/get-started/index.html @@ -0,0 +1,66 @@ + + + + + + + Get Started - Handbook - Apache ECharts + + +

Get Started

Getting Apache ECharts

Apache ECharts supports several download methods, which are further explained in the next tutorial Installation. Here, we take the example of getting it from the jsDelivr CDN and explain how to install it quickly.

At https://www.jsdelivr.com/package/npm/echarts select dist/echarts.js, click and save it as echarts.js file.

More information about these files can be found in the next tutorial Installation.

Including ECharts

Create a new index.html file in the directory where you just saved echarts.js, with the following content:

<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <!-- Include the ECharts file you just downloaded -->
+    <script src="echarts.js"></script>
+  </head>
+</html>

When you open this index.html, you will see an empty page. But don't worry. Open the console and make sure that no error message is reported, then you can proceed to the next step.

Plotting a Simple Chart

Before drawing we need to prepare a DOM container for ECharts with a defined height and width. Add the following code after the </head> tag introduced earlier.

<body>
+  <!-- Prepare a DOM with a defined width and height for ECharts -->
+  <div id="main" style="width: 600px;height:400px;"></div>
+</body>

Then you can initialize an echarts instance with the echarts.init method and set the echarts instance with setOption method to generate a simple bar chart. Here is the complete code.

<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <title>ECharts</title>
+    <!-- Include the ECharts file you just downloaded -->
+    <script src="echarts.js"></script>
+  </head>
+  <body>
+    <!-- Prepare a DOM with a defined width and height for ECharts -->
+    <div id="main" style="width: 600px;height:400px;"></div>
+    <script type="text/javascript">
+      // Initialize the echarts instance based on the prepared dom
+      var myChart = echarts.init(document.getElementById('main'));
+
+      // Specify the configuration items and data for the chart
+      var option = {
+        title: {
+          text: 'ECharts Getting Started Example'
+        },
+        tooltip: {},
+        legend: {
+          data: ['sales']
+        },
+        xAxis: {
+          data: ['Shirts', 'Cardigans', 'Chiffons', 'Pants', 'Heels', 'Socks']
+        },
+        yAxis: {},
+        series: [
+          {
+            name: 'sales',
+            type: 'bar',
+            data: [5, 20, 36, 10, 10, 20]
+          }
+        ]
+      };
+
+      // Display the chart using the configuration items and data just specified.
+      myChart.setOption(option);
+    </script>
+  </body>
+</html>

And this is your first chart with Apache ECharts!

Contributors Edit this page on GitHub

plainheart plainheartOvilia Oviliarandyl randylpissang pissang
+ + + + + diff --git a/docs/en/how-to/animation/transition/index.html b/docs/en/how-to/animation/transition/index.html new file mode 100644 index 000000000..dd0109044 --- /dev/null +++ b/docs/en/how-to/animation/transition/index.html @@ -0,0 +1,196 @@ + + + + + + + Data Transition - Animation - How To Guides - Handbook - Apache ECharts + + +

Data Transition

Apache EChartsTM will apply transition on the position, scale, shape when adding, updating and removing data. It makes the chart smoother and shows relationships between data better. Often the developer does not need to worry about how to use the animations, but simply uses setOption to update the data, and ECharts will find the difference between the last data and automatically apply the most appropriate transition animation.

For example, the following example shows the transition on a timed update of the pie chart data.

function makeRandomData() {
+  return [
+    {
+      value: Math.random(),
+      name: 'A'
+    },
+    {
+      value: Math.random(),
+      name: 'B'
+    },
+    {
+      value: Math.random(),
+      name: 'C'
+    }
+  ];
+}
+option = {
+  series: [
+    {
+      type: 'pie',
+      radius: [0, '50%'],
+      data: makeRandomData()
+    }
+  ]
+};
+
+setInterval(() => {
+  myChart.setOption({
+    series: {
+      data: makeRandomData()
+    }
+  });
+}, 2000);
live

Configuration of Transitions

Because adding and updating data will often require different animations, for example we would expect the data update animation to be shorter, ECharts distinguishes between the two animation configurations.

  • For adding data, we apply an enter animation, using animationDuration, animationEasing, and animationDelay to configure the duration, easing and delay of the animation respectively.
  • For updating data, we will apply an update animation with animationDurationUpdate, animationEasingUpdate, and animationDelayUpdate configuring the duration, easing and delay of the animation respectively.

As you can see, the update animation configuration is the enter animation configuration with the Update suffix.

Each time using setOption in ECharts, the data will be diffed to the last updated data and three states are performed for the data based on the diff result: add, update and remove. This diff is based on the name of the data, for example, if the last update had three names of 'A', 'B', 'C', and the new update has become 'B', 'C', 'D', then the data 'B', 'C' will be updated, the data 'A' will be removed, and the data ' D' will be added. If it is the first time setOption, because there is no old data, all data will be added. Depending on the three states ECharts will apply entry animation, update animation and leave animation respectively.

All these configurations can be set at the top level of option for all series and components, or separately for each series.

If we want to turn off animations, we can simply set option.animation to false.

Animation Duration

animationDuration and animationDurationUpdate are used to set the duration of the animation in ms. Setting a longer animation duration allows the user to see the effect of the transition animation more clearly, but we also need to be careful that too much time can make the user lose patience while waiting animation to be finished.

A setting of 0 will turn the animation off, and this can be achieved by setting the corresponding configuration to 0 individually when we only want to turn off the enter animation or update animation.

Animation Easing

The animationEasing and animationEasingUpdate configuration items are used to set the animation's easing function, which is a function that inputs the animation time and outputs the animation progress.

(t: number) => number;

The common animation easing functions such as 'cubicIn' and 'cubicOut' are built into ECharts and can be used directly

Built-in easing functions.

Animation Delay

The animationDelay and animationDelayUpdate are used to set the time at which the animation delay starts, usually we will use a callback function to set different delays for different data to achieve the effect of staggered animations:

var xAxisData = [];
+var data1 = [];
+var data2 = [];
+for (var i = 0; i < 100; i++) {
+  xAxisData.push('A' + i);
+  data1.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5);
+  data2.push((Math.cos(i / 5) * (i / 5 - 10) + i / 6) * 5);
+}
+option = {
+  legend: {
+    data: ['bar', 'bar2']
+  },
+  xAxis: {
+    data: xAxisData,
+    splitLine: {
+      show: false
+    }
+  },
+  yAxis: {},
+  series: [
+    {
+      name: 'bar',
+      type: 'bar',
+      data: data1,
+      emphasis: {
+        focus: 'series'
+      },
+      animationDelay: function(idx) {
+        return idx * 10;
+      }
+    },
+    {
+      name: 'bar2',
+      type: 'bar',
+      data: data2,
+      emphasis: {
+        focus: 'series'
+      },
+      animationDelay: function(idx) {
+        return idx * 10 + 100;
+      }
+    }
+  ],
+  animationEasing: 'elasticOut',
+  animationDelayUpdate: function(idx) {
+    return idx * 5;
+  }
+};
live

Performance Optimization of Animations

When the amount of data is particularly large, running animation can have performance issue, so we can set animation: false to turn off animation.

For charts where the amount of data changes dynamically, we recommend using the animationThreshold configuration, which allows ECharts to automatically turn off animation when the number of graphs in the canvas exceeds this threshold to improve drawing performance. This is often an empirical value, and ECharts is usually capable of rendering thousands of graphs in real time (our default value is also given as 2000), but if your charts are complex, or your user environment is harsh and there is a lot of other complex code running on the page at the same time, it may be appropriate to adjust this value downwards to ensure the smoothness of the whole application.

Listening to the End of Animation

Sometimes we want to get the result of the current rendering, if no animation is used, ECharts will perform the rendering directly after setOption and we can use getDataURL method to get the rendering result synchronisely.

const chart = echarts.init(dom);
+chart.setOption({
+  animation: false
+  //...
+});
+// can be executed directly and synchronously
+const dataUrl = chart.getDataURL();

But if the chart is animated, executing getDataURL right away will give us the picture at the beginning of the animation, not the final result. So we need to know when the animation has finished and then execute getDataURL to get the result.

If you are sure of the duration of the animation, a simpler and more brutal way is to delay the execution with setTimeout depending on the duration of the animation:

chart.setOption({
+  animationDuration: 1000
+  //...
+});
+setTimeout(() => {
+  const dataUrl = chart.getDataURL();
+}, 1000);

Alternatively, we can use the rendered event provided by ECharts to determine that the ECharts have finished animating and stopped rendering

chart.setOption({
+  animationDuration: 1000
+  //...
+});
+
+function onRendered() {
+  const dataUrl = chart.getDataURL();
+  // ...
+  // This event will also be triggered if there is a subsequent interaction and the interaction is redrawn, so it needs to be removed when you're done using it
+  chart.off('rendered', onRendered);
+}
+chart.on('rendered', onRendered);

Contributors Edit this page on GitHub

pissang pissang
+ + + + + diff --git a/docs/en/how-to/chart-types/bar/bar-race/index.html b/docs/en/how-to/chart-types/bar/bar-race/index.html new file mode 100644 index 000000000..944423589 --- /dev/null +++ b/docs/en/how-to/chart-types/bar/bar-race/index.html @@ -0,0 +1,127 @@ + + + + + + + Bar Racing - Bar - Common Charts - How To Guides - Handbook - Apache ECharts + + +

Dynamic Sorting Bar Chart

Bar race is a chart that shows changes in the ranking of data over time and it is supported by default since ECharts 5.

Bar race charts usually use horizontal bars. If you want to use vertical bars, just take the X axis and Y axis in this tutorial to the opposite.

  1. Set realtimeSort of the bar series to be true to enable bar race
  2. Set yAxis.inverse to be true to display longer bars at top
  3. yAxis.animationDuration is suggested to be set to be 300 for bar reordering animation for the first time
  4. yAxis.animationDurationUpdate is suggested to be set to be 300 for bar reordering animation for later times
  5. Set yAxis.max to be n - 1 where n is the number of bars to be displayed; otherwise, all bars are displayed
  6. xAxis.max is suggested to be set to be 'dataMax' so that the maximum of data is used as X maximum.
  7. If realtime label changing is required, set series.label.valueAnimation to be true
  8. Set animationDuration to be 0 so that the first animation doesn't start from 0; if you wish otherwise, set it to be the same value as animationDurationUpdate
  9. animationDurationUpdate is suggested to be set to be 3000 for animation update duration, which should be the same as the frequency of calling setOption
  10. Call setOption to update data to be of next time with setInterval at the frequency of animationDurationUpdate

Demo

A complete demo:

var data = [];
+for (let i = 0; i < 5; ++i) {
+  data.push(Math.round(Math.random() * 200));
+}
+
+option = {
+  xAxis: {
+    max: 'dataMax'
+  },
+  yAxis: {
+    type: 'category',
+    data: ['A', 'B', 'C', 'D', 'E'],
+    inverse: true,
+    animationDuration: 300,
+    animationDurationUpdate: 300,
+    max: 2 // only the largest 3 bars will be displayed
+  },
+  series: [
+    {
+      realtimeSort: true,
+      name: 'X',
+      type: 'bar',
+      data: data,
+      label: {
+        show: true,
+        position: 'right',
+        valueAnimation: true
+      }
+    }
+  ],
+  legend: {
+    show: true
+  },
+  animationDuration: 0,
+  animationDurationUpdate: 3000,
+  animationEasing: 'linear',
+  animationEasingUpdate: 'linear'
+};
+
+function run() {
+  var data = option.series[0].data;
+  for (var i = 0; i < data.length; ++i) {
+    if (Math.random() > 0.9) {
+      data[i] += Math.round(Math.random() * 2000);
+    } else {
+      data[i] += Math.round(Math.random() * 200);
+    }
+  }
+  myChart.setOption(option);
+}
+
+setTimeout(function() {
+  run();
+}, 0);
+setInterval(function() {
+  run();
+}, 3000);
live

Contributors Edit this page on GitHub

Ovilia Oviliapissang pissangShofol Shofol
+ + + + + diff --git a/docs/en/how-to/chart-types/bar/basic-bar/index.html b/docs/en/how-to/chart-types/bar/basic-bar/index.html new file mode 100644 index 000000000..761afb300 --- /dev/null +++ b/docs/en/how-to/chart-types/bar/basic-bar/index.html @@ -0,0 +1,229 @@ + + + + + + + Basic Bar - Bar - Common Charts - How To Guides - Handbook - Apache ECharts + + +

Basic Bar Chart

Bar Chart, is a chart that presents the comparisons among discrete data. The length of the bars is proportionally related to the categorical data.

To set the bar chart, you need to set the type of series as 'bar'.

[Option]

Simple Example

Let's begin with a basic bar chart:

option = {
+  xAxis: {
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};
live

In this case, the x-axis is under the category type. Therefore, you should define some corresponding values for 'xAxis'. Meanwhile, the data type of the y-axis is numerical. The range of the y-axis will be generated automatically by the data in 'series'.

Multi-series Bar Chart

You may use a series to represent a group of related data. To show multiple series in the same chart, you need to add one more array under the series.

option = {
+  xAxis: {
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    },
+    {
+      type: 'bar',
+      data: [26, 24, 18, 22, 23, 20, 27]
+    }
+  ]
+};
live

Customized Bar Chart

Styles

It is a good idea to install the style of Bar Chart by using 'series.itemStyle'. Description of the SCI:

  • Color of column('color');
  • Outline color('borderColor'), width('borderWidth'), type('borderType') of column;
  • Border radius of column('barBorderRadius');
  • Transparency('opacity');
  • Shadow type('shadowBlur', 'shadowColor', 'shadowOffsetX', 'shadowOffsetY')

Here is a example:

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [
+        10,
+        22,
+        28,
+        {
+          value: 43,
+          // Specify the style for single bar
+          itemStyle: {
+            color: '#91cc75',
+            shadowColor: '#91cc75',
+            borderType: 'dashed',
+            opacity: 0.5
+          }
+        },
+        49
+      ],
+      itemStyle: {
+        barBorderRadius: 5,
+        borderWidth: 1,
+        borderType: 'solid',
+        borderColor: '#73c0de',
+        shadowColor: '#5470c6',
+        shadowBlur: 3
+      }
+    }
+  ]
+};
live

In this case, we defined the style of the bar chart by 'itemStyle' of corresponding series. For complete configuration items and their usage, please check the configuration item manual: series.itemStyle

Width and Height of Column

You can use barWidth to change the width of the bar. For instance, the 'barWidth' in the following case was set to '20%'. It indicates that width of each bar is 20% of the category width. As there are 5 data in every series, 20% 'barWidth' means 4% for the entire x-axis.

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [10, 22, 28, 43, 49],
+      barWidth: '20%'
+    }
+  ]
+};
live

In addition, barMaxWidth has limited the maximum width of the bar. For some small value, you can declare a minimum height for the bar: barMinHeight. When the corresponding height of data is smaller than the limit, ECharts will take 'barMinHeight' as the replaced height.

Column Spacing

There are two kinds of column spacing. One is the spacing between different series under the same category: barGap. The other is the spacing between categories: barCategoryGap.

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 18],
+      barGap: '20%',
+      barCategoryGap: '40%'
+    },
+    {
+      type: 'bar',
+      data: [12, 14, 9, 9, 11]
+    }
+  ]
+};
live

In this case, the barGap is '20%'. That means the distance between bars under the same category is 20% of the bar width. For instance, if we set the barCategoryGap to '40%', the gap on each side of the bar will take 40% place in categories (compared with the width of the column).

Usually, barWidth is not necessary to be clarified if 'barGap' and barCategoryGap was set. If you need to make sure the bar is not too wide while the graph is large, try to use barMaxWidth to limit the maximum width of bars.

In the same cartesian coordinate system, the property will be shared by several column series. To make sure it takes effect on the graph, please set the property on the last bar chart series of the system.

Add Background Color for Bars

You might want to change the background color of bars sometimes. After ECharts v4.7.0, this function can be enabled by 'showBackground' and configured by 'backgroundStyle'.

option = {
+  xAxis: {
+    type: 'category',
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      data: [120, 200, 150, 80, 70, 110, 130],
+      type: 'bar',
+      showBackground: true,
+      backgroundStyle: {
+        color: 'rgba(220, 220, 220, 0.8)'
+      }
+    }
+  ]
+};
live

Contributors Edit this page on GitHub

plainheart plainheartpissang pissang
+ + + + + diff --git a/docs/en/how-to/chart-types/bar/stacked-bar/index.html b/docs/en/how-to/chart-types/bar/stacked-bar/index.html new file mode 100644 index 000000000..37119d676 --- /dev/null +++ b/docs/en/how-to/chart-types/bar/stacked-bar/index.html @@ -0,0 +1,49 @@ + + + + + + + Stacked Bar - Bar - Common Charts - How To Guides - Handbook - Apache ECharts + + +

Stacked Bar Chart

Sometimes, we hope to not only figure series separately but also the trend of the sum. It's a good choice to implement it by using the stacked bar chart. As the name suggests, in the stacked bar chart, data in the same category will be stacked up in one column. The overall height of the bar explained the change of total.

There is a simple way to implement a stacked bar chart by ECharts. You need to set the same string type value for a group of series in stack. The series with the same stack value will be in the same category.

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 43, 49],
+      type: 'bar',
+      stack: 'x'
+    },
+    {
+      data: [5, 4, 3, 5, 10],
+      type: 'bar',
+      stack: 'x'
+    }
+  ]
+};
live

In this case, the position of the second series is based on the position of the first series, the height increased is corresponding to the first series' height. Therefore, from the position of the second series, you can find the changing trend of the sum of the two.

The value of stack explained what series will be stacked up together. Theoretically, the specific value of 'stack' is meaningless. However, we prefer some suggestive strings for the convenience of reading.

For instance, here is a chart with 4 series that counted the amount of male and female. "adult male" and "boy" need to be stacked while "adult female" and "girl" need to be stacked. In this case, the suggestive value of stack is 'male' and 'female'. Although meaningless strings like 'a' and 'b' can achieve the same effect but the code will have worse readability.

Contributors Edit this page on GitHub

pissang pissang
+ + + + + diff --git a/docs/en/how-to/chart-types/bar/waterfall/index.html b/docs/en/how-to/chart-types/bar/waterfall/index.html new file mode 100644 index 000000000..6757489a7 --- /dev/null +++ b/docs/en/how-to/chart-types/bar/waterfall/index.html @@ -0,0 +1,177 @@ + + + + + + + Waterfall - Bar - Common Charts - How To Guides - Handbook - Apache ECharts + + +

Waterfall

There is no waterfall series in Apache ECharts, but we can simulate the effect using a stacked bar chart.

Assuming that the values in the data array represent an increase or decrease from the previous value.

var data = [900, 345, 393, -108, -154, 135, 178, 286, -119, -361, -203];

That is, the first data is 900 and the second data 345 represents the addition of 345 to 900, etc. When presenting this data as a stepped waterfall chart, we can use three series: the first is a non-interactive transparent series to implement the suspension bar effect, the second series is used to represent positive numbers, and the third series is used to represent negative numbers.

var data = [900, 345, 393, -108, -154, 135, 178, 286, -119, -361, -203];
+var help = [];
+var positive = [];
+var negative = [];
+for (var i = 0, sum = 0; i < data.length; ++i) {
+  if (data[i] >= 0) {
+    positive.push(data[i]);
+    negative.push('-');
+  } else {
+    positive.push('-');
+    negative.push(-data[i]);
+  }
+
+  if (i === 0) {
+    help.push(0);
+  } else {
+    sum += data[i - 1];
+    if (data[i] < 0) {
+      help.push(sum + data[i]);
+    } else {
+      help.push(sum);
+    }
+  }
+}
+
+option = {
+  title: {
+    text: 'Waterfall'
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    splitLine: { show: false },
+    data: (function() {
+      var list = [];
+      for (var i = 1; i <= 11; i++) {
+        list.push('Oct/' + i);
+      }
+      return list;
+    })()
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      type: 'bar',
+      stack: 'all',
+      itemStyle: {
+        normal: {
+          barBorderColor: 'rgba(0,0,0,0)',
+          color: 'rgba(0,0,0,0)'
+        },
+        emphasis: {
+          barBorderColor: 'rgba(0,0,0,0)',
+          color: 'rgba(0,0,0,0)'
+        }
+      },
+      data: help
+    },
+    {
+      name: 'positive',
+      type: 'bar',
+      stack: 'all',
+      data: positive
+    },
+    {
+      name: 'negative',
+      type: 'bar',
+      stack: 'all',
+      data: negative,
+      itemStyle: {
+        color: '#f33'
+      }
+    }
+  ]
+};
live

Contributors Edit this page on GitHub

plainheart plainheartpissang pissang
+ + + + + diff --git a/docs/en/how-to/chart-types/line/area-line/index.html b/docs/en/how-to/chart-types/line/area-line/index.html new file mode 100644 index 000000000..3710c8575 --- /dev/null +++ b/docs/en/how-to/chart-types/line/area-line/index.html @@ -0,0 +1,55 @@ + + + + + + + Area Chart - Line - Common Charts - How To Guides - Handbook - Apache ECharts + + +

Area Chart

The area chart fills the space between the line and axis with the background color, to express the data by the size of the area. Compared with the normal line chart, the area chart has more intuitive visual effects. It is especially suitable for the scenario with a few series.

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 23, 19],
+      type: 'line',
+      areaStyle: {}
+    },
+    {
+      data: [25, 14, 23, 35, 10],
+      type: 'line',
+      areaStyle: {
+        color: '#ff0',
+        opacity: 0.5
+      }
+    }
+  ]
+};
live

If you want to change the area style of the line chart, try to use areaStyle. Set 'areaStyle' to {} to use the default type: use the color of series to fill the area in translucent. If you want to change the style, try to override the configuration items in 'areaStyle'. For example, the color of the second series was changed to yellow with 50% opacity.

Contributors Edit this page on GitHub

pissang pissang
+ + + + + diff --git a/docs/en/how-to/chart-types/line/basic-line/index.html b/docs/en/how-to/chart-types/line/basic-line/index.html new file mode 100644 index 000000000..5a6fb931f --- /dev/null +++ b/docs/en/how-to/chart-types/line/basic-line/index.html @@ -0,0 +1,163 @@ + + + + + + + Basic Line - Line - Common Charts - How To Guides - Handbook - Apache ECharts + + +

Basic Line Chart

Simple Example

We can use the following code to build a line chart which has x-axis as category, y-axis as value:

option = {
+  xAxis: {
+    type: 'category',
+    data: ['A', 'B', 'C']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      data: [120, 200, 150],
+      type: 'line'
+    }
+  ]
+};
live

In this case, we set the type of axis to category and value under xAxis and yAxis. We also clarified the content on the x-axis through data. In series, we set the type to line, and specify the values of three points through data. In this way, we got a simple line chart.

The type here can be omitted because the defaults of the axis are value while xAxis has specified the category's data. In this case, ECharts can recognize that this is a category axis.

Line Chart in Cartesian Coordinate System

How to implement if we want the line chart to be continuous? The answer is simple, as long as every value in data of the series is represented by an array containing two elements.

option = {
+  xAxis: {},
+  yAxis: {},
+  series: [
+    {
+      data: [
+        [20, 120],
+        [50, 200],
+        [40, 50]
+      ],
+      type: 'line'
+    }
+  ]
+};
live

Customized Line Chart

Line Style

Line style can be changed by lineStyle setting. You can specify color, line width, polyline type and opacity etc.. For details, please see the handbook series.lineStyle to figure out.

Here is an example of setting color, line width and type.

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 23, 19],
+      type: 'line',
+      lineStyle: {
+        normal: {
+          color: 'green',
+          width: 4,
+          type: 'dashed'
+        }
+      }
+    }
+  ]
+};
live

When we set the line width here, the line width of items will not change. The line style of items needs to be set separately.

Item Style

Item style can be change by series.itemStyle. It included color, borderColor, borderStyle, borderWidth, borderType, shadowColor, opacity and so on. It works the same as the lineType, so we will not do further discuss.

Display Value on Items.

In the series, the label of the item was specified by series.label. If we change the show under label to true, the value will be displayed by default. Otherwise, if series.emphasis.label.show is true, the label will show only if the mouse moved across the item.

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 23, 19],
+      type: 'line',
+      label: {
+        show: true,
+        position: 'bottom',
+        textStyle: {
+          fontSize: 20
+        }
+      }
+    }
+  ]
+};
live

Empty Data

In a series, there are empty data. It has some difference with 0. While there are empty elements, the lines chart will ignore that point without pass through it----empty elements will not be connected by the points next by.

In ECharts, we use '-' to represent null data, It is applicable for data in other series.

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [0, 22, '-', 23, 19],
+      type: 'line'
+    }
+  ]
+};
live

Please note the difference between the empty data and 0.

Contributors Edit this page on GitHub

pissang pissang
+ + + + + diff --git a/docs/en/how-to/chart-types/line/smooth-line/index.html b/docs/en/how-to/chart-types/line/smooth-line/index.html new file mode 100644 index 000000000..06d2d00a8 --- /dev/null +++ b/docs/en/how-to/chart-types/line/smooth-line/index.html @@ -0,0 +1,39 @@ + + + + + + + Smoothed Line - Line - Common Charts - How To Guides - Handbook - Apache ECharts + + +

Smooth Line Chart

The smooth line chart is also a variant of the basic line graph. It is a better choice for you to perform a comfort visual experience. While using the ECharts, you only need to change the smooth to true to achieve this effect.

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 23, 19],
+      type: 'line',
+      smooth: true
+    }
+  ]
+};
live

Contributors Edit this page on GitHub

pissang pissang
+ + + + + diff --git a/docs/en/how-to/chart-types/line/stacked-line/index.html b/docs/en/how-to/chart-types/line/stacked-line/index.html new file mode 100644 index 000000000..156bcd545 --- /dev/null +++ b/docs/en/how-to/chart-types/line/stacked-line/index.html @@ -0,0 +1,87 @@ + + + + + + + Stacked Line - Line - Common Charts - How To Guides - Handbook - Apache ECharts + + +

Stacked Line Chart

Similar to the Stacked Bar Chart, Stacked Line Chart use the 'stack' in series to decide which series should be stacked together.

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 43, 49],
+      type: 'line',
+      stack: 'x'
+    },
+    {
+      data: [5, 4, 3, 5, 10],
+      type: 'line',
+      stack: 'x'
+    }
+  ]
+};
live

However, without clarification, it is hard for us to judge whether it is a stacked line chart or normal line chart. Therefore, filling color for the area under the line is recommended to indicate for a stacked line chart.

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 43, 49],
+      type: 'line',
+      stack: 'x',
+      areaStyle: {}
+    },
+    {
+      data: [5, 4, 3, 5, 10],
+      type: 'line',
+      stack: 'x',
+      areaStyle: {}
+    }
+  ]
+};
live

Contributors Edit this page on GitHub

vincentbernat vincentbernatpissang pissangomkar787 omkar787
+ + + + + diff --git a/docs/en/how-to/chart-types/line/step-line/index.html b/docs/en/how-to/chart-types/line/step-line/index.html new file mode 100644 index 000000000..0ae813b4a --- /dev/null +++ b/docs/en/how-to/chart-types/line/step-line/index.html @@ -0,0 +1,73 @@ + + + + + + + Step Line - Line - Common Charts - How To Guides - Handbook - Apache ECharts + + +

Step Line Chart

The normal line chart connects two points by straight line directly, while the step line chart, also known as square wave chart, uses only horizontal and vertical lines to connect the nearby items together. Compared with the normal line chart, the step line chart significantly shows the sudden changes of analyzed data.

In ECharts, step is used to characterize the connection type of the step line chart. It has three available values: 'start', 'end', and 'middle'. For item A and B, these values corresponded that the corner occurred at A, B, and mid-point between A and B.

option = {
+  legend: {},
+  xAxis: {
+    type: 'category',
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      name: 'Step Start',
+      type: 'line',
+      step: 'start',
+      data: [120, 132, 101, 134, 90, 230, 210]
+    },
+    {
+      name: 'Step Middle',
+      type: 'line',
+      step: 'middle',
+      data: [220, 282, 201, 234, 290, 430, 410]
+    },
+    {
+      name: 'Step End',
+      type: 'line',
+      step: 'end',
+      data: [450, 432, 401, 454, 590, 530, 510]
+    }
+  ]
+};
live

Please focus on the difference of line between three separate types.

Contributors Edit this page on GitHub

pissang pissang
+ + + + + diff --git a/docs/en/how-to/chart-types/pie/basic-pie/index.html b/docs/en/how-to/chart-types/pie/basic-pie/index.html new file mode 100644 index 000000000..678ba3cbf --- /dev/null +++ b/docs/en/how-to/chart-types/pie/basic-pie/index.html @@ -0,0 +1,175 @@ + + + + + + + Basic Pie - Pie - Common Charts - How To Guides - Handbook - Apache ECharts + + +

Basic Pie Chart

Pie charts are mainly used to show the proportion of several categories compared with the total. The radians represent the proportion of each category.

Simple Example

The config of the pie chart is not completely the same as the line chart and bar chart. There is no need to configure the axis. The name and value of data need to be defined in the series. Let's begin with a basic pie chart:

option = {
+  series: [
+    {
+      type: 'pie',
+      data: [
+        {
+          value: 335,
+          name: 'Direct Visit'
+        },
+        {
+          value: 234,
+          name: 'Union Ad'
+        },
+        {
+          value: 1548,
+          name: 'Search Engine'
+        }
+      ]
+    }
+  ]
+};
live

To be mentioned, the value here does not need to be percentage data. ECharts will proportionately distribute their corresponding radians in the pie chart depending on all the data.

Customized Pie Chart

Radius of Pie Chart

The radius of pie chart can be defined by series.radius. Both percent string('60%') and absolute pixel string('200') are available. While it is a percent string, it is proportional related to the shorter container('div') edge.

option = {
+  series: [
+    {
+      type: 'pie',
+      data: [
+        {
+          value: 335,
+          name: 'Direct Visit'
+        },
+        {
+          value: 234,
+          name: 'Union Ad'
+        },
+        {
+          value: 1548,
+          name: 'Search Engine'
+        }
+      ],
+      radius: '50%'
+    }
+  ]
+};
live

Hide Chart While Data Sum is 0

By default, if the data sum is 0, the series will divide the shape equally. For instance, if you don't want to show any shape while all 4 series have value equals 0, you could define series.stillShowZeroSum to false.

option = {
+  series: [
+    {
+      type: 'pie',
+      stillShowZeroSum: false,
+      data: [
+        {
+          value: 0,
+          name: 'Direct Visit'
+        },
+        {
+          value: 0,
+          name: 'Union Ad'
+        },
+        {
+          value: 0,
+          name: 'Search Engine'
+        }
+      ]
+    }
+  ]
+};
live

If you are willing to hide the label as well, define the series.label.show to false as well.

option = {
+    series: [{
+        type: 'pie',
+        stillShowZeroSum: false,
+        label: {
+            show: false
+        }
+        data: [{
+            value: 0,
+            name: 'Direct Visit'
+        }, {
+            value: 0,
+            name: 'Union Ad'
+        }, {
+            value: 0,
+            name: 'Search Engine'
+        }]
+    }]
+};
live

Contributors Edit this page on GitHub

pissang pissang
+ + + + + diff --git a/docs/en/how-to/chart-types/pie/doughnut/index.html b/docs/en/how-to/chart-types/pie/doughnut/index.html new file mode 100644 index 000000000..50b80c0d9 --- /dev/null +++ b/docs/en/how-to/chart-types/pie/doughnut/index.html @@ -0,0 +1,135 @@ + + + + + + + Ring Style - Pie - Common Charts - How To Guides - Handbook - Apache ECharts + + +

Doughnut Chart

Doughnut charts are also used to show the proportion of values compared with the total. Different from the pie chart, the blank in the middle of the chart can be used to provide some extra info. It makes a doughnut chart commonly used chart type.

Basic Doughnut Chart

In ECharts, the radius of the pie chart could also be an array with 2 elements. Every element in the array could be string or value. The first element represents the inner radius while the second one is the outer radius.

The bar chart, from this perspective, is a subset of the doughnut chart that has inner radius equals to 0.

option = {
+  title: {
+    text: 'A Case of Doughnut Chart',
+    left: 'center',
+    top: 'center'
+  },
+  series: [
+    {
+      type: 'pie',
+      data: [
+        {
+          value: 335,
+          name: 'A'
+        },
+        {
+          value: 234,
+          name: 'B'
+        },
+        {
+          value: 1548,
+          name: 'C'
+        }
+      ],
+      radius: ['40%', '70%']
+    }
+  ]
+};
live

If we set one radius to string of a percentage value, while the other to a value, the inner radius will be smaller than the outer radius in some resolution. ECharts will choose the smaller element for the inner radius automatically. However, it will still cause not an unexpected outcome.

Show Text In Middle Of Doughnut From Highlighted Sector

The previous case gives you a way to show fixed text in the middle of doughnut chart. The next case will show you how to display the corresponding text of the sector highlighted by the mouse. The general idea is to fix label in the middle of the chart while hiding label in default.

option = {
+  legend: {
+    orient: 'vertical',
+    x: 'left',
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  series: [
+    {
+      type: 'pie',
+      radius: ['50%', '70%'],
+      avoidLabelOverlap: false,
+      label: {
+        show: false,
+        position: 'center'
+      },
+      labelLine: {
+        show: false
+      },
+      emphasis: {
+        label: {
+          show: true,
+          fontSize: '30',
+          fontWeight: 'bold'
+        }
+      },
+      data: [
+        { value: 335, name: 'A' },
+        { value: 310, name: 'B' },
+        { value: 234, name: 'C' },
+        { value: 135, name: 'D' },
+        { value: 1548, name: 'E' }
+      ]
+    }
+  ]
+};
live

In this case, avoidLabelOverlap is used to control whether ECharts adjust the position of label to avoid overlaps. Default value of avoidLabelOverlap is true. We want the label to be fixed in the middle so that we need to define it as false.

Therefore, the middle of doughnut chart will show the name of the highlighted sector.

Contributors Edit this page on GitHub

plainheart plainheartpissang pissang
+ + + + + diff --git a/docs/en/how-to/chart-types/pie/rose/index.html b/docs/en/how-to/chart-types/pie/rose/index.html new file mode 100644 index 000000000..4e02b62a6 --- /dev/null +++ b/docs/en/how-to/chart-types/pie/rose/index.html @@ -0,0 +1,73 @@ + + + + + + + Rose Style - Pie - Common Charts - How To Guides - Handbook - Apache ECharts + + +

Rose Chart(Nightingale Chart)

Rose Chart, which was also called the nightingale chart, usually indicates categories by sector of the same radius but different radius.

ECharts can implement Rose Chart by defining series.roseType of pie chart to 'area'. All other configs are the same as a basic pie chart.

option = {
+  series: [
+    {
+      type: 'pie',
+      data: [
+        {
+          value: 100,
+          name: 'A'
+        },
+        {
+          value: 200,
+          name: 'B'
+        },
+        {
+          value: 300,
+          name: 'C'
+        },
+        {
+          value: 400,
+          name: 'D'
+        },
+        {
+          value: 500,
+          name: 'E'
+        }
+      ],
+      roseType: 'area'
+    }
+  ]
+};
live

Contributors Edit this page on GitHub

pissang pissang
+ + + + + diff --git a/docs/en/how-to/chart-types/scatter/basic-scatter/index.html b/docs/en/how-to/chart-types/scatter/basic-scatter/index.html new file mode 100644 index 000000000..5a42d5861 --- /dev/null +++ b/docs/en/how-to/chart-types/scatter/basic-scatter/index.html @@ -0,0 +1,126 @@ + + + + + + + Basic Scatter - Scatter - Common Charts - How To Guides - Handbook - Apache ECharts + + +

Basic Scatter Chart

Scatter Chart, a frequently used chart type, was constructed with several "points". These points sometimes represent the position of the value in the coordinate system (cartesian coordinate system, geo coordinate system, etc.), sometimes the size and color of items can be mapped to the value, represent high-dimensional data.

Simple Example

The following example is a basic scatter chart configuration with the x-axis as category and the y-axis as value:

option = {
+  xAxis: {
+    data: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'scatter',
+      data: [220, 182, 191, 234, 290, 330, 310]
+    }
+  ]
+};
live

Scatter Chart in Cartesian Coordinate System

In the previous case, the x-axis of the scatter chart is a discrete category axis and the y-axis is a continuous value axis. However, the normal scene for the scatter chart is to have 2 continuous value axis (also called the cartesian coordinate system). The series type is different in that both x-axis and y-axis value are included in data, but not in xAxis and yAxis.

option = {
+  xAxis: {},
+  yAxis: {},
+  series: [
+    {
+      type: 'scatter',
+      data: [
+        [10, 5],
+        [0, 8],
+        [6, 10],
+        [2, 12],
+        [8, 9]
+      ]
+    }
+  ]
+};
live

Customized Scatter Chart

Symbol Style

Symbol refers to the item shape in a scatter chart. There are three types of config available. The first is ECharts built-in shape, the second is image, the last is the SVG path.

The built-in shape in ECharts included: 'circle', 'rect'(rectangle), 'roundRect'(rounded rectangle), 'triangle', 'diamond', 'pin' and 'arrow'. To use built-in shapes, you need to state the symbol to the corresponding string.

If you want to define the shape as any image, try to use 'image' following by the path, eg. 'image://http://example.com/xxx.png' or 'image://./xxx.png'.

ECharts symbol also supports SVG vector graphics. You can define symbol as an SVG file path that starts with 'path://' to locate the vector graphics. The advantages of vector graphics are smaller size and no jagged or blurred.

Method to find the SVG path: Open an SVG path; Find the path similar as <path d="M… L…"></path>; Add d's value after 'path://'. Let's check how to define an item to vector shape of heart.

Firstly, we need an SVG file of a heart. You can draw one by vector editing software, or download one from the internet. Here is the content:

<?xml version="1.0" encoding="iso-8859-1"?>
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 51.997 51.997" style="enable-background:new 0 0 51.997 51.997;" xml:space="preserve">
+    <path d="M51.911,16.242C51.152,7.888,45.239,1.827,37.839,1.827c-4.93,0-9.444,2.653-11.984,6.905 c-2.517-4.307-6.846-6.906-11.697-6.906c-7.399,0-13.313,6.061-14.071,14.415c-0.06,0.369-0.306,2.311,0.442,5.478 c1.078,4.568,3.568,8.723,7.199,12.013l18.115,16.439l18.426-16.438c3.631-3.291,6.121-7.445,7.199-12.014 C52.216,18.553,51.97,16.611,51.911,16.242z"/>
+</svg>

In ECharts, define config symbol as a path of d:

option = {
+  xAxis: {
+    data: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'scatter',
+      data: [220, 182, 191, 234, 290, 330, 310],
+      symbolSize: 20,
+      symbol:
+        'path://M51.911,16.242C51.152,7.888,45.239,1.827,37.839,1.827c-4.93,0-9.444,2.653-11.984,6.905 c-2.517-4.307-6.846-6.906-11.697-6.906c-7.399,0-13.313,6.061-14.071,14.415c-0.06,0.369-0.306,2.311,0.442,5.478 c1.078,4.568,3.568,8.723,7.199,12.013l18.115,16.439l18.426-16.438c3.631-3.291,6.121-7.445,7.199-12.014 C52.216,18.553,51.97,16.611,51.911,16.242z'
+    }
+  ]
+};
live

In this way, we have a heart vector of the item.

Symbol Size

The size of symbol is defined by series.symbolSize. It can be s pixel value of the item size, or an array included two numbers, to define the width and height.

Besides, it can be defined as a call back function. Here is an example of the format:

(value: Array | number, params: Object) => number | Array;

The first argument is the data value, and the second argument included other arguments of the data item. In the following instance, we define the size of the item proportional related to the data value.

option = {
+  xAxis: {
+    data: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'scatter',
+      data: [220, 182, 191, 234, 290, 330, 310],
+      symbolSize: function(value) {
+        return value / 10;
+      }
+    }
+  ]
+};
live

Contributors Edit this page on GitHub

pissang pissang
+ + + + + diff --git a/docs/en/how-to/cross-platform/server/index.html b/docs/en/how-to/cross-platform/server/index.html new file mode 100644 index 000000000..06d3719ef --- /dev/null +++ b/docs/en/how-to/cross-platform/server/index.html @@ -0,0 +1,132 @@ + + + + + + + Server Side Rendering - Cross Platform - How To Guides - Handbook - Apache ECharts + + +

Server Side Rendering

Normally, Apache EChartsTM renders the chart dynamically in the browser and will re-render after user interactions. However, there are specific scenarios where we also need to render charts on the server side:

  • Reducing the FCP time and ensuring the chart is displayed immediately.
  • Embedding charts in the environments such as Markdown, PDF that do not support scripts.

In these scenarios, ECharts offers both SVG and Canvas server-side rendering (SSR) solutions.

Solution Rendering Result Pros
Serverside SVG Rendering SVG string Smaller than Canvas images;
Vector SVG images are not blurred;
Support for initial animation
Serverside Canvas Rendering Image The image format is available for a wider range of scenarios, and is optional for scenarios that do not support SVG

In general, the server-side SVG rendering solution should be preferred, or if SVG is not applicable, the Canvas rendering solution can be considered.

Server-side rendering also has some limitations, especially some operations related to interaction cannot be supported. Therefore, if you have interaction requirements, you can refer to "Server-Side Rendering with Hydration" below.

Server-Side SVG Rendering

Server-Side SVG Rendering

Version Update:

  • 5.3.0: Introduced a new zero-dependency server-side string based SVG rendering solution, and support for initial animation
  • 5.5.0: Added a lightweight client runtime, which allows some interaction without the need to load the full ECharts on the client side

We introduced a new zero-dependency server-side string based SVG rendering solution in 5.3.0.

// Server-side code
+const echarts = require('echarts');
+
+// In SSR mode the first container parameter is not required
+const chart = echarts.init(null, null, {
+  renderer: 'svg', // must use SVG rendering mode
+  ssr: true, // enable SSR
+  width: 400, // need to specify height and width
+  height: 300
+});
+
+// use setOption as normal
+chart.setOption({
+  //...
+});
+
+// Output a string
+const svgStr = chart.renderToSVGString();
+
+// If chart is no longer useful, consider dispose it to release memory.
+chart.dispose();
+chart = null;

The overall code structure is the almost same as in the browser, starting with init to initialise a chart example and then setting the configuration items for the chart via setOption. However, the parameters passed to init will be different from those used in the browser.

  • Firstly, since the SVG is rendered on the server side is string based, we don't need a container to display the rendered content, so we can pass null or undefined as the first container parameter in the init.
  • Then in the third parameter of init we need to tell ECharts that we need to enable server-side rendering mode by specifying ssr: true in the display. Then ECharts will know it needs to disable the animation loop and event modules.
  • We also have to specify the height and width of the chart, so if your chart size needs to be responsive to the container, you may need to think about whether server-side rendering is appropriate for your scenario.

In the browser ECharts automatically renders the result to the page after setOption and then determines at each frame if there is an animation that needs to be redrawn, but in Node.js we don't do this after setting ssr: true. Instead, we use renderToSVGString to render the current chart to an SVG string, which can then be returned to the front-end via HTTP Response or saved to a local file.

Response to the browser (using Express.js as example):

res.writeHead(200, {
+  'Content-Type': 'application/xml'
+});
+res.write(svgStr); // svgStr is the result of chart.renderToSVGString()
+res.end();

Or save to a local file

fs.writeFile('bar.svg', svgStr, 'utf-8');

Animations in Server-side Rendering

As you can see in the example above, even using server-side rendering, ECharts can still provide animation effects, which are achieved by embedding CSS animations in the output SVG string. There is no need for additional JavaScript to play the animation.

However, the limitations of CSS animation prevent us from implementing more flexible animations in server-side rendering, such as bar chart racing animations, label animations, and special effects animations in the lines series. Animation of some of the series, such as the pie, have been specially optimised for server-side rendering.

If you don't want this animation, you can turn it off by setting animation: false when setOption.

setOption({
+  animation: false
+});

Server-side Canvas rendering

If you want the output to be an image rather than an SVG string, or if you're still using an older version, we'd recommend using node-canvas for server-side rendering, node-canvas is Canvas implementations on Node.js that provide an interface that is almost identical to the Canvas in the browser.

Here's a simple example

var echarts = require('echarts');
+const { createCanvas } = require('canvas');
+
+// In versions ealier than 5.3.0, you had to register the canvas factory with setCanvasCreator.
+// Not necessary since 5.3.0
+echarts.setCanvasCreator(() => {
+  return createCanvas();
+});
+
+const canvas = createCanvas(800, 600);
+// ECharts can use the Canvas instance created by node-canvas as a container directly
+const chart = echarts.init(canvas);
+
+// setOption as normal
+chart.setOption({
+  //...
+});
+
+const buffer = renderChart().toBuffer('image/png');
+
+// If chart is no longer useful, consider dispose it to release memory.
+chart.dispose();
+chart = null;
+
+// Output the PNG image via Response
+res.writeHead(200, {
+  'Content-Type': 'image/png'
+});
+res.write(buffer);
+res.end();

Loading of images

node-canvas provides an Image implementation for image loading. If you use to images in your code, we can adapt them using the setPlatformAPI interface that was introduced in 5.3.0.

echarts.setPlatformAPI({
+  // Same with the old setCanvasCreator
+  createCanvas() {
+    return createCanvas();
+  },
+  loadImage(src, onload, onerror) {
+    const img = new Image();
+    // must be bound to this context.
+    img.onload = onload.bind(img);
+    img.onerror = onerror.bind(img);
+    img.src = src;
+    return img;
+  }
+});

If you are using images from remote, we recommend that you prefetch the image via an http request to get base64 before passing it on as the URL of the image, to ensure that the image is loaded when render.

Client Hydration

Lazy-loading Full ECharts

With the latest version of ECharts, the server-side rendering solution can do the following things along with rendering the chart:

  • Support for initial animation (i.e., the animation that is played when the chart is first rendered)
  • Highlighting styles (i.e., the highlighting effect when the mouse moves over a bar in a bar chart)

But there are features that cannot be supported by server-side rendering:

  • Dynamically changing data
  • Clicking on a legend to toggle whether the series is displayed or not
  • Moving the mouse to show a tooltip
  • Other interaction-related features

If you have such requirements, you can consider using server-side rendering to quickly output the first screen chart, then wait for echarts.js to finish loading and re-render the same chart on the client side, so that you can achieve normal interaction effects and dynamically change the data. Note that when rendering on the client side, you should turn on interactive components like tooltip: { show: true } and turn off the initial animation with animation: 0 (the initial animation should be done by the SVG animation of the rendered result on the server side).

As we can see, from the user experience point of view, there is almost no secondary rendering process, and the whole switching effect is very seamless. You can also use a library like pace-js to display the loading progress bar during the loading of echarts.js as in the above example to solve the problem of no interactive feedback before the ECharts are fully loaded.

Using server-side rendering with client-side rendering along with a lazy-loading echarts.js on the client side is a good solution for scenarios where the first screen needs to be rendered quickly and then the interaction needs to be supported. However, it takes some time to load the echarts.js and before it is fully loaded, there is no interactive feedback, in which case, a "Loading" text might be displayed to the user. This is a commonly recommended solution for scenarios where the first screen needs to be rendered quickly and then the interaction needs to be supported.

Lightweight Client Runtime

Solution A provides a way for implementing complete interactions, but in some scenarios, we don't need complex interactions, we just hope to be able to perform some simple interactions on the client side based on server-side rendering, such as: clicking the legend to toggle whether the series is displayed. In this case, can we avoid loading at least a few hundred KBs of ECharts code on the client side?

Starting from version v5.5.0, if the chart only needs the following effects and interactions, it can be achieved through server-side SVG rendering + client-side lightweight runtime:

  • Initial chart animation (implementation principle: the SVG rendered by the server comes with CSS animation)
  • Highlight style (implementation principle: the SVG rendered by the server comes with CSS animation)
  • Dynamically changing data (implementation principle: the lightweight runtime requests the server for secondary rendering)
  • Click the legend to toggle whether the series is displayed (implementation principle: the lightweight runtime requests the server for secondary rendering)
<div id="chart-container" style="width:800px;height:600px"></div>
+
+<script src="https://cdn.jsdelivr.net/npm/echarts/ssr/client/dist/index.js"></script>
+<script>
+const ssrClient = window['echarts-ssr-client'];
+
+let isSeriesShown = {
+  a: true,
+  b: true
+};
+
+function updateChart(svgStr) {
+  const container = document.getElementById('chart-container');
+  container.innerHTML = svgStr;
+
+  // Use the lightweight runtime to give the chart interactive capabilities
+  ssrClient.hydrate(main, {
+    on: {
+      click: (params) => {
+        if (params.ssrType === 'legend') {
+          // Click the legend element, request the server for secondary rendering
+          isSeriesShown[params.seriesName] = !isSeriesShown[params.seriesName];
+          $.get('...?series=' + JSON.stringify(isSeriesShown)).then(svgStr => {
+            updateChart(svgStr);
+          });
+        }
+      }
+    }
+  });
+}
+
+// Get the SVG string rendered by the server through an AJAX request
+$.get('...').then(svgStr => {
+  updateChart(svgStr);
+});
+</script>

The server side performs secondary rendering based on the information passed by the client about whether each series is displayed (isSeriesShown) and returns a new SVG string. The server-side code is the same as above, and will not be repeated.

About state recording: Compared with pure client-side rendering, developers need to record and maintain some additional information (such as whether each series is displayed in this example). This is inevitable because HTTP requests are stateless. If you want to implement a state, either the client records the state and passes it like the above example, or the server retains the state (for example, through a session, but it requires more server memory and more complex destruction logic, so it is not recommended).

Using server-side SVG rendering plus client-side lightweight runtime, the advantage is that the client no longer needs to load hundreds of KBs of ECharts code, only needs to load a less than 4KB lightweight runtime code; and from the user experience, very little is sacrificed (supports initial animation, mouse highlighting). The disadvantage is that it requires a certain development cost to maintain additional state information, and it does not support interactions with high real-time requirements (such as displaying tooltips when moving the mouse). Overall, it is recommended to use it in environments with very strict requirements for code volume.

Using Lightweight Runtime

The client-side lightweight runtime enables interaction with the SVG charts rendered by the server-side by understanding the content.

The client-side lightweight runtime can be imported in the following ways:

<!-- Method one: Using CDN -->
+<script src="https://cdn.jsdelivr.net/npm/echarts/ssr/client/dist/index.js"></script>
+<!-- Method two: Using NPM -->
+<script src="node_modules/echarts/ssr/client/dist/index.js"></script>

API

The following APIs are provided in the global variable window['echarts-ssr-client']:

hydrate(dom: HTMLElement, options: ECSSRClientOptions)

  • dom: The chart container, the content of which should be set as the SVG chart rendered by the server-side before calling this method
  • options: Configuration items
ECSSRClientOptions
on?: {
+  mouseover?: (params: ECSSRClientEventParams) => void,
+  mouseout?: (params: ECSSRClientEventParams) => void,
+  click?: (params: ECSSRClientEventParams) => void
+}

Just like the chart mouse events, the events here are for the chart items (e.g., the bars of a bar chart, the data item of a line chart, etc.), not for the chart container.

ECSSRClientEventParams
{
+  type: 'mouseover' | 'mouseout' | 'click';
+  ssrType: 'legend' | 'chart';
+  seriesIndex?: number;
+  dataIndex?: number;
+  event: Event;
+}
  • type: Event type
  • ssrType: Event object type, legend represents legend data, chart represents chart data object
  • seriesIndex: Series index
  • dataIndex: Data index
  • event: Native event object

Example

See the "Lightweight Client Runtime" section above.

Summary

Above, we introduced several different rendering solutions, including:

  • Client-side rendering
  • Server-side SVG rendering
  • Server-side Canvas rendering
  • Client-side lightweight runtime rendering

These four rendering methods can be used in combination. Let's summarize their respective applicable scenarios:

Rendering Solution Loading Volume Loss of Function and Interaction Relative Development Workload Recommended Scenario
Client-side rendering Largest None Minimum The first screen load time is not sensitive, and there is a high demand for complete functionality and interaction
Client-side rendering (partial package importing on demand) Large Large: the packages not included cannot use the corresponding functions Small The first screen load time is not sensitive, there is no strict requirement for code volume but hope to be as small as possible, only use a small part of ECharts functions, no server resources
One-time server-side SVG rendering Small Large: unable to dynamically change data, does not support legend toggle series display, does not support tooltips and other interactions with high real-time requirements Medium The first screen load time is sensitive, low demand for complete functionality and interaction
One-time server-side Canvas rendering Large Largest: the same as above and does not support initial animation, larger image volume, blurry when enlarged Medium The first screen load time is sensitive, low demand for complete functionality and interaction, platform restrictions cannot use SVG
Server-side SVG rendering plus client-side ECharts lazy loading Small, then large Medium: cannot interact before lazy loading is completed Medium The first screen load time is sensitive, high demand for complete functionality and interaction, the chart is best not needed for interaction immediately after loading
Server-side SVG rendering plus client-side lightweight runtime Small Medium: Cannot implement interactions with high real-time requirements Large (need to maintain chart status, define client-server interface protocol) The first screen load time is sensitive, low demand for complete functionality and interaction, very strict requirements for code volume, not strict requirements for interaction real-time
Server-side SVG rendering plus client-side ECharts lazy loading, using lightweight runtime before lazy loading is completed Small, then large Small: Cannot perform complex interactions before lazy loading is completed Largest The first screen load time is sensitive, high demand for complete functionality and interaction, sufficient development time

Of course, there are some other combination possibilities, but the most common ones are the above. I believe that if you understand the characteristics of these rendering solutions, you can choose the appropriate solution based on your own scenario.

Contributors Edit this page on GitHub

Ovilia Oviliapissang pissangballoon72 balloon72
+ + + + + diff --git a/docs/en/how-to/data/dynamic-data/index.html b/docs/en/how-to/data/dynamic-data/index.html new file mode 100644 index 000000000..00b6ab02f --- /dev/null +++ b/docs/en/how-to/data/dynamic-data/index.html @@ -0,0 +1,83 @@ + + + + + + + Dynamic Data - Data - How To Guides - Handbook - Apache ECharts + + +

Asynchronous Data Loading and Dynamic Update

Asynchronous Loading

Data in Getting Started Example is directly updated by using setOption. But in many cases, the data needs to be filled by asynchronous loading frequently. ECharts can implement asynchronous loading in a simple way. You can get data asynchronously through a function such as jQuery and use setOption to fill in data and configs after the chart initialized.

var myChart = echarts.init(document.getElementById('main'));
+
+$.get('data.json').done(function(data) {
+  // Structure of data:
+  // {
+  //     categories: ["Shirt","Wool sweater","Chiffon shirt","Pants","High-heeled shoes","socks"],
+  //     values: [5, 20, 36, 10, 10, 20]
+  // }
+  myChart.setOption({
+    title: {
+      text: 'Asynchronous Loading Example'
+    },
+    tooltip: {},
+    legend: {},
+    xAxis: {
+      data: data.categories
+    },
+    yAxis: {},
+    series: [
+      {
+        name: 'Sales',
+        type: 'bar',
+        data: data.values
+      }
+    ]
+  });
+});

Or display empty axes with all styles defined before fill in the data:

var myChart = echarts.init(document.getElementById('main'));
+// Show title, legends and empty axes
+myChart.setOption({
+  title: {
+    text: 'Asynchronous Loading Example'
+  },
+  tooltip: {},
+  legend: {
+    data: ['Sales']
+  },
+  xAxis: {
+    data: []
+  },
+  yAxis: {},
+  series: [
+    {
+      name: 'Sales',
+      type: 'bar',
+      data: []
+    }
+  ]
+});
+
+// Asynchronous Data Loading
+$.get('data.json').done(function(data) {
+  // Fill in the data
+  myChart.setOption({
+    xAxis: {
+      data: data.categories
+    },
+    series: [
+      {
+        // Find series by name
+        name: 'Sales',
+        data: data.data
+      }
+    ]
+  });
+});

For example:

You need to use name to "navigate" ECharts when updating data. In the previous example, the chart can update normally depending on the order of series, but we recommend you to add the name data while updating data.

loading Animation

When it takes a long time to load the data, the user is facing the empty chart with only axes will wonder if there is a bug.

ECharts have a simple loading animation by default. You can call showLoading to display. When the data loading was completed, call hideLoading to hide the animation.

myChart.showLoading();
+$.get('data.json').done(function (data) {
+    myChart.hideLoading();
+    myChart.setOption(...);
+});

Here is the effect:

Dynamic Update

ECharts was driven by data, change in data will drive changes in the presentation of the chart. Therefore, It's surprisingly simple to implement a dynamic update.

All data's updates were implemented by setOption. You only need to fetch the data periodically. ECharts will find the difference between two groups of data to use the proper way to choose the animation.

Check the following example.

Contributors Edit this page on GitHub

yhoiseth yhoisethpissang pissangballoon72 balloon72
+ + + + + diff --git a/docs/en/how-to/interaction/coarse-pointer/index.html b/docs/en/how-to/interaction/coarse-pointer/index.html new file mode 100644 index 000000000..56a71941c --- /dev/null +++ b/docs/en/how-to/interaction/coarse-pointer/index.html @@ -0,0 +1,15 @@ + + + + + + + Intelligent Pointer Snapping - Interaction - How To Guides - Handbook - Apache ECharts + + +

Intelligent Pointer Snapping

Some interactive elements may be relatively small in charts, so sometimes it is difficult for users to click and do other operations accurately, especially on the mobile. Therefore, in Apache EChartsTM 5.4.0, we introduced the concept of "intelligent pointer snapping".

Starting from this version, by default, ECharts enables pointer snapping for mobile charts and disables it for non-mobile charts.

If it needs to be enabled for all platforms, it can be achieved by setting opt.useCoarsePointer to true in init; set to false is turned off for all platforms.

Snapping Algorithm

When a mouse or touch event occurs, ECharts will determine whether it is intersecting with an interactive element based on the position of the mouse or touch. If it is, the element is the object to be interacted with, which is the same logic before this optimization. If not, find an element that is closest to the mouse or touch position within a certain range.

The default range is 44px (see W3C standard), developers can set this value through opt.pointerSize when init.

More specifically, ECharts will loop through different angles and different radii (within opt.pointerSize) around the mouse or touch position until it finds an element that intersects it. If found, the element is considered to be the interactive object.

That is, if an element is within the opt.pointerSize radius of the mouse or touch position, the closest intersected element is considered the interactive object.

Performance

As for the implementation, we first judge the intersection between the mouse or touch position and the AABB bounding box of all interactive elements, so as to quickly eliminate most of the elements that is not intersecting. Then, we perform an accurate path intersection judgment on the remaining elements. Therefore, from the perspective of user experience, there is hardly any perceivable performance loss.

For chart series with large-scale data (that is, bar charts, scatter charts, etc. with large: true enabled), the snapping will not be enabled.

Contributors Edit this page on GitHub

Ovilia Oviliaplainheart plainheart
+ + + + + diff --git a/docs/en/how-to/interaction/drag/index.html b/docs/en/how-to/interaction/drag/index.html new file mode 100644 index 000000000..8dfeb7089 --- /dev/null +++ b/docs/en/how-to/interaction/drag/index.html @@ -0,0 +1,219 @@ + + + + + + + Drag - Interaction - How To Guides - Handbook - Apache ECharts + + +

An Example: Implement Dragging

This is a tiny example, introducing how to implement dragging of graphic elements in Apache EChartsTM. From this example, we will see how to make an application with rich intractivity based on echarts API.

This example mainly implements that dragging points of a curve and by which the curve is modified. Although it is simple example, but we can do more based on that, like edit charts viually. So let's get started from this simple example.

Implement basic dragging

First of all, we create a basic line chart (line series):

var symbolSize = 20;
+var data = [
+  [15, 0],
+  [-50, 10],
+  [-56.5, 20],
+  [-46.5, 30],
+  [-22.1, 40]
+];
+
+myChart.setOption({
+  xAxis: {
+    min: -100,
+    max: 80,
+    type: 'value',
+    axisLine: { onZero: false }
+  },
+  yAxis: {
+    min: -30,
+    max: 60,
+    type: 'value',
+    axisLine: { onZero: false }
+  },
+  series: [
+    {
+      id: 'a',
+      type: 'line',
+      smooth: true,
+      // Set a big symbolSize for dragging convenience.
+      symbolSize: symbolSize,
+      data: data
+    }
+  ]
+});

Since the symbols in line is not draggable, we make them draggable by using graphic component to add draggable circular elements to symbols respectively.

myChart.setOption({
+  // Declare a graphic component, which contains some graphic elements
+  // with the type of 'circle'.
+  // Here we have used the method `echarts.util.map`, which has the same
+  // behavior as Array.prototype.map, and is compatible with ES5-.
+  graphic: echarts.util.map(data, function(dataItem, dataIndex) {
+    return {
+      // 'circle' means this graphic element is a shape of circle.
+      type: 'circle',
+
+      shape: {
+        // The radius of the circle.
+        r: symbolSize / 2
+      },
+      // Transform is used to located the circle. position:
+      // [x, y] means translate the circle to the position [x, y].
+      // The API `convertToPixel` is used to get the position of
+      // the circle, which will introduced later.
+      position: myChart.convertToPixel('grid', dataItem),
+
+      // Make the circle invisible (but mouse event works as normal).
+      invisible: true,
+      // Make the circle draggable.
+      draggable: true,
+      // Give a big z value, which makes the circle cover the symbol
+      // in line series.
+      z: 100,
+      // This is the event handler of dragging, which will be triggered
+      // repeatly while dragging. See more details below.
+      // A util method `echarts.util.curry` is used here to generate a
+      // new function the same as `onPointDragging`, except that the
+      // first parameter is fixed to be the `dataIndex` here.
+      ondrag: echarts.util.curry(onPointDragging, dataIndex)
+    };
+  })
+});

In the code above, API convertToPixel is used to convert data to its "pixel coodinate", based on which each graphic elements can be rendered on canvas. The term "pixel coodinate" means the coordinate is in canvas pixel, whose origin is the top-left of the canvas. In the sentence myChart.convertToPixel('grid', dataItem), the first parameter 'grid' indicates that dataItem should be converted in the first grid component (cartesian).

Notice: convertToPixel should not be called before the first time that setOption called. Namely, it can only be used after coordinate systems (grid/polar/...) initialized.

Now points have been made draggable. Then we will bind event listeners on dragging to those points.

// This function will be called repeatly while dragging.
+// The mission of this function is to update `series.data` based on
+// the new points updated by dragging, and to re-render the line
+// series based on the new data, by which the graphic elements of the
+// line series can be synchronized with dragging.
+function onPointDragging(dataIndex) {
+  // Here the `data` is declared in the code block in the beginning
+  // of this article. The `this` refers to the dragged circle.
+  // `this.position` is the current position of the circle.
+  data[dataIndex] = myChart.convertFromPixel('grid', this.position);
+  // Re-render the chart based on the updated `data`.
+  myChart.setOption({
+    series: [
+      {
+        id: 'a',
+        data: data
+      }
+    ]
+  });
+}

In the code above, API convertFromPixel is used, which is the reversed process of convertToPixel. myChart.convertFromPixel('grid', this.position) converts a pixel coordinate to data item in grid (cartesian).

Finally, add those code to make graphic elements responsive to change of canvas size.

window.addEventListener('resize', function() {
+  // Re-calculate the position of each circle and update chart using `setOption`.
+  myChart.setOption({
+    graphic: echarts.util.map(data, function(item, dataIndex) {
+      return {
+        position: myChart.convertToPixel('grid', item)
+      };
+    })
+  });
+});

Add tooltip component

Now basic functionality have been implemented by parte 1. If we need the data can be displayed realtime when dragging, we can use tooltip component to do that. Nevertheless, tooltip component has its default "show/hide rule", which is not applicable in this case. So we need to customize the "show/hide rule" for our case.

Add these snippets to the code block above:

myChart.setOption({
+  // ...,
+  tooltip: {
+    // Means disable default "show/hide rule".
+    triggerOn: 'none',
+    formatter: function(params) {
+      return (
+        'X: ' +
+        params.data[0].toFixed(2) +
+        '<br>Y: ' +
+        params.data[1].toFixed(2)
+      );
+    }
+  }
+});
myChart.setOption({
+  graphic: data.map(function(item, dataIndex) {
+    return {
+      type: 'circle',
+      // ...,
+      // Customize "show/hide rule", show when mouse over, hide when mouse out.
+      onmousemove: echarts.util.curry(showTooltip, dataIndex),
+      onmouseout: echarts.util.curry(hideTooltip, dataIndex)
+    };
+  })
+});
+
+function showTooltip(dataIndex) {
+  myChart.dispatchAction({
+    type: 'showTip',
+    seriesIndex: 0,
+    dataIndex: dataIndex
+  });
+}
+
+function hideTooltip(dataIndex) {
+  myChart.dispatchAction({
+    type: 'hideTip'
+  });
+}

The API dispatchAction is used to show/hide tooltip content, where actions showTip and hideTip is dispatched.

Full code

Full code is shown as follow:

import echarts from 'echarts';
+
+var symbolSize = 20;
+var data = [
+  [15, 0],
+  [-50, 10],
+  [-56.5, 20],
+  [-46.5, 30],
+  [-22.1, 40]
+];
+var myChart = echarts.init(document.getElementById('main'));
+myChart.setOption({
+  tooltip: {
+    triggerOn: 'none',
+    formatter: function(params) {
+      return (
+        'X: ' +
+        params.data[0].toFixed(2) +
+        '<br />Y: ' +
+        params.data[1].toFixed(2)
+      );
+    }
+  },
+  xAxis: { min: -100, max: 80, type: 'value', axisLine: { onZero: false } },
+  yAxis: { min: -30, max: 60, type: 'value', axisLine: { onZero: false } },
+  series: [
+    { id: 'a', type: 'line', smooth: true, symbolSize: symbolSize, data: data }
+  ]
+});
+myChart.setOption({
+  graphic: echarts.util.map(data, function(item, dataIndex) {
+    return {
+      type: 'circle',
+      position: myChart.convertToPixel('grid', item),
+      shape: { r: symbolSize / 2 },
+      invisible: true,
+      draggable: true,
+      ondrag: echarts.util.curry(onPointDragging, dataIndex),
+      onmousemove: echarts.util.curry(showTooltip, dataIndex),
+      onmouseout: echarts.util.curry(hideTooltip, dataIndex),
+      z: 100
+    };
+  })
+});
+window.addEventListener('resize', function() {
+  myChart.setOption({
+    graphic: echarts.util.map(data, function(item, dataIndex) {
+      return { position: myChart.convertToPixel('grid', item) };
+    })
+  });
+});
+function showTooltip(dataIndex) {
+  myChart.dispatchAction({
+    type: 'showTip',
+    seriesIndex: 0,
+    dataIndex: dataIndex
+  });
+}
+function hideTooltip(dataIndex) {
+  myChart.dispatchAction({ type: 'hideTip' });
+}
+function onPointDragging(dataIndex, dx, dy) {
+  data[dataIndex] = myChart.convertFromPixel('grid', this.position);
+  myChart.setOption({
+    series: [
+      {
+        id: 'a',
+        data: data
+      }
+    ]
+  });
+}

With knowledge introduced above, more feature can be implemented. For example, dataZoom component can be added to cooperate with the cartesian, or we can make a plotting board on coordinate systems. Use your imagination ~

Contributors Edit this page on GitHub

Ovilia Oviliapissang pissang
+ + + + + diff --git a/docs/en/how-to/label/rich-text/index.html b/docs/en/how-to/label/rich-text/index.html new file mode 100644 index 000000000..b1b2f1e7c --- /dev/null +++ b/docs/en/how-to/label/rich-text/index.html @@ -0,0 +1,657 @@ + + + + + + + Rich Text - Label - How To Guides - Handbook - Apache ECharts + + +

Rich Text

Rich text can be used in Apache EChartsTM labels of series, axis or other components since v3.7. Which supports:

  • Box styles (background, border, shadow, etc.), rotation, position of a text block can be specified.
  • Styles (color, font, width/height, background, shadow, etc.) and alignment can be customzied on fragments of text.
  • Image can be used in text as icon or background.
  • Combine these configurations, some special effects can be made, such as simple table, horizontal rule (hr).

At the beginning, the meanings of two terms that will be used below should be clarified:

  • Text Block: The whole block of label text.
  • Text fragment: Some piece of text in a text block.

For example:

Options about Text

echarts provides plenty of text options, including:

  • Basic font style: fontStyle, fontWeight, fontSize, fontFamily.
  • Fill of text: color.
  • Stroke of text: textBorderColor, textBorderWidth.
  • Shadow of text: textShadowColor, textShadowBlur, textShadowOffsetX, textShadowOffsetY.
  • Box size of text block or text fragment: lineHeight, width, height, padding.
  • Alignment of text block or text fragment: align, verticalAlign.
  • Border, background (color or image) of text block or text fragment: backgroundColor, borderColor, borderWidth, borderRadius.
  • Shadow of text block or text fragment: shadowColor, shadowBlur, shadowOffsetX, shadowOffsetY.
  • Position and rotation of text block: position, distance, rotate.

User can defined styles for text fragment in rich property. For example, series-bar.label.rich

For example:

labelOption = {
+  // Styles defined in 'rich' can be applied to some fragments
+  // of text by adding some markers to those fragment, like
+  // `{styleName|text content text content}`.
+  // `'\n'` is the newline character.
+  formatter: [
+    '{a|Style "a" is applied to this fragment}',
+    '{b|Style "b" is applied to this fragment}This fragment use default style{x|use style "x"}'
+  ].join('\n'),
+
+  // Styles for the whole text block are defined here:
+  color: '#333',
+  fontSize: 5,
+  fontFamily: 'Arial',
+  borderWidth: 3,
+  backgroundColor: '#984455',
+  padding: [3, 10, 10, 5],
+  lineHeight: 20,
+
+  // Styles for text fragments are defined here:
+  rich: {
+    a: {
+      color: 'red',
+      lineHeight: 10
+    },
+    b: {
+      backgroundColor: {
+        image: 'xxx/xxx.jpg'
+      },
+      height: 40
+    },
+    x: {
+      fontSize: 18,
+      fontFamily: 'Microsoft YaHei',
+      borderColor: '#449933',
+      borderRadius: 4
+    }
+    // ...
+  }
+};

Notice: width and height only work when rich specified.

Basic Styles of Text, Text Block and Text Fragment

Basic font style can be set to text: fontStyle, fontWeight, fontSize, fontFamily.

Fill color and stroke color can be set to text: color, textBorderColor, textBorderWidth.

Border style and background style can be set to text block: borderColor, borderWidth, backgroundColor, padding.

Border style and background style can be set to text fragment too: borderColor, borderWidth, backgroundColor, padding.

For example:

option = {
+  series: [
+    {
+      type: 'scatter',
+      symbolSize: 1,
+      data: [
+        {
+          value: [0, 0],
+          label: {
+            show: true,
+            formatter: [
+              'Plain text',
+              '{textBorder|textBorderColor + textBorderWidth}',
+              '{textShadow|textShadowColor + textShadowBlur + textShadowOffsetX + textShadowOffsetY}',
+              '{bg|backgroundColor + borderRadius + padding}',
+              '{border|borderColor + borderWidth + borderRadius + padding}',
+              '{shadow|shadowColor + shadowBlur + shadowOffsetX + shadowOffsetY}'
+            ].join('\n'),
+            backgroundColor: '#eee',
+            borderColor: '#333',
+            borderWidth: 2,
+            borderRadius: 5,
+            padding: 10,
+            color: '#000',
+            fontSize: 14,
+            shadowBlur: 3,
+            shadowColor: '#888',
+            shadowOffsetX: 0,
+            shadowOffsetY: 3,
+            lineHeight: 30,
+            rich: {
+              textBorder: {
+                fontSize: 20,
+                textBorderColor: '#000',
+                textBorderWidth: 3,
+                color: '#fff'
+              },
+              textShadow: {
+                fontSize: 16,
+                textShadowBlur: 5,
+                textShadowColor: '#000',
+                textShadowOffsetX: 3,
+                textShadowOffsetY: 3,
+                color: '#fff'
+              },
+              bg: {
+                backgroundColor: '#339911',
+                color: '#fff',
+                borderRadius: 15,
+                padding: 5
+              },
+              border: {
+                color: '#000',
+                borderColor: '#449911',
+                borderWidth: 1,
+                borderRadius: 3,
+                padding: 5
+              },
+              shadow: {
+                backgroundColor: '#992233',
+                padding: 5,
+                color: '#fff',
+                shadowBlur: 5,
+                shadowColor: '#336699',
+                shadowOffsetX: 6,
+                shadowOffsetY: 6
+              }
+            }
+          }
+        }
+      ]
+    }
+  ],
+  xAxis: {
+    show: false,
+    min: -1,
+    max: 1
+  },
+  yAxis: {
+    show: false,
+    min: -1,
+    max: 1
+  }
+};
live

Label Position

label option can be use in charts like bar, line, scatter, etc. The position of a label, can be specified by label.positionlabel.distance.

Try to modify the position and distance option in the following example:

option = {
+  series: [
+    {
+      type: 'scatter',
+      symbolSize: 160,
+      symbol: 'roundRect',
+      data: [[1, 1]],
+      label: {
+        // Options: 'left', 'right', 'top', 'bottom', 'inside', 'insideTop', 'insideLeft', 'insideRight', 'insideBottom', 'insideTopLeft', 'insideTopRight', 'insideBottomLeft', 'insideBottomRight'
+        position: 'top',
+        distance: 10,
+
+        show: true,
+        formatter: ['Label Text'].join('\n'),
+        backgroundColor: '#eee',
+        borderColor: '#555',
+        borderWidth: 2,
+        borderRadius: 5,
+        padding: 10,
+        fontSize: 18,
+        shadowBlur: 3,
+        shadowColor: '#888',
+        shadowOffsetX: 0,
+        shadowOffsetY: 3,
+        textBorderColor: '#000',
+        textBorderWidth: 3,
+        color: '#fff'
+      }
+    }
+  ],
+  xAxis: {
+    max: 2
+  },
+  yAxis: {
+    max: 2
+  }
+};
live

Notice, there are different optional values of position by different chart types. And distance is not supported in every chart. More detailed info can be checked in option doc.

Label Rotation

Sometimes label is needed to be rotated. For example:

const labelOption = {
+  show: true,
+  rotate: 90,
+  formatter: '{c}  {name|{a}}',
+  fontSize: 16,
+  rich: {
+    name: {}
+  }
+};
+
+option = {
+  xAxis: [
+    {
+      type: 'category',
+      data: ['2012', '2013', '2014', '2015', '2016']
+    }
+  ],
+  yAxis: [
+    {
+      type: 'value'
+    }
+  ],
+  series: [
+    {
+      name: 'Forest',
+      type: 'bar',
+      barGap: 0,
+      label: labelOption,
+      emphasis: {
+        focus: 'series'
+      },
+      data: [320, 332, 301, 334, 390]
+    },
+    {
+      name: 'Steppe',
+      type: 'bar',
+      label: labelOption,
+      emphasis: {
+        focus: 'series'
+      },
+      data: [220, 182, 191, 234, 290]
+    }
+  ]
+};
live

align andverticalAlign can be used to adjust location of label in this scenario.

Notice, align and verticalAlign are applied firstly, then rotate.

Layout and Alignment of Text fragment

To understand the layout rule, every text fragment can be imagined as a inline-block dom element in CSS.

content box size of a text fragment is determined by its font size by default. It can also be specified directly by width and height, although they are rarely set. border box size of a text fragment is calculated by adding the border box size and padding.

Only '\n' is the newline character, which breaks a line.

Multiple text fragment exist in a single line. The height of a line is determined by the biggest lineHeight of text fragments. lineHeight of a text fragment can be specified in rich, or in the parent level of rich, otherwise using box size of the text fragment.

Having lineHeight determined, the vertical position of text fragments can be determined by verticalAlign (there is a little different from the rule in CSS):

  • 'bottom': The bottom edge of the text fragment sticks to the bottom edge of the line.
  • 'top': The top edge of the text fragment sticks to the top edge of the line.
  • 'middle': In the middle of the line.

The width of a text block can be specified by width, otherwise, by the longest line. Having the width determined, text fragment can be placed in each line, where the horizontal position of text fragments can be determined by its align.

  • Firstly, place text fragments whose align is 'left' from left to right continuously.
  • Secondly, place text fragments whose align is 'right' from right to left continuously.
  • Finally, the text fragments remained will be sticked and placed in the center of the rest of space.

The position of text in a text fragment:

  • If align is 'center', text aligns at the center of the text fragment box.
  • If align is 'left', text aligns at the left of the text fragment box.
  • If align is 'right', text aligns at the right of the text fragment box.

Effects: Icon, Horizontal Rule, Title Block, Simple Table

See example:

option = {
+  series: [
+    {
+      type: 'scatter',
+      data: [
+        {
+          value: [0, 0],
+          label: {
+            formatter: [
+              '{tc|Center Title}{titleBg|}',
+              '  Content text xxxxxxxx {sunny|} xxxxxxxx {cloudy|}  ',
+              '{hr|}',
+              '  xxxxx {showers|} xxxxxxxx  xxxxxxxxx  '
+            ].join('\n'),
+            rich: {
+              titleBg: {
+                align: 'right'
+              }
+            }
+          }
+        },
+        {
+          value: [0, 1],
+          label: {
+            formatter: [
+              '{titleBg|Left Title}',
+              '  Content text xxxxxxxx {sunny|} xxxxxxxx {cloudy|}  ',
+              '{hr|}',
+              '  xxxxx {showers|} xxxxxxxx  xxxxxxxxx  '
+            ].join('\n')
+          }
+        },
+        {
+          value: [0, 2],
+          label: {
+            formatter: [
+              '{titleBg|Right Title}',
+              '  Content text xxxxxxxx {sunny|} xxxxxxxx {cloudy|}  ',
+              '{hr|}',
+              '  xxxxx {showers|} xxxxxxxx  xxxxxxxxx  '
+            ].join('\n'),
+            rich: {
+              titleBg: {
+                align: 'right'
+              }
+            }
+          }
+        }
+      ],
+      symbolSize: 1,
+      label: {
+        show: true,
+        backgroundColor: '#ddd',
+        borderColor: '#555',
+        borderWidth: 1,
+        borderRadius: 5,
+        color: '#000',
+        fontSize: 14,
+        rich: {
+          titleBg: {
+            backgroundColor: '#000',
+            height: 30,
+            borderRadius: [5, 5, 0, 0],
+            padding: [0, 10, 0, 10],
+            width: '100%',
+            color: '#eee'
+          },
+          tc: {
+            align: 'center',
+            color: '#eee'
+          },
+          hr: {
+            borderColor: '#777',
+            width: '100%',
+            borderWidth: 0.5,
+            height: 0
+          },
+          sunny: {
+            height: 30,
+            align: 'left',
+            backgroundColor: {
+              image:
+                'https://echarts.apache.org/examples/data/asset/img/weather/sunny_128.png'
+            }
+          },
+          cloudy: {
+            height: 30,
+            align: 'left',
+            backgroundColor: {
+              image:
+                'https://echarts.apache.org/examples/data/asset/img/weather/cloudy_128.png'
+            }
+          },
+          showers: {
+            height: 30,
+            align: 'left',
+            backgroundColor: {
+              image:
+                'https://echarts.apache.org/examples/data/asset/img/weather/showers_128.png'
+            }
+          }
+        }
+      }
+    }
+  ],
+  xAxis: {
+    show: false,
+    min: -1,
+    max: 1
+  },
+  yAxis: {
+    show: false,
+    min: 0,
+    max: 2,
+    inverse: true
+  }
+};
live

Icon is implemented by using image in backgroundColor.

rich: {
+    Sunny: {
+        backgroundColor: {
+            image: './data/asset/img/weather/sunny_128.png'
+        },
+        // Can only height specified, but leave width auto obtained
+        // from the image, where the aspect ratio kept.
+        height: 30
+    }
+}

Horizontal rule (like HTML <hr> tag) can be implemented by border:

rich: {
+    hr: {
+        borderColor: '#777',
+        // width is set as '100%' to fullfill the text block.
+        // Notice, the percentage is based on the content box, without
+        // padding. Although it is a little different from CSS rule,
+        // it is convinent in most cases.
+        width: '100%',
+        borderWidth: 0.5,
+        height: 0
+    }
+}

Title block can be implemented by backgroundColor:

// Title is at left.
+formatter: '{titleBg|Left Title}',
+rich: {
+    titleBg: {
+        backgroundColor: '#000',
+        height: 30,
+        borderRadius: [5, 5, 0, 0],
+        padding: [0, 10, 0, 10],
+        width: '100%',
+        color: '#eee'
+    }
+}
+
+// Title is in the center of the line.
+// This implementation is a little tricky, but is works
+// without more complicated layout mechanism involved.
+formatter: '{tc|Center Title}{titleBg|}',
+rich: {
+    titleBg: {
+        align: 'right',
+        backgroundColor: '#000',
+        height: 30,
+        borderRadius: [5, 5, 0, 0],
+        padding: [0, 10, 0, 10],
+        width: '100%',
+        color: '#eee'
+    }
+}

Simple table can be implemented by specify the same width to text fragments that are in the same column of different lines. See the example.

Contributors Edit this page on GitHub

plainheart plainheartTSinChen TSinChenpissang pissang
+ + + + + diff --git a/docs/en/index.html b/docs/en/index.html new file mode 100644 index 000000000..3842e6d57 --- /dev/null +++ b/docs/en/index.html @@ -0,0 +1,15 @@ + + + + + + + Handbook - Apache ECharts + + + + + + + + diff --git a/docs/en/meta/edit-guide/index.html b/docs/en/meta/edit-guide/index.html new file mode 100644 index 000000000..185152df6 --- /dev/null +++ b/docs/en/meta/edit-guide/index.html @@ -0,0 +1,155 @@ + + + + + + + Edit Guide - Edit Handbook - Handbook - Apache ECharts + + +

Document Editing Guidelines

Adding a Markdown File

Add a markdown file to the contents/zh/ (Chinese posts) or contents/en/ (English posts) directories, up to three levels. Update the path and title information in contents/zh/posts.yml or contents/en/posts.yml.

Lowercase markdown file names.

Using Prettier to Automatically Format Code

Before you start, we recommend installing the prettier VSCode plugin, which will automatically format the code for you when you save it.

If you feel that the automatic formatting is breaking your code block, you can add the following comment to prevent prettier from formatting the code inside the block

<!-- prettier-ignore-start -->
+<!-- prettier-ignore-end -->

If you find blocks of code that are not formatted, check first for syntax errors in the code.

Built-in Variables

  • optionPath
  • mainSitePath
  • exampleViewPath
  • exampleEditorPath
  • lang

Usage:

${xxxxx}
+
[Get Apache ECharts](${lang}/basics/download)

Get Apache ECharts

Embedding Code

Basic Usage

```js
+option = {
+    series: [{
+        type: 'bar',
+        data: [23, 24, 18, 25, 27, 28, 25]
+    }]
+};
+\```
option = {
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};

In order to allow the tool to help us format the code, we should try to avoid syntactically problematic writing styles.

For example, the comment ...

option = {
+  series: [
+    {
+      type: 'bar'
+      // ...
+    }
+  ]
+};

Live Preview and Editing

Currently only preview of Option code is supported

\```js live
+option = {
+  xAxis: {
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};
+\```
option = {
+  xAxis: {
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};
live

More Preview Layouts

Left to Right

<md-live lang="js" code="'b3B0aW9uID0gewogIC4uLgp9OwpcYGBg'" v-bind="{layout: 'lr'}" />
+
+<!-- prettier-ignore-end -->
+
+<md-live lang="js" code="'b3B0aW9uID0gewogIHhBeGlzOiB7CiAgICBkYXRhOiBbJ01vbicsICdUdWUnLCAnV2VkJywgJ1RodScsICdGcmknLCAnU2F0JywgJ1N1biddCiAgfSwKICB5QXhpczoge30sCiAgc2VyaWVzOiBbCiAgICB7CiAgICAgIHR5cGU6ICdiYXInLAogICAgICBkYXRhOiBbMjMsIDI0LCAxOCwgMjUsIDI3LCAyOCwgMjVdCiAgICB9CiAgXQp9Ow'" v-bind="{layout: 'lr'}" />
+
+#### Right to left
+
+<!-- prettier-ignore-start -->
markdown +
option = {
+  ...
+};
+\```
live

option = {
+  xAxis: {
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};
live

Down to Up

<md-live lang="js" code="'b3B0aW9uID0gewogIC4uLgp9OwpcYGBg'" v-bind="{layout: 'bt'}" />
+
+<!-- prettier-ignore-end -->
+
+<md-live lang="js" code="'b3B0aW9uID0gewogIHhBeGlzOiB7CiAgICBkYXRhOiBbJ01vbicsICdUdWUnLCAnV2VkJywgJ1RodScsICdGcmknLCAnU2F0JywgJ1N1biddCiAgfSwKICB5QXhpczoge30sCiAgc2VyaWVzOiBbCiAgICB7CiAgICAgIHR5cGU6ICdiYXInLAogICAgICBkYXRhOiBbMjMsIDI0LCAxOCwgMjUsIDI3LCAyOCwgMjVdCiAgICB9CiAgXQp9Ow'" v-bind="{layout: 'bt'}" />
+
+### Highlighting Lines of Code and Adding Filenames
+
+Use.
+
+<!-- prettier-ignore-start -->
markdown

option = {
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};
+\```
+

Effects.

option = {
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};
+

Embedding Images

Source images are stored under static/images/.

![image description](images/demo.png)

Set the Image Height and Width

For the temporary style of the current page, you can just write html.

<img data-src="images/demo.png" style="width: 50px" />

Add Example Iframe

src is the string after ?c= in the https://echarts.apache.org/examples/en/editor.html?c=line-simple address

Use:

<md-example src="doc-example/getting-started" width="100%" height="300"></md-example>

Result: +

Use:

<md-option link="series-bar.itemStyle.color"></md-option>

Result: +series-bar.itemStyle.color

More Component Usage

The documentation supports the use of globally registered markdown components. In addition to the md-example component just described, the following components are also available

md-alert

Prompt components

<md-alert type="info">
+This is an info alert.
+</md-alert>

+This is an info alert. +

<md-alert type="success">
+This is a success alert.
+</md-alert>

+This is a success alert. +

<md-alert type="warning">
+This is a warning alert.
+</md-alert>

+This is a warning alert. +

<md-alert type="danger">
+This is a danger alert.
+</md-alert>

+This is a danger alert. +

Contributors Edit this page on GitHub

pissang pissangplainheart plainheart
+ + + + + diff --git a/docs/images/5-2-0/group-transition-2.gif b/docs/images/5-2-0/group-transition-2.gif new file mode 100644 index 000000000..caf3dd7e2 Binary files /dev/null and b/docs/images/5-2-0/group-transition-2.gif differ diff --git a/docs/images/5-2-0/group-transition.gif b/docs/images/5-2-0/group-transition.gif new file mode 100644 index 000000000..8d13ee96b Binary files /dev/null and b/docs/images/5-2-0/group-transition.gif differ diff --git a/docs/images/5-2-0/polar-bar-label.jpg b/docs/images/5-2-0/polar-bar-label.jpg new file mode 100644 index 000000000..ee6853d8c Binary files /dev/null and b/docs/images/5-2-0/polar-bar-label.jpg differ diff --git a/docs/images/5-2-0/universal-transition-2.gif b/docs/images/5-2-0/universal-transition-2.gif new file mode 100644 index 000000000..9b7db8374 Binary files /dev/null and b/docs/images/5-2-0/universal-transition-2.gif differ diff --git a/docs/images/5-2-0/universal-transition-3.gif b/docs/images/5-2-0/universal-transition-3.gif new file mode 100644 index 000000000..8a7e2128b Binary files /dev/null and b/docs/images/5-2-0/universal-transition-3.gif differ diff --git a/docs/images/5-2-0/universal-transition.gif b/docs/images/5-2-0/universal-transition.gif new file mode 100644 index 000000000..bbb46a33c Binary files /dev/null and b/docs/images/5-2-0/universal-transition.gif differ diff --git a/docs/images/5-3-0/map-projection.gif b/docs/images/5-3-0/map-projection.gif new file mode 100644 index 000000000..188b8f622 Binary files /dev/null and b/docs/images/5-3-0/map-projection.gif differ diff --git a/docs/images/5-3-0/pie-label-after.png b/docs/images/5-3-0/pie-label-after.png new file mode 100644 index 000000000..d08ec4a51 Binary files /dev/null and b/docs/images/5-3-0/pie-label-after.png differ diff --git a/docs/images/5-3-0/pie-label-after2.png b/docs/images/5-3-0/pie-label-after2.png new file mode 100644 index 000000000..d52ce38a3 Binary files /dev/null and b/docs/images/5-3-0/pie-label-after2.png differ diff --git a/docs/images/5-3-0/pie-label-before.png b/docs/images/5-3-0/pie-label-before.png new file mode 100644 index 000000000..1e05cd63f Binary files /dev/null and b/docs/images/5-3-0/pie-label-before.png differ diff --git a/docs/images/5-3-0/pie-label-before2.png b/docs/images/5-3-0/pie-label-before2.png new file mode 100644 index 000000000..3d74681b0 Binary files /dev/null and b/docs/images/5-3-0/pie-label-before2.png differ diff --git a/docs/images/5-3-0/svg-after.gif b/docs/images/5-3-0/svg-after.gif new file mode 100644 index 000000000..94b419762 Binary files /dev/null and b/docs/images/5-3-0/svg-after.gif differ diff --git a/docs/images/5-3-0/svg-before.gif b/docs/images/5-3-0/svg-before.gif new file mode 100644 index 000000000..7f13dbe89 Binary files /dev/null and b/docs/images/5-3-0/svg-before.gif differ diff --git a/docs/images/5-4-0/pie-amap.png b/docs/images/5-4-0/pie-amap.png new file mode 100644 index 000000000..64f701296 Binary files /dev/null and b/docs/images/5-4-0/pie-amap.png differ diff --git a/docs/images/5-4-0/pie-bmap.png b/docs/images/5-4-0/pie-bmap.png new file mode 100644 index 000000000..45012e38b Binary files /dev/null and b/docs/images/5-4-0/pie-bmap.png differ diff --git a/docs/images/5-4-0/pie-calendar.png b/docs/images/5-4-0/pie-calendar.png new file mode 100644 index 000000000..4e1ddea59 Binary files /dev/null and b/docs/images/5-4-0/pie-calendar.png differ diff --git a/docs/images/5-4-0/pie-geo.png b/docs/images/5-4-0/pie-geo.png new file mode 100644 index 000000000..0457ee174 Binary files /dev/null and b/docs/images/5-4-0/pie-geo.png differ diff --git a/docs/images/5-4-0/pie-grid.png b/docs/images/5-4-0/pie-grid.png new file mode 100644 index 000000000..874e46465 Binary files /dev/null and b/docs/images/5-4-0/pie-grid.png differ diff --git a/docs/images/5-5-0/ssr-example.png b/docs/images/5-5-0/ssr-example.png new file mode 100644 index 000000000..ab3403850 Binary files /dev/null and b/docs/images/5-5-0/ssr-example.png differ diff --git a/docs/images/demo.png b/docs/images/demo.png new file mode 100644 index 000000000..478f54860 Binary files /dev/null and b/docs/images/demo.png differ diff --git a/docs/images/design/axis/charts_axis_img01.jpg b/docs/images/design/axis/charts_axis_img01.jpg new file mode 100644 index 000000000..b2ceeae31 Binary files /dev/null and b/docs/images/design/axis/charts_axis_img01.jpg differ diff --git a/docs/images/design/axis/charts_axis_img02.jpg b/docs/images/design/axis/charts_axis_img02.jpg new file mode 100644 index 000000000..1c605cd2d Binary files /dev/null and b/docs/images/design/axis/charts_axis_img02.jpg differ diff --git a/docs/images/design/axis/charts_axis_img02.png b/docs/images/design/axis/charts_axis_img02.png new file mode 100644 index 000000000..bbb445f1e Binary files /dev/null and b/docs/images/design/axis/charts_axis_img02.png differ diff --git a/docs/images/design/axis/charts_axis_img04.png b/docs/images/design/axis/charts_axis_img04.png new file mode 100644 index 000000000..35711b9ab Binary files /dev/null and b/docs/images/design/axis/charts_axis_img04.png differ diff --git a/docs/images/design/axis/charts_axis_img05.png b/docs/images/design/axis/charts_axis_img05.png new file mode 100644 index 000000000..5bd9f05af Binary files /dev/null and b/docs/images/design/axis/charts_axis_img05.png differ diff --git a/docs/images/design/axis/charts_axis_img07.png b/docs/images/design/axis/charts_axis_img07.png new file mode 100644 index 000000000..70f96694a Binary files /dev/null and b/docs/images/design/axis/charts_axis_img07.png differ diff --git a/docs/images/design/axis/charts_axis_img10.png b/docs/images/design/axis/charts_axis_img10.png new file mode 100644 index 000000000..e4b2ae073 Binary files /dev/null and b/docs/images/design/axis/charts_axis_img10.png differ diff --git a/docs/images/design/axis/charts_axis_img12.png b/docs/images/design/axis/charts_axis_img12.png new file mode 100644 index 000000000..11422944f Binary files /dev/null and b/docs/images/design/axis/charts_axis_img12.png differ diff --git a/docs/images/design/bar/bar01.jpg b/docs/images/design/bar/bar01.jpg new file mode 100644 index 000000000..3e569f7a7 Binary files /dev/null and b/docs/images/design/bar/bar01.jpg differ diff --git a/docs/images/design/bar/bar02.jpg b/docs/images/design/bar/bar02.jpg new file mode 100644 index 000000000..392e310c0 Binary files /dev/null and b/docs/images/design/bar/bar02.jpg differ diff --git a/docs/images/design/bar/bar03.jpg b/docs/images/design/bar/bar03.jpg new file mode 100644 index 000000000..1799fad39 Binary files /dev/null and b/docs/images/design/bar/bar03.jpg differ diff --git a/docs/images/design/bar/bar04.jpg b/docs/images/design/bar/bar04.jpg new file mode 100644 index 000000000..1e310abae Binary files /dev/null and b/docs/images/design/bar/bar04.jpg differ diff --git a/docs/images/design/bi-directional-bar/bi-directional-bar01.jpg b/docs/images/design/bi-directional-bar/bi-directional-bar01.jpg new file mode 100755 index 000000000..392e310c0 Binary files /dev/null and b/docs/images/design/bi-directional-bar/bi-directional-bar01.jpg differ diff --git a/docs/images/design/bi-directional-bar/bi-directional-bar02.jpg b/docs/images/design/bi-directional-bar/bi-directional-bar02.jpg new file mode 100755 index 000000000..2c175143f Binary files /dev/null and b/docs/images/design/bi-directional-bar/bi-directional-bar02.jpg differ diff --git a/docs/images/design/color/color01.png b/docs/images/design/color/color01.png new file mode 100644 index 000000000..35ac64d55 Binary files /dev/null and b/docs/images/design/color/color01.png differ diff --git a/docs/images/design/color/color02.png b/docs/images/design/color/color02.png new file mode 100644 index 000000000..63984038b Binary files /dev/null and b/docs/images/design/color/color02.png differ diff --git a/docs/images/design/color/color03.png b/docs/images/design/color/color03.png new file mode 100644 index 000000000..9afa664e6 Binary files /dev/null and b/docs/images/design/color/color03.png differ diff --git a/docs/images/design/color/color04.png b/docs/images/design/color/color04.png new file mode 100644 index 000000000..63939e029 Binary files /dev/null and b/docs/images/design/color/color04.png differ diff --git a/docs/images/design/legend/charts_sign_img01.png b/docs/images/design/legend/charts_sign_img01.png new file mode 100644 index 000000000..223a64bcc Binary files /dev/null and b/docs/images/design/legend/charts_sign_img01.png differ diff --git a/docs/images/design/legend/charts_sign_img02.png b/docs/images/design/legend/charts_sign_img02.png new file mode 100644 index 000000000..419a2ca7b Binary files /dev/null and b/docs/images/design/legend/charts_sign_img02.png differ diff --git a/docs/images/design/legend/charts_sign_img03.png b/docs/images/design/legend/charts_sign_img03.png new file mode 100644 index 000000000..9afd2411d Binary files /dev/null and b/docs/images/design/legend/charts_sign_img03.png differ diff --git a/docs/images/design/legend/charts_sign_img04.png b/docs/images/design/legend/charts_sign_img04.png new file mode 100644 index 000000000..1f5b91062 Binary files /dev/null and b/docs/images/design/legend/charts_sign_img04.png differ diff --git a/docs/images/design/line/line01.jpg b/docs/images/design/line/line01.jpg new file mode 100644 index 000000000..dff5cfd08 Binary files /dev/null and b/docs/images/design/line/line01.jpg differ diff --git a/docs/images/design/pie/pie01.jpg b/docs/images/design/pie/pie01.jpg new file mode 100644 index 000000000..375a0fb59 Binary files /dev/null and b/docs/images/design/pie/pie01.jpg differ diff --git a/docs/images/design/pie/pie02.jpg b/docs/images/design/pie/pie02.jpg new file mode 100644 index 000000000..828577a28 Binary files /dev/null and b/docs/images/design/pie/pie02.jpg differ diff --git a/docs/images/design/pie/pie03.jpg b/docs/images/design/pie/pie03.jpg new file mode 100644 index 000000000..c519208bc Binary files /dev/null and b/docs/images/design/pie/pie03.jpg differ diff --git a/docs/images/design/pie/pie04.jpg b/docs/images/design/pie/pie04.jpg new file mode 100644 index 000000000..1980e344b Binary files /dev/null and b/docs/images/design/pie/pie04.jpg differ diff --git a/docs/images/design/scatter/scatter5.jpg b/docs/images/design/scatter/scatter5.jpg new file mode 100755 index 000000000..c077463ed Binary files /dev/null and b/docs/images/design/scatter/scatter5.jpg differ diff --git a/docs/images/feature-v5/dashboard-pointer.png b/docs/images/feature-v5/dashboard-pointer.png new file mode 100644 index 000000000..2dabc8fc6 Binary files /dev/null and b/docs/images/feature-v5/dashboard-pointer.png differ diff --git a/docs/images/feature-v5/dataZoom.png b/docs/images/feature-v5/dataZoom.png new file mode 100644 index 000000000..296963d7e Binary files /dev/null and b/docs/images/feature-v5/dataZoom.png differ diff --git a/docs/images/feature-v5/dirty-rect.gif b/docs/images/feature-v5/dirty-rect.gif new file mode 100644 index 000000000..8b0467a1e Binary files /dev/null and b/docs/images/feature-v5/dirty-rect.gif differ diff --git a/docs/images/feature-v5/dirty-rect.png b/docs/images/feature-v5/dirty-rect.png new file mode 100644 index 000000000..c7ee56db4 Binary files /dev/null and b/docs/images/feature-v5/dirty-rect.png differ diff --git a/docs/images/feature-v5/echarts-5-en.png b/docs/images/feature-v5/echarts-5-en.png new file mode 100644 index 000000000..120ce9cfc Binary files /dev/null and b/docs/images/feature-v5/echarts-5-en.png differ diff --git a/docs/images/feature-v5/echarts-5.png b/docs/images/feature-v5/echarts-5.png new file mode 100644 index 000000000..666d43ba2 Binary files /dev/null and b/docs/images/feature-v5/echarts-5.png differ diff --git a/docs/images/feature-v5/gauge-pointer.png b/docs/images/feature-v5/gauge-pointer.png new file mode 100644 index 000000000..2dabc8fc6 Binary files /dev/null and b/docs/images/feature-v5/gauge-pointer.png differ diff --git a/docs/images/feature-v5/new-theme-dark.png b/docs/images/feature-v5/new-theme-dark.png new file mode 100644 index 000000000..727a94295 Binary files /dev/null and b/docs/images/feature-v5/new-theme-dark.png differ diff --git a/docs/images/feature-v5/new-theme-light.png b/docs/images/feature-v5/new-theme-light.png new file mode 100644 index 000000000..a18e2ac3c Binary files /dev/null and b/docs/images/feature-v5/new-theme-light.png differ diff --git a/docs/images/feature-v5/new-tooltip-2 copy.png b/docs/images/feature-v5/new-tooltip-2 copy.png new file mode 100644 index 000000000..52d341803 Binary files /dev/null and b/docs/images/feature-v5/new-tooltip-2 copy.png differ diff --git a/docs/images/feature-v5/new-tooltip-2.png b/docs/images/feature-v5/new-tooltip-2.png new file mode 100644 index 000000000..be34cc1e9 Binary files /dev/null and b/docs/images/feature-v5/new-tooltip-2.png differ diff --git a/docs/images/feature-v5/new-tooltip.png b/docs/images/feature-v5/new-tooltip.png new file mode 100644 index 000000000..56ad86509 Binary files /dev/null and b/docs/images/feature-v5/new-tooltip.png differ diff --git a/docs/images/feature-v5/new-tooltip2.png b/docs/images/feature-v5/new-tooltip2.png new file mode 100644 index 000000000..52d341803 Binary files /dev/null and b/docs/images/feature-v5/new-tooltip2.png differ diff --git a/docs/images/feature-v5/pie-label copy.png b/docs/images/feature-v5/pie-label copy.png new file mode 100644 index 000000000..aee331521 Binary files /dev/null and b/docs/images/feature-v5/pie-label copy.png differ diff --git a/docs/images/feature-v5/pie-label-2.png b/docs/images/feature-v5/pie-label-2.png new file mode 100644 index 000000000..8c427b9bd Binary files /dev/null and b/docs/images/feature-v5/pie-label-2.png differ diff --git a/docs/images/feature-v5/pie-label.png b/docs/images/feature-v5/pie-label.png new file mode 100644 index 000000000..aee331521 Binary files /dev/null and b/docs/images/feature-v5/pie-label.png differ diff --git a/docs/images/feature-v5/theme-color.png b/docs/images/feature-v5/theme-color.png new file mode 100644 index 000000000..636c86834 Binary files /dev/null and b/docs/images/feature-v5/theme-color.png differ diff --git a/docs/images/feature-v5/time-axis-2.png b/docs/images/feature-v5/time-axis-2.png new file mode 100644 index 000000000..8bce19faa Binary files /dev/null and b/docs/images/feature-v5/time-axis-2.png differ diff --git a/docs/images/feature-v5/time-axis.png b/docs/images/feature-v5/time-axis.png new file mode 100644 index 000000000..00b7b00d3 Binary files /dev/null and b/docs/images/feature-v5/time-axis.png differ diff --git a/docs/images/feature-v5/time-axis2.png b/docs/images/feature-v5/time-axis2.png new file mode 100644 index 000000000..d89e441bf Binary files /dev/null and b/docs/images/feature-v5/time-axis2.png differ diff --git a/docs/images/feature-v5/timeline.png b/docs/images/feature-v5/timeline.png new file mode 100644 index 000000000..e38150de7 Binary files /dev/null and b/docs/images/feature-v5/timeline.png differ diff --git a/docs/images/feature-v5/yAxis-default-style-change.webp b/docs/images/feature-v5/yAxis-default-style-change.webp new file mode 100644 index 000000000..76823eb95 Binary files /dev/null and b/docs/images/feature-v5/yAxis-default-style-change.webp differ diff --git a/docs/images/how-to/coarse-pointer-en.gif b/docs/images/how-to/coarse-pointer-en.gif new file mode 100644 index 000000000..cf7085dcc Binary files /dev/null and b/docs/images/how-to/coarse-pointer-en.gif differ diff --git a/docs/images/how-to/coarse-pointer-zh.gif b/docs/images/how-to/coarse-pointer-zh.gif new file mode 100644 index 000000000..485bf192f Binary files /dev/null and b/docs/images/how-to/coarse-pointer-zh.gif differ diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 000000000..1ad930241 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,15 @@ + + + + + + + Handbook - Apache ECharts + + + + + + + + diff --git a/docs/zh/basics/download/index.html b/docs/zh/basics/download/index.html new file mode 100644 index 000000000..8857ac59c --- /dev/null +++ b/docs/zh/basics/download/index.html @@ -0,0 +1,15 @@ + + + + + + + 获取 ECharts - 入门篇 - 使用手册 - Apache ECharts + + +

获取 Apache ECharts

Apache ECharts 提供了多种安装方式,你可以根据项目的实际情况选择以下任意一种方式安装。

  • 从 GitHub 获取
  • 从 npm 获取
  • 从 CDN 获取
  • 在线定制

接下来我们将分别介绍这些安装方式,以及下载后的目录结构。

安装方式

从 npm 获取

npm install echarts

详见在项目中引入 Apache ECharts

从 CDN 获取

可以从以下免费 CDN 中获取和引用 ECharts。

从 GitHub 获取

apache/echarts 项目的 release 页面可以找到各个版本的链接。点击下载页面下方 Assets 中的 Source code,解压后 dist 目录下的 echarts.js 即为包含完整 ECharts 功能的文件。

在线定制

如果只想引入部分模块以减少包体积,可以使用 ECharts 在线定制功能。

本文贡献者 在 GitHub 上编辑本页

pissang pissangplainheart plainheartOvilia Ovilia100pah 100pah
+ + + + + diff --git a/docs/zh/basics/help/index.html b/docs/zh/basics/help/index.html new file mode 100644 index 000000000..9300e0e0c --- /dev/null +++ b/docs/zh/basics/help/index.html @@ -0,0 +1,15 @@ + + + + + + + 寻求帮助 - 入门篇 - 使用手册 - Apache ECharts + + +

寻求帮助

技术问题

确保现有文档等资料无法解决你的问题

ECharts 有非常大量的用户,所以你遇到过的问题很可能别人在此之前也遇到并解决了。通过查看文档以及使用搜索引擎搜索关键字,可以帮助你自助地在第一时间解决问题,而不需要依赖社区的帮助。

因此,在做其他操作前,请确保现有文档等资料无法解决你的问题。可以尝试查看或搜索的资料包括:

创建一个最简单可复现的例子

使用官方编辑器CodePenCodeSandboxJSFiddle 创建一个例子,这将使得他人更方便地复现你的问题。

例子应尽可能以最简单的方式复现你的问题,去除不必要的配置项和数据,可以让帮助你的人更快速地定位问题,从而让你的问题更快得到解决。更详细的介绍请参见 如何创建一个最小的可复现代码示例

判断是否是 bug

报告 bug 或请求新功能

如果不符合文档描述或你的预期效果,这很有可能是 bug。如果是 bug,或者你有一个想请求实现的功能,请使用 issue 模板 新建一个 issue 并按照提示详细描述。

咨询类问题

如果不是 bug,而是不知道如何实现某种效果,可以尝试在 stackoverflow.com开源中国SegmentFault 思否 等问答平台上提问。

如果没能得到答复,也可以发送邮件至邮件组 dev@echarts.apache.org。为了让更多人理解你的问题,并且在将来搜索的时候得到帮助,强烈建议使用英文发送邮件。

非技术类问题

其他问题可以发送英文邮件至邮件组 dev@echarts.apache.org

本文贡献者 在 GitHub 上编辑本页

plainheart plainheartOvilia Ovilia100pah 100pahpissang pissang
+ + + + + diff --git a/docs/zh/basics/import/index.html b/docs/zh/basics/import/index.html new file mode 100644 index 000000000..49f82ac8f --- /dev/null +++ b/docs/zh/basics/import/index.html @@ -0,0 +1,128 @@ + + + + + + + 在项目中引入 ECharts - 入门篇 - 使用手册 - Apache ECharts + + +

在项目中引入 Apache ECharts

假如你的开发环境使用了 npm 或者 yarn 等包管理工具,并且使用 webpack 等打包工具进行构建,本文将会介绍如何引入 Apache EChartsTM 并通过 tree-shaking 特性只打包需要的模块以减少包体积。

NPM 安装 ECharts

你可以使用如下命令通过 npm 安装 ECharts

npm install echarts --save

引入 ECharts

import * as echarts from 'echarts';
+
+// 基于准备好的dom,初始化echarts实例
+var myChart = echarts.init(document.getElementById('main'));
+// 绘制图表
+myChart.setOption({
+  title: {
+    text: 'ECharts 入门示例'
+  },
+  tooltip: {},
+  xAxis: {
+    data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
+  },
+  yAxis: {},
+  series: [
+    {
+      name: '销量',
+      type: 'bar',
+      data: [5, 20, 36, 10, 10, 20]
+    }
+  ]
+});

按需引入 ECharts 图表和组件

上面的代码会引入 ECharts 中所有的图表和组件,如果你不想引入所有组件,也可以使用 ECharts 提供的按需引入的接口来打包必须的组件。

// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
+import * as echarts from 'echarts/core';
+// 引入柱状图图表,图表后缀都为 Chart
+import { BarChart } from 'echarts/charts';
+// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
+import {
+  TitleComponent,
+  TooltipComponent,
+  GridComponent,
+  DatasetComponent,
+  TransformComponent
+} from 'echarts/components';
+// 标签自动布局、全局过渡动画等特性
+import { LabelLayout, UniversalTransition } from 'echarts/features';
+// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
+import { CanvasRenderer } from 'echarts/renderers';
+
+// 注册必须的组件
+echarts.use([
+  TitleComponent,
+  TooltipComponent,
+  GridComponent,
+  DatasetComponent,
+  TransformComponent,
+  BarChart,
+  LabelLayout,
+  UniversalTransition,
+  CanvasRenderer
+]);
+
+// 接下来的使用就跟之前一样,初始化图表,设置配置项
+var myChart = echarts.init(document.getElementById('main'));
+myChart.setOption({
+  // ...
+});

需要注意的是为了保证打包的体积是最小的,ECharts 按需引入的时候不再提供任何渲染器,所以需要选择引入 CanvasRenderer 或者 SVGRenderer 作为渲染器。这样的好处是假如你只需要使用 svg 渲染模式,打包的结果中就不会再包含无需使用的 CanvasRenderer 模块。

我们在示例编辑页的“完整代码”标签提供了非常方便的生成按需引入代码的功能。这个功能会根据当前的配置项动态生成最小的按需引入的代码。你可以直接在你的项目中使用。

v5.5.0 版本开始使用 ESM 作为默认的模块规范,查看可能的 Breaking Changes 以及 Pull Request

在 TypeScript 中按需引入

对于使用了 TypeScript 来开发 ECharts 的开发者,我们提供了类型接口来组合出最小的 EChartsOption 类型。这个更严格的类型可以有效帮助你检查出是否少加载了组件或者图表。

import * as echarts from 'echarts/core';
+import {
+  BarChart,
+  LineChart
+} from 'echarts/charts';
+import {
+  TitleComponent,
+  TooltipComponent,
+  GridComponent,
+  // 数据集组件
+  DatasetComponent,
+  // 内置数据转换器组件 (filter, sort)
+  TransformComponent
+} from 'echarts/components';
+import { LabelLayout, UniversalTransition } from 'echarts/features';
+import { CanvasRenderer } from 'echarts/renderers';
+import type {
+  // 系列类型的定义后缀都为 SeriesOption
+  BarSeriesOption,
+  LineSeriesOption
+} from 'echarts/charts';
+import type {
+  // 组件类型的定义后缀都为 ComponentOption
+  TitleComponentOption,
+  TooltipComponentOption,
+  GridComponentOption,
+  DatasetComponentOption
+} from 'echarts/components';
+import type {
+  ComposeOption,
+} from 'echarts/core';
+
+// 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型
+type ECOption = ComposeOption<
+  | BarSeriesOption
+  | LineSeriesOption
+  | TitleComponentOption
+  | TooltipComponentOption
+  | GridComponentOption
+  | DatasetComponentOption
+>;
+
+// 注册必须的组件
+echarts.use([
+  TitleComponent,
+  TooltipComponent,
+  GridComponent,
+  DatasetComponent,
+  TransformComponent,
+  BarChart,
+  LineChart,
+  LabelLayout,
+  UniversalTransition,
+  CanvasRenderer
+]);
+
+const option: ECOption = {
+  // ...
+};

本文贡献者 在 GitHub 上编辑本页

pissang pissangplainheart plainheartmichaelxiaohan michaelxiaohanOvilia Oviliaaimuz aimuzvueadmin vueadmingugujigua gugujiguabtea bteaYechuanjie Yechuanjie
+ + + + + diff --git a/docs/zh/basics/release-note/5-2-0/index.html b/docs/zh/basics/release-note/5-2-0/index.html new file mode 100644 index 000000000..805010f67 --- /dev/null +++ b/docs/zh/basics/release-note/5-2-0/index.html @@ -0,0 +1,593 @@ + + + + + + + 5.2 - 版本特性 - 入门篇 - 使用手册 - Apache ECharts + + +

Apache ECharts 5.2.0 特性介绍

全局过渡动画

在 Apache ECharts 中我们一直把自然流畅的过渡动画作为一个重要特性。通过避免数据带来的突变,不仅仅可以改善视觉效果,更为表达数据的关联和演变提供了可能。因此,在 5.2.0 中,我们进一步将过渡动画从表现系列内部数据的变化,泛化到全局能力。接下来,我们会看到这种全局过渡动画 Universal Transition是如何为图表增加表现力和叙事能力的。

在之前的版本中,过渡动画有一定的局限性:只能用于相同类型的图形的位置、尺寸、形状,而且只能作用在相同类型的系列上。比如,下面例子就是通过饼图中扇区形状的变化反映了数据分布的变化:

function makeRandomData() {
+  return [
+    {
+      value: Math.random(),
+      name: 'A'
+    },
+    {
+      value: Math.random(),
+      name: 'B'
+    },
+    {
+      value: Math.random(),
+      name: 'C'
+    }
+  ];
+}
+option = {
+  series: [
+    {
+      type: 'pie',
+      radius: [0, '50%'],
+      data: makeRandomData()
+    }
+  ]
+};
+
+setInterval(() => {
+  myChart.setOption({
+    series: {
+      data: makeRandomData()
+    }
+  });
+}, 2000);
live

而从 5.2.0 开始,我们引入了更强大的全局过渡动画能力,让过渡动画不再局限于相同类型的系列之间。现在,我们可以使用这种跨系列的形变,为任意类型的系列和任意类型的图形做形变动画。

这会有多酷呢?我们一起来感受一下!

跨系列的形变动画

在设置universalTransition: true开启全局过渡动画后,从饼图切换成柱状图,或者从柱状图切换成散点图,甚至旭日图和矩形树图这类复杂的图表之间,都可以通过形变的方式自然的进行动画过渡。

如下,饼图和柱状图之间的切换:

const dataset = {
+  dimensions: ['name', 'score'],
+  source: [
+    ['Hannah Krause', 314],
+    ['Zhao Qian', 351],
+    ['Jasmin Krause ', 287],
+    ['Li Lei', 219],
+    ['Karle Neumann', 253],
+    ['Mia Neumann', 165],
+    ['Böhm Fuchs', 318],
+    ['Han Meimei', 366]
+  ]
+};
+const pieOption = {
+  dataset: [dataset],
+  series: [
+    {
+      type: 'pie',
+      // 通过 id 关联需要过渡动画的系列
+      id: 'Score',
+      radius: [0, '50%'],
+      universalTransition: true,
+      animationDurationUpdate: 1000
+    }
+  ]
+};
+const barOption = {
+  dataset: [dataset],
+  xAxis: {
+    type: 'category'
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      // 通过 id 关联需要过渡动画的系列
+      id: 'Score',
+      // 每个数据都是用不同的颜色
+      colorBy: 'data',
+      encode: { x: 'name', y: 'score' },
+      universalTransition: true,
+      animationDurationUpdate: 1000
+    }
+  ]
+};
+
+option = barOption;
+
+setInterval(() => {
+  option = option === pieOption ? barOption : pieOption;
+  // 使用 notMerge 的形式可以移除坐标轴
+  myChart.setOption(option, true);
+}, 2000);
live

更多的常见基础图表之间的过渡:

这样的动画过渡不再仅仅局限于基础的折、柱、饼中,在柱状图和地图之间:

或者旭日图和矩形树图之间,甚至非常灵活的自定义系列之间都可以进行动画的过渡。

注意需要配置系列的 id 来保证需要动画过渡的系列之间能够一一对应。

按需引入的代码需要单独引入该特性

import { UniversalTransition } from 'echarts/features';
+echarts.use([UniversalTransition]);
+

数据的分裂和合并动画

除了常见的数据值的更新,有时候我们还会碰到数据的聚合、下钻等交互后的更新,这个时候我们就不能直接应用一对一的动画过渡,而需要使用更多像分裂、合并这样的动画效果,来通过正确的图形动画表达出数据的变换。

为了能够表达数据之间可能存在的多对多联系,在 5.2.0 中我们新引入了一个数据组groupId的概念,我们可以通过 series.dataGroupId 设置整个系列所属的组,或者更细粒度的通过 series.data.groupId 设置每个数据所属的组。如果你使用了dataset管理数据则更方便了,可以使用encode.itemGroupId来指定一个维度编码成groupId

比如我们要实现一个柱状图下钻的动画,可以将下钻后的整个系列的数据都设置同一个groupId,然后跟下钻前的数据对应起来:

option = {
+  xAxis: {
+    data: ['Animals', 'Fruits', 'Cars']
+  },
+  yAxis: {},
+  dataGroupId: '',
+  animationDurationUpdate: 500,
+  series: {
+    type: 'bar',
+    id: 'sales',
+    data: [
+      {
+        value: 5,
+        groupId: 'animals'
+      },
+      {
+        value: 2,
+        groupId: 'fruits'
+      },
+      {
+        value: 4,
+        groupId: 'cars'
+      }
+    ],
+    universalTransition: {
+      enabled: true,
+      divideShape: 'clone'
+    }
+  }
+};
+
+const drilldownData = [
+  {
+    dataGroupId: 'animals',
+    data: [
+      ['Cats', 4],
+      ['Dogs', 2],
+      ['Cows', 1],
+      ['Sheep', 2],
+      ['Pigs', 1]
+    ]
+  },
+  {
+    dataGroupId: 'fruits',
+    data: [
+      ['Apples', 4],
+      ['Oranges', 2]
+    ]
+  },
+  {
+    dataGroupId: 'cars',
+    data: [
+      ['Toyota', 4],
+      ['Opel', 2],
+      ['Volkswagen', 2]
+    ]
+  }
+];
+
+myChart.on('click', event => {
+  if (event.data) {
+    const subData = drilldownData.find(data => {
+      return data.dataGroupId === event.data.groupId;
+    });
+    if (!subData) {
+      return;
+    }
+    myChart.setOption({
+      xAxis: {
+        data: subData.data.map(item => {
+          return item[0];
+        })
+      },
+      series: {
+        type: 'bar',
+        id: 'sales',
+        dataGroupId: subData.dataGroupId,
+        data: subData.data.map(item => {
+          return item[1];
+        }),
+        universalTransition: {
+          enabled: true,
+          divideShape: 'clone'
+        }
+      },
+      graphic: [
+        {
+          type: 'text',
+          left: 50,
+          top: 20,
+          style: {
+            text: 'Back',
+            fontSize: 18
+          },
+          onclick: function() {
+            myChart.setOption(option, true);
+          }
+        }
+      ]
+    });
+  }
+});
live

通过groupId,我们还可以实现更丰富的聚合,下钻动画。

数据的聚合:

单系列下钻成两个系列:

全局过渡动画使得数据的关系和演变的表达能力走上新的台阶,为你的可视化创作灵感插上翅膀。

看到这里,我们知道你已经跃跃欲试了。但是别急,5.2.0 还有更多值得一看的新功能。

调色盘的取色策略

在上面全局过渡动画的示例中,大家可能有注意到我们使用了一个之前版本没有的colorBy配置项,这个配置项也是我们这个版本新增加的一个特性,用来给系列配置不同粒度的调色盘取色。这个配置目前支持两种策略:

  • 'series' 按照系列分配调色盘中的颜色,同一系列中的所有数据都是用相同的颜色。
  • 'data' 按照数据项分配调色盘中的颜色,每个数据项都使用不同的颜色。

在之前我们是按照系列的类型固定了这个策略,比如柱状图就是固定'series'的策略,而饼图则是固定'data'的策略。

而现在新增这个配置项后,我们可以在柱状图中给每个数据项都分配不同的颜色:

option = {
+  xAxis: {
+    type: 'category',
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      data: [120, 200, 150, 80, 70, 110, 130],
+      type: 'bar',
+      colorBy: 'data'
+    }
+  ]
+};
live

或者在饼图中统一使用一个颜色:

option = {
+  series: {
+    type: 'pie',
+    colorBy: 'series',
+    radius: [0, '50%'],
+    itemStyle: {
+      borderColor: '#fff',
+      borderWidth: 1
+    },
+    data: [
+      {
+        value: 335,
+        name: 'Direct Visit'
+      },
+      {
+        value: 234,
+        name: 'Union Ad'
+      },
+      {
+        value: 1548,
+        name: 'Search Engine'
+      }
+    ]
+  }
+};
live

这一配置项可以让我们避免了去找调色盘颜色然后去一一设置的麻烦,可能在特定的场景需求中提供便捷。后续我们会对这个配置项做进一步的增强,提供更多的调色盘取色的策略。

极坐标柱状图的标签

这个版本中我们实现了极坐标上的柱状图的标签,并且支持丰富的标签定位配置。下面是一个最常见的标签显示在端点的进度图:

option = {
+  angleAxis: {
+    show: false,
+    max: 10
+  },
+  radiusAxis: {
+    show: false,
+    type: 'category',
+    data: ['AAA', 'BBB', 'CCC', 'DDD']
+  },
+  polar: {},
+  series: [
+    {
+      type: 'bar',
+      data: [3, 4, 5, 6],
+      colorBy: 'data',
+      roundCap: true,
+      label: {
+        show: true,
+        // 试试改成 'insideStart'
+        position: 'start',
+        formatter: '{b}'
+      },
+      coordinateSystem: 'polar'
+    }
+  ]
+};
live

更多标签位置的配置:

这一灵活的标签位置配置项大大丰富了极坐标柱状图的表达能力,让文字清晰地匹配对应的数据。

空数据的饼图样式

在之前的版本中,如果饼图没有数据,画面中可能就是完全空白的。因为没有任何的视觉元素,所以用户会疑惑是不是出现了 bug 导致图中没有内容。

为了解决这个问题,这个版本我们会默认在无可显示数据的时候显示一个灰色的占位圆以防止画面中完全空白。我们可以通过emptyCircleStyle配置这个占位圆的样式。

option = {
+  series: [
+    {
+      type: 'pie',
+      data: [],
+      // showEmptyCircle: false,
+      emptyCircleStyle: {
+        // 将样式改为空心圆
+        color: 'transparent',
+        borderColor: '#ddd',
+        borderWidth: 1
+      }
+    }
+  ]
+};
live

如果不想要显示这个灰色的圆,也可以设置showEmptyCircle: false关闭。

高维数据的性能增强

我们从 4.0 开始引入了 dataset 用来管理图表的数据,通常情况下dataset提供了更方便的数据管理方式而且跟传统的方式不会有什么性能上的差别。但是在一些极端的特别高维(>100)数据的场景下,我们还是会碰到一些性能急剧下降的问题,比如下面这种通过一千个系列去可视化千维数据的场景(#11907),甚至可能会卡住。

const indices = Array.from(Array(1000), (_, i) => {
+  return `index${i}`;
+});
+const option = {
+  xAxis: { type: 'category' },
+  yAxis: {},
+  dataset: {
+    // dimension: ['date', ...indices],
+    source: Array.from(Array(10), (_, i) => {
+      return {
+        date: i,
+        ...indices.reduce((item, next) => {
+          item[next] = Math.random() * 100;
+          return item;
+        }, {})
+      };
+    })
+  },
+  series: indices.map(index => {
+    return { type: 'line', name: index };
+  })
+};

产生这个性能问题是因为我们在底层每个系列都会按照其需要处理一遍这个 dataset,然后保存一份处理过后的数据以及维度等元信息。这意味着刚才那个例子中需要处理并保存1000 x 1000个维度的信息,这带来了巨大的内存和垃圾回收的压力,从而导致了高维度的性能的急剧下降。

在新版本中我们对这个问题做了优化,所有系列都尽可能共享 dataset 的数据(能否共享取决于系列怎么使用这份数据)存储而非每个系列都处理并存储一次,并且只处理和存储了使用到的维度。这些优化保证了内存不会随着 dataset 维度和系列的增长而爆炸,大幅度的提升了极端场景下的初始化性能。刚才例子的渲染耗时也从卡住降低到了可接受的 300 毫秒以下。

这次优化带来收益的还不只是这种高维的场景,在使用维度不高但是数据量很大的 dataset 的时候,因为数据的共享所以多个系列只处理了一遍数据,因此也可以带来显著的性能提升。

自定义系列的类型优化

自定义系列提供了非常灵活的创建系列图形的方式,相对于其它系列,自定义系列的学习曲线可能有些陡峭,而且容易出错。因此在这个版本中,我们进一步的优化了自定义系列中的核心方法renderItem的类型,对于renderItem的参数和返回值类型做了更精确的推断,从而可以根据返回的图形类型推断出可以设置该图形的哪些属性:

series = {
+  type: 'custom',
+  renderItem(params) {
+    return {
+      type: 'group',
+      // group 类型使用 children 存储其它类型的子元素
+      children: [
+        {
+          type: 'circle',
+          // circle 拥有下面这些可以配置的 shape 属性
+          shape: { r: 10, cx: 0, cy: 0 },
+          // 可以配置的样式
+          style: { fill: 'red' }
+        },
+        {
+          type: 'rect',
+          // rect 拥有下面这些可以配置的 shape 属性
+          shape: { x: 0, y: 0, width: 100, height: 100 }
+        },
+        {
+          type: 'path',
+          // 自定义路径图形
+          shape: { d: '...' }
+        }
+      ]
+    };
+  }
+};

小结

以上我们介绍了 5.2.0 中的新特性以及优化,如果你对其中的一些特性感兴趣,不妨更新到最新版本的 Apache ECharts 亲自体验一下。

如果你对 Apache ECharts 接下来的计划感兴趣,也可以在 GitHub Milestone 关注我们的开发计划。也非常欢迎加入我们的贡献者行列(在 Wiki 中了解更多)。

完整更新记录

查看版本更新

本文贡献者 在 GitHub 上编辑本页

pissang pissangOvilia Ovilia
+ + + + + diff --git a/docs/zh/basics/release-note/5-3-0/index.html b/docs/zh/basics/release-note/5-3-0/index.html new file mode 100644 index 000000000..4c4885f00 --- /dev/null +++ b/docs/zh/basics/release-note/5-3-0/index.html @@ -0,0 +1,851 @@ + + + + + + + 5.3 - 版本特性 - 入门篇 - 使用手册 - Apache ECharts + + +

Apache ECharts 5.3.0 特性介绍

Apache ECharts 5.3.0 在动画表达力、渲染性能、服务端渲染上做了大幅度的增强,同时也新增了多坐标轴刻度自动对齐、tooltip 数值格式化、地图投影等社区中期盼已久的特性。

关键帧动画

在之前 ECharts 的动画集中在图形添加、更新以及移除的过渡动画上,过渡动画往往只有开始状态和结束状态。为了表达更复杂的动画效果,我们 5.3.0 中为自定义系列图形组件引入了全新的关键帧动画。

下面是一个简单的通过关键帧动画实现的呼吸动画的效果。

option = {
+  graphic: {
+    type: 'circle',
+    shape: { r: 100 },
+    left: 'center',
+    top: 'center',
+    keyframeAnimation: [
+      {
+        duration: 3000,
+        loop: true,
+        keyframes: [
+          {
+            percent: 0.5,
+            easing: 'sinusoidalInOut',
+            scaleX: 0.1,
+            scaleY: 0.1
+          },
+          {
+            percent: 1,
+            easing: 'sinusoidalInOut',
+            scaleX: 1,
+            scaleY: 1
+          }
+        ]
+      }
+    ]
+  }
+};
live

在关键帧动画中,你可以配置动画时长、缓动、是否循环、每个关键帧的位置、缓动以及图形属性等。而且每个图形可以同时设置多个不同配置的关键帧动画。灵活的配置让我们可以实现非常复杂的动画效果,下面列举几个可以应用关键帧动画的场景。

自定义加载动画

ECharts 默认内置了一个加载动画,可以调用showLoading显示。开发者经常会提需求需要更多的加载动画效果。现在有了关键帧动画后,我们可以通过图形(graphic)组件配合关键帧动画实现任何想要的加载动画效果。

比如文本描边动画:

option = {
+  graphic: {
+    elements: [
+      {
+        type: 'text',
+        left: 'center',
+        top: 'center',
+        style: {
+          text: 'Apache ECharts',
+          fontSize: 40,
+          fontWeight: 'bold',
+          lineDash: [0, 200],
+          lineDashOffset: 0,
+          fill: 'transparent',
+          stroke: '#000',
+          lineWidth: 1
+        },
+        keyframeAnimation: {
+          duration: 3000,
+          loop: true,
+          keyframes: [
+            {
+              percent: 0.7,
+              style: {
+                fill: 'transparent',
+                lineDashOffset: 200,
+                lineDash: [200, 0]
+              }
+            },
+            {
+              // Stop for a while.
+              percent: 0.8,
+              style: {
+                fill: 'transparent'
+              }
+            },
+            {
+              percent: 1,
+              style: {
+                fill: 'black'
+              }
+            }
+          ]
+        }
+      }
+    ]
+  }
+};
live

或者柱状图形状的加载动画:

const columns = [];
+for (let i = 0; i < 7; i++) {
+  columns.push({
+    type: 'rect',
+    x: i * 20,
+    shape: {
+      x: 0,
+      y: -40,
+      width: 10,
+      height: 80
+    },
+    style: {
+      fill: '#5470c6'
+    },
+    keyframeAnimation: {
+      duration: 1000,
+      delay: i * 200,
+      loop: true,
+      keyframes: [
+        {
+          percent: 0.5,
+          scaleY: 0.1,
+          easing: 'cubicIn'
+        },
+        {
+          percent: 1,
+          scaleY: 1,
+          easing: 'cubicOut'
+        }
+      ]
+    }
+  });
+}
+option = {
+  graphic: {
+    elements: [
+      {
+        type: 'group',
+        left: 'center',
+        top: 'center',
+        children: columns
+      }
+    ]
+  }
+};
live

扩展更丰富的散点图动画特效

带有特效动画的散点图一直以来是 ECharts 的特色功能。开发者可以使用 effectScatter 系列来实现带有涟漪特效的动态散点图,这种特效动画除了让作品更有趣,也起到了高亮提示用户的效果。跟加载动画一样,开发者也常常提出需要更多动画效果的需求。现在我们可以在自定义系列中通过使用关键帧动画来实现更复杂的特效。

比如下面例子在 SVG 地图上给自定义系列绘制的图钉加上了跳动的动画效果,同时配上了涟漪动画。

fetch(
+  'https://fastly.jsdelivr.net/gh/apache/echarts-website@asf-site/examples/data/asset/geo/Map_of_Iceland.svg'
+)
+  .then(response => response.text())
+  .then(svg => {
+    echarts.registerMap('iceland_svg', { svg: svg });
+    option = {
+      geo: {
+        map: 'iceland_svg',
+        left: 0,
+        right: 0
+      },
+      series: {
+        type: 'custom',
+        coordinateSystem: 'geo',
+        geoIndex: 0,
+        zlevel: 1,
+        data: [
+          [488, 459, 100],
+          [770, 757, 30],
+          [1180, 743, 80],
+          [894, 1188, 61],
+          [1372, 477, 70],
+          [1378, 935, 81]
+        ],
+        renderItem(params, api) {
+          const coord = api.coord([
+            api.value(0, params.dataIndex),
+            api.value(1, params.dataIndex)
+          ]);
+
+          const circles = [];
+          for (let i = 0; i < 5; i++) {
+            circles.push({
+              type: 'circle',
+              shape: {
+                cx: 0,
+                cy: 0,
+                r: 30
+              },
+              style: {
+                stroke: 'red',
+                fill: 'none',
+                lineWidth: 2
+              },
+              // Ripple animation
+              keyframeAnimation: {
+                duration: 4000,
+                loop: true,
+                delay: (-i / 4) * 4000,
+                keyframes: [
+                  {
+                    percent: 0,
+                    scaleX: 0,
+                    scaleY: 0,
+                    style: {
+                      opacity: 1
+                    }
+                  },
+                  {
+                    percent: 1,
+                    scaleX: 1,
+                    scaleY: 0.4,
+                    style: {
+                      opacity: 0
+                    }
+                  }
+                ]
+              }
+            });
+          }
+          return {
+            type: 'group',
+            x: coord[0],
+            y: coord[1],
+            children: [
+              ...circles,
+              {
+                type: 'path',
+                shape: {
+                  d:
+                    'M16 0c-5.523 0-10 4.477-10 10 0 10 10 22 10 22s10-12 10-22c0-5.523-4.477-10-10-10zM16 16c-3.314 0-6-2.686-6-6s2.686-6 6-6 6 2.686 6 6-2.686 6-6 6z',
+                  x: -10,
+                  y: -35,
+                  width: 20,
+                  height: 40
+                },
+                style: {
+                  fill: 'red'
+                },
+                // Jump animation.
+                keyframeAnimation: {
+                  duration: 1000,
+                  loop: true,
+                  delay: Math.random() * 1000,
+                  keyframes: [
+                    {
+                      y: -10,
+                      percent: 0.5,
+                      easing: 'cubicOut'
+                    },
+                    {
+                      y: 0,
+                      percent: 1,
+                      easing: 'bounceOut'
+                    }
+                  ]
+                }
+              }
+            ]
+          };
+        }
+      }
+    };
+
+    myChart.setOption(option);
+  });
live

加载 Lottie 动画

为了充分发掘出新的关键帧动画的能力,ECharts 团队的沈毅写了一个 Lottie 动画的解析库,可以将 Lottie 动画文件解析成 ECharts 的图形格式进行渲染。结合 Lottie 的表达力我们可以进一步的在我们的项目中绘制出细腻的动画。

图形组件过渡动画

我们在 5.0 里为自定义系列中返回的图形提供了更灵活的过渡动画配置。可以通过transition, enterFrom, leaveTo三个配置项来配置每个图形哪些属性会拥有过渡动画,当图形创建和被移除的时候该执行怎么样的动画。例如:

function renderItem() {
+  //...
+  return {
+    //...
+    x: 100,
+    // 'style', 'x', 'y' 会被动画
+    transition: ['style', 'x', 'y'],
+    enterFrom: {
+      style: {
+        // 淡入
+        opacity: 0
+      },
+      //从左侧飞入
+      x: 0
+    },
+    leaveTo: {
+      // 淡出
+      opacity: 0
+    },
+    // 向右侧飞出
+    x: 200
+  };
+}

在 5.3.0 中我们把这些过渡动画的配置扩展到了图形(graphic)组件中,并且做了更多的增强:

如果你不想一一写出每个要动画的属性,现在你可以直接配置transition: 'all'为所有属性都加上动画过渡。

与此同时我们还新增了enterAnimationupdateAnimationleaveAnimation分别配置每个图形入场、更新、出场动画的时长(duration)、延迟(delay)和缓动(easing)。除此之外,渐变色现在也支持动画了。

全新的 SVG 渲染器

在 5.3.0 中我们重构了我们的 SVG 渲染器,新的 SVG 渲染器能够带来 2x ~ 10x 的性能提升,在某些特殊场景中甚至能有数十倍的提升。

之前的 SVG 渲染器我们直接从渲染队列更新到 DOM。但是因为 zrender 的图形属性跟 DOM 并不是一一对应的,因此中间需要实现非常复杂的 Diff 逻辑,容易出错而且在某些场景下性能并不能做到最好。在这个版本我们重构成先全量渲染到 VDOM,然后再将 VDOM patch 到 DOM 完成渲染。全量渲染可以避免复杂的 Diff 逻辑带来的潜在 Bug。而 VDOM 和 DOM 的一一对应可以保证在 patch 的时候保证更新是最少的,从而带来巨大的性能提升。

这个例子 可以给大家带来比较直观的性能提升的感受。新的版本在 SVG 模式下拖动的交互上比之前版本流畅非常多。

5.2.2 (Before) 5.3.0 (After)
before after

除了性能的提升,我们还可以使用中间全量渲染得到的 VDom 做更多的事情,比如下面会介绍的服务端渲染。

零依赖的服务端渲染

在之前的版本 ECharts 也可以实现服务端的渲染,但是必须得依赖 node-canvas,如果是使用 SVG 模式则需要依赖 JSDOM 来模拟 DOM 环境。这些依赖一是带来了额外的体积和使用要求,二是也会有更多的性能损耗。

这次新的 SVG 渲染器可以让我们从中间的 VDOM 渲染得到字符串,带来了完全零依赖的服务端渲染,输出更精简并且带有 CSS 动画的 SVG 字符串。

const echarts = require('echarts');
+
+// 在 SSR 模式下第一个参数不需要再传入 DOM 对象
+const chart = echarts.init(null, null, {
+  renderer: 'svg', // 必须使用 SVG 模式
+  ssr: true, // 开启 SSR
+  width: 400, // 需要指明高和宽
+  height: 300
+});
+
+// 像正常使用一样 setOption
+chart.setOption({
+  xAxis: {
+    type: 'category',
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      data: [120, 200, 150, 80, 70, 110, 130],
+      type: 'bar'
+    }
+  ]
+});
+
+// 输出字符串
+const svgStr = chart.renderToSVGString();

在此基础上,我们优化了输出的 SVG 字符串,使其在诸如 PowerPoint 等更多的平台上有更好的显示效果。

自定义地图投影

地图一直是 ECharts 中使用非常广泛的组件。一般地图组件会使用存储了经纬度的 GeoJSON 格式的数据。而 ECharts 则计算出合适的显示区域然后把经纬度线性映射到这个区域。这是一种最简单的地图投影方式。但是简单的线性投影并无法满足某些复杂的地图场景,例如使用 Albers 投影解决线性投影中面积失真的问题,或者在世界地图中让太平洋显示在中间等等。

因此在 5.3.0 里中我们引入了自定义的地图投影,可以通过projectunproject两个方法告诉 ECharts 如何投影坐标,以及如何根据投影后坐标计算经纬度。下面是简单的使用墨卡托投影的例子:

series = {
+  type: 'map',
+  projection: {
+    project: point => [
+      (point[0] / 180) * Math.PI,
+      -Math.log(Math.tan((Math.PI / 2 + (point[1] / 180) * Math.PI) / 2))
+    ],
+    unproject: point => [
+      (point[0] * 180) / Math.PI,
+      ((2 * 180) / Math.PI) * Math.atan(Math.exp(point[1])) - 90
+    ]
+  }
+};

除了我们自己实现投影公式,我们也可以使用 d3-geo 等第三方库提供的现成的投影实现:

const projection = d3.geoConicEqualArea();
+// ...
+series = {
+  type: 'map',
+  projection: {
+    project: point => projection(point),
+    unproject: point => projection.invert(point)
+  }
+};

配合在 5.2 里新增的全局过渡动画特性,我们可以实现不同投影效果之间的动画过渡:

地图投影动画

除了地图的投影之外,我们在这个版本对于地图还做了下面两个增强:

  • 对 GeoJSON 数据提供了'LineString''MultiLineString'的支持。
  • 将默认标签位置的计算从包围盒中心改为最大区域的重心坐标,计算结果更加准确。

多坐标轴的刻度对齐

多坐标轴的刻度对齐是社区中提了很久的一个需求,我们在网上也可以看到很多开发者写的如何在 ECharts 中实现坐标轴对齐的文章,通常都会比较麻烦而且会有比较多的局限性。

在 5.3.0 中我们终于引入了数值轴坐标轴刻度对齐的功能。可以在需要对齐刻度的坐标轴中配置alignTicks: true。该坐标轴就会根据第一个坐标轴的刻度划分去调整自己的刻度,实现自动对齐。

option = {
+  tooltip: {
+    trigger: 'axis'
+  },
+  legend: {},
+  xAxis: [
+    {
+      type: 'category',
+      data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+      axisPointer: {
+        type: 'shadow'
+      }
+    }
+  ],
+  yAxis: [
+    {
+      type: 'value',
+      name: 'Precipitation',
+      alignTicks: true,
+      axisLabel: {
+        formatter: '{value} ml'
+      }
+    },
+    {
+      type: 'value',
+      name: 'Temperature',
+      axisLabel: {
+        formatter: '{value} °C'
+      }
+    }
+  ],
+  series: [
+    {
+      name: 'Evaporation',
+      type: 'bar',
+      // prettier-ignore
+      data: [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3]
+    },
+    {
+      name: 'Precipitation',
+      type: 'bar',
+      // prettier-ignore
+      data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3]
+    },
+    {
+      name: 'Temperature',
+      type: 'line',
+      yAxisIndex: 1,
+      data: [2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2]
+    }
+  ]
+};
live

支持高亮和选中状态的关闭

ECharts 中高亮状态可以在鼠标移到图形上的时候给用户提供反馈,但是在图表中有海量图形的时候,高亮的动画也可能带来交互上的性能问题。特别在 tooltip 或者图例组件联动触发的高亮会同时高亮多个图形。

因此在这个版本中我们新增了emphasis.disabled配置项。如果不需要高亮的反馈,又对交互性能非常在意的话,可以通过这个配置项来关闭高亮状态。

与此同时,对于选中状态,我们也新增了select.disabled。该配置项可以用于细粒度配置部分数据不可选。

支持整个系列的选中

在 5.3.0 中我们支持将selectedMode配置为'series'以实现系列所有数据的选中。

tooltip 中的数值格式化

tooltip 可以在用户移到图形上的时候通过提示框显示更详细的相关信息,ECharts 也提供了formatter回调函数可以让开发者更灵活的自定义提示框的内容。

但是我们发现大部分时候开发者只是需要格式化提示框中的数字部分,例如固定精度,加上$前缀等等,而之前为了格式化数字开发者只能通过formatter重写整个提示框的内容。特别是在 5.0 后 ECharts 的提示框结构更复杂,样式更美观了,重写变得成本很大而且很难达到默认的效果。

因此在这个版本我们为 tooltip 新增了valueFormatter配置项用于数值部分的格式化。

还是刚才那个坐标轴对齐的例子,我们可以为提示框中的数值部分加上 °C 和 ml 的后缀。

option = {
+  tooltip: {
+    trigger: 'axis'
+  },
+  legend: {},
+  xAxis: [
+    {
+      type: 'category',
+      data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+      axisPointer: {
+        type: 'shadow'
+      }
+    }
+  ],
+  yAxis: [
+    {
+      type: 'value',
+      name: 'Precipitation',
+      alignTicks: true,
+      axisLabel: {
+        formatter: '{value} ml'
+      }
+    },
+    {
+      type: 'value',
+      name: 'Temperature',
+      axisLabel: {
+        formatter: '{value} °C'
+      }
+    }
+  ],
+  series: [
+    {
+      name: 'Evaporation',
+      type: 'bar',
+      tooltip: {
+        valueFormatter: value => value + ' ml'
+      },
+      // prettier-ignore
+      data: [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3]
+    },
+    {
+      name: 'Precipitation',
+      type: 'bar',
+      tooltip: {
+        valueFormatter: value => value + ' ml'
+      },
+      // prettier-ignore
+      data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3]
+    },
+    {
+      name: 'Temperature',
+      type: 'line',
+      yAxisIndex: 1,
+      tooltip: {
+        valueFormatter: value => value + ' °C'
+      },
+      data: [2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2]
+    }
+  ]
+};
live

每个系列都可以根据自己的数值格式配置自己的valueFormatter

更灵活的扇区圆角

在 5.0 中我们为扇区新增了圆角的配置,可以让饼图,旭日图变得更有趣。之前圆角的配置只支持内半径和外半径分开配置,这次我们更进一步,支持扇区的四个角都配置成不同的圆角大小,带来更灵活的呈现。

option = {
+  tooltip: {
+    trigger: 'item'
+  },
+  legend: {
+    top: '5%',
+    left: 'center'
+  },
+  series: [
+    {
+      name: 'Access From',
+      type: 'pie',
+      radius: ['30%', '70%'],
+      roseType: 'angle',
+      itemStyle: {
+        borderRadius: [20, 5, 5, 10],
+        borderColor: '#fff',
+        borderWidth: 2
+      },
+      label: {
+        show: false
+      },
+      data: [
+        { value: 800, name: 'Search Engine' },
+        { value: 735, name: 'Direct' },
+        { value: 580, name: 'Email' },
+        { value: 484, name: 'Union Ads' },
+        { value: 400, name: 'Video Ads' }
+      ]
+    }
+  ]
+};
live

饼图的复杂标签优化

饼图一直是 ECharts 中标签呈现最复杂的图表之一,我们从 5.0 开始就一直在饼图的标签布局、显示上做了很多的优化。

这次我们针对使用了换行,背景色,富文本等格式比较复杂的饼图标签做了深度的优化。在宽度的自适应、超出容器、引导线的计算上比之前有了更好的效果:

5.2.2 (Before) 5.3.0 (After)
before after
before after

柱状图 large 模式优化

在数据量很多(> 2k)的时候,我们支持柱状图通过开启 large 模式来加速渲染,提升交互性能,但是之前 large 模式下对柱状图布局比较简单,不支持多系列堆叠后的布局。在 5.3.0 中我们对 large 模式的布局进行了优化,跟普通模式保持了一致性。我们可以在更多的场景中通过开启 large 来优化柱状图的性能。

除此之外,优化后的柱状图布局也修复了在对数轴这样的非线性轴上堆叠效果不正确的 bug。

非兼容改动

registerMap 和 getMap 方法需要在引入地图组件后才能使用

为了减少最小打包的体积,我们从核心模块中移除了地图数据管理的方法getMapregisterMap

如果你是按需引入 ECharts 组件的话,需要保证先引入了GeoComponent或者MapChart之后,才能使用registerMap注册地图数据。

import * as echarts from 'echarts/core';
+import { MapChart } from 'echarts/charts';
+
+echarts.use([MapChart]);
+
+// 必须在使用 use 方法注册了 MapChart 后才能使用 registerMap 注册地图
+echarts.registerMap('world', worldJSON);

如果你是使用import * as echarts from 'echarts'全量引入,这次改动不会对你产生任何影响。

折线图移除默认高亮加粗的效果

我们在 5.0 里对折线图引入了默认高亮加粗的效果,但是社区反馈这个在很多场景效果并不好,所以在这个版本我们将这个效果从默认开启改为默认关闭,如果需要使用高亮加粗,则可以显式配置:

series = {
+  type: 'line',
+  //...
+  emphasis: {
+    lineStyle: {
+      width: 'bolder'
+    }
+  }
+};

完整更新记录

查看版本更新

本文贡献者 在 GitHub 上编辑本页

pissang pissangOvilia Oviliaplainheart plainheart
+ + + + + diff --git a/docs/zh/basics/release-note/5-4-0/index.html b/docs/zh/basics/release-note/5-4-0/index.html new file mode 100644 index 000000000..31315c0e8 --- /dev/null +++ b/docs/zh/basics/release-note/5-4-0/index.html @@ -0,0 +1,15 @@ + + + + + + + 5.4 - 版本特性 - 入门篇 - 使用手册 - Apache ECharts + + +

Apache ECharts 5.4.0 特性介绍

智能指针吸附

在图表中,部分可交互元素可能比较小,有时候用户不易准确地进行点击等操作,移动端尤其如此。因此,在 Apache ECharts 5.4.0 中,我们引入了“智能指针吸附”的概念。

具体请参见智能指针吸附

在更多坐标系中使用饼图

Apache ECharts 一个很强大的功能就是各种图表类型、坐标系、组件的组合。在这个版本中,我们为饼图增加了坐标系的配置项。

于是,饼图可以出现在直角坐标系:

日历坐标系:

地理坐标系:

等等各种坐标系中,甚至可以和百度地图扩展联动,在地图上显示饼图:

这大大扩展了饼图的灵活性,让开发者可以使用 Apache ECharts 创作出更多图表的组合效果。

新增乌克兰语翻译

在这个版本中,我们支持了乌克兰语。目前 Apache ECharts 已支持 17 种语言!

如果需要使用除中英文以外的语言,需要在初始化图表前,先调用 echarts.registerLocale 初始化,然后在 init 时候传入 opts.locale 修改图表语言。

仪表盘文字旋转

在这个版本中,我们支持了仪表盘的文字旋转。

axisLabel.rotate 可以设为 'tangential' | 'radial' | number。如果是 number 类型,则表示标签的旋转角,从 -90 度到 90 度,正值是逆时针。除此之外,还可以是字符串 'radial' 表示径向旋转、'tangential' 表示切向旋转。

完整更新记录

查看版本更新

本文贡献者 在 GitHub 上编辑本页

Ovilia Ovilia
+ + + + + diff --git a/docs/zh/basics/release-note/5-5-0/index.html b/docs/zh/basics/release-note/5-5-0/index.html new file mode 100644 index 000000000..c6a86b9d5 --- /dev/null +++ b/docs/zh/basics/release-note/5-5-0/index.html @@ -0,0 +1,82 @@ + + + + + + + 5.5 - 版本特性 - 入门篇 - 使用手册 - Apache ECharts + + +

Apache ECharts 5.5.0 特性介绍

增强的 ESM 支持

为了让开发者在测试和 Node.js 环境使用更方便,我们在这个版本中对 ESM 的识别问题进行了优化。

以前,ECharts 只在 npm(npm 包的 lib 目录中)导出 *.esm 文件。虽然这在 bundlers 环境表现良好,但 Node.js 环境和一些基于 Node.js 的测试框架(如 vitest 和 jest)中的表现并不理想。

有了这个新功能,我们做了几个改变以改善这个问题:

  • package.json 中添加了 "type": "module"
  • package.json 中添加了 "exports": {...}
  • 在子目录中添加了一些只包含 "type": "commonjs"package.json 文件

这些改变意味着,像 echarts/core.js 这样的文件现在可以在像纯 Node.js、vitest、jest 和 create-react-app 这样的环境中解析为 ESM。

我们还确保了这个新功能与各种环境兼容,包括运行时(Node.js/vitest/jest(create-react-app)/ssr/…)和打包器(webpack/rollup/vite/esbuild/…)。

我们非常期待这一新功能,并相信它将极大地改善开发者的体验。

服务端渲染 + 客户端轻量运行时

Apache ECharts 功能强大,相应地,包体积也比较大。我们在之前的版本中也做了各种努力来改进这一点。开发者可以使用 TreeShaking 按需加载部分代码,以减少加载的代码量。从 Apache ECharts 5.3 版本起,我们支持了零依赖的服务端 SVG 字符串渲染方案,并支持图表的初始动画。这样,使用服务端渲染的结果作为首屏渲染的画面,可以大大减少首屏加载时间。

服务端渲染虽然是一种很有效减少包体积的解决方案,但如果需要在客户端实现一些交互,那么不得不仍旧加载 echarts.js,这可能会增加更多的加载时间。对于一些对页面加载速度要求较高的场景,这可能不是一个理想的选择。

在 5.5.0 版本中,我们新增了客户端轻量运行时,客户端无需加载完整 ECharts 即可实现部分交互。这样,我们可以在服务端渲染图表,然后在客户端加载轻量运行时,实现一些常见的交互。这意味着,只需要加载 4KB 的轻量运行时(gzip 后 1KB),即可实现带初始动画和部分常用交互形式的图表。这一改进将极大地提升页面加载速度,特别是对于移动端的体验。

以这个带标题的饼图为例,如果按客户端仅打包饼图和标题组件的方案,gzip 后需要 135KB;如果按服务端渲染的方案,渲染结果 SVG gzip 后 1 KB、客户端运行时 gzip 后 1KB,仅为前者体积的 1.5%。交互方面,后者也可以做到初始动画、鼠标移动到图表元素后的高亮,并且获取到点击事件,能够满足大部分的常见交互需求。

如需使用这一方案,服务端代码和之前一样,但需要保证 ECharts 版本号在 5.5.0 以上。

// 服务端代码
+const echarts = require('echarts');
+
+// 在 SSR 模式下第一个参数不需要再传入 DOM 对象
+const chart = echarts.init(null, null, {
+  renderer: 'svg', // 必须使用 SVG 模式
+  ssr: true, // 开启 SSR
+  width: 400, // 需要指明高和宽,如果是根据客户端容器大小动态的,该值需要从客户端得到
+  height: 300
+});
+
+// 像正常使用一样 setOption
+chart.setOption({
+  //...
+});
+
+// 输出字符串
+const svgStr = chart.renderToSVGString();
+
+// 调用 dispose 以释放内存
+chart.dispose();
+chart = null;
+
+// 通过 HTTP Response 返回 svgStr 给前端或者缓存到本地(这里以 Express.js 为例):
+res.writeHead(200, {
+  'Content-Type': 'application/xml'
+});
+res.write(svgStr);
+res.end();

客户端将得到的 SVG 字符串添加到容器中,并绑定轻量运行时:

<div id="chart-container" style="width:800px;height:600px"></div>
+
+<script src="https://cdn.jsdelivr.net/npm/echarts/ssr/client/dist/index.min.js"></script>
+<script>
+const ssrClient = window['echarts-ssr-client'];
+
+let isSeriesShown = {
+  a: true,
+  b: true
+};
+
+function updateChart(svgStr) {
+  const container = document.getElementById('chart-container');
+  container.innerHTML = svgStr;
+
+  // 使用轻量运行时赋予图表交互能力
+  ssrClient.hydrate(main, {
+    on: {
+      click: (params) => {
+        if (params.ssrType === 'legend') {
+          // 点击图例元素,请求服务器进行二次渲染
+          isSeriesShown[params.seriesName] = !isSeriesShown[params.seriesName];
+          fetch('...?series=' + JSON.stringify(isSeriesShown))
+            .then(res => res.text())
+            .then(svgStr => {
+              updateChart(svgStr);
+            });
+        }
+      }
+    }
+  });
+}
+
+// 通过 AJAX 请求获取服务端渲染的 SVG 字符串
+fetch('...')
+  .then(res => res.text())
+  .then(svgStr => {
+    updateChart(svgStr);
+  });
+</script>

客户端轻量运行时必须配合 SVG 形式的服务端渲染结果使用,支持以下交互:

  • 图表初始动画(实现原理:服务端渲染的 SVG 带有 CSS 动画)
  • 高亮样式(实现原理:服务端渲染的 SVG 带有 CSS 动画)
  • 动态改变数据(实现原理:轻量运行时请求服务器进行二次渲染)
  • 点击图例切换系列是否显示(实现原理:轻量运行时请求服务器进行二次渲染)

可以发现,这能够满足大部分的交互场景需求。如果需要更复杂的交互,则客户端需要加载 echarts.js 实现完整功能。完整的介绍请参见服务端渲染 ECharts 图表

数据下钻支持过渡动画

在 5.5.0 版本中,我们新增了 childGroupId 配置项,可以实现数据下钻的过渡动画功能。

在之前的版本中,我们已经支持使用 groupId,用以表示当前数据所属的组别。而这次新增的 childGroupId 则可以用来表明当前数据本身的组别,与 groupId 配合使用后形成一个“父-子-孙”的关系链条。当用户点击图表中的数据元素时,图表会以过渡动画的形式展示下钻的数据。

开发者只需要指定 groupIdchildGroupId,ECharts 就会自动处理层级关系,实现过渡动画。

饼图支持扇区之间的间隔

通过设置饼图扇区之间的间隔,可以让饼图的数据块之间更加清晰,并且形成独特的视觉效果。参见(series-pie.padAngle)。

饼图和极坐标系支持结束角度

结束角度的配置项使得我们可以制作半圆形等不完整的饼图。参见(series-pie.endAngle)。

极坐标系也同样支持了结束角度,可以制作出更加丰富的极坐标图表。参见(angleAxis.endAngle)。

新增 min-max 采样方式

ECharts 的 sampling 配置项允许设置折线图在数据量远大于像素点时候的降采样策略,开启后可以有效的优化图表的绘制效率。在 5.5.0 版本中,我们新增了 min-max 采样方式,可以在保留数据的整体趋势的同时,更加精确的展示数据的极值。

新增两种语言:阿拉伯语和荷兰语

在 5.5.0 版本中,我们新增了阿拉伯语(AR)和荷兰语(NL)两种语言的支持。开发者可以通过 echarts.registerLocale 方法注册新的语言包。

提示框支持指定容器

在之前的版本中,提示框(Tooltip)只能插入到图表容器或者 document.body 中。现在,可以通过 tooltip.appendTo 指定容器,从而能更灵活地控制提示框的位置。

坐标轴最大、最小标签的对齐方式

在 5.5.0 版本中,我们新增了 axisLabel.alignMinLabelaxisLabel.alignMaxLabel 配置项,可以控制坐标轴最大、最小标签的对齐方式。如果图表绘图区域比较大,不希望坐标轴标签溢出,可以将最大、最小标签分别对齐到右和左。

象形柱图支持裁剪

象形柱图可能存在超过绘图区域的情况,如果希望避免这种情况,可以通过 series-pictorialBar.clip 配置项进行裁剪。

提示框 valueFormatter 增加 dataIndex 参数

valueFormatter 可以用来自定义提示框内容中数值的部分,现在新增了 dataIndex 参数,可以用来获取当前数据的索引。

完整更新记录

查看版本更新

本文贡献者 在 GitHub 上编辑本页

Ovilia Oviliaplainheart plainheart
+ + + + + diff --git a/docs/zh/basics/release-note/v5-feature/index.html b/docs/zh/basics/release-note/v5-feature/index.html new file mode 100644 index 000000000..29db1174f --- /dev/null +++ b/docs/zh/basics/release-note/v5-feature/index.html @@ -0,0 +1,19 @@ + + + + + + + ECharts 5 特性介绍 - 版本特性 - 入门篇 - 使用手册 - Apache ECharts + + +

Apache ECharts 5 新特性

数据可视化在过去的几年中得到了长足的发展。开发者对于可视化产品的期待不再是简单的图表创建工具,而在交互、性能、数据处理等方面有了更高级的需求。

Apache ECharts 始终致力于让开发者以更方便的方式创造灵活丰富的可视化作品。在最新推出的 Apache ECharts 5,我们着力加强了图表的叙事能力,让开发者可以以更简单的方式,讲述数据背后的故事。

“表·达”是 Apache ECharts 5 的核心,通过五大模块、十五项特性的全面升级,围绕可视化作品的叙事表达能力,让图“表”更能传“达”数据背后的故事,帮助开发者更轻松地创造满足各种场景需求的可视化作品。

动态叙事

动画对于人类认知的重要性不言而喻。在之前的作品中,我们会通过初始化动画和过渡动画帮助用户理解数据变换之间的联系,让图表的出现和变换显得不那么生硬。这次,我们更是大幅度增强了我们的动画叙事能力,希望能够进一步发挥动画对于用户认知的帮助作用,借助图表的动态叙事功能,帮助用户更容易理解图表背后表达的故事。

动态排序图

Apache ECharts 5 新增支持动态排序柱状图(bar-racing)以及动态排序折线图(line-racing),帮助开发者方便地创建带有时序性的图表,展现数据随着时间维度上的变化,讲述数据的演变过程。

动态排序图展现了不同的类目随着时间在排名上的衍变。而开发者只需要通过几行简单的配置项就可以在 ECharts 中开启这样的效果。

自定义系列动画

除了动态排序图,Apache ECharts 5 在自定义系列中提供了更加丰富强大的动画效果,支持标签数值文本的插值动画,图形的形变(morph)、分裂(separate)、合并(combine)等效果的过渡动画。

想象一下,用这些动态效果,你可以创造出多么令人称奇的可视化作品!

视觉设计

视觉设计的作用并不仅仅是为了让图表更好看,更重要的是,符合可视化原理的设计可以帮用户更快速地理解图表想表达的内容,并且尽可能消除不良设计带来的误解。

默认设计

我们发现,有很大一部分开发者使用了 ECharts 默认的主题样式,因而设计优雅、符合可视化原理的默认主题设计是非常重要的。在 Apache ECharts 5 中,我们重新设计了默认的主题样式,针对不同的系列和组件分别做了优化调整。以主题色为例,我们考量了颜色之间的区分度、与背景色的对比度、相邻颜色的和谐度等因素,并且确保色觉辨识障碍人士也能清楚地区分数据。

我们以最常用的柱状图为例,来看看新版本浅色主题和深色主题的样式:

对于折线图,我们做了比较直观的一个改变就是去掉了直角坐标系最左侧数据轴Y轴的默认显示。左侧是原本默认的折线图的样式,其实通过中间的几条数据分割线,我们就已经可以定位折线图的每个数据值。因此我们希望通过减少不必要的图形元素,来达到更清晰地传递信息的目的。

对于数据区域缩放,时间轴等交互组件,我们也设计了全新的样式并且提供了更好的交互体验:

标签

标签是图表中的核心元素之一,清晰而明确的标签可以帮助用户对数据有更准确的理解。Apache ECharts 5 提供了多种新的标签功能,让密集的标签能清晰显示、准确表意。

Apache ECharts 5 可以通过一个配置项开启自动隐藏重叠的标签。对于超出显示区域的标签,可以选择自动截断或者换行。密集的饼图标签,现在有了更美观的自动排布。

这些功能可以帮助避免文字过于密集影响可读性。并且,无需开发者编写额外的代码就能默认生效,大大简化了开发者的开发成本。

我们也提供了多个配置项来让开发者主动控制标签的布局策略,例如标签拖动、整体显示在画布边缘,用引导线和图形元素连接,并且仍可联动高亮表达关联关系。

新的标签功能可以让你在移动端这样局限的空间内也可以有很优雅的标签展示:

时间轴

Apache ECharts 5 带来了适于表达时间标签刻度的时间轴。时间轴的默认设计更突出重要的信息,并且提供了更灵活的定制化能力,让开发者根据不同的需求定制时间轴的标签内容。

首先,时间轴不再如之前般绝对平均分割,而是选取年、月、日、整点这类更有意义的点来展示,并且能同时显示不同层级的刻度。标签的 formatter 支持了时间模版(例如 {yyyy}-{MM}-{dd}),并且可以为不同时间粒度的标签指定不同的 formatter,结合已有的富文本标签,可以定制出醒目而多样的时间效果。

不同的 dataZoom 粒度下时间刻度的显示:

提示框

提示框(Tooltip)是一种最常用的可视化组件,可以帮助用户交互式地了解数据的详细信息。在 Apache ECharts 5 中,我们对提示框的样式进行了优化,通过对字体样式,颜色的调整,指向图形的箭头,跟随图形颜色的边框色等功能,让提示框的默认展示优雅又清晰。并且改进了富文本的渲染逻辑,确保显示效果与 HTML 方式一致,让用户在不同场景下可以选择不同的技术方案实现同样的效果。

除此之外,我们这次也加上了提示框内的列表按照数值大小或者类目顺序排序的功能。

仪表盘

我们看到社区用户创建了很多酷炫的仪表盘图表,但是他们的配置方式往往比较复杂而取巧。因此,我们对仪表盘的功能作了全面升级,支持了图片或者矢量路径绘制指针、也支持了锚点(anchor)配置项、进度条(progress)、圆角效果等等配置项。

不同样式的仪表盘指针:

这些升级,不仅可以让开发者用更简单的配置项实现酷炫的效果,而且带来了更丰富的定制能力。

扇形圆角

圆角可以带来更美观而柔和的视觉,也能够赋予更多的创造力。Apache ECharts 5 支持了饼图、旭日图、矩形树图的扇形圆角。可不要小看了简单的圆角配置项,合理地搭配其他的效果,就可以形成更具个性的的可视化作品。

交互能力

可视化作品的交互能力帮助用户探索了解作品,加深对于图表主旨的理解。

状态管理

在 ECharts 4 中有高亮(emphasis)和普通(normal)两个交互的状态,在鼠标移到图形上的时候会进入高亮状态以区分该数据,开发者可以分别设置这两个状态的颜色,阴影等样式。

这次在 Apache ECharts 5 中,我们在原先的鼠标 hover 高亮的基础上,新增加了淡出其它非相关元素的效果,从而可以达到聚焦目标数据的目的。

比如在这个柱状图的例子中,鼠标移到一个系列上的时候,其它非相关的系列就会淡出,从而可以更清晰的突出聚焦系列中数据的对比。在关系图,树图,旭日图,桑基等更复杂数据结构的图上,也可以通过淡出非相关元素来观察数据之间的联系。而且颜色,阴影等在高亮(emphasis)中可以设置的样式,现在也可以在淡出(blur)状态中设置了。

除此之外,我们为所有系列还添加了点击选中这个之前只有在饼图、地图等少数系列中才能开启的交互,开发者可以设置为单选或多选模式,并且通过监听 selectchanged 事件获取到选中的所有图形然后进行更进一步的处理。与高亮和淡出一样,选中的样式也可以在 select 中配置。

性能提升

脏矩形渲染

Apache ECharts 5 新支持了脏矩形渲染,解决只有局部变化的场景下的性能瓶颈。在使用 Canvas 渲染器时,脏矩形渲染技术探测并只更新视图变化的部分,而不是任何变动都引起画布完全重绘。这能在一些特殊场景下帮助提高渲染帧率,例如在图形很多时候,鼠标频繁触发一些图形高亮的场景。以往这类场景,会使用额外的 Canvas 层以优化性能,但是这种方式不是所有场景都通用,而且对于复杂的样式的效果并不理想。脏矩形渲染很好地同时满足了性能和显示正确。

脏矩形的可视化演示,红色框选部分为该帧重绘区域:

大家在新的示例页面选择开启脏矩形优化就可以看到该效果。

实时时序数据的折线图性能优化

除此之外,海量数据下折线图的性能也有了大幅度的性能提升。我们经常碰到大量的实时时序数据的高性能绘制的需求,这些数据可能需要几百或者几十毫秒更新一次。

Apache ECharts 5 对这些场景下的 CPU 消耗、内存占用、初始化时间都进行了深度的优化,使得百万量级的数据也能做到实时的更新(每次更新耗时少于 30ms),甚至对于千万级的数据,也可以在 1s 内渲染完,并且保持很小的内存占用以及流畅的提示框(tooltip)等交互。

开发体验

我们希望如此强大的可视化工具可以被更多开发者以更简单的方式使用,因而开发者的开发体验也是我们非常关注的方面。

数据集

ECharts 5 加强了数据集的数据转换能力,让开发者可以使用简单的方式实现常用的数据处理,如:数据过滤(filter)、排序(sort)、聚合(aggregate)、直方图(histogram)、简单聚类(clustering)、回归线计算(regression)等。开发者可以用统一的声明式方式来使用这些功能,可以方便地实现常用的数据操作。

国际化

ECharts 原有的国际化方案,采用的是根据不同的语言参数打包出不同的部署文件的形式。​ 这种方式,使动态的语言和静态的代码包绑定在一起,使用的时候只能通过重新加载不同语言版本的 ECharts 代码来达到切换语言的目的。

因此,从 Apache ECharts 5 开始,动态的语言包和静态的代码包分离开。切换语言的时候,只需要加载相应语言包 ​,通过类似挂载主题的方式,使用 registerLocale 函数挂载语言包对象 ​,重新初始化后就完成了语言的切换 ​。

// import the lang object and set when init​
+echarts.registerLocale('DE', lang);​
+echarts.init(DomElement, null, {​
+   locale: 'DE'​
+});

TypeScript 重构

在近 8 年的时间里,Apache ECharts 已经发展成一个非常复杂的可视化库了,为了可以更安全高效的进行重构和新功能的开发,我们在 Apache ECharts 5 的开发之初,使用 TypeScript 对代码进行了重写,TypeScript 所带来的强类型让我们更有信心地在 ECharts 5 开发的时候对代码进行大刀阔斧的重构以实现更多令人激动人心的特性。

对于开发者,我们也可以从 TypeScript 代码直接生成更好更符合代码的DTS类型描述文件。在此之前,ECharts 的类型描述文件一直是由社区开发者帮我们维护并发布到 DefinitelyTyped,这个有着不小的工作量,非常感谢大家的贡献。

除此之外,如果开发者的组件是按需引入的,我们还提供了一个 ComposeOption 类型方法,可以组合出一个只包含了引入组件的配置项类型,可以带来更严格的类型检查,帮助你提前检测到未引入的组件类型。

可访问性

Apache ECharts 一直非常重视无障碍设计,我们希望让视觉障碍人士也能平等了解图表传递的信息。并且也希望图表的开发者能以极低的开发成本实现这一点,因而有利于让开发者更愿意为视觉障碍人士提供支持。

在上一个大版本中,我们支持了根据不同的图表类型和数据自动一键智能生成图表描述的功能,帮助开发者非常方便地支持图表的 DOM 描述信息。在 ECharts 5 中,我们也做了更多提高可访问性的设计,帮助视觉障碍人士更好地理解图表内容。

主题配色

我们在设计新版默认主题样式的时候,将无障碍设计作为一个重要的考量依据,对颜色的明度和色值都进行反复测试,帮助视觉辨识障碍用户清楚地识别图表数据。​

并且,针对有更进一步无障碍需求的开发者,我们还提供了特殊的高对比度主题,以更高对比度颜色的主题将数据作进一步区分。

贴花图案

ECharts 5 还新增提供了贴花的功能,用图案辅助颜色表达,进一步帮助用户区分数据。

此外,贴花图案还能在一些其他的场景下提供帮助,比如:在报纸、书籍之类只有单色或者非常少的颜色的印刷品中,帮助更好地区分数据;用图形元素方便用户对数据产生更直观的理解等。

小结

除了以上介绍的功能,Apache ECharts 还在非常多的细节中做了改进,帮助开发者更轻松地创建默认好用、配置灵活的图表,用图表讲述数据背后的故事。

感谢所有使用过 ECharts,甚至参与过社区贡献的开发者,正是你们才使得 Apache ECharts 5 成为可能。我们会以更大的热情投入到未来的开发中,Apache ECharts 也会以更大的诚意和大家在 6 相见!

本文贡献者 在 GitHub 上编辑本页

plainheart plainheartpissang pissangjiangmaniu jiangmaniuLuckyHookin LuckyHookin
+ + + + + diff --git a/docs/zh/basics/release-note/v5-upgrade-guide/index.html b/docs/zh/basics/release-note/v5-upgrade-guide/index.html new file mode 100644 index 000000000..5b17c42f3 --- /dev/null +++ b/docs/zh/basics/release-note/v5-upgrade-guide/index.html @@ -0,0 +1,97 @@ + + + + + + + v4 升级 v5 指南 - 版本特性 - 入门篇 - 使用手册 - Apache ECharts + + +

Apache ECharts 5 升级指南

本指南面向那些希望将 echarts 4.x(以下简称 v4)升级到 echarts 5.x(以下简称 v5)的用户。大家可以在 ECharts 5 新特性 中了解这次v5带来了哪些值得升级的新特性。在绝大多数情况下,开发者用不着为这个升级做什么额外的事,因为 echarts 一直尽可能地保持 API 的稳定和向后兼容。但是,v5 仍然带来了一些非兼容改动,需要特别关注。此外,在一些情况下,v5 提供了更好的 API 用来取代之前的 API,这些被取代的 API 将不再被推荐使用(当然,我们尽量兼容了这些改动)。我们会在这篇文档里尽量详尽得解释这些改动。

非兼容性改变

默认主题(theme)

首先是默认主题的改动,v5 在配色等主题设计上做了很多的优化来达到更好的视觉效果。如果大家依旧想保留旧版本的颜色,可以手动声明颜色,如下:

chart.setOption({
+  color: [
+    '#c23531',
+    '#2f4554',
+    '#61a0a8',
+    '#d48265',
+    '#91c7ae',
+    '#749f83',
+    '#ca8622',
+    '#bda29a',
+    '#6e7074',
+    '#546570',
+    '#c4ccd3'
+  ]
+  // ...
+});

或者,做一个简单的 v4 主题:

var themeEC4 = {
+  color: [
+    '#c23531',
+    '#2f4554',
+    '#61a0a8',
+    '#d48265',
+    '#91c7ae',
+    '#749f83',
+    '#ca8622',
+    '#bda29a',
+    '#6e7074',
+    '#546570',
+    '#c4ccd3'
+  ]
+};
+var chart = echarts.init(dom, themeEC4);
+chart.setOption(/* ... */);

引用 ECharts

去除 default exports 的支持

如果使用者在 v4 中这样引用了 echarts:

import echarts from 'echarts';
+// 或者按需引入
+import echarts from 'echarts/lib/echarts';

这两种方式,v5 中不再支持了。

使用者需要如下更改代码解决这个问题:

import * as echarts from 'echarts';
+// 按需引入
+import * as echarts from 'echarts/lib/echarts';

按需引入

在 5.0.1 中,我们引入了新的按需引入接口

import * as echarts from 'echarts/core';
+import { BarChart } from 'echarts/charts';
+import { GridComponent } from 'echarts/components';
+// 注意,新的接口中默认不再包含 Canvas 渲染器,需要显示引入,如果需要使用 SVG 渲染模式则使用 SVGRenderer
+import { CanvasRenderer } from 'echarts/renderers';
+
+echarts.use([BarChart, GridComponent, CanvasRenderer]);

如果之前是使用import 'echarts/lib/chart/bar'引入,新的接口对应的是import {BarChart} from 'echarts/charts';

为了方便大家了解自己的配置项需要引入哪些模块,我们新的示例编辑页面添加了生成按需引入代码的功能,大家可以在示例编辑页的完整代码标签下选中按需引入后查看需要引入的模块以及相关代码。

在大部分情况下,我们都推荐大家尽可能用这套新的按需引入接口,它可以最大程度的利用打包工具 tree-shaking 的能力,并且可以有效解决命名空间冲突的问题而且防止了内部结构的暴露。如果你依旧在使用 CommonJS 的模块写法,之前的方式我们也依旧是支持的:

const echarts = require('echarts/lib/echarts');
+require('echarts/lib/chart/bar');
+require('echarts/lib/component/grid');

其次,因为我们的源代码已使用 TypeScript 重写,v5 将不再支持从 echarts/src 引用文件,需要改为从echarts/lib引入。

依赖调整

注意:该部分只针对为了保证较小的打包体积而是用按需引入接口的开发者,如果是全量引入的不需要关注

为了保证 tree-shaking 后的体积足够小,我们去除了一些之前会默认被打包进来的依赖。比如前面提到的在使用新的按需引入接口的时候,CanvasRenderer将不再被默认引入,这样可以保证只需要使用 SVG 渲染模式的时候不会把不需要的 Canvas 渲染代码也一起打包进来,除此之外,还有下面这些依赖的改动:

  • 在使用折线图,柱状图中不再默认引入直角坐标系组件,因此之前使用下面的引入方式
const echarts = require('echarts/lib/echarts');
+require('echarts/lib/chart/bar');
+require('echarts/lib/chart/line');

需要再单独引入grid组件

require('echarts/lib/component/grid');

参考 issue:#14080, #13764

  • 默认不再引入aria组件,如果需要的话可以手动引入。
import { AriaComponent } from 'echarts/components';
+echarts.use(AriaComponent);

或者:

require('echarts/lib/component/aria');

去除内置的 geoJSON

v5 移除了内置的 geoJSON(原先在 echarts/map 文件夹下)。这些 geoJSON 文件本就一直来源于第三方。如果使用者仍然需要他们,可以去从老版本中得到,或者自己寻找更合适的数据然后通过 registerMap 接口注册到 ECharts 中。

浏览器兼容性

v5 不再支持 IE8 浏览器。我们不再继续维护和升级之前的 VML 渲染器 来着实现 IE8 的兼容。如果使用者确实有很强的需求,那么欢迎提 pull request 来升级 VML 渲染器,或者单独维护一个第三方 VML 渲染器,我们从 v5.0.1 开始支持注册独立的渲染器了。

配置项调整

Y 轴默认不显示轴线和刻度线

v5 去掉了直角坐标系最左侧数据轴 Y 轴的默认显示。如果仍希望展示轴线和刻度线,需要显式配置:

yAxis: {
+  type: 'value',
+  // 显式设置 `axisLine.show` 和 `axisTick.show` 为 `true`
+  axisLine: {
+    show: true
+  },
+  axisTick: {
+    show: true
+  }
+}

视觉样式设置的优先级改变

v5 对调了 visualMap 组件itemStyle | lineStyle | areaStyle 的视觉样式优先级。

具体来说,v4 中,visualMap 组件 中生成的视觉样式(如,颜色、图形类型、图形尺寸等)的优先级,比开发者在 itemStyle | lineStyle | areaStyle 中设置的样式的优先级高,也就是说如果他们同时设置的话,前者会生效而后者不会生效。这带来了些麻烦:假如使用者在使用 visualMap 组件 时,又想针对某个数据项对应的图形,设置 itemStyle 样式,则做不到。v5 中于是提高了 itemStyle | lineStyle | areaStyle 的优先级,使他们能生效。

在绝大多处情况下,这个变化并不会带来什么影响。但是为保险起见,使用者在升级 v4v5 时,还是可以检查下,是否有同时使用 visualMapitemStyle | lineStyle | areaStyle 的情况。

富文本的 padding

v5 调整了 rich.?.padding 的格式使其更符合 CSS 的规范。v4 里,例如 rich.?.padding: [11, 22, 33, 44] 表示 padding-top33padding-bottom11。在 v5 中调整了上下的位置,rich.?.padding: [11, 22, 33, 44] 表示 padding-top11padding-bottom33

如果使用者有在使用 rich.?.padding,需要注意调整下这个顺序。

扩展的兼容

如果想要升级到 v5 ,下面这些扩展需要升级到最新的版本实现兼容。

不再推荐使用的 API

一些 API(包括接口调用,事件监听和配置项)在 v5 中不再推荐使用。当然,使用者仍然可以用他们,只是会在 dev 模式下,在 console 中打印一些 warning,并不会影响功能。但是从长远维护考虑,我们还是推荐升级成新的 API。

下面是不再推荐使用的 API 以及推荐的新 API:

  • 图形元素 transform 相关的属性被改变了: +
    • 变更点: +
      • position: [number, number] 改为 x: number / y: number
      • scale: [number, number] 改为 scaleX: number / scaleY: number
      • origin: [number, number] 改为 originX: number / originY: number
    • positionscaleorigin 仍然支持,但已不推荐使用。
    • 它影响到这些地方: +
      • graphic组件中:每个元素的声明。
      • custom series 中:renderItem 返回的每个元素的声明。
      • 直接使用 zrender 图形元素时。
  • Text 相关的属性被改变: +
    • 变更点: +
      • 图形元素附带的文本的声明方式被改变: +
        • 除了 Text 元素之外,其他元素中的属性 style.text 都不推荐使用了。取而代之的是新属性 textContenttextConfig,他们能带来更丰富的功能。
        • 其中,下面左边部分的这些属性已不推荐使用或废弃。请使用下面的右边部分的属性: +
          • textPosition => textConfig.position
          • textOffset => textConfig.offset
          • textRotation => textConfig.rotation
          • textDistance => textConfig.distance
      • 下面左边部分的属性在 stylestyle.rich.? 中已不推荐使用或废弃。请使用下面右边的属性: +
        • textFill => fill
        • textStroke => stroke
        • textFont => font
        • textStrokeWidth => lineWidth
        • textAlign => align
        • textVerticalAlign => verticalAlign
        • textLineHeight => lineHeight
        • textWidth => width
        • textHeight => hight
        • textBackgroundColor => backgroundColor
        • textPadding => padding
        • textBorderColor => borderColor
        • textBorderWidth => borderWidth
        • textBorderRadius => borderRadius
        • textBoxShadowColor => shadowColor
        • textBoxShadowBlur => shadowBlur
        • textBoxShadowOffsetX => shadowOffsetX
        • textBoxShadowOffsetY => shadowOffsetY
      • 注:这些属性并没有变化: +
        • textShadowColor
        • textShadowBlur
        • textShadowOffsetX
        • textShadowOffsetY
    • 它影响到这些地方: +
      • graphic 组件中:每个元素的声明。(原来的写法仍兼容,但在一些很复杂的情况下,可能效果不完全一致。)
      • 在自定义系列(custom series)中:renderItem 返回中的每个元素的声明。(原来的写法仍兼容,但在一些很复杂的情况下,可能效果不完全一致。)
      • 直接使用 zrender API 创建图形元素。(不再兼容,原写法被废弃。)
  • 图表实例上的 API: +
    • chart.one(...) 已不推荐使用。
  • label。 +
    • 属性 colortextBorderColorbackgroundColorborderColor 中,值 auto 已不推荐使用,而推荐使用 'inherit' 代替。
  • hoverAnimation: +
    • 选项 series.hoverAnimation 已不推荐使用,使用 series.emphasis.scale 代替之。
  • 折线图(line series): +
    • 选项 series.clipOverflow 已不推荐使用,使用 series.clip 代替之。
  • 自定义系列(custom series)。 +
    • renderItem 中,api.style(...)api.styleEmphasis(...) 已不推荐使用。因为这两个接口其实并不真正必要,也很难保证向后兼容。用户可以通过 api.visual(...) 获取系统自动分配的视觉信息。
  • 旭日图(sunburst): +
    • 动作类型 highlight 已被弃用,请使用 sunburstHighlight 代替。
    • 动作类型 downplay 已被弃用,请使用 sunburstUnhighlight 代替。
    • 选项 series.downplay 已被弃用,请使用 series.blur 代替。
    • 选项 series.highlightPolicy 已不适用,请使用 series.emphasis.focus 代替。
  • 饼图(pie): +
    • 下面左边部分的 action 名已经不推荐使用。请使用右边的 action 名。 +
      • pieToggleSelect => toggleSelect
      • pieSelect => select
      • pieUnSelect => unselect
    • 下面左边部分的事件名已经不推荐使用。请使用右边的事件名。 +
      • pieselectchanged => selectchanged
      • pieselected => selected
      • pieunselected => unselected
    • 选项 series.label.margin 已经不推荐使用。使用 series.label.edgeDistance 代替。
    • 选项 series.clockWise 已经不推荐使用。使用 series.clockwise 代替。
    • 选项 series.hoverOffset 已经不推荐使用。使用 series.emphasis.scaleSize 代替。
  • 地图(map series): +
    • 下文左边部分的 action 名已经不推荐使用。请使用右边的 action 名。 +
      • mapToggleSelect => toggleSelect
      • mapSelect => select
      • mapUnSelect => unselect
    • 下面左边部分的事件名已经不推荐使用。请使用右边的事件名。 +
      • mapselectchanged => selectchanged
      • mapselected => selected
      • mapunselected => unselected
    • 选项 series.mapType 已经不推荐使用。使用 series.map 代替。
    • 选项 series.mapLocation 已经不推荐使用。
  • 关系图(graph series): +
    • 选项 series.focusNodeAdjacency 已经不推荐使用。使用 series.emphasis: { focus: 'adjacency'} 代替。
  • 仪表盘(gauge series): +
    • 选项 series.clockWise 已经不推荐使用。使用 series.clockwise 代替。
    • 选项 series.hoverOffset 已经不推荐使用。使用 series.emphasis.scaleSize 代替。
  • dataZoom 组件: +
    • 选项 dataZoom.handleIcon 如果使用 SVGPath,需要前缀 path://
  • 雷达图(radar): +
    • 选项 radar.name 已经不推荐使用。使用 radar.axisName 代替。
    • 选项 radar.nameGap 已经不推荐使用。使用 radar.axisNameGap 代替。
  • Parse and format: +
    • echarts.format.formatTime 已经不推荐使用。使用 echarts.time.format 代替。
    • echarts.number.parseDate 已经不推荐使用。使用 echarts.time.parse 代替。
    • echarts.format.getTextRect 已经不推荐使用。

本文贡献者 在 GitHub 上编辑本页

plainheart plainheartpissang pissangOvilia Oviliafredricen fredricen
+ + + + + diff --git a/docs/zh/best-practices/aria/index.html b/docs/zh/best-practices/aria/index.html new file mode 100644 index 000000000..3a5d3198e --- /dev/null +++ b/docs/zh/best-practices/aria/index.html @@ -0,0 +1,37 @@ + + + + + + + 无障碍访问 - 最佳实践 - 使用手册 - Apache ECharts + + +

无障碍访问

W3C 制定了无障碍富互联网应用规范集(WAI-ARIA,the Accessible Rich Internet Applications Suite),致力于使得网页内容和网页应用能够被更多残障人士访问。

Apache ECharts 4 遵从这一规范,支持自动根据图表配置项智能生成描述,使得盲人可以在朗读设备的帮助下了解图表内容,让图表可以被更多人群访问。Apache ECharts 5 新增了贴花功能,让图表数据除了可以用颜色区分之外,还能用贴花图案区分,提供了更好的无障碍访问体验。

无障碍访问功能默认关闭,需要通过将 aria.show 设置为 true 开启。

图表描述

开启 aria.show 后,会根据图表、数据、标题等情况,自动智能生成关于图表的描述,用户也可以通过配置项修改描述。

对于配置项:

option = {
+  aria: {
+    show: true
+  },
+  title: {
+    text: '某站点用户访问来源',
+    x: 'center'
+  },
+  series: [
+    {
+      name: '访问来源',
+      type: 'pie',
+      data: [
+        { value: 335, name: '直接访问' },
+        { value: 310, name: '邮件营销' },
+        { value: 234, name: '联盟广告' },
+        { value: 135, name: '视频广告' },
+        { value: 1548, name: '搜索引擎' }
+      ]
+    }
+  ]
+};

生成的图表 DOM 上,会有一个 aria-label 属性,在朗读设备的帮助下,盲人能够了解图表的内容。其值为:

这是一个关于“某站点用户访问来源”的图表。图表类型是饼图,表示访问来源。其数据是——直接访问的数据是335,邮件营销的数据是310,联盟广告的数据是234,视频广告的数据是135,搜索引擎的数据是1548。
+

默认语言会根据语言包(默认中文)选择,也可以使用配置项自定义模板。

整体修改描述

对于有些图表,默认生成的数据点的描述并不足以表现整体的信息。比如下图的散点图,默认生成的描述可以包含数据点的坐标值,但是知道几百几千个点的坐标并不能帮助我们有效地理解图表表达的信息。

这时候,用户可以通过 aria.description 配置项指定图表的整体描述。

定制模板描述

除了整体性修改描述之外,我们还提供了生成描述的模板,可以方便地进行细粒度的修改。

生成描述的基本流程为,如果 aria.show 设置为 true,则生成无障碍访问描述,否则不生成。如果定义了 aria.description,则将其作为图表的完整描述,否则根据模板拼接生成描述。我们提供了默认的生成描述的算法,仅当生成的描述不太合适时,才需要修改这些模板,甚至使用 aria.description 完全覆盖。

使用模板拼接时,先根据是否存在标题 title.text 决定使用 aria.general.withTitle 还是 aria.general.withoutTitle 作为整体性描述。其中,aria.general.withTitle 配置项包括模板变量 '{title}',将会被替换成图表标题。也就是说,如果 aria.general.withTitle 被设置为 '图表的标题是:{title}。',则如果包含标题 '价格分布图',这部分的描述为 '图表的标题是:价格分布图。'

拼接完标题之后,会依次拼接系列的描述(aria.series),和每个系列的数据的描述(aria.data)。同样,每个模板都有可能包括模板变量,用以替换实际的值。

完整的描述生成流程请参见 ARIA 文档

贴花图案

除此之外,Apache ECharts 5 新增支持贴花纹理,作为颜色的辅助表达,进一步用以区分数据。在 aria.enabledtrue 的前提下,将 aria.decal.show 设为 true 即可采用默认的贴花样式。

如果需要自定义贴花图案,可以使用 aria.decal.decals 配置出灵活多变的图案。

更具体的信息请参见 ARIA 文档

本文贡献者 在 GitHub 上编辑本页

Ovilia Oviliaplainheart plainheartpissang pissang
+ + + + + diff --git a/docs/zh/best-practices/canvas-vs-svg/index.html b/docs/zh/best-practices/canvas-vs-svg/index.html new file mode 100644 index 000000000..be37c8e76 --- /dev/null +++ b/docs/zh/best-practices/canvas-vs-svg/index.html @@ -0,0 +1,26 @@ + + + + + + + Canvas vs. SVG - 最佳实践 - 使用手册 - Apache ECharts + + +

使用 Canvas 或者 SVG 渲染

浏览器端图表库大多会选择 SVG 或者 Canvas 进行渲染。对于绘制图表来说,这两种技术往往是可替换的,效果相近。但是在一些场景中,他们的表现和能力又有一定差异。于是,对它们的选择取舍,就成为了一个一直存在的不易有标准答案的话题。

ECharts 从初始一直使用 Canvas 绘制图表。而 ECharts v4.0 发布了 SVG 渲染器,从而提供了一种新的选择。在初始化图表实例时,只需设置 renderer 参数'canvas''svg' 即可指定渲染器,比较方便。

SVG 和 Canvas 这两种使用方式差异很大的技术,能够做到同时被透明支持,主要归功于 ECharts 底层库 ZRender 的抽象和实现,形成可互换的 SVG 渲染器和 Canvas 渲染器。

选择哪种渲染器

一般来说,Canvas 更适合绘制图形元素数量较多(这一般是由数据量大导致)的图表(如热力图、地理坐标系或平行坐标系上的大规模线图或散点图等),也利于实现某些视觉 特效。但是,在不少场景中,SVG 具有重要的优势:它的内存占用更低(这对移动端尤其重要)、并且用户使用浏览器内置的缩放功能时不会模糊。

选择哪种渲染器,我们可以根据软硬件环境、数据量、功能需求综合考虑。

  • 在软硬件环境较好,数据量不大的场景下,两种渲染器都可以适用,并不需要太多纠结。
  • 在环境较差,出现性能问题需要优化的场景下,可以通过试验来确定使用哪种渲染器。比如有这些经验: +
    • 在需要创建很多 ECharts 实例且浏览器易崩溃的情况下(可能是因为 Canvas 数量多导致内存占用超出手机承受能力),可以使用 SVG 渲染器来进行改善。大略的说,如果图表运行在低端安卓机,或者我们在使用一些特定图表如 水球图 等,SVG 渲染器可能效果更好。
    • 数据量较大(经验判断 > 1k)、较多交互时,建议选择 Canvas 渲染器。

我们强烈欢迎开发者们反馈给我们使用的体验和场景,帮助我们更好的做优化。

注:当前某些特殊的渲染依然需要依赖 Canvas:如炫光尾迹特效带有混合效果的热力图等。

我们在 v5.3.0 中使用虚拟 DOM 技术对 SVG 渲染器进行了重构,从而使其渲染性能提升了 2~10 倍,在某些特殊场景中甚至能有数十倍的提升!参见 #836

如何使用渲染器

如果是用如下的方式完整引入echarts,代码中已经包含了 SVG 渲染器和 Canvas 渲染器

import * as echarts from 'echarts';

如果你是按照 在项目中引入 Apache ECharts 一文中的介绍使用按需引入,则需要手动引入需要的渲染器

import * as echarts from 'echarts/core';
+// 可以根据需要选用只用到的渲染器
+import { SVGRenderer, CanvasRenderer } from 'echarts/renderers';
+
+echarts.use([SVGRenderer, CanvasRenderer]);

然后,我们就可以在代码中,初始化图表实例时,传入参数 选择渲染器类型:

// 使用 Canvas 渲染器(默认)
+var chart = echarts.init(containerDom, null, { renderer: 'canvas' });
+// 等价于:
+var chart = echarts.init(containerDom);
+
+// 使用 SVG 渲染器
+var chart = echarts.init(containerDom, null, { renderer: 'svg' });

本文贡献者 在 GitHub 上编辑本页

plainheart plainheartpissang pissangChengxi9 Chengxi9btea btea
+ + + + + diff --git a/docs/zh/concepts/axis/index.html b/docs/zh/concepts/axis/index.html new file mode 100644 index 000000000..c54b8ffef --- /dev/null +++ b/docs/zh/concepts/axis/index.html @@ -0,0 +1,283 @@ + + + + + + + 坐标轴 - 概念篇 - 使用手册 - Apache ECharts + + +

坐标轴

直角坐标系中的 x/y 轴。

x 轴、y 轴

x 轴和 y 轴都由轴线、刻度、刻度标签、轴标题四个部分组成。部分图表中还会有网格线来帮助查看和计算数据

普通的二维数据坐标系都有 x 轴和 y 轴,通常情况下,x 轴显示在图表的底部,y 轴显示在左侧,一般配置如下:

option = {
+  xAxis: {
+    // ...
+  },
+  yAxis: {
+    // ...
+  }
+};

x 轴常用来标示数据的维度,维度一般用来指数据的类别,是观察数据的角度,例如“销售时间” “销售地点” “产品名称”等。y 轴常常用来标示数据的数值,数值是用来具体考察某一类数据的数量值,也是我们需要分析的指标,例如“销售数量”和“销售金额”等。

option = {
+  xAxis: {
+    type: 'time',
+    name: '销售时间'
+    // ...
+  },
+  yAxis: {
+    type: 'value',
+    name: '销售数量'
+    // ...
+  }
+  // ...
+};

当 x 轴(水平坐标轴)跨度很大,可以采用区域缩放方式灵活显示数据内容。

option = {
+  xAxis: {
+    type: 'time',
+    name: '销售时间'
+    // ...
+  },
+  yAxis: {
+    type: 'value',
+    name: '销售数量'
+    // ...
+  },
+  dataZoom: [
+    // ...
+  ]
+  // ...
+};

在二维数据中,轴也可以有多个。ECharts 中一般情况下单个 grid 组件最多只能放两个 x/y 轴,多于两个 x/y 轴需要通过配置 offset 属性防止同个位置多个轴的重叠。两个 x 轴显示在上下,两个 y 轴显示在左右两侧。

option = {
+  xAxis: {
+    type: 'time',
+    name: '销售时间'
+    // ...
+  },
+  yAxis: [
+    {
+      type: 'value',
+      name: '销售数量'
+      // ...
+    },
+    {
+      type: 'value',
+      name: '销售金额'
+      // ...
+    }
+  ]
+  // ...
+};

轴线

ECharts 提供了轴线 axisLine 相关的配置,我们可以根据实际情况调整,例如轴线两端的箭头,轴线的样式等。

option = {
+  xAxis: {
+    axisLine: {
+      symbol: 'arrow',
+      lineStyle: {
+        type: 'dashed'
+        // ...
+      }
+    }
+    // ...
+  },
+  yAxis: {
+    axisLine: {
+      symbol: 'arrow',
+      lineStyle: {
+        type: 'dashed'
+        // ...
+      }
+    }
+  }
+  // ...
+};

刻度

ECharts 提供了轴线 axisTick 相关的配置,我们可以根据实际情况调整,例如刻度线的长度,样式等。

option = {
+  xAxis: {
+    axisTick: {
+      length: 6,
+      lineStyle: {
+        type: 'dashed'
+        // ...
+      }
+    }
+    // ...
+  },
+  yAxis: {
+    axisTick: {
+      length: 6,
+      lineStyle: {
+        type: 'dashed'
+        // ...
+      }
+    }
+  }
+  // ...
+};

刻度标签

ECharts 提供了轴线 axisLabel 相关的配置,我们可以根据实际情况调整,例如文字对齐方式,自定义刻度标签内容等。

option = {
+  xAxis: {
+    axisLabel: {
+      formatter: '{value} kg',
+      align: 'center'
+      // ...
+    }
+    // ...
+  },
+  yAxis: {
+    axisLabel: {
+      formatter: '{value} 元',
+      align: 'center'
+      // ...
+    }
+  }
+  // ...
+};

示例

图左侧的 y 轴代表东京月平均气温,右侧的 y 轴表示东京降水量,x 轴表示时间。两组 y 轴在一起,反映了平均气温和降水量间的趋势关系。

option = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: { type: 'cross' }
+  },
+  legend: {},
+  xAxis: [
+    {
+      type: 'category',
+      axisTick: {
+        alignWithLabel: true
+      },
+      data: [
+        '1月',
+        '2月',
+        '3月',
+        '4月',
+        '5月',
+        '6月',
+        '7月',
+        '8月',
+        '9月',
+        '10月',
+        '11月',
+        '12月'
+      ]
+    }
+  ],
+  yAxis: [
+    {
+      type: 'value',
+      name: '降水量',
+      min: 0,
+      max: 250,
+      position: 'right',
+      axisLabel: {
+        formatter: '{value} ml'
+      }
+    },
+    {
+      type: 'value',
+      name: '温度',
+      min: 0,
+      max: 25,
+      position: 'left',
+      axisLabel: {
+        formatter: '{value} °C'
+      }
+    }
+  ],
+  series: [
+    {
+      name: '降水量',
+      type: 'bar',
+      yAxisIndex: 0,
+      data: [6, 32, 70, 86, 68.7, 100.7, 125.6, 112.2, 78.7, 48.8, 36.0, 19.3]
+    },
+    {
+      name: '温度',
+      type: 'line',
+      smooth: true,
+      yAxisIndex: 1,
+      data: [
+        6.0,
+        10.2,
+        10.3,
+        11.5,
+        10.3,
+        13.2,
+        14.3,
+        16.4,
+        18.0,
+        16.5,
+        12.0,
+        5.2
+      ]
+    }
+  ]
+};
live

这里简要介绍了坐标轴相关的常用配置项及用法,更多关于坐标轴配置项及用法请移步官网

本文贡献者 在 GitHub 上编辑本页

pissang pissangOvilia Oviliaplainheart plainheartEssentric Essentric
+ + + + + diff --git a/docs/zh/concepts/chart-size/index.html b/docs/zh/concepts/chart-size/index.html new file mode 100644 index 000000000..f7d52661d --- /dev/null +++ b/docs/zh/concepts/chart-size/index.html @@ -0,0 +1,43 @@ + + + + + + + 图表容器及大小 - 概念篇 - 使用手册 - Apache ECharts + + +

图表容器及大小

快速上手中,我们介绍了初始化 ECharts 的接口 echarts.initAPI 文档中详细介绍了参数的具体含义,建议理解后再阅读本文。

下面,我们就常见的几种使用场景,介绍如何初始化一个图表以及改变其大小。

初始化

在 HTML 中定义有宽度和高度的父容器(推荐)

通常来说,需要在 HTML 中先定义一个 <div> 节点,并且通过 CSS 使得该节点具有宽度和高度。初始化的时候,传入该节点,图表的大小默认即为该节点的大小,除非声明了 opts.widthopts.height 将其覆盖。

<div id="main" style="width: 600px;height:400px;"></div>
+<script type="text/javascript">
+  var myChart = echarts.init(document.getElementById('main'));
+</script>

需要注意的是,使用这种方法在调用 echarts.init 时需保证容器已经有宽度和高度了。

指定图表的大小

如果图表容器不存在宽度和高度,或者,你希望图表宽度和高度不等于容器大小,也可以在初始化的时候指定大小。

<div id="main"></div>
+<script type="text/javascript">
+  var myChart = echarts.init(document.getElementById('main'), null, {
+    width: 600,
+    height: 400
+  });
+</script>

响应容器大小的变化

监听图表容器的大小并改变图表大小

在有些场景下,我们希望当容器大小改变时,图表的大小也相应地改变。

比如,图表容器是一个高度为 400px、宽度为页面 100% 的节点,你希望在浏览器宽度改变的时候,始终保持图表宽度是页面的 100%。

这种情况下,可以监听页面的 resize 事件获取浏览器大小改变的事件,然后调用 echartsInstance.resize 改变图表的大小。

<style>
+  #main,
+  html,
+  body {
+    width: 100%;
+  }
+  #main {
+    height: 400px;
+  }
+</style>
+<div id="main"></div>
+<script type="text/javascript">
+  var myChart = echarts.init(document.getElementById('main'));
+  window.addEventListener('resize', function() {
+    myChart.resize();
+  });
+</script>

小贴士:有时候我们可能会通过 JS 或 CSS 调整容器大小,由于页面大小并未发生改变,因此 resize 事件将不会被触发。如果有需要覆盖这种情况,可以借助浏览器的 ResizeObserver API 来实现更细粒度的监听。

为图表设置特定的大小

除了直接调用 resize() 不含参数的形式之外,还可以指定宽度和高度,实现图表大小不等于容器大小的效果。

myChart.resize({
+  width: 800,
+  height: 400
+});

小贴士:阅读 API 文档的时候要留意接口的定义方式,这一接口有时会被误认为是 myCharts.resize(800, 400) 的形式,但其实不存在这样的调用方式。

容器节点被销毁以及被重建时

假设页面中存在多个标签页,每个标签页都包含一些图表。当选中一个标签页的时候,其他标签页的内容在 DOM 中被移除了。这样,当用户再选中这些标签页的时候,就会发现图表“不见”了。

本质上,这是由于图表的容器节点被移除导致的。即使之后该节点被重新添加,图表所在的节点也已经不存在了。

正确的做法是,在图表容器被销毁之后,调用 echartsInstance.dispose 销毁实例,在图表容器重新被添加后再次调用 echarts.init 初始化。

小贴士:在容器节点被销毁时,总是应调用 echartsInstance.dispose 以销毁实例释放资源,避免内存泄漏。

本文贡献者 在 GitHub 上编辑本页

pissang pissangOvilia Oviliaplainheart plainheartppd0705 ppd0705
+ + + + + diff --git a/docs/zh/concepts/data-transform/index.html b/docs/zh/concepts/data-transform/index.html new file mode 100644 index 000000000..672a293a5 --- /dev/null +++ b/docs/zh/concepts/data-transform/index.html @@ -0,0 +1,598 @@ + + + + + + + 数据转换 - 概念篇 - 使用手册 - Apache ECharts + + +

使用 transform 进行数据转换

Apache EChartsTM 5 开始支持了“数据转换”( data transform )功能。在 echarts 中,“数据转换” 这个词指的是,给定一个已有的“数据集”(dataset)和一个“转换方法”(transform),echarts 能生成一个新的“数据集”,然后可以使用这个新的“数据集”绘制图表。这些工作都可以声明式地完成。

抽象地来说,数据转换是这样一种公式:outData = f(inputData)f 是转换方法,例如:filtersortregressionboxplotclusteraggregate(todo) 等等。有了数据转换能力后,我们就至少可以做到这些事情:

  • 把数据分成多份用不同的饼图展现。
  • 进行一些数据统计运算,并展示结果。
  • 用某些数据可视化算法处理数据,并展示结果。
  • 数据排序。
  • 去除或直选择数据项。
  • ...

数据转换基础使用

在 echarts 中,数据转换是依托于数据集(dataset)来实现的. 我们可以设置 dataset.transform 来表示,此 dataset 的数据,来自于此 transform 的结果。

下面是上述例子的效果,三个饼图分别显示了 2011、2012、2013 年的数据。

var option = {
+  dataset: [
+    {
+      // 这个 dataset 的 index 是 `0`。
+      source: [
+        ['Product', 'Sales', 'Price', 'Year'],
+        ['Cake', 123, 32, 2011],
+        ['Cereal', 231, 14, 2011],
+        ['Tofu', 235, 5, 2011],
+        ['Dumpling', 341, 25, 2011],
+        ['Biscuit', 122, 29, 2011],
+        ['Cake', 143, 30, 2012],
+        ['Cereal', 201, 19, 2012],
+        ['Tofu', 255, 7, 2012],
+        ['Dumpling', 241, 27, 2012],
+        ['Biscuit', 102, 34, 2012],
+        ['Cake', 153, 28, 2013],
+        ['Cereal', 181, 21, 2013],
+        ['Tofu', 395, 4, 2013],
+        ['Dumpling', 281, 31, 2013],
+        ['Biscuit', 92, 39, 2013],
+        ['Cake', 223, 29, 2014],
+        ['Cereal', 211, 17, 2014],
+        ['Tofu', 345, 3, 2014],
+        ['Dumpling', 211, 35, 2014],
+        ['Biscuit', 72, 24, 2014]
+      ]
+      // id: 'a'
+    },
+    {
+      // 这个 dataset 的 index 是 `1`。
+      // 这个 `transform` 配置,表示,此 dataset 的数据,来自于此 transform 的结果。
+      transform: {
+        type: 'filter',
+        config: { dimension: 'Year', value: 2011 }
+      }
+      // 我们还可以设置这些可选的属性: `fromDatasetIndex` 或 `fromDatasetId`。
+      // 这些属性,指定了,transform 的输入,来自于哪个 dataset。例如,
+      // `fromDatasetIndex: 0` 表示输入来自于 index 为 `0` 的 dataset 。又例如,
+      // `fromDatasetId: 'a'` 表示输入来自于 `id: 'a'` 的 dataset。
+      // 当这些属性都不指定时,默认认为,输入来自于 index 为 `0` 的 dataset 。
+    },
+    {
+      // 这个 dataset 的 index 是 `2`。
+      // 同样,这里因为 `fromDatasetIndex` 和 `fromDatasetId` 都没有被指定,
+      // 那么输入默认来自于 index 为 `0` 的 dataset 。
+      transform: {
+        // 这个类型为 "filter" 的 transform 能够遍历并筛选出满足条件的数据项。
+        type: 'filter',
+        // 每个 transform 如果需要有配置参数的话,都须配置在 `config` 里。
+        // 在这个 "filter" transform 中,`config` 用于指定筛选条件。
+        // 下面这个筛选条件是:选出维度( dimension )'Year' 中值为 2012 的所有
+        // 数据项。
+        config: { dimension: 'Year', value: 2012 }
+      }
+    },
+    {
+      // 这个 dataset 的 index 是 `3`。
+      transform: {
+        type: 'filter',
+        config: { dimension: 'Year', value: 2013 }
+      }
+    }
+  ],
+  series: [
+    {
+      type: 'pie',
+      radius: 50,
+      center: ['25%', '50%'],
+      // 这个饼图系列,引用了 index 为 `1` 的 dataset 。也就是,引用了上述
+      // 2011 年那个 "filter" transform 的结果。
+      datasetIndex: 1
+    },
+    {
+      type: 'pie',
+      radius: 50,
+      center: ['50%', '50%'],
+      datasetIndex: 2
+    },
+    {
+      type: 'pie',
+      radius: 50,
+      center: ['75%', '50%'],
+      datasetIndex: 3
+    }
+  ]
+};
live

现在我们简单总结下,使用 transform 时的几个要点:

  • 在一个空的 dataset 中声明 transform, fromDatasetIndex/fromDatasetId 来表示我们要生成新的数据。
  • 系列引用这个 dataset 。

数据转换的进阶使用

链式声明 transform

transform 可以被链式声明,这是一个语法糖。

option = {
+  dataset: [
+    {
+      source: [
+        // 原始数据
+      ]
+    },
+    {
+      // 几个 transform 被声明成 array ,他们构成了一个链,
+      // 前一个 transform 的输出是后一个 transform 的输入。
+      transform: [
+        {
+          type: 'filter',
+          config: { dimension: 'Product', value: 'Tofu' }
+        },
+        {
+          type: 'sort',
+          config: { dimension: 'Year', order: 'desc' }
+        }
+      ]
+    }
+  ],
+  series: {
+    type: 'pie',
+    // 这个系列引用上述 transform 的结果。
+    datasetIndex: 1
+  }
+};

注意:理论上,任何 transform 都可能有多个输入或多个输出。但是,如果一个 transform 被链式声明,它只能获取前一个 transform 的第一个输出作为输入(第一个 transform 除外),以及它只能把自己的第一个输出给到后一个 transform (最后一个 transform 除外)。

一个 transform 输出多个 data

在大多数场景下,transform 只需输出一个 data 。但是也有一些场景,需要输出多个 data ,每个 data 可以被不同的 series 或者 dataset 所使用。

例如,在内置的 "boxplot" transform 中,除了 boxplot 系列所需要的 data 外,离群点( outlier )也会被生成,并且可以用例如散点图系列显示出来。例如,example

我们提供配置 dataset.fromTransformResult 来满足这种情况,例如:

option = {
+  dataset: [
+    {
+      // 这个 dataset 的 index 为 `0`。
+      source: [
+        // 原始数据
+      ]
+    },
+    {
+      // 这个 dataset 的 index 为 `1`。
+      transform: {
+        type: 'boxplot'
+      }
+      // 这个 "boxplot" transform 生成了两个数据:
+      // result[0]: boxplot series 所需的数据。
+      // result[1]: 离群点数据。
+      // 当其他 series 或者 dataset 引用这个 dataset 时,他们默认只能得到
+      // result[0] 。
+      // 如果想要他们得到 result[1] ,需要额外声明如下这样一个 dataset :
+    },
+    {
+      // 这个 dataset 的 index 为 `2`。
+      // 这个额外的 dataset 指定了数据来源于 index 为 `1` 的 dataset。
+      fromDatasetIndex: 1,
+      // 并且指定了获取 transform result[1] 。
+      fromTransformResult: 1
+    }
+  ],
+  xAxis: {
+    type: 'category'
+  },
+  yAxis: {},
+  series: [
+    {
+      name: 'boxplot',
+      type: 'boxplot',
+      // Reference the data from result[0].
+      // 这个 series 引用 index 为 `1` 的 dataset 。
+      datasetIndex: 1
+    },
+    {
+      name: 'outlier',
+      type: 'scatter',
+      // 这个 series 引用 index 为 `2` 的 dataset 。
+      // 从而也就得到了上述的 transform result[1] (即离群点数据)
+      datasetIndex: 2
+    }
+  ]
+};

另外,dataset.fromTransformResultdataset.transform 能同时出现在一个 dataset 中,这表示,这个 transform 的输入,是上游的结果中以 fromTransformResult 获取的结果。例如:

{
+  fromDatasetIndex: 1,
+  fromTransformResult: 1,
+  transform: {
+    type: 'sort',
+    config: { dimension: 2, order: 'desc' }
+  }
+}

在开发环境中 debug

使用 transform 时,有时候我们会配不对,显示不出来结果,并且不知道哪里错了。所以,这里提供了一个配置项 transform.print 方便 debug 。这个配置项只在开发环境中生效。如下例:

option = {
+  dataset: [
+    {
+      source: []
+    },
+    {
+      transform: {
+        type: 'filter',
+        config: {},
+        // 配置为 `true` 后, transform 的结果
+        // 会被 console.log 打印出来。
+        print: true
+      }
+    }
+  ]
+  // ...
+};

数据转换器 "filter"

echarts 内置提供了能起过滤作用的数据转换器。我们只需声明 transform.type: "filter",以及给出数据筛选条件。如下例:

option = {
+  dataset: [
+    {
+      source: [
+        ['Product', 'Sales', 'Price', 'Year'],
+        ['Cake', 123, 32, 2011],
+        ['Latte', 231, 14, 2011],
+        ['Tofu', 235, 5, 2011],
+        ['Milk Tee', 341, 25, 2011],
+        ['Porridge', 122, 29, 2011],
+        ['Cake', 143, 30, 2012],
+        ['Latte', 201, 19, 2012],
+        ['Tofu', 255, 7, 2012],
+        ['Milk Tee', 241, 27, 2012],
+        ['Porridge', 102, 34, 2012],
+        ['Cake', 153, 28, 2013],
+        ['Latte', 181, 21, 2013],
+        ['Tofu', 395, 4, 2013],
+        ['Milk Tee', 281, 31, 2013],
+        ['Porridge', 92, 39, 2013],
+        ['Cake', 223, 29, 2014],
+        ['Latte', 211, 17, 2014],
+        ['Tofu', 345, 3, 2014],
+        ['Milk Tee', 211, 35, 2014],
+        ['Porridge', 72, 24, 2014]
+      ]
+    },
+    {
+      transform: {
+        type: 'filter',
+        config: { dimension: 'Year', '=': 2011 }
+        // 这个筛选条件表示,遍历数据,筛选出维度( dimension )
+        // 'Year' 上值为 2011 的所有数据项。
+      }
+    }
+  ],
+  series: {
+    type: 'pie',
+    datasetIndex: 1
+  }
+};
live

这是 filter 的另一个例子的效果:

在 "filter" transform 中,有这些要素:

关于维度( dimension ):

config.dimension 指定了维度,能设成这样的值:

  • 设定成声明在 dataset 中的维度名,例如 config: { dimension: 'Year', '=': 2011 }。不过, dataset 中维度名的声明并非强制,所以我们也可以
  • 设定成 dataset 中的维度 index (index 值从 0 开始)例如 config: { dimension: 3, '=': 2011 }

关于关系比较操作符:

关系操作符,可以设定这些: +>gt)、>=gte)、<lt)、<=lte)、=eq)、!=ne<>)、reg。(小括号中的符号或名字,是别名,设置起来作用相同)。他们首先基本地能基于数值大小进行比较,然后也有些额外的功能特性:

  • 多个关系操作符能声明在一个 {} 中,例如 { dimension: 'Price', '>=': 20, '<': 30 }。这表示“与”的关系,即,筛选出价格大于等于 20 小于 30 的数据项。
  • data 里的值,不仅可以是数值( number ),也可以是“类数值的字符串”(“ numeric string ”)。“类数值的字符串”本身是一个字符串,但是可以被转换为字面所描述的数值,例如 ' 123 '。转换过程中,空格(全角半角空格)和换行符都能被消除( trim )。
  • 如果我们需要对日期对象(JS Date)或者日期字符串(如 '2012-05-12')进行比较,我们需要手动指定 parser: 'time',例如 config: { dimension: 3, lt: '2012-05-12', parser: 'time' }
  • 纯字符串比较也被支持,但是只能用在 =!= 上。而 >, >=, <, <= 并不支持纯字符串比较,也就是说,这四个操作符的右值,不能是字符串。
  • reg 操作符能提供正则表达式比较。例如, { dimension: 'Name', reg: /\s+Müller\s*$/ } 能在 'Name' 维度上选出姓 'Müller' 的数据项。

关于逻辑比较:

我们也支持了逻辑比较操作符 与或非and | or | not ):

option = {
+  dataset: [
+    {
+      source: [
+        // ...
+      ]
+    },
+    {
+      transform: {
+        type: 'filter',
+        config: {
+          // 使用 and 操作符。
+          // 类似地,同样的位置也可以使用 “or” 或 “not”。
+          // 但是注意 “not” 后应该跟一个 {...} 而非 [...] 。
+          and: [
+            { dimension: 'Year', '=': 2011 },
+            { dimension: 'Price', '>=': 20, '<': 30 }
+          ]
+        }
+        // 这个表达的是,选出 2011 年价格大于等于 20 但小于 30 的数据项。
+      }
+    }
+  ],
+  series: {
+    type: 'pie',
+    datasetIndex: 1
+  }
+};

and/or/not 自然可以被嵌套,例如:

transform: {
+  type: 'filter',
+  config: {
+    or: [{
+      and: [{
+        dimension: 'Price', '>=': 10, '<': 20
+      }, {
+        dimension: 'Sales', '<': 100
+      }, {
+        not: { dimension: 'Product', '=': 'Tofu' }
+      }]
+    }, {
+      and: [{
+        dimension: 'Price', '>=': 10, '<': 20
+      }, {
+        dimension: 'Sales', '<': 100
+      }, {
+        not: { dimension: 'Product', '=': 'Cake' }
+      }]
+    }]
+  }
+}

关于解析器( parser ):

还可以指定“解析器”( parser )来对值进行解析后再做比较。现在支持的解析器有:

  • parser: 'time':把原始值解析成时间戳( timestamp )后再做比较。这个解析器的行为,和 echarts.time.parse 相同,即,当原始值为时间对象( JS Date 实例),或者是时间戳,或者是描述时间的字符串(例如 '2012-05-12 03:11:22' ),都可以被解析为时间戳,然后就可以基于数值大小进行比较。如果原始数据是其他不可解析为时间戳的值,那么会被解析为 NaN。
  • parser: 'trim':如果原始数据是字符串,则把字符串两端的空格(全角半角)和换行符去掉。如果不是字符串,还保持为原始数据。
  • parser: 'number':强制把原始数据转成数值。如果不能转成有意义的数值,那么转成 NaN。在大多数场景下,我们并不需要这个解析器,因为按默认策略,“像数值的字符串”就会被转成数值。但是默认策略比较严格,这个解析器比较宽松,如果我们遇到含有尾缀的字符串(例如 '33%', 12px),我们需要手动指定 parser: 'number',从而去掉尾缀转为数值才能比较。

这个例子显示了如何使用 parser: 'time'

option = {
+  dataset: [
+    {
+      source: [
+        ['Product', 'Sales', 'Price', 'Date'],
+        ['Milk Tee', 311, 21, '2012-05-12'],
+        ['Cake', 135, 28, '2012-05-22'],
+        ['Latte', 262, 36, '2012-06-02'],
+        ['Milk Tee', 359, 21, '2012-06-22'],
+        ['Cake', 121, 28, '2012-07-02'],
+        ['Latte', 271, 36, '2012-06-22']
+        // ...
+      ]
+    },
+    {
+      transform: {
+        type: 'filter',
+        config: {
+          dimension: 'Date',
+          '>=': '2012-05',
+          '<': '2012-06',
+          parser: 'time'
+        }
+      }
+    }
+  ]
+};

形式化定义:

最后,我们给出,数据转换器 "filter" 的 config 的形式化定义:

type FilterTransform = {
+  type: 'filter';
+  config: ConditionalExpressionOption;
+};
+type ConditionalExpressionOption =
+  | true
+  | false
+  | RelationalExpressionOption
+  | LogicalExpressionOption;
+type RelationalExpressionOption = {
+  dimension: DimensionName | DimensionIndex;
+  parser?: 'time' | 'trim' | 'number';
+  lt?: DataValue; // less than
+  lte?: DataValue; // less than or equal
+  gt?: DataValue; // greater than
+  gte?: DataValue; // greater than or equal
+  eq?: DataValue; // equal
+  ne?: DataValue; // not equal
+  '<'?: DataValue; // lt
+  '<='?: DataValue; // lte
+  '>'?: DataValue; // gt
+  '>='?: DataValue; // gte
+  '='?: DataValue; // eq
+  '!='?: DataValue; // ne
+  '<>'?: DataValue; // ne (SQL style)
+  reg?: RegExp | string; // RegExp
+};
+type LogicalExpressionOption = {
+  and?: ConditionalExpressionOption[];
+  or?: ConditionalExpressionOption[];
+  not?: ConditionalExpressionOption;
+};
+type DataValue = string | number | Date;
+type DimensionName = string;
+type DimensionIndex = number;

注意:使用按需引入接口时,如果需要使用该内置转换器,除了 Dataset 组件,还需引入 Transform 组件。

import {
+  DatasetComponent,
+  TransformComponent
+} from 'echarts/components';
+
+echarts.use([
+  DatasetComponent,
+  TransformComponent
+]);

数据转换器 "sort"

"sort" 是另一个内置的数据转换器,用于排序数据。目前主要能用于在类目轴( axis.type: 'category' )中显示排过序的数据。例如:

option = {
+  dataset: [
+    {
+      dimensions: ['name', 'age', 'profession', 'score', 'date'],
+      source: [
+        [' Hannah Krause ', 41, 'Engineer', 314, '2011-02-12'],
+        ['Zhao Qian ', 20, 'Teacher', 351, '2011-03-01'],
+        [' Jasmin Krause ', 52, 'Musician', 287, '2011-02-14'],
+        ['Li Lei', 37, 'Teacher', 219, '2011-02-18'],
+        [' Karle Neumann ', 25, 'Engineer', 253, '2011-04-02'],
+        [' Adrian Groß', 19, 'Teacher', null, '2011-01-16'],
+        ['Mia Neumann', 71, 'Engineer', 165, '2011-03-19'],
+        [' Böhm Fuchs', 36, 'Musician', 318, '2011-02-24'],
+        ['Han Meimei ', 67, 'Engineer', 366, '2011-03-12']
+      ]
+    },
+    {
+      transform: {
+        type: 'sort',
+        // 按分数排序
+        config: { dimension: 'score', order: 'asc' }
+      }
+    }
+  ],
+  series: {
+    type: 'bar',
+    datasetIndex: 1
+  }
+  // ...
+};

数据转换器 "sort" 还有一些额外的功能:

  • 可以多重排序,多个维度一起排序。见下面的例子。
  • 排序规则是这样的: +
    • 默认按照数值大小排序。其中,“可转为数值的字符串”也被转换成数值,和其他数值一起按大小排序。
    • 对于其他“不能转为数值的字符串”,也能在它们之间按字符串进行排序。这个特性有助于这种场景:把相同标签的数据项排到一起,尤其是当多个维度共同排序时。见下面的例子。
    • 当“数值及可转为数值的字符串”和“不能转为数值的字符串”进行排序时,或者它们和“其他类型的值”进行比较时,它们本身是不知如何进行比较的。那么我们称呼“后者”为“incomparable”,并且可以设置 incomparable: 'min' | 'max' 来指定一个“incomparable”在这个比较中是最大还是最小,从而能使它们能产生比较结果。这个设定的用途,比如可以是,决定空值(例如 null, undefined, NaN, '', '-')在排序的头还是尾。
  • 解析器 parser: 'time' | 'trim' | 'number' 可以被使用,和数据转换器 "filter" 中的情况一样。 +
    • 如果要对时间进行排序(例如,值为 JS Date 实例或者时间字符串如 '2012-03-12 11:13:54'),我们需要声明 parser: 'time'
    • 如果需要对有后缀的数值进行排序(如 '33%', '16px')我们需要声明 parser: 'number'

这是一个“多维度排序”的例子。

option = {
+  dataset: [
+    {
+      dimensions: ['name', 'age', 'profession', 'score', 'date'],
+      source: [
+        [' Hannah Krause ', 41, 'Engineer', 314, '2011-02-12'],
+        ['Zhao Qian ', 20, 'Teacher', 351, '2011-03-01'],
+        [' Jasmin Krause ', 52, 'Musician', 287, '2011-02-14'],
+        ['Li Lei', 37, 'Teacher', 219, '2011-02-18'],
+        [' Karle Neumann ', 25, 'Engineer', 253, '2011-04-02'],
+        [' Adrian Groß', 19, 'Teacher', null, '2011-01-16'],
+        ['Mia Neumann', 71, 'Engineer', 165, '2011-03-19'],
+        [' Böhm Fuchs', 36, 'Musician', 318, '2011-02-24'],
+        ['Han Meimei ', 67, 'Engineer', 366, '2011-03-12']
+      ]
+    },
+    {
+      transform: {
+        type: 'sort',
+        config: [
+          // 对两个维度按声明的优先级分别排序。
+          { dimension: 'profession', order: 'desc' },
+          { dimension: 'score', order: 'desc' }
+        ]
+      }
+    }
+  ],
+  series: {
+    type: 'bar',
+    datasetIndex: 1
+  }
+  //...
+};

最后,我们给出数据转换器 "sort" 的 config 的形式化定义。

type SortTransform = {
+  type: 'sort';
+  config: OrderExpression | OrderExpression[];
+};
+type OrderExpression = {
+  dimension: DimensionName | DimensionIndex;
+  order: 'asc' | 'desc';
+  incomparable?: 'min' | 'max';
+  parser?: 'time' | 'trim' | 'number';
+};
+type DimensionName = string;
+type DimensionIndex = number;

注意:使用按需引入接口时,如果需要使用该内置转换器,除了 Dataset 组件,还需引入 Transform 组件。

import {
+  DatasetComponent,
+  TransformComponent
+} from 'echarts/components';
+
+echarts.use([
+  DatasetComponent,
+  TransformComponent
+]);

使用外部的数据转换器

除了上述的内置的数据转换器外,我们也可以使用外部的数据转换器。外部数据转换器能提供或自己定制更丰富的功能。下面的例子中,我们使用第三方库 ecStat 提供的数据转换器。

生成数据的回归线:

// 首先要注册外部数据转换器。
+echarts.registerTransform(ecStatTransform(ecStat).regression);
option = {
+  dataset: [
+    {
+      source: rawData
+    },
+    {
+      transform: {
+        // 引用注册的数据转换器。
+        // 注意,每个外部的数据转换器,都有名空间(如 'ecStat:xxx','ecStat' 是名空间)。
+        // 而内置数据转换器(如 'filter', 'sort')没有名空间。
+        type: 'ecStat:regression',
+        config: {
+          // 这里是此外部数据转换器所需的参数。
+          method: 'exponential'
+        }
+      }
+    }
+  ],
+  xAxis: { type: 'category' },
+  yAxis: {},
+  series: [
+    {
+      name: 'scatter',
+      type: 'scatter',
+      datasetIndex: 0
+    },
+    {
+      name: 'regression',
+      type: 'line',
+      symbol: 'none',
+      datasetIndex: 1
+    }
+  ]
+};

一些使用 echarts-stat 的例子:

本文贡献者 在 GitHub 上编辑本页

pissang pissang100pah 100pahplainheart plainheartidaibin idaibinshangchen0531 shangchen0531meishijia meishijia
+ + + + + diff --git a/docs/zh/concepts/dataset/index.html b/docs/zh/concepts/dataset/index.html new file mode 100644 index 000000000..c1100314e --- /dev/null +++ b/docs/zh/concepts/dataset/index.html @@ -0,0 +1,502 @@ + + + + + + + 数据集 - 概念篇 - 使用手册 - Apache ECharts + + +

数据集

数据集(dataset)是专门用来管理数据的组件。虽然每个系列都可以在 series.data 中设置数据,但是从 ECharts4 支持数据集开始,更推荐使用数据集来管理数据。因为这样,数据可以被多个组件复用,也方便进行 “数据和其他配置” 分离的配置风格。毕竟,在运行时,数据是最常改变的,而其他配置大多并不会改变。

在系列中设置数据

如果数据设置在 系列(series) 中,例如:

option = {
+  xAxis: {
+    type: 'category',
+    data: ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      name: '2015',
+      data: [89.3, 92.1, 94.4, 85.4]
+    },
+    {
+      type: 'bar',
+      name: '2016',
+      data: [95.8, 89.4, 91.2, 76.9]
+    },
+    {
+      type: 'bar',
+      name: '2017',
+      data: [97.7, 83.1, 92.5, 78.1]
+    }
+  ]
+};
live

这种方式的优点是,适于对一些特殊的数据结构(如“树”、“图”、超大数据)进行一定的数据类型定制。 +但是缺点是,常需要用户先处理数据,把数据分割设置到各个系列(和类目轴)中。此外,不利于多个系列共享一份数据,也不利于基于原始数据进行图表类型、系列的映射安排。

在数据集中设置数据

而数据设置在 数据集(dataset) 中,会有这些好处:

  • 能够贴近数据可视化常见思维方式:(I)提供数据,(II)指定数据到视觉的映射,从而形成图表。
  • 数据和其他配置可以被分离开来。数据常变,其他配置常不变。分开易于分别管理。
  • 数据可以被多个系列或者组件复用,对于大数据量的场景,不必为每个系列创建一份数据。
  • 支持更多的数据的常用格式,例如二维数组、对象数组等,一定程度上避免使用者为了数据格式而进行转换。

下面是一个最简单的 dataset 的例子:

option = {
+  legend: {},
+  tooltip: {},
+  dataset: {
+    // 提供一份数据。
+    source: [
+      ['product', '2015', '2016', '2017'],
+      ['Matcha Latte', 43.3, 85.8, 93.7],
+      ['Milk Tea', 83.1, 73.4, 55.1],
+      ['Cheese Cocoa', 86.4, 65.2, 82.5],
+      ['Walnut Brownie', 72.4, 53.9, 39.1]
+    ]
+  },
+  // 声明一个 X 轴,类目轴(category)。默认情况下,类目轴对应到 dataset 第一列。
+  xAxis: { type: 'category' },
+  // 声明一个 Y 轴,数值轴。
+  yAxis: {},
+  // 声明多个 bar 系列,默认情况下,每个系列会自动对应到 dataset 的每一列。
+  series: [{ type: 'bar' }, { type: 'bar' }, { type: 'bar' }]
+};
live

或者也可以使用常见的“对象数组”的格式:

option = {
+  legend: {},
+  tooltip: {},
+  dataset: {
+    // 用 dimensions 指定了维度的顺序。直角坐标系中,如果 X 轴 type 为 category,
+    // 默认把第一个维度映射到 X 轴上,后面维度映射到 Y 轴上。
+    // 如果不指定 dimensions,也可以通过指定 series.encode
+    // 完成映射,参见后文。
+    dimensions: ['product', '2015', '2016', '2017'],
+    source: [
+      { product: 'Matcha Latte', '2015': 43.3, '2016': 85.8, '2017': 93.7 },
+      { product: 'Milk Tea', '2015': 83.1, '2016': 73.4, '2017': 55.1 },
+      { product: 'Cheese Cocoa', '2015': 86.4, '2016': 65.2, '2017': 82.5 },
+      { product: 'Walnut Brownie', '2015': 72.4, '2016': 53.9, '2017': 39.1 }
+    ]
+  },
+  xAxis: { type: 'category' },
+  yAxis: {},
+  series: [{ type: 'bar' }, { type: 'bar' }, { type: 'bar' }]
+};
live

数据到图形的映射

如上所述,数据可视化的一个常见思路是:(I)提供数据,(II)指定数据到视觉的映射。

简而言之,可以进行这些映射的设定:

  • 指定 数据集 的列(column)还是行(row)映射为 系列(series)。这件事可以使用 series.seriesLayoutBy 属性来配置。默认是按照列(column)来映射。
  • 指定维度映射的规则:如何从 dataset 的维度(一个“维度”的意思是一行/列)映射到坐标轴(如 X、Y 轴)、提示框(tooltip)、标签(label)、图形元素大小颜色等(visualMap)。这件事可以使用 series.encode 属性,以及 visualMap 组件来配置(如果有需要映射颜色大小等视觉维度的话)。上面的例子中,没有给出这种映射配置,那么 ECharts 就按最常见的理解进行默认映射:X 坐标轴声明为类目轴,默认情况下会自动对应到 dataset.source 中的第一列;三个柱图系列,一一对应到 dataset.source 中后面每一列。

下面详细解释这些映射的设定。

把数据集(dataset)的行或列映射为系列(series)

有了数据表之后,使用者可以灵活地配置:数据如何对应到轴和图形系列。

用户可以使用 seriesLayoutBy 配置项,改变图表对于行列的理解。seriesLayoutBy 可取值:

  • 'column': 默认值。系列被安放到 dataset 的列上面。
  • 'row': 系列被安放到 dataset 的行上面。

看这个例子:

option = {
+  legend: {},
+  tooltip: {},
+  dataset: {
+    source: [
+      ['product', '2012', '2013', '2014', '2015'],
+      ['Matcha Latte', 41.1, 30.4, 65.1, 53.3],
+      ['Milk Tea', 86.5, 92.1, 85.7, 83.1],
+      ['Cheese Cocoa', 24.1, 67.2, 79.5, 86.4]
+    ]
+  },
+  xAxis: [
+    { type: 'category', gridIndex: 0 },
+    { type: 'category', gridIndex: 1 }
+  ],
+  yAxis: [{ gridIndex: 0 }, { gridIndex: 1 }],
+  grid: [{ bottom: '55%' }, { top: '55%' }],
+  series: [
+    // 这几个系列会出现在第一个直角坐标系中,每个系列对应到 dataset 的每一行。
+    { type: 'bar', seriesLayoutBy: 'row' },
+    { type: 'bar', seriesLayoutBy: 'row' },
+    { type: 'bar', seriesLayoutBy: 'row' },
+    // 这几个系列会出现在第二个直角坐标系中,每个系列对应到 dataset 的每一列。
+    { type: 'bar', xAxisIndex: 1, yAxisIndex: 1 },
+    { type: 'bar', xAxisIndex: 1, yAxisIndex: 1 },
+    { type: 'bar', xAxisIndex: 1, yAxisIndex: 1 },
+    { type: 'bar', xAxisIndex: 1, yAxisIndex: 1 }
+  ]
+};
live

维度(dimension)

常用图表所描述的数据大部分是“二维表”结构,上述的例子中,我们都使用二维数组来容纳二维表。现在,当我们把系列(series)对应到“列”的时候,那么每一列就称为一个“维度(dimension)”,而每一行称为数据项(item)。反之,如果我们把系列(series)对应到表行,那么每一行就是“维度(dimension)”,每一列就是数据项(item)。

维度可以有单独的名字,便于在图表中显示。维度名(dimension name)可以在定义在 dataset 的第一行(或者第一列)。例如上面的例子中,'score''amount''product' 就是维度名。从第二行开始,才是正式的数据。dataset.source 中第一行(列)到底包含不包含维度名,ECharts 默认会自动探测。当然也可以设置 dataset.sourceHeader: true 显示声明第一行(列)就是维度,或者 dataset.sourceHeader: false 表明第一行(列)开始就直接是数据。

维度的定义,也可以使用单独的 dataset.dimensions 或者 series.dimensions 来定义,这样可以同时指定维度名,和维度的类型(dimension type):

var option1 = {
+  dataset: {
+    dimensions: [
+      { name: 'score' },
+      // 可以简写为 string ,表示 dimension name 。
+      'amount',
+      // 可以在 type 中指定维度类型。
+      { name: 'product', type: 'ordinal' }
+    ],
+    source: [
+      //...
+    ]
+  }
+  // ...
+};
+
+var option2 = {
+  dataset: {
+    source: [
+      // ...
+    ]
+  },
+  series: {
+    type: 'line',
+    // series.dimensions 会更优先于 dataset.dimension 采纳。
+    dimensions: [
+      null, // 可以设置为 null 表示不想设置维度名
+      'amount',
+      { name: 'product', type: 'ordinal' }
+    ]
+  }
+  // ...
+};

大多数情况下,我们并不需要去设置维度类型,因为 ECharts 会自动尝试判断。但是如果不足够准确时,可以手动设置维度类型。

维度类型(dimension type)可以取这些值:

  • 'number': 默认,表示普通数据。
  • 'ordinal': 对于类目、文本这些 string 类型的数据,如果需要能在数轴上使用,须是 'ordinal' 类型。ECharts 默认会试图自动判断这个类型。但是自动判断也可能不准确,所以使用者也可以手动强制指定。
  • 'time': 表示时间数据。设置成 'time' 则能支持自动解析数据成时间戳(timestamp),比如该维度的数据是 '2017-05-10',会自动被解析。如果这个维度被用在时间数轴(axis.type'time')上,那么会被自动设置为 'time' 类型。时间类型的支持参见 data
  • 'float': 如果设置成 'float',在存储时候会使用 TypedArray,对性能优化有好处。
  • 'int': 如果设置成 'int',在存储时候会使用 TypedArray,对性能优化有好处。

数据到图形的映射(series.encode)

了解了维度的概念后,我们就可以使用 series.encode 来做映射。总体是这样的感觉:

var option = {
+  dataset: {
+    source: [
+      ['score', 'amount', 'product'],
+      [89.3, 58212, 'Matcha Latte'],
+      [57.1, 78254, 'Milk Tea'],
+      [74.4, 41032, 'Cheese Cocoa'],
+      [50.1, 12755, 'Cheese Brownie'],
+      [89.7, 20145, 'Matcha Cocoa'],
+      [68.1, 79146, 'Tea'],
+      [19.6, 91852, 'Orange Juice'],
+      [10.6, 101852, 'Lemon Juice'],
+      [32.7, 20112, 'Walnut Brownie']
+    ]
+  },
+  xAxis: {},
+  yAxis: { type: 'category' },
+  series: [
+    {
+      type: 'bar',
+      encode: {
+        // 将 "amount" 列映射到 X 轴。
+        x: 'amount',
+        // 将 "product" 列映射到 Y 轴。
+        y: 'product'
+      }
+    }
+  ]
+};
live

series.encode 声明的基本结构如下。其中冒号左边是坐标系、标签等特定名称,如 'x', 'y', 'tooltip' 等,冒号右边是数据中的维度名(string 格式)或者维度的序号(number 格式,从 0 开始计数),可以指定一个或多个维度(使用数组)。通常情况下,下面各种信息不需要所有的都写,按需写即可。

下面是 series.encode 支持的属性:

// 在任何坐标系和系列中,都支持:
+encode: {
+  // 使用 “名为 product 的维度” 和 “名为 score 的维度” 的值在 tooltip 中显示
+  tooltip: ['product', 'score']
+  // 使用 “维度 1” 和 “维度 3” 的维度名连起来作为系列名。(有时候名字比较长,这可以避免在 series.name 重复输入这些名字)
+  seriesName: [1, 3],
+  // 表示使用 “维度2” 中的值作为 id。这在使用 setOption 动态更新数据时有用处,可以使新老数据用 id 对应起来,从而能够产生合适的数据更新动画。
+  itemId: 2,
+  // 指定数据项的名称使用 “维度3” 在饼图等图表中有用,可以使这个名字显示在图例(legend)中。
+  itemName: 3
+}
+
+// 直角坐标系(grid/cartesian)特有的属性:
+encode: {
+  // 把 “维度1”、“维度5”、“名为 score 的维度” 映射到 X 轴:
+  x: [1, 5, 'score'],
+  // 把“维度0”映射到 Y 轴。
+  y: 0
+}
+
+// 单轴(singleAxis)特有的属性:
+encode: {
+  single: 3
+}
+
+// 极坐标系(polar)特有的属性:
+encode: {
+  radius: 3,
+  angle: 2
+}
+
+// 地理坐标系(geo)特有的属性:
+encode: {
+  lng: 3,
+  lat: 2
+}
+
+// 对于一些没有坐标系的图表,例如饼图、漏斗图等,可以是:
+encode: {
+  value: 3
+}

这是个更丰富的 series.encode示例

默认的 series.encode

值得一提的是,当 series.encode 并没有指定时,ECharts 针对最常见直角坐标系中的图表(折线图、柱状图、散点图、K 线图等)、饼图、漏斗图,会采用一些默认的映射规则。默认的映射规则比较简单,大体是:

  • 在坐标系中(如直角坐标系、极坐标系等) +
    • 如果有类目轴(axis.type'category'),则将第一列(行)映射到这个轴上,后续每一列(行)对应一个系列。
    • 如果没有类目轴,假如坐标系有两个轴(例如直角坐标系的 X Y 轴),则每两列对应一个系列,这两列分别映射到这两个轴上。
  • 如果没有坐标系(如饼图) +
    • 取第一列(行)为名字,第二列(行)为数值(如果只有一列,则取第一列为数值)。

默认的规则不能满足要求时,就可以自己来配置 encode,也并不复杂。这是一个 例子

几个常见的 series.encode 设置方式举例

问:如何把第三列设置为 X 轴,第五列设置为 Y 轴?

答:

option = {
+  series: {
+    // 注意维度序号(dimensionIndex)从 0 开始计数,第三列是 dimensions[2]。
+    encode: { x: 2, y: 4 }
+    // ...
+  }
+};

问:如何把第三行设置为 X 轴,第五行设置为 Y 轴?

答:

option = {
+  series: {
+    encode: { x: 2, y: 4 },
+    seriesLayoutBy: 'row'
+    // ...
+  }
+};

问:如何把第二列设置为标签?

答: +关于标签的显示 label.formatter,现在支持引用特定维度的值,例如:

series: {
+  label: {
+    // `'{@score}'` 表示 “名为 score” 的维度里的值。
+    // `'{@[4]}'` 表示引用序号为 4 的维度里的值。
+    formatter: 'aaa{@product}bbb{@score}ccc{@[4]}ddd';
+  }
+}

问:如何让第 2 列和第 3 列显示在提示框(tooltip)中?

答:

option = {
+  series: {
+    encode: {
+      tooltip: [1, 2]
+      // ...
+    }
+    // ...
+  }
+};

问:数据里没有维度名,那么怎么给出维度名?

答:

var option = {
+  dataset: {
+    dimensions: ['score', 'amount'],
+    source: [
+      [89.3, 3371],
+      [92.1, 8123],
+      [94.4, 1954],
+      [85.4, 829]
+    ]
+  }
+};

问:如何把第三列映射为气泡图的点的大小?

答:

var option = {
+  dataset: {
+    source: [
+      [12, 323, 11.2],
+      [23, 167, 8.3],
+      [81, 284, 12],
+      [91, 413, 4.1],
+      [13, 287, 13.5]
+    ]
+  },
+  visualMap: {
+    show: false,
+    dimension: 2, // 指向第三列(列序号从 0 开始记,所以设置为 2)。
+    min: 2, // 需要给出数值范围,最小数值。
+    max: 15, // 需要给出数值范围,最大数值。
+    inRange: {
+      // 气泡尺寸:5 像素到 60 像素。
+      symbolSize: [5, 60]
+    }
+  },
+  xAxis: {},
+  yAxis: {},
+  series: {
+    type: 'scatter'
+  }
+};
live

问:encode 里指定了映射,但是不管用?

答:可以查查有没有拼错,比如,维度名是:'Life Expectancy',encode 中拼成了 'Life Expectency'

视觉通道(颜色、尺寸等)的映射

我们可以使用 visualMap 组件进行视觉通道的映射。详见 visualMap 文档的介绍。这是一个 示例

数据的各种格式

多数常见图表中,数据适于用二维表的形式描述。广为使用的数据表格软件(如 MS Excel、Numbers)或者关系数据数据库都是二维表。他们的数据可以导出成 JSON 格式,输入到 dataset.source 中,在不少情况下可以免去一些数据处理的步骤。

假如数据导出成 csv 文件,那么可以使用一些 csv 工具如 dsv 或者 PapaParse 将 csv 转成 JSON。

在 JavaScript 常用的数据传输格式中,二维数组可以比较直观的存储二维表。前面的示例都是使用二维数组表示。

除了二维数组以外,dataset 也支持例如下面 key-value 方式的数据格式,这类格式也非常常见。但是这类格式中,目前并不支持 seriesLayoutBy 参数。

dataset: [
+  {
+    // 按行的 key-value 形式(对象数组),这是个比较常见的格式。
+    source: [
+      { product: 'Matcha Latte', count: 823, score: 95.8 },
+      { product: 'Milk Tea', count: 235, score: 81.4 },
+      { product: 'Cheese Cocoa', count: 1042, score: 91.2 },
+      { product: 'Walnut Brownie', count: 988, score: 76.9 }
+    ]
+  },
+  {
+    // 按列的 key-value 形式。
+    source: {
+      product: ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie'],
+      count: [823, 235, 1042, 988],
+      score: [95.8, 81.4, 91.2, 76.9]
+    }
+  }
+];

多个 dataset 以及如何引用他们

可以同时定义多个 dataset。系列可以通过 series.datasetIndex 来指定引用哪个 dataset。例如:

var option = {
+  dataset: [
+    {
+      // 序号为 0 的 dataset。
+      source: []
+    },
+    {
+      // 序号为 1 的 dataset。
+      source: []
+    },
+    {
+      // 序号为 2 的 dataset。
+      source: []
+    }
+  ],
+  series: [
+    {
+      // 使用序号为 2 的 dataset。
+      datasetIndex: 2
+    },
+    {
+      // 使用序号为 1 的 dataset。
+      datasetIndex: 1
+    }
+  ]
+};

ECharts 3 的数据设置方式(series.data)仍正常使用

ECharts 4 之前一直以来的数据声明方式仍然被正常支持,如果系列已经声明了 series.data, 那么就会使用 series.data 而非 dataset

option = {
+  xAxis: {
+    type: 'category',
+    data: ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      name: '2015',
+      data: [89.3, 92.1, 94.4, 85.4]
+    },
+    {
+      type: 'bar',
+      name: '2016',
+      data: [95.8, 89.4, 91.2, 76.9]
+    },
+    {
+      type: 'bar',
+      name: '2017',
+      data: [97.7, 83.1, 92.5, 78.1]
+    }
+  ]
+};
live

其实,series.data 也是种会一直存在的重要设置方式。一些特殊的非 table 格式的图表,如 treemapgraphlines 等,现在仍不支持在 dataset 中设置,仍然需要使用 series.data。另外,对于巨大数据量的渲染(如百万以上的数据量),需要使用 appendData 进行增量加载,这种情况不支持使用 dataset

其他

目前并非所有图表都支持 dataset。支持 dataset 的图表有: +linebarpiescattereffectScatterparallelcandlestickmapfunnelcustom。 +后续会有更多的图表进行支持。

最后,给出这个 示例,多个图表共享一个 dataset,并带有联动交互。

本文贡献者 在 GitHub 上编辑本页

pissang pissangplainheart plainheart100pah 100pahOvilia Ovilia
+ + + + + diff --git a/docs/zh/concepts/event/index.html b/docs/zh/concepts/event/index.html new file mode 100644 index 000000000..250fd0f65 --- /dev/null +++ b/docs/zh/concepts/event/index.html @@ -0,0 +1,335 @@ + + + + + + + 事件与行为 - 概念篇 - 使用手册 - Apache ECharts + + +

事件与行为

在 Apache ECharts 的图表中用户的操作将会触发相应的事件。开发者可以监听这些事件,然后通过回调函数做相应的处理,比如跳转到一个地址,或者弹出对话框,或者做数据下钻等等。

ECharts 中的事件名称对应 DOM 事件名称,均为小写的字符串,如下是一个绑定点击操作的示例。

myChart.on('click', function(params) {
+  // 控制台打印数据的名称
+  console.log(params.name);
+});

在 ECharts 中事件分为两种类型,一种是用户鼠标操作点击,或者 hover 图表的图形时触发的事件,还有一种是用户在使用可以交互的组件后触发的行为事件,例如在切换图例开关时触发的 'legendselectchanged' 事件(这里需要注意切换图例开关是不会触发 'legendselected' 事件的),数据区域缩放时触发的 'datazoom' 事件等等。

鼠标事件的处理

ECharts 支持常规的鼠标事件类型,包括 'click''dblclick''mousedown''mousemove''mouseup''mouseover''mouseout''globalout''contextmenu' 事件。下面先来看一个简单的点击柱状图后打开相应的百度搜索页面的示例。

// 基于准备好的dom,初始化ECharts实例
+// var myChart = echarts.init(document.getElementById('main'));
+
+// 指定图表的配置项和数据
+var option = {
+  xAxis: {
+    data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
+  },
+  yAxis: {},
+  series: [
+    {
+      name: '销量',
+      type: 'bar',
+      data: [5, 20, 36, 10, 10, 20]
+    }
+  ]
+};
+// 使用刚指定的配置项和数据显示图表。
+myChart.setOption(option);
+// 处理点击事件并且跳转到相应的百度搜索页面
+myChart.on('click', function(params) {
+  window.open('https://www.baidu.com/s?wd=' + encodeURIComponent(params.name));
+});
live

所有的鼠标事件包含参数 params,这是一个包含点击图形的数据信息的对象,如下格式:

type EventParams = {
+  // 当前点击的图形元素所属的组件名称,
+  // 其值如 'series'、'markLine'、'markPoint'、'timeLine' 等。
+  componentType: string;
+  // 系列类型。值可能为:'line'、'bar'、'pie' 等。当 componentType 为 'series' 时有意义。
+  seriesType: string;
+  // 系列在传入的 option.series 中的 index。当 componentType 为 'series' 时有意义。
+  seriesIndex: number;
+  // 系列名称。当 componentType 为 'series' 时有意义。
+  seriesName: string;
+  // 数据名,类目名
+  name: string;
+  // 数据在传入的 data 数组中的 index
+  dataIndex: number;
+  // 传入的原始数据项
+  data: Object;
+  // sankey、graph 等图表同时含有 nodeData 和 edgeData 两种 data,
+  // dataType 的值会是 'node' 或者 'edge',表示当前点击在 node 还是 edge 上。
+  // 其他大部分图表中只有一种 data,dataType 无意义。
+  dataType: string;
+  // 传入的数据值
+  value: number | Array;
+  // 数据图形的颜色。当 componentType 为 'series' 时有意义。
+  color: string;
+};

如何区分鼠标点击到了哪里:

myChart.on('click', function(params) {
+  if (params.componentType === 'markPoint') {
+    // 点击到了 markPoint 上
+    if (params.seriesIndex === 5) {
+      // 点击到了 index 为 5 的 series 的 markPoint 上。
+    }
+  } else if (params.componentType === 'series') {
+    if (params.seriesType === 'graph') {
+      if (params.dataType === 'edge') {
+        // 点击到了 graph 的 edge(边)上。
+      } else {
+        // 点击到了 graph 的 node(节点)上。
+      }
+    }
+  }
+});

使用 query 只对指定的组件的图形元素的触发回调:

chart.on(eventName, query, handler);

query 可为 string 或者 Object

如果为 string 表示组件类型。格式可以是 'mainType' 或者 'mainType.subType'。例如:

chart.on('click', 'series', function() {});
+chart.on('click', 'series.line', function() {});
+chart.on('click', 'dataZoom', function() {});
+chart.on('click', 'xAxis.category', function() {});

如果为 Object,可以包含以下一个或多个属性,每个属性都是可选的:

{
+  ${mainType}Index: number // 组件 index
+  ${mainType}Name: string // 组件 name
+  ${mainType}Id: string // 组件 id
+  dataIndex: number // 数据项 index
+  name: string // 数据项 name
+  dataType: string // 数据项 type,如关系图中的 'node', 'edge'
+  element: string // 自定义系列中的 el 的 name
+}

例如:

chart.setOption({
+  // ...
+  series: [
+    {
+      name: 'uuu'
+      // ...
+    }
+  ]
+});
+chart.on('mouseover', { seriesName: 'uuu' }, function() {
+  // series name 为 'uuu' 的系列中的图形元素被 'mouseover' 时,此方法被回调。
+});

例如:

chart.setOption({
+  // ...
+  series: [
+    {
+      // ...
+    },
+    {
+      // ...
+      data: [
+        { name: 'xx', value: 121 },
+        { name: 'yy', value: 33 }
+      ]
+    }
+  ]
+});
+chart.on('mouseover', { seriesIndex: 1, name: 'xx' }, function() {
+  // series index 1 的系列中的 name 为 'xx' 的元素被 'mouseover' 时,此方法被回调。
+});

例如:

chart.setOption({
+  // ...
+  series: [
+    {
+      type: 'graph',
+      nodes: [
+        { name: 'a', value: 10 },
+        { name: 'b', value: 20 }
+      ],
+      edges: [{ source: 0, target: 1 }]
+    }
+  ]
+});
+chart.on('click', { dataType: 'node' }, function() {
+  // 关系图的节点被点击时此方法被回调。
+});
+chart.on('click', { dataType: 'edge' }, function() {
+  // 关系图的边被点击时此方法被回调。
+});

例如:

chart.setOption({
+  // ...
+  series: {
+    // ...
+    type: 'custom',
+    renderItem: function(params, api) {
+      return {
+        type: 'group',
+        children: [
+          {
+            type: 'circle',
+            name: 'my_el'
+            // ...
+          },
+          {
+            // ...
+          }
+        ]
+      };
+    },
+    data: [[12, 33]]
+  }
+});
+chart.on('mouseup', { element: 'my_el' }, function() {
+  // name 为 'my_el' 的元素被 'mouseup' 时,此方法被回调。
+});

你可以在回调函数中获得这个对象中的数据名、系列名称后在自己的数据仓库中索引得到其它的信息后更新图表,显示浮层等等,如下示例代码:

myChart.on('click', function(parmas) {
+  $.get('detail?q=' + params.name, function(detail) {
+    myChart.setOption({
+      series: [
+        {
+          name: 'pie',
+          // 通过饼图表现单个柱子中的数据分布
+          data: [detail.data]
+        }
+      ]
+    });
+  });
+});

组件交互的行为事件

在 ECharts 中基本上所有的组件交互行为都会触发相应的事件,常用的事件和事件对应参数在 events 文档中有列出。

下面是监听一个图例开关的示例:

// 图例开关的行为只会触发 legendselectchanged 事件
+myChart.on('legendselectchanged', function(params) {
+  // 获取点击图例的选中状态
+  var isSelected = params.selected[params.name];
+  // 在控制台中打印
+  console.log((isSelected ? '选中了' : '取消选中了') + '图例' + params.name);
+  // 打印所有图例的状态
+  console.log(params.selected);
+});

代码触发 ECharts 中组件的行为

上面提到诸如 'legendselectchanged' 事件会由组件交互的行为触发,那除了用户的交互操作,有时候也会有需要在程序里调用方法触发图表的行为,诸如显示 tooltip,选中图例。

在 ECharts 通过调用 myChart.dispatchAction({ type: '' }) 触发图表行为,统一管理了所有动作,也可以方便地根据需要去记录用户的行为路径。

常用的动作和动作对应参数在 action 文档中有列出。

下面示例演示了如何通过 dispatchAction 去轮流高亮饼图的每个扇形。

option = {
+  title: {
+    text: '饼图程序调用高亮示例',
+    left: 'center'
+  },
+  tooltip: {
+    trigger: 'item',
+    formatter: '{a} <br/>{b} : {c} ({d}%)'
+  },
+  legend: {
+    orient: 'vertical',
+    left: 'left',
+    data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
+  },
+  series: [
+    {
+      name: '访问来源',
+      type: 'pie',
+      radius: '55%',
+      center: ['50%', '60%'],
+      data: [
+        { value: 335, name: '直接访问' },
+        { value: 310, name: '邮件营销' },
+        { value: 234, name: '联盟广告' },
+        { value: 135, name: '视频广告' },
+        { value: 1548, name: '搜索引擎' }
+      ],
+      emphasis: {
+        itemStyle: {
+          shadowBlur: 10,
+          shadowOffsetX: 0,
+          shadowColor: 'rgba(0, 0, 0, 0.5)'
+        }
+      }
+    }
+  ]
+};
+
+let currentIndex = -1;
+
+setInterval(function() {
+  var dataLen = option.series[0].data.length;
+  // 取消之前高亮的图形
+  myChart.dispatchAction({
+    type: 'downplay',
+    seriesIndex: 0,
+    dataIndex: currentIndex
+  });
+  currentIndex = (currentIndex + 1) % dataLen;
+  // 高亮当前图形
+  myChart.dispatchAction({
+    type: 'highlight',
+    seriesIndex: 0,
+    dataIndex: currentIndex
+  });
+  // 显示 tooltip
+  myChart.dispatchAction({
+    type: 'showTip',
+    seriesIndex: 0,
+    dataIndex: currentIndex
+  });
+}, 1000);
live

监听“空白处”的事件

有时候,开发者需要监听画布的“空白处”所触发的事件。比如,当需要在用户点击“空白处”的时候重置图表时。

在讨论这个功能之前,我们需要先明确两种事件。zrender 事件和 echarts 事件。

myChart.getZr().on('click', function(event) {
+  // 该监听器正在监听一个`zrender 事件`。
+});
+myChart.on('click', function(event) {
+  // 该监听器正在监听一个`echarts 事件`。
+});

zrender 事件与 echarts 事件不同。前者是当鼠标在任何地方都会被触发,而后者是只有当鼠标在图形元素上时才能被触发。事实上,echarts 事件是在 zrender 事件的基础上实现的,也就是说,当一个 zrender 事件在图形元素上被触发时,echarts 将触发一个 echarts 事件给开发者。

有了 zrender 事件,我们就可以实现监听空白处的事件,具体如下:

myChart.getZr().on('click', function(event) {
+  // 没有 target 意味着鼠标/指针不在任何一个图形元素上,它是从“空白处”触发的。
+  if (!event.target) {
+    // 点击在了空白处,做些什么。
+  }
+});

本文贡献者 在 GitHub 上编辑本页

pissang pissangOvilia Oviliaplainheart plainheart100pah 100pah
+ + + + + diff --git a/docs/zh/concepts/legend/index.html b/docs/zh/concepts/legend/index.html new file mode 100644 index 000000000..cd35aefa7 --- /dev/null +++ b/docs/zh/concepts/legend/index.html @@ -0,0 +1,126 @@ + + + + + + + 图例 - 概念篇 - 使用手册 - Apache ECharts + + +

图例

图例是图表中对内容区元素的注释、用不同形状、颜色、文字等来标示不同数据列,通过点击对应数据列的标记,可以显示或隐藏该数据列。图例虽然不是图表中的主要信息、却是了解图表信息的钥匙。

布局

图例一般放在图表的右上角、也可以放在图表的底部、同一页面中的所有图例位置保持一致,可以横排对齐也可以纵排对齐。还要综合考虑整体的图表空间是适合哪种摆放方式。当图表纵向空间紧张或者内容区量过大的时候、建议摆放在图表的下方。下面是几种图例的摆放方式:

option = {
+  legend: {
+    // Try 'horizontal'
+    orient: 'vertical',
+    right: 10,
+    top: 'center'
+  },
+  dataset: {
+    source: [
+      ['product', '2015', '2016', '2017'],
+      ['Matcha Latte', 43.3, 85.8, 93.7],
+      ['Milk Tea', 83.1, 73.4, 55.1],
+      ['Cheese Cocoa', 86.4, 65.2, 82.5],
+      ['Walnut Brownie', 72.4, 53.9, 39.1]
+    ]
+  },
+  xAxis: { type: 'category' },
+  yAxis: {},
+  series: [{ type: 'bar' }, { type: 'bar' }, { type: 'bar' }]
+};
live

对于图例较多时,可以使用可滚动翻页的图例

option = {
+  legend: {
+    type: 'scroll',
+    orient: 'vertical',
+    right: 10,
+    top: 20,
+    bottom: 20,
+    data: ['图例一', '图例二', '图例三' /* ... */, , '图例n']
+    // ...
+  }
+  // ...
+};

样式

在深色系背景下、为了方便阅读,建议给图例加上半透明的浅色背景层,文字颜色设置为浅色。

option = {
+  legend: {
+    data: ['图例一', '图例二', '图例三'],
+    backgroundColor: '#ccc',
+    textStyle: {
+      color: '#ccc'
+      // ...
+    }
+    // ...
+  }
+  // ...
+};

图例的颜色标签有很多种设计方式、针对不同的图表、图例样式也会有所不同。

option = {
+  legend: {
+    data: ['图例一', '图例二', '图例三'],
+    icon: 'rect'
+    // ...
+  }
+  // ...
+};

交互

根据场景需要,图例可支持交互操作,点击控制显示或隐藏对应的数据列;

option = {
+  legend: {
+    data: ['图例一', '图例二', '图例三'],
+    selected: {
+      图例一: true,
+      图例二: true,
+      图例三: false
+    }
+    // ...
+  }
+  // ...
+};

图例注意事项

图例要注意视情况使用,有些双轴图包含了多种图表类型,不同类型的图例样式要有所区分。

option = {
+  legend: {
+    data: [
+      {
+        name: '图例一',
+        icon: 'rect'
+      },
+      {
+        name: '图例二',
+        icon: 'circle'
+      },
+      {
+        name: '图例三',
+        icon: 'pin'
+      }
+    ]
+    // ...
+  },
+  series: [
+    {
+      name: '图例一'
+      // ...
+    },
+    {
+      name: '图例二'
+      // ...
+    },
+    {
+      name: '图例三'
+      // ...
+    }
+  ]
+  // ...
+};

当图表只有一种数据信息时,用图表标题说明数据信息即可。建议此时不要加上图例。

本文贡献者 在 GitHub 上编辑本页

pissang pissangOvilia OviliaGeoffyscat Geoffyscat
+ + + + + diff --git a/docs/zh/concepts/style/index.html b/docs/zh/concepts/style/index.html new file mode 100644 index 000000000..141f1bcd0 --- /dev/null +++ b/docs/zh/concepts/style/index.html @@ -0,0 +1,460 @@ + + + + + + + 样式 - 概念篇 - 使用手册 - Apache ECharts + + +

ECharts 中的样式简介

本文主要是大略概述,用哪些方法,可以在 Apache EChartsTM 中设置样式,改变图形元素或者文字的颜色、明暗、大小等。

为了让表述更通俗易懂,我们在这里用了“样式”这种可能不是很符合数据可视化思维的词

本文介绍这几种方式,他们的功能范畴可能会有交叉(即同一种细节的效果可能可以用不同的方式实现),但是他们各有各的场景偏好。

  • 颜色主题(Theme)
  • 调色盘
  • 直接样式设置(itemStyle、lineStyle、areaStyle、label、...)
  • 视觉映射(visualMap)

颜色主题(Theme)

最简单的更改全局样式的方式,是直接采用颜色主题(theme)。例如,在 示例集合 中,可以通过切换深色模式,直接看到采用主题的效果。

ECharts5 除了一贯的默认主题外,还内置了'dark'主题。可以像这样切换成深色模式:

var chart = echarts.init(dom, 'dark');

其他的主题,没有内置在 ECharts 中,需要自己加载。这些主题可以在 主题编辑器 里访问到。也可以使用这个主题编辑器,自己编辑主题。下载下来的主题可以这样使用:

如果主题保存为 JSON 文件,则需要自行加载和注册,例如:

// 假设主题名称是 "vintage"
+fetch('theme/vintage.json')
+  .then(r => r.json())
+  .then(theme => {
+    echarts.registerTheme('vintage', theme);
+    var chart = echarts.init(dom, 'vintage');
+  })

如果保存为 UMD 格式的 JS 文件,文件内部已经做了自注册,直接引入 JS 即可:

// HTML 引入 vintage.js 文件后(假设主题名称是 "vintage")
+var chart = echarts.init(dom, 'vintage');
+// ...

调色盘

调色盘,可以在 option 中设置。它给定了一组颜色,图形、系列会自动从其中选择颜色。 +可以设置全局的调色盘,也可以设置系列自己专属的调色盘。

option = {
+  // 全局调色盘。
+  color: [
+    '#c23531',
+    '#2f4554',
+    '#61a0a8',
+    '#d48265',
+    '#91c7ae',
+    '#749f83',
+    '#ca8622',
+    '#bda29a',
+    '#6e7074',
+    '#546570',
+    '#c4ccd3'
+  ],
+
+  series: [
+    {
+      type: 'bar',
+      // 此系列自己的调色盘。
+      color: [
+        '#dd6b66',
+        '#759aa0',
+        '#e69d87',
+        '#8dc1a9',
+        '#ea7e53',
+        '#eedd78',
+        '#73a373',
+        '#73b9bc',
+        '#7289ab',
+        '#91ca8c',
+        '#f49f42'
+      ]
+      // ...
+    },
+    {
+      type: 'pie',
+      // 此系列自己的调色盘。
+      color: [
+        '#37A2DA',
+        '#32C5E9',
+        '#67E0E3',
+        '#9FE6B8',
+        '#FFDB5C',
+        '#ff9f7f',
+        '#fb7293',
+        '#E062AE',
+        '#E690D1',
+        '#e7bcf3',
+        '#9d96f5',
+        '#8378EA',
+        '#96BFFF'
+      ]
+      // ...
+    }
+  ]
+};

直接的样式设置

直接的样式设置是比较常用设置方式。纵观 ECharts 的 option 中,很多地方可以设置 itemStylelineStyleareaStylelabel 等等。这些的地方可以直接设置图形元素的颜色、线宽、点的大小、标签的文字、标签的样式等等。

一般来说,ECharts 的各个系列和组件,都遵从这些命名习惯,虽然不同图表和组件中,itemStylelabel 等可能出现在不同的地方。

在下面例子中我们给气泡图设置了阴影,渐变色等复杂的样式,你可以修改代码中的样式看修改后的效果:

var data = [
+  [
+    [28604, 77, 17096869, 'Australia', 1990],
+    [31163, 77.4, 27662440, 'Canada', 1990],
+    [1516, 68, 1154605773, 'China', 1990],
+    [13670, 74.7, 10582082, 'Cuba', 1990],
+    [28599, 75, 4986705, 'Finland', 1990],
+    [29476, 77.1, 56943299, 'France', 1990],
+    [31476, 75.4, 78958237, 'Germany', 1990],
+    [28666, 78.1, 254830, 'Iceland', 1990],
+    [1777, 57.7, 870601776, 'India', 1990],
+    [29550, 79.1, 122249285, 'Japan', 1990],
+    [2076, 67.9, 20194354, 'North Korea', 1990],
+    [12087, 72, 42972254, 'South Korea', 1990],
+    [24021, 75.4, 3397534, 'New Zealand', 1990],
+    [43296, 76.8, 4240375, 'Norway', 1990],
+    [10088, 70.8, 38195258, 'Poland', 1990],
+    [19349, 69.6, 147568552, 'Russia', 1990],
+    [10670, 67.3, 53994605, 'Turkey', 1990],
+    [26424, 75.7, 57110117, 'United Kingdom', 1990],
+    [37062, 75.4, 252847810, 'United States', 1990]
+  ],
+  [
+    [44056, 81.8, 23968973, 'Australia', 2015],
+    [43294, 81.7, 35939927, 'Canada', 2015],
+    [13334, 76.9, 1376048943, 'China', 2015],
+    [21291, 78.5, 11389562, 'Cuba', 2015],
+    [38923, 80.8, 5503457, 'Finland', 2015],
+    [37599, 81.9, 64395345, 'France', 2015],
+    [44053, 81.1, 80688545, 'Germany', 2015],
+    [42182, 82.8, 329425, 'Iceland', 2015],
+    [5903, 66.8, 1311050527, 'India', 2015],
+    [36162, 83.5, 126573481, 'Japan', 2015],
+    [1390, 71.4, 25155317, 'North Korea', 2015],
+    [34644, 80.7, 50293439, 'South Korea', 2015],
+    [34186, 80.6, 4528526, 'New Zealand', 2015],
+    [64304, 81.6, 5210967, 'Norway', 2015],
+    [24787, 77.3, 38611794, 'Poland', 2015],
+    [23038, 73.13, 143456918, 'Russia', 2015],
+    [19360, 76.5, 78665830, 'Turkey', 2015],
+    [38225, 81.4, 64715810, 'United Kingdom', 2015],
+    [53354, 79.1, 321773631, 'United States', 2015]
+  ]
+];
+
+option = {
+  backgroundColor: {
+    type: 'radial',
+    x: 0.3,
+    y: 0.3,
+    r: 0.8,
+    colorStops: [
+      {
+        offset: 0,
+        color: '#f7f8fa'
+      },
+      {
+        offset: 1,
+        color: '#cdd0d5'
+      }
+    ]
+  },
+  grid: {
+    left: 10,
+    containLabel: true,
+    bottom: 10,
+    top: 10,
+    right: 30
+  },
+  xAxis: {
+    splitLine: {
+      show: false
+    }
+  },
+  yAxis: {
+    splitLine: {
+      show: false
+    },
+    scale: true
+  },
+  series: [
+    {
+      name: '1990',
+      data: data[0],
+      type: 'scatter',
+      symbolSize: function(data) {
+        return Math.sqrt(data[2]) / 5e2;
+      },
+      emphasis: {
+        focus: 'series',
+        label: {
+          show: true,
+          formatter: function(param) {
+            return param.data[3];
+          },
+          position: 'top'
+        }
+      },
+      itemStyle: {
+        shadowBlur: 10,
+        shadowColor: 'rgba(120, 36, 50, 0.5)',
+        shadowOffsetY: 5,
+        color: {
+          type: 'radial',
+          x: 0.4,
+          y: 0.3,
+          r: 1,
+          colorStops: [
+            {
+              offset: 0,
+              color: 'rgb(251, 118, 123)'
+            },
+            {
+              offset: 1,
+              color: 'rgb(204, 46, 72)'
+            }
+          ]
+        }
+      }
+    },
+    {
+      name: '2015',
+      data: data[1],
+      type: 'scatter',
+      symbolSize: function(data) {
+        return Math.sqrt(data[2]) / 5e2;
+      },
+      emphasis: {
+        focus: 'series',
+        label: {
+          show: true,
+          formatter: function(param) {
+            return param.data[3];
+          },
+          position: 'top'
+        }
+      },
+      itemStyle: {
+        shadowBlur: 10,
+        shadowColor: 'rgba(25, 100, 150, 0.5)',
+        shadowOffsetY: 5,
+        color: {
+          type: 'radial',
+          x: 0.4,
+          y: 0.3,
+          r: 1,
+          colorStops: [
+            {
+              offset: 0,
+              color: 'rgb(129, 227, 238)'
+            },
+            {
+              offset: 1,
+              color: 'rgb(25, 183, 207)'
+            }
+          ]
+        }
+      }
+    }
+  ]
+};
live

高亮的样式:emphasis

在鼠标悬浮到图形元素上时,一般会出现高亮的样式。默认情况下,高亮的样式是根据普通样式自动生成的。但是高亮的样式也可以自己定义,主要是通过 emphasis 属性来定制。emphasis 中的结构,和普通样式的结构相同,例如:

option = {
+  series: {
+    type: 'scatter',
+
+    // 普通样式。
+    itemStyle: {
+      // 点的颜色。
+      color: 'red'
+    },
+    label: {
+      show: true,
+      // 标签的文字。
+      formatter: 'This is a normal label.'
+    },
+
+    // 高亮样式。
+    emphasis: {
+      itemStyle: {
+        // 高亮时点的颜色。
+        color: 'blue'
+      },
+      label: {
+        show: true,
+        // 高亮时标签的文字。
+        formatter: 'This is a emphasis label.'
+      }
+    }
+  }
+};

注意:在 ECharts4 以前,高亮和普通样式的写法,是这样的:

option = {
+  series: {
+    type: 'scatter',
+
+    itemStyle: {
+      // 普通样式。
+      normal: {
+        // 点的颜色。
+        color: 'red'
+      },
+      // 高亮样式。
+      emphasis: {
+        // 高亮时点的颜色。
+        color: 'blue'
+      }
+    },
+
+    label: {
+      // 普通样式。
+      normal: {
+        show: true,
+        // 标签的文字。
+        formatter: 'This is a normal label.'
+      },
+      // 高亮样式。
+      emphasis: {
+        show: true,
+        // 高亮时标签的文字。
+        formatter: 'This is a emphasis label.'
+      }
+    }
+  }
+};

这种写法 仍然被兼容,但是,不再推荐。事实上,多数情况下,开发者只想配置普通状态下的样式,而使用默认的高亮样式。所以在 ECharts4 中,支持不写 normal 的配置方法(即前一个代码片段里的写法),使得配置项更扁平简单。

通过 visualMap 组件设定样式

visualMap 组件 能指定数据到颜色、图形尺寸的映射规则,详见 数据的视觉映射

本文贡献者 在 GitHub 上编辑本页

pissang pissangplainheart plainheartwangcheng0825 wangcheng0825fuchunhui fuchunhui1335951413 1335951413
+ + + + + diff --git a/docs/zh/concepts/visual-map/index.html b/docs/zh/concepts/visual-map/index.html new file mode 100644 index 000000000..7393e3322 --- /dev/null +++ b/docs/zh/concepts/visual-map/index.html @@ -0,0 +1,81 @@ + + + + + + + 视觉映射 - 概念篇 - 使用手册 - Apache ECharts + + +

数据的视觉映射

数据可视化是数据到视觉元素的映射过程(这个过程也可称为视觉编码,视觉元素也可称为视觉通道)。

ECharts 的每种图表本身就内置了这种映射过程,比如折线图把数据映射到“线”,柱状图把数据映射到“长度”。一些更复杂的图表,如关系图、事件河流图、树图也都会做出各自内置的映射。

此外,ECharts 还提供了 visualMap 组件 来提供通用的视觉映射。visualMap 组件中可以使用的视觉元素有:

  • 图形类别(symbol)、图形大小(symbolSize)
  • 颜色(color)、透明度(opacity)、颜色透明度(colorAlpha)、
  • 颜色明暗度(colorLightness)、颜色饱和度(colorSaturation)、色调(colorHue)

下面对 visualMap 组件的使用方式进行简要的介绍。

数据和维度

ECharts 中的数据,一般存放于 series.data 中。根据图表类型不同,数据的具体形式也可能有些许差异。比如可能是“线性表“、“树“、“图“等。但他们都有个共性:都是“数据项(dataItem)“的集合。每个数据项含有“数据值(value)“和其他信息(如果需要的话)。每个数据值,可以是单一的数值(一维)或者一个数组(多维)。

例如,series.data 最常见的形式,是“线性表“,即一个普通数组:

series: {
+  data: [
+    {
+      // 这里每一个项就是数据项(dataItem)
+      value: 2323, // 这是数据项的数据值(value)
+      itemStyle: {}
+    },
+    1212, // 也可以直接是 dataItem 的 value,这更常见。
+    2323, // 每个 value 都是“一维“的。
+    4343,
+    3434
+  ];
+}
series: {
+  data: [
+    {
+      // 这里每一个项就是数据项(dataItem)
+      value: [3434, 129, '圣马力诺'], // 这是数据项的数据值(value)
+      itemStyle: {}
+    },
+    [1212, 5454, '梵蒂冈'], // 也可以直接是 dataItem 的 value,这更常见。
+    [2323, 3223, '瑙鲁'], // 每个 value 都是“三维“的,每列是一个维度。
+    [4343, 23, '图瓦卢'] // 假如是“气泡图“,常见第一维度映射到x轴,
+    // 第二维度映射到y轴,
+    // 第三维度映射到气泡半径(symbolSize)
+  ];
+}

在图表中,往往默认把 value 的前一两个维度进行映射,比如取第一个维度映射到 x 轴,取第二个维度映射到 y 轴。如果想要把更多的维度展现出来,可以借助 visualMap。最常见的情况,散点图(scatter) 使用半径展现了第三个维度。

visualMap 组件

visualMap 组件定义了把数据的哪个维度映射到什么视觉元素上

现在提供如下两种类型的 visualMap 组件,通过 visualMap.type 来区分。

其定义结构例如:

option = {
+  visualMap: [
+    // 可以同时定义多个 visualMap 组件。
+    {
+      // 第一个 visualMap 组件
+      type: 'continuous' // 定义为连续型 visualMap
+      // ...
+    },
+    {
+      // 第二个 visualMap 组件
+      type: 'piecewise' // 定义为分段型 visualMap
+      // ...
+    }
+  ]
+  // ...
+};

连续型与分段型视觉映射组件

ECharts 的视觉映射组件分为连续型(visualMapContinuous)与分段型(visualMapPiecewise)。

连续型的意思是,进行视觉映射的数据维度是连续的数值;而分段型则是数据被分成了多段或者是离散型的数据。

连续型视觉映射

连续型视觉映射通过指定最大值、最小值,就可以确定视觉映射的范围。

option = {
+  visualMap: [
+    {
+      type: 'continuous',
+      min: 0,
+      max: 5000,
+      dimension: 3, // series.data 的第四个维度(即 value[3])被映射
+      seriesIndex: 4, // 对第四个系列进行映射。
+      inRange: {
+        // 选中范围中的视觉配置
+        color: ['blue', '#121122', 'red'], // 定义了图形颜色映射的颜色列表,
+        // 数据最小值映射到'blue'上,
+        // 最大值映射到'red'上,
+        // 其余自动线性计算。
+        symbolSize: [30, 100] // 定义了图形尺寸的映射范围,
+        // 数据最小值映射到30上,
+        // 最大值映射到100上,
+        // 其余自动线性计算。
+      },
+      outOfRange: {
+        // 选中范围外的视觉配置
+        symbolSize: [30, 100]
+      }
+    }
+    //    ...
+  ]
+};

其中,visualMap.inRange 表示在数据映射范围内的数据采用的样式;而 visualMap.outOfRange 则指定了超出映射范围外的数据的样式。

visualMap.dimension 则指定了将数据的哪个维度做视觉映射。

分段型视觉映射

分段型视觉映射组件有三种模式:

使用分段型视觉映射时,需要将 type 设为 'piecewise',并且将上面的三个配置项选其一配置即可,其他配置项类似连续型视觉映射。

本文贡献者 在 GitHub 上编辑本页

Ovilia Oviliaplainheart plainheartpissang pissang
+ + + + + diff --git a/docs/zh/get-started/index.html b/docs/zh/get-started/index.html new file mode 100644 index 000000000..64800f27e --- /dev/null +++ b/docs/zh/get-started/index.html @@ -0,0 +1,66 @@ + + + + + + + 快速上手 - 使用手册 - Apache ECharts + + +

快速上手

获取 Apache ECharts

Apache ECharts 支持多种下载方式,可以在下一篇教程安装中查看所有方式。这里,我们以从 jsDelivr CDN 上获取为例,介绍如何快速安装。

https://www.jsdelivr.com/package/npm/echarts 选择 dist/echarts.js,点击并保存为 echarts.js 文件。

关于这些文件的介绍,可以在下一篇教程安装中了解更多信息。

引入 Apache ECharts

在刚才保存 echarts.js 的目录新建一个 index.html 文件,内容如下:

<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <!-- 引入刚刚下载的 ECharts 文件 -->
+    <script src="echarts.js"></script>
+  </head>
+</html>

打开这个 index.html,你会看到一片空白。但是不要担心,打开控制台确认没有报错信息,就可以进行下一步。

绘制一个简单的图表

在绘图前我们需要为 ECharts 准备一个定义了高宽的 DOM 容器。在刚才的例子 </head> 之后,添加:

<body>
+  <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
+  <div id="main" style="width: 600px;height:400px;"></div>
+</body>

然后就可以通过 echarts.init 方法初始化一个 echarts 实例并通过 setOption 方法生成一个简单的柱状图,下面是完整代码。

<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <title>ECharts</title>
+    <!-- 引入刚刚下载的 ECharts 文件 -->
+    <script src="echarts.js"></script>
+  </head>
+  <body>
+    <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
+    <div id="main" style="width: 600px;height:400px;"></div>
+    <script type="text/javascript">
+      // 基于准备好的dom,初始化echarts实例
+      var myChart = echarts.init(document.getElementById('main'));
+
+      // 指定图表的配置项和数据
+      var option = {
+        title: {
+          text: 'ECharts 入门示例'
+        },
+        tooltip: {},
+        legend: {
+          data: ['销量']
+        },
+        xAxis: {
+          data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
+        },
+        yAxis: {},
+        series: [
+          {
+            name: '销量',
+            type: 'bar',
+            data: [5, 20, 36, 10, 10, 20]
+          }
+        ]
+      };
+
+      // 使用刚指定的配置项和数据显示图表。
+      myChart.setOption(option);
+    </script>
+  </body>
+</html>

这样你的第一个图表就诞生了!

本文贡献者 在 GitHub 上编辑本页

Ovilia Oviliapissang pissangzxx0006 zxx0006
+ + + + + diff --git a/docs/zh/how-to/animation/transition/index.html b/docs/zh/how-to/animation/transition/index.html new file mode 100644 index 000000000..7902e3cfd --- /dev/null +++ b/docs/zh/how-to/animation/transition/index.html @@ -0,0 +1,196 @@ + + + + + + + 数据过渡动画 - 动画 - 应用篇 - 使用手册 - Apache ECharts + + +

基础的过渡动画

Apache EChartsTM 中使用了平移,缩放,变形等形式的过渡动画让数据的添加更新删除,以及用户的交互变得更加顺滑。通常情况下开发者不需要操心该如何去使用动画,只需要按自己的需求使用setOption更新数据,ECharts 就会找出跟上一次数据之间的区别,然后自动应用最合适的过渡动画。

比如下面例子就是定时更新饼图数据(随机)的过渡动画效果。

function makeRandomData() {
+  return [
+    {
+      value: Math.random(),
+      name: 'A'
+    },
+    {
+      value: Math.random(),
+      name: 'B'
+    },
+    {
+      value: Math.random(),
+      name: 'C'
+    }
+  ];
+}
+option = {
+  series: [
+    {
+      type: 'pie',
+      radius: [0, '50%'],
+      data: makeRandomData()
+    }
+  ]
+};
+
+setInterval(() => {
+  myChart.setOption({
+    series: {
+      data: makeRandomData()
+    }
+  });
+}, 2000);
live

过渡动画的配置

因为数据添加和数据更新往往会需要不一样的动画效果,比如我们会期望数据更新动画的时长更短,因此 ECharts 区分了这两者的动画配置:

  • 对于新添加的数据,我们会应用入场动画,通过animationDuration, animationEasing, animationDelay三个配置项分别配置动画的时长,缓动以及延时。
  • 对于数据更新,我们会应用更新动画,通过animationDurationUpdate, animationEasingUpdate, animationDelayUpdate三个配置项分别配置动画的时长,缓动以及延时。

可以看到,更新动画配置是入场动画配置加上了Update的后缀。

在 ECharts 中每次 setOption 的更新,数据会跟上一次更新的数据做对比,然后根据对比结果分别为数据执行三种状态:添加,更新以及移除。这个比对是根据数据的name来决定的,例如上一次更新数据有三个name'A', 'B', 'C'的数据,而新更新的数据变为了'B', 'C', 'D'的数据,则数据'B', 'C'会被执行更新,数据'A'会被移除,而数据'D'会被添加。如果是第一次更新因为没有旧数据,所以所有数据都会被执行添加。根据这三种状态 ECharts 会分别应用相应的入场动画,更新动画以及移除动画。

所有这些配置都可以分别设置在option最顶层对所有系列和组件生效,也可以分别为每个系列配置。

如果我们想要关闭动画,可以直接设置option.animationfalse

动画时长

animationDurationanimationDurationUpdate用于设置动画的时长,单位为ms,设置较长的动画时长可以让用户更清晰的看到过渡动画的效果,但是我们也需要小心过长的时间会让用户再等待的过程中失去耐心。

设置为0会关闭动画,在我们只想要单独关闭入场动画或者更新动画的时候可以通过单独将相应的配置设置为0来实现。

动画缓动

animationEasinganimationEasingUpdate两个配置项用于设置动画的缓动函数,缓动函数是一个输入动画时间,输出动画进度的函数:

(t: number) => number;

在 ECharts 里内置了缓入'cubicIn',缓出'cubicOut'等常见的动画缓动函数,我们可以直接通过名字来声明使用这些缓动函数。

内置缓动函数:

延时触发

animationDelayanimationDelayUpdate用于设置动画延迟开始的时间,通常我们会使用回调函数将不同数据设置不同的延时来实现交错动画的效果:

var xAxisData = [];
+var data1 = [];
+var data2 = [];
+for (var i = 0; i < 100; i++) {
+  xAxisData.push('A' + i);
+  data1.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5);
+  data2.push((Math.cos(i / 5) * (i / 5 - 10) + i / 6) * 5);
+}
+option = {
+  legend: {
+    data: ['bar', 'bar2']
+  },
+  xAxis: {
+    data: xAxisData,
+    splitLine: {
+      show: false
+    }
+  },
+  yAxis: {},
+  series: [
+    {
+      name: 'bar',
+      type: 'bar',
+      data: data1,
+      emphasis: {
+        focus: 'series'
+      },
+      animationDelay: function(idx) {
+        return idx * 10;
+      }
+    },
+    {
+      name: 'bar2',
+      type: 'bar',
+      data: data2,
+      emphasis: {
+        focus: 'series'
+      },
+      animationDelay: function(idx) {
+        return idx * 10 + 100;
+      }
+    }
+  ],
+  animationEasing: 'elasticOut',
+  animationDelayUpdate: function(idx) {
+    return idx * 5;
+  }
+};
live

动画的性能优化

在数据量特别大的时候,为图形应用动画可能会导致应用的卡顿,这个时候我们可以设置animation: false关闭动画。

对于数据量会动态变化的图表,我们更推荐使用animationThreshold这个配置项,当画布中图形数量超过这个阈值的时候,ECharts 会自动关闭动画来提升绘制性能。这个配置往往是一个经验值,通常 ECharts 的性能足够实时渲染上千个图形的动画(我们默认值也是给了 2000),但是如果你的图表很复杂,或者你的用户环境比较恶劣,页面中又同时会运行很多其它复杂的代码,也可以适当的下调这个值保证整个应用的流畅性。

监听动画结束

有时候我们想要获取当前渲染的结果,如果没有使用动画,我们在setOption之后 ECharts 就会直接执行渲染,我们可以同步的通过getDataURL方法获取渲染得到的结果。

const chart = echarts.init(dom);
+chart.setOption({
+  animation: false
+  //...
+});
+// 可以直接同步执行
+const dataUrl = chart.getDataURL();

但是如果图表中有动画,马上执行getDataURL得到的是动画刚开始的画面,而非最终展示的结果。因此我们需要知道动画结束然后再执行getDataURL得到结果。

假如你确定动画的时长,一种比较简单粗暴的方式是根据动画时长来执行setTimeout延迟执行:

chart.setOption({
+  animationDuration: 1000
+  //...
+});
+setTimeout(() => {
+  const dataUrl = chart.getDataURL();
+}, 1000);

或者我们也可以使用 ECharts 提供的rendered事件来判断 ECharts 已经动画结束停止了渲染

chart.setOption({
+  animationDuration: 1000
+  //...
+});
+
+function onRendered() {
+  const dataUrl = chart.getDataURL();
+  // ...
+  // 后续如果有交互,交互发生重绘也会触发该事件,因此使用完就需要移除
+  chart.off('rendered', onRendered);
+}
+chart.on('rendered', onRendered);

本文贡献者 在 GitHub 上编辑本页

pissang pissang
+ + + + + diff --git a/docs/zh/how-to/chart-types/bar/bar-race/index.html b/docs/zh/how-to/chart-types/bar/bar-race/index.html new file mode 100644 index 000000000..f5c6a8cb0 --- /dev/null +++ b/docs/zh/how-to/chart-types/bar/bar-race/index.html @@ -0,0 +1,121 @@ + + + + + + + 动态排序柱状图 - 柱状图 - 常用图表类型 - 应用篇 - 使用手册 - Apache ECharts + + +

动态排序柱状图

基本设置

动态排序柱状图是一种展示随时间变化的数据排名变化的图表,从 ECharts 5 开始内置支持。

动态排序柱状图通常是横向的柱条,如果想要采用纵向的柱条,只要把本教程中的 X 轴和 Y 轴相反设置即可。

  1. 柱状图系列的 realtimeSort 设为 true,表示开启该系列的动态排序效果
  2. yAxis.inverse 设为 true,表示 Y 轴从下往上是从小到大的排列
  3. yAxis.animationDuration 建议设为 300,表示第一次柱条排序动画的时长
  4. yAxis.animationDurationUpdate 建议设为 300,表示第一次后柱条排序动画的时长
  5. 如果想只显示前 n 名,将 yAxis.max 设为 n - 1,否则显示所有柱条
  6. xAxis.max 建议设为 'dataMax' 表示用数据的最大值作为 X 轴最大值,视觉效果更好
  7. 如果想要实时改变标签,需要将 series.label.valueAnimation 设为 true
  8. animationDuration 设为 0,表示第一份数据不需要从 0 开始动画(如果希望从 0 开始则设为和 animationDurationUpdate 相同的值)
  9. animationDurationUpdate 建议设为 3000 表示每次更新动画时长,这一数值应与调用 setOption 改变数据的频率相同
  10. animationDurationUpdate 的频率调用 setInterval,更新数据值,显示下一个时间点对应的柱条排序

示例

完整的例子如下:

var data = [];
+for (let i = 0; i < 5; ++i) {
+  data.push(Math.round(Math.random() * 200));
+}
+
+option = {
+  xAxis: {
+    max: 'dataMax'
+  },
+  yAxis: {
+    type: 'category',
+    data: ['A', 'B', 'C', 'D', 'E'],
+    inverse: true,
+    animationDuration: 300,
+    animationDurationUpdate: 300,
+    max: 2 // only the largest 3 bars will be displayed
+  },
+  series: [
+    {
+      realtimeSort: true,
+      name: 'X',
+      type: 'bar',
+      data: data,
+      label: {
+        show: true,
+        position: 'right',
+        valueAnimation: true
+      }
+    }
+  ],
+  legend: {
+    show: true
+  },
+  animationDuration: 3000,
+  animationDurationUpdate: 3000,
+  animationEasing: 'linear',
+  animationEasingUpdate: 'linear'
+};
+
+function update() {
+  var data = option.series[0].data;
+  for (var i = 0; i < data.length; ++i) {
+    if (Math.random() > 0.9) {
+      data[i] += Math.round(Math.random() * 2000);
+    } else {
+      data[i] += Math.round(Math.random() * 200);
+    }
+  }
+  myChart.setOption(option);
+}
+
+setInterval(function() {
+  update();
+}, 3000);
live

本文贡献者 在 GitHub 上编辑本页

Ovilia Oviliapissang pissang
+ + + + + diff --git a/docs/zh/how-to/chart-types/bar/basic-bar/index.html b/docs/zh/how-to/chart-types/bar/basic-bar/index.html new file mode 100644 index 000000000..fbd118cb7 --- /dev/null +++ b/docs/zh/how-to/chart-types/bar/basic-bar/index.html @@ -0,0 +1,229 @@ + + + + + + + 基础柱状图 - 柱状图 - 常用图表类型 - 应用篇 - 使用手册 - Apache ECharts + + +

基本柱状图

柱状图(或称条形图)是一种通过柱形的长度来表现数据大小的一种常用图表类型。

设置柱状图的方式,是将 seriestype 设为 'bar'

[配置项手册]

最简单的柱状图

最简单的柱状图可以这样设置:

option = {
+  xAxis: {
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};
live

在这个例子中,横坐标是类目型的,因此需要在 xAxis 中指定对应的值;而纵坐标是数值型的,可以根据 series 中的 data,自动生成对应的坐标范围。

多系列的柱状图

我们可以用一个系列表示一组相关的数据,如果需要实现多系列的柱状图,只需要在 series 多添加一项就可以了——

option = {
+  xAxis: {
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    },
+    {
+      type: 'bar',
+      data: [26, 24, 18, 22, 23, 20, 27]
+    }
+  ]
+};
live

柱状图样式设置

柱条样式

柱条的样式可以通过 series.itemStyle 设置,包括:

  • 柱条的颜色(color);
  • 柱条的描边颜色(borderColor)、宽度(borderWidth)、样式(borderType);
  • 柱条圆角的半径(barBorderRadius);
  • 柱条透明度(opacity);
  • 阴影(shadowBlurshadowColorshadowOffsetXshadowOffsetY)。
option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [
+        10,
+        22,
+        28,
+        {
+          value: 43,
+          // 设置单个柱子的样式
+          itemStyle: {
+            color: '#91cc75',
+            shadowColor: '#91cc75',
+            borderType: 'dashed',
+            opacity: 0.5
+          }
+        },
+        49
+      ],
+      itemStyle: {
+        barBorderRadius: 5,
+        borderWidth: 1,
+        borderType: 'solid',
+        borderColor: '#73c0de',
+        shadowColor: '#5470c6',
+        shadowBlur: 3
+      }
+    }
+  ]
+};
live

在这个例子中,我们通过设置柱状图对应 seriesitemStyle,设置了柱条的样式。完整的配置项及其用法请参见配置项手册 series.itemStyle

柱条宽度和高度

柱条宽度可以通过 barWidth 设置。比如在下面的例子中,将 barWidth 设为 '20%',表示每个柱条的宽度就是类目宽度的 20%。由于这个例子中,每个系列有 5 个数据,20% 的类目宽度也就是整个 x 轴宽度的 4%。

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [10, 22, 28, 43, 49],
+      barWidth: '20%'
+    }
+  ]
+};
live

另外,还可以设置 barMaxWidth 限制柱条的最大宽度。对于一些特别小的数据,我们也可以为柱条指定最小高度 barMinHeight,当数据对应的柱条高度小于该值时,柱条高度将采用这个最小高度。

柱条间距

柱条间距分为两种,一种是不同系列在同一类目下的距离 barGap,另一种是类目与类目的距离 barCategoryGap

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 18],
+      barGap: '20%',
+      barCategoryGap: '40%'
+    },
+    {
+      type: 'bar',
+      data: [12, 14, 9, 9, 11]
+    }
+  ]
+};
live

在这个例子中,barGap 被设为 '20%',这意味着每个类目(比如 A)下的两个柱子之间的距离,相对于柱条宽度的百分比。而 barCategoryGap'40%',意味着柱条每侧空余的距离,相对于柱条宽度的百分比。

通常而言,设置 barGapbarCategoryGap 后,就不需要设置 barWidth 了,这时候的宽度会自动调整。如果有需要的话,可以设置 barMaxWidth 作为柱条宽度的上限,当图表宽度很大的时候,柱条宽度也不会太宽。

在同一坐标系上,此属性会被多个柱状图系列共享。此属性应设置于此坐标系中最后一个柱状图系列上才会生效,并且是对此坐标系中所有柱状图系列生效。

为柱条添加背景色

有时,我们希望能够为柱条添加背景色。从 ECharts 4.7.0 版本开始,这一功能可以简单地用 showBackground 开启,并且可以通过 backgroundStyle 配置。

option = {
+  xAxis: {
+    type: 'category',
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      data: [120, 200, 150, 80, 70, 110, 130],
+      type: 'bar',
+      showBackground: true,
+      backgroundStyle: {
+        color: 'rgba(220, 220, 220, 0.8)'
+      }
+    }
+  ]
+};
live

本文贡献者 在 GitHub 上编辑本页

plainheart plainheartpissang pissangtanjiasong005 tanjiasong005
+ + + + + diff --git a/docs/zh/how-to/chart-types/bar/stacked-bar/index.html b/docs/zh/how-to/chart-types/bar/stacked-bar/index.html new file mode 100644 index 000000000..fc0f9f862 --- /dev/null +++ b/docs/zh/how-to/chart-types/bar/stacked-bar/index.html @@ -0,0 +1,49 @@ + + + + + + + 堆叠柱状图 - 柱状图 - 常用图表类型 - 应用篇 - 使用手册 - Apache ECharts + + +

堆叠柱状图

有时候,我们不仅希望知道不同系列各自的数值,还希望知道它们之和的变化,这时候通常使用堆叠柱状图来表现。顾名思义,堆叠柱状图就是一个系列的数值“堆叠”在另一个系列上,因而从他们的高度总和就能表达总量的变化。

使用 EChart 实现堆叠柱状图的方法非常简单,只需要给一个系列的 stack 值设置一个字符串类型的值,这一个值表示该系列堆叠的类别。也就是说,拥有同样 stack 值的系列将堆叠在一组。

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 43, 49],
+      type: 'bar',
+      stack: 'x'
+    },
+    {
+      data: [5, 4, 3, 5, 10],
+      type: 'bar',
+      stack: 'x'
+    }
+  ]
+};
live

在这个例子中,第二个系列所在的位置是在第一个系列的位置的基础上,上升了第二个系列数值对应的高度。因此,从第二个系列的位置,就能看出这两者总和的变化趋势。

stack 的取值用来表明哪些系列将被堆叠在一起,理论上只要取值相同即可,具体的取值并没有什么区别。但在实际的应用中,我们建议使用一些有意义的字符串方便阅读。

比如,在一个统计男女人数的图中,有四个系列,“成年男性”和“男孩”系列需要进行堆叠,“成年女性”和“女孩”系列需要堆叠。这时,这两组的的 stack 值就建议分别设为 '男''女'。虽然使用 'a''b' 这样没有意义的字符串也能实现同样的效果,但是代码的可阅读性就差了。

本文贡献者 在 GitHub 上编辑本页

ArisLittle ArisLittlepissang pissang
+ + + + + diff --git a/docs/zh/how-to/chart-types/bar/waterfall/index.html b/docs/zh/how-to/chart-types/bar/waterfall/index.html new file mode 100644 index 000000000..105c17388 --- /dev/null +++ b/docs/zh/how-to/chart-types/bar/waterfall/index.html @@ -0,0 +1,177 @@ + + + + + + + 阶梯瀑布图 - 柱状图 - 常用图表类型 - 应用篇 - 使用手册 - Apache ECharts + + +

阶梯瀑布图

Apache ECharts 中并没有单独的瀑布图类型,但是我们可以使用堆叠的柱状图模拟该效果。

假设数据数组中的值是表示对前一个值的增减:

var data = [900, 345, 393, -108, -154, 135, 178, 286, -119, -361, -203];

也就是第一个数据是 900,第二个数据 345 表示的是在 900 的基础上增加了 345……将这个数据展示为阶梯瀑布图时,我们可以使用三个系列:第一个是不可交互的透明系列,用来实现“悬空”的柱状图效果;第二个系列用来表示正数;第三个系列用来表示负数。

var data = [900, 345, 393, -108, -154, 135, 178, 286, -119, -361, -203];
+var help = [];
+var positive = [];
+var negative = [];
+for (var i = 0, sum = 0; i < data.length; ++i) {
+  if (data[i] >= 0) {
+    positive.push(data[i]);
+    negative.push('-');
+  } else {
+    positive.push('-');
+    negative.push(-data[i]);
+  }
+
+  if (i === 0) {
+    help.push(0);
+  } else {
+    sum += data[i - 1];
+    if (data[i] < 0) {
+      help.push(sum + data[i]);
+    } else {
+      help.push(sum);
+    }
+  }
+}
+
+option = {
+  title: {
+    text: 'Waterfall'
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    splitLine: { show: false },
+    data: (function() {
+      var list = [];
+      for (var i = 1; i <= 11; i++) {
+        list.push('Oct/' + i);
+      }
+      return list;
+    })()
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      type: 'bar',
+      stack: 'all',
+      itemStyle: {
+        normal: {
+          barBorderColor: 'rgba(0,0,0,0)',
+          color: 'rgba(0,0,0,0)'
+        },
+        emphasis: {
+          barBorderColor: 'rgba(0,0,0,0)',
+          color: 'rgba(0,0,0,0)'
+        }
+      },
+      data: help
+    },
+    {
+      name: 'positive',
+      type: 'bar',
+      stack: 'all',
+      data: positive
+    },
+    {
+      name: 'negative',
+      type: 'bar',
+      stack: 'all',
+      data: negative,
+      itemStyle: {
+        color: '#f33'
+      }
+    }
+  ]
+};
live

本文贡献者 在 GitHub 上编辑本页

robyle robylepissang pissang
+ + + + + diff --git a/docs/zh/how-to/chart-types/line/area-line/index.html b/docs/zh/how-to/chart-types/line/area-line/index.html new file mode 100644 index 000000000..1456662c5 --- /dev/null +++ b/docs/zh/how-to/chart-types/line/area-line/index.html @@ -0,0 +1,55 @@ + + + + + + + 区域面积图 - 折线图 - 常用图表类型 - 应用篇 - 使用手册 - Apache ECharts + + +

区域面积图

区域面积图将折线到坐标轴的空间设置背景色,用区域面积表达数据。相比普通的折线图,区域面积图的视觉效果更加饱满丰富,在系列不多的场景下尤其适用。

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 23, 19],
+      type: 'line',
+      areaStyle: {}
+    },
+    {
+      data: [25, 14, 23, 35, 10],
+      type: 'line',
+      areaStyle: {
+        color: '#ff0',
+        opacity: 0.5
+      }
+    }
+  ]
+};
live

通过 areaStyle 设置折线图的填充区域样式,将其设为为 {} 表示使用默认样式,即使用系列的颜色以半透明的方式填充区域。如果想指定特定的样式,可以通过设置 areaStyle 下的配置项覆盖,如第二个系列将填充区域的颜色设为不透明度为 0.5 的黄色。

本文贡献者 在 GitHub 上编辑本页

pissang pissang
+ + + + + diff --git a/docs/zh/how-to/chart-types/line/basic-line/index.html b/docs/zh/how-to/chart-types/line/basic-line/index.html new file mode 100644 index 000000000..1eb9661c4 --- /dev/null +++ b/docs/zh/how-to/chart-types/line/basic-line/index.html @@ -0,0 +1,163 @@ + + + + + + + 基础折线图 - 折线图 - 常用图表类型 - 应用篇 - 使用手册 - Apache ECharts + + +

基础折线图

折线图主要用来展示数据项随着时间推移的趋势或变化。

最简单的折线图

如果我们想建立一个横坐标是类目型(category)、纵坐标是数值型(value)的折线图,我们可以使用这样的方式:

option = {
+  xAxis: {
+    type: 'category',
+    data: ['A', 'B', 'C']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      data: [120, 200, 150],
+      type: 'line'
+    }
+  ]
+};
live

在这个例子中,我们通过 xAxis 将横坐标设为类目型,并指定了对应的值;通过 typeyAxis 的类型设定为数值型。在 series 中,我们将系列类型设为 line,并且通过 data 指定了折线图三个点的取值。这样,就能得到一个最简单的折线图了。

这里 xAxisyAxistype 属性都可以隐去不写。因为坐标轴的默认类型是数值型,而 xAxis 指定了类目型的 data,所以 ECharts 也能识别出这是类目型的坐标轴。为了让大家更容易理解,我们特意写了 type。在实际的应用中,如果是 'value' 类型,也可以省略不写。

笛卡尔坐标系中的折线图

如果我们希望折线图在横坐标和纵坐标上都是连续的,即在笛卡尔坐标系中,应该如何实现呢?答案也很简单,只要把 seriesdata 每个数据用一个包含两个元素的数组表示就行了。

option = {
+  xAxis: {},
+  yAxis: {},
+  series: [
+    {
+      data: [
+        [20, 120],
+        [50, 200],
+        [40, 50]
+      ],
+      type: 'line'
+    }
+  ]
+};
live

折线图样式设置

折线的样式

折线图中折线的样式可以通过 lineStyle 设置。可以为其指定颜色、线宽、折线类型、阴影、不透明度等等,具体的可以参考配置项手册 series.lineStyle 了解。这里,我们以设置颜色(color)、线宽(width)和折线类型(type)为例说明。

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 23, 19],
+      type: 'line',
+      lineStyle: {
+        normal: {
+          color: 'green',
+          width: 4,
+          type: 'dashed'
+        }
+      }
+    }
+  ]
+};
live

这里设置折线宽度时,数据点描边的宽度是不会跟着改变的,而应该在数据点的配置项中另外设置。

数据点的样式

数据点的样式可以通过 series.itemStyle 指定填充颜色(color)、描边颜色(borderColor)、描边宽度(borderWidth)、描边类型(borderType)、阴影(shadowColor)、不透明度(opacity)等。与折线样式的设置十分相似,这里不再展开说明。

在数据点处显示数值

在系列中,这数据点的标签通过 series.label 属性指定。如果将 label 下的 show 指定为true,则表示该数值默认时就显示;如果为 false,而 series.emphasis.label.showtrue,则表示只有在鼠标移动到该数据时,才显示数值。

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 23, 19],
+      type: 'line',
+      label: {
+        show: true,
+        position: 'bottom',
+        textStyle: {
+          fontSize: 20
+        }
+      }
+    }
+  ]
+};
live

空数据

在一个系列中,可能一个横坐标对应的取值是“空”的,将其设为 0 有时并不能满足我们的期望--空数据不应被其左右的数据连接。

在 ECharts 中,我们使用字符串 '-' 表示空数据,这对其他系列的数据也是适用的。

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [0, 22, '-', 23, 19],
+      type: 'line'
+    }
+  ]
+};
live

注意区别这个例子中,“空”数据与取值为 0 的数据。

本文贡献者 在 GitHub 上编辑本页

pissang pissang
+ + + + + diff --git a/docs/zh/how-to/chart-types/line/smooth-line/index.html b/docs/zh/how-to/chart-types/line/smooth-line/index.html new file mode 100644 index 000000000..19520e321 --- /dev/null +++ b/docs/zh/how-to/chart-types/line/smooth-line/index.html @@ -0,0 +1,39 @@ + + + + + + + 平滑曲线图 - 折线图 - 常用图表类型 - 应用篇 - 使用手册 - Apache ECharts + + +

平滑曲线图

平滑曲线图也是折线图的一种变形,这种更柔和的样式也是一种不错的视觉选择。使用时,只需要将折线图系列的 smooth 属性设置为 true 即可。

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 23, 19],
+      type: 'line',
+      smooth: true
+    }
+  ]
+};
live

本文贡献者 在 GitHub 上编辑本页

pissang pissang
+ + + + + diff --git a/docs/zh/how-to/chart-types/line/stacked-line/index.html b/docs/zh/how-to/chart-types/line/stacked-line/index.html new file mode 100644 index 000000000..9997d197c --- /dev/null +++ b/docs/zh/how-to/chart-types/line/stacked-line/index.html @@ -0,0 +1,87 @@ + + + + + + + 堆叠折线图 - 折线图 - 常用图表类型 - 应用篇 - 使用手册 - Apache ECharts + + +

堆叠折线图

堆叠柱状图类似,堆叠折线图也是用系列的 stack 设置哪些系列堆叠在一起。

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 43, 49],
+      type: 'line',
+      stack: 'x'
+    },
+    {
+      data: [5, 4, 3, 5, 10],
+      type: 'line',
+      stack: 'x'
+    }
+  ]
+};
live

但是不同的是,如果不加说明的话,我们很难判断出这是一个堆叠折线图,还是一个普通的折线图。所以,对于堆叠折线图而言,一般建议使用区域填充色以表明堆叠的情况。

option = {
+  xAxis: {
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  yAxis: {},
+  series: [
+    {
+      data: [10, 22, 28, 43, 49],
+      type: 'line',
+      stack: 'x',
+      areaStyle: {}
+    },
+    {
+      data: [5, 4, 3, 5, 10],
+      type: 'line',
+      stack: 'x',
+      areaStyle: {}
+    }
+  ]
+};
live

本文贡献者 在 GitHub 上编辑本页

vincentbernat vincentbernatpissang pissang
+ + + + + diff --git a/docs/zh/how-to/chart-types/line/step-line/index.html b/docs/zh/how-to/chart-types/line/step-line/index.html new file mode 100644 index 000000000..7f3c7c900 --- /dev/null +++ b/docs/zh/how-to/chart-types/line/step-line/index.html @@ -0,0 +1,71 @@ + + + + + + + 阶梯线图 - 折线图 - 常用图表类型 - 应用篇 - 使用手册 - Apache ECharts + + +

阶梯线图

阶梯线图又称方波图,它使用水平和垂直的线来连接两个数据点,而普通折线图则直接将两个点连接起来。阶梯线图能够很好地表达数据的突变。

在 ECharts 中,系列的 step 属性用来表征阶梯线图的连接类型,它共有三种取值:'start''middle''end',分别表示在当前点,当前点与下个点的中间点,下个点拐弯。

option = {
+  xAxis: {
+    type: 'category',
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      name: 'Step Start',
+      type: 'line',
+      step: 'start',
+      data: [120, 132, 101, 134, 90, 230, 210]
+    },
+    {
+      name: 'Step Middle',
+      type: 'line',
+      step: 'middle',
+      data: [220, 282, 201, 234, 290, 430, 410]
+    },
+    {
+      name: 'Step End',
+      type: 'line',
+      step: 'end',
+      data: [450, 432, 401, 454, 590, 530, 510]
+    }
+  ]
+};
live

请注意这个例子中不同的 step 取值对应的数据点和连线的区别。

本文贡献者 在 GitHub 上编辑本页

pissang pissang
+ + + + + diff --git a/docs/zh/how-to/chart-types/pie/basic-pie/index.html b/docs/zh/how-to/chart-types/pie/basic-pie/index.html new file mode 100644 index 000000000..7a1d749dd --- /dev/null +++ b/docs/zh/how-to/chart-types/pie/basic-pie/index.html @@ -0,0 +1,187 @@ + + + + + + + 基础饼图 - 饼图 - 常用图表类型 - 应用篇 - 使用手册 - Apache ECharts + + +

基础饼图

饼图主要用于表现不同类目的数据在总和中的占比。每个的弧度表示数据数量的比例。

最简单的饼图

饼图的配置和折线图、柱状图略有不同,不再需要配置坐标轴,而是把数据名称和值都写在系列中。以下是一个最简单的饼图的例子。

option = {
+  series: [
+    {
+      type: 'pie',
+      data: [
+        {
+          value: 335,
+          name: '直接访问'
+        },
+        {
+          value: 234,
+          name: '联盟广告'
+        },
+        {
+          value: 1548,
+          name: '搜索引擎'
+        }
+      ]
+    }
+  ]
+};
live

需要注意的是,这里是 value 不需要是百分比数据,ECharts 会根据所有数据的 value ,按比例分配它们在饼图中对应的弧度。

饼图样式设置

饼图的半径

饼图的半径可以通过 series.radius 设置,可以是诸如 '60%' 这样相对的百分比字符串,或是 200 这样的绝对像素数值。当它是百分比字符串时,它是相对于容器宽高中较小的一条边的。也就是说,如果宽度大于高度,则百分比是相对于高度的,反之则反;当它是数值型时,它表示绝对的像素大小。

option = {
+  series: [
+    {
+      type: 'pie',
+      data: [
+        {
+          value: 335,
+          name: '直接访问'
+        },
+        {
+          value: 234,
+          name: '联盟广告'
+        },
+        {
+          value: 1548,
+          name: '搜索引擎'
+        }
+      ],
+      radius: '50%'
+    }
+  ]
+};
live

如果数据和为 0,不显示饼图

在默认情况下,如果数据值和为 0,会显示平均分割的扇形。比如,如果有 4 个数据项,并且每个数据项都是 0,则每个扇形都是 90°。如果我们希望在这种情况下不显示任何扇形,可以将 series.stillShowZeroSum 设为 false

option = {
+  series: [
+    {
+      type: 'pie',
+      stillShowZeroSum: false,
+      data: [
+        {
+          value: 0,
+          name: '直接访问'
+        },
+        {
+          value: 0,
+          name: '联盟广告'
+        },
+        {
+          value: 0,
+          name: '搜索引擎'
+        }
+      ]
+    }
+  ]
+};
live

如果希望扇形对应的标签也不显示,可以将 series.label.show 设为 false

option = {
+  series: [
+    {
+      type: 'pie',
+      stillShowZeroSum: false,
+      label: {
+        show: false
+      },
+      data: [
+        {
+          value: 0,
+          name: '直接访问'
+        },
+        {
+          value: 0,
+          name: '联盟广告'
+        },
+        {
+          value: 0,
+          name: '搜索引擎'
+        }
+      ]
+    }
+  ]
+};
live

本文贡献者 在 GitHub 上编辑本页

pissang pissang
+ + + + + diff --git a/docs/zh/how-to/chart-types/pie/doughnut/index.html b/docs/zh/how-to/chart-types/pie/doughnut/index.html new file mode 100644 index 000000000..6612978a6 --- /dev/null +++ b/docs/zh/how-to/chart-types/pie/doughnut/index.html @@ -0,0 +1,135 @@ + + + + + + + 圆环图 - 饼图 - 常用图表类型 - 应用篇 - 使用手册 - Apache ECharts + + +

圆环图

圆环图同样可以用来表示数据占总体的比例,相比于饼图,它中间空余的部分可以用来显示一些额外的文字等信息,因而也是一种常用的图表类型。

基础圆环图

在 ECharts 中,饼图的半径除了上一小节提到的,可以是一个数值或者字符串之外,还可以是一个包含两个元素的数组,每个元素可以为数值或字符串。当它是一个数组时,它的前一项表示内半径,后一项表示外半径,这样就形成了一个圆环图。

从这个角度上来说,可以认为饼图是一个内半径为 0 的圆环图,也就是说,饼图是圆环图的特例。

option = {
+  title: {
+    text: '圆环图的例子',
+    left: 'center',
+    top: 'center'
+  },
+  series: [
+    {
+      type: 'pie',
+      data: [
+        {
+          value: 335,
+          name: 'A'
+        },
+        {
+          value: 234,
+          name: 'B'
+        },
+        {
+          value: 1548,
+          name: 'C'
+        }
+      ],
+      radius: ['40%', '70%']
+    }
+  ]
+};
live

如果半径是数组,其中的两项也可以一项是数值,另一项是百分比形式的字符串。但是这样可能导致在某些分辨率下,内半径小于外半径。ECharts 会自动使用小的一项作为内半径,但是仍应小心这样可能会导致的非预期效果。

在圆环图中间显示高亮扇形对应的文字

上面的例子展现了在圆环图中间显示固定文字的例子,下面我们要介绍,如何在圆环图中间显示鼠标高亮的扇形对应的文字。实现这一效果的思路是,利用系列的 label(默认用扇形颜色显示数据的 name),显示在圆环图中间。在默认情况下不显示系列的 label,在高亮时显示。具体的代码如下:

option = {
+  legend: {
+    orient: 'vertical',
+    x: 'left',
+    data: ['A', 'B', 'C', 'D', 'E']
+  },
+  series: [
+    {
+      type: 'pie',
+      radius: ['50%', '70%'],
+      avoidLabelOverlap: false,
+      label: {
+        show: false,
+        position: 'center'
+      },
+      labelLine: {
+        show: false
+      },
+      emphasis: {
+        label: {
+          show: true,
+          fontSize: '30',
+          fontWeight: 'bold'
+        }
+      },
+      data: [
+        { value: 335, name: 'A' },
+        { value: 310, name: 'B' },
+        { value: 234, name: 'C' },
+        { value: 135, name: 'D' },
+        { value: 1548, name: 'E' }
+      ]
+    }
+  ]
+};
live

其中,avoidLabelOverlap 是用来控制是否由 ECharts 调整标签位置以实现防止标签重叠。它的默认值是 true,而在这里,我们不希望标签位置调整到不是中间的位置,因此我们需要将其设为 false

这样,圆环图中间会显示高亮数据的 name 值。

本文贡献者 在 GitHub 上编辑本页

pissang pissangguda-art guda-art
+ + + + + diff --git a/docs/zh/how-to/chart-types/pie/rose/index.html b/docs/zh/how-to/chart-types/pie/rose/index.html new file mode 100644 index 000000000..a7d018e0d --- /dev/null +++ b/docs/zh/how-to/chart-types/pie/rose/index.html @@ -0,0 +1,73 @@ + + + + + + + 南丁格尔图(玫瑰图) - 饼图 - 常用图表类型 - 应用篇 - 使用手册 - Apache ECharts + + +

南丁格尔图(玫瑰图)

南丁格尔图又称玫瑰图,通常用弧度相同但半径不同的扇形表示各个类目。

ECharts 可以通过将饼图的 series.roseType 值设为 'area' 实现南丁格尔图,其他配置项和饼图是相同的。

option = {
+  series: [
+    {
+      type: 'pie',
+      data: [
+        {
+          value: 100,
+          name: 'A'
+        },
+        {
+          value: 200,
+          name: 'B'
+        },
+        {
+          value: 300,
+          name: 'C'
+        },
+        {
+          value: 400,
+          name: 'D'
+        },
+        {
+          value: 500,
+          name: 'E'
+        }
+      ],
+      roseType: 'area'
+    }
+  ]
+};
live

本文贡献者 在 GitHub 上编辑本页

pissang pissang
+ + + + + diff --git a/docs/zh/how-to/chart-types/scatter/basic-scatter/index.html b/docs/zh/how-to/chart-types/scatter/basic-scatter/index.html new file mode 100644 index 000000000..42fcb828b --- /dev/null +++ b/docs/zh/how-to/chart-types/scatter/basic-scatter/index.html @@ -0,0 +1,126 @@ + + + + + + + 基础散点图 - 散点图 - 常用图表类型 - 应用篇 - 使用手册 - Apache ECharts + + +

基础散点图

散点图,也是一种常见的图表类型。散点图由许多“点”组成,有时,这些点用来表示数据在坐标系中的位置(比如在笛卡尔坐标系下,表示数据在 x 轴和 y 轴上的坐标;在地图坐标系下,表示数据在地图上的某个位置等);有时,这些点的大小、颜色等属性也可以映射到数据值,用以表现高维数据。

最简单的散点图

下面是一个横坐标为类目轴、纵坐标为数值轴的最简单的散点图配置:

option = {
+  xAxis: {
+    data: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'scatter',
+      data: [220, 182, 191, 234, 290, 330, 310]
+    }
+  ]
+};
live

笛卡尔坐标系下的散点图

在上文的例子中,散点图的横坐标都是离散的类目轴,而纵坐标都是连续的数值轴。而对于散点图而言,另一种常见的场景是,两个坐标轴均为连续的数值轴,也就是笛卡尔坐标系。这时的系列形式略有不同,数据的横坐标和纵坐标一同写在 data 中,而非坐标轴中。

option = {
+  xAxis: {},
+  yAxis: {},
+  series: [
+    {
+      type: 'scatter',
+      data: [
+        [10, 5],
+        [0, 8],
+        [6, 10],
+        [2, 12],
+        [8, 9]
+      ]
+    }
+  ]
+};
live

散点图样式设置

图形的形状

图形(symbol)指的是散点图中数据“点”的形状。有三类图形可选,一种是 ECharts 内置形状,第二种是图片,第三种是 SVG 的路径。

ECharts 内置形状包括:圆形、矩形、圆角矩形、三角形、菱形、大头针形、箭头形,分别对应'circle''rect''roundRect''triangle''diamond''pin''arrow'。使用内置形状时,只要将 symbol 属性指定为形状名称对应的字符串即可。

如果想要将图形指定为任意的图片,以 'image://' 开头,后面跟图片的绝对或相对地址。形如:'image://http://example.com/xxx.png''image://./xxx.png'

除此之外,还支持 SVG 的路径作为矢量图形,将 symbol 设置为以 'path://' 开头的 SVG 路径即可。使用矢量图形的好处是,图片不会因为缩放而产生锯齿或模糊,并且通常而言比图片形式的文件大小更小。路径的查看方法为,打开一个 SVG 文件,找到形如 <path d="M… L…"></path> 的路径,将 d 的值添加在 'path://' 后即可。

下面,我们展示一个将图形设置为矢量爱心形状的方式。

首先,我们需要一个爱心的 SVG 文件,可以使用矢量编辑软件绘制,或者从网上下载到相关资源。其内容如下:

<?xml version="1.0" encoding="iso-8859-1"?>
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 51.997 51.997" style="enable-background:new 0 0 51.997 51.997;" xml:space="preserve">
+    <path d="M51.911,16.242C51.152,7.888,45.239,1.827,37.839,1.827c-4.93,0-9.444,2.653-11.984,6.905 c-2.517-4.307-6.846-6.906-11.697-6.906c-7.399,0-13.313,6.061-14.071,14.415c-0.06,0.369-0.306,2.311,0.442,5.478 c1.078,4.568,3.568,8.723,7.199,12.013l18.115,16.439l18.426-16.438c3.631-3.291,6.121-7.445,7.199-12.014 C52.216,18.553,51.97,16.611,51.911,16.242z"/>
+</svg>

在 ECharts 的 symbol 配置项中,我们使用 d 的值作为路径。

option = {
+  xAxis: {
+    data: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'scatter',
+      data: [220, 182, 191, 234, 290, 330, 310],
+      symbolSize: 20,
+      symbol:
+        'path://M51.911,16.242C51.152,7.888,45.239,1.827,37.839,1.827c-4.93,0-9.444,2.653-11.984,6.905 c-2.517-4.307-6.846-6.906-11.697-6.906c-7.399,0-13.313,6.061-14.071,14.415c-0.06,0.369-0.306,2.311,0.442,5.478 c1.078,4.568,3.568,8.723,7.199,12.013l18.115,16.439l18.426-16.438c3.631-3.291,6.121-7.445,7.199-12.014 C52.216,18.553,51.97,16.611,51.911,16.242z'
+    }
+  ]
+};
live

这样,就能得到爱心形状的图形作为点的形状了。

图形的大小

图形大小可以使用 series.symbolSize 控制。它既可以是一个表示图形大小的像素值,也可以是一个包含两个 number 元素的数组,分别表示图形的宽和高。

除此之外,它还可以是一个回调函数,其参数格式为:

(value: Array | number, params: Object) => number | Array;

第一个参数为数据值,第二个参数是数据项的其他参数。

在下面的例子中,我们将散点图点的大小设置为与其数据值成正比。

option = {
+  xAxis: {
+    data: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'scatter',
+      data: [220, 182, 191, 234, 290, 330, 310],
+      symbolSize: function(value) {
+        return value / 10;
+      }
+    }
+  ]
+};
live

本文贡献者 在 GitHub 上编辑本页

pissang pissang
+ + + + + diff --git a/docs/zh/how-to/cross-platform/baidu-app/index.html b/docs/zh/how-to/cross-platform/baidu-app/index.html new file mode 100644 index 000000000..4c4ee715c --- /dev/null +++ b/docs/zh/how-to/cross-platform/baidu-app/index.html @@ -0,0 +1,15 @@ + + + + + + + 百度智能小程序 - 跨平台方案 - 应用篇 - 使用手册 - Apache ECharts + + +

在百度智能小程序中使用 ECharts

ECharts 图表 以小程序动态库的形式提供了在百度智能小程序中使用 ECharts 的方式。

baidu-smart-app-echarts-demo 项目是使用该动态库的一个示例工程,可以作为参考,一般情况下不需要引入自己的项目。

如有使用上的问题,可以在 baidu-smart-app-echarts-demo/issues 中咨询。

使用方式

参见百度智能小程序文档 ECharts 图表

注意事项

百度智能小程序上的 ECharts 以动态库的形式开放,因此开发者的使用方式与在微信小程序中使用 ECharts 不太相同。尤其需要注意的是,前者需要在指定动态库名称的时候确定 ECharts 的版本号,而不能自行更换或使用自定义构建。这一点是由底层框架的技术实现决定的。具体来说,在指定百度智能小程序动态库名称的时候,需要通过 provider 指定动态库名称,具体参见文档的「在项目中引用动态库」章节。

请务必查看文档的「兼容性说明」以了解各功能的实现方式。

本文贡献者 在 GitHub 上编辑本页

Ovilia Oviliavincentbernat vincentbernatpissang pissang
+ + + + + diff --git a/docs/zh/how-to/cross-platform/server/index.html b/docs/zh/how-to/cross-platform/server/index.html new file mode 100644 index 000000000..30b673c22 --- /dev/null +++ b/docs/zh/how-to/cross-platform/server/index.html @@ -0,0 +1,132 @@ + + + + + + + 服务端渲染 - 跨平台方案 - 应用篇 - 使用手册 - Apache ECharts + + +

服务端渲染 ECharts 图表

通常情况下,Apache EChartsTM 会在浏览器中动态的渲染图表,并且根据用户的交互来更新渲染。但是在下面这些比较特殊的场景,我们也需要在服务端中渲染图表并且输出到浏览器中:

  • 需要缩短前端的渲染时间,保证第一时间显示图表
  • 需要在 Markdown, PDF 等不支持动态运行脚本的环境中嵌入图表

在这些场景下,ECharts 也提供了两种服务端渲染(server-side rendering,SSR)的方案:SVG 渲染或 Canvas 渲染。

渲染方案 渲染结果的形式 优点
服务端 SVG 渲染 SVG 字符串 比 Canvas 图片体积更小;
矢量 SVG 图片不会模糊;
支持初始动画
服务端 Canvas 渲染 图片 图片形式适用场景更广泛,对不支持 SVG 的场景可选择

通常情况下,应优先考虑使用服务端 SVG 渲染方案,如果 SVG 不适用,也可以考虑 Canvas 渲染方案。

使用服务端渲染也有一定的局限性,尤其是和交互相关的一些操作无法支持。因此,如果有交互需求,可参考下文的“服务端渲染 Hydration”。

服务端渲染

服务端 SVG 渲染

版本更新:

  • 5.3.0 版本:使用零依赖的服务端 SVG 字符串渲染方案,并支持图表的初始动画
  • 5.5.0 版本:新增客户端轻量运行时,客户端无需加载完整 ECharts 即可实现部分交互

5.3.0 里新引入了零依赖的服务端 SVG 字符串渲染方案:

// 服务端代码
+const echarts = require('echarts');
+
+// 在 SSR 模式下第一个参数不需要再传入 DOM 对象
+const chart = echarts.init(null, null, {
+  renderer: 'svg', // 必须使用 SVG 模式
+  ssr: true, // 开启 SSR
+  width: 400, // 需要指明高和宽
+  height: 300
+});
+
+// 像正常使用一样 setOption
+chart.setOption({
+  //...
+});
+
+// 输出字符串
+const svgStr = chart.renderToSVGString();
+
+// 如果不再需要图表,调用 dispose 以释放内存
+chart.dispose();
+chart = null;

整体使用的代码结构跟在浏览器中使用一样,首先是init初始化一个图表实例,然后通过setOption设置图表的配置项。但是init传入的参数会跟在跟浏览器中使用有所不同:

  • 首先因为在服务端会采用字符串拼接的方式来渲染得到 SVG,我们并不需要容器来展示渲染的内容,所以我们可以在init的时候第一个container参数传入null或者undefined
  • 然后我们在init的第三个参数中,我们需要通过显示指定ssr: true来告诉 ECharts 我们需要开启服务端渲染的模式,该模式下 ECharts 会关闭动画循环的模块以及事件交互的模块。
  • 在服务端渲染中我们也必须要通过widthheight显示的指定图表的高和宽,因此如果你的图表是需要根据容器大小自适应的话,可能需要思考一下服务端渲染是否适合你的场景了。一种可能的解决方案是,首屏获取到图表容器大小后,请求服务端渲染图表,然后在客户端渲染图表;当用户交互改变容器大小时,重新请求服务端渲染。

在浏览器中我们在setOption完之后 ECharts 就会自动进行渲染将结果绘制到页面中,后续也会在每一帧判断是否有动画需要进行重绘。Node.js 中我们在设置了ssr: true后则没有这个过程。取而代之我们使用了renderToSVGString,将当前的图表渲染到 SVG 字符串,进一步得再通过 HTTP Response 返回给前端或者缓存到本地。

HTTP Response 返回给前端(这里以 Express.js 为例):

res.writeHead(200, {
+  'Content-Type': 'application/xml'
+});
+res.write(svgStr); // svgStr 是上面 chart.renderToSVGString() 得到的字符串
+res.end();

或者保存到本地:

fs.writeFile('bar.svg', svgStr, 'utf-8');

服务端渲染中的动画效果

上面的例子中可以看到,就算是服务端渲染 ECharts 也可以提供动画效果,这个动画效果是通过在输出的 SVG 字符串中嵌入 CSS 动画实现的。并不需要额外的 JavaScript 再去控制动画。

但是,也因为 CSS 动画的局限性,我们没法在服务端渲染中实现一些更灵活的动画功能,诸如柱状图排序动画,标签动画,路径图的特效动画等。部分系列诸如饼图的动画效果也为服务端渲染做了特殊的优化。

如果你不希望有这个动画效果,可以在setOption的时候通过animation: false关闭动画。

setOption({
+  animation: false
+});

服务端 Canvas 渲染

如果你希望输出的是一张图片而非 SVG 字符串,或者你还在使用更老的版本,我们会推荐使用 node-canvas 来实现 ECharts 的服务渲染,node-canvas 是在 Node.js 上的一套 Canvas 实现,它提供了跟浏览器中 Canvas 几乎一致的接口。

下面是一个简单的例子

var echarts = require('echarts');
+const { createCanvas } = require('canvas');
+
+// 在 5.3.0 之前的版本中,你必须要通过该接口注册 canvas 实例创建方法。
+// 从 5.3.0 开始就不需要了
+echarts.setCanvasCreator(() => {
+  return createCanvas();
+});
+
+const canvas = createCanvas(800, 600);
+// ECharts 可以直接使用 node-canvas 创建的 Canvas 实例作为容器
+const chart = echarts.init(canvas);
+
+// 像正常使用一样 setOption
+chart.setOption({
+  //...
+});
+
+const buffer = renderChart().toBuffer('image/png');
+
+// 如果不再需要图表,调用 dispose 以释放内存
+chart.dispose();
+chart = null;
+
+// 通过 Response 输出 PNG 图片
+res.writeHead(200, {
+  'Content-Type': 'image/png'
+});
+res.write(buffer);
+res.end();

图片的加载

node-canvas 提供了图片加载的Image实现,如果你在图表中使用了到了图片,我们可以使用5.3.0新增的setPlatformAPI接口来适配。

echarts.setPlatformAPI({
+  // 同老版本的 setCanvasCreator
+  createCanvas() {
+    return createCanvas();
+  },
+  loadImage(src, onload, onerror) {
+    const img = new Image();
+    // 必须要绑定 this context.
+    img.onload = onload.bind(img);
+    img.onerror = onerror.bind(img);
+    img.src = src;
+    return img;
+  }
+});

如果你的图片是需要远程获取的,我们建议你通过 http 请求先预取该图片得到base64之后再作为图片的 URL 传入,这样可以保证在 Response 输出的时候图片是加载完成的。

客户端二次渲染

客户端懒加载完整 ECharts

最新版本的 ECharts 服务端 SVG 渲染除了完成图表的渲染外,支持的功能包括:

  • 图表初始动画(例如:柱状图初始化时的柱子上升动画)
  • 高亮样式(例如:鼠标移动到柱状图柱子上时的高亮效果)

但仅使用服务端渲染无法支持的功能包括:

  • 动态改变数据
  • 点击图例切换系列是否显示
  • 移动鼠标显示提示框
  • 其他交互相关的功能

如果有相关需求,可以考虑先使用服务端渲染快速输出首屏图表,然后等待 echarts.js 加载完后,重新在客户端渲染同样的图表(称为 Hydration),这样就可以实现正常的交互效果和动态改变数据了。需要注意的是,在客户端渲染的时候,应开启 tooltip: { show: true } 之类的交互组件,并且用 animation: 0 关闭初始动画(初始动画应由服务端渲染结果的 SVG 动画完成)。

从用户体验的角度,几乎感受不到二次渲染的过程,整个切换效果是非常无缝衔接的。你也可以像上面的例子中一样,在加载 echarts.js 的过程中使用 pace-js 之类的库实现显示加载进度条的效果,来解决 ECharts 尚未完全加载完之前没有交互反馈的问题。

使用服务端渲染 SVG 加上客户端 ECharts 懒加载的方式,其优点是,能够在首屏快速展示图表,而懒加载完成后可以实现所有 ECharts 的功能和交互;而缺点是,懒加载完整的 ECharts 需要一定时间,在加载完成前无法实现除高亮之外的用户交互(在这种情况下,开发者可以通过显示“加载中”来解决无交互反馈带来的困惑)。这个方案也是目前比较推荐的对首屏加载时间敏感,对功能交互完整性要求高的方案。

客户端轻量运行时

方案一给出了实现完整交互的方案,但是有些场景下,我们并不需要很复杂的交互,只是希望在服务端渲染的基础上,能够在客户端进行一些简单的交互,例如:点击图例切换系列是否显示。这种情况下,我们能否不在客户端加载至少需要几百 KB 的 ECharts 代码呢?

从 v5.5.0 版本起,如果图表只需要以下效果和交互,可以通过服务端 SVG 渲染 + 客户端轻量运行时来实现:

  • 图表初始动画(实现原理:服务端渲染的 SVG 带有 CSS 动画)
  • 高亮样式(实现原理:服务端渲染的 SVG 带有 CSS 动画)
  • 动态改变数据(实现原理:轻量运行时请求服务器进行二次渲染)
  • 点击图例切换系列是否显示(实现原理:轻量运行时请求服务器进行二次渲染)
<div id="chart-container" style="width:800px;height:600px"></div>
+
+<script src="https://cdn.jsdelivr.net/npm/echarts/ssr/client/dist/index.js"></script>
+<script>
+const ssrClient = window['echarts-ssr-client'];
+
+let isSeriesShown = {
+  a: true,
+  b: true
+};
+
+function updateChart(svgStr) {
+  const container = document.getElementById('chart-container');
+  container.innerHTML = svgStr;
+
+  // 使用轻量运行时赋予图表交互能力
+  ssrClient.hydrate(main, {
+    on: {
+      click: (params) => {
+        if (params.ssrType === 'legend') {
+          // 点击图例元素,请求服务器进行二次渲染
+          isSeriesShown[params.seriesName] = !isSeriesShown[params.seriesName];
+          $.get('...?series=' + JSON.stringify(isSeriesShown)).then(svgStr => {
+            updateChart(svgStr);
+          });
+        }
+      }
+    }
+  });
+}
+
+// 通过 AJAX 请求获取服务端渲染的 SVG 字符串
+$.get('...').then(svgStr => {
+  updateChart(svgStr);
+});
+</script>

服务器端根据客户端传来的每个系列是否显示的信息(isSeriesShown)进行二次渲染,返回新的 SVG 字符串。服务端代码同上文,不再赘述。

关于状态记录:上述这种开发方式和纯客户端渲染的相比,开发者需要记录并维护一些额外的信息(例如这个例子中每个系列是否显示)。这是不可避免的,因为 HTTP 请求本身是无状态的,如果要实现有状态,要么像上面的例子这样由客户端记录状态并传递,要么服务器保留状态(例如通过 session,但需要耗费更多的服务器内存以及更复杂的销毁逻辑所以并不推荐)。

使用服务端 SVG 渲染加上客户端轻量运行时的方式,其优点是,客户端不再需要加载几百 KB 的 ECharts 代码,只需要加载一个不到 4KB 的轻量运行时代码;并且从用户体验的角度牺牲很少(支持初始动画、鼠标高亮)。而缺点是,需要一定的开发成本来维护额外的状态信息,并且无法支持实时性要求高的交互(例如移动鼠标显示提示框)。总体来说,推荐在对代码体积有非常严格要求的环境使用

使用轻量运行时

客户端轻量运行时通过将服务端渲染的 SVG 图表进行理解,从而赋予图表一定的交互能力。

可以通过以下方式引入客户端轻量运行时:

<!-- 方法一:使用 CDN -->
+<script src="https://cdn.jsdelivr.net/npm/echarts/ssr/client/dist/index.js"></script>
+<!-- 方法二:使用 NPM -->
+<script src="node_modules/echarts/ssr/client/dist/index.js"></script>

API

在全局变量 window['echarts-ssr-client'] 中提供了以下 API:

hydrate(dom: HTMLElement, options: ECSSRClientOptions)

  • dom:图表容器,其内部的内容在调用本方法前应已设为服务端渲染的 SVG 图表
  • options:配置项
ECSSRClientOptions
on?: {
+  mouseover?: (params: ECSSRClientEventParams) => void,
+  mouseout?: (params: ECSSRClientEventParams) => void,
+  click?: (params: ECSSRClientEventParams) => void
+}

图表鼠标事件一样,这里的时间都是针对图表数据对象的(例如:柱状图的柱子、折线图的数据点等),而不是针对图表容器的。

ECSSRClientEventParams
{
+  type: 'mouseover' | 'mouseout' | 'click';
+  ssrType: 'legend' | 'chart';
+  seriesIndex?: number;
+  dataIndex?: number;
+  event: Event;
+}
  • type:事件类型
  • ssrType:事件对象类型,legend 表示图例数据,chart 表示图表数据对象
  • seriesIndex:系列索引
  • dataIndex:数据索引
  • event:原生事件对象

示例

参见上文「客户端轻量运行时」章节。

小结

上面,我们介绍了几种不同的渲染方案,包括:

  • 客户端渲染
  • 服务端 SVG 渲染
  • 服务端 Canvas 渲染
  • 客户端轻量运行时渲染

这四种渲染方式可以结合使用,我们再来总结一下它们各自适用的场景:

渲染方案 加载体积 功能及交互损失 相对开发工作量 推荐场景
客户端渲染 最大 最小 首屏加载时间不敏感,对功能交互完整性要求高
客户端渲染(按需引用部分包) 大:没有引入的包就无法使用对应功能 首屏加载时间不敏感,对代码体积没有严格要求但是希望尽可能小,仅使用 ECharts 的一小部分功能,没有服务器资源
一次性服务端 SVG 渲染 大:无法动态改变数据、不支持图例切换系列是否显示、不支持提示框等实时性要求高的交互 首屏加载时间敏感,对功能交互完整性要求低
一次性服务端 Canvas 渲染 最大:同上且不支持初始动画、图片体积更大、放大会模糊 首屏加载时间敏感,对功能交互完整性要求低,平台限制无法使用 SVG
服务端 SVG 渲染加客户端懒加载 ECharts 小,然后大 中:懒加载完成前无法交互 首屏加载时间敏感,对功能交互完整性要求高,最好图表不会在加载后立刻需要交互
服务端 SVG 渲染加客户端轻量运行时 中:无法实现实时性要求高的交互 大(需要维护图表状态、定义客户端服务端接口协议) 首屏加载时间敏感,对功能交互完整性要求低,对代码体积有非常严格要求,交互实时性要求不严格
服务端 SVG 渲染加客户端懒加载 ECharts,懒加载完成前使用轻量运行时 小,然后大 小:在懒加载完成前无法进行复杂交互 最大 首屏加载时间敏感,对功能交互完整性要求高,有充分的开发时间

当然,还存在一些其他的组合可能性,但最常用的就是以上几种,相信如果你了解了这些渲染方案的特点,就可以根据自己的场景选择合适的方案了。

本文贡献者 在 GitHub 上编辑本页

Ovilia Oviliapissang pissang
+ + + + + diff --git a/docs/zh/how-to/cross-platform/wechat-app/index.html b/docs/zh/how-to/cross-platform/wechat-app/index.html new file mode 100644 index 000000000..452046486 --- /dev/null +++ b/docs/zh/how-to/cross-platform/wechat-app/index.html @@ -0,0 +1,15 @@ + + + + + + + 微信小程序 - 跨平台方案 - 应用篇 - 使用手册 - Apache ECharts + + +

在微信小程序中使用 ECharts

echarts-for-weixin 项目提供了一个小程序组件,用这种方式可以方便地使用 ECharts。

使用方式

  1. 下载该项目
  2. 如有必要,将 ec-canvas 目录下的 echarts.js 替换为最新版的 ECharts。如果希望减小包体积大小,可以使用自定义构建生成并替换 echarts.js
  3. pages 目录下是使用的示例文件,可以作为参考,或者删除不需要的页面。

更详细的说明请参见 echarts-for-weixin 项目。

注意事项

最新版的 ECharts 微信小程序支持微信 Canvas 2d,当用户的基础库版本 >= 2.9.0 且没有设置 force-use-old-canvas="true" 的情况下,使用新的 Canvas 2d(默认)。

使用新的 Canvas 2d 可以提升渲染性能,解决非同层渲染问题,强烈建议开启。

更详细的说明请参见 Canvas 2d 版本要求

本文贡献者 在 GitHub 上编辑本页

pissang pissang
+ + + + + diff --git a/docs/zh/how-to/data/dynamic-data/index.html b/docs/zh/how-to/data/dynamic-data/index.html new file mode 100644 index 000000000..66d95be98 --- /dev/null +++ b/docs/zh/how-to/data/dynamic-data/index.html @@ -0,0 +1,83 @@ + + + + + + + 动态的异步数据 - 数据处理 - 应用篇 - 使用手册 - Apache ECharts + + +

异步数据的加载与动态更新

异步加载

入门示例中的数据是在初始化后setOption中直接填入的,但是很多时候可能数据需要异步加载后再填入。ECharts 中实现异步数据的更新非常简单,在图表初始化后不管任何时候只要通过 jQuery 等工具异步获取数据后通过 setOption 填入数据和配置项就行。

var myChart = echarts.init(document.getElementById('main'));
+
+$.get('data.json').done(function(data) {
+  // data 的结构:
+  // {
+  //     categories: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"],
+  //     values: [5, 20, 36, 10, 10, 20]
+  // }
+  myChart.setOption({
+    title: {
+      text: '异步数据加载示例'
+    },
+    tooltip: {},
+    legend: {},
+    xAxis: {
+      data: data.categories
+    },
+    yAxis: {},
+    series: [
+      {
+        name: '销量',
+        type: 'bar',
+        data: data.values
+      }
+    ]
+  });
+});

或者先设置完其它的样式,显示一个空的直角坐标轴,然后获取数据后填入数据。

var myChart = echarts.init(document.getElementById('main'));
+// 显示标题,图例和空的坐标轴
+myChart.setOption({
+  title: {
+    text: '异步数据加载示例'
+  },
+  tooltip: {},
+  legend: {
+    data: ['销量']
+  },
+  xAxis: {
+    data: []
+  },
+  yAxis: {},
+  series: [
+    {
+      name: '销量',
+      type: 'bar',
+      data: []
+    }
+  ]
+});
+
+// 异步加载数据
+$.get('data.json').done(function(data) {
+  // 填入数据
+  myChart.setOption({
+    xAxis: {
+      data: data.categories
+    },
+    series: [
+      {
+        // 根据名字对应到相应的系列
+        name: '销量',
+        data: data.data
+      }
+    ]
+  });
+});

如下:

ECharts 中在更新数据的时候需要通过name属性对应到相应的系列,上面示例中如果name不存在也可以根据系列的顺序正常更新,但是更多时候推荐更新数据的时候加上系列的name数据。

loading 动画

如果数据加载时间较长,一个空的坐标轴放在画布上也会让用户觉得是不是产生 bug 了,因此需要一个 loading 的动画来提示用户数据正在加载。

ECharts 默认有提供了一个简单的加载动画。只需要调用 showLoading 方法显示。数据加载完成后再调用 hideLoading 方法隐藏加载动画。

myChart.showLoading();
+$.get('data.json').done(function (data) {
+    myChart.hideLoading();
+    myChart.setOption(...);
+});

效果如下:

数据的动态更新

ECharts 由数据驱动,数据的改变驱动图表展现的改变,因此动态数据的实现也变得异常简单。

所有数据的更新都通过 setOption实现,你只需要定时获取数据,setOption 填入数据,而不用考虑数据到底产生了哪些变化,ECharts 会找到两组数据之间的差异然后通过合适的动画去表现数据的变化。

具体可以看下面示例:

本文贡献者 在 GitHub 上编辑本页

ZonaHex ZonaHexpissang pissangjishen027 jishen027
+ + + + + diff --git a/docs/zh/how-to/interaction/coarse-pointer/index.html b/docs/zh/how-to/interaction/coarse-pointer/index.html new file mode 100644 index 000000000..32def7f9e --- /dev/null +++ b/docs/zh/how-to/interaction/coarse-pointer/index.html @@ -0,0 +1,15 @@ + + + + + + + 智能指针吸附 - 交互 - 应用篇 - 使用手册 - Apache ECharts + + +

智能指针吸附

在图表中,部分可交互元素可能比较小,有时候用户不易准确地进行点击等操作,移动端尤其如此。因此,在 Apache EChartsTM 5.4.0 中,我们引入了“智能指针吸附”的概念。

从该版本起,在默认情况下,ECharts 对移动端的图表开启指针吸附,对非移动端的图表关闭。

如果需要对所有平台都开启,则可以通过在 init 的时候将 opt.useCoarsePointer 设置为 true 来实现;设为 false 则对所有平台都关闭。

吸附原理

在鼠标或触摸事件发生时,ECharts 会根据鼠标或触摸的位置,判断是否和某个可交互元素相交。如果是,则认为该元素是交互对象(与优化前的逻辑一致);如果不是,则在一定范围内找到最接近鼠标或触摸位置的一个元素。

默认的范围是 44px(参见 W3C 标准),开发者可在 init 的时候,通过 opt.pointerSize 设置该值。

更具体地说,ECharts 会在鼠标或触摸位置的周围,依次循环不同角度和不同半径(在 opt.pointerSize 范围内),直到找到一个元素与其相交。如果找到了,则认为该元素是交互对象。

也就是说,如果有元素在鼠标或触摸位置的 opt.pointerSize 半径范围内,则最靠近的可交互元素会被认为是交互对象。

性能分析

在实际算法实现的时候,我们首先将鼠标或触摸位置与所有可交互元素的 AABB 包围盒判断相交性,从而快速剔除了大部分不相交的元素。然后,我们再对剩余的元素进行精确的路径相交判断。因此,从用户体验角度,不会带来可感知的性能损耗。

对于大规模数据的图表系列(也就是开启了 large: true 的柱状图、散点图等),不会开启吸附功能。

本文贡献者 在 GitHub 上编辑本页

Ovilia Oviliaplainheart plainheart
+ + + + + diff --git a/docs/zh/how-to/interaction/drag/index.html b/docs/zh/how-to/interaction/drag/index.html new file mode 100644 index 000000000..6a34f86a1 --- /dev/null +++ b/docs/zh/how-to/interaction/drag/index.html @@ -0,0 +1,210 @@ + + + + + + + 拖拽的实现 - 交互 - 应用篇 - 使用手册 - Apache ECharts + + +

拖拽的实现

本篇通过介绍一个实现拖拽的小例子来介绍如何在 Apache EChartsTM 中实现复杂的交互。

这个例子主要做到了这样一件事,用鼠标可以拖拽曲线的点,从而改变曲线的形状。例子很简单,但是有了这个基础我们还可以做更多的事情,比如在图中进行可视化得编辑。所以我们从这个简单的例子开始。

echarts 本身没有提供封装好的“拖拽改变图表”这样比较业务定制的功能。但是这个功能开发者可以通过 API 扩展实现。

实现基本的拖拽功能

在这个例子中,基础的图表是一个 折线图 (series-line)。参见如下配置:

var symbolSize = 20;
+
+// 这个 data 变量在这里单独声明,在后面也会用到。
+var data = [
+  [15, 0],
+  [-50, 10],
+  [-56.5, 20],
+  [-46.5, 30],
+  [-22.1, 40]
+];
+
+myChart.setOption({
+  xAxis: {
+    min: -100,
+    max: 80,
+    type: 'value',
+    axisLine: { onZero: false }
+  },
+  yAxis: {
+    min: -30,
+    max: 60,
+    type: 'value',
+    axisLine: { onZero: false }
+  },
+  series: [
+    {
+      id: 'a',
+      type: 'line',
+      smooth: true,
+      symbolSize: symbolSize, // 为了方便拖拽,把 symbolSize 尺寸设大了。
+      data: data
+    }
+  ]
+});

既然折线中原生的点没有拖拽功能,我们就为它加上拖拽功能:用 graphic 组件,在每个点上面,覆盖一个隐藏的可拖拽的圆点。

myChart.setOption({
+  // 声明一个 graphic component,里面有若干个 type 为 'circle' 的 graphic elements。
+  // 这里使用了 echarts.util.map 这个帮助方法,其行为和 Array.prototype.map 一样,但是兼容 es5 以下的环境。
+  // 用 map 方法遍历 data 的每项,为每项生成一个圆点。
+  graphic: echarts.util.map(data, function(dataItem, dataIndex) {
+    return {
+      // 'circle' 表示这个 graphic element 的类型是圆点。
+      type: 'circle',
+
+      shape: {
+        // 圆点的半径。
+        r: symbolSize / 2
+      },
+      // 用 transform 的方式对圆点进行定位。position: [x, y] 表示将圆点平移到 [x, y] 位置。
+      // 这里使用了 convertToPixel 这个 API 来得到每个圆点的位置,下面介绍。
+      position: myChart.convertToPixel('grid', dataItem),
+
+      // 这个属性让圆点不可见(但是不影响他响应鼠标事件)。
+      invisible: true,
+      // 这个属性让圆点可以被拖拽。
+      draggable: true,
+      // 把 z 值设得比较大,表示这个圆点在最上方,能覆盖住已有的折线图的圆点。
+      z: 100,
+      // 此圆点的拖拽的响应事件,在拖拽过程中会不断被触发。下面介绍详情。
+      // 这里使用了 echarts.util.curry 这个帮助方法,意思是生成一个与 onPointDragging
+      // 功能一样的新的函数,只不过第一个参数永远为此时传入的 dataIndex 的值。
+      ondrag: echarts.util.curry(onPointDragging, dataIndex)
+    };
+  })
+});

上面的代码中,使用 convertToPixel 这个 API,进行了从 data 到“像素坐标”的转换,从而得到了每个圆点应该在的位置,从而能绘制这些圆点。myChart.convertToPixel('grid', dataItem) 这句话中,第一个参数 'grid' 表示 dataItemgrid 这个组件中(即直角坐标系)中进行转换。所谓“像素坐标”,就是以 echarts 容器 dom element 的左上角为零点的以像素为单位的坐标系中的坐标。

注意这件事需要在第一次 setOption 后再进行,也就是说,须在坐标系(grid)初始化后才能调用 myChart.convertToPixel('grid', dataItem)

有了这段代码后,就有了诸个能拖拽的点。接下来要为每个点,加上拖拽响应的事件:

// 拖拽某个圆点的过程中会不断调用此函数。
+// 此函数中会根据拖拽后的新位置,改变 data 中的值,并用新的 data 值,重绘折线图,从而使折线图同步于被拖拽的隐藏圆点。
+function onPointDragging(dataIndex) {
+  // 这里的 data 就是本文最初的代码块中声明的 data,在这里会被更新。
+  // 这里的 this 就是被拖拽的圆点。this.position 就是圆点当前的位置。
+  data[dataIndex] = myChart.convertFromPixel('grid', this.position);
+  // 用更新后的 data,重绘折线图。
+  myChart.setOption({
+    series: [
+      {
+        id: 'a',
+        data: data
+      }
+    ]
+  });
+}

上面的代码中,使用了 convertFromPixel 这个 API。它是 convertToPixel 的逆向过程。myChart.convertFromPixel('grid', this.position) 表示把当前像素坐标转换成 grid 组件中直角坐标系的 dataItem 值。

最后,为了使 dom 尺寸改变时,图中的元素能自适应得变化,加上这些代码:

window.addEventListener('resize', function() {
+  // 对每个拖拽圆点重新计算位置,并用 setOption 更新。
+  myChart.setOption({
+    graphic: echarts.util.map(data, function(item, dataIndex) {
+      return {
+        position: myChart.convertToPixel('grid', item)
+      };
+    })
+  });
+});

添加 tooltip 组件

到此,拖拽的基本功能就完成了。但是想要更进一步得实时看到拖拽过程中,被拖拽的点的 data 值的变化状况,我们可以使用 tooltip 组件来实时显示这个值。但是,tooltip 有其默认的“显示”“隐藏”触发规则,在我们拖拽的场景中并不适用,所以我们还要手动定制 tooltip 的“显示”“隐藏”行为。

在上述代码中分别添加如下定义:

myChart.setOption({
+  // ...,
+  tooltip: {
+    // 表示不使用默认的“显示”“隐藏”触发规则。
+    triggerOn: 'none',
+    formatter: function(params) {
+      return (
+        'X: ' +
+        params.data[0].toFixed(2) +
+        '<br>Y: ' +
+        params.data[1].toFixed(2)
+      );
+    }
+  }
+});
myChart.setOption({
+  graphic: data.map(function(item, dataIndex) {
+    return {
+      type: 'circle',
+      // ...,
+      // 在 mouseover 的时候显示,在 mouseout 的时候隐藏。
+      onmousemove: echarts.util.curry(showTooltip, dataIndex),
+      onmouseout: echarts.util.curry(hideTooltip, dataIndex)
+    };
+  })
+});
+
+function showTooltip(dataIndex) {
+  myChart.dispatchAction({
+    type: 'showTip',
+    seriesIndex: 0,
+    dataIndex: dataIndex
+  });
+}
+
+function hideTooltip(dataIndex) {
+  myChart.dispatchAction({
+    type: 'hideTip'
+  });
+}

这里使用了 dispatchAction 来显示隐藏 tooltip。用到了 showTiphideTip

全部代码

总结一下,全部的代码如下:

import echarts from 'echarts';
+
+var symbolSize = 20;
+var data = [
+  [15, 0],
+  [-50, 10],
+  [-56.5, 20],
+  [-46.5, 30],
+  [-22.1, 40]
+];
+var myChart = echarts.init(document.getElementById('main'));
+myChart.setOption({
+  tooltip: {
+    triggerOn: 'none',
+    formatter: function(params) {
+      return (
+        'X: ' +
+        params.data[0].toFixed(2) +
+        '<br />Y: ' +
+        params.data[1].toFixed(2)
+      );
+    }
+  },
+  xAxis: { min: -100, max: 80, type: 'value', axisLine: { onZero: false } },
+  yAxis: { min: -30, max: 60, type: 'value', axisLine: { onZero: false } },
+  series: [
+    { id: 'a', type: 'line', smooth: true, symbolSize: symbolSize, data: data }
+  ]
+});
+myChart.setOption({
+  graphic: echarts.util.map(data, function(item, dataIndex) {
+    return {
+      type: 'circle',
+      position: myChart.convertToPixel('grid', item),
+      shape: { r: symbolSize / 2 },
+      invisible: true,
+      draggable: true,
+      ondrag: echarts.util.curry(onPointDragging, dataIndex),
+      onmousemove: echarts.util.curry(showTooltip, dataIndex),
+      onmouseout: echarts.util.curry(hideTooltip, dataIndex),
+      z: 100
+    };
+  })
+});
+window.addEventListener('resize', function() {
+  myChart.setOption({
+    graphic: echarts.util.map(data, function(item, dataIndex) {
+      return { position: myChart.convertToPixel('grid', item) };
+    })
+  });
+});
+function showTooltip(dataIndex) {
+  myChart.dispatchAction({
+    type: 'showTip',
+    seriesIndex: 0,
+    dataIndex: dataIndex
+  });
+}
+function hideTooltip(dataIndex) {
+  myChart.dispatchAction({ type: 'hideTip' });
+}
+function onPointDragging(dataIndex, dx, dy) {
+  data[dataIndex] = myChart.convertFromPixel('grid', this.position);
+  myChart.setOption({
+    series: [
+      {
+        id: 'a',
+        data: data
+      }
+    ]
+  });
+}

有了这些基础,就可以定制更多的功能了。可以加 dataZoom 组件,可以制作一个直角坐标系上的绘图板等等。可以发挥想象力。

本文贡献者 在 GitHub 上编辑本页

Ovilia Oviliapissang pissang
+ + + + + diff --git a/docs/zh/how-to/label/rich-text/index.html b/docs/zh/how-to/label/rich-text/index.html new file mode 100644 index 000000000..5ebdfb7bc --- /dev/null +++ b/docs/zh/how-to/label/rich-text/index.html @@ -0,0 +1,664 @@ + + + + + + + 富文本标签 - 标签 - 应用篇 - 使用手册 - Apache ECharts + + +

富文本标签

Apache EChartsTM 中的文本标签从 v3.7 开始支持富文本模式,能够:

  • 定制文本块整体的样式(如背景、边框、阴影等)、位置、旋转等。
  • 对文本块中个别片段定义样式(如颜色、字体、高宽、背景、阴影等)、对齐方式等。
  • 在文本中使用图片做小图标或者背景。
  • 特定组合以上的规则,可以做出简单表格、分割线等效果。

开始下面的介绍之前,先说明一下下面会使用的两个名词的含义:

  • 文本块(Text Block):文本标签块整体。
  • 文本片段(Text fragment):文本标签块中的部分文本。

如下图示例:

文本样式相关的配置项

echarts 提供了丰富的文本标签配置项,包括:

  • 字体基本样式设置:fontStylefontWeightfontSizefontFamily
  • 文字颜色:color
  • 文字描边:textBorderColortextBorderWidth
  • 文字阴影:textShadowColortextShadowBlurtextShadowOffsetXtextShadowOffsetY
  • 文本块或文本片段大小:lineHeightwidthheightpadding
  • 文本块或文本片段的对齐:alignverticalAlign
  • 文本块或文本片段的边框、背景(颜色或图片):backgroundColorborderColorborderWidthborderRadius
  • 文本块或文本片段的阴影:shadowColorshadowBlurshadowOffsetXshadowOffsetY
  • 文本块的位置和旋转:positiondistancerotate

可以在各处的 rich 属性中定义文本片段样式。例如 series-bar.label.rich

例如:

labelOption = {
+  // 在文本中,可以对部分文本采用 rich 中定义样式。
+  // 这里需要在文本中使用标记符号:
+  // `{styleName|text content text content}` 标记样式名。
+  // 注意,换行仍是使用 '\n'。
+  formatter: [
+    '{a|这段文本采用样式a}',
+    '{b|这段文本采用样式b}这段用默认样式{x|这段用样式x}'
+  ].join('\n'),
+
+  // 这里是文本块的样式设置:
+  color: '#333',
+  fontSize: 5,
+  fontFamily: 'Arial',
+  borderWidth: 3,
+  backgroundColor: '#984455',
+  padding: [3, 10, 10, 5],
+  lineHeight: 20,
+
+  // rich 里是文本片段的样式设置:
+  rich: {
+    a: {
+      color: 'red',
+      lineHeight: 10
+    },
+    b: {
+      backgroundColor: {
+        image: 'xxx/xxx.jpg'
+      },
+      height: 40
+    },
+    x: {
+      fontSize: 18,
+      fontFamily: 'Microsoft YaHei',
+      borderColor: '#449933',
+      borderRadius: 4
+    }
+  }
+};

注意:如果不定义 rich,不能指定文字块的 widthheight

文本、文本框、文本片段的基本样式和装饰

每个文本可以设置基本的字体样式:fontStylefontWeightfontSizefontFamily

可以设置文字的颜色 color 和边框的颜色 textBorderColortextBorderWidth

文本框可以设置边框和背景的样式:borderColorborderWidthbackgroundColorpadding

文本片段也可以设置边框和背景的样式:borderColorborderWidthbackgroundColorpadding

例如:

option = {
+  series: [
+    {
+      type: 'scatter',
+      symbolSize: 1,
+      data: [
+        {
+          value: [0, 0],
+          label: {
+            show: true,
+            formatter: [
+              'Plain text',
+              '{textBorder|textBorderColor + textBorderWidth}',
+              '{textShadow|textShadowColor + textShadowBlur + textShadowOffsetX + textShadowOffsetY}',
+              '{bg|backgroundColor + borderRadius + padding}',
+              '{border|borderColor + borderWidth + borderRadius + padding}',
+              '{shadow|shadowColor + shadowBlur + shadowOffsetX + shadowOffsetY}'
+            ].join('\n'),
+            backgroundColor: '#eee',
+            borderColor: '#333',
+            borderWidth: 2,
+            borderRadius: 5,
+            padding: 10,
+            color: '#000',
+            fontSize: 14,
+            shadowBlur: 3,
+            shadowColor: '#888',
+            shadowOffsetX: 0,
+            shadowOffsetY: 3,
+            lineHeight: 30,
+            rich: {
+              textBorder: {
+                fontSize: 20,
+                textBorderColor: '#000',
+                textBorderWidth: 3,
+                color: '#fff'
+              },
+              textShadow: {
+                fontSize: 16,
+                textShadowBlur: 5,
+                textShadowColor: '#000',
+                textShadowOffsetX: 3,
+                textShadowOffsetY: 3,
+                color: '#fff'
+              },
+              bg: {
+                backgroundColor: '#339911',
+                color: '#fff',
+                borderRadius: 15,
+                padding: 5
+              },
+              border: {
+                color: '#000',
+                borderColor: '#449911',
+                borderWidth: 1,
+                borderRadius: 3,
+                padding: 5
+              },
+              shadow: {
+                backgroundColor: '#992233',
+                padding: 5,
+                color: '#fff',
+                shadowBlur: 5,
+                shadowColor: '#336699',
+                shadowOffsetX: 6,
+                shadowOffsetY: 6
+              }
+            }
+          }
+        }
+      ]
+    }
+  ],
+  xAxis: {
+    show: false,
+    min: -1,
+    max: 1
+  },
+  yAxis: {
+    show: false,
+    min: -1,
+    max: 1
+  }
+};
live

标签的位置

对于折线图、柱状图、散点图等,均可以使用 label 来设置标签。标签的相对于图形元素的位置,一般使用 label.positionlabel.distance 来配置。

试试在下面例子中修改positiondistance 属性:

option = {
+  series: [
+    {
+      type: 'scatter',
+      symbolSize: 160,
+      symbol: 'roundRect',
+      data: [[1, 1]],
+      label: {
+        // 修改 position 和 distance 的值试试
+        // 支持:'left', 'right', 'top', 'bottom', 'inside', 'insideTop', 'insideLeft', 'insideRight', 'insideBottom', 'insideTopLeft', 'insideTopRight', 'insideBottomLeft', 'insideBottomRight'
+        position: 'top',
+        distance: 10,
+
+        show: true,
+        formatter: ['Label Text'].join('\n'),
+        backgroundColor: '#eee',
+        borderColor: '#555',
+        borderWidth: 2,
+        borderRadius: 5,
+        padding: 10,
+        fontSize: 18,
+        shadowBlur: 3,
+        shadowColor: '#888',
+        shadowOffsetX: 0,
+        shadowOffsetY: 3,
+        textBorderColor: '#000',
+        textBorderWidth: 3,
+        color: '#fff'
+      }
+    }
+  ],
+  xAxis: {
+    max: 2
+  },
+  yAxis: {
+    max: 2
+  }
+};
live

注意:position 在不同的图中可取值有所不同。distance 并不是在每个图中都支持。详情请参见 option 文档

标签的旋转

某些图中,为了能有足够长的空间来显示标签,需要对标签进行旋转。例如:

const labelOption = {
+  show: true,
+  rotate: 90,
+  formatter: '{c}  {name|{a}}',
+  fontSize: 16,
+  rich: {
+    name: {}
+  }
+};
+
+option = {
+  xAxis: [
+    {
+      type: 'category',
+      data: ['2012', '2013', '2014', '2015', '2016']
+    }
+  ],
+  yAxis: [
+    {
+      type: 'value'
+    }
+  ],
+  series: [
+    {
+      name: 'Forest',
+      type: 'bar',
+      barGap: 0,
+      label: labelOption,
+      emphasis: {
+        focus: 'series'
+      },
+      data: [320, 332, 301, 334, 390]
+    },
+    {
+      name: 'Steppe',
+      type: 'bar',
+      label: labelOption,
+      emphasis: {
+        focus: 'series'
+      },
+      data: [220, 182, 191, 234, 290]
+    }
+  ]
+};
live

这种场景下,可以结合 alignverticalAlign 来调整标签位置。

注意,逻辑是,先使用 alignverticalAlign 定位,再旋转。

文本片段的排版和对齐

关于排版方式,每个文本片段,可以想象成 CSS 中的 inline-block,在文档流中按行放置。

每个文本片段的内容盒尺寸(content box size),默认是根据文字大小决定的。但是,也可以设置 widthheight 来强制指定,虽然一般不会这么做(参见下文)。文本片段的边框盒尺寸(border box size),由上述本身尺寸,加上文本片段的 padding 来得到。

只有 '\n' 是换行符,能导致换行。

一行内,会有多个文本片段。每行的实际高度,由 lineHeight 最大的文本片段决定。文本片段的 lineHeight 可直接在 rich 中指定,也可以在 rich 的父层级中统一指定而采用到 rich 的所有项中,如果都不指定,则取文本片段的边框盒尺寸(border box size)。

在一行的 lineHeight 被决定后,一行内,文本片段的竖直位置,由文本片段的 verticalAlign 来指定(这里和 CSS 中的规则稍有不同):

  • 'bottom':文本片段的盒的底边贴住行底。
  • 'top':文本片段的盒的顶边贴住行顶。
  • 'middle':居行中。

文本块的宽度,可以直接由文本块的 width 指定,否则,由最长的行决定。宽度决定后,在一行中进行文本片段的放置。文本片段的 align 决定了文本片段在行中的水平位置:

  • 首先,从左向右连续紧靠放置 align'left' 的文本片段盒。
  • 然后,从右向左连续紧靠放置 align'right' 的文本片段盒。
  • 最后,剩余的没处理的文本片段盒,紧贴着,在中间剩余的区域中居中放置。

关于文字在文本片段盒中的位置:

  • 如果 align'center',则文字在文本片段盒中是居中的。
  • 如果 align'left',则文字在文本片段盒中是居左的。
  • 如果 align'right',则文字在文本片段盒中是居右的。

特殊效果:图标、分割线、标题块、简单表格

看下面的例子:

option = {
+  series: [
+    {
+      type: 'scatter',
+      data: [
+        {
+          value: [0, 0],
+          label: {
+            formatter: [
+              '{tc|Center Title}{titleBg|}',
+              '  Content text xxxxxxxx {sunny|} xxxxxxxx {cloudy|}  ',
+              '{hr|}',
+              '  xxxxx {showers|} xxxxxxxx  xxxxxxxxx  '
+            ].join('\n'),
+            rich: {
+              titleBg: {
+                align: 'right'
+              }
+            }
+          }
+        },
+        {
+          value: [0, 1],
+          label: {
+            formatter: [
+              '{titleBg|Left Title}',
+              '  Content text xxxxxxxx {sunny|} xxxxxxxx {cloudy|}  ',
+              '{hr|}',
+              '  xxxxx {showers|} xxxxxxxx  xxxxxxxxx  '
+            ].join('\n')
+          }
+        },
+        {
+          value: [0, 2],
+          label: {
+            formatter: [
+              '{titleBg|Right Title}',
+              '  Content text xxxxxxxx {sunny|} xxxxxxxx {cloudy|}  ',
+              '{hr|}',
+              '  xxxxx {showers|} xxxxxxxx  xxxxxxxxx  '
+            ].join('\n'),
+            rich: {
+              titleBg: {
+                align: 'right'
+              }
+            }
+          }
+        }
+      ],
+      symbolSize: 1,
+      label: {
+        show: true,
+        backgroundColor: '#ddd',
+        borderColor: '#555',
+        borderWidth: 1,
+        borderRadius: 5,
+        color: '#000',
+        fontSize: 14,
+        rich: {
+          titleBg: {
+            backgroundColor: '#000',
+            height: 30,
+            borderRadius: [5, 5, 0, 0],
+            padding: [0, 10, 0, 10],
+            width: '100%',
+            color: '#eee'
+          },
+          tc: {
+            align: 'center',
+            color: '#eee'
+          },
+          hr: {
+            borderColor: '#777',
+            width: '100%',
+            borderWidth: 0.5,
+            height: 0
+          },
+          sunny: {
+            height: 30,
+            align: 'left',
+            backgroundColor: {
+              image:
+                'https://echarts.apache.org/examples/data/asset/img/weather/sunny_128.png'
+            }
+          },
+          cloudy: {
+            height: 30,
+            align: 'left',
+            backgroundColor: {
+              image:
+                'https://echarts.apache.org/examples/data/asset/img/weather/cloudy_128.png'
+            }
+          },
+          showers: {
+            height: 30,
+            align: 'left',
+            backgroundColor: {
+              image:
+                'https://echarts.apache.org/examples/data/asset/img/weather/showers_128.png'
+            }
+          }
+        }
+      }
+    }
+  ],
+  xAxis: {
+    show: false,
+    min: -1,
+    max: 1
+  },
+  yAxis: {
+    show: false,
+    min: 0,
+    max: 2,
+    inverse: true
+  }
+};
live

文本片段的 backgroundColor 可以指定为图片后,就可以在文本中使用图标了:

labelOption = {
+  rich: {
+    Sunny: {
+      // 这样设定 backgroundColor 就可以是图片了。
+      backgroundColor: {
+        image: './data/asset/img/weather/sunny_128.png'
+      },
+      // 可以只指定图片的高度,从而图片的宽度根据图片的长宽比自动得到。
+      height: 30
+    }
+  }
+};

分割线实际是用 border 实现的:

labelOption = {
+  rich: {
+    hr: {
+      borderColor: '#777',
+      // 这里把 width 设置为 '100%',表示分割线的长度充满文本块。
+      // 注意,这里是文本块内容盒(content box)的 100%,而不包含 padding。
+      // 虽然这和 CSS 相关的定义有所不同,但是在这类场景中更加方便。
+      width: '100%',
+      borderWidth: 0.5,
+      height: 0
+    }
+  }
+};

标题块是使用 backgroundColor 实现的:

labelOption = {
+  // 标题文字居左
+  formatter: '{titleBg|Left Title}',
+  rich: {
+    titleBg: {
+      backgroundColor: '#000',
+      height: 30,
+      borderRadius: [5, 5, 0, 0],
+      padding: [0, 10, 0, 10],
+      width: '100%',
+      color: '#eee'
+    }
+  }
+};
+
+// 标题文字居中。
+// 这个实现有些 tricky,但是,能够不引入更复杂的排版规则而实现这个效果。
+labelOption = {
+  formatter: '{tc|Center Title}{titleBg|}',
+  rich: {
+    titleBg: {
+      align: 'right',
+      backgroundColor: '#000',
+      height: 30,
+      borderRadius: [5, 5, 0, 0],
+      padding: [0, 10, 0, 10],
+      width: '100%',
+      color: '#eee'
+    }
+  }
+};

简单表格的设定,其实就是给不同行上纵向对应的文本片段设定同样的宽度就可以了。见 该例子

本文贡献者 在 GitHub 上编辑本页

plainheart plainheartpissang pissang
+ + + + + diff --git a/docs/zh/index.html b/docs/zh/index.html new file mode 100644 index 000000000..fc8810ad3 --- /dev/null +++ b/docs/zh/index.html @@ -0,0 +1,15 @@ + + + + + + + 使用手册 - Apache ECharts + + + + + + + + diff --git a/docs/zh/meta/edit-guide/index.html b/docs/zh/meta/edit-guide/index.html new file mode 100644 index 000000000..48736be4c --- /dev/null +++ b/docs/zh/meta/edit-guide/index.html @@ -0,0 +1,185 @@ + + + + + + + 文档编辑指南 - 编辑本文档 - 使用手册 - Apache ECharts + + +

文档编辑指南

新增一个 markdown 文件

contents/zh/(中文文章)或 contents/en/(英文文章)目录下新增一个 markdown 文件,最多支持三级目录。将路径及标题信息更新在 contents/zh/posts.ymlcontents/en/posts.yml

markdown 文件名称小写。

使用 prettier 来自动格式化代码

在开始之前,我们推荐安装prettierVSCode 插件,该插件可以在你保存的时候自动帮你格式化代码。

如果你觉得自动的格式化破坏了你的代码块,你可以在在代码块外面加上下面代码阻止prettier格式化该部分代码

<!-- prettier-ignore-start -->
+<!-- prettier-ignore-end -->

如果你发现有的代码块并没有被格式化,请先检查该代码是否存在语法上的错误。

内置变量

  • optionPath
  • mainSitePath
  • exampleViewPath
  • exampleEditorPath
  • lang

使用方式:

${xxxxx}
+

引用其它文章

[获取 Apache ECharts](${lang}/basics/download)

获取 Apache ECharts

引用代码

基础使用

```js
+option = {
+    series: [{
+        type: 'bar',
+        data: [23, 24, 18, 25, 27, 28, 25]
+    }]
+};
+\```
option = {
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};

代码推荐写法

为了可以让工具帮助我们对代码进行格式化,我们应该尽量避免有语法问题的写法。

比如注释 ...

option = {
+  series: [
+    {
+      type: 'bar'
+      // ...
+    }
+  ]
+};

实时预览和编辑

目前只支持对 Option 代码的预览

\```js live
+option = {
+  xAxis: {
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};
+\```
option = {
+  xAxis: {
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};
live

更多预览布局

左右

\```js live {layout: 'lr'}
+option = {
+  ...
+};
+\```
option = {
+  xAxis: {
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};
live

右左

\```js live {layout: 'rl'}
+option = {
+  ...
+};
+\```
option = {
+  xAxis: {
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};
live

下上

\```js live {layout: 'bt'}
+option = {
+  ...
+};
+\```
option = {
+  xAxis: {
+    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+  },
+  yAxis: {},
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};
live

高亮代码行

使用:

\```js {1,3-5}
+option = {
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};
+\```

效果:

option = {
+  series: [
+    {
+      type: 'bar',
+      data: [23, 24, 18, 25, 27, 28, 25]
+    }
+  ]
+};

引用图片

图片实际存放地址在 static/images/ 下。

![图片说明](images/demo.png)

设置图片高宽

对于当前页面的临时样式,可以直接写 html:

<img data-src="images/demo.png" style="width: 50px" />

添加示例 iframe

srchttps://echarts.apache.org/examples/zh/editor.html?c=line-simple 地址中?c=后面这一串

使用:

<md-example src="doc-example/getting-started" width="100%" height="300" />

效果: +

添加配置项链接

使用:

<md-option link="series-bar.itemStyle.color" />

效果: +series-bar.itemStyle.color

更多组件使用

文档支持使用全局注册的markdown组件,除了刚才介绍的md-example组件,还有下面几种组件

md-alert

提示组件

<md-alert type="info">
+This is an info alert.
+</md-alert>

+This is an info alert. +

<md-alert type="success">
+This is a success alert.
+</md-alert>

+This is a success alert. +

<md-alert type="warning">
+This is a warning alert.
+</md-alert>

+This is a warning alert. +

<md-alert type="danger">
+This is a danger alert.
+</md-alert>

+This is a danger alert. +

本文贡献者 在 GitHub 上编辑本页

pissang pissangsuisuiz suisuiz
+ + + + +