You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by sh...@apache.org on 2020/06/18 06:42:25 UTC
[incubator-echarts-doc] branch live-example updated: example: add
more UI config, support custom symbol upload
This is an automated email from the ASF dual-hosted git repository.
shenyi pushed a commit to branch live-example
in repository https://gitbox.apache.org/repos/asf/incubator-echarts-doc.git
The following commit(s) were added to refs/heads/live-example by this push:
new 1335a40 example: add more UI config, support custom symbol upload
1335a40 is described below
commit 1335a408dd7ec785e26b2b196d083324380c2b4d
Author: pissang <bm...@gmail.com>
AuthorDate: Thu Jun 18 14:42:07 2020 +0800
example: add more UI config, support custom symbol upload
---
en/option/component/radar.md | 4 -
src/components/OptionControl.vue | 5 +-
src/controls/ControlIcon.vue | 108 +++
src/dep/flatten.js | 1175 +++++++++++++++++++++++++++++++
src/i18n.js | 6 +
tool/md2json.js | 5 +-
zh/option/component/angle-axis.md | 71 ++
zh/option/component/axis-common.md | 2 +-
zh/option/component/data-zoom-inside.md | 48 +-
zh/option/component/data-zoom-slider.md | 51 +-
zh/option/component/data-zoom.md | 21 +-
zh/option/component/legend.md | 4 +
zh/option/component/radar.md | 54 +-
zh/option/partial/symbol.md | 4 +-
zh/option/series/pie.md | 23 +-
zh/option/series/radar.md | 18 +-
16 files changed, 1545 insertions(+), 54 deletions(-)
diff --git a/en/option/component/radar.md b/en/option/component/radar.md
index 540a3c3..9960c9a 100644
--- a/en/option/component/radar.md
+++ b/en/option/component/radar.md
@@ -53,10 +53,6 @@ formatter: function (value, indicator) {
Distance between the indicator's name and axis.
-## axisType(string) = 'value'
-{{ use: partial-version(version = "4.5.0") }}
-{{ use: partial-axis-type-content() }}
-
## splitNumber(number) = 5
Segments of indicator axis.
diff --git a/src/components/OptionControl.vue b/src/components/OptionControl.vue
index 27ffd81..c6a85d8 100644
--- a/src/components/OptionControl.vue
+++ b/src/components/OptionControl.vue
@@ -19,6 +19,8 @@ import ControlPercent from '../controls/ControlPercent.vue';
import {store, changeOption} from '../store';
import ControlPercentVector from '../controls/ControlPercentVector.vue';
import ControlText from '../controls/ControlText.vue';
+import ControlIcon from '../controls/ControlIcon.vue';
+
const uiComponentMap = {
boolean: ControlBoolean,
@@ -30,7 +32,8 @@ const uiComponentMap = {
angle: ControlNumber,
percent: ControlPercent,
percentvector: ControlPercentVector,
- text: ControlText
+ text: ControlText,
+ icon: ControlIcon
};
const uiComponentDefault = {
diff --git a/src/controls/ControlIcon.vue b/src/controls/ControlIcon.vue
new file mode 100644
index 0000000..473a574
--- /dev/null
+++ b/src/controls/ControlIcon.vue
@@ -0,0 +1,108 @@
+<template>
+<div class="control-icon">
+ <el-select size="mini" v-model="innerValue" @change="onValueChange">
+ <el-option v-for="item in optionsArr"
+ :key="item"
+ :value="item"
+ >{{item}}</el-option>
+ </el-select>
+ <el-button size="mini" type="primary" @click="chooseFile">{{$t('example.upload')}}</el-button>
+</div>
+</template>
+
+<script>
+
+import {flatten} from '../dep/flatten';
+
+export function parseXML(svgStr) {
+ const parser = new DOMParser();
+ const svg = parser.parseFromString(svgStr, 'text/xml');
+ let svgNode = svg;
+ // Document node. If using $.get, doc node may be input.
+ if (svgNode.nodeType === 9) {
+ svgNode = svgNode.firstChild;
+ }
+ // nodeName of <!DOCTYPE svg> is also 'svg'.
+ while (svgNode.nodeName.toLowerCase() !== 'svg' || svgNode.nodeType !== 1) {
+ svgNode = svgNode.nextSibling;
+ }
+
+ return svgNode;
+}
+
+export default {
+
+ props: ['value'],
+
+ computed: {
+ optionsArr() {
+ return ['circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow', 'none']
+ },
+ },
+
+ data() {
+ return {
+ innerValue: this.value
+ }
+ },
+
+ watch: {
+ value(val) {
+ this.innerValue = val;
+ }
+ },
+
+ methods: {
+ onValueChange() {
+ this.$emit('change', this.innerValue);
+ },
+ chooseFile() {
+ const input = document.createElement('input');
+ input.type = 'file';
+ input.accept= '.jpg, .jpeg, .png, .svg'
+ input.addEventListener('change', (e) => {
+ const file = e.target.files[0];
+ if (!file) {
+ return;
+ }
+ if (file.name.endsWith('.svg')) {
+ // read path
+ // Use image
+ const fileReader = new FileReader();
+ fileReader.addEventListener('load', () => {
+ const svgStr = fileReader.result;
+ const svg = parseXML(svgStr);
+ try {
+ flatten(svg);
+ }
+ catch (e) {
+ console.error('Unexpected error happens when handling the SVG.');
+ console.error(e.toString());
+ }
+
+ const paths = svg.querySelectorAll('path');
+ let defs = [];
+ for (let i = 0; i < paths.length; i++) {
+ defs.push(paths[i].getAttribute('d'));
+ }
+ this.$emit('change', 'path://' + defs.join(' '));
+ });
+ fileReader.readAsText(file);
+ }
+ else {
+ // Use image
+ const fileReader = new FileReader();
+ fileReader.addEventListener('load', () => {
+ this.$emit('change', 'image://' + fileReader.result);
+ });
+ fileReader.readAsDataURL(file);
+ }
+ });
+ input.click();
+ }
+ }
+}
+</script>
+
+<style lang="scss">
+</style>
\ No newline at end of file
diff --git a/src/dep/flatten.js b/src/dep/flatten.js
new file mode 100644
index 0000000..2357a78
--- /dev/null
+++ b/src/dep/flatten.js
@@ -0,0 +1,1175 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2014 Timo (https://github.com/timo22345)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/*
+Usage example: http://jsfiddle.net/Nv78L/1/embedded/result/
+
+Basic usage: flatten(document.getElementById('svg'));
+
+What it does: Flattens elements (converts elements to paths and flattens transformations).
+If the argument element (whose id is above 'svg') has children, or it's descendants has children,
+these children elements are flattened also.
+
+If you want to modify path coordinates using non-affine methods (eg. perspective distort),
+you can convert all segments to cubic curves using:
+
+flatten(document.getElementById('svg'), true);
+
+There are also arguments 'toAbsolute' (convert coordinates to absolute) and 'dec',
+number of digits after decimal separator.
+*/
+
+
+SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement || function(toElement) {
+ return toElement.getScreenCTM().inverse().multiply(this.getScreenCTM());
+};
+ var p2s = /,?([achlmqrstvxz]),?/gi;
+ var convertToString = function (arr)
+ {
+ return arr.join(',').replace(p2s, '$1');
+ };
+
+ // Flattens transformations of element or it's children and sub-children
+ // elem: DOM element
+ // toCubics: converts all segments to cubics
+ // toAbsolute: converts all segments to Absolute
+ // dec: number of digits after decimal separator
+ // Returns: no return value
+export function flatten(elem, toCubics, toAbsolute, rectAsArgs, dec)
+ {
+ if (!elem) return;
+ if (typeof (rectAsArgs) == 'undefined') rectAsArgs = false;
+ if (typeof (toCubics) == 'undefined') toCubics = false;
+ if (typeof (toAbsolute) == 'undefined') toAbsolute = false;
+ if (typeof (dec) == 'undefined') dec = false;
+
+ if (elem && elem.children && elem.children.length)
+ {
+ for (var i = 0, ilen = elem.children.length; i < ilen; i++)
+ {
+ //console.log(elem.children[i]);
+ flatten(elem.children[i], toCubics, toAbsolute, rectAsArgs, dec);
+ }
+ elem.removeAttribute('transform');
+ return;
+ }
+ if (!(elem instanceof SVGCircleElement ||
+ elem instanceof SVGRectElement ||
+ elem instanceof SVGEllipseElement ||
+ elem instanceof SVGLineElement ||
+ elem instanceof SVGPolygonElement ||
+ elem instanceof SVGPolylineElement ||
+ elem instanceof SVGPathElement)) return;
+
+ var path_elem = convertToPath(elem, rectAsArgs);
+ //console.log('path_elem', $(path_elem).wrap('<div />').parent().html() );
+ //$(path_elem).unwrap();
+
+ if (!path_elem || path_elem.getAttribute(d) == '') return 'M 0 0';
+
+ // Rounding coordinates to dec decimals
+ if (dec || dec === 0)
+ {
+ if (dec > 15) dec = 15;
+ else if (dec < 0) dec = 0;
+ }
+ else dec = false;
+
+ function r(num)
+ {
+ if (dec !== false) return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
+ else return num;
+ }
+
+ var arr;
+ //var pathDOM = path_elem.node;
+ var pathDOM = path_elem;
+ var d = pathDOM.getAttribute('d').trim();
+
+ // If you want to retain current path commans, set toCubics to false
+ if (!toCubics)
+ { // Set to false to prevent possible re-normalization.
+ arr = parsePathString(d); // str to array
+ var arr_orig = arr;
+ arr = pathToAbsolute(arr); // mahvstcsqz -> uppercase
+ }
+ // If you want to modify path data using nonAffine methods,
+ // set toCubics to true
+ else
+ {
+ arr = path2curve(d); // mahvstcsqz -> MC
+ var arr_orig = arr;
+ }
+ var svgDOM = pathDOM.ownerSVGElement;
+
+ // Get the relation matrix that converts path coordinates
+ // to SVGroot's coordinate space
+ var matrix = pathDOM.getTransformToElement(svgDOM);
+
+ // The following code can bake transformations
+ // both normalized and non-normalized data
+ // Coordinates have to be Absolute in the following
+ var i = 0,
+ j, m = arr.length,
+ letter = '',
+ letter_orig = '',
+ x = 0,
+ y = 0,
+ point, newcoords = [],
+ newcoords_orig = [],
+ pt = svgDOM.createSVGPoint(),
+ subpath_start = {}, prevX = 0,
+ prevY = 0;
+ subpath_start.x = null;
+ subpath_start.y = null;
+ for (; i < m; i++)
+ {
+ letter = arr[i][0].toUpperCase();
+ letter_orig = arr_orig[i][0];
+ newcoords[i] = [];
+ newcoords[i][0] = arr[i][0];
+
+ if (letter == 'A')
+ {
+ x = arr[i][6];
+ y = arr[i][7];
+
+ pt.x = arr[i][6];
+ pt.y = arr[i][7];
+ newcoords[i] = arc_transform(arr[i][1], arr[i][2], arr[i][3], arr[i][4], arr[i][5], pt, matrix);
+ // rounding arc parameters
+ // x,y are rounded normally
+ // other parameters at least to 5 decimals
+ // because they affect more than x,y rounding
+ newcoords[i][1] = newcoords[i][1]; //rx
+ newcoords[i][2] = newcoords[i][2]; //ry
+ newcoords[i][3] = newcoords[i][3]; //x-axis-rotation
+ newcoords[i][6] = newcoords[i][6]; //x
+ newcoords[i][7] = newcoords[i][7]; //y
+ }
+ else if (letter != 'Z')
+ {
+ // parse other segs than Z and A
+ for (j = 1; j < arr[i].length; j = j + 2)
+ {
+ if (letter == 'V') y = arr[i][j];
+ else if (letter == 'H') x = arr[i][j];
+ else
+ {
+ x = arr[i][j];
+ y = arr[i][j + 1];
+ }
+ pt.x = x;
+ pt.y = y;
+ point = pt.matrixTransform(matrix);
+
+ if (letter == 'V' || letter == 'H')
+ {
+ newcoords[i][0] = 'L';
+ newcoords[i][j] = point.x;
+ newcoords[i][j + 1] = point.y;
+ }
+ else
+ {
+ newcoords[i][j] = point.x;
+ newcoords[i][j + 1] = point.y;
+ }
+ }
+ }
+ if ((letter != 'Z' && subpath_start.x === null) || letter == 'M')
+ {
+ subpath_start.x = x;
+ subpath_start.y = y;
+ }
+ if (letter == 'Z')
+ {
+ x = subpath_start.x;
+ y = subpath_start.y;
+ }
+ }
+ // Convert all that was relative back to relative
+ // This could be combined to above, but to make code more readable
+ // this is made separately.
+ var prevXtmp = 0;
+ var prevYtmp = 0;
+ subpath_start.x = '';
+ for (i = 0; i < newcoords.length; i++)
+ {
+ letter_orig = arr_orig[i][0];
+ if (letter_orig == 'A' || letter_orig == 'M' || letter_orig == 'L' || letter_orig == 'C' || letter_orig == 'S' || letter_orig == 'Q' || letter_orig == 'T' || letter_orig == 'H' || letter_orig == 'V')
+ {
+ var len = newcoords[i].length;
+ var lentmp = len;
+ if (letter_orig == 'A')
+ {
+ newcoords[i][6] = r(newcoords[i][6]);
+ newcoords[i][7] = r(newcoords[i][7]);
+ }
+ else
+ {
+ lentmp--;
+ while (--lentmp) newcoords[i][lentmp] = r(newcoords[i][lentmp]);
+ }
+ prevX = newcoords[i][len - 2];
+ prevY = newcoords[i][len - 1];
+ }
+ else
+ if (letter_orig == 'a')
+ {
+ prevXtmp = newcoords[i][6];
+ prevYtmp = newcoords[i][7];
+ newcoords[i][0] = letter_orig;
+ newcoords[i][6] = r(newcoords[i][6] - prevX);
+ newcoords[i][7] = r(newcoords[i][7] - prevY);
+ prevX = prevXtmp;
+ prevY = prevYtmp;
+ }
+ else
+ if (letter_orig == 'm' || letter_orig == 'l' || letter_orig == 'c' || letter_orig == 's' || letter_orig == 'q' || letter_orig == 't' || letter_orig == 'h' || letter_orig == 'v')
+ {
+ var len = newcoords[i].length;
+ prevXtmp = newcoords[i][len - 2];
+ prevYtmp = newcoords[i][len - 1];
+ for (j = 1; j < len; j = j + 2)
+ {
+ if (letter_orig == 'h' || letter_orig == 'v')
+ newcoords[i][0] = 'l';
+ else newcoords[i][0] = letter_orig;
+ newcoords[i][j] = r(newcoords[i][j] - prevX);
+ newcoords[i][j + 1] = r(newcoords[i][j + 1] - prevY);
+ }
+ prevX = prevXtmp;
+ prevY = prevYtmp;
+ }
+ if ((letter_orig.toLowerCase() != 'z' && subpath_start.x == '') || letter_orig.toLowerCase() == 'm')
+ {
+ subpath_start.x = prevX;
+ subpath_start.y = prevY;
+ }
+ if (letter_orig.toLowerCase() == 'z')
+ {
+ prevX = subpath_start.x;
+ prevY = subpath_start.y;
+ }
+ }
+ if (toAbsolute) newcoords = pathToAbsolute(newcoords);
+ path_elem.setAttribute('d', convertToString(newcoords));
+ path_elem.removeAttribute('transform');
+ }
+
+ // Converts all shapes to path retaining attributes.
+ // oldElem - DOM element to be replaced by path. Can be one of the following:
+ // ellipse, circle, path, line, polyline, polygon and rect.
+ // rectAsArgs - Boolean. If true, rect roundings will be as arcs. Otherwise as cubics.
+ // Return value: path element.
+ // Source: https://github.com/duopixel/Method-Draw/blob/master/editor/src/svgcanvas.js
+ // Modifications: Timo (https://github.com/timo22345)
+ function convertToPath(oldElem, rectAsArgs)
+ {
+ if (!oldElem) return;
+ // Create new path element
+ var path = document.createElementNS(oldElem.ownerSVGElement.namespaceURI, 'path');
+
+ // All attributes that path element can have
+ var attrs = ['requiredFeatures', 'requiredExtensions', 'systemLanguage', 'id', 'xml:base', 'xml:lang', 'xml:space', 'onfocusin', 'onfocusout', 'onactivate', 'onclick', 'onmousedown', 'onmouseup', 'onmouseover', 'onmousemove', 'onmouseout', 'onload', 'alignment-baseline', 'baseline-shift', 'clip', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cursor', 'direction', 'display', 'dominant-baseline', 'enable-ba [...]
+
+ // Copy attributes of oldElem to path
+ var attrName, attrValue;
+ for (var i = 0, ilen = attrs.length; i < ilen; i++)
+ {
+ var attrName = attrs[i];
+ var attrValue = oldElem.getAttribute(attrName);
+ if (attrValue) path.setAttribute(attrName, attrValue);
+ }
+
+ var d = '';
+
+ var valid = function (val)
+ {
+ return !(typeof (val) !== 'number' || val == Infinity || val < 0);
+ }
+
+ // Possibly the cubed root of 6, but 1.81 works best
+ var num = 1.81;
+ var tag = oldElem.tagName;
+ switch (tag)
+ {
+ case 'ellipse':
+ case 'circle':
+ var rx = +oldElem.getAttribute('rx'),
+ ry = +oldElem.getAttribute('ry'),
+ cx = +oldElem.getAttribute('cx'),
+ cy = +oldElem.getAttribute('cy');
+ if (tag == 'circle')
+ {
+ rx = ry = +oldElem.getAttribute('r');
+ }
+
+ d += convertToString([
+ ['M', (cx - rx), (cy)],
+ ['C', (cx - rx), (cy - ry / num), (cx - rx / num), (cy - ry), (cx), (cy - ry)],
+ ['C', (cx + rx / num), (cy - ry), (cx + rx), (cy - ry / num), (cx + rx), (cy)],
+ ['C', (cx + rx), (cy + ry / num), (cx + rx / num), (cy + ry), (cx), (cy + ry)],
+ ['C', (cx - rx / num), (cy + ry), (cx - rx), (cy + ry / num), (cx - rx), (cy)],
+ ['Z']
+ ]);
+ break;
+ case 'path':
+ d = oldElem.getAttribute('d');
+ break;
+ case 'line':
+ var x1 = oldElem.getAttribute('x1'),
+ y1 = oldElem.getAttribute('y1');
+ x2 = oldElem.getAttribute('x2');
+ y2 = oldElem.getAttribute('y2');
+ d = 'M' + x1 + ',' + y1 + 'L' + x2 + ',' + y2;
+ break;
+ case 'polyline':
+ d = 'M' + oldElem.getAttribute('points');
+ break;
+ case 'polygon':
+ d = 'M' + oldElem.getAttribute('points') + 'Z';
+ break;
+ case 'rect':
+ var rx = +oldElem.getAttribute('rx'),
+ ry = +oldElem.getAttribute('ry'),
+ b = oldElem.getBBox(),
+ x = b.x,
+ y = b.y,
+ w = b.width,
+ h = b.height;
+
+ // Validity checks from http://www.w3.org/TR/SVG/shapes.html#RectElement:
+ // If neither ‘rx’ nor ‘ry’ are properly specified, then set both rx and ry to 0. (This will result in square corners.)
+ if (!valid(rx) && !valid(ry)) rx = ry = 0;
+ // Otherwise, if a properly specified value is provided for ‘rx’, but not for ‘ry’, then set both rx and ry to the value of ‘rx’.
+ else if (valid(rx) && !valid(ry)) ry = rx;
+ // Otherwise, if a properly specified value is provided for ‘ry’, but not for ‘rx’, then set both rx and ry to the value of ‘ry’.
+ else if (valid(ry) && !valid(rx)) rx = ry;
+ else
+ {
+ // If rx is greater than half of ‘width’, then set rx to half of ‘width’.
+ if (rx > w / 2) rx = w / 2;
+ // If ry is greater than half of ‘height’, then set ry to half of ‘height’.
+ if (ry > h / 2) ry = h / 2;
+ }
+
+ if (!rx && !ry)
+ {
+ d += convertToString([
+ ['M', x, y],
+ ['L', x + w, y],
+ ['L', x + w, y + h],
+ ['L', x, y + h],
+ ['L', x, y],
+ ['Z']
+ ]);
+ }
+ else if (rectAsArgs)
+ {
+ d += convertToString([
+ ['M', x + rx, y],
+ ['H', x + w - rx],
+ ['A', rx, ry, 0, 0, 1, x + w, y + ry],
+ ['V', y + h - ry],
+ ['A', rx, ry, 0, 0, 1, x + w - rx, y + h],
+ ['H', x + rx],
+ ['A', rx, ry, 0, 0, 1, x, y + h - ry],
+ ['V', y + ry],
+ ['A', rx, ry, 0, 0, 1, x + rx, y]
+ ]);
+ }
+ else
+ {
+ var num = 2.19;
+ if (!ry) ry = rx
+ d += convertToString([
+ ['M', x, y + ry],
+ ['C', x, y + ry / num, x + rx / num, y, x + rx, y],
+ ['L', x + w - rx, y],
+ ['C', x + w - rx / num, y, x + w, y + ry / num, x + w, y + ry],
+ ['L', x + w, y + h - ry],
+ ['C', x + w, y + h - ry / num, x + w - rx / num, y + h, x + w - rx, y + h],
+ ['L', x + rx, y + h],
+ ['C', x + rx / num, y + h, x, y + h - ry / num, x, y + h - ry],
+ ['L', x, y + ry],
+ ['Z']
+ ]);
+ }
+ break;
+ default:
+ //path.parentNode.removeChild(path);
+ break;
+ }
+
+ if (d) path.setAttribute('d', d);
+
+ // Replace the current element with the converted one
+ oldElem.parentNode.replaceChild(path, oldElem);
+ return path;
+ };
+
+ // This is needed to flatten transformations of elliptical arcs
+ // Note! This is not needed if Raphael.path2curve is used
+ function arc_transform(a_rh, a_rv, a_offsetrot, large_arc_flag, sweep_flag, endpoint, matrix, svgDOM)
+ {
+ function NEARZERO(B)
+ {
+ if (Math.abs(B) < 0.0000000000000001) return true;
+ else return false;
+ }
+
+ var rh, rv, rot;
+
+ var m = []; // matrix representation of transformed ellipse
+ var s, c; // sin and cos helpers (the former offset rotation)
+ var A, B, C; // ellipse implicit equation:
+ var ac, A2, C2; // helpers for angle and halfaxis-extraction.
+ rh = a_rh;
+ rv = a_rv;
+
+ a_offsetrot = a_offsetrot * (Math.PI / 180); // deg->rad
+ rot = a_offsetrot;
+
+ s = parseFloat(Math.sin(rot));
+ c = parseFloat(Math.cos(rot));
+
+ // build ellipse representation matrix (unit circle transformation).
+ // the 2x2 matrix multiplication with the upper 2x2 of a_mat is inlined.
+ m[0] = matrix.a * +rh * c + matrix.c * rh * s;
+ m[1] = matrix.b * +rh * c + matrix.d * rh * s;
+ m[2] = matrix.a * -rv * s + matrix.c * rv * c;
+ m[3] = matrix.b * -rv * s + matrix.d * rv * c;
+
+ // to implict equation (centered)
+ A = (m[0] * m[0]) + (m[2] * m[2]);
+ C = (m[1] * m[1]) + (m[3] * m[3]);
+ B = (m[0] * m[1] + m[2] * m[3]) * 2.0;
+
+ // precalculate distance A to C
+ ac = A - C;
+
+ // convert implicit equation to angle and halfaxis:
+ if (NEARZERO(B))
+ {
+ a_offsetrot = 0;
+ A2 = A;
+ C2 = C;
+ }
+ else
+ {
+ if (NEARZERO(ac))
+ {
+ A2 = A + B * 0.5;
+ C2 = A - B * 0.5;
+ a_offsetrot = Math.PI / 4.0;
+ }
+ else
+ {
+ // Precalculate radical:
+ var K = 1 + B * B / (ac * ac);
+
+ // Clamp (precision issues might need this.. not likely, but better save than sorry)
+ if (K < 0) K = 0;
+ else K = Math.sqrt(K);
+
+ A2 = 0.5 * (A + C + K * ac);
+ C2 = 0.5 * (A + C - K * ac);
+ a_offsetrot = 0.5 * Math.atan2(B, ac);
+ }
+ }
+
+ // This can get slightly below zero due to rounding issues.
+ // it's save to clamp to zero in this case (this yields a zero length halfaxis)
+ if (A2 < 0) A2 = 0;
+ else A2 = Math.sqrt(A2);
+ if (C2 < 0) C2 = 0;
+ else C2 = Math.sqrt(C2);
+
+ // now A2 and C2 are half-axis:
+ if (ac <= 0)
+ {
+ a_rv = A2;
+ a_rh = C2;
+ }
+ else
+ {
+ a_rv = C2;
+ a_rh = A2;
+ }
+
+ // If the transformation matrix contain a mirror-component
+ // winding order of the ellise needs to be changed.
+ if ((matrix.a * matrix.d) - (matrix.b * matrix.c) < 0)
+ {
+ if (!sweep_flag) sweep_flag = 1;
+ else sweep_flag = 0;
+ }
+
+ // Finally, transform arc endpoint. This takes care about the
+ // translational part which we ignored at the whole math-showdown above.
+ endpoint = endpoint.matrixTransform(matrix);
+
+ // Radians back to degrees
+ a_offsetrot = a_offsetrot * 180 / Math.PI;
+
+ var r = ['A', a_rh, a_rv, a_offsetrot, large_arc_flag, sweep_flag, endpoint.x, endpoint.y];
+ return r;
+ }
+
+ // Parts of Raphaël 2.1.0 (MIT licence: http://raphaeljs.com/license.html)
+ // Contains eg. bugfixed path2curve() function
+
+ var R = {};
+ var has = 'hasOwnProperty';
+ var Str = String;
+ var array = 'array';
+ var isnan = {
+ 'NaN': 1,
+ 'Infinity': 1,
+ '-Infinity': 1
+ };
+ var lowerCase = Str.prototype.toLowerCase;
+ var upperCase = Str.prototype.toUpperCase;
+ var objectToString = Object.prototype.toString;
+ var concat = 'concat';
+ var split = 'split';
+ var apply = 'apply';
+ var math = Math,
+ mmax = math.max,
+ mmin = math.min,
+ abs = math.abs,
+ pow = math.pow,
+ PI = math.PI,
+ round = math.round,
+ toFloat = parseFloat,
+ toInt = parseInt;
+ var p2s = /,?([achlmqrstvxz]),?/gi;
+ var pathCommand = /([achlmrqstvz])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig;
+ var pathValues = /(-?\d*\.?\d*(?:e[\-+]?\d+)?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/ig;
+ R.is = function (o, type)
+ {
+ type = lowerCase.call(type);
+ if (type == 'finite')
+ {
+ return !isnan[has](+o);
+ }
+ if (type == 'array')
+ {
+ return o instanceof Array;
+ }
+ return type == 'null' && o === null || type == typeof o && o !== null || type == 'object' && o === Object(o) || type == 'array' && Array.isArray && Array.isArray(o) || objectToString.call(o).slice(8, -1).toLowerCase() == type
+ };
+
+ function clone(obj)
+ {
+ if (Object(obj) !== obj)
+ {
+ return obj;
+ }
+ var res = new obj.constructor;
+ for (var key in obj)
+ {
+ if (obj[has](key))
+ {
+ res[key] = clone(obj[key]);
+ }
+ }
+ return res;
+ }
+ R._path2string = function ()
+ {
+ return this.join(',').replace(p2s, '$1');
+ };
+
+ var pathClone = function (pathArray)
+ {
+ var res = clone(pathArray);
+ res.toString = R._path2string;
+ return res;
+ };
+ var paths = function (ps)
+ {
+ var p = paths.ps = paths.ps ||
+ {};
+ if (p[ps]) p[ps].sleep = 100;
+ else p[ps] = {
+ sleep: 100
+ };
+ setTimeout(function ()
+ {
+ for (var key in p)
+ {
+ if (p[has](key) && key != ps)
+ {
+ p[key].sleep--;
+ !p[key].sleep && delete p[key];
+ }
+ }
+ });
+ return p[ps];
+ };
+
+ function catmullRom2bezier(crp, z)
+ {
+ var d = [];
+ for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2)
+ {
+ var p = [
+ {
+ x: +crp[i - 2],
+ y: +crp[i - 1]
+ },
+ {
+ x: +crp[i],
+ y: +crp[i + 1]
+ },
+ {
+ x: +crp[i + 2],
+ y: +crp[i + 3]
+ },
+ {
+ x: +crp[i + 4],
+ y: +crp[i + 5]
+ }];
+ if (z)
+ {
+ if (!i)
+ {
+ p[0] = {
+ x: +crp[iLen - 2],
+ y: +crp[iLen - 1]
+ };
+ }
+ else
+ {
+ if (iLen - 4 == i)
+ {
+ p[3] = {
+ x: +crp[0],
+ y: +crp[1]
+ };
+ }
+ else
+ {
+ if (iLen - 2 == i)
+ {
+ p[2] = {
+ x: +crp[0],
+ y: +crp[1]
+ };
+ p[3] = {
+ x: +crp[2],
+ y: +crp[3]
+ };
+ }
+ }
+ }
+ }
+ else
+ {
+ if (iLen - 4 == i)
+ {
+ p[3] = p[2];
+ }
+ else
+ {
+ if (!i)
+ {
+ p[0] = {
+ x: +crp[i],
+ y: +crp[i + 1]
+ };
+ }
+ }
+ }
+ d.push(['C', (-p[0].x + 6 * p[1].x + p[2].x) / 6, (-p[0].y + 6 * p[1].y + p[2].y) / 6, (p[1].x + 6 * p[2].x - p[3].x) / 6, (p[1].y + 6 * p[2].y - p[3].y) / 6, p[2].x, p[2].y])
+ }
+ return d
+ };
+ var parsePathString = function (pathString)
+ {
+ if (!pathString) return null;
+ var pth = paths(pathString);
+ if (pth.arr) return pathClone(pth.arr)
+ var paramCounts = {
+ a: 7,
+ c: 6,
+ h: 1,
+ l: 2,
+ m: 2,
+ r: 4,
+ q: 4,
+ s: 4,
+ t: 2,
+ v: 1,
+ z: 0
+ }, data = [];
+ if (R.is(pathString, array) && R.is(pathString[0], array)) data = pathClone(pathString);
+ if (!data.length)
+ {
+ Str(pathString).replace(pathCommand, function (a, b, c)
+ {
+ var params = [],
+ name = b.toLowerCase();
+ c.replace(pathValues, function (a, b)
+ {
+ b && params.push(+b);
+ });
+ if (name == 'm' && params.length > 2)
+ {
+ data.push([b][concat](params.splice(0, 2)));
+ name = 'l';
+ b = b == 'm' ? 'l' : 'L'
+ }
+ if (name == 'r') data.push([b][concat](params))
+ else
+ {
+ while (params.length >= paramCounts[name])
+ {
+ data.push([b][concat](params.splice(0, paramCounts[name])));
+ if (!paramCounts[name]) break;
+ }
+ }
+ })
+ }
+ data.toString = R._path2string;
+ pth.arr = pathClone(data);
+ return data;
+ };
+
+ function repush(array, item)
+ {
+ for (var i = 0, ii = array.length; i < ii; i++)
+ if (array[i] === item)
+ {
+ return array.push(array.splice(i, 1)[0]);
+ }
+ }
+
+ var pathToAbsolute = cacher(function (pathArray)
+ {
+ //var pth = paths(pathArray); // Timo: commented to prevent multiple caching
+ // for some reason only FF proceed correctly
+ // when not cached using cacher() around
+ // this function.
+ //if (pth.abs) return pathClone(pth.abs)
+ if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array))
+ pathArray = parsePathString(pathArray)
+ if (!pathArray || !pathArray.length) return [['M', 0, 0]];
+ var res = [],
+ x = 0,
+ y = 0,
+ mx = 0,
+ my = 0,
+ start = 0;
+ if (pathArray[0][0] == 'M')
+ {
+ x = +pathArray[0][1];
+ y = +pathArray[0][2];
+ mx = x;
+ my = y;
+ start++;
+ res[0] = ['M', x, y];
+ }
+ var crz = pathArray.length == 3 && pathArray[0][0] == 'M' && pathArray[1][0].toUpperCase() == 'R' && pathArray[2][0].toUpperCase() == 'Z';
+ for (var r, pa, i = start, ii = pathArray.length; i < ii; i++)
+ {
+ res.push(r = []);
+ pa = pathArray[i];
+ if (pa[0] != upperCase.call(pa[0]))
+ {
+ r[0] = upperCase.call(pa[0]);
+ switch (r[0])
+ {
+ case 'A':
+ r[1] = pa[1];
+ r[2] = pa[2];
+ r[3] = pa[3];
+ r[4] = pa[4];
+ r[5] = pa[5];
+ r[6] = +(pa[6] + x);
+ r[7] = +(pa[7] + y);
+ break;
+ case 'V':
+ r[1] = +pa[1] + y;
+ break;
+ case 'H':
+ r[1] = +pa[1] + x;
+ break;
+ case 'R':
+ var dots = [x, y][concat](pa.slice(1));
+ for (var j = 2, jj = dots.length; j < jj; j++)
+ {
+ dots[j] = +dots[j] + x;
+ dots[++j] = +dots[j] + y
+ }
+ res.pop();
+ res = res[concat](catmullRom2bezier(dots, crz));
+ break;
+ case 'M':
+ mx = +pa[1] + x;
+ my = +pa[2] + y;
+ default:
+ for (j = 1, jj = pa.length; j < jj; j++)
+ r[j] = +pa[j] + (j % 2 ? x : y)
+ }
+ }
+ else
+ {
+ if (pa[0] == 'R')
+ {
+ dots = [x, y][concat](pa.slice(1));
+ res.pop();
+ res = res[concat](catmullRom2bezier(dots, crz));
+ r = ['R'][concat](pa.slice(-2));
+ }
+ else
+ {
+ for (var k = 0, kk = pa.length; k < kk; k++)
+ r[k] = pa[k]
+ }
+ }
+ switch (r[0])
+ {
+ case 'Z':
+ x = mx;
+ y = my;
+ break;
+ case 'H':
+ x = r[1];
+ break;
+ case 'V':
+ y = r[1];
+ break;
+ case 'M':
+ mx = r[r.length - 2];
+ my = r[r.length - 1];
+ default:
+ x = r[r.length - 2];
+ y = r[r.length - 1];
+ }
+ }
+ res.toString = R._path2string;
+ //pth.abs = pathClone(res);
+ return res;
+ });
+
+ function cacher(f, scope, postprocessor)
+ {
+ function newf()
+ {
+ var arg = Array.prototype.slice.call(arguments, 0),
+ args = arg.join('\u2400'),
+ cache = newf.cache = newf.cache ||
+ {}, count = newf.count = newf.count || [];
+ if (cache.hasOwnProperty(args))
+ {
+ for (var i = 0, ii = count.length; i < ii; i++)
+ if (count[i] === args)
+ {
+ count.push(count.splice(i, 1)[0]);
+ }
+ return postprocessor ? postprocessor(cache[args]) : cache[args];
+ }
+ count.length >= 1E3 && delete cache[count.shift()];
+ count.push(args);
+ cache[args] = f.apply(scope, arg);
+ return postprocessor ? postprocessor(cache[args]) : cache[args];
+ }
+ return newf;
+ }
+
+ var l2c = function (x1, y1, x2, y2)
+ {
+ return [x1, y1, x2, y2, x2, y2];
+ },
+ q2c = function (x1, y1, ax, ay, x2, y2)
+ {
+ var _13 = 1 / 3,
+ _23 = 2 / 3;
+ return [_13 * x1 + _23 * ax, _13 * y1 + _23 * ay, _13 * x2 + _23 * ax, _13 * y2 + _23 * ay, x2, y2]
+ },
+ a2c = cacher(function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive)
+ {
+ var _120 = PI * 120 / 180,
+ rad = PI / 180 * (+angle || 0),
+ res = [],
+ xy,
+ rotate = cacher(function (x, y, rad)
+ {
+ var X = x * Math.cos(rad) - y * Math.sin(rad),
+ Y = x * Math.sin(rad) + y * Math.cos(rad);
+ return {
+ x: X,
+ y: Y
+ };
+ });
+ if (!recursive)
+ {
+ xy = rotate(x1, y1, -rad);
+ x1 = xy.x;
+ y1 = xy.y;
+ xy = rotate(x2, y2, -rad);
+ x2 = xy.x;
+ y2 = xy.y;
+ var cos = Math.cos(PI / 180 * angle),
+ sin = Math.sin(PI / 180 * angle),
+ x = (x1 - x2) / 2,
+ y = (y1 - y2) / 2;
+ var h = x * x / (rx * rx) + y * y / (ry * ry);
+ if (h > 1)
+ {
+ h = Math.sqrt(h);
+ rx = h * rx;
+ ry = h * ry;
+ }
+ var rx2 = rx * rx,
+ ry2 = ry * ry,
+ k = (large_arc_flag == sweep_flag ? -1 : 1) * Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
+ cx = k * rx * y / ry + (x1 + x2) / 2,
+ cy = k * -ry * x / rx + (y1 + y2) / 2,
+ f1 = Math.asin(((y1 - cy) / ry).toFixed(9)),
+ f2 = Math.asin(((y2 - cy) / ry).toFixed(9));
+ f1 = x1 < cx ? PI - f1 : f1;
+ f2 = x2 < cx ? PI - f2 : f2;
+ f1 < 0 && (f1 = PI * 2 + f1);
+ f2 < 0 && (f2 = PI * 2 + f2);
+ if (sweep_flag && f1 > f2)
+ {
+ f1 = f1 - PI * 2;
+ }
+ if (!sweep_flag && f2 > f1)
+ {
+ f2 = f2 - PI * 2;
+ }
+ }
+ else
+ {
+ f1 = recursive[0];
+ f2 = recursive[1];
+ cx = recursive[2];
+ cy = recursive[3];
+ }
+ var df = f2 - f1;
+ if (Math.abs(df) > _120)
+ {
+ var f2old = f2,
+ x2old = x2,
+ y2old = y2;
+ f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
+ x2 = cx + rx * Math.cos(f2);
+ y2 = cy + ry * Math.sin(f2);
+ res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy])
+ }
+ df = f2 - f1;
+ var c1 = Math.cos(f1),
+ s1 = Math.sin(f1),
+ c2 = Math.cos(f2),
+ s2 = Math.sin(f2),
+ t = Math.tan(df / 4),
+ hx = 4 / 3 * rx * t,
+ hy = 4 / 3 * ry * t,
+ m1 = [x1, y1],
+ m2 = [x1 + hx * s1, y1 - hy * c1],
+ m3 = [x2 + hx * s2, y2 - hy * c2],
+ m4 = [x2, y2];
+ m2[0] = 2 * m1[0] - m2[0];
+ m2[1] = 2 * m1[1] - m2[1];
+ if (recursive) return [m2, m3, m4].concat(res);
+ else
+ {
+ res = [m2, m3, m4].concat(res).join().split(',');
+ var newres = [];
+ for (var i = 0, ii = res.length; i < ii; i++)
+ newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x
+ return newres
+ }
+ });
+
+ var path2curve = cacher(function (path, path2)
+ {
+ var pth = !path2 && paths(path);
+ if (!path2 && pth.curve) return pathClone(pth.curve)
+ var p = pathToAbsolute(path),
+ p2 = path2 && pathToAbsolute(path2),
+ attrs = {
+ x: 0,
+ y: 0,
+ bx: 0,
+ by: 0,
+ X: 0,
+ Y: 0,
+ qx: null,
+ qy: null
+ },
+ attrs2 = {
+ x: 0,
+ y: 0,
+ bx: 0,
+ by: 0,
+ X: 0,
+ Y: 0,
+ qx: null,
+ qy: null
+ },
+ processPath = function (path, d, pcom)
+ {
+ var nx, ny;
+ if (!path)
+ {
+ return ['C', d.x, d.y, d.x, d.y, d.x, d.y];
+ }!(path[0] in
+ {
+ T: 1,
+ Q: 1
+ }) && (d.qx = d.qy = null);
+ switch (path[0])
+ {
+ case 'M':
+ d.X = path[1];
+ d.Y = path[2];
+ break;
+ case 'A':
+ path = ['C'][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1))));
+ break;
+ case 'S':
+ if (pcom == 'C' || pcom == 'S')
+ {
+ nx = d.x * 2 - d.bx;
+ ny = d.y * 2 - d.by;
+ }
+ else
+ {
+ nx = d.x;
+ ny = d.y;
+ }
+ path = ['C', nx, ny][concat](path.slice(1));
+ break;
+ case 'T':
+ if (pcom == 'Q' || pcom == 'T')
+ {
+ d.qx = d.x * 2 - d.qx;
+ d.qy = d.y * 2 - d.qy;
+ }
+ else
+ {
+ d.qx = d.x;
+ d.qy = d.y;
+ }
+ path = ['C'][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
+ break;
+ case 'Q':
+ d.qx = path[1];
+ d.qy = path[2];
+ path = ['C'][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4]));
+ break;
+ case 'L':
+ path = ['C'][concat](l2c(d.x, d.y, path[1], path[2]));
+ break;
+ case 'H':
+ path = ['C'][concat](l2c(d.x, d.y, path[1], d.y));
+ break;
+ case 'V':
+ path = ['C'][concat](l2c(d.x, d.y, d.x, path[1]));
+ break;
+ case 'Z':
+ path = ['C'][concat](l2c(d.x, d.y, d.X, d.Y));
+ break
+ }
+ return path
+ },
+ fixArc = function (pp, i)
+ {
+ if (pp[i].length > 7)
+ {
+ pp[i].shift();
+ var pi = pp[i];
+ while (pi.length)
+ {
+ pcoms1[i] = 'A';
+ p2 && (pcoms2[i] = 'A');
+ pp.splice(i++, 0, ['C'][concat](pi.splice(0, 6)));
+ }
+ pp.splice(i, 1);
+ ii = mmax(p.length, p2 && p2.length || 0);
+ }
+ },
+ fixM = function (path1, path2, a1, a2, i)
+ {
+ if (path1 && path2 && path1[i][0] == 'M' && path2[i][0] != 'M')
+ {
+ path2.splice(i, 0, ['M', a2.x, a2.y]);
+ a1.bx = 0;
+ a1.by = 0;
+ a1.x = path1[i][1];
+ a1.y = path1[i][2];
+ ii = mmax(p.length, p2 && p2.length || 0);
+ }
+ },
+ pcoms1 = [],
+ pcoms2 = [],
+ pfirst = '',
+ pcom = '';
+ for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++)
+ {
+ p[i] && (pfirst = p[i][0]);
+ if (pfirst != 'C')
+ {
+ pcoms1[i] = pfirst;
+ i && (pcom = pcoms1[i - 1]);
+ }
+ p[i] = processPath(p[i], attrs, pcom);
+ if (pcoms1[i] != 'A' && pfirst == 'C') pcoms1[i] = 'C';
+ fixArc(p, i);
+ if (p2)
+ {
+ p2[i] && (pfirst = p2[i][0]);
+ if (pfirst != 'C')
+ {
+ pcoms2[i] = pfirst;
+ i && (pcom = pcoms2[i - 1]);
+ }
+ p2[i] = processPath(p2[i], attrs2, pcom);
+ if (pcoms2[i] != 'A' && pfirst == 'C') pcoms2[i] = 'C'
+ fixArc(p2, i);
+ }
+ fixM(p, p2, attrs, attrs2, i);
+ fixM(p2, p, attrs2, attrs, i);
+ var seg = p[i],
+ seg2 = p2 && p2[i],
+ seglen = seg.length,
+ seg2len = p2 && seg2.length;
+ attrs.x = seg[seglen - 2];
+ attrs.y = seg[seglen - 1];
+ attrs.bx = toFloat(seg[seglen - 4]) || attrs.x;
+ attrs.by = toFloat(seg[seglen - 3]) || attrs.y;
+ attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x);
+ attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y);
+ attrs2.x = p2 && seg2[seg2len - 2];
+ attrs2.y = p2 && seg2[seg2len - 1];
+ }
+ if (!p2) pth.curve = pathClone(p);
+ return p2 ? [p, p2] : p
+ }, null, pathClone);
diff --git a/src/i18n.js b/src/i18n.js
index 8848502..f2c773c 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -33,6 +33,9 @@ export default {
absoluteMode: 'ABSOLUTE',
percentMode: 'PERCENT',
+ builtin: 'Builtin',
+ upload: 'Upload SVG or PNG',
+
setOptionError: 'Something Unexpected Happerns. Click refresh to try again!',
refresh: 'Refresh',
@@ -72,6 +75,9 @@ export default {
absoluteMode: '绝对值',
percentMode: '百分比',
+ builtin: '内置',
+ upload: '上传 SVG 或 PNG',
+
setOptionError: '发生了一些意料之外的错误,点击刷新再试试!',
refresh: '刷新',
diff --git a/tool/md2json.js b/tool/md2json.js
index 34f508b..3edb06f 100644
--- a/tool/md2json.js
+++ b/tool/md2json.js
@@ -224,7 +224,8 @@ function mdToJsonSchema(mdStr, maxDepth, imagePath) {
}
else if (tagName.startsWith('exampleuicontrol')) {
const type = tagName.replace('exampleuicontrol', '').toLowerCase();
- if (['boolean', 'color', 'number', 'vector', 'enum', 'angle', 'percent', 'percentvector', 'text']
+ if (['boolean', 'color', 'number', 'vector', 'enum', 'angle', 'percent', 'percentvector', 'text',
+ 'icon']
.indexOf(type) < 0) {
console.error(`Unkown ExampleUIControl Type ${type}`);
}
@@ -246,7 +247,7 @@ function mdToJsonSchema(mdStr, maxDepth, imagePath) {
if (currentExampleCode) {
// Get code from map;
if (!codeMap[data]) {
- throw new Error('Can\'t find code.', codeMap, data);
+ console.error('Can\'t find code.', codeMap, data);
}
currentExampleCode.code = codeMap[data];
}
diff --git a/zh/option/component/angle-axis.md b/zh/option/component/angle-axis.md
index 119daf5..6609043 100644
--- a/zh/option/component/angle-axis.md
+++ b/zh/option/component/angle-axis.md
@@ -5,6 +5,73 @@
极坐标系的角度轴。
+<ExampleBaseOption name="two-number-axis" title="双数值轴">
+const data = [];
+
+for (let i = 0; i <= 360; i++) {
+ const t = i / 180 * Math.PI;
+ const r = Math.sin(2 * t) * Math.cos(2 * t);
+ data.push([r, i]);
+}
+
+const option = {
+ polar: {
+ center: ['50%', '54%']
+ },
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'cross'
+ }
+ },
+ angleAxis: {
+ type: 'value',
+ startAngle: 0,
+ },
+ radiusAxis: {
+ min: 0
+ },
+ series: [{
+ coordinateSystem: 'polar',
+ name: 'line',
+ type: 'line',
+ showSymbol: false,
+ data: data
+ }],
+ animationDuration: 2000
+};
+</ExampleBaseOption>
+
+<ExampleBaseOption name="two-category-axis" title="双类目轴">
+
+const hours = ['12a', '1a', '2a', '3a', '4a', '5a', '6a',
+ '7a', '8a', '9a','10a','11a',
+ '12p', '1p', '2p', '3p', '4p', '5p',
+ '6p', '7p', '8p', '9p', '10p', '11p'];
+const days = ['Saturday', 'Friday', 'Thursday',
+ 'Wednesday', 'Tuesday', 'Monday', 'Sunday'];
+
+const option = {
+ title: {
+ text: 'Punch Card of Github'
+ },
+ legend: {
+ data: ['Punch Card'],
+ left: 'right'
+ },
+ polar: {},
+ angleAxis: {
+ type: 'category',
+ data: hours,
+ boundaryGap: false
+ },
+ radiusAxis: {
+ type: 'category',
+ data: days
+ }
+};
+</ExampleBaseOption>
+
{{use: partial-component-id(prefix="#")}}
## polarIndex(number) = 0
@@ -13,6 +80,8 @@
## startAngle(number) = 90
+<ExampleUIControlAngle default="90" min="-360" max="360" step="1" />
+
起始刻度的角度,默认为 90 度,即圆心的正上方。0 度为圆心的正右方。
如下示例是 startAngle 为 45 的效果:
@@ -21,6 +90,8 @@
## clockwise(boolean) = true
+<ExampleUIControlBoolean default="true" />
+
刻度增长是否按顺时针,默认顺时针。
如下示例是 clockwise 为 `false` (逆时针)的效果:
diff --git a/zh/option/component/axis-common.md b/zh/option/component/axis-common.md
index 87ad2e4..a6174b1 100644
--- a/zh/option/component/axis-common.md
+++ b/zh/option/component/axis-common.md
@@ -42,7 +42,7 @@ X 轴或者 Y 轴的轴线是否在另一个轴的 0 刻度上,只有在另一
##${prefix} symbol(string|Array) = 'none'
-<ExampleUIControlEnum default="none" options="none,circle,rect,roundRect,triangle,diamond,pin,arrow" />
+<ExampleUIControlIcon default="none" />
轴线两边的箭头。可以是字符串,表示两端使用同样的箭头;或者长度为 2 的字符串数组,分别表示两端的箭头。默认不显示箭头,即 `'none'`。两端都显示箭头可以设置为 `'arrow'`,只在末端显示箭头可以设置为 `['none', 'arrow']`。
diff --git a/zh/option/component/data-zoom-inside.md b/zh/option/component/data-zoom-inside.md
index adffbb0..de904dc 100644
--- a/zh/option/component/data-zoom-inside.md
+++ b/zh/option/component/data-zoom-inside.md
@@ -14,8 +14,42 @@
+ 移动端:在移动端触屏上,支持两指滑动缩放。
-<br>
-<br>
+<ExampleBaseOption name="data-zoom-inside" title="使用拖拽滚轮平移缩放">
+const data = [["2014-07-14",156],["2014-07-15",140],["2014-07-16",133],["2014-07-17",186],["2014-07-18",182],["2014-07-19",106],["2014-07-20",119],["2014-07-21",68],["2014-07-22",54],["2014-07-23",82],["2014-07-24",90],["2014-07-25",134],["2014-07-26",188],["2014-07-27",194],["2014-07-28",159],["2014-07-29",159],["2014-07-30",169],["2014-07-31",244],["2014-08-01",199],["2014-08-02",163],["2014-08-03",149],["2014-08-05",80],["2014-08-06",67],["2014-08-07",162],["2014-08-08",140],["2014-08 [...]
+
+const option = {
+ color: ['#3398DB'],
+ title: {
+ text: 'Beijing AQI'
+ },
+ tooltip: {
+ trigger: 'axis'
+ },
+ xAxis: {
+ data: data.map(function (item) {
+ return item[0];
+ })
+ },
+ yAxis: {
+ splitLine: {
+ show: false
+ }
+ },
+ dataZoom: [{
+ start: 80,
+ type: 'inside'
+ }, {
+ start: 80
+ }],
+ series: {
+ name: 'Beijing AQI',
+ type: 'bar',
+ data: data.map(function (item) {
+ return item[1];
+ })
+ }
+};
+</ExampleBaseOption>
## type(string) = 'inside'
@@ -24,6 +58,8 @@
## disabled(boolean) = false
+<ExampleUIControlBoolean />
+
是否停止组件的功能。
{{ use: partial-data-zoom-common(
@@ -34,6 +70,8 @@
## zoomOnMouseWheel(boolean|string) = true
+<ExampleUIControlEnum options="true,false,shift,ctrl,alt" default="true" />
+
如何触发缩放。可选值为:
+ `true`:表示不按任何功能键,鼠标滚轮能触发缩放。
@@ -44,6 +82,8 @@
## moveOnMouseMove(boolean|string) = true
+<ExampleUIControlEnum options="true,false,shift,ctrl,alt" default="true" />
+
如何触发数据窗口平移。可选值为:
+ `true`:表示不按任何功能键,鼠标移动能触发数据窗口平移。
@@ -54,6 +94,8 @@
## moveOnMouseWheel(boolean|string) = true
+<ExampleUIControlEnum options="true,false,shift,ctrl,alt" default="true" />
+
如何触发数据窗口平移。可选值为:
+ `true`:表示不按任何功能键,鼠标滚轮能触发数据窗口平移。
@@ -64,4 +106,6 @@
## preventDefaultMouseMove(boolean) = true
+<ExampleUIControlBoolean default="true" />
+
是否阻止 mousemove 事件的默认行为。
\ No newline at end of file
diff --git a/zh/option/component/data-zoom-slider.md b/zh/option/component/data-zoom-slider.md
index 2c5b2a2..adb65d7 100644
--- a/zh/option/component/data-zoom-slider.md
+++ b/zh/option/component/data-zoom-slider.md
@@ -6,9 +6,36 @@
(参考[数据区域缩放组件(dataZoom)的介绍](~dataZoom))
-
-<br>
-<br>
+<ExampleBaseOption name="data-zoom-slider" title="滑块缩放的 dataZoom">
+const data = [["2014-07-14",156],["2014-07-15",140],["2014-07-16",133],["2014-07-17",186],["2014-07-18",182],["2014-07-19",106],["2014-07-20",119],["2014-07-21",68],["2014-07-22",54],["2014-07-23",82],["2014-07-24",90],["2014-07-25",134],["2014-07-26",188],["2014-07-27",194],["2014-07-28",159],["2014-07-29",159],["2014-07-30",169],["2014-07-31",244],["2014-08-01",199],["2014-08-02",163],["2014-08-03",149],["2014-08-05",80],["2014-08-06",67],["2014-08-07",162],["2014-08-08",140],["2014-08 [...]
+
+const option = {
+ color: ['#3398DB'],
+ tooltip: {
+ trigger: 'axis'
+ },
+ xAxis: {
+ data: data.map(function (item) {
+ return item[0];
+ })
+ },
+ yAxis: {
+ splitLine: {
+ show: false
+ }
+ },
+ dataZoom: [{
+ start: 80
+ }],
+ series: {
+ name: 'Beijing AQI',
+ type: 'bar',
+ data: data.map(function (item) {
+ return item[1];
+ })
+ }
+};
+</ExampleBaseOption>
## type(string) = 'slider'
@@ -17,11 +44,15 @@
## show(boolean) = true
+<ExampleUIControlBoolean default="true" />
+
是否显示 ${dataZoomName} 组件。如果设置为 `false`,不会显示,但是数据过滤的功能还存在。
## backgroundColor(Color) = 'rgba(47,69,84,0)'
+<ExampleUIControlColor default="rgba(47,69,84,0)" />
+
组件的背景颜色。
@@ -53,10 +84,14 @@
## fillerColor(Color) = 'rgba(167,183,204,0.4)'
+<ExampleUIControlColor default="rgba(167,183,204,0.4)" />
+
选中范围的填充颜色。
## borderColor(Color) = '#ddd'
+<ExampleUIControlColor default="#ddd" />
+
边框颜色。
@@ -73,6 +108,8 @@
## handleSize(number|string) = '100%'
+<ExampleUIControlPercent min="0" step="1" default="100%" />
+
控制手柄的尺寸,可以是像素大小,也可以是相对于 dataZoom 组件宽度的百分比,默认跟 dataZoom 宽度相同。
## handleStyle(Object)
@@ -87,6 +124,8 @@
## labelPrecision(number|string) = 'auto'
+<ExampleUIControlNumber min="0" step="1" />
+
显示label的小数精度。默认根据数据自动决定。
@@ -113,16 +152,22 @@ labelFormatter: function (value) {
## showDetail(boolean) = true
+<ExampleUIControlBoolean default="true" />
+
是否显示detail,即拖拽时候显示详细数值信息。
## showDataShadow(string) = 'auto'
+<ExampleUIControlBoolean />
+
是否在 `dataZoom-silder` 组件中显示数据阴影。数据阴影可以简单地反应数据走势。
## realtime(boolean) = true
+<ExampleUIControlBoolean default="true" />
+
拖动时,是否实时更新系列的视图。如果设置为 `false`,则只在拖拽结束的时候更新。
diff --git a/zh/option/component/data-zoom.md b/zh/option/component/data-zoom.md
index 64f3ad5..5659c17 100644
--- a/zh/option/component/data-zoom.md
+++ b/zh/option/component/data-zoom.md
@@ -114,11 +114,6 @@ option = {
如果需要改变这种处理顺序,那么改变 `dataZoomX` 和 `dataZoomY` 在 option 中的出现顺序即可。
-<br>
-<br>
-
-
-
{{import: component-data-zoom-inside}}
{{import: component-data-zoom-slider}}
@@ -200,11 +195,15 @@ option: {
## filterMode(string) = 'filter'
+<ExampleUIControlEnum options="filter,weakFilter,empty,none" default="filter" />
+
{{use: partial-data-zoom-filterMode}}
## start(number) = 0
+<ExampleUIControlNumber min="0" max="100" step="0.5" />
+
数据窗口范围的起始百分比。范围是:0 ~ 100。表示 0% ~ 100%。
[${dataZoomName}.start](~${dataZoomName}.start) 和 [${dataZoomName}.end](~${dataZoomName}.end) 共同用 **百分比** 的形式定义了数据窗口范围。
@@ -214,6 +213,8 @@ option: {
## end(number) = 100
+<ExampleUIControlNumber min="0" max="100" default="100" step="0.5" />
+
数据窗口范围的结束百分比。范围是:0 ~ 100。
[${dataZoomName}.start](~${dataZoomName}.start) 和 [${dataZoomName}.end](~${dataZoomName}.end) 共同用 **百分比** 的形式定义了数据窗口范围。
@@ -247,12 +248,16 @@ option: {
## minSpan(number) = null
+<ExampleUIControlNumber min="0" max="100" step="0.5" />
+
用于限制窗口大小的最小值(百分比值),取值范围是 `0` ~ `100`。
如果设置了 [${dataZoomName}.minValueSpan](~${dataZoomName}.minValueSpan) 则 `minSpan` 失效。
## maxSpan(number) = null
+<ExampleUIControlNumber min="0" max="100" step="0.5" />
+
用于限制窗口大小的最大值(百分比值),取值范围是 `0` ~ `100`。
如果设置了 [${dataZoomName}.maxValueSpan](~${dataZoomName}.maxValueSpan) 则 `maxSpan` 失效。
@@ -273,6 +278,8 @@ option: {
## orient(string) = null
+<ExampleUIControlEnum options="horizontal,vertical" />
+
布局方式是横还是竖。不仅是布局方式,对于直角坐标系而言,也决定了,缺省情况控制横向数轴还是纵向数轴。
可选值为:
@@ -284,6 +291,8 @@ option: {
## zoomLock(boolean) = false
+<ExampleUIControlBoolean />
+
是否锁定选择区域(或叫做数据窗口)的大小。
如果设置为 `true` 则锁定选择区域的大小,也就是说,只能平移,不能缩放。
@@ -291,6 +300,8 @@ option: {
## throttle(number) = 100
+<ExampleUIControlNumber default="100" min="0" step="20" />
+
设置触发视图刷新的频率。单位为毫秒(ms)。
如果 [animation](~animation) 设为 `true` 且 [animationDurationUpdate](~animationDurationUpdate) 大于 `0`,可以保持 `throttle` 为默认值 `100`(或者设置为大于 `0` 的值),否则拖拽时有可能画面感觉卡顿。
diff --git a/zh/option/component/legend.md b/zh/option/component/legend.md
index ac15747..71c814c 100644
--- a/zh/option/component/legend.md
+++ b/zh/option/component/legend.md
@@ -175,6 +175,8 @@ const option = {
## symbolKeepAspect(boolean) = true
+<ExampleUIControlBoolean />
+
如果图标(可能来自系列的 `symbol` 或用户自定义的 `legend.data.icon`)是 `path://` 的形式,是否在缩放时保持该图形的长宽比。
## formatter(string|Function) = null
@@ -248,6 +250,8 @@ legend: {
## icon(string)
+<ExampleUIControlIcon />
+
图例项的 icon。
{{ use: partial-icon }}
diff --git a/zh/option/component/radar.md b/zh/option/component/radar.md
index 1952691..8a9d088 100644
--- a/zh/option/component/radar.md
+++ b/zh/option/component/radar.md
@@ -11,6 +11,42 @@
~[400x400](${galleryViewPath}doc-example/radar&edit=1&reset=1)
+<ExampleBaseOption name="radar" title="基础雷达图">
+const option = {
+ title: {
+ text: '基础雷达图'
+ },
+ tooltip: {},
+ legend: {
+ data: ['Allocated Budget', 'Actual Spending']
+ },
+ radar: {
+ indicator: [
+ { name: 'sales', max: 6500},
+ { name: 'Administration', max: 16000},
+ { name: 'Information Techology', max: 30000},
+ { name: 'Customer Support', max: 38000},
+ { name: 'Development', max: 52000},
+ { name: 'Marketing', max: 25000}
+ ]
+ },
+ series: [{
+ name: '预算 vs 开销(Budget vs spending)',
+ type: 'radar',
+ data: [
+ {
+ value: [4300, 10000, 28000, 35000, 50000, 19000],
+ name: 'Allocated Budget'
+ },
+ {
+ value: [5000, 14000, 28000, 31000, 42000, 21000],
+ name: 'Actual Spending'
+ }
+ ]
+ }]
+};
+</ExampleBaseOption>
+
{{use: partial-component-id(prefix="#")}}
{{use: component-circular-layout(
@@ -51,22 +87,26 @@ formatter: function (value, indicator) {
## nameGap(number) = 15
-指示器名称和指示器轴的距离。
+<ExampleUIControlNumber default="15" step="1" />
-## axisType(string) = 'value'
-{{ use: partial-version(version = "4.5.0") }}
-{{ use: partial-axis-type-content() }}
+指示器名称和指示器轴的距离。
## splitNumber(number) = 5
+<ExampleUIControlNumber default="15" step="1" />
+
指示器轴的分割段数。
## shape(string) = 'polygon'
+<ExampleUIControlEnum options="polygon,circle" />
+
雷达图绘制类型,支持 `'polygon'` 和 `'circle'`。
## scale(boolean) = false
+<ExampleUIControlBoolean />
+
是否是脱离 0 值比例。设置成 `true` 后坐标刻度不会强制包含零刻度。在双数值轴的散点图中比较有用。
{{ use: partial-axis-common-axis-line(
@@ -118,12 +158,18 @@ indicator: [
### max(number)
+<ExampleUIControlNumber default="100" step="1" />
+
指示器的最大值,可选,建议设置
### min(number)
+<ExampleUIControlNumber step="1" />
+
指示器的最小值,可选,默认为 0。
### color(string)
+<ExampleUIControlColor />
+
标签特定的颜色。
\ No newline at end of file
diff --git a/zh/option/partial/symbol.md b/zh/option/partial/symbol.md
index ebe6a8d..044bdab 100644
--- a/zh/option/partial/symbol.md
+++ b/zh/option/partial/symbol.md
@@ -2,7 +2,7 @@
#${prefix} symbol(string{{ if: ${hasCallback} }}|Function{{ /if}}) = ${defaultSymbol}
-<ExampleUIControlEnum default="circle" options="circle,rect,roundRect,triangle,diamond,pin,arrow,none" />
+<ExampleUIControlIcon default="circle" />
${name}标记的图形。
@@ -48,6 +48,8 @@ ${name}标记的旋转角度(而非弧度)。正值表示逆时针旋转。
#${prefix} symbolKeepAspect(boolean) = false
+<ExampleUIControlBoolean />
+
如果 `symbol` 是 `path://` 的形式,是否在缩放时保持该图形的长宽比。
#${prefix} symbolOffset(Array) = [0, 0]
diff --git a/zh/option/series/pie.md b/zh/option/series/pie.md
index aa9b486..405d0b6 100644
--- a/zh/option/series/pie.md
+++ b/zh/option/series/pie.md
@@ -39,30 +39,9 @@ const option = {
]
};
-<ExampleBaseOption name="pie" title="很多数据的饼图">
-const option = {
- legend: {
- orient: 'vertical',
- left: 'left',
- data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
- },
- series: [
- {
- name: '访问来源',
- type: 'pie',
- data: [
- {value: 335, name: '直接访问'},
- {value: 310, name: '邮件营销'},
- {value: 234, name: '联盟广告'},
- {value: 135, name: '视频广告'},
- {value: 1548, name: '搜索引擎'}
- ]
- }
- ]
-};
-
</ExampleBaseOption>
+
## type(string) = 'pie'
{{use: partial-component-id(prefix="#")}}
diff --git a/zh/option/series/radar.md b/zh/option/series/radar.md
index 20daa2d..5b5ba28 100644
--- a/zh/option/series/radar.md
+++ b/zh/option/series/radar.md
@@ -18,16 +18,16 @@ const option = {
},
tooltip: {},
legend: {
- data: ['预算分配(Allocated Budget)', '实际开销(Actual Spending)']
+ data: ['Allocated Budget', 'Actual Spending']
},
radar: {
indicator: [
- { name: '销售(sales)', max: 6500},
- { name: '管理(Administration)', max: 16000},
- { name: '信息技术(Information Techology)', max: 30000},
- { name: '客服(Customer Support)', max: 38000},
- { name: '研发(Development)', max: 52000},
- { name: '市场(Marketing)', max: 25000}
+ { name: 'sales', max: 6500},
+ { name: 'Administration', max: 16000},
+ { name: 'Information Techology', max: 30000},
+ { name: 'Customer Support', max: 38000},
+ { name: 'Development', max: 52000},
+ { name: 'Marketing', max: 25000}
]
},
series: [{
@@ -36,11 +36,11 @@ const option = {
data: [
{
value: [4300, 10000, 28000, 35000, 50000, 19000],
- name: '预算分配(Allocated Budget)'
+ name: 'Allocated Budget'
},
{
value: [5000, 14000, 28000, 31000, 42000, 21000],
- name: '实际开销(Actual Spending)'
+ name: 'Actual Spending'
}
]
}]
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org